diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2016-07-21 14:25:03 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2016-07-23 11:05:33 +0200 |
commit | 9fec162fd5ac3f94850653c63f45ed0a83c5a9d0 (patch) | |
tree | 8e5f336af588e01de6fda24d17c3578e66d40636 /pose-widget | |
parent | fbc79e91ce1dd7904a4ed55891bfde38797d0c22 (diff) |
pose-widget: don't do barycentric lookup twice
In the affine transformation (aka the pose widget) of The Octopus we use
barycentric coordinates of two triangles making up The Octopus
rectangle. Triangles are symmetrical.
Take advantage of the symmetry (no perspective transform applied) and
take barycentric coordinates only once.
Diffstat (limited to 'pose-widget')
-rw-r--r-- | pose-widget/glwidget.cpp | 232 | ||||
-rw-r--r-- | pose-widget/glwidget.h | 2 |
2 files changed, 131 insertions, 103 deletions
diff --git a/pose-widget/glwidget.cpp b/pose-widget/glwidget.cpp index b2ec68a7..5de26eef 100644 --- a/pose-widget/glwidget.cpp +++ b/pose-widget/glwidget.cpp @@ -51,44 +51,13 @@ void GLWidget::rotateBy(float xAngle, float yAngle, float zAngle, float x, float update(); } - class Triangle { using num = GLWidget::num; using vec2 = GLWidget::vec2; using vec3 = GLWidget::vec3; public: - Triangle(const vec2& p1, - const vec2& p2, - const vec2& p3) - { - origin = p1; - v0 = vec2(p3.x() - p1.x(), p3.y() - p1.y()); - v1 = vec2(p2.x() - p1.x(), p2.y() - p1.y()); - dot00 = v0.dot(v0); - dot01 = v0.dot(v1); - dot11 = v1.dot(v1); - const num denom = dot00 * dot11 - dot01 * dot01; - if (std::fabs(denom) < 1e3f) - { - // for perpendicular plane, ensure u and v don't come out right - // this is done here to avoid branching below, in a hot loop - invDenom = 0; - dot00 = dot01 = dot11 = 0; - v0 = v1 = vec2(0, 0); - } - else - invDenom = 1 / denom; - } - bool barycentric_coords(const vec2& px, vec2& uv) const - { - const vec2 v2 = px - origin; - const num dot12 = v1.dot(v2); - const num dot02 = v0.dot(v2); - const num u = (dot11 * dot02 - dot01 * dot12) * invDenom; - const num v = (dot00 * dot12 - dot01 * dot02) * invDenom; - uv = vec2(u, v); - return (u >= 0) && (v >= 0) && (u + v <= 1); - } + Triangle(const vec2& p1, const vec2& p2, const vec2& p3); + bool barycentric_coords(const vec2& px, vec2& uv, int& i) const; private: num dot00, dot01, dot11, invDenom; @@ -109,7 +78,56 @@ inline GLWidget::vec3 GLWidget::normal(const vec3& p1, const vec3& p2, const vec return tmp * i; } -void GLWidget::project_quad_texture() { +Triangle::Triangle(const Triangle::vec2& p1, const Triangle::vec2& p2, const Triangle::vec2& p3) +{ + using std::fabs; + + origin = p1; + + v0 = vec2(p3 - p1); + v1 = vec2(p2 - p1); + + dot00 = v0.dot(v0); + dot01 = v0.dot(v1); + dot11 = v1.dot(v1); + + const num denom = dot00 * dot11 - dot01 * dot01; + + if (fabs(denom) < num(1e3)) + { + // for perpendicular plane, ensure u and v don't come out right + // this is done here to avoid branching below, in a hot loop + invDenom = 0; + dot00 = dot01 = dot11 = 0; + v0 = v1 = vec2(0, 0); + } + else + invDenom = 1 / denom; +} + +bool Triangle::barycentric_coords(const Triangle::vec2& px, Triangle::vec2& uv, int& i) const +{ + i = 0; + const vec2 v2 = px - origin; + const num dot12 = v1.dot(v2); + const num dot02 = v0.dot(v2); + num u = (dot11 * dot02 - dot01 * dot12) * invDenom; + num v = (dot00 * dot12 - dot01 * dot02) * invDenom; + if (!(u >= 0 && v >= 0)) + return false; + if (u + v > 1) + { + i = 1; + + u = 1 - u; + v = 1 - v; + } + uv = vec2(u, v); + return u >= 0 && v >= 0 && u + v <= 1; +} + +void GLWidget::project_quad_texture() +{ const int sx = width(), sy = height(); const int ow = front.width(), oh = front.height(); const vec3 corners[] = { @@ -141,12 +159,27 @@ void GLWidget::project_quad_texture() { QColor bgColor = palette().color(QPalette::Current, QPalette::Window); texture.fill(bgColor); - const vec2 projected[2][3] = { { pt[0], pt[1], pt[2] }, { pt[3], pt[1], pt[2] } }; - const vec2 origs[2][3] = { - { vec2(0, 0), vec2(ow-1, 0), vec2(0, oh-1) }, - { vec2(ow-1, oh-1), vec2(ow-1, 0), vec2(0, oh-1) } + const vec2 projected[2][3] = + { + { pt[0], pt[1], pt[2] }, + { pt[3], pt[1], pt[2] } }; - const Triangle triangles[2] = { + + const vec2 origs[2][3] = + { + { + vec2(0, 0), + vec2(ow-1, 0), + vec2(0, oh-1) }, + { + vec2(ow-1, oh-1), + vec2(0, oh-1), + vec2(ow-1, 0) + } + }; + + const Triangle triangles[2] = + { Triangle(projected[0][0], projected[0][1], projected[0][2]), Triangle(projected[1][0], projected[1][1], projected[1][2]) }; @@ -165,70 +198,64 @@ void GLWidget::project_quad_texture() { return; for (int y = 0; y < sy; y++) - for (int x = 0; x < sx; x++) { + for (int x = 0; x < sx; x++) + { vec2 pos(x, y); - for (int i = 0; i < 2; i++) { - vec2 uv; - // XXX knowing center of the lookup pos, - // we have symmetry so only one lookup is needed -sh 20150831 - if (triangles[i].barycentric_coords(pos, uv)) - { - const float fx = origs[i][0].x() - + uv.x() * (origs[i][2].x() - origs[i][0].x()) - + uv.y() * (origs[i][1].x() - origs[i][0].x()); - const float fy = origs[i][0].y() - + uv.x() * (origs[i][2].y() - origs[i][0].y()) - + uv.y() * (origs[i][1].y() - origs[i][0].y()); - - const int px_ = fx + .5f; - const int py_ = fy + .5f; - const int px = fx; - const int py = fy; - const float ax_ = fx - px; - const float ay_ = fy - py; - const float ax = 1.f - ax_; - const float ay = 1.f - ay_; - - // 0, 0 -- ax, ay - const int orig_pos = py * orig_pitch + px * orig_depth; - const unsigned char r = orig[orig_pos + 2]; - const unsigned char g = orig[orig_pos + 1]; - const unsigned char b = orig[orig_pos + 0]; - - // 1, 1 -- ax_, ay_ - const int orig_pos_ = py_ * orig_pitch + px_ * orig_depth; - const unsigned char r_ = orig[orig_pos_ + 2]; - const unsigned char g_ = orig[orig_pos_ + 1]; - const unsigned char b_ = orig[orig_pos_ + 0]; - - // 1, 0 -- ax_, ay - const int orig_pos__ = py * orig_pitch + px_ * orig_depth; - const unsigned char r__ = orig[orig_pos__ + 2]; - const unsigned char g__ = orig[orig_pos__ + 1]; - const unsigned char b__ = orig[orig_pos__ + 0]; - - // 0, 1 -- ax, ay_ - const int orig_pos___ = py_ * orig_pitch + px * orig_depth; - const unsigned char r___ = orig[orig_pos___ + 2]; - const unsigned char g___ = orig[orig_pos___ + 1]; - const unsigned char b___ = orig[orig_pos___ + 0]; - - const unsigned char a1 = orig[orig_pos + 3]; - const unsigned char a2 = orig[orig_pos_ + 3]; - const unsigned char a3 = orig[orig_pos__ + 3]; - const unsigned char a4 = orig[orig_pos___ + 3]; - - const int pos = y * dest_pitch + x * dest_depth; - - //qDebug() << "pos" << fx << fy << "uv" << ax << ay; - - dest[pos + 0] = (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 + 3] = (a1 * ax + a3 * ax_) * ay + (a4 * ax + a2 * ax_) * ay_; - - break; - } + vec2 uv; + int i; + if (triangles[0].barycentric_coords(pos, uv, i)) + { + const float fx = origs[i][0].x() + + uv.x() * (origs[i][2].x() - origs[i][0].x()) + + uv.y() * (origs[i][1].x() - origs[i][0].x()); + const float fy = origs[i][0].y() + + uv.x() * (origs[i][2].y() - origs[i][0].y()) + + uv.y() * (origs[i][1].y() - origs[i][0].y()); + + const int px_ = fx + .5f; + const int py_ = fy + .5f; + const int px = fx; + const int py = fy; + const float ax_ = fx - px; + const float ay_ = fy - py; + const float ax = 1.f - ax_; + const float ay = 1.f - ay_; + + // 0, 0 -- ax, ay + const int orig_pos = py * orig_pitch + px * orig_depth; + const unsigned char r = orig[orig_pos + 2]; + const unsigned char g = orig[orig_pos + 1]; + const unsigned char b = orig[orig_pos + 0]; + + // 1, 1 -- ax_, ay_ + const int orig_pos_ = py_ * orig_pitch + px_ * orig_depth; + const unsigned char r_ = orig[orig_pos_ + 2]; + const unsigned char g_ = orig[orig_pos_ + 1]; + const unsigned char b_ = orig[orig_pos_ + 0]; + + // 1, 0 -- ax_, ay + const int orig_pos__ = py * orig_pitch + px_ * orig_depth; + const unsigned char r__ = orig[orig_pos__ + 2]; + const unsigned char g__ = orig[orig_pos__ + 1]; + const unsigned char b__ = orig[orig_pos__ + 0]; + + // 0, 1 -- ax, ay_ + const int orig_pos___ = py_ * orig_pitch + px * orig_depth; + const unsigned char r___ = orig[orig_pos___ + 2]; + const unsigned char g___ = orig[orig_pos___ + 1]; + const unsigned char b___ = orig[orig_pos___ + 0]; + + const unsigned char a1 = orig[orig_pos + 3]; + const unsigned char a2 = orig[orig_pos_ + 3]; + const unsigned char a3 = orig[orig_pos__ + 3]; + const unsigned char a4 = orig[orig_pos___ + 3]; + + const int pos = y * dest_pitch + x * dest_depth; + + dest[pos + 0] = (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 + 3] = (a1 * ax + a3 * ax_) * ay + (a4 * ax + a2 * ax_) * ay_; } } image = texture; @@ -252,3 +279,4 @@ GLWidget::vec3 GLWidget::project2(const vec3 &point) { return rotation * point; } + diff --git a/pose-widget/glwidget.h b/pose-widget/glwidget.h index 25823985..0d48ede9 100644 --- a/pose-widget/glwidget.h +++ b/pose-widget/glwidget.h @@ -31,7 +31,7 @@ public: ~GLWidget(); void rotateBy(float xAngle, float yAngle, float zAngle, float x, float y, float z); protected: - void paintEvent ( QPaintEvent * event ) override; + void paintEvent (QPaintEvent *event) override; private: vec2 project(const vec3& point); vec3 project2(const vec3& point); |