00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00019
00033
00034
00035
00037
00038
00039 #include <qdatetime.h>
00040 #include <qfiledialog.h>
00041 #include <qimage.h>
00042 #include <qmessagebox.h>
00043 #include <qpoint.h>
00044 #include <qstringlist.h>
00045 #include <qtimer.h>
00046
00047
00048 #include "glview.h"
00049 #include "quaternion.h"
00050 #include "vector3d.h"
00051
00055
00057 GLView::GLView(QWidget* parent, const char* name) : QGLWidget(parent,name),
00059 xPos(0.0f),
00060 yPos(0.0f),
00061 zPos(0.0f),
00062
00063 xRot(0.0f),
00064 yRot(0.0f),
00065 zRot(0.0f),
00066 animation(false),
00067 maxRadius(1.0f),
00068 currentPerspectiveProjection(baseParameters.perspectiveProjection)
00069 {
00070 setFocusPolicy(QWidget::StrongFocus);
00071 orientationQuaternion = new Quaternion<float>(0.0f, 0.0f, 0.0f);
00072 timer = new QTimer(this);
00073 connect(timer, SIGNAL(timeout()), this, SLOT(update()));
00074 setModified(false);
00075
00076
00077
00078 updateIndex = staticUpdateIndex - 1;
00079 }
00080
00082 GLView::~GLView()
00084 {
00085 delete orientationQuaternion;
00086 }
00087
00089 bool GLView::isModified() const
00091 {
00092 return viewModified;
00093 }
00094
00096 bool GLView::isAnimating() const
00098 {
00099 return animation;
00100 }
00101
00103 unsigned int GLView::calculateFPS()
00106 {
00107 unsigned int numFPS = 0;
00108 const int nummSec = 5000;
00109 QTime t;
00110
00112 bool oldAnimation = animation;
00113 Quaternion<float> oldOrientation = *orientationQuaternion;
00114
00116 animation = false;
00117 t.start();
00118 while (t.elapsed() < nummSec)
00119 {
00120 xRot = 1.00;
00121 yRot = 1.25;
00122 zRot = 1.50;
00123 updateGL();
00124 numFPS++;
00125 }
00126
00128 animation = oldAnimation;
00129 *orientationQuaternion = oldOrientation;
00130 updateGL();
00131
00133 return numFPS*1000/nummSec;
00134 }
00135
00137 void GLView::setParameters(GLBaseParameters params)
00140 {
00141 baseParameters = params;
00142 staticUpdateIndex++;
00143 }
00144
00148
00150 void GLView::setModified(const bool status)
00152 {
00153 if(!status)
00154 {
00155 viewModified = false;
00156 return;
00157 }
00158 if(!viewModified)
00159 {
00160 viewModified = true;
00161 emit modified();
00162 }
00163 emit changed();
00164 }
00165
00167 void GLView::toggleAnimation()
00169 {
00170 animation = !animation;
00171 if(animation)
00172 {
00173 xRot = 1.0;
00174 yRot = 0.0;
00175 zRot = 0.0;
00176 updateGL();
00177 }
00178 else
00179 timer->stop();
00180
00181 emit changed();
00182 }
00183
00185 void GLView::centerView(const bool update)
00187 {
00188 xPos = 0.0;
00189 yPos = 0.0;
00190 if(update)
00191 updateGL();
00192 setModified();
00193 }
00194
00196 void GLView::resetOrientation(const bool update)
00198 {
00199 orientationQuaternion->eulerToQuaternion(0.0f, 0.0f, 0.0f);
00200 if(update)
00201 updateGL();
00202 setModified();
00203 }
00204
00206 void GLView::zoomFit(const bool update)
00209 {
00211 maxRadius = boundingSphereRadius();
00213 if(baseParameters.perspectiveProjection)
00214 {
00215 if(width() > height())
00216 zPos = maxRadius/tan(fieldOfView)/1.5f;
00217 else
00218 zPos = maxRadius/tan(fieldOfView)/1.5f * static_cast<float>(height())/static_cast<float>(width());
00219 if(zPos < 0.1f)
00220 zPos = 0.1f;
00221 }
00222 else
00223 {
00224 zPos = 1.0f;
00225 resizeGL(width(), height());
00226 }
00227
00229 updateFog(maxRadius);
00230 if(update)
00231 updateGL();
00232 setModified();
00233 }
00234
00236 void GLView::resetView(const bool update)
00238 {
00239 centerView(false);
00240 resetOrientation(false);
00241 zoomFit();
00242 if(update)
00243 updateGL();
00244 }
00245
00247 void GLView::saveImage()
00249 {
00251 QStringList saveFormats = QImage::outputFormatList();
00252 QStringList::Iterator it = saveFormats.begin();
00253 while(it != saveFormats.end())
00254 {
00255 if((*it) == "JPEG")
00256 *it = "JPEG (*.jpg)";
00257 else
00258 *it += " (*."+(*it).lower()+")";
00259 it++;
00260 }
00261
00263
00264
00265
00266
00267
00268
00269
00270
00272
00273
00274
00275
00276
00277 QString selectedFilter;
00278 QString filename = QFileDialog::getSaveFileName(0, saveFormats.join(";;"), 0, 0, tr("Choose a filename and format"), &selectedFilter);
00279 if(filename.isEmpty())
00280 return;
00281
00282
00283
00284
00285
00286 QString extension = selectedFilter.mid(selectedFilter.find(".")).remove(")");
00287
00288 if(filename.contains(extension) == 0)
00289 filename += extension;
00290
00291
00292
00293 QString format = selectedFilter.left(selectedFilter.find(" "));
00294
00295
00296
00297 QImage image = grabFrameBuffer();
00298
00299
00300 if(!image.save(filename, format))
00301 QMessageBox::warning(this, tr("Save image"), tr("An error occured. Image is not saved"));
00302 }
00303
00307
00309 void GLView::initializeGL()
00312 {
00313 GLfloat lightAmbient[] = {0.2f, 0.2f, 0.2f, 0.0f};
00314 GLfloat lightDiffuse[] = {0.5f, 0.5f, 0.5f, 0.0f};
00315 GLfloat lightSpecular[] = {1.0f, 1.0f, 1.0f, 0.0f};
00316
00317 updateGLSettings();
00318
00321
00322
00323
00325 glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
00326 glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
00327 glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular);
00328 glEnable(GL_LIGHTING);
00329 glEnable(GL_LIGHT0);
00330
00331 glEnable(GL_AUTO_NORMAL);
00332 glEnable(GL_NORMALIZE);
00333
00335 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
00336 glEnable(GL_COLOR_MATERIAL);
00337
00338 glEnable(GL_DITHER);
00339 glEnable(GL_DEPTH_TEST);
00340
00341 glCullFace(GL_BACK);
00342 glEnable(GL_CULL_FACE);
00343
00345
00346
00348 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
00349
00351 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
00352
00353
00354
00355 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00356
00358 glFogi(GL_FOG_MODE, GL_LINEAR);
00359
00361 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
00362 }
00363
00365 void GLView::resizeGL(int w, int h)
00368 {
00369 glViewport(0, 0, w, h);
00370 glMatrixMode(GL_PROJECTION);
00371 glLoadIdentity();
00372
00373 setPerspective();
00374 glMatrixMode(GL_MODELVIEW);
00375 }
00376
00378 void GLView::paintGL()
00380 {
00381 if(staticUpdateIndex != updateIndex)
00382 updateGLSettings();
00383
00385 Quaternion<float> changeQuaternion(xRot, yRot, zRot);
00387 Quaternion<float> tempQuaternion = *orientationQuaternion;
00388 *orientationQuaternion = tempQuaternion*changeQuaternion;
00390 Vector3D<float> axis;
00391 float angle;
00392 orientationQuaternion->getAxisAngle(axis, angle);
00393
00394 if(!animation)
00395 {
00397 xRot = 0.0f;
00398 yRot = 0.0f;
00399 zRot = 0.0f;
00400 }
00401
00402
00403
00404
00405
00406
00407
00408 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00409
00410
00411 glLoadIdentity();
00412
00413
00415 if(baseParameters.perspectiveProjection)
00416 gluLookAt(0.0f, 0.0f, zPos, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
00417 else
00418 resizeGL(width(), height());
00419 glPushMatrix();
00420 glTranslatef(xPos, yPos, 0.0f);
00421 glRotatef(angle, axis.x(), axis.y(), axis.z());
00422
00423 drawScene();
00424
00425 glPopMatrix();
00426 glFlush();
00427 if(animation)
00428 timer->start(redrawWait, true);
00429 }
00430
00432 void GLView::mousePressEvent(QMouseEvent* e)
00434 {
00435 if(e->button() & Qt::LeftButton)
00436 {
00437 mousePosition = e->pos();
00438 startingClick = true;
00439 }
00440 else
00441 e->ignore();
00442 }
00443
00445 void GLView::mouseMoveEvent(QMouseEvent* e)
00447 {
00448 if(e->state() & Qt::LeftButton)
00449 {
00450 QPoint newPosition = e->pos();
00451
00452 if(e->state() & Qt::ShiftButton)
00453 {
00458 if(abs(newPosition.y() - mousePosition.y()) > abs(newPosition.x() - mousePosition.x()))
00459 translateZ(newPosition.y() - mousePosition.y());
00460 else
00461 zRot = -180.0f * static_cast<float>(newPosition.x() - mousePosition.x()) / static_cast<float>(width());
00462 }
00463 else if(e->state() & Qt::ControlButton)
00464 {
00469 translateXY(newPosition.x() - mousePosition.x(), newPosition.y() - mousePosition.y());
00470 }
00471 else
00472 {
00476 yRot = 180.0f * static_cast<float>(newPosition.x() - mousePosition.x()) / static_cast<float>(width());
00477 xRot = 180.0f * static_cast<float>(newPosition.y() - mousePosition.y()) / static_cast<float>(height());
00478 }
00479 setModified();
00480 mousePosition = newPosition;
00481 updateGL();
00482 startingClick = false;
00483 }
00484 else
00485 e->ignore();
00486 }
00487
00489 void GLView::mouseReleaseEvent(QMouseEvent* e)
00492 {
00493 if(e->button() & Qt::LeftButton)
00494 {
00495 if(startingClick)
00496 {
00498 clicked(mousePosition);
00499 }
00500 }
00501 else
00502 e->ignore();
00503 }
00504
00506 void GLView::keyPressEvent(QKeyEvent* e)
00522 {
00523 switch(e->key())
00524 {
00525 case Qt::Key_Left : if(e->state() & Qt::ShiftButton)
00526 zRot = 5.0f;
00527 else if(e->state() & Qt::ControlButton)
00528 translateXY(-5, 0);
00529 else
00530 yRot = -5.0f;
00531 break;
00532
00533 case Qt::Key_Up : if(e->state() & Qt::ShiftButton)
00534 translateZ(-5);
00535 else if(e->state() & Qt::ControlButton)
00536 translateXY(0, -5);
00537 else
00538 xRot = -5.0f;
00539 break;
00540
00541 case Qt::Key_Right : if(e->state() & Qt::ShiftButton)
00542 zRot = -5.0f;
00543 else if(e->state() & Qt::ControlButton)
00544 translateXY(5, 0);
00545 else
00546 yRot = 5.0f;
00547 break;
00548
00549 case Qt::Key_Down : if(e->state() & Qt::ShiftButton)
00550 translateZ(5);
00551 else if(e->state() & Qt::ControlButton)
00552 translateXY(0, 5);
00553 else
00554 xRot = 5.0f;
00555 break;
00556
00557 default: e->ignore();
00558 return;
00559 }
00560 setModified();
00561 updateGL();
00562 }
00563
00565 void GLView::wheelEvent(QWheelEvent* e)
00568 {
00569 translateZ(-e->delta()/4);
00570 setModified();
00571 updateGL();
00572 e->accept();
00573 }
00574
00576 void GLView::translateZ(const int amount)
00579 {
00580
00581
00582 if(amount != 0)
00583 {
00584 float zoomFactor = static_cast<float>(amount)/height();
00585 if(baseParameters.perspectiveProjection)
00586 zoomFactor *= 2.0f * maxRadius;
00587 zPos += zoomFactor;
00588 if(zPos < 0.1f)
00589 zPos = 0.1f;
00590 if(!baseParameters.perspectiveProjection)
00591 resizeGL(width(), height());
00592 }
00593 }
00594
00596 void GLView::translateXY(const int amountX, const int amountY)
00599 {
00600 if(amountX != 0)
00601 xPos += amountX < 0 ? -0.1f : 0.1f;
00602 if(amountY != 0)
00603 yPos += amountY > 0 ? -0.1f : 0.1f;
00604 }
00605
00607 void GLView::clicked(const QPoint&)
00611 {
00612 }
00613
00615 void GLView::updateGLSettings()
00619 {
00620 updateIndex = staticUpdateIndex;
00621
00623 GLfloat lightPosition[] = {baseParameters.lightPositionX, baseParameters.lightPositionY, baseParameters.lightPositionZ, 0.0f};
00624 GLfloat materialSpecular[] = {baseParameters.materialSpecular/100.0f, baseParameters.materialSpecular/100.0f, baseParameters.materialSpecular/100.0f, 0.0f};
00625 GLfloat materialShininess[] = {baseParameters.materialShininess};
00626
00627 glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
00628 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materialSpecular);
00629 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, materialShininess);
00630
00632
00633 qglClearColor(QColor(baseParameters.backgroundColor));
00634
00636 if(baseParameters.smoothShading)
00637 glShadeModel(GL_SMOOTH);
00638 else
00639 glShadeModel(GL_FLAT);
00640
00642 if(baseParameters.antialias)
00643 {
00644
00645
00646
00647
00648
00649 glEnable(GL_LINE_SMOOTH);
00650 glEnable(GL_POINT_SMOOTH);
00651 }
00652 else
00653 {
00654
00655
00656
00657 glDisable(GL_LINE_SMOOTH);
00658 glDisable(GL_POINT_SMOOTH);
00659 }
00660
00662 if(baseParameters.depthCue)
00663 glEnable(GL_FOG);
00664 else
00665 glDisable(GL_FOG);
00666
00667 updateProjection();
00668
00670 resizeGL(width(), height());
00671 }
00672
00674 void GLView::updateFog(const float radius)
00677 {
00678 makeCurrent();
00679 GLfloat fogStart = zPos;
00680 GLfloat fogEnd = zPos + 2.0*radius;
00681
00682 glFogf(GL_FOG_START, fogStart);
00683 glFogf(GL_FOG_END, fogEnd);
00684 }
00685
00687 void GLView::updateProjection()
00689 {
00690 if(currentPerspectiveProjection == baseParameters.perspectiveProjection)
00691 return;
00692
00693 resizeGL(width(), height());
00694 zoomFit();
00695
00696 currentPerspectiveProjection = baseParameters.perspectiveProjection;
00697 }
00698
00700 void GLView::setPerspective()
00702 {
00703 GLfloat aspectRatio = static_cast<float>(width()) / static_cast<float>(height());
00704 if(baseParameters.perspectiveProjection)
00705 gluPerspective(fieldOfView, aspectRatio, 0.1f, 100.0f);
00706
00707
00708 else
00709 glOrtho(-maxRadius*aspectRatio*zPos, maxRadius*aspectRatio*zPos, -maxRadius*zPos, maxRadius*zPos, -maxRadius, maxRadius);
00710 }
00711
00715
00716 int GLView::staticUpdateIndex = 0;
00717 const int GLView::redrawWait = 33;
00718 const float GLView::fieldOfView = 60.0f;
00719
00722
00723
00724 GLBaseParameters GLView::baseParameters = {1.0f, 1.0f, 1.0f, 0xffffff, 0.80f, 100.0f,
00725 0x000000, false, true, false, true};
00726