diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2017-04-06 01:53:59 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2017-04-06 04:21:41 +0200 |
commit | facfc0e2444e485d6e14b6b96462ef0acefb42c0 (patch) | |
tree | 298df22ddb9eb4c001521a9319f35e195e500905 /pose-widget | |
parent | 2d4570810c861606c38330d90137d856b8862d02 (diff) |
pose-widget: prevent races and serial execution
We actually need to use "mtx" with the condition variable and
copy the data to the worker thread's stack.
Also allow for synchronous pose update, for tracking stoppage.
Diffstat (limited to 'pose-widget')
-rw-r--r-- | pose-widget/pose-widget.cpp | 73 | ||||
-rw-r--r-- | pose-widget/pose-widget.hpp | 21 |
2 files changed, 60 insertions, 34 deletions
diff --git a/pose-widget/pose-widget.cpp b/pose-widget/pose-widget.cpp index a0653f17..e711a617 100644 --- a/pose-widget/pose-widget.cpp +++ b/pose-widget/pose-widget.cpp @@ -23,16 +23,14 @@ pose_transform::pose_transform(QWidget* dst) : image2(w, h, QImage::Format_ARGB32), width(w), height(h) { + fresh.clear(std::memory_order_seq_cst); + front = QImage(QString(":/images/side1.png")); back = QImage(QString(":/images/side6.png")); image.fill(Qt::transparent); image2.fill(Qt::transparent); - rotateBy(0, 0, 0, 0, 0, 0, QSize(w, h)); - - project_quad_texture(); - start(); } @@ -57,15 +55,15 @@ void pose_transform::run() if (isInterruptionRequested()) break; - static struct cruft { - void lock() {} - void unlock() {} - } not_a_mutex; + lock_guard l(mtx); + const cv_status st = cvar.wait_for(l, std::chrono::milliseconds(2000)); + if (st == cv_status::timeout) + continue; - const cv_status st = cvar.wait_for(not_a_mutex, std::chrono::milliseconds(2000)); - if (st == cv_status::timeout) - continue; + rotation = rotation_; + translation = translation_; + } project_quad_texture(); } @@ -73,18 +71,22 @@ void pose_transform::run() pose_widget::pose_widget(QWidget* parent) : QWidget(parent), xform(this) { + rotate_sync(0,0,0, 0,0,0); } pose_widget::~pose_widget() { } -void pose_widget::rotateBy(double xAngle, double yAngle, double zAngle, double x, double y, double z) +void pose_widget::rotate_async(double xAngle, double yAngle, double zAngle, double x, double y, double z) { - xform.rotateBy(xAngle, yAngle, zAngle, x, y, z, size()); + if (!xform.fresh.test_and_set(std::memory_order_seq_cst)) + update(); + xform.rotate_async(xAngle, yAngle, zAngle, x, y, z); } -void pose_transform::rotateBy(double xAngle, double yAngle, double zAngle, double x, double y, double z, const QSize& size) +template<typename F> +void pose_transform::with_rotate(F&& fun, double xAngle, double yAngle, double zAngle, double x, double y, double z) { using std::sin; using std::cos; @@ -98,11 +100,31 @@ void pose_transform::rotateBy(double xAngle, double yAngle, double zAngle, doubl for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) - rotation(i, j) = num(r(i, j)); + rotation_(i, j) = num(r(i, j)); - translation = vec3(x, y, z); + translation_ = vec3(x, y, z); - cvar.notify_one(); + fun(); +} + +void pose_widget::rotate_sync(double xAngle, double yAngle, double zAngle, double x, double y, double z) +{ + xform.rotate_sync(xAngle, yAngle, zAngle, x, y, z); +} + +void pose_transform::rotate_async(double xAngle, double yAngle, double zAngle, double x, double y, double z) +{ + with_rotate([this]() { cvar.notify_one(); }, xAngle, yAngle, zAngle, x, y, z); +} + +void pose_transform::rotate_sync(double xAngle, double yAngle, double zAngle, double x, double y, double z) +{ + with_rotate([this]() { + rotation = rotation_; + translation = translation_; + project_quad_texture(); + dst->repaint(); + }, xAngle, yAngle, zAngle, x, y, z); } class Triangle { @@ -182,8 +204,6 @@ void pose_transform::project_quad_texture() 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; @@ -318,21 +338,22 @@ void pose_transform::project_quad_texture() lock_guard l2(mtx2); image2.fill(Qt::transparent); std::swap(image, image2); + fresh.clear(); } - - run_in_thread_async(dst->thread(), [this]() { dst->update(); }); } vec2 pose_transform::project(const vec3 &point) { + using std::fabsf; + vec3 ret = rotation * point; - num z = std::max<num>(.75f, 1 + translation.z()/-60); + num z = std::max<num>(.5, 1 + translation.z()/-80); num w = width, h = height; - num x = w * translation.x() / 2 / -40; - if (std::abs(x) > w/2) + num x = w * translation.x() / 2 / -80; + if (fabsf(x) > w/2) x = x > 0 ? w/2 : w/-2; - num y = h * translation.y() / 2 / -40; - if (std::abs(y) > h/2) + num y = h * translation.y() / 2 / -80; + if (fabsf(y) > h/2) y = y > 0 ? h/2 : h/-2; return vec2(z * (ret.x() + x), z * (ret.y() + y)); } diff --git a/pose-widget/pose-widget.hpp b/pose-widget/pose-widget.hpp index 4f50008e..7befe72d 100644 --- a/pose-widget/pose-widget.hpp +++ b/pose-widget/pose-widget.hpp @@ -16,6 +16,7 @@ #include <mutex> #include <condition_variable> +#include <atomic> #ifdef BUILD_POSE_WIDGET # define POSE_WIDGET_EXPORT Q_DECL_EXPORT @@ -46,9 +47,11 @@ class pose_transform final : private QThread friend class pose_widget; - void rotateBy(double xAngle, double yAngle, double zAngle, - double x, double y, double z, - const QSize& size); + void rotate_async(double xAngle, double yAngle, double zAngle, double x, double y, double z); + void rotate_sync(double xAngle, double yAngle, double zAngle, double x, double y, double z); + + template<typename F> + void with_rotate(F&& fun, double xAngle, double yAngle, double zAngle, double x, double y, double z); void run() override; @@ -61,10 +64,10 @@ class pose_transform final : private QThread static vec3 normal(const vec3& p1, const vec3& p2, const vec3& p3); - rmat rotation; - vec3 translation; + rmat rotation, rotation_; + vec3 translation, translation_; - std::condition_variable_any cvar; + std::condition_variable cvar; std::mutex mtx, mtx2; QWidget* dst; @@ -74,6 +77,8 @@ class pose_transform final : private QThread int width, height; + std::atomic_flag fresh; + static constexpr int w = 320, h = 240; }; @@ -82,8 +87,8 @@ class POSE_WIDGET_EXPORT pose_widget final : public QWidget public: pose_widget(QWidget *parent = nullptr); ~pose_widget(); - void rotateBy(double xAngle, double yAngle, double zAngle, - double x, double y, double z); + void rotate_async(double xAngle, double yAngle, double zAngle, double x, double y, double z); + void rotate_sync(double xAngle, double yAngle, double zAngle, double x, double y, double z); private: pose_transform xform; |