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); +} | 
