PARP Research Group University of Murcia, Spain


src/qvgui/qvglcanvas.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007, 2008. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00024 
00025 #include <QMouseEvent>
00026 
00027 #include <qvipp.h>
00028 #include <qvdefines.h>
00029 #include <qvmatrixalgebra.h>
00030 
00031 #include <qvgui/qvglcanvas.h>
00032 
00033 #define GL_VIEW_ASPECT   1.333
00034 
00035 
00036 QVGLCanvas::QVGLCanvas(const QString &title, float worldx1, float worldy1, float worldz1, float worldx2, float worldy2, float worldz2, bool dr_box, bool dr_center, QWidget* parent) : QGLWidget(parent), wx1(worldx1), wy1(worldy1), wz1(worldz1), wx2(worldx2), wy2(worldy2), wz2(worldz2), trackballQuat(QVQuaternion::trackball(0.0, 0.0, 0.0, 0.0)), dr_box(dr_box), dr_center(dr_center), zoom(45), pressedleft(FALSE), pressedright(FALSE)
00037 {
00038         widex = wx2-wx1;
00039         widey = wy2-wy1;
00040         widez = wz2-wz1;
00041 
00042         maxwide = (widex>widey) ? widex : widey;
00043         maxwide = (widez>maxwide) ? widez : maxwide;
00044 
00045         cx = (wx1+wx2)/2;
00046         cy = (wy1+wy2)/2;
00047         cz = (wz1+wz2)/2;
00048 
00049         resize(400,(int)(400/GL_VIEW_ASPECT));
00050         setWindowTitle(title);
00051         show();
00052 }
00053 
00054 QVGLCanvas::~QVGLCanvas ()
00055         {
00056         // FIXME: is it needed?: makeCurrent(); 
00057         }
00058 
00062 void QVGLCanvas::linkModelMatrix(QVWorker &worker, const QString &matrixPropertyName, const QString &objectName)
00063         {
00065         worker.linkProperty(matrixPropertyName, this, objectName + " matrix", QVWorker::AsynchronousLink);
00066 
00068         QObject::connect(&worker, SIGNAL(endIteration(uint, int)), this, SLOT(updateGL()));
00069         }
00070 
00071 void QVGLCanvas::add(const QV3DModel &model, const QString &name)
00072         {
00073         addProperty<QV3DModel>(name, inputFlag | outputFlag, model, name + " 3d object model");
00074         addProperty<QVMatrix>(name + " matrix", inputFlag | outputFlag, QVMatrix::identity(4), name + " 3d location matrix");
00075         }
00076 
00077 void QVGLCanvas::initializeGL()
00078         {
00079         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00080 
00081         glDisable(GL_CULL_FACE);
00082         glEnable(GL_DEPTH_TEST);
00083         
00084         glEnable(GL_DITHER);
00085         glShadeModel(GL_SMOOTH);
00086         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
00087         glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
00088         
00089         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
00090         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
00091         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
00092 
00093         glEnable(GL_DEPTH_TEST);
00094         glEnable(GL_CULL_FACE);
00095         glEnable(GL_TEXTURE_2D);
00096 
00097         init();
00098         }
00099 
00100 void QVGLCanvas::drawModels()
00101         {
00102         readInputProperties();
00103 
00104         glScaled((GLdouble)1/maxwide,(GLdouble)1/maxwide,(GLdouble)1/maxwide);
00105 
00106         foreach(QString name, getPropertyListByType<QV3DModel>())
00107                 {
00108                 QV3DModel model = getPropertyValue<QV3DModel>(name);
00109                 QVMatrix matrix = getPropertyValue<QVMatrix>(name + " matrix");
00110 
00111                 //std::cout << "maxwide = " << maxwide << std::endl;
00112                 //std::cout << "Matrix = " << matrix << std::endl;
00113                 //std::cout << "Model: '" << qPrintable(name) << "'." << std::endl;
00114                 if (matrix.getCols() == 4 && matrix.getRows() == 4)
00115                         {
00116                         glPushMatrix();
00117 
00119                         GLfloat m[4][4];
00120                         QVMatrix M = pseudoInverse(matrix);
00121 
00122                         for (int i=0; i <4; i++)
00123                                 for (int j=0; j <4; j++)
00124                                         m[i][j] = matrix(i,j);
00125 
00126                         for (int i=0; i <3; i++)
00127                                 { m[3][i] = 0; m[i][3] = 0; }
00128 
00129                         glTranslated(-M(0,3), -M(1,3), -M(2,3));
00130 
00131                         glMultMatrixf(&m[0][0]);
00132                         
00133                         model.paint(*this);
00134                         glPopMatrix();
00135 
00136                         glFlush();
00137                         }
00138                 else
00139                         model.paint(*this);
00140                 }
00141         }
00142 
00143 
00144 void QVGLCanvas::draw_center_of_rotation()
00145         {
00146         /* Yellow cross: (center of rotation). */
00147         glBegin(GL_LINES);
00148                 glColor3ub(255,255,0);
00149                 
00150                 glVertex3f(cx-maxwide/20,cy,cz);
00151                 glVertex3f(cx+maxwide/20,cy,cz);
00152                 
00153                 glVertex3f(cx,cy-maxwide/20,cz);
00154                 glVertex3f(cx,cy+maxwide/20,cz);
00155                 
00156                 glVertex3f(cx,cy,cz-maxwide/20);
00157                 glVertex3f(cx,cy,cz+maxwide/20);
00158         glEnd();
00159         }
00160 
00161 void QVGLCanvas::draw_world_box()
00162         {
00163         glBegin(GL_LINES);
00164         /* X, Y and Z Axis = Red, Green, Blue: */
00165                 glColor3ub(255,0,0);
00166                 glVertex3f(wx1,wy1,wz1);
00167                 glVertex3f(wx2,wy1,wz1);
00168                 
00169                 glColor3ub(0,255,0);
00170                 glVertex3f(wx1,wy1,wz1);
00171                 glVertex3f(wx1,wy2,wz1); 
00172                 
00173                 glColor3ub(0,0,255);
00174                 glVertex3f(wx1,wy1,wz1);
00175                 glVertex3f(wx1,wy1,wz2);
00176                 
00177                 glColor3ub(255,255,255);
00178                 
00179                 glVertex3f(wx2,wy1,wz1);
00180                 glVertex3f(wx2,wy2,wz1);
00181                 
00182                 glVertex3f(wx2,wy1,wz1);
00183                 glVertex3f(wx2,wy1,wz2);
00184                 
00185                 glVertex3f(wx1,wy2,wz1);
00186                 glVertex3f(wx2,wy2,wz1);
00187                 
00188                 glVertex3f(wx1,wy2,wz1);
00189                 glVertex3f(wx1,wy2,wz2);
00190                 
00191                 glVertex3f(wx1,wy1,wz2);
00192                 glVertex3f(wx1,wy2,wz2);
00193                 
00194                 glVertex3f(wx1,wy1,wz2);
00195                 glVertex3f(wx2,wy1,wz2);
00196                 
00197                 glVertex3f(wx1,wy2,wz2);
00198                 glVertex3f(wx2,wy2,wz2);
00199                 
00200                 glVertex3f(wx2,wy1,wz2);
00201                 glVertex3f(wx2,wy2,wz2);
00202                 
00203                 glVertex3f(wx2,wy2,wz1);
00204                 glVertex3f(wx2,wy2,wz2);
00205         glEnd();
00206         }
00207 
00208 
00209 
00210 
00211 void QVGLCanvas::paintGL()
00212         {
00213         glMatrixMode(GL_PROJECTION);
00214 
00215         glLoadIdentity();
00216         gluPerspective(zoom,(float)size().width()/(float)size().height(),1,100);
00217         glMatrixMode(GL_MODELVIEW);
00218 
00219         glClearColor(.5, .5, .75, 1.0);
00220         glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
00221 
00222         glLoadIdentity();
00223         
00224         glTranslatef(0,0,-4); 
00225         glScaled((GLdouble)1/maxwide,(GLdouble)1/maxwide,(GLdouble)1/maxwide);
00226 
00227         GLfloat m[4][4];
00228         QVMatrix M(trackballQuat);
00229 
00230         for (int i=0; i <4; i++)
00231                 for (int j=0; j <4; j++)
00232                         m[i][j] = M(i,j);
00233 
00234         glMultMatrixf(&m[0][0]);
00235         
00236         glRotatef(270,1,0,0); 
00237         
00238         glTranslatef(-cx,-cy,-cz); 
00239 
00240         if(dr_box)
00241                 draw_world_box();
00242         if(dr_center)
00243                 draw_center_of_rotation();
00244 
00245         drawModels();
00246 
00247         display();
00248         }
00249 
00250 void QVGLCanvas::resizeGL( int w, int h )
00251         {
00252         glViewport(0,0,w,h); 
00253         reshape(w,h);
00254 
00255         drawModels();
00256         }
00257 
00261 
00262 void QVGLCanvas::mousePressEvent(QMouseEvent *event)
00263 {
00264     beginx = event->x();
00265     beginy = event->y();
00266     if(event->button() == Qt::LeftButton) {
00267         pressedleft = TRUE;
00268     } else if(event->button() == Qt::RightButton) {
00269         pressedright = TRUE;
00270     }
00271 }
00272 
00273 void QVGLCanvas::mouseReleaseEvent(QMouseEvent *event)
00274 {
00275     if(event->button() == Qt::LeftButton) {
00276         pressedleft = FALSE;
00277     } else if(event->button() == Qt::RightButton) {
00278         pressedright = FALSE;
00279     }
00280 }
00281 
00282 void QVGLCanvas::mouseMoveEvent(QMouseEvent *event)
00283 {
00284     int x,y;
00285 
00286     x = (int) event->x();
00287     y = (int) event->y();
00288 
00289     if (pressedleft) {
00290         QVQuaternion spinQuat = QVQuaternion::trackball(
00291                         (2.0*beginx - size().width())   / size().width(),
00292                         (size().height() - 2.0*beginy)  / size().height(),
00293                         (2.0*x - size().width())        / size().width(),
00294                         (size().height() - 2.0*y)       / size().height());
00295 
00296         trackballQuat = spinQuat * trackballQuat;
00297         updateGL();
00298     }
00299 
00300     if (pressedright) {
00301         /* zooming drag */
00302         //printf("MouseMove right button\n");
00303         zoom += ((y - beginy) / size().height()) * 40;
00304         if (zoom < 5) zoom = 5;
00305         if (zoom > 120) zoom = 120;
00306         /* zoom has changed, redraw  */
00307         updateGL();
00308     }
00309     beginx = x;
00310     beginy = y;
00311 }
00312 
00313 void QVGLCanvas::wheelEvent(QWheelEvent *event)
00314 {
00315     /* zooming wheel */
00316     zoom -= event->delta()/32;
00317     if (zoom < 5) zoom = 5;
00318     if (zoom > 120) zoom = 120;
00319     /* zoom has changed, redraw  */
00320     updateGL();
00321 }
00322 
00323 
00324 
00325 void QVGLCanvas::keyPressEvent(QKeyEvent *event)
00326 {
00327     //printf("KeyPress\n");
00328     switch(event->key()) {
00329       case Qt::Key_Left:
00330         cx -= maxwide/20;
00331         break;
00332       case Qt::Key_Right:
00333         cx += maxwide/20;
00334         break;
00335       case Qt::Key_Up:
00336         cy += maxwide/20;
00337         break;
00338       case Qt::Key_Down:
00339         cy -= maxwide/20;
00340         break;
00341       case Qt::Key_PageUp:
00342         cz += maxwide/20;
00343         break;
00344       case Qt::Key_PageDown:
00345         cz -= maxwide/20;
00346         break;
00347       case 'C':
00348         dr_center = not dr_center;
00349         break;
00350       case 'B':
00351         dr_box = not dr_box;
00352         break;
00353     }
00354     /* Something changed; redraw: */
00355     updateGL();
00356 }
00357 
00358 void QVGLCanvas::closeEvent(QCloseEvent * event)
00359 {
00360         Q_UNUSED(event);
00361     emit closed();
00362 }
00363 
00365 
00366 int nearest_gl_texture_size(int v)
00367         {
00368         int n = 0, last = 0;
00369         for (int s = 0; s < 32; ++s)
00370                 {
00371                 if (((v>>s) & 1) == 1)
00372                         {
00373                         n++;
00374                         last = s;
00375                         }
00376                 }
00377 
00378         if (n > 1)
00379                 return 1 << (last+1);
00380         return 1 << last;
00381         }
00382 
00383 GLuint QVGLCanvas::bindTexture(const QVImage<uChar,3> &image, GLenum target)
00384         {
00385         const uInt cols = image.getCols(), rows = image.getRows(), step = image.getStep();
00386         bool clean = false;
00387 
00388         // Scale the pixmap if needed. GL textures needs to have the
00389         // dimensions 2^n+2(border) x 2^m+2(border).
00390         int textureImage_w = nearest_gl_texture_size(cols);
00391         int textureImage_h = nearest_gl_texture_size(rows);
00392 
00393         QVImage<uChar,3> textureImage(textureImage_w, textureImage_h);
00394         Resize(image, textureImage);
00395 
00396         GLuint textureImage_id;
00397         glGenTextures(1, &textureImage_id);
00398         glBindTexture(target, textureImage_id);
00399         glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00400         glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
00401         glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
00402         glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00403         glTexImage2D(target, 0, GL_RGB, textureImage_w, textureImage_h, 0, GL_BGR, GL_UNSIGNED_BYTE, textureImage.getReadData());
00404 
00405         return textureImage_id;
00406         }



QVision framework. PARP research group, copyright 2007, 2008.