From bf45260ce8f235e593a22cdbdf9bcd98d508ae7f Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 27 Apr 2013 11:25:41 +0200 Subject: WIP: rewrite the GL widget in pure software mode --- ftnoir_posewidget/glwidget.cpp | 375 +++++++++++++++++++------------------ ftnoir_posewidget/glwidget.h | 99 +++++++--- ftnoir_posewidget/images/side1.bmp | Bin 44950 -> 0 bytes ftnoir_posewidget/images/side2.png | Bin 2922 -> 0 bytes ftnoir_posewidget/images/side3.png | Bin 2922 -> 0 bytes ftnoir_posewidget/images/side4.png | Bin 2922 -> 0 bytes ftnoir_posewidget/images/side5.png | Bin 2922 -> 0 bytes ftnoir_posewidget/posewidget.qrc | 4 - 8 files changed, 266 insertions(+), 212 deletions(-) delete mode 100644 ftnoir_posewidget/images/side1.bmp delete mode 100644 ftnoir_posewidget/images/side2.png delete mode 100644 ftnoir_posewidget/images/side3.png delete mode 100644 ftnoir_posewidget/images/side4.png delete mode 100644 ftnoir_posewidget/images/side5.png (limited to 'ftnoir_posewidget') 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 . * -*********************************************************************************/ +/* Copyright (c) 2013 Stanislaw Halik + * + * 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 -#include - #include "glwidget.h" #include +#include +#include -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(ow - 1, std::max(0, qx - 0.5)); + int qy1 = std::min(oh - 1, std::max(0, qy - 0.5)); + int qx2 = std::min(ow - 1, std::max(0, qx + 0.5)); + int qy2 = std::min(oh - 1, std::max(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(0, std::min(255, r)); + dest[y * dest_pitch + x * dest_depth + 1] = std::max(0, std::min(255, g)); + dest[y * dest_pitch + x * dest_depth + 2] = std::max(0, std::min(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 -#include +#include #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 vertices; - QVector 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 Binary files a/ftnoir_posewidget/images/side1.bmp and /dev/null differ diff --git a/ftnoir_posewidget/images/side2.png b/ftnoir_posewidget/images/side2.png deleted file mode 100644 index 67eb060b..00000000 Binary files a/ftnoir_posewidget/images/side2.png and /dev/null differ diff --git a/ftnoir_posewidget/images/side3.png b/ftnoir_posewidget/images/side3.png deleted file mode 100644 index 67eb060b..00000000 Binary files a/ftnoir_posewidget/images/side3.png and /dev/null differ diff --git a/ftnoir_posewidget/images/side4.png b/ftnoir_posewidget/images/side4.png deleted file mode 100644 index 67eb060b..00000000 Binary files a/ftnoir_posewidget/images/side4.png and /dev/null differ diff --git a/ftnoir_posewidget/images/side5.png b/ftnoir_posewidget/images/side5.png deleted file mode 100644 index 67eb060b..00000000 Binary files a/ftnoir_posewidget/images/side5.png and /dev/null 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 @@ images/side1.png - images/side2.png - images/side3.png - images/side4.png - images/side5.png images/side6.png -- cgit v1.2.3