summaryrefslogtreecommitdiffhomepage
path: root/ftnoir_posewidget
diff options
context:
space:
mode:
Diffstat (limited to 'ftnoir_posewidget')
-rw-r--r--ftnoir_posewidget/glwidget.cpp375
-rw-r--r--ftnoir_posewidget/glwidget.h99
-rw-r--r--ftnoir_posewidget/images/side1.bmpbin44950 -> 0 bytes
-rw-r--r--ftnoir_posewidget/images/side2.pngbin2922 -> 0 bytes
-rw-r--r--ftnoir_posewidget/images/side3.pngbin2922 -> 0 bytes
-rw-r--r--ftnoir_posewidget/images/side4.pngbin2922 -> 0 bytes
-rw-r--r--ftnoir_posewidget/images/side5.pngbin2922 -> 0 bytes
-rw-r--r--ftnoir_posewidget/posewidget.qrc4
8 files changed, 266 insertions, 212 deletions
diff --git a/ftnoir_posewidget/glwidget.cpp b/ftnoir_posewidget/glwidget.cpp
index 32723dc9..375cb97f 100644
--- a/ftnoir_posewidget/glwidget.cpp
+++ b/ftnoir_posewidget/glwidget.cpp
@@ -1,214 +1,229 @@
-/********************************************************************************
-* FaceTrackNoIR This program is a private project of the some enthusiastic *
-* gamers from Holland, who don't like to pay much for *
-* head-tracking. *
-* *
-* Copyright (C) 2010 Wim Vriend (Developing) *
-* Ron Hendriks (Researching and Testing) *
-* *
-* Homepage *
-* *
-* This program is free software; you can redistribute it and/or modify it *
-* under the terms of the GNU General Public License as published by the *
-* Free Software Foundation; either version 3 of the License, or (at your *
-* option) any later version. *
-* *
-* This program is distributed in the hope that it will be useful, but *
-* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
-* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for *
-* more details. *
-* *
-* Adopted this widget from the 'textures' sample of the Nokia Qt toolkit. *
-* *
-* You should have received a copy of the GNU General Public License along *
-* with this program; if not, see <http://www.gnu.org/licenses/>. *
-*********************************************************************************/
+/* Copyright (c) 2013 Stanislaw Halik <sthalik@misaki.pl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ */
#include <QtGui>
-#include <QtOpenGL>
-
#include "glwidget.h"
#include <QWidget>
+#include <cmath>
+#include <algorithm>
-GLWidget::GLWidget(QWidget *parent, QGLWidget *shareWidget)
- : QGLWidget(parent, shareWidget)
+GLWidget::GLWidget(QWidget *parent) : QWidget(parent)
{
-#if !defined(_WIN32)
- setAttribute(Qt::WA_NativeWindow, true);
-#endif
- clearColor = Qt::black;
- xRot = 0;
- yRot = 0;
- zRot = 0;
-
-#ifdef QT_OPENGL_ES_2
- program = 0;
-#endif
+ front = QImage(QString(":/images/side1.png"));
+ back = QImage(QString(":/images/side6.png"));
+ rotateBy(0, 0, 0);
}
GLWidget::~GLWidget()
{
}
-QSize GLWidget::minimumSizeHint() const
-{
- return QSize(60, 60);
-}
-
-QSize GLWidget::sizeHint() const
-{
- return QSize(90, 90);
-}
-
-void GLWidget::rotateBy(int xAngle, int yAngle, int zAngle)
-{
- xRot = xAngle;
- yRot = yAngle;
- zRot = zAngle;
- updateGL();
+void GLWidget::paintEvent ( QPaintEvent * event ) {
+ QWidget::paintEvent(event);
+ QPainter p(this);
+ project_quad_texture();
+ p.drawPixmap(QRect(0, 0, width(), height()), pixmap);
}
-void GLWidget::setClearColor(const QColor &color)
+void GLWidget::rotateBy(double xAngle, double yAngle, double zAngle)
{
- clearColor = color;
- updateGL();
+
+ double ch = cos(xAngle / 57.295781);
+ double sh = sin(xAngle / 57.295781);
+ double ca = cos(yAngle / 57.295781);
+ double sa = sin(yAngle / 57.295781);
+ double cb = cos(zAngle / 57.295781);
+ double sb = sin(zAngle / 57.295781);
+
+ matrix[0 * 3 + 0] = ch * ca;
+ matrix[0 * 3 + 1]= sh*sb - ch*sa*cb;
+ matrix[0 * 3 + 2]= ch*sa*sb + sh*cb;
+ matrix[1 * 3 + 0]= sa;
+ matrix[1 * 3 + 1]= ca*cb;
+ matrix[1 * 3 + 2]= -ca*sb;
+ matrix[2 * 3 + 0]= -sh*ca;
+ matrix[2 * 3 + 1]= sh*sa*cb + ch*sb;
+ matrix[2 * 3 + 2]= -sh*sa*sb + ch*cb;
+ repaint();
}
-void GLWidget::initializeGL()
-{
- makeObject();
-
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
-#ifndef QT_OPENGL_ES_2
- glEnable(GL_TEXTURE_2D);
-#endif
-
-#ifdef QT_OPENGL_ES_2
-
-#define PROGRAM_VERTEX_ATTRIBUTE 0
-#define PROGRAM_TEXCOORD_ATTRIBUTE 1
-
- QGLShader *vshader = new QGLShader(QGLShader::Vertex, this);
- const char *vsrc =
- "attribute highp vec4 vertex;\n"
- "attribute mediump vec4 texCoord;\n"
- "varying mediump vec4 texc;\n"
- "uniform mediump mat4 matrix;\n"
- "void main(void)\n"
- "{\n"
- " gl_Position = matrix * vertex;\n"
- " texc = texCoord;\n"
- "}\n";
- vshader->compileSourceCode(vsrc);
-
- QGLShader *fshader = new QGLShader(QGLShader::Fragment, this);
- const char *fsrc =
- "uniform sampler2D texture;\n"
- "varying mediump vec4 texc;\n"
- "void main(void)\n"
- "{\n"
- " gl_FragColor = texture2D(texture, texc.st);\n"
- "}\n";
- fshader->compileSourceCode(fsrc);
-
- program = new QGLShaderProgram(this);
- program->addShader(vshader);
- program->addShader(fshader);
- program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
- program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);
- program->link();
-
- program->bind();
- program->setUniformValue("texture", 0);
-#else
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, vertices.constData());
- glTexCoordPointer(2, GL_FLOAT, 0, texCoords.constData());
-#endif
+static __inline double dot(const Vec2f& p1, const Vec2f& p2) {
+ return p1.x * p2.x + p1.y * p2.y;
}
-void GLWidget::paintGL()
+static bool barycentric_coords(const Vec2f& p1,
+ const Vec2f& p2,
+ const Vec2f& p3,
+ const Vec2f& px,
+ Vec2f& uv)
{
- glClearColor(0, 0, 0, 1);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-#if 1
+ Vec2f v0(p3.x - p1.x, p3.y - p1.y);
+ Vec2f v1(p2.x - p1.x, p2.y - p1.y);
+ Vec2f v2(px.x - p1.x, px.y - p1.y);
- glLoadIdentity();
- glTranslatef(0.0f, 0.0f, -10.0f);
+ double dot00 = dot(v0, v0);
+ double dot01 = dot(v0, v1);
+ double dot02 = dot(v0, v2);
+ double dot11 = dot(v1, v1);
+ double dot12 = dot(v1, v2);
- glRotatef(xRot, 1.0f, 0.0f, 0.0f);
- glRotatef(yRot, 0.0f, 1.0f, 0.0f);
- glRotatef(-1.0f * zRot, 0.0f, 0.0f, 1.0f);
+ double invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
+ double u = (dot11 * dot02 - dot01 * dot12) * invDenom;
+ double v = (dot00 * dot12 - dot01 * dot02) * invDenom;
-#else
+ uv.x = u;
+ uv.y = v;
- QMatrix4x4 m;
- m.ortho(-0.5f, +0.5f, +0.5f, -0.5f, 4.0f, 15.0f);
- m.translate(0.0f, 0.0f, -10.0f);
- m.rotate(xRot / 16.0f, 1.0f, 0.0f, 0.0f);
- m.rotate(yRot / 16.0f, 0.0f, 1.0f, 0.0f);
- m.rotate(zRot / 16.0f, 0.0f, 0.0f, 1.0f);
-
- program->setUniformValue("matrix", m);
- program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
- program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
- program->setAttributeArray
- (PROGRAM_VERTEX_ATTRIBUTE, vertices.constData());
- program->setAttributeArray
- (PROGRAM_TEXCOORD_ATTRIBUTE, texCoords.constData());
-
-#endif
-
- for (int i = 0; i < 6; ++i) {
- glBindTexture(GL_TEXTURE_2D, textures[i]);
- glDrawArrays(GL_TRIANGLE_FAN, i * 4, 4);
- }
- glFlush();
+ return (u >= 0) && (v >= 0) && (u + v <= 1);
}
-void GLWidget::resizeGL(int width, int height)
+static __inline Vec3f normal(const Vec3f& p1, const Vec3f& p2, const Vec3f& p3)
{
- int side = qMin(width, height);
- glViewport((width - side) / 2, (height - side) / 2, side, side);
-
-#if !defined(QT_OPENGL_ES_2)
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
-#ifndef QT_OPENGL_ES
- glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0);
-#else
- glOrthof(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0);
-#endif
- glMatrixMode(GL_MODELVIEW);
-#endif
+ Vec3f u(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z);
+ Vec3f v(p3.x - p1.x, p3.y - p1.y, p3.z - p1.z);
+
+ Vec3f tmp(u.y * v.z - u.z * v.y,
+ u.z * v.x - u.x * v.z,
+ u.x * v.y - u.y * v.x);
+
+ double i = 1./sqrt(tmp.x * tmp.x + tmp.y * tmp.y + tmp.z * tmp.z);
+
+ return Vec3f(i * tmp.x, i * tmp.y, i * tmp.z);
}
-void GLWidget::makeObject()
+static __inline Vec3f cross(const Vec3f& p1, const Vec3f& p2)
{
- static const int coords[6][4][3] = {
- { { +1, -1, -1 }, { -1, -1, -1 }, { -1, +1, -1 }, { +1, +1, -1 } },
- { { +1, +1, -1 }, { -1, +1, -1 }, { -1, +1, +1 }, { +1, +1, +1 } },
- { { +1, -1, +1 }, { +1, -1, -1 }, { +1, +1, -1 }, { +1, +1, +1 } },
- { { -1, -1, -1 }, { -1, -1, +1 }, { -1, +1, +1 }, { -1, +1, -1 } },
- { { +1, -1, +1 }, { -1, -1, +1 }, { -1, -1, -1 }, { +1, -1, -1 } },
- { { -1, -1, +1 }, { +1, -1, +1 }, { +1, +1, +1 }, { -1, +1, +1 } }
- };
+ return Vec3f(p1.y * p2.z - p2.y * p1.z,
+ p2.x * p1.z - p1.x * p2.z,
+ p1.x * p2.y - p1.y * p2.x);
+}
- for (int j=0; j < 6; ++j) {
- textures[j] = bindTexture
- (QPixmap(QString(":/images/side%1.png").arg(j + 1)), GL_TEXTURE_2D);
+void GLWidget::project_quad_texture() {
+ const int sx = 90, sy = 90;
+ Point pt[4];
+ static Vec3f corners[] = {
+ Vec3f(0, 0, 0),
+ Vec3f(sx-1, 0, 0),
+ Vec3f(0, sy-1, 0),
+ Vec3f(sx-1, sy-1, 0)
+ };
+
+ for (int i = 0; i < 4; i++) {
+ pt[i] = project(Vec3f(corners[i].x - sx/2, corners[i].y - sy/2, 0));
+ pt[i].x += sx/2;
+ pt[i].y += sy/2;
}
-
- for (int i = 0; i < 6; ++i) {
- for (int j = 0; j < 4; ++j) {
- texCoords.append
- (QVector2D(j == 0 || j == 3, j == 0 || j == 1));
- vertices.append
- (QVector3D(0.4 * coords[i][j][0], 0.4 * coords[i][j][1],
- 0.02 * coords[i][j][2]));
- }
+
+ Vec3f normal1(0, 0, 1);
+ Vec3f normal2;
+ {
+ Vec3f foo[3];
+ for (int i = 0; i < 3; i++)
+ foo[i] = project2(corners[i]);
+ normal2 = normal(foo[0], foo[1], foo[2]);
}
+
+ double dir = normal1.x * normal2.x + normal1.y * normal2.y + normal1.z * normal2.z;
+
+ QImage& tex = dir < 0 ? back : front;
+
+ int ow = tex.width(), oh = tex.height();
+
+ Vec2f p2[4];
+
+ for (int i = 0; i < 4; i++)
+ p2[i] = Vec2f(pt[i].x, pt[i].y);
+
+ QImage texture(QSize(sx, sy), QImage::Format_RGB888);
+ texture.fill(Qt::black);
+
+ const Vec2f projected[2][3] = { { p2[0], p2[1], p2[2] }, { p2[3], p2[1], p2[2] } };
+ const Vec2f origs[2][3] = {
+ { Vec2f(0, 0), Vec2f(ow-1, 0), Vec2f(0, oh-1) },
+ { Vec2f(ow-1, oh-1), Vec2f(ow-1, 0), Vec2f(0, oh-1) }
+ };
+
+ double sqrt2 = std::sqrt(2.0);
+ int orig_pitch = tex.bytesPerLine();
+ int dest_pitch = texture.bytesPerLine();
+
+ const unsigned char* orig = tex.bits();
+ unsigned char* dest = texture.bits();
+
+ int orig_depth = tex.depth() / 8;
+ int dest_depth = texture.depth() / 8;
+
+ /* image breakage? */
+ if (orig_depth < 3)
+ return;
+
+ for (int y = 0; y < sy; y++)
+ for (int x = 0; x < sx; x++) {
+ Vec2f pos;
+ pos.x = x;
+ pos.y = y;
+ for (int i = 0; i < 2; i++) {
+ Vec2f coords;
+ if (barycentric_coords(projected[i][0],
+ projected[i][1],
+ projected[i][2],
+ pos,
+ coords))
+ {
+ double qx = origs[i][0].x
+ + coords.x * (origs[i][2].x - origs[i][0].x)
+ + coords.y * (origs[i][1].x - origs[i][0].x);
+ double qy = origs[i][0].y
+ + coords.x * (origs[i][2].y - origs[i][0].y)
+ + coords.y * (origs[i][1].y - origs[i][0].y);
+ int qx1 = std::min<int>(ow - 1, std::max<int>(0, qx - 0.5));
+ int qy1 = std::min<int>(oh - 1, std::max<int>(0, qy - 0.5));
+ int qx2 = std::min<int>(ow - 1, std::max<int>(0, qx + 0.5));
+ int qy2 = std::min<int>(oh - 1, std::max<int>(0, qy + 0.5));
+
+ double dx1 = qx1 - qx;
+ double dy1 = qy1 - qy;
+ double dx2 = qx2 - qx;
+ double dy2 = qy2 - qy;
+
+ double d1 = sqrt2 - std::sqrt(dx1 * dx1 + dy1 * dy1);
+ double d2 = sqrt2 - std::sqrt(dx2 * dx2 + dy2 * dy2);
+ double d3 = sqrt2 - std::sqrt(dx2 * dx2 + dy1 * dy1);
+ double d4 = sqrt2 - std::sqrt(dx1 * dx1 + dy2 * dy2);
+
+ double inv_norm = 1. / (d1 + d2 + d3 + d4);
+
+ d1 *= inv_norm;
+ d2 *= inv_norm;
+ d3 *= inv_norm;
+ d4 *= inv_norm;
+
+ double r = d1 * (double) orig[qy1 * orig_pitch + qx1 * orig_depth + 2]
+ + d2 * (double) orig[qy2 * orig_pitch + qx2 * orig_depth + 2]
+ + d3 * (double) orig[qy1 * orig_pitch + qx2 * orig_depth + 2]
+ + d4 * (double) orig[qy2 * orig_pitch + qx1 * orig_depth + 2];
+
+ double g = d1 * (double) orig[qy1 * orig_pitch + qx1 * orig_depth + 1]
+ + d2 * (double) orig[qy2 * orig_pitch + qx2 * orig_depth + 1]
+ + d3 * (double) orig[qy1 * orig_pitch + qx2 * orig_depth + 1]
+ + d4 * (double) orig[qy2 * orig_pitch + qx1 * orig_depth + 1];
+
+ double b = d1 * (double) orig[qy1 * orig_pitch + qx1 * orig_depth + 0]
+ + d2 * (double) orig[qy2 * orig_pitch + qx2 * orig_depth + 0]
+ + d3 * (double) orig[qy1 * orig_pitch + qx2 * orig_depth + 0]
+ + d4 * (double) orig[qy2 * orig_pitch + qx1 * orig_depth + 0];
+
+ dest[y * dest_pitch + x * dest_depth + 0] = std::max<int>(0, std::min<int>(255, r));
+ dest[y * dest_pitch + x * dest_depth + 1] = std::max<int>(0, std::min<int>(255, g));
+ dest[y * dest_pitch + x * dest_depth + 2] = std::max<int>(0, std::min<int>(255, b));
+
+ break;
+ }
+ }
}
+ pixmap = QPixmap::fromImage(texture);
+} \ No newline at end of file
diff --git a/ftnoir_posewidget/glwidget.h b/ftnoir_posewidget/glwidget.h
index 3d0e590a..9525f7d4 100644
--- a/ftnoir_posewidget/glwidget.h
+++ b/ftnoir_posewidget/glwidget.h
@@ -28,46 +28,89 @@
#define GLWIDGET_H
#include <QtGui>
-#include <QGLWidget>
+#include <QPixmap>
#include "ftnoir_tracker_base/ftnoir_tracker_base.h"
-class QGLShaderProgram;
+struct Point {
+ Point(int x, int y) :
+ x(x), y(y)
+ {
+ }
+ Point() :
+ x(0), y(0)
+ {
+ }
+ int x, y;
+};
+
+struct Vec3f {
+ double x, y, z;
+ Vec3f(double x, double y, double z) :
+ x(x), y(y), z(z)
+ {
+ }
+ Vec3f() :
+ x(0), y(0), z(0)
+ {
+ }
+};
-class FTNOIR_TRACKER_BASE_EXPORT GLWidget : public QGLWidget
+struct Vec2f {
+ double x, y;
+ Vec2f(double x, double y) :
+ x(x), y(y)
+ {
+ }
+ Vec2f() :
+ x(0), y(0)
+ {
+ }
+};
+
+class FTNOIR_TRACKER_BASE_EXPORT GLWidget : public QWidget
{
Q_OBJECT
public:
- GLWidget(QWidget *parent = 0, QGLWidget *shareWidget = 0);
+ GLWidget(QWidget *parent);
~GLWidget();
-
- QSize minimumSizeHint() const;
- QSize sizeHint() const;
- void rotateBy(int xAngle, int yAngle, int zAngle);
- void setClearColor(const QColor &color);
-
-signals:
- void clicked();
-
+ void rotateBy(double xAngle, double yAngle, double zAngle);
+
protected:
- void initializeGL();
- void paintGL();
- void resizeGL(int width, int height);
+ void paintEvent ( QPaintEvent * event );
private:
- void makeObject();
+ Point project(const Vec3f& point) {
+ Point rect;
- QColor clearColor;
- QPoint lastPos;
- int xRot;
- int yRot;
- int zRot;
- GLuint textures[6];
- QVector<QVector3D> vertices;
- QVector<QVector2D> texCoords;
-#ifdef QT_OPENGL_ES_2
- QGLShaderProgram *program;
-#endif
+ rect.x = point.x * matrix[0]
+ + point.y * matrix[1]
+ + point.z * matrix[2];
+ rect.y = point.x * matrix[3]
+ + point.y * matrix[4]
+ + point.z * matrix[5];
+
+ return rect;
+ }
+ Vec3f project2(const Vec3f& point) {
+ Vec3f rect;
+
+ rect.x = point.x * matrix[0]
+ + point.y * matrix[1]
+ + point.z * matrix[2];
+ rect.y = point.x * matrix[3]
+ + point.y * matrix[4]
+ + point.z * matrix[5];
+ rect.z = point.x * matrix[6]
+ + point.y * matrix[7]
+ + point.z * matrix[8];
+ return rect;
+ }
+ void project_quad_texture();
+ double matrix[9];
+ QImage front;
+ QImage back;
+ QPixmap pixmap;
};
#endif
diff --git a/ftnoir_posewidget/images/side1.bmp b/ftnoir_posewidget/images/side1.bmp
deleted file mode 100644
index 29c28d80..00000000
--- a/ftnoir_posewidget/images/side1.bmp
+++ /dev/null
Binary files differ
diff --git a/ftnoir_posewidget/images/side2.png b/ftnoir_posewidget/images/side2.png
deleted file mode 100644
index 67eb060b..00000000
--- a/ftnoir_posewidget/images/side2.png
+++ /dev/null
Binary files differ
diff --git a/ftnoir_posewidget/images/side3.png b/ftnoir_posewidget/images/side3.png
deleted file mode 100644
index 67eb060b..00000000
--- a/ftnoir_posewidget/images/side3.png
+++ /dev/null
Binary files differ
diff --git a/ftnoir_posewidget/images/side4.png b/ftnoir_posewidget/images/side4.png
deleted file mode 100644
index 67eb060b..00000000
--- a/ftnoir_posewidget/images/side4.png
+++ /dev/null
Binary files differ
diff --git a/ftnoir_posewidget/images/side5.png b/ftnoir_posewidget/images/side5.png
deleted file mode 100644
index 67eb060b..00000000
--- a/ftnoir_posewidget/images/side5.png
+++ /dev/null
Binary files differ
diff --git a/ftnoir_posewidget/posewidget.qrc b/ftnoir_posewidget/posewidget.qrc
index 65038eba..e799432f 100644
--- a/ftnoir_posewidget/posewidget.qrc
+++ b/ftnoir_posewidget/posewidget.qrc
@@ -1,10 +1,6 @@
<RCC>
<qresource prefix="/">
<file>images/side1.png</file>
- <file>images/side2.png</file>
- <file>images/side3.png</file>
- <file>images/side4.png</file>
- <file>images/side5.png</file>
<file>images/side6.png</file>
</qresource>
</RCC>