summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2016-07-21 14:25:03 +0200
committerStanislaw Halik <sthalik@misaki.pl>2016-07-23 11:05:33 +0200
commit9fec162fd5ac3f94850653c63f45ed0a83c5a9d0 (patch)
tree8e5f336af588e01de6fda24d17c3578e66d40636
parentfbc79e91ce1dd7904a4ed55891bfde38797d0c22 (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.
-rw-r--r--pose-widget/glwidget.cpp232
-rw-r--r--pose-widget/glwidget.h2
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);