00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <qvgui/qvglcanvas.h>
00026 #include <qvip/qvipp/qvipp.h>
00027 #include <qvmath/qvmatrixalgebra.h>
00028 #include <QMouseEvent>
00029 #include <qvcore/qvdefines.h>
00030
00031 #define GL_VIEW_ASPECT 1.333
00032
00033 QVGLCanvas::QVGLCanvas(const QString &title, QWidget* parent):
00034 QGLWidget(parent), maxwide(2.0), cx(0.0), cy(0.0), cz(0.0),
00035 trackballQuat(QVQuaternion::trackball(0.0, 0.0, 0.0, 0.0)),
00036 zoom(45), pressedleft(FALSE), pressedright(FALSE)
00037 {
00038 resize(400,(int)(400/GL_VIEW_ASPECT));
00039 setWindowTitle(title);
00040 show();
00041 }
00042
00043 QVGLCanvas::~QVGLCanvas ()
00044 {
00045
00046 }
00047
00051 void QVGLCanvas::linkModelMatrix(QVWorker &worker, const QString &matrixPropertyName, const QString &objectName)
00052 {
00054 worker.linkProperty(matrixPropertyName, this, objectName + " matrix", QVWorker::AsynchronousLink);
00055
00057 QObject::connect(&worker, SIGNAL(endIteration()), this, SLOT(updateGL()));
00058 }
00059
00060 void QVGLCanvas::add(const QV3DModel &model, const QString &name)
00061 {
00062 addProperty<QV3DModel>(name, inputFlag | outputFlag, model, name + " 3d object model");
00063 addProperty<QVMatrix>(name + " matrix", inputFlag | outputFlag, QVMatrix::identity(4), name + " 3d location matrix");
00064 }
00065
00066 void QVGLCanvas::initializeGL()
00067 {
00068 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00069
00070 glDisable(GL_CULL_FACE);
00071 glEnable(GL_DEPTH_TEST);
00072
00073 glEnable(GL_DITHER);
00074 glShadeModel(GL_SMOOTH);
00075 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
00076 glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
00077
00078 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00079 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00080 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
00081
00082 glEnable(GL_DEPTH_TEST);
00083 glEnable(GL_CULL_FACE);
00084 glEnable(GL_TEXTURE_2D);
00085
00086 init();
00087 }
00088
00089 void QVGLCanvas::drawModels()
00090 {
00091 readInputProperties();
00092
00093 glScaled((GLdouble)1/maxwide,(GLdouble)1/maxwide,(GLdouble)1/maxwide);
00094
00095 foreach(QString name, getPropertyListByType<QV3DModel>())
00096 {
00097 QV3DModel model = getPropertyValue<QV3DModel>(name);
00098 QVMatrix matrix = getPropertyValue<QVMatrix>(name + " matrix");
00099
00100
00101
00102
00103 if (matrix.getCols() == 4 && matrix.getRows() == 4)
00104 {
00105 glPushMatrix();
00106
00108 GLfloat m[4][4];
00109 QVMatrix M = pseudoInverse(matrix);
00110
00111 for (int i=0; i <4; i++)
00112 for (int j=0; j <4; j++)
00113 m[i][j] = matrix(i,j);
00114
00115 for (int i=0; i <3; i++)
00116 { m[3][i] = 0; m[i][3] = 0; }
00117
00118 glTranslated(-M(0,3), -M(1,3), -M(2,3));
00119
00120 glMultMatrixf(&m[0][0]);
00121
00122 model.paint(*this);
00123 glPopMatrix();
00124
00125 glFlush();
00126 }
00127 else
00128 model.paint(*this);
00129 }
00130 }
00131
00132 void QVGLCanvas::paintGL()
00133 {
00134 glMatrixMode(GL_PROJECTION);
00135
00136 glLoadIdentity();
00137 gluPerspective(zoom,(float)size().width()/(float)size().height(),1,100);
00138 glMatrixMode(GL_MODELVIEW);
00139
00140 glLoadIdentity();
00141
00142 glTranslatef(0,0,-4);
00143 glScaled((GLdouble)1/maxwide,(GLdouble)1/maxwide,(GLdouble)1/maxwide);
00144
00145
00146 GLfloat m[4][4];
00147 QVMatrix M(trackballQuat);
00148
00149 for (int i=0; i <4; i++)
00150 for (int j=0; j <4; j++)
00151 m[i][j] = M(i,j);
00152
00153 glMultMatrixf(&m[0][0]);
00154
00155 glRotatef(270,1,0,0);
00156
00157 glTranslatef(-cx,-cy,-cz);
00158
00159 glClearColor(.5, .5, .75, 1.0);
00160 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
00161
00162 drawModels();
00163
00164 display();
00165 }
00166
00167 void QVGLCanvas::resizeGL( int w, int h )
00168 {
00169 glViewport(0,0,w,h);
00170 reshape(w,h);
00171
00172 drawModels();
00173 }
00174
00178
00179 void QVGLCanvas::mousePressEvent(QMouseEvent *event)
00180 {
00181 beginx = event->x();
00182 beginy = event->y();
00183 if(event->button() == Qt::LeftButton) {
00184 pressedleft = TRUE;
00185 } else if(event->button() == Qt::RightButton) {
00186 pressedright = TRUE;
00187 }
00188 }
00189
00190 void QVGLCanvas::mouseReleaseEvent(QMouseEvent *event)
00191 {
00192 if(event->button() == Qt::LeftButton) {
00193 pressedleft = FALSE;
00194 } else if(event->button() == Qt::RightButton) {
00195 pressedright = FALSE;
00196 }
00197 }
00198
00199 void QVGLCanvas::mouseMoveEvent(QMouseEvent *event)
00200 {
00201 int x,y;
00202
00203 x = (int) event->x();
00204 y = (int) event->y();
00205
00206 if (pressedleft) {
00207 QVQuaternion spinQuat = QVQuaternion::trackball(
00208 (2.0*beginx - size().width()) / size().width(),
00209 (size().height() - 2.0*beginy) / size().height(),
00210 (2.0*x - size().width()) / size().width(),
00211 (size().height() - 2.0*y) / size().height());
00212
00213 trackballQuat = spinQuat * trackballQuat;
00214 updateGL();
00215 }
00216
00217 if (pressedright) {
00218
00219
00220 zoom += ((y - beginy) / size().height()) * 40;
00221 if (zoom < 5) zoom = 5;
00222 if (zoom > 120) zoom = 120;
00223
00224 updateGL();
00225 }
00226 beginx = x;
00227 beginy = y;
00228 }
00229
00230 void QVGLCanvas::wheelEvent(QWheelEvent *event)
00231 {
00232
00233 zoom -= event->delta()/32;
00234 if (zoom < 5) zoom = 5;
00235 if (zoom > 120) zoom = 120;
00236
00237 updateGL();
00238 }
00239
00240
00241
00242 void QVGLCanvas::keyPressEvent(QKeyEvent *event)
00243 {
00244
00245 switch(event->key()) {
00246 case Qt::Key_Left:
00247 cx -= maxwide/20;
00248 break;
00249 case Qt::Key_Right:
00250 cx += maxwide/20;
00251 break;
00252 case Qt::Key_Up:
00253 cy += maxwide/20;
00254 break;
00255 case Qt::Key_Down:
00256 cy -= maxwide/20;
00257 break;
00258 case Qt::Key_PageUp:
00259 cz += maxwide/20;
00260 break;
00261 case Qt::Key_PageDown:
00262 cz -= maxwide/20;
00263 break;
00264 }
00265
00266 updateGL();
00267 }
00268
00269 void QVGLCanvas::closeEvent(QCloseEvent * event)
00270 {
00271 Q_UNUSED(event);
00272 emit closed();
00273 }
00274
00276
00277 int nearest_gl_texture_size(int v)
00278 {
00279 int n = 0, last = 0;
00280 for (int s = 0; s < 32; ++s)
00281 {
00282 if (((v>>s) & 1) == 1)
00283 {
00284 n++;
00285 last = s;
00286 }
00287 }
00288
00289 if (n > 1)
00290 return 1 << (last+1);
00291 return 1 << last;
00292 }
00293
00294 GLuint QVGLCanvas::bindTexture(const QVImage<uChar,3> &image, GLenum target)
00295 {
00296 const uInt cols = image.getCols(), rows = image.getRows(), step = image.getStep();
00297 bool clean = false;
00298
00299
00300
00301 int textureImage_w = nearest_gl_texture_size(cols);
00302 int textureImage_h = nearest_gl_texture_size(rows);
00303
00304 QVImage<uChar,3> textureImage(textureImage_w, textureImage_h);
00305 Resize(image, textureImage);
00306
00307 GLuint textureImage_id;
00308 glGenTextures(1, &textureImage_id);
00309 glBindTexture(target, textureImage_id);
00310 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00311 glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
00312 glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
00313 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00314 glTexImage2D(target, 0, GL_RGB, textureImage_w, textureImage_h, 0, GL_BGR, GL_UNSIGNED_BYTE, textureImage.getReadData());
00315
00316 return textureImage_id;
00317 }