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