diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2017-03-29 19:28:20 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2017-03-29 19:28:27 +0200 |
commit | 87c02a5399abb0dfe020f3cd1c5e2337c0d8cb8f (patch) | |
tree | ed82c1509ca562b49aee7df440ce575ceb3beb88 /pose-widget/glwidget.cpp | |
parent | 94f510f31c3f5ca79f24f2daa085cb34d5650565 (diff) |
pose-widget: reduce latency
- project on a separate thread
- use Qt's native ARGB32
- use double buffering
- more fine-grained locks
Diffstat (limited to 'pose-widget/glwidget.cpp')
-rw-r--r-- | pose-widget/glwidget.cpp | 113 |
1 files changed, 88 insertions, 25 deletions
diff --git a/pose-widget/glwidget.cpp b/pose-widget/glwidget.cpp index 17f4e1a2..beddc5e9 100644 --- a/pose-widget/glwidget.cpp +++ b/pose-widget/glwidget.cpp @@ -7,6 +7,7 @@ #include "glwidget.h" #include "compat/util.hpp" +#include "compat/timer.hpp" #include <cmath> #include <algorithm> #include <QPainter> @@ -14,44 +15,94 @@ #include <QDebug> -using namespace euler; using namespace pose_widget_impl; -GLWidget::GLWidget(QWidget *parent) : QWidget(parent) +pose_transform::pose_transform(QWidget* dst) : + dst(dst), + image(w, h, QImage::Format_ARGB32), + image2(w, h, QImage::Format_ARGB32), + width(w), height(h) { front = QImage(QString(":/images/side1.png")); back = QImage(QString(":/images/side6.png")); - rotateBy(0, 0, 0, 0, 0, 0); + + image.fill(Qt::transparent); + image2.fill(Qt::transparent); + + rotateBy(0, 0, 0, 0, 0, 0, QSize(w, h)); + + project_quad_texture(); + + start(); } -GLWidget::~GLWidget() +pose_transform::~pose_transform() { + requestInterruption(); + wait(); } -void GLWidget::paintEvent(QPaintEvent * event) +void pose_widget::paintEvent(QPaintEvent* event) { QPainter p(this); - project_quad_texture(); - p.drawImage(event->rect(), image); + xform.with_image_lock([&](const QImage& image) { + p.drawImage(event->rect(), image); + }); +} + +void pose_transform::run() +{ + for (;;) + { + if (isInterruptionRequested()) + break; + + static struct cruft + { + void lock() {} + void unlock() {} + } not_a_mutex; + + const cv_status st = cvar.wait_for(not_a_mutex, std::chrono::milliseconds(2000)); + if (st == cv_status::timeout) + continue; + + project_quad_texture(); + } +} + +pose_widget::pose_widget(QWidget* parent) : QWidget(parent), xform(this) +{ +} + +pose_widget::~pose_widget() +{ } -void GLWidget::rotateBy(double xAngle, double yAngle, double zAngle, double x, double y, double z) +void pose_widget::rotateBy(double xAngle, double yAngle, double zAngle, double x, double y, double z) +{ + xform.rotateBy(xAngle, yAngle, zAngle, x, y, z, size()); +} + +void pose_transform::rotateBy(double xAngle, double yAngle, double zAngle, double x, double y, double z, const QSize& size) { using std::sin; using std::cos; static constexpr double d2r = M_PI / 180; - translation = vec3(x, y, z); - euler::euler_t euler(-zAngle * d2r, xAngle * d2r, -yAngle * d2r); euler::rmat r = euler::euler_to_rmat(euler); + lock_guard l(mtx); + for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) rotation(i, j) = num(r(i, j)); - update(); + translation = vec3(x, y, z); + + cvar.notify_one(); } class Triangle { @@ -62,7 +113,7 @@ public: bool barycentric_coords(const vec2& px, vec2& uv, int& i) const; }; -inline vec3 GLWidget::normal(const vec3& p1, const vec3& p2, const vec3& p3) +inline vec3 pose_transform::normal(const vec3& p1, const vec3& p2, const vec3& p3) { using std::sqrt; @@ -124,13 +175,15 @@ bool Triangle::barycentric_coords(const vec2& px, vec2& uv, int& i) const return u >= 0 && v >= 0 && u + v <= 1; } -void GLWidget::project_quad_texture() +void pose_transform::project_quad_texture() { num dir; vec2 pt[4]; - const int sx = width() - 1, sy = height() - 1; + const int sx = width - 1, sy = height - 1; vec2 projected[3]; + lock_guard l(mtx); + { const int sx_ = (sx - std::max(0, (sx - sy)/2)) * 5/9; const int sy_ = (sy - std::max(0, (sy - sx)/2)) * 5/9; @@ -163,12 +216,6 @@ void GLWidget::project_quad_texture() } const QImage& tex = dir < 0 ? back : front; - - if (image.size() != size()) - image = QImage(QSize(sx, sy), QImage::Format_RGBA8888); - - image.fill(palette().color(QPalette::Current, QPalette::Window)); - const int ow = tex.width(), oh = tex.height(); vec2 origs[2][3] = @@ -260,19 +307,27 @@ void GLWidget::project_quad_texture() const int pos = y * dest_pitch + x * dest_depth; - dest[pos + 0] = (r * ax + r__ * ax_) * ay + (r___ * ax + r_ * ax_) * ay_; + dest[pos + 2] = (r * ax + r__ * ax_) * ay + (r___ * ax + r_ * ax_) * ay_; dest[pos + 1] = (g * ax + g__ * ax_) * ay + (g___ * ax + g_ * ax_) * ay_; - dest[pos + 2] = (b * ax + b__ * ax_) * ay + (b___ * ax + b_ * ax_) * ay_; + dest[pos + 0] = (b * ax + b__ * ax_) * ay + (b___ * ax + b_ * ax_) * ay_; dest[pos + 3] = (a1 * ax + a3 * ax_) * ay + (a4 * ax + a2 * ax_) * ay_; } } + + { + lock_guard l2(mtx2); + image2.fill(Qt::transparent); + std::swap(image, image2); + } + + run_in_thread_async(dst->thread(), [this]() { dst->update(); }); } -vec2 GLWidget::project(const vec3 &point) +vec2 pose_transform::project(const vec3 &point) { vec3 ret = rotation * point; num z = std::max<num>(.75f, 1 + translation.z()/-60); - num w = width(), h = height(); + num w = width, h = height; num x = w * translation.x() / 2 / -40; if (std::abs(x) > w/2) x = x > 0 ? w/2 : w/-2; @@ -282,8 +337,16 @@ vec2 GLWidget::project(const vec3 &point) return vec2(z * (ret.x() + x), z * (ret.y() + y)); } -vec3 GLWidget::project2(const vec3 &point) +vec3 pose_transform::project2(const vec3 &point) { return rotation * point; } + +template<typename F> +inline void pose_transform::with_image_lock(F&& fun) +{ + lock_guard l(mtx2); + + fun(image2); +} |