00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
00112
00113
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
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
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
00302
00303 zoom += ((y - beginy) / size().height()) * 40;
00304 if (zoom < 5) zoom = 5;
00305 if (zoom > 120) zoom = 120;
00306
00307 updateGL();
00308 }
00309 beginx = x;
00310 beginy = y;
00311 }
00312
00313 void QVGLCanvas::wheelEvent(QWheelEvent *event)
00314 {
00315
00316 zoom -= event->delta()/32;
00317 if (zoom < 5) zoom = 5;
00318 if (zoom > 120) zoom = 120;
00319
00320 updateGL();
00321 }
00322
00323
00324
00325 void QVGLCanvas::keyPressEvent(QKeyEvent *event)
00326 {
00327
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
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
00389
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 }