00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "domUtils.h"
00024 #include "qglviewer.h"
00025 #include "camera.h"
00026 #include "keyFrameInterpolator.h"
00027
00028 #if QT_VERSION >= 0x040000
00029 # include <QtAlgorithms>
00030 # include <QTextEdit>
00031 # include <QApplication>
00032 # include <QFileInfo>
00033 # include <QDateTime>
00034 # include <QMessageBox>
00035 # include <QPushButton>
00036 # include <QTabWidget>
00037 # include <QTextStream>
00038 # include <QMouseEvent>
00039 # include <QTimer>
00040 # include <QImage>
00041 # include <QDir>
00042 # include <QUrl>
00043 #else
00044 # include <qapplication.h>
00045 # include <qfileinfo.h>
00046 # include <qdatetime.h>
00047 # include <qmessagebox.h>
00048 # include <qpushbutton.h>
00049 # include <qtabwidget.h>
00050 # include <qtextstream.h>
00051 # include <qtimer.h>
00052 # include <qimage.h>
00053 # include <qtextedit.h>
00054 # include <qkeysequence.h>
00055 # include <qdir.h>
00056
00057 # define KeyboardModifierMask KeyButtonMask
00058
00059 # define value data
00060 #endif
00061
00062 using namespace std;
00063 using namespace qglviewer;
00064
00065
00066 #if QT_VERSION >= 0x040000
00067 QList<QGLViewer*> QGLViewer::QGLViewerPool_;
00068 #else
00069 QPtrList<QGLViewer> QGLViewer::QGLViewerPool_;
00070 #endif
00071
00072
00096 void QGLViewer::defaultConstructor()
00097 {
00098
00099
00100
00101
00102
00103 updateGLOK_ = false;
00104
00105
00106
00107
00108
00109 #if QT_VERSION >= 0x040000
00110 int poolIndex = QGLViewer::QGLViewerPool_.indexOf(NULL);
00111 setFocusPolicy(Qt::StrongFocus);
00112 #else
00113 int poolIndex = QGLViewer::QGLViewerPool_.findRef(NULL);
00114 setFocusPolicy(QWidget::StrongFocus);
00115 #endif
00116
00117 if (poolIndex >= 0)
00118 QGLViewer::QGLViewerPool_.replace(poolIndex, this);
00119 else
00120 QGLViewer::QGLViewerPool_.append(this);
00121
00122 camera_ = new Camera();
00123 setCamera(camera());
00124
00125 setDefaultShortcuts();
00126 setDefaultMouseBindings();
00127
00128 setSnapshotFileName(tr("snapshot", "Default snapshot file name"));
00129 initializeSnapshotFormats();
00130 setSnapshotCounter(0);
00131 setSnapshotQuality(95);
00132
00133 fpsTime_.start();
00134 fpsCounter_ = 0;
00135 f_p_s_ = 0.0;
00136 fpsString_ = tr("%1Hz", "Frames per seconds, in Hertz").arg("?");
00137 visualHint_ = 0;
00138 previousPathId_ = 0;
00139
00140
00141
00142 manipulatedFrame_ = NULL;
00143 manipulatedFrameIsACamera_ = false;
00144 mouseGrabberIsAManipulatedFrame_ = false;
00145 mouseGrabberIsAManipulatedCameraFrame_ = false;
00146 displayMessage_ = false;
00147 connect(&messageTimer_, SIGNAL(timeout()), SLOT(hideMessage()));
00148 #if QT_VERSION >= 0x040000
00149 messageTimer_.setSingleShot(true);
00150 #endif
00151 helpWidget_ = NULL;
00152 setMouseGrabber(NULL);
00153
00154 setSceneRadius(1.0);
00155 showEntireScene();
00156 setStateFileName(".qglviewer.xml");
00157
00158
00159 setAxisIsDrawn(false);
00160 setGridIsDrawn(false);
00161 setFPSIsDisplayed(false);
00162 setCameraIsEdited(false);
00163 setTextIsEnabled(true);
00164 setStereoDisplay(false);
00165 setFullScreen(false);
00166
00167 animationTimerId_ = 0;
00168 stopAnimation();
00169 setAnimationPeriod(40);
00170
00171 selectBuffer_ = NULL;
00172 setSelectBufferSize(4*1000);
00173 setSelectRegionWidth(3);
00174 setSelectRegionHeight(3);
00175 setSelectedName(-1);
00176
00177 bufferTextureId_ = 0;
00178 bufferTextureMaxU_ = 0.0;
00179 bufferTextureMaxV_ = 0.0;
00180 bufferTextureWidth_ = 0;
00181 bufferTextureHeight_ = 0;
00182 previousBufferTextureFormat_ = 0;
00183 previousBufferTextureInternalFormat_ = 0;
00184
00185 #if QT_VERSION >= 0x040000
00186 setAttribute(Qt::WA_NoSystemBackground);
00187 #endif
00188
00189 tileRegion_ = NULL;
00190 }
00191
00192 #if QT_VERSION >= 0x040000
00193
00200 QGLViewer::QGLViewer(QWidget* parent, const QGLWidget* shareWidget, Qt::WFlags flags)
00201 : QGLWidget(parent, shareWidget, flags)
00202 { defaultConstructor(); }
00203
00209 QGLViewer::QGLViewer(QGLContext *context, QWidget* parent, const QGLWidget* shareWidget, Qt::WFlags flags)
00210 : QGLWidget(context, parent, shareWidget, flags)
00211 { defaultConstructor(); }
00212
00217 QGLViewer::QGLViewer(const QGLFormat& format, QWidget* parent, const QGLWidget* shareWidget, Qt::WFlags flags)
00218 : QGLWidget(format, parent, shareWidget, flags)
00219 { defaultConstructor(); }
00220 #endif
00221
00226 QGLViewer::~QGLViewer()
00227 {
00228
00229
00230
00231
00232
00233 #if QT_VERSION >= 0x040000
00234 QGLViewer::QGLViewerPool_.replace(QGLViewer::QGLViewerPool_.indexOf(this), NULL);
00235 #else
00236 QGLViewer::QGLViewerPool_.replace(QGLViewer::QGLViewerPool_.findRef(this), NULL);
00237 #endif
00238
00239 delete camera();
00240 delete[] selectBuffer_;
00241 if (helpWidget())
00242 {
00243
00244 helpWidget()->close();
00245 delete helpWidget_;
00246 }
00247 }
00248
00249
00250 static QString QGLViewerVersionString()
00251 {
00252 return QString::number((QGLVIEWER_VERSION & 0xff0000) >> 16) + "." +
00253 QString::number((QGLVIEWER_VERSION & 0x00ff00) >> 8) + "." +
00254 QString::number(QGLVIEWER_VERSION & 0x0000ff);
00255 }
00256
00257 static int convertToKeyboardModifiers(int state)
00258 {
00259 #if QT_VERSION < 0x040000
00260
00261
00262 if (state & Qt::MODIFIER_MASK)
00263 {
00264 if (state & Qt::CTRL) { state &= ~Qt::CTRL; state |= Qt::ControlButton; }
00265 if (state & Qt::SHIFT) { state &= ~Qt::SHIFT; state |= Qt::ShiftButton; }
00266 if (state & Qt::ALT) { state &= ~Qt::ALT; state |= Qt::AltButton; }
00267 # if QT_VERSION >= 0x030100
00268 if (state & Qt::META) { state &= ~Qt::META; state |= Qt::MetaButton; }
00269 # endif
00270 }
00271 #endif
00272 return state;
00273 }
00274
00275 static QtKeyboardModifiers convertKeyboardModifiers(QtKeyboardModifiers modifiers)
00276 {
00277 #if QT_VERSION < 0x040000
00278 return QtKeyboardModifiers(convertToKeyboardModifiers(modifiers));
00279 #else
00280 return modifiers;
00281 #endif
00282 }
00283
00284 static int convertToShortModifier(int state)
00285 {
00286
00287
00288 #if QT_VERSION < 0x040000
00289 if (state & Qt::KeyButtonMask)
00290 {
00291 if (state & Qt::ControlButton) { state &= ~Qt::ControlButton; state |= Qt::CTRL; }
00292 if (state & Qt::ShiftButton) { state &= ~Qt::ShiftButton; state |= Qt::SHIFT; }
00293 if (state & Qt::AltButton) { state &= ~Qt::AltButton; state |= Qt::ALT; }
00294 # if QT_VERSION >= 0x030100
00295 if (state & Qt::MetaButton) { state &= ~Qt::MetaButton; state |= Qt::META; }
00296 # endif
00297 }
00298 #endif
00299 return state;
00300 }
00301
00320 void QGLViewer::initializeGL()
00321 {
00322 if (updateGLOK_)
00323 qWarning("Internal debug: initializeGL() is called in QGLViewer constructor.");
00324
00325 glEnable(GL_LIGHT0);
00326 glEnable(GL_LIGHTING);
00327 glEnable(GL_DEPTH_TEST);
00328 glEnable(GL_COLOR_MATERIAL);
00329
00330
00331 setForegroundColor(QColor(180, 180, 180));
00332 setBackgroundColor(QColor(51, 51, 51));
00333
00334
00335 if (format().stereo())
00336 {
00337 glDrawBuffer(GL_BACK_RIGHT);
00338 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00339 glDrawBuffer(GL_BACK_LEFT);
00340 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00341 }
00342 else
00343 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00344
00345
00346 init();
00347
00348
00349 if (isFullScreen())
00350 QTimer::singleShot( 100, this, SLOT(delayedFullScreen()) );
00351
00352 updateGLOK_ = true;
00353 }
00354
00361 void QGLViewer::paintGL()
00362 {
00363 updateGLOK_ = false;
00364 if (displaysInStereo())
00365 {
00366 for (int view=1; view>=0; --view)
00367 {
00368
00369 preDrawStereo(view);
00370
00371 if (camera()->frame()->isManipulated())
00372 fastDraw();
00373 else
00374 draw();
00375 postDraw();
00376 }
00377 }
00378 else
00379 {
00380
00381 preDraw();
00382
00383 if (camera()->frame()->isManipulated())
00384 fastDraw();
00385 else
00386 draw();
00387
00388 postDraw();
00389 }
00390 updateGLOK_ = true;
00391 Q_EMIT drawFinished(true);
00392 }
00393
00405 void QGLViewer::preDraw()
00406 {
00407 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00408
00409
00410 camera()->loadProjectionMatrix();
00411
00412 camera()->loadModelViewMatrix();
00413
00414 Q_EMIT drawNeeded();
00415 }
00416
00427 void QGLViewer::postDraw()
00428 {
00429
00430 glMatrixMode(GL_MODELVIEW);
00431 glPushMatrix();
00432 camera()->loadModelViewMatrix();
00433
00434
00435
00436 glPushAttrib(GL_ALL_ATTRIB_BITS);
00437
00438
00439 glDisable(GL_TEXTURE_1D);
00440 glDisable(GL_TEXTURE_2D);
00441 #ifdef GL_TEXTURE_3D // OpenGL 1.2 Only...
00442 glDisable(GL_TEXTURE_3D);
00443 #endif
00444
00445 glDisable(GL_TEXTURE_GEN_Q);
00446 glDisable(GL_TEXTURE_GEN_R);
00447 glDisable(GL_TEXTURE_GEN_S);
00448 glDisable(GL_TEXTURE_GEN_T);
00449
00450 #ifdef GL_RESCALE_NORMAL // OpenGL 1.2 Only...
00451 glEnable(GL_RESCALE_NORMAL);
00452 #endif
00453
00454 glDisable(GL_COLOR_MATERIAL);
00455 qglColor(foregroundColor());
00456
00457 if (cameraIsEdited())
00458 camera()->drawAllPaths();
00459
00460
00461 drawVisualHints();
00462
00463 if (gridIsDrawn()) { glLineWidth(1.0); drawGrid(camera()->sceneRadius()); }
00464 if (axisIsDrawn()) { glLineWidth(2.0); drawAxis(camera()->sceneRadius()); }
00465
00466
00467 const unsigned int maxCounter = 20;
00468 if (++fpsCounter_ == maxCounter)
00469 {
00470 f_p_s_ = 1000.0 * maxCounter / fpsTime_.restart();
00471 fpsString_ = tr("%1Hz", "Frames per seconds, in Hertz").arg(f_p_s_, 0, 'f', ((f_p_s_ < 10.0)?1:0));
00472 fpsCounter_ = 0;
00473 }
00474
00475
00476 float color[4];
00477 color[0] = foregroundColor().red() / 255.0;
00478 color[1] = foregroundColor().green() / 255.0;
00479 color[2] = foregroundColor().blue() / 255.0;
00480 color[3] = 1.0;
00481 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
00482 glDisable(GL_LIGHTING);
00483 glDisable(GL_DEPTH_TEST);
00484
00485 if (FPSIsDisplayed()) displayFPS();
00486 if (displayMessage_) drawText(10, height()-10, message_);
00487
00488
00489 glPopAttrib();
00490 glPopMatrix();
00491 }
00492
00498 void QGLViewer::preDrawStereo(bool leftBuffer)
00499 {
00500
00501
00502
00503 if (!leftBuffer)
00504 glDrawBuffer(GL_BACK_LEFT);
00505 else
00506 glDrawBuffer(GL_BACK_RIGHT);
00507
00508
00509 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00510
00511 camera()->loadProjectionMatrixStereo(leftBuffer);
00512
00513 camera()->loadModelViewMatrixStereo(leftBuffer);
00514
00515 Q_EMIT drawNeeded();
00516 }
00517
00525 void QGLViewer::fastDraw()
00526 {
00527 draw();
00528 }
00529
00537 void QGLViewer::setCameraIsEdited(bool edit)
00538 {
00539 cameraIsEdited_ = edit;
00540 if (edit)
00541 {
00542 previousCameraZClippingCoefficient_ = camera()->zClippingCoefficient();
00543
00544 camera()->setZClippingCoefficient(5.0);
00545 }
00546 else
00547 camera()->setZClippingCoefficient(previousCameraZClippingCoefficient_);
00548
00549 Q_EMIT cameraIsEditedChanged(edit);
00550
00551 if (updateGLOK_)
00552 updateGL();
00553 }
00554
00555
00556 void QGLViewer::setDefaultShortcuts()
00557 {
00558
00559 setShortcut(DRAW_AXIS, Qt::Key_A);
00560 setShortcut(DRAW_GRID, Qt::Key_G);
00561 setShortcut(DISPLAY_FPS, Qt::Key_F);
00562 setShortcut(ENABLE_TEXT, Qt::SHIFT+Qt::Key_Question);
00563 setShortcut(EXIT_VIEWER, Qt::Key_Escape);
00564 setShortcut(SAVE_SCREENSHOT, Qt::CTRL+Qt::Key_S);
00565 setShortcut(CAMERA_MODE, Qt::Key_Space);
00566 setShortcut(FULL_SCREEN, Qt::ALT+Qt::Key_Return);
00567 setShortcut(STEREO, Qt::Key_S);
00568 setShortcut(ANIMATION, Qt::Key_Return);
00569 setShortcut(HELP, Qt::Key_H);
00570 setShortcut(EDIT_CAMERA, Qt::Key_C);
00571 setShortcut(MOVE_CAMERA_LEFT, Qt::Key_Left);
00572 setShortcut(MOVE_CAMERA_RIGHT,Qt::Key_Right);
00573 setShortcut(MOVE_CAMERA_UP, Qt::Key_Up);
00574 setShortcut(MOVE_CAMERA_DOWN, Qt::Key_Down);
00575 setShortcut(INCREASE_FLYSPEED,Qt::Key_Plus);
00576 setShortcut(DECREASE_FLYSPEED,Qt::Key_Minus);
00577 setShortcut(SNAPSHOT_TO_CLIPBOARD,Qt::CTRL+Qt::Key_C);
00578
00579 keyboardActionDescription_[DISPLAY_FPS] = tr("Toggles the display of the FPS", "DISPLAY_FPS action description");
00580 keyboardActionDescription_[SAVE_SCREENSHOT] = tr("Saves a screenshot", "SAVE_SCREENSHOT action description");
00581 keyboardActionDescription_[FULL_SCREEN] = tr("Toggles full screen display", "FULL_SCREEN action description");
00582 keyboardActionDescription_[DRAW_AXIS] = tr("Toggles the display of the world axis", "DRAW_AXIS action description");
00583 keyboardActionDescription_[DRAW_GRID] = tr("Toggles the display of the XY grid", "DRAW_GRID action description");
00584 keyboardActionDescription_[CAMERA_MODE] = tr("Changes camera mode (revolve or fly)", "CAMERA_MODE action description");
00585 keyboardActionDescription_[STEREO] = tr("Toggles stereo display", "STEREO action description");
00586 keyboardActionDescription_[HELP] = tr("Opens this help window", "HELP action description");
00587 keyboardActionDescription_[ANIMATION] = tr("Starts/stops the animation", "ANIMATION action description");
00588 keyboardActionDescription_[EDIT_CAMERA] = tr("Toggles camera paths display", "EDIT_CAMERA action description");
00589 keyboardActionDescription_[ENABLE_TEXT] = tr("Toggles the display of the text", "ENABLE_TEXT action description");
00590 keyboardActionDescription_[EXIT_VIEWER] = tr("Exits program", "EXIT_VIEWER action description");
00591 keyboardActionDescription_[MOVE_CAMERA_LEFT] = tr("Moves camera left", "MOVE_CAMERA_LEFT action description");
00592 keyboardActionDescription_[MOVE_CAMERA_RIGHT] = tr("Moves camera right", "MOVE_CAMERA_RIGHT action description");
00593 keyboardActionDescription_[MOVE_CAMERA_UP] = tr("Moves camera up", "MOVE_CAMERA_UP action description");
00594 keyboardActionDescription_[MOVE_CAMERA_DOWN] = tr("Moves camera down", "MOVE_CAMERA_DOWN action description");
00595 keyboardActionDescription_[INCREASE_FLYSPEED] = tr("Increases fly speed", "INCREASE_FLYSPEED action description");
00596 keyboardActionDescription_[DECREASE_FLYSPEED] = tr("Decreases fly speed", "DECREASE_FLYSPEED action description");
00597 keyboardActionDescription_[SNAPSHOT_TO_CLIPBOARD] = tr("Copies a snapshot to clipboard", "SNAPSHOT_TO_CLIPBOARD action description");
00598
00599
00600 setPathKey(Qt::Key_F1, 1);
00601 setPathKey(Qt::Key_F2, 2);
00602 setPathKey(Qt::Key_F3, 3);
00603 setPathKey(Qt::Key_F4, 4);
00604 setPathKey(Qt::Key_F5, 5);
00605 setPathKey(Qt::Key_F6, 6);
00606 setPathKey(Qt::Key_F7, 7);
00607 setPathKey(Qt::Key_F8, 8);
00608 setPathKey(Qt::Key_F9, 9);
00609 setPathKey(Qt::Key_F10, 10);
00610 setPathKey(Qt::Key_F11, 11);
00611 setPathKey(Qt::Key_F12, 12);
00612
00613 #if QT_VERSION >= 0x040000
00614 setAddKeyFrameKeyboardModifiers(Qt::AltModifier);
00615 setPlayPathKeyboardModifiers(Qt::NoModifier);
00616 #else
00617 setAddKeyFrameKeyboardModifiers(Qt::AltButton);
00618 setPlayPathKeyboardModifiers(Qt::NoButton);
00619 #endif
00620 }
00621
00622
00623 void QGLViewer::setDefaultMouseBindings()
00624 {
00625 #if QT_VERSION >= 0x040000
00626 const QtKeyboardModifiers cameraKeyboardModifiers = Qt::NoModifier;
00627 const QtKeyboardModifiers frameKeyboardModifiers = Qt::ControlModifier;
00628 #else
00629 const QtKeyboardModifiers cameraKeyboardModifiers = Qt::NoButton;
00630 const QtKeyboardModifiers frameKeyboardModifiers = Qt::ControlButton;
00631 #endif
00632
00633 for (int handler=0; handler<2; ++handler)
00634 {
00635 MouseHandler mh = (MouseHandler)(handler);
00636 QtKeyboardModifiers modifiers = (mh == FRAME) ? frameKeyboardModifiers : cameraKeyboardModifiers;
00637
00638 setMouseBinding(modifiers | Qt::LeftButton, mh, ROTATE);
00639 setMouseBinding(modifiers | Qt::MidButton, mh, ZOOM);
00640 setMouseBinding(modifiers | Qt::RightButton, mh, TRANSLATE);
00641
00642 setMouseBinding(modifiers | Qt::LeftButton | Qt::MidButton, mh, SCREEN_ROTATE);
00643
00644
00645 setWheelBinding(modifiers, mh, ZOOM);
00646 }
00647
00648 #if QT_VERSION >= 0x040000
00649
00650 setMouseBinding(Qt::ShiftModifier | Qt::MidButton, CAMERA, ZOOM_ON_REGION);
00651
00652 setMouseBinding(Qt::ShiftModifier | Qt::LeftButton, SELECT);
00653 #else
00654 setMouseBinding(Qt::ShiftButton | Qt::MidButton, CAMERA, ZOOM_ON_REGION);
00655 setMouseBinding(Qt::ShiftButton | Qt::LeftButton, SELECT);
00656 #endif
00657
00658
00659 setMouseBinding(Qt::LeftButton, ALIGN_CAMERA, true);
00660 setMouseBinding(Qt::MidButton, SHOW_ENTIRE_SCENE, true);
00661 setMouseBinding(Qt::RightButton, CENTER_SCENE, true);
00662
00663 setMouseBinding(frameKeyboardModifiers | Qt::LeftButton, ALIGN_FRAME, true);
00664 setMouseBinding(frameKeyboardModifiers | Qt::RightButton, CENTER_FRAME, true);
00665
00666
00667 setMouseBinding(Qt::LeftButton, RAP_FROM_PIXEL, true, Qt::RightButton);
00668 setMouseBinding(Qt::RightButton, RAP_IS_CENTER, true, Qt::LeftButton);
00669 setMouseBinding(Qt::LeftButton, ZOOM_ON_PIXEL, true, Qt::MidButton);
00670 setMouseBinding(Qt::RightButton, ZOOM_TO_FIT, true, Qt::MidButton);
00671
00672 #ifdef Q_OS_MAC
00673
00674
00675
00676 # if QT_VERSION >= 0x040000
00677 const QtKeyboardModifiers macKeyboardModifiers = Qt::AltModifier;
00678 # else
00679 const QtKeyboardModifiers macKeyboardModifiers = Qt::AltButton;
00680 # endif
00681
00682 setMouseBinding(macKeyboardModifiers | Qt::LeftButton, CAMERA, TRANSLATE);
00683 setMouseBinding(macKeyboardModifiers | Qt::LeftButton, CENTER_SCENE, true);
00684 setMouseBinding(frameKeyboardModifiers | macKeyboardModifiers | Qt::LeftButton, CENTER_FRAME, true);
00685 setMouseBinding(frameKeyboardModifiers | macKeyboardModifiers | Qt::LeftButton, FRAME, TRANSLATE);
00686
00687
00688
00689 setMouseBinding(Qt::MetaModifier | Qt::RightButton, RAP_FROM_PIXEL, true, Qt::LeftButton);
00690 setMouseBinding(Qt::ShiftModifier | Qt::MetaModifier | Qt::RightButton, RAP_IS_CENTER, true, Qt::LeftButton);
00691
00692 setMouseBinding(Qt::MetaModifier | Qt::RightButton, ZOOM_ON_PIXEL, false);
00693 setMouseBinding(Qt::ShiftModifier | Qt::MetaModifier | Qt::RightButton, ZOOM_TO_FIT, false);
00694 #endif
00695 }
00696
00713 void QGLViewer::setCamera(Camera* const camera)
00714 {
00715 if (!camera)
00716 return;
00717
00718 camera->setSceneRadius(sceneRadius());
00719 camera->setSceneCenter(sceneCenter());
00720 camera->setScreenWidthAndHeight(width(),height());
00721
00722
00723 disconnect(this->camera()->frame(), SIGNAL(manipulated()), this, SLOT(updateGL()));
00724 disconnect(this->camera()->frame(), SIGNAL(spun()), this, SLOT(updateGL()));
00725
00726
00727 connect(camera->frame(), SIGNAL(manipulated()), SLOT(updateGL()));
00728 connect(camera->frame(), SIGNAL(spun()), SLOT(updateGL()));
00729
00730 connectAllCameraKFIInterpolatedSignals(false);
00731 camera_ = camera;
00732 connectAllCameraKFIInterpolatedSignals();
00733
00734 previousCameraZClippingCoefficient_ = this->camera()->zClippingCoefficient();
00735 }
00736
00737 void QGLViewer::connectAllCameraKFIInterpolatedSignals(bool connection)
00738 {
00739 for (QMap<int, KeyFrameInterpolator*>::ConstIterator it = camera()->kfi_.begin(), end=camera()->kfi_.end(); it != end; ++it)
00740 {
00741 if (connection)
00742 connect(camera()->keyFrameInterpolator(it.key()), SIGNAL(interpolated()), SLOT(updateGL()));
00743 else
00744 disconnect(camera()->keyFrameInterpolator(it.key()), SIGNAL(interpolated()), this, SLOT(updateGL()));
00745 }
00746
00747 if (connection)
00748 connect(camera()->interpolationKfi_, SIGNAL(interpolated()), SLOT(updateGL()));
00749 else
00750 disconnect(camera()->interpolationKfi_, SIGNAL(interpolated()), this, SLOT(updateGL()));
00751 }
00752
00769 void QGLViewer::drawLight(GLenum light, float scale) const
00770 {
00771 static GLUquadric* quadric = gluNewQuadric();
00772
00773 const float length = sceneRadius() / 5.0 * scale;
00774
00775 GLboolean lightIsOn;
00776 glGetBooleanv(light, &lightIsOn);
00777
00778 if (lightIsOn)
00779 {
00780
00781 glPushMatrix();
00782 glLoadIdentity();
00783
00784 float color[4];
00785 glGetLightfv(light, GL_DIFFUSE, color);
00786 glColor4fv(color);
00787
00788 float pos[4];
00789 glGetLightfv(light, GL_POSITION, pos);
00790
00791 if (pos[3] != 0.0)
00792 {
00793 glTranslatef(pos[0]/pos[3], pos[1]/pos[3], pos[2]/pos[3]);
00794
00795 GLfloat cutOff;
00796 glGetLightfv(light, GL_SPOT_CUTOFF, &cutOff);
00797 if (cutOff != 180.0)
00798 {
00799 GLfloat dir[4];
00800 glGetLightfv(light, GL_SPOT_DIRECTION, dir);
00801 glMultMatrixd(Quaternion(Vec(0,0,1), Vec(dir)).matrix());
00802 QGLViewer::drawArrow(length);
00803 gluCylinder(quadric, 0.0, 0.7 * length * sin(cutOff * M_PI / 180.0), 0.7 * length * cos(cutOff * M_PI / 180.0), 12, 1);
00804 }
00805 else
00806 gluSphere(quadric, 0.2*length, 10, 10);
00807 }
00808 else
00809 {
00810
00811 Vec dir(pos[0], pos[1], pos[2]);
00812 dir.normalize();
00813 Frame fr=Frame(camera()->cameraCoordinatesOf(4.0 * length * camera()->frame()->inverseTransformOf(dir)),
00814 Quaternion(Vec(0,0,-1), dir));
00815 glMultMatrixd(fr.matrix());
00816 drawArrow(length);
00817 }
00818
00819 glPopMatrix();
00820 }
00821 }
00822
00823
00866 void QGLViewer::drawText(int x, int y, const QString& text, const QFont& fnt)
00867 {
00868 if (!textIsEnabled())
00869 return;
00870
00871 #if QT_VERSION < QGLVIEWER_QT_VERSION_WITHOUT_GLUT
00872 const GLfloat font_scale = 119.05f - 33.33f;
00873
00874 startScreenCoordinatesSystem();
00875
00876
00877 glPushAttrib(GL_ALL_ATTRIB_BITS);
00878 glDisable(GL_LIGHTING);
00879 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00880 glEnable(GL_BLEND);
00881 glDisable(GL_DEPTH_TEST);
00882 glEnable(GL_LINE_SMOOTH);
00883 glLineWidth(1.0);
00884
00885 glTranslatef((GLfloat)x, (GLfloat)y, 0.0);
00886 const GLfloat scale = ((fnt.pixelSize()>0)?fnt.pixelSize():fnt.pointSize()) / font_scale;
00887 glScalef(scale, -scale, scale);
00888
00889 for (uint i=0; i<text.length(); ++i)
00890 glutStrokeCharacter(GLUT_STROKE_ROMAN, text.at(i));
00891
00892 glPopAttrib();
00893
00894 stopScreenCoordinatesSystem();
00895 #else
00896
00897 # if QT_VERSION < 0x030300 && defined Q_OS_UNIX
00898
00899 QFont newFont(fnt);
00900 newFont.setFamily("fixed");
00901 newFont.setRawMode(true);
00902 newFont.setPixelSize(10);
00903 newFont.setFixedPitch(true);
00904 # if QT_VERSION >= 0x030200
00905 newFont.setStyleStrategy(QFont::OpenGLCompatible);
00906 # endif
00907 newFont.setStyleHint(QFont::AnyStyle, QFont::PreferBitmap);
00908 renderText(x, y, text, newFont);
00909 # else
00910 if (tileRegion_ != NULL) {
00911 renderText((x-tileRegion_->xMin) * width() / (tileRegion_->xMax - tileRegion_->xMin),
00912 (y-tileRegion_->yMin) * height() / (tileRegion_->yMax - tileRegion_->yMin), text, scaledFont(fnt));
00913 } else
00914 renderText(x, y, text, fnt);
00915 # endif
00916
00917 #endif
00918 }
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00998 void QGLViewer::displayMessage(const QString& message, int delay)
00999 {
01000 message_ = message;
01001 displayMessage_ = true;
01002 #if QT_VERSION >= 0x040000
01003
01004 messageTimer_.start(delay);
01005 #else
01006 if (messageTimer_.isActive())
01007 messageTimer_.changeInterval(delay);
01008 else
01009 messageTimer_.start(delay, true);
01010 #endif
01011 if (textIsEnabled() && updateGLOK_)
01012 updateGL();
01013 }
01014
01015 void QGLViewer::hideMessage()
01016 {
01017 displayMessage_ = false;
01018 if (textIsEnabled())
01019 updateGL();
01020 }
01021
01022
01032 void QGLViewer::displayFPS()
01033 {
01034 drawText(10, int(1.5*((QApplication::font().pixelSize()>0)?QApplication::font().pixelSize():QApplication::font().pointSize())), fpsString_);
01035 }
01036
01068 void QGLViewer::startScreenCoordinatesSystem(bool upward) const
01069 {
01070 glMatrixMode(GL_PROJECTION);
01071 glPushMatrix();
01072 glLoadIdentity();
01073 if (tileRegion_ != NULL)
01074 if (upward)
01075 glOrtho(tileRegion_->xMin, tileRegion_->xMax, tileRegion_->yMin, tileRegion_->yMax, 0.0, -1.0);
01076 else
01077 glOrtho(tileRegion_->xMin, tileRegion_->xMax, tileRegion_->yMax, tileRegion_->yMin, 0.0, -1.0);
01078 else
01079 if (upward)
01080 glOrtho(0, width(), 0, height(), 0.0, -1.0);
01081 else
01082 glOrtho(0, width(), height(), 0, 0.0, -1.0);
01083
01084 glMatrixMode(GL_MODELVIEW);
01085 glPushMatrix();
01086 glLoadIdentity();
01087 }
01088
01093 void QGLViewer::stopScreenCoordinatesSystem() const
01094 {
01095 glMatrixMode(GL_PROJECTION);
01096 glPopMatrix();
01097
01098 glMatrixMode(GL_MODELVIEW);
01099 glPopMatrix();
01100 }
01101
01105 void QGLViewer::timerEvent(QTimerEvent *)
01106 {
01107 if (animationIsStarted())
01108 {
01109 animate();
01110 updateGL();
01111 }
01112 }
01113
01115 void QGLViewer::startAnimation()
01116 {
01117 animationTimerId_ = startTimer(animationPeriod());
01118 animationStarted_ = true;
01119 }
01120
01122 void QGLViewer::stopAnimation()
01123 {
01124 animationStarted_ = false;
01125 if (animationTimerId_ != 0)
01126 killTimer(animationTimerId_);
01127 }
01128
01132 void QGLViewer::closeEvent(QCloseEvent *e)
01133 {
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164 saveStateToFile();
01165 QGLWidget::closeEvent(e);
01166 }
01167
01177 void QGLViewer::select(const QMouseEvent* event)
01178 {
01179
01180 Q_EMIT pointSelected(event);
01181 select(event->pos());
01182 }
01183
01234 void QGLViewer::select(const QPoint& point)
01235 {
01236 beginSelection(point);
01237 drawWithNames();
01238 endSelection(point);
01239 postSelection(point);
01240 }
01241
01253 void QGLViewer::beginSelection(const QPoint& point)
01254 {
01255
01256 makeCurrent();
01257
01258
01259 glSelectBuffer(selectBufferSize(), selectBuffer());
01260 glRenderMode(GL_SELECT);
01261 glInitNames();
01262
01263
01264 glMatrixMode(GL_PROJECTION);
01265 glLoadIdentity();
01266 static GLint viewport[4];
01267 camera()->getViewport(viewport);
01268 gluPickMatrix(point.x(), point.y(), selectRegionWidth(), selectRegionHeight(), viewport);
01269
01270
01271
01272 camera()->loadProjectionMatrix(false);
01273
01274 camera()->loadModelViewMatrix();
01275 }
01276
01313 void QGLViewer::endSelection(const QPoint& point)
01314 {
01315 Q_UNUSED(point);
01316
01317
01318 glFlush();
01319
01320
01321 GLint nbHits = glRenderMode(GL_RENDER);
01322
01323 if (nbHits <= 0)
01324 setSelectedName(-1);
01325 else
01326 {
01327
01328
01329
01330
01331 GLuint zMin = (selectBuffer())[1];
01332 setSelectedName((selectBuffer())[3]);
01333 for (int i=1; i<nbHits; ++i)
01334 if ((selectBuffer())[4*i+1] < zMin)
01335 {
01336 zMin = (selectBuffer())[4*i+1];
01337 setSelectedName((selectBuffer())[4*i+3]);
01338 }
01339 }
01340 }
01341
01345 void QGLViewer::setSelectBufferSize(int size)
01346 {
01347 if (selectBuffer_)
01348 delete[] selectBuffer_;
01349 selectBufferSize_ = size;
01350 selectBuffer_ = new GLuint[selectBufferSize()];
01351 }
01352
01353 void QGLViewer::performClickAction(ClickAction ca, const QMouseEvent* const e)
01354 {
01355
01356 switch (ca)
01357 {
01358
01359
01360 case NO_CLICK_ACTION :
01361 break;
01362 case ZOOM_ON_PIXEL :
01363 camera()->interpolateToZoomOnPixel(e->pos());
01364 break;
01365 case ZOOM_TO_FIT :
01366 camera()->interpolateToFitScene();
01367 break;
01368 case SELECT :
01369 select(e);
01370 updateGL();
01371 break;
01372 case RAP_FROM_PIXEL :
01373 if (camera()->setRevolveAroundPointFromPixel(e->pos()))
01374 {
01375 setVisualHintsMask(1);
01376 updateGL();
01377 }
01378 break;
01379 case RAP_IS_CENTER :
01380 camera()->setRevolveAroundPoint(sceneCenter());
01381 setVisualHintsMask(1);
01382 updateGL();
01383 break;
01384 case CENTER_FRAME :
01385 if (manipulatedFrame())
01386 manipulatedFrame()->projectOnLine(camera()->position(), camera()->viewDirection());
01387 break;
01388 case CENTER_SCENE :
01389 camera()->centerScene();
01390 break;
01391 case SHOW_ENTIRE_SCENE :
01392 camera()->showEntireScene();
01393 break;
01394 case ALIGN_FRAME :
01395 if (manipulatedFrame())
01396 manipulatedFrame()->alignWithFrame(camera()->frame());
01397 break;
01398 case ALIGN_CAMERA :
01399 camera()->frame()->alignWithFrame(NULL, true);
01400 break;
01401 }
01402 }
01403
01420 void QGLViewer::mousePressEvent(QMouseEvent* e)
01421 {
01422
01423
01424 ClickActionPrivate cap;
01425 cap.doubleClick = false;
01426 #if QT_VERSION >= 0x040000
01427 cap.modifiers = e->modifiers();
01428 cap.button = e->button();
01429 cap.buttonsBefore = (QtMouseButtons)(e->buttons() & ~(e->button()));
01430 #else
01431 cap.modifiers = (QtKeyboardModifiers)(e->state() & Qt::KeyboardModifierMask);
01432 cap.button = (QtMouseButtons)((e->stateAfter() & Qt::MouseButtonMask) & (~(e->state() & Qt::MouseButtonMask)));
01433 cap.buttonsBefore = (QtMouseButtons)(e->state() & Qt::MouseButtonMask);
01434 #endif
01435
01436 if (clickBinding_.contains(cap))
01437 performClickAction(clickBinding_[cap], e);
01438 else
01439 if (mouseGrabber())
01440 {
01441 if (mouseGrabberIsAManipulatedFrame_)
01442 {
01443 for (QMap<int, MouseActionPrivate>::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it!=end; ++it)
01444 #if QT_VERSION >= 0x040000
01445 if ((it.value().handler == FRAME) && ((it.key() & Qt::MouseButtonMask) == e->buttons()))
01446 #else
01447 if ((it.data().handler == FRAME) && ((it.key() & Qt::MouseButtonMask) == (e->stateAfter() & Qt::MouseButtonMask)))
01448 #endif
01449 {
01450 ManipulatedFrame* mf = dynamic_cast<ManipulatedFrame*>(mouseGrabber());
01451 if (mouseGrabberIsAManipulatedCameraFrame_)
01452 {
01453 mf->ManipulatedFrame::startAction(it.value().action, it.value().withConstraint);
01454 mf->ManipulatedFrame::mousePressEvent(e, camera());
01455 }
01456 else
01457 {
01458 mf->startAction(it.value().action, it.value().withConstraint);
01459 mf->mousePressEvent(e, camera());
01460 }
01461 break;
01462 }
01463 }
01464 else
01465 mouseGrabber()->mousePressEvent(e, camera());
01466 updateGL();
01467 }
01468 else
01469 {
01470
01471 #if QT_VERSION >= 0x040000
01472 const int state = e->modifiers() | e->buttons();
01473 #else
01474 const int state = e->stateAfter();
01475 #endif
01476
01477 if (mouseBinding_.contains(state))
01478 {
01479 MouseActionPrivate map = mouseBinding_[state];
01480 switch (map.handler)
01481 {
01482 case CAMERA :
01483 camera()->frame()->startAction(map.action, map.withConstraint);
01484 camera()->frame()->mousePressEvent(e, camera());
01485 break;
01486 case FRAME :
01487 if (manipulatedFrame())
01488 {
01489 if (manipulatedFrameIsACamera_)
01490 {
01491 manipulatedFrame()->ManipulatedFrame::startAction(map.action, map.withConstraint);
01492 manipulatedFrame()->ManipulatedFrame::mousePressEvent(e, camera());
01493 }
01494 else
01495 {
01496 manipulatedFrame()->startAction(map.action, map.withConstraint);
01497 manipulatedFrame()->mousePressEvent(e, camera());
01498 }
01499 }
01500 break;
01501 }
01502 if (map.action == SCREEN_ROTATE)
01503
01504 updateGL();
01505 }
01506 #if QT_VERSION >= 0x030000
01507 else
01508 e->ignore();
01509 #endif
01510 }
01511 }
01512
01552 void QGLViewer::mouseMoveEvent(QMouseEvent* e)
01553 {
01554 if (mouseGrabber())
01555 {
01556 mouseGrabber()->checkIfGrabsMouse(e->x(), e->y(), camera());
01557 if (mouseGrabber()->grabsMouse())
01558 if (mouseGrabberIsAManipulatedCameraFrame_)
01559 (dynamic_cast<ManipulatedFrame*>(mouseGrabber()))->ManipulatedFrame::mouseMoveEvent(e, camera());
01560 else
01561 mouseGrabber()->mouseMoveEvent(e, camera());
01562 else
01563 setMouseGrabber(NULL);
01564 updateGL();
01565 }
01566
01567 if (!mouseGrabber())
01568 {
01569
01570 if (camera()->frame()->isManipulated())
01571 {
01572 camera()->frame()->mouseMoveEvent(e, camera());
01573
01574 if (camera()->frame()->action_ == ZOOM_ON_REGION)
01575 updateGL();
01576 }
01577 else
01578 if ((manipulatedFrame()) && (manipulatedFrame()->isManipulated()))
01579 if (manipulatedFrameIsACamera_)
01580 manipulatedFrame()->ManipulatedFrame::mouseMoveEvent(e, camera());
01581 else
01582 manipulatedFrame()->mouseMoveEvent(e, camera());
01583 else
01584 if (hasMouseTracking())
01585 {
01586 #if QT_VERSION >= 0x040000
01587 Q_FOREACH (MouseGrabber* mg, MouseGrabber::MouseGrabberPool())
01588 {
01589 #else
01590 QPtrListIterator<MouseGrabber> it(MouseGrabber::MouseGrabberPool());
01591 for (MouseGrabber* mg; (mg = it.current()); ++it)
01592 {
01593 #endif
01594 mg->checkIfGrabsMouse(e->x(), e->y(), camera());
01595 if (mg->grabsMouse())
01596 {
01597 setMouseGrabber(mg);
01598
01599 if (mouseGrabber() == mg)
01600 {
01601 updateGL();
01602 break;
01603 }
01604 }
01605 }
01606 }
01607 }
01608 }
01609
01615 void QGLViewer::mouseReleaseEvent(QMouseEvent* e)
01616 {
01617 if (mouseGrabber())
01618 {
01619 if (mouseGrabberIsAManipulatedCameraFrame_)
01620 (dynamic_cast<ManipulatedFrame*>(mouseGrabber()))->ManipulatedFrame::mouseReleaseEvent(e, camera());
01621 else
01622 mouseGrabber()->mouseReleaseEvent(e, camera());
01623 mouseGrabber()->checkIfGrabsMouse(e->x(), e->y(), camera());
01624 if (!(mouseGrabber()->grabsMouse()))
01625 setMouseGrabber(NULL);
01626
01627 }
01628 else
01629
01630 if (camera()->frame()->isManipulated())
01631 {
01632
01633
01634 camera()->frame()->mouseReleaseEvent(e, camera());
01635
01636
01637
01638 }
01639 else
01640 if ((manipulatedFrame()) && (manipulatedFrame()->isManipulated()))
01641 {
01642
01643 if (manipulatedFrameIsACamera_)
01644 manipulatedFrame()->ManipulatedFrame::mouseReleaseEvent(e, camera());
01645 else
01646 manipulatedFrame()->mouseReleaseEvent(e, camera());
01647
01648
01649 }
01650 #if QT_VERSION >= 0x030000
01651 else
01652 e->ignore();
01653 #endif
01654
01655
01656
01657 updateGL();
01658 }
01659
01664 void QGLViewer::wheelEvent(QWheelEvent* e)
01665 {
01666 if (mouseGrabber())
01667 {
01668 if (mouseGrabberIsAManipulatedFrame_)
01669 {
01670 for (QMap<QtKeyboardModifiers, MouseActionPrivate>::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it!=end; ++it)
01671 if (it.value().handler == FRAME)
01672 {
01673 ManipulatedFrame* mf = dynamic_cast<ManipulatedFrame*>(mouseGrabber());
01674 if (mouseGrabberIsAManipulatedCameraFrame_)
01675 {
01676 mf->ManipulatedFrame::startAction(it.value().action, it.value().withConstraint);
01677 mf->ManipulatedFrame::wheelEvent(e, camera());
01678 }
01679 else
01680 {
01681 mf->startAction(it.value().action, it.value().withConstraint);
01682 mf->wheelEvent(e, camera());
01683 }
01684 break;
01685 }
01686 }
01687 else
01688 mouseGrabber()->wheelEvent(e, camera());
01689 updateGL();
01690 }
01691 else
01692 {
01693
01694 #if QT_VERSION >= 0x040000
01695 const QtKeyboardModifiers modifiers = e->modifiers();
01696 #else
01697 const QtKeyboardModifiers modifiers = e->state();
01698 #endif
01699 if (wheelBinding_.contains(modifiers))
01700 {
01701 MouseActionPrivate map = wheelBinding_[modifiers];
01702 switch (map.handler)
01703 {
01704 case CAMERA :
01705 camera()->frame()->startAction(map.action, map.withConstraint);
01706 camera()->frame()->wheelEvent(e, camera());
01707 break;
01708 case FRAME :
01709 if (manipulatedFrame()) {
01710 if (manipulatedFrameIsACamera_)
01711 {
01712 manipulatedFrame()->ManipulatedFrame::startAction(map.action, map.withConstraint);
01713 manipulatedFrame()->ManipulatedFrame::wheelEvent(e, camera());
01714 }
01715 else
01716 {
01717 manipulatedFrame()->startAction(map.action, map.withConstraint);
01718 manipulatedFrame()->wheelEvent(e, camera());
01719 }
01720 }
01721 break;
01722 }
01723 }
01724 #if QT_VERSION >= 0x030000
01725 else
01726 e->ignore();
01727 #endif
01728 }
01729 }
01730
01735 void QGLViewer::mouseDoubleClickEvent(QMouseEvent* e)
01736 {
01737
01738 ClickActionPrivate cap;
01739 cap.doubleClick = true;
01740 #if QT_VERSION >= 0x040000
01741 cap.modifiers = e->modifiers();
01742 cap.button = e->button();
01743 cap.buttonsBefore = (QtMouseButtons)(e->buttons() & ~(e->button()));
01744 #else
01745 cap.modifiers = (QtKeyboardModifiers)(e->state() & Qt::KeyboardModifierMask);
01746 cap.button = (QtMouseButtons)((e->stateAfter() & Qt::MouseButtonMask) & (~(e->state() & Qt::MouseButtonMask)));
01747 cap.buttonsBefore = (QtMouseButtons)(e->state() & Qt::MouseButtonMask);
01748 #endif
01749 if (clickBinding_.contains(cap))
01750 performClickAction(clickBinding_[cap], e);
01751 else
01752 if (mouseGrabber())
01753 mouseGrabber()->mouseDoubleClickEvent(e, camera());
01754 #if QT_VERSION >= 0x030000
01755 else
01756 e->ignore();
01757 #endif
01758 }
01759
01764 void QGLViewer::setStereoDisplay(bool stereo)
01765 {
01766 if (format().stereo())
01767 {
01768 stereo_ = stereo;
01769 if (!displaysInStereo())
01770 {
01771 glDrawBuffer(GL_BACK_LEFT);
01772 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01773 glDrawBuffer(GL_BACK_RIGHT);
01774 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01775 }
01776
01777 Q_EMIT stereoChanged(stereo_);
01778
01779 if (updateGLOK_)
01780 updateGL();
01781 }
01782 else
01783 if (stereo)
01784 QMessageBox::warning(this, tr("Stereo not supported", "Message box window title"), tr("Stereo is not supported on this display."));
01785 else
01786 stereo_ = false;
01787 }
01788
01793 void QGLViewer::setFullScreen(bool fullScreen)
01794 {
01795 fullScreen_ = fullScreen;
01796
01797
01798 if (!updateGLOK_)
01799 return;
01800
01801 QWidget* tlw = topLevelWidget();
01802
01803 if (isFullScreen())
01804 {
01805 prevPos_ = topLevelWidget()->pos();
01806 tlw->showFullScreen();
01807 tlw->move(0,0);
01808 }
01809 else
01810 {
01811 tlw->showNormal();
01812 tlw->move(prevPos_);
01813 }
01814 }
01815
01822 void QGLViewer::setMouseGrabber(MouseGrabber* mouseGrabber)
01823 {
01824 if (!mouseGrabberIsEnabled(mouseGrabber))
01825 return;
01826
01827 mouseGrabber_ = mouseGrabber;
01828
01829 mouseGrabberIsAManipulatedFrame_ = (dynamic_cast<ManipulatedFrame*>(mouseGrabber) != NULL);
01830 mouseGrabberIsAManipulatedCameraFrame_ = ((dynamic_cast<ManipulatedCameraFrame*>(mouseGrabber) != NULL) &&
01831 (mouseGrabber != camera()->frame()));
01832 Q_EMIT mouseGrabberChanged(mouseGrabber);
01833 }
01834
01836 void QGLViewer::setMouseGrabberIsEnabled(const qglviewer::MouseGrabber* const mouseGrabber, bool enabled)
01837 {
01838 if (enabled)
01839 disabledMouseGrabbers_.remove(reinterpret_cast<size_t>(mouseGrabber));
01840 else
01841 disabledMouseGrabbers_[reinterpret_cast<size_t>(mouseGrabber)];
01842 }
01843
01844 static QString keyboardModifiersString(QtKeyboardModifiers m, bool noButton=false)
01845 {
01846 #if QT_VERSION >= 0x040000
01847 if (noButton && (m==Qt::NoModifier))
01848 #else
01849 if (noButton && (m==Qt::NoButton))
01850 #endif
01851 return QGLViewer::tr("(no button)");
01852
01853 QString keySequence = "";
01854
01855 #if QT_VERSION >= 0x040000
01856 if (m & Qt::ControlModifier) keySequence += "Ctrl+";
01857 if (m & Qt::AltModifier) keySequence += "Alt+";
01858 if (m & Qt::ShiftModifier) keySequence += "Shift+";
01859 if (m & Qt::MetaModifier) keySequence += "Meta+";
01860 #else
01861 if (m & Qt::ControlButton) keySequence += "Ctrl+";
01862 if (m & Qt::AltButton) keySequence += "Alt+";
01863 if (m & Qt::ShiftButton) keySequence += "Shift+";
01864 # if QT_VERSION >= 0x030000
01865 if (m & Qt::MetaButton) keySequence += "Meta+";
01866 # endif
01867 #endif
01868
01869 if (keySequence.length() > 0)
01870 #if QT_VERSION >= 0x040000
01871 return QKeySequence(keySequence+"X").toString(QKeySequence::NativeText).replace("X", "");
01872 #else
01873 return QString(QKeySequence(keySequence+"X")).replace("X", "");
01874 #endif
01875 else
01876 return QString();
01877 }
01878
01879 static QString mouseButtonsString(QtMouseButtons b)
01880 {
01881 QString result("");
01882 bool addAmpersand = false;
01883 if (b & Qt::LeftButton) { result += QGLViewer::tr("Left", "left mouse button"); addAmpersand=true; }
01884 if (b & Qt::MidButton) { if (addAmpersand) result += " & "; result += QGLViewer::tr("Middle", "middle mouse button"); addAmpersand=true; }
01885 if (b & Qt::RightButton) { if (addAmpersand) result += " & "; result += QGLViewer::tr("Right", "right mouse button"); }
01886 return result;
01887 }
01888
01889 QString QGLViewer::mouseActionString(QGLViewer::MouseAction ma)
01890 {
01891 switch (ma)
01892 {
01893 case QGLViewer::NO_MOUSE_ACTION : return QString::null;
01894 case QGLViewer::ROTATE : return QGLViewer::tr("Rotates", "ROTATE mouse action");
01895 case QGLViewer::ZOOM : return QGLViewer::tr("Zooms", "ZOOM mouse action");
01896 case QGLViewer::TRANSLATE : return QGLViewer::tr("Translates", "TRANSLATE mouse action");
01897 case QGLViewer::MOVE_FORWARD : return QGLViewer::tr("Moves forward", "MOVE_FORWARD mouse action");
01898 case QGLViewer::LOOK_AROUND : return QGLViewer::tr("Looks around", "LOOK_AROUND mouse action");
01899 case QGLViewer::MOVE_BACKWARD : return QGLViewer::tr("Moves backward", "MOVE_BACKWARD mouse action");
01900 case QGLViewer::SCREEN_ROTATE : return QGLViewer::tr("Rotates in screen plane", "SCREEN_ROTATE mouse action");
01901 case QGLViewer::ROLL : return QGLViewer::tr("Rolls", "ROLL mouse action");
01902 case QGLViewer::DRIVE : return QGLViewer::tr("Drives", "DRIVE mouse action");
01903 case QGLViewer::SCREEN_TRANSLATE : return QGLViewer::tr("Horizontally/Vertically translates", "SCREEN_TRANSLATE mouse action");
01904 case QGLViewer::ZOOM_ON_REGION : return QGLViewer::tr("Zooms on region for", "ZOOM_ON_REGION mouse action");
01905 }
01906 return QString::null;
01907 }
01908
01909 QString QGLViewer::clickActionString(QGLViewer::ClickAction ca)
01910 {
01911 switch (ca)
01912 {
01913 case QGLViewer::NO_CLICK_ACTION : return QString::null;
01914 case QGLViewer::ZOOM_ON_PIXEL : return QGLViewer::tr("Zooms on pixel", "ZOOM_ON_PIXEL click action");
01915 case QGLViewer::ZOOM_TO_FIT : return QGLViewer::tr("Zooms to fit scene", "ZOOM_TO_FIT click action");
01916 case QGLViewer::SELECT : return QGLViewer::tr("Selects", "SELECT click action");
01917 case QGLViewer::RAP_FROM_PIXEL : return QGLViewer::tr("Sets revolve around point", "RAP_FROM_PIXEL click action");
01918 case QGLViewer::RAP_IS_CENTER : return QGLViewer::tr("Resets revolve around point", "RAP_IS_CENTER click action");
01919 case QGLViewer::CENTER_FRAME : return QGLViewer::tr("Centers frame", "CENTER_FRAME click action");
01920 case QGLViewer::CENTER_SCENE : return QGLViewer::tr("Centers scene", "CENTER_SCENE click action");
01921 case QGLViewer::SHOW_ENTIRE_SCENE : return QGLViewer::tr("Shows entire scene", "SHOW_ENTIRE_SCENE click action");
01922 case QGLViewer::ALIGN_FRAME : return QGLViewer::tr("Aligns frame", "ALIGN_FRAME click action");
01923 case QGLViewer::ALIGN_CAMERA : return QGLViewer::tr("Aligns camera", "ALIGN_CAMERA click action");
01924 }
01925 return QString::null;
01926 }
01927
01928 QString QGLViewer::formatClickActionPrivate(ClickActionPrivate cap)
01929 {
01930 bool buttonsBefore = cap.buttonsBefore != Qt::NoButton;
01931 return tr("%1%2%3%4%5%6", "Modifier / button or wheel / double click / with / button / pressed")
01932 .arg(keyboardModifiersString(cap.modifiers))
01933 .arg(mouseButtonsString(cap.button)+(cap.button == Qt::NoButton ? tr("Wheel", "Mouse wheel") : ""))
01934 .arg(cap.doubleClick ? tr(" double click", "Suffix after mouse button") : "")
01935 .arg(buttonsBefore ? tr(" with ", "As in : Left button with Ctrl pressed") : "")
01936 .arg(buttonsBefore ? mouseButtonsString(cap.buttonsBefore) : "")
01937 .arg(buttonsBefore ? tr(" pressed", "As in : Left button with Ctrl pressed") : "");
01938 }
01939
01974 void QGLViewer::setMouseBindingDescription(int state, QString description, bool doubleClick, QtMouseButtons buttonsBefore)
01975 {
01976 ClickActionPrivate cap;
01977 cap.modifiers = QtKeyboardModifiers(convertToKeyboardModifiers(state) & Qt::KeyboardModifierMask);
01978 cap.button = QtMouseButtons(state & Qt::MouseButtonMask);
01979 cap.doubleClick = doubleClick;
01980 cap.buttonsBefore = buttonsBefore;
01981
01982 if (description.isEmpty())
01983 mouseDescription_.remove(cap);
01984 else
01985 mouseDescription_[cap] = description;
01986 }
01987
01988 static QString tableLine(const QString& left, const QString& right)
01989 {
01990 static bool even = false;
01991 const QString tdtd("</b></td><td>");
01992 const QString tdtr("</td></tr>\n");
01993
01994 QString res("<tr bgcolor=\"");
01995
01996 if (even)
01997 res += "#eeeeff\">";
01998 else
01999 res += "#ffffff\">";
02000 res += "<td><b>" + left + tdtd + right + tdtr;
02001 even = !even;
02002
02003 return res;
02004 }
02005
02015 QString QGLViewer::mouseString() const
02016 {
02017 QString text("<center><table border=\"1\" cellspacing=\"0\" cellpadding=\"4\">\n");
02018 const QString trtd("<tr><td>");
02019 const QString tdtr("</td></tr>\n");
02020 const QString tdtd("</td><td>");
02021
02022 text += QString("<tr bgcolor=\"#aaaacc\"><th align=\"center\">%1</th><th align=\"center\">%2</th></tr>\n").
02023 arg(tr("Button(s)", "Buttons column header in help window mouse tab")).arg(tr("Description", "Description column header in help window mouse tab"));
02024
02025 QMap<ClickActionPrivate, QString> mouseBinding;
02026
02027
02028 for (QMap<ClickActionPrivate, QString>::ConstIterator itm=mouseDescription_.begin(), endm=mouseDescription_.end(); itm!=endm; ++itm)
02029 mouseBinding[itm.key()] = itm.value();
02030
02031 for (QMap<ClickActionPrivate, QString>::ConstIterator it=mouseBinding.begin(), end=mouseBinding.end(); it != end; ++it)
02032 {
02033
02034 if (it.value().isNull())
02035 continue;
02036
02037 text += tableLine(formatClickActionPrivate(it.key()), it.value());
02038 }
02039
02040
02041 if (!mouseBinding.isEmpty())
02042 {
02043 mouseBinding.clear();
02044 text += QString("<tr bgcolor=\"#aaaacc\"><td colspan=2>%1</td></tr>\n").arg(tr("Standard mouse bindings", "In help window mouse tab"));
02045 }
02046
02047
02048
02049
02050 for (QMap<QtKeyboardModifiers, MouseActionPrivate>::ConstIterator itw=wheelBinding_.begin(), endw=wheelBinding_.end(); itw != endw; ++itw)
02051 {
02052 ClickActionPrivate cap;
02053 cap.doubleClick = false;
02054 cap.modifiers = itw.key();
02055 cap.button = Qt::NoButton;
02056 cap.buttonsBefore = Qt::NoButton;
02057
02058 QString text = mouseActionString(itw.value().action);
02059
02060 if (!text.isNull())
02061 {
02062 switch (itw.value().handler)
02063 {
02064 case CAMERA: text += " " + tr("camera", "Suffix after action"); break;
02065 case FRAME: text += " " + tr("manipulated frame", "Suffix after action"); break;
02066 }
02067 if (!(itw.value().withConstraint))
02068 text += "*";
02069 }
02070
02071 mouseBinding[cap] = text;
02072 }
02073
02074 for (QMap<int, MouseActionPrivate>::ConstIterator itmb=mouseBinding_.begin(), endmb=mouseBinding_.end();
02075 itmb != endmb; ++itmb)
02076 {
02077 ClickActionPrivate cap;
02078 cap.doubleClick = false;
02079 cap.modifiers = QtKeyboardModifiers(itmb.key() & Qt::KeyboardModifierMask);
02080 cap.button = QtMouseButtons(itmb.key() & Qt::MouseButtonMask);
02081 cap.buttonsBefore = Qt::NoButton;
02082
02083 QString text = mouseActionString(itmb.value().action);
02084
02085 if (!text.isNull())
02086 {
02087 switch (itmb.value().handler)
02088 {
02089 case CAMERA: text += " " + tr("camera", "Suffix after action"); break;
02090 case FRAME: text += " " + tr("manipulated frame", "Suffix after action"); break;
02091 }
02092 if (!(itmb.value().withConstraint))
02093 text += "*";
02094 }
02095 mouseBinding[cap] = text;
02096 }
02097
02098 for (QMap<ClickActionPrivate, ClickAction>::ConstIterator itcb=clickBinding_.begin(), endcb=clickBinding_.end(); itcb!=endcb; ++itcb)
02099 mouseBinding[itcb.key()] = clickActionString(itcb.value());
02100
02101 for (QMap<ClickActionPrivate, QString>::ConstIterator it2=mouseBinding.begin(), end2=mouseBinding.end(); it2 != end2; ++it2)
02102 {
02103 if (it2.value().isNull())
02104 continue;
02105
02106 text += tableLine(formatClickActionPrivate(it2.key()), it2.value());
02107 }
02108
02109 text += "</table></center>";
02110
02111 return text;
02112 }
02113
02128 void QGLViewer::setKeyDescription(int key, QString description)
02129 {
02130 #if QT_VERSION >= 0x030000
02131
02132 key = convertToKeyboardModifiers(key);
02133 #endif
02134 if (description.isEmpty())
02135 keyDescription_.remove(key);
02136 else
02137 keyDescription_[key] = description;
02138 }
02139
02140 static QString keyString(int key)
02141 {
02142 #if QT_VERSION >= 0x030000
02143 return QString(QKeySequence(convertToShortModifier(key)));
02144 #else
02145
02146 return QString(QKeySequence(key));
02147 #endif
02148 }
02149
02150 QString QGLViewer::cameraPathKeysString() const
02151 {
02152 if (pathIndex_.isEmpty())
02153 return QString::null;
02154
02155 #if QT_VERSION >= 0x040000 || QT_VERSION < 0x030000
02156 QVector<int> keys;
02157 #else
02158 QValueVector<int> keys;
02159 #endif
02160 keys.reserve(pathIndex_.count());
02161 for (QMap<Qt::Key, int>::ConstIterator i = pathIndex_.begin(), endi=pathIndex_.end(); i != endi; ++i)
02162 keys.push_back(i.key());
02163 #if QT_VERSION >= 0x040000
02164 qSort(keys);
02165 #else
02166 # if QT_VERSION >= 0x030000
02167 qHeapSort(keys);
02168 # else
02169 sort(keys.begin(), keys.end());
02170 # endif
02171 #endif
02172
02173 #if QT_VERSION >= 0x040000 || QT_VERSION < 0x030000
02174 QVector<int>::const_iterator it = keys.begin(), end = keys.end();
02175 #else
02176 QValueVector<int>::const_iterator it = keys.begin(), end = keys.end();
02177 #endif
02178 QString res = keyString(*it);
02179
02180 const int maxDisplayedKeys = 6;
02181 int nbDisplayedKeys = 0;
02182 int previousKey = (*it);
02183 int state = 0;
02184 ++it;
02185 while ((it != end) && (nbDisplayedKeys < maxDisplayedKeys-1))
02186 {
02187 switch (state)
02188 {
02189 case 0 :
02190 if ((*it) == previousKey + 1)
02191 state++;
02192 else
02193 {
02194 res += ", " + keyString(*it);
02195 nbDisplayedKeys++;
02196 }
02197 break;
02198 case 1 :
02199 if ((*it) == previousKey + 1)
02200 state++;
02201 else
02202 {
02203 res += ", " + keyString(previousKey);
02204 res += ", " + keyString(*it);
02205 nbDisplayedKeys += 2;
02206 state = 0;
02207 }
02208 break;
02209 default :
02210 if ((*it) != previousKey + 1)
02211 {
02212 res += ".." + keyString(previousKey);
02213 res += ", " + keyString(*it);
02214 nbDisplayedKeys += 2;
02215 state = 0;
02216 }
02217 break;
02218 }
02219 previousKey = *it;
02220 ++it;
02221 }
02222
02223 if (state == 1)
02224 res += ", " + keyString(previousKey);
02225 if (state == 2)
02226 res += ".." + keyString(previousKey);
02227 if (it != end)
02228 res += "...";
02229
02230 return res;
02231 }
02232
02241 QString QGLViewer::keyboardString() const
02242 {
02243 QString text("<center><table border=\"1\" cellspacing=\"0\" cellpadding=\"4\">\n");
02244 text += QString("<tr bgcolor=\"#aaaacc\"><th align=\"center\">%1</th><th align=\"center\">%2</th></tr>\n").
02245 arg(QGLViewer::tr("Key(s)", "Keys column header in help window mouse tab")).arg(QGLViewer::tr("Description", "Description column header in help window mouse tab"));
02246
02247 QMap<int, QString> keyDescription;
02248
02249
02250 for (QMap<int, QString>::ConstIterator kd=keyDescription_.begin(), kdend=keyDescription_.end(); kd!=kdend; ++kd)
02251 keyDescription[kd.key()] = kd.value();
02252
02253
02254 for (QMap<int, QString>::ConstIterator kb=keyDescription.begin(), endb=keyDescription.end(); kb!=endb; ++kb)
02255 text += tableLine(keyString(kb.key()), kb.value());
02256
02257
02258
02259 if (!keyDescription.isEmpty())
02260 {
02261 keyDescription.clear();
02262 text += QString("<tr bgcolor=\"#aaaacc\"><td colspan=2>%1</td></tr>\n").arg(QGLViewer::tr("Standard viewer keys", "In help window keys tab"));
02263 }
02264
02265
02266
02267 for (QMap<KeyboardAction, int>::ConstIterator it=keyboardBinding_.begin(), end=keyboardBinding_.end(); it != end; ++it)
02268 if ((it.value() != 0) && ((!cameraIsInRevolveMode()) || ((it.key() != INCREASE_FLYSPEED) && (it.key() != DECREASE_FLYSPEED))))
02269 keyDescription[it.value()] = keyboardActionDescription_[it.key()];
02270
02271
02272 for (QMap<int, QString>::ConstIterator kb2=keyDescription.begin(), endb2=keyDescription.end(); kb2!=endb2; ++kb2)
02273 text += tableLine(keyString(kb2.key()), kb2.value());
02274
02275
02276
02277 const QString cpks = cameraPathKeysString();
02278 if (!cpks.isNull())
02279 {
02280 text += "<tr bgcolor=\"#ccccff\"><td colspan=2>\n";
02281 text += QGLViewer::tr("Camera paths are controlled using %1 (noted <i>Fx</i> below):", "Help window key tab camera keys").arg(cpks) + "</td></tr>\n";
02282 text += tableLine(keyboardModifiersString(playPathKeyboardModifiers()) + "<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>",
02283 QGLViewer::tr("Plays path (or resets saved position)"));
02284 text += tableLine(keyboardModifiersString(addKeyFrameKeyboardModifiers()) + "<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>",
02285 QGLViewer::tr("Adds a key frame to path (or defines a position)"));
02286 text += tableLine(keyboardModifiersString(addKeyFrameKeyboardModifiers()) + "<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>+<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>",
02287 QGLViewer::tr("Deletes path (or saved position)"));
02288 }
02289 text += "</table></center>";
02290
02291 return text;
02292 }
02293
02295 void QGLViewer::aboutQGLViewer() {
02296 help();
02297 #if QT_VERSION >= 0x040000
02298 helpWidget()->setCurrentIndex(3);
02299 #else
02300 helpWidget()->setCurrentPage(3);
02301 #endif
02302 }
02303
02304
02314 void QGLViewer::help()
02315 {
02316 Q_EMIT helpRequired();
02317
02318 bool resize = false;
02319 int width=600;
02320 int height=400;
02321
02322 static QString label[] = {tr("&Help", "Help window tab title"), tr("&Keyboard", "Help window tab title"), tr("&Mouse", "Help window tab title"), tr("&About", "Help window about title")};
02323
02324 if (!helpWidget())
02325 {
02326
02327 helpWidget_ = new QTabWidget(NULL);
02328 #if QT_VERSION >= 0x040000
02329 helpWidget()->setWindowTitle(tr("Help", "Help window title"));
02330 #else
02331 helpWidget()->setCaption(tr("Help", "Help window title"));
02332 #endif
02333
02334 resize = true;
02335 for (int i=0; i<4; ++i)
02336 {
02337 QTextEdit* tab = new QTextEdit(NULL);
02338 #if QT_VERSION >= 0x030000
02339 tab->setReadOnly(true);
02340 #endif
02341
02342 #if QT_VERSION >= 0x040000
02343 helpWidget()->insertTab(i, tab, label[i]);
02344 if (i==3) {
02345 # include "qglviewer-icon.xpm"
02346 QPixmap pixmap(qglviewer_icon);
02347 tab->document()->addResource(QTextDocument::ImageResource,
02348 QUrl("mydata://qglviewer-icon.xpm"), QVariant(pixmap));
02349 }
02350 #else
02351 tab->setTextFormat(Qt::RichText);
02352 helpWidget()->insertTab(tab, label[i]);
02353 #endif
02354 }
02355 }
02356
02357
02358 #if QT_VERSION < 0x030000
02359 const int currentPageIndex = helpWidget()->currentPageIndex();
02360 #endif
02361
02362 for (int i=0; i<4; ++i)
02363 {
02364 QString text;
02365 switch (i)
02366 {
02367 case 0 : text = helpString(); break;
02368 case 1 : text = keyboardString(); break;
02369 case 2 : text = mouseString(); break;
02370 case 3 : text = QString("<center><br><img src=\"mydata://qglviewer-icon.xpm\">") + tr(
02371 "<h1>libQGLViewer</h1>"
02372 "<h3>Version %1</h3><br>"
02373 "A versatile 3D viewer based on OpenGL and Qt<br>"
02374 "Copyright 2002-%2 Gilles Debunne<br>"
02375 "<code>%3</code>").arg(QGLViewerVersionString()).arg("2010").arg("http://www.libqglviewer.com") +
02376 QString("</center>");
02377 break;
02378 default : break;
02379 }
02380
02381 #if QT_VERSION >= 0x040000
02382 QTextEdit* textEdit = (QTextEdit*)(helpWidget()->widget(i));
02383 textEdit->setHtml(text);
02384 #else
02385 # if QT_VERSION < 0x030000
02386 helpWidget()->setCurrentPage(i);
02387 QTextEdit* textEdit = (QTextEdit*)(helpWidget()->currentPage());
02388 # else
02389 QTextEdit* textEdit = (QTextEdit*)(helpWidget()->page(i));
02390 # endif
02391 textEdit->setText(text);
02392 #endif
02393
02394 #if QT_VERSION < 0x040000
02395 if (resize && (textEdit->heightForWidth(width) > height))
02396 height = textEdit->heightForWidth(width);
02397 #else
02398 if (resize && (textEdit->height() > height))
02399 height = textEdit->height();
02400 #endif
02401 }
02402
02403 #if QT_VERSION < 0x030000
02404 helpWidget()->setCurrentPage(currentPageIndex);
02405 #endif
02406
02407 if (resize)
02408 helpWidget()->resize(width, height+40);
02409 helpWidget()->show();
02410 helpWidget()->raise();
02411 }
02412
02439 void QGLViewer::keyPressEvent(QKeyEvent *e)
02440 {
02441 if (e->key() == 0)
02442 {
02443 e->ignore();
02444 return;
02445 }
02446
02447 const Qt::Key key = Qt::Key(e->key());
02448 #if QT_VERSION >= 0x040000
02449 const QtKeyboardModifiers modifiers = e->modifiers();
02450 #else
02451 const QtKeyboardModifiers modifiers = (QtKeyboardModifiers)(e->state() & Qt::KeyboardModifierMask);
02452 #endif
02453
02454 QMap<KeyboardAction, int>::ConstIterator it=keyboardBinding_.begin(), end=keyboardBinding_.end();
02455 while ((it != end) && (it.value() != (key | modifiers)))
02456 ++it;
02457
02458 if (it != end)
02459 handleKeyboardAction(it.key());
02460 else
02461 if (pathIndex_.contains(Qt::Key(key)))
02462 {
02463
02464 int index = pathIndex_[Qt::Key(key)];
02465
02466 static QTime doublePress;
02467
02468 if (modifiers == playPathKeyboardModifiers())
02469 {
02470 int elapsed = doublePress.restart();
02471 if ((elapsed < 250) && (index==previousPathId_))
02472 camera()->resetPath(index);
02473 else
02474 {
02475
02476 if (index != previousPathId_)
02477 {
02478 KeyFrameInterpolator* previous = camera()->keyFrameInterpolator(previousPathId_);
02479 if ((previous) && (previous->interpolationIsStarted()))
02480 previous->resetInterpolation();
02481 }
02482 camera()->playPath(index);
02483 }
02484 previousPathId_ = index;
02485 }
02486 else if (modifiers == addKeyFrameKeyboardModifiers())
02487 {
02488 int elapsed = doublePress.restart();
02489 if ((elapsed < 250) && (index==previousPathId_))
02490 {
02491 if (camera()->keyFrameInterpolator(index))
02492 {
02493 disconnect(camera()->keyFrameInterpolator(index), SIGNAL(interpolated()), this, SLOT(updateGL()));
02494 if (camera()->keyFrameInterpolator(index)->numberOfKeyFrames() > 1)
02495 displayMessage(tr("Path %1 deleted", "Feedback message").arg(index));
02496 else
02497 displayMessage(tr("Position %1 deleted", "Feedback message").arg(index));
02498 camera()->deletePath(index);
02499 }
02500 }
02501 else
02502 {
02503 bool nullBefore = (camera()->keyFrameInterpolator(index) == NULL);
02504 camera()->addKeyFrameToPath(index);
02505 if (nullBefore)
02506 connect(camera()->keyFrameInterpolator(index), SIGNAL(interpolated()), SLOT(updateGL()));
02507 int nbKF = camera()->keyFrameInterpolator(index)->numberOfKeyFrames();
02508 if (nbKF > 1)
02509 displayMessage(tr("Path %1, position %2 added", "Feedback message").arg(index).arg(nbKF));
02510 else
02511 displayMessage(tr("Position %1 saved", "Feedback message").arg(index));
02512 }
02513 previousPathId_ = index;
02514 }
02515 updateGL();
02516 }
02517 else
02518 e->ignore();
02519 }
02520
02521 void QGLViewer::handleKeyboardAction(KeyboardAction id)
02522 {
02523 switch (id)
02524 {
02525 case DRAW_AXIS : toggleAxisIsDrawn(); break;
02526 case DRAW_GRID : toggleGridIsDrawn(); break;
02527 case DISPLAY_FPS : toggleFPSIsDisplayed(); break;
02528 case ENABLE_TEXT : toggleTextIsEnabled(); break;
02529 case EXIT_VIEWER : saveStateToFileForAllViewers(); qApp->closeAllWindows(); break;
02530 case SAVE_SCREENSHOT : saveSnapshot(false, false); break;
02531 case FULL_SCREEN : toggleFullScreen(); break;
02532 case STEREO : toggleStereoDisplay(); break;
02533 case ANIMATION : toggleAnimation(); break;
02534 case HELP : help(); break;
02535 case EDIT_CAMERA : toggleCameraIsEdited(); break;
02536 case SNAPSHOT_TO_CLIPBOARD : snapshotToClipboard(); break;
02537 case CAMERA_MODE :
02538 toggleCameraMode();
02539 displayMessage(cameraIsInRevolveMode()?tr("Camera in revolve around mode", "Feedback message"):tr("Camera in fly mode", "Feedback message"));
02540 break;
02541
02542 case MOVE_CAMERA_LEFT :
02543 camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(-10.0*camera()->flySpeed(), 0.0, 0.0)));
02544 updateGL();
02545 break;
02546 case MOVE_CAMERA_RIGHT :
02547 camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec( 10.0*camera()->flySpeed(), 0.0, 0.0)));
02548 updateGL();
02549 break;
02550 case MOVE_CAMERA_UP :
02551 camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(0.0, 10.0*camera()->flySpeed(), 0.0)));
02552 updateGL();
02553 break;
02554 case MOVE_CAMERA_DOWN :
02555 camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(0.0, -10.0*camera()->flySpeed(), 0.0)));
02556 updateGL();
02557 break;
02558
02559 case INCREASE_FLYSPEED : camera()->setFlySpeed(camera()->flySpeed() * 1.5); break;
02560 case DECREASE_FLYSPEED : camera()->setFlySpeed(camera()->flySpeed() / 1.5); break;
02561 }
02562 }
02563
02568 void QGLViewer::resizeGL(int width, int height)
02569 {
02570 QGLWidget::resizeGL(width, height);
02571 glViewport( 0, 0, GLint(width), GLint(height) );
02572 camera()->setScreenWidthAndHeight(this->width(), this->height());
02573 }
02574
02576
02578
02596 void QGLViewer::setShortcut(KeyboardAction action, int key)
02597 {
02598 keyboardBinding_[action] = convertToKeyboardModifiers(key);
02599 }
02600
02616 int QGLViewer::shortcut(KeyboardAction action) const
02617 {
02618 if (keyboardBinding_.contains(action))
02619 return convertToShortModifier(keyboardBinding_[action]);
02620 else
02621 return 0;
02622 }
02623
02624 #ifndef DOXYGEN
02625 void QGLViewer::setKeyboardAccelerator(KeyboardAction action, int key)
02626 {
02627 qWarning("setKeyboardAccelerator is deprecated. Use setShortcut instead.");
02628 setShortcut(action, key);
02629 }
02630
02631 int QGLViewer::keyboardAccelerator(KeyboardAction action) const
02632 {
02633 qWarning("keyboardAccelerator is deprecated. Use shortcut instead.");
02634 return shortcut(action);
02635 }
02636 #endif
02637
02639
02655 Qt::Key QGLViewer::pathKey(int index) const
02656 {
02657 for (QMap<Qt::Key, int>::ConstIterator it = pathIndex_.begin(), end=pathIndex_.end(); it != end; ++it)
02658 if (it.value() == index)
02659 return it.key();
02660 return Qt::Key(0);
02661 }
02662
02674 void QGLViewer::setPathKey(int key, int index)
02675 {
02676 if (key < 0)
02677 pathIndex_.remove(Qt::Key(-key));
02678 else
02679 pathIndex_[Qt::Key(key)] = index;
02680 }
02681
02683 void QGLViewer::setPlayPathKeyboardModifiers(QtKeyboardModifiers modifiers)
02684 {
02685 playPathKeyboardModifiers_ = convertKeyboardModifiers(modifiers);
02686 }
02687
02689 void QGLViewer::setAddKeyFrameKeyboardModifiers(QtKeyboardModifiers modifiers)
02690 {
02691 addKeyFrameKeyboardModifiers_ = convertKeyboardModifiers(modifiers);
02692 }
02693
02707 QtKeyboardModifiers QGLViewer::addKeyFrameKeyboardModifiers() const
02708 {
02709 return addKeyFrameKeyboardModifiers_;
02710 }
02711
02724 QtKeyboardModifiers QGLViewer::playPathKeyboardModifiers() const
02725 {
02726 return playPathKeyboardModifiers_;
02727 }
02728
02729 #ifndef DOXYGEN
02730
02731 QtKeyboardModifiers QGLViewer::addKeyFrameStateKey() const
02732 {
02733 qWarning("addKeyFrameStateKey has been renamed addKeyFrameKeyboardModifiers");
02734 return addKeyFrameKeyboardModifiers(); }
02735
02736 QtKeyboardModifiers QGLViewer::playPathStateKey() const
02737 {
02738 qWarning("playPathStateKey has been renamed playPathKeyboardModifiers");
02739 return playPathKeyboardModifiers();
02740 }
02741
02742 void QGLViewer::setAddKeyFrameStateKey(int buttonState)
02743 {
02744 qWarning("setAddKeyFrameStateKey has been renamed setAddKeyFrameKeyboardModifiers");
02745 setAddKeyFrameKeyboardModifiers(QtKeyboardModifiers(buttonState & Qt::KeyboardModifierMask));
02746 }
02747
02748 void QGLViewer::setPlayPathStateKey(int buttonState)
02749 {
02750 qWarning("setPlayPathStateKey has been renamed setPlayPathKeyboardModifiers");
02751 setPlayPathKeyboardModifiers(QtKeyboardModifiers(buttonState & Qt::KeyboardModifierMask));
02752 }
02753
02754 Qt::Key QGLViewer::keyFrameKey(int index) const
02755 {
02756 qWarning("keyFrameKey has been renamed pathKey.");
02757 return pathKey(index);
02758 }
02759
02760 QtKeyboardModifiers QGLViewer::playKeyFramePathStateKey() const
02761 {
02762 qWarning("playKeyFramePathStateKey has been renamed playPathKeyboardModifiers.");
02763 return playPathKeyboardModifiers();
02764 }
02765
02766 void QGLViewer::setKeyFrameKey(int index, int key)
02767 {
02768 qWarning("setKeyFrameKey is deprecated, use setPathKey instead, with swapped parameters.");
02769 setPathKey(key, index);
02770 }
02771
02772 void QGLViewer::setPlayKeyFramePathStateKey(int buttonState)
02773 {
02774 qWarning("setPlayKeyFramePathStateKey has been renamed setPlayPathKeyboardModifiers.");
02775 setPlayPathKeyboardModifiers(QtKeyboardModifiers(buttonState & Qt::KeyboardModifierMask));
02776 }
02777 #endif
02778
02780
02782
02823 void QGLViewer::setHandlerKeyboardModifiers(MouseHandler handler, QtKeyboardModifiers modifiers)
02824 {
02825 QMap<int, MouseActionPrivate> newMouseBinding;
02826 QMap<QtKeyboardModifiers, MouseActionPrivate> newWheelBinding;
02827 QMap<ClickActionPrivate, ClickAction> newClickBinding_;
02828
02829 QMap<int, MouseActionPrivate>::Iterator mit;
02830 QMap<QtKeyboardModifiers, MouseActionPrivate>::Iterator wit;
02831
02832
02833 for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit)
02834 if ((mit.value().handler != handler) || (mit.value().action == ZOOM_ON_REGION))
02835 newMouseBinding[mit.key()] = mit.value();
02836
02837 for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit)
02838 if (wit.value().handler != handler)
02839 newWheelBinding[wit.key()] = wit.value();
02840
02841
02842 modifiers = convertKeyboardModifiers(modifiers);
02843 for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit)
02844 if ((mit.value().handler == handler) && (mit.value().action != ZOOM_ON_REGION))
02845 {
02846 int newState = modifiers | (mit.key() & Qt::MouseButtonMask);
02847 newMouseBinding[newState] = mit.value();
02848 }
02849
02850 for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit)
02851 if (wit.value().handler == handler)
02852 {
02853 QtKeyboardModifiers newState = modifiers;
02854 newWheelBinding[newState] = wit.value();
02855 }
02856
02857
02858 for (QMap<ClickActionPrivate, ClickAction>::ConstIterator cb=clickBinding_.begin(), end=clickBinding_.end(); cb != end; ++cb)
02859 if (((handler==CAMERA) && ((cb.value() == CENTER_SCENE) || (cb.value() == ALIGN_CAMERA))) ||
02860 ((handler==FRAME) && ((cb.value() == CENTER_FRAME) || (cb.value() == ALIGN_FRAME))))
02861 {
02862 ClickActionPrivate cap;
02863 cap.modifiers = modifiers;
02864 cap.button = cb.key().button;
02865 cap.doubleClick = cb.key().doubleClick;
02866 cap.buttonsBefore = cb.key().buttonsBefore;
02867 newClickBinding_[cap] = cb.value();
02868 }
02869 else
02870 newClickBinding_[cb.key()] = cb.value();
02871
02872 mouseBinding_ = newMouseBinding;
02873 wheelBinding_ = newWheelBinding;
02874 clickBinding_ = newClickBinding_;
02875 }
02876
02877
02878 #ifndef DOXYGEN
02879 void QGLViewer::setHandlerStateKey(MouseHandler handler, int buttonState)
02880 {
02881 qWarning("setHandlerStateKey has been renamed setHandlerKeyboardModifiers");
02882 setHandlerKeyboardModifiers(handler, QtKeyboardModifiers(buttonState & Qt::KeyboardModifierMask));
02883 }
02884
02885 void QGLViewer::setMouseStateKey(MouseHandler handler, int buttonState)
02886 {
02887 qWarning("setMouseStateKey has been renamed setHandlerKeyboardModifiers.");
02888 setHandlerKeyboardModifiers(handler, QtKeyboardModifiers(buttonState & Qt::KeyboardModifierMask));
02889 }
02890 #endif
02891
02923 void QGLViewer::setMouseBinding(int state, MouseHandler handler, MouseAction action, bool withConstraint)
02924 {
02925 if ((handler == FRAME) && ((action == MOVE_FORWARD) || (action == MOVE_BACKWARD) ||
02926 (action == ROLL) || (action == LOOK_AROUND) ||
02927 (action == ZOOM_ON_REGION)))
02928 {
02929 #if QT_VERSION >= 0x040000
02930 qWarning("Cannot bind %s to FRAME", mouseActionString(action).toLatin1().constData());
02931 #else
02932 qWarning("Cannot bind %s to FRAME", mouseActionString(action).latin1());
02933 #endif
02934 }
02935 else
02936 if ((state & Qt::MouseButtonMask) == 0)
02937 qWarning("No mouse button specified in setMouseBinding");
02938 else
02939 {
02940 MouseActionPrivate map;
02941 map.handler = handler;
02942 map.action = action;
02943 map.withConstraint = withConstraint;
02944 state = convertToKeyboardModifiers(state);
02945
02946 mouseBinding_.remove(state);
02947
02948 if (action != NO_MOUSE_ACTION)
02949 mouseBinding_.insert(state, map);
02950
02951 ClickActionPrivate cap;
02952 cap.modifiers = QtKeyboardModifiers(state & Qt::KeyboardModifierMask);
02953 cap.button = QtMouseButtons(state & Qt::MouseButtonMask);
02954 cap.doubleClick = false;
02955 cap.buttonsBefore = Qt::NoButton;
02956 clickBinding_.remove(cap);
02957 }
02958 }
02959
02978 void QGLViewer::setMouseBinding(int state, ClickAction action, bool doubleClick, QtMouseButtons buttonsBefore)
02979 {
02980 if ((buttonsBefore != Qt::NoButton) && !doubleClick)
02981 qWarning("Buttons before is only meaningful when doubleClick is true in setMouseBinding().");
02982 else
02983 if ((state & Qt::MouseButtonMask) == 0)
02984 qWarning("No mouse button specified in setMouseBinding");
02985 else
02986 {
02987 ClickActionPrivate cap;
02988 state = convertToKeyboardModifiers(state);
02989 cap.modifiers = QtKeyboardModifiers(state & Qt::KeyboardModifierMask);
02990 cap.button = QtMouseButtons(state & Qt::MouseButtonMask);
02991 cap.doubleClick = doubleClick;
02992 cap.buttonsBefore = buttonsBefore;
02993 clickBinding_.remove(cap);
02994
02995
02996 if (action != NO_CLICK_ACTION)
02997 clickBinding_.insert(cap, action);
02998
02999 if ((!doubleClick) && (buttonsBefore == Qt::NoButton))
03000 mouseBinding_.remove(state);
03001 }
03002 }
03003
03014 void QGLViewer::setWheelBinding(QtKeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint)
03015 {
03016
03017 if ((action != ZOOM) && (action != MOVE_FORWARD) && (action != MOVE_BACKWARD) && (action != NO_MOUSE_ACTION))
03018 #if QT_VERSION >= 0x040000
03019 qWarning("Cannot bind %s to wheel", mouseActionString(action).toLatin1().constData());
03020 #else
03021 qWarning("Cannot bind %s to wheel", + mouseActionString(action).latin1());
03022 #endif
03023 else
03024 if ((handler == FRAME) && (action != ZOOM) && (action != NO_MOUSE_ACTION))
03025 #if QT_VERSION >= 0x040000
03026 qWarning("Cannot bind %s to FRAME wheel", mouseActionString(action).toLatin1().constData());
03027 #else
03028 qWarning("Cannot bind %s to FRAME wheel", mouseActionString(action).latin1());
03029 #endif
03030 else
03031 {
03032 MouseActionPrivate map;
03033 map.handler = handler;
03034 map.action = action;
03035 map.withConstraint = withConstraint;
03036 modifiers = convertKeyboardModifiers(modifiers);
03037 wheelBinding_.remove(modifiers);
03038
03039 if (action != NO_MOUSE_ACTION)
03040 wheelBinding_.insert(modifiers, map);
03041 }
03042 }
03043
03055 QGLViewer::MouseAction QGLViewer::mouseAction(int state) const
03056 {
03057 state = convertToKeyboardModifiers(state);
03058 if (mouseBinding_.contains(state))
03059 return mouseBinding_[state].action;
03060 else
03061 return NO_MOUSE_ACTION;
03062 }
03063
03074 int QGLViewer::mouseHandler(int state) const
03075 {
03076 state = convertToKeyboardModifiers(state);
03077 if (mouseBinding_.contains(state))
03078 return mouseBinding_[state].handler;
03079 else
03080 return -1;
03081 }
03082
03100 int QGLViewer::mouseButtonState(MouseHandler handler, MouseAction action, bool withConstraint) const
03101 {
03102 for (QMap<int, MouseActionPrivate>::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it != end; ++it)
03103 if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) )
03104 return it.key();
03105
03106 return Qt::NoButton;
03107 }
03108
03114 QGLViewer::MouseAction QGLViewer::wheelAction(QtKeyboardModifiers modifiers) const
03115 {
03116 modifiers = convertKeyboardModifiers(modifiers);
03117 if (wheelBinding_.contains(modifiers))
03118 return wheelBinding_[modifiers].action;
03119 else
03120 return NO_MOUSE_ACTION;
03121 }
03122
03124 int QGLViewer::wheelHandler(QtKeyboardModifiers modifiers) const
03125 {
03126 modifiers = convertKeyboardModifiers(modifiers);
03127 if (wheelBinding_.contains(modifiers))
03128 return wheelBinding_[modifiers].handler;
03129 else
03130 return -1;
03131 }
03132
03137 int QGLViewer::wheelButtonState(MouseHandler handler, MouseAction action, bool withConstraint) const
03138 {
03139 for (QMap<QtKeyboardModifiers, MouseActionPrivate>::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it!=end; ++it)
03140 if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) )
03141 return it.key();
03142
03143 return -1;
03144 }
03145
03147 QGLViewer::ClickAction QGLViewer::clickAction(int state, bool doubleClick, QtMouseButtons buttonsBefore) const
03148 {
03149 ClickActionPrivate cap;
03150 cap.modifiers = QtKeyboardModifiers(convertToKeyboardModifiers(state) & Qt::KeyboardModifierMask);
03151 cap.button = QtMouseButtons(state & Qt::MouseButtonMask);
03152 cap.doubleClick = doubleClick;
03153 cap.buttonsBefore = buttonsBefore;
03154 if (clickBinding_.contains(cap))
03155 return clickBinding_[cap];
03156 else
03157 return NO_CLICK_ACTION;
03158 }
03159
03165 void QGLViewer::getClickButtonState(ClickAction ca, int& state, bool& doubleClick, QtMouseButtons& buttonsBefore) const
03166 {
03167 for (QMap<ClickActionPrivate, ClickAction>::ConstIterator it=clickBinding_.begin(), end=clickBinding_.end(); it != end; ++it)
03168 if (it.value() == ca)
03169 {
03170 state = it.key().modifiers | it.key().button;
03171 doubleClick = it.key().doubleClick;
03172 buttonsBefore = it.key().buttonsBefore;
03173 return;
03174 }
03175
03176 state = Qt::NoButton;
03177 }
03178
03182 bool QGLViewer::cameraIsInRevolveMode() const
03183 {
03184
03185 return mouseButtonState(CAMERA, ROTATE) != Qt::NoButton;
03186 }
03187
03201 void QGLViewer::toggleCameraMode()
03202 {
03203 bool revolveMode = cameraIsInRevolveMode();
03204 int bs;
03205 if (revolveMode)
03206 bs = mouseButtonState(CAMERA, ROTATE);
03207 else
03208 bs = mouseButtonState(CAMERA, MOVE_FORWARD);
03209 QtKeyboardModifiers modifiers = QtKeyboardModifiers(bs & Qt::KeyboardModifierMask);
03210
03211
03212 if (revolveMode)
03213 {
03214 camera()->frame()->updateFlyUpVector();
03215 camera()->frame()->stopSpinning();
03216
03217 setMouseBinding(modifiers | Qt::LeftButton, CAMERA, MOVE_FORWARD);
03218 setMouseBinding(modifiers | Qt::MidButton, CAMERA, LOOK_AROUND);
03219 setMouseBinding(modifiers | Qt::RightButton, CAMERA, MOVE_BACKWARD);
03220
03221 setMouseBinding(modifiers | Qt::LeftButton | Qt::MidButton, CAMERA, ROLL);
03222
03223
03224 setMouseBinding(Qt::LeftButton, NO_CLICK_ACTION, true);
03225 setMouseBinding(Qt::MidButton, NO_CLICK_ACTION, true);
03226 setMouseBinding(Qt::RightButton, NO_CLICK_ACTION, true);
03227
03228 setWheelBinding(modifiers, CAMERA, MOVE_FORWARD);
03229 }
03230 else
03231 {
03232
03233 setMouseBinding(modifiers | Qt::LeftButton, CAMERA, ROTATE);
03234 setMouseBinding(modifiers | Qt::MidButton, CAMERA, ZOOM);
03235 setMouseBinding(modifiers | Qt::RightButton, CAMERA, TRANSLATE);
03236
03237 setMouseBinding(modifiers | Qt::LeftButton | Qt::MidButton, CAMERA, SCREEN_ROTATE);
03238
03239
03240 setMouseBinding(Qt::LeftButton, ALIGN_CAMERA, true);
03241 setMouseBinding(Qt::MidButton, SHOW_ENTIRE_SCENE, true);
03242 setMouseBinding(Qt::RightButton, CENTER_SCENE, true);
03243
03244 setWheelBinding(modifiers, CAMERA, ZOOM);
03245 }
03246 }
03247
03249
03251
03263 void QGLViewer::setManipulatedFrame(ManipulatedFrame* frame)
03264 {
03265 if (manipulatedFrame())
03266 {
03267 manipulatedFrame()->stopSpinning();
03268
03269 if (manipulatedFrame() != camera()->frame())
03270 {
03271 disconnect(manipulatedFrame(), SIGNAL(manipulated()), this, SLOT(updateGL()));
03272 disconnect(manipulatedFrame(), SIGNAL(spun()), this, SLOT(updateGL()));
03273 }
03274 }
03275
03276 manipulatedFrame_ = frame;
03277
03278 manipulatedFrameIsACamera_ = ((manipulatedFrame() != camera()->frame()) &&
03279 (dynamic_cast<ManipulatedCameraFrame*>(manipulatedFrame()) != NULL));
03280
03281 if (manipulatedFrame())
03282 {
03283
03284 if (manipulatedFrame() != camera()->frame())
03285 {
03286 connect(manipulatedFrame(), SIGNAL(manipulated()), SLOT(updateGL()));
03287 connect(manipulatedFrame(), SIGNAL(spun()), SLOT(updateGL()));
03288 }
03289 }
03290 }
03291
03292 #ifndef DOXYGEN
03293
03294
03296
03311 void QGLViewer::drawVisualHints()
03312 {
03313
03314 if (visualHint_ & 1)
03315 {
03316 const float size = 15.0;
03317 Vec proj = camera()->projectedCoordinatesOf(camera()->revolveAroundPoint());
03318 startScreenCoordinatesSystem();
03319 glDisable(GL_LIGHTING);
03320 glDisable(GL_DEPTH_TEST);
03321 glLineWidth(3.0);
03322 glBegin(GL_LINES);
03323 glVertex2f(proj.x - size, proj.y);
03324 glVertex2f(proj.x + size, proj.y);
03325 glVertex2f(proj.x, proj.y - size);
03326 glVertex2f(proj.x, proj.y + size);
03327 glEnd();
03328 glEnable(GL_DEPTH_TEST);
03329 stopScreenCoordinatesSystem();
03330 }
03331
03332
03333
03334
03335
03336 ManipulatedFrame* mf = NULL;
03337 Vec pnt;
03338 if (camera()->frame()->action_ == SCREEN_ROTATE)
03339 {
03340 mf = camera()->frame();
03341 pnt = camera()->revolveAroundPoint();
03342 }
03343 if (manipulatedFrame() && (manipulatedFrame()->action_ == SCREEN_ROTATE))
03344 {
03345 mf = manipulatedFrame();
03346
03347
03348 pnt = manipulatedFrame()->position();
03349 }
03350
03351 if (mf)
03352 {
03353 pnt = camera()->projectedCoordinatesOf(pnt);
03354 startScreenCoordinatesSystem();
03355 glDisable(GL_LIGHTING);
03356 glDisable(GL_DEPTH_TEST);
03357 glLineWidth(3.0);
03358 glBegin(GL_LINES);
03359 glVertex2f(pnt.x, pnt.y);
03360 glVertex2f(mf->prevPos_.x(), mf->prevPos_.y());
03361 glEnd();
03362 glEnable(GL_DEPTH_TEST);
03363 stopScreenCoordinatesSystem();
03364 }
03365
03366
03367 if (camera()->frame()->action_ == ZOOM_ON_REGION)
03368 {
03369 startScreenCoordinatesSystem();
03370 glDisable(GL_LIGHTING);
03371 glDisable(GL_DEPTH_TEST);
03372 glLineWidth(2.0);
03373 glBegin(GL_LINE_LOOP);
03374 glVertex2i(camera()->frame()->pressPos_.x(), camera()->frame()->pressPos_.y());
03375 glVertex2i(camera()->frame()->prevPos_.x(), camera()->frame()->pressPos_.y());
03376 glVertex2i(camera()->frame()->prevPos_.x(), camera()->frame()->prevPos_.y());
03377 glVertex2i(camera()->frame()->pressPos_.x(), camera()->frame()->prevPos_.y());
03378 glEnd();
03379 glEnable(GL_DEPTH_TEST);
03380 stopScreenCoordinatesSystem();
03381 }
03382 }
03383
03387 void QGLViewer::setVisualHintsMask(int mask, int delay)
03388 {
03389 visualHint_ = visualHint_ | mask;
03390 QTimer::singleShot(delay, this, SLOT(resetVisualHints()));
03391 }
03392
03394 void QGLViewer::resetVisualHints()
03395 {
03396 visualHint_ = 0;
03397 }
03398 #endif
03399
03401
03403
03413 void QGLViewer::drawArrow(float length, float radius, int nbSubdivisions)
03414 {
03415 static GLUquadric* quadric = gluNewQuadric();
03416
03417 if (radius < 0.0)
03418 radius = 0.05 * length;
03419
03420 const float head = 2.5*(radius / length) + 0.1;
03421 const float coneRadiusCoef = 4.0 - 5.0 * head;
03422
03423 gluCylinder(quadric, radius, radius, length * (1.0 - head/coneRadiusCoef), nbSubdivisions, 1);
03424 glTranslatef(0.0, 0.0, length * (1.0 - head));
03425 gluCylinder(quadric, coneRadiusCoef * radius, 0.0, head * length, nbSubdivisions, 1);
03426 glTranslatef(0.0, 0.0, -length * (1.0 - head));
03427 }
03428
03433 void QGLViewer::drawArrow(const Vec& from, const Vec& to, float radius, int nbSubdivisions)
03434 {
03435 glPushMatrix();
03436 glTranslatef(from[0],from[1],from[2]);
03437 const Vec dir = to-from;
03438 glMultMatrixd(Quaternion(Vec(0,0,1), dir).matrix());
03439 QGLViewer::drawArrow(dir.norm(), radius, nbSubdivisions);
03440 glPopMatrix();
03441 }
03442
03461 void QGLViewer::drawAxis(float length)
03462 {
03463 const float charWidth = length / 40.0;
03464 const float charHeight = length / 30.0;
03465 const float charShift = 1.04 * length;
03466
03467 GLboolean lighting, colorMaterial;
03468 glGetBooleanv(GL_LIGHTING, &lighting);
03469 glGetBooleanv(GL_COLOR_MATERIAL, &colorMaterial);
03470
03471 glDisable(GL_LIGHTING);
03472
03473 glBegin(GL_LINES);
03474
03475 glVertex3f(charShift, charWidth, -charHeight);
03476 glVertex3f(charShift, -charWidth, charHeight);
03477 glVertex3f(charShift, -charWidth, -charHeight);
03478 glVertex3f(charShift, charWidth, charHeight);
03479
03480 glVertex3f( charWidth, charShift, charHeight);
03481 glVertex3f(0.0, charShift, 0.0);
03482 glVertex3f(-charWidth, charShift, charHeight);
03483 glVertex3f(0.0, charShift, 0.0);
03484 glVertex3f(0.0, charShift, 0.0);
03485 glVertex3f(0.0, charShift, -charHeight);
03486
03487 glVertex3f(-charWidth, charHeight, charShift);
03488 glVertex3f( charWidth, charHeight, charShift);
03489 glVertex3f( charWidth, charHeight, charShift);
03490 glVertex3f(-charWidth, -charHeight, charShift);
03491 glVertex3f(-charWidth, -charHeight, charShift);
03492 glVertex3f( charWidth, -charHeight, charShift);
03493 glEnd();
03494
03495 glEnable(GL_LIGHTING);
03496 glDisable(GL_COLOR_MATERIAL);
03497
03498 float color[4];
03499 color[0] = 0.7f; color[1] = 0.7f; color[2] = 1.0f; color[3] = 1.0f;
03500 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
03501 QGLViewer::drawArrow(length, 0.01*length);
03502
03503 color[0] = 1.0f; color[1] = 0.7f; color[2] = 0.7f; color[3] = 1.0f;
03504 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
03505 glPushMatrix();
03506 glRotatef(90.0, 0.0, 1.0, 0.0);
03507 QGLViewer::drawArrow(length, 0.01*length);
03508 glPopMatrix();
03509
03510 color[0] = 0.7f; color[1] = 1.0f; color[2] = 0.7f; color[3] = 1.0f;
03511 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
03512 glPushMatrix();
03513 glRotatef(-90.0, 1.0, 0.0, 0.0);
03514 QGLViewer::drawArrow(length, 0.01*length);
03515 glPopMatrix();
03516
03517 if (colorMaterial)
03518 glEnable(GL_COLOR_MATERIAL);
03519 if (!lighting)
03520 glDisable(GL_LIGHTING);
03521 }
03522
03529 void QGLViewer::drawGrid(float size, int nbSubdivisions)
03530 {
03531 GLboolean lighting;
03532 glGetBooleanv(GL_LIGHTING, &lighting);
03533
03534 glDisable(GL_LIGHTING);
03535
03536 glBegin(GL_LINES);
03537 for (int i=0; i<=nbSubdivisions; ++i)
03538 {
03539 const float pos = size*(2.0*i/nbSubdivisions-1.0);
03540 glVertex2f(pos, -size);
03541 glVertex2f(pos, +size);
03542 glVertex2f(-size, pos);
03543 glVertex2f( size, pos);
03544 }
03545 glEnd();
03546
03547 if (lighting)
03548 glEnable(GL_LIGHTING);
03549 }
03550
03552
03554
03556 void QGLViewer::saveStateToFileForAllViewers()
03557 {
03558 #if QT_VERSION >= 0x040000
03559 Q_FOREACH (QGLViewer* viewer, QGLViewer::QGLViewerPool())
03560 {
03561 #else
03562 QPtrListIterator<QGLViewer> it(QGLViewer::QGLViewerPool());
03563 for (QGLViewer* viewer; (viewer = it.current()) != 0; ++it)
03564 {
03565 #endif
03566 if (viewer)
03567 viewer->saveStateToFile();
03568 }
03569 }
03570
03572
03574
03588 QString QGLViewer::stateFileName() const
03589 {
03590 QString name = stateFileName_;
03591
03592 if (!name.isEmpty() && QGLViewer::QGLViewerIndex(this) > 0)
03593 {
03594 QFileInfo fi(name);
03595 #if QT_VERSION >= 0x040000
03596 if (fi.suffix().isEmpty())
03597 #else
03598 if (fi.extension(false).isEmpty())
03599 #endif
03600 name += QString::number(QGLViewer::QGLViewerIndex(this));
03601 else
03602 #if QT_VERSION >= 0x040000
03603 name = fi.absolutePath() + '/' + fi.completeBaseName() + QString::number(QGLViewer::QGLViewerIndex(this)) + "." + fi.suffix();
03604 #else
03605 # if QT_VERSION >= 0x030000
03606 name = fi.dirPath() + '/' + fi.baseName(true) + QString::number(QGLViewer::QGLViewerIndex(this)) + "." + fi.extension(false);
03607 # else
03608 name = fi.dirPath() + '/' + fi.baseName() + QString::number(QGLViewer::QGLViewerIndex(this)) + "." + fi.extension();
03609 # endif
03610 #endif
03611 }
03612
03613 return name;
03614 }
03615
03623 void QGLViewer::saveStateToFile()
03624 {
03625 QString name = stateFileName();
03626
03627 if (name.isEmpty())
03628 return;
03629
03630 QFileInfo fileInfo(name);
03631
03632 if (fileInfo.isDir())
03633 {
03634 QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("State file name (%1) references a directory instead of a file.").arg(name));
03635 return;
03636 }
03637
03638 #if QT_VERSION >= 0x040000
03639 const QString dirName = fileInfo.absolutePath();
03640 #else
03641 const QString dirName = fileInfo.dirPath();
03642 #endif
03643 if (!QFileInfo(dirName).exists())
03644 {
03645 QDir dir;
03646 #if QT_VERSION >= 0x040000
03647 if (!(dir.mkdir(dirName)))
03648 #else
03649 if (!(dir.mkdir(dirName, true)))
03650 #endif
03651 {
03652 QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to create directory %1").arg(dirName));
03653 return;
03654 }
03655 }
03656
03657
03658 QFile f(name);
03659 #if QT_VERSION >= 0x040000
03660 if (f.open(QIODevice::WriteOnly))
03661 #else
03662 if (f.open(IO_WriteOnly))
03663 #endif
03664 {
03665 QTextStream out(&f);
03666 QDomDocument doc("QGLVIEWER");
03667 doc.appendChild(domElement("QGLViewer", doc));
03668 doc.save(out, 2);
03669 f.flush();
03670 f.close();
03671 }
03672 else
03673 #if QT_VERSION < 0x030200
03674 QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to save to file %1").arg(name));
03675 #else
03676 QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to save to file %1").arg(name) + ":\n" + f.errorString());
03677 #endif
03678 }
03679
03700 bool QGLViewer::restoreStateFromFile()
03701 {
03702 QString name = stateFileName();
03703
03704 if (name.isEmpty())
03705 return false;
03706
03707 QFileInfo fileInfo(name);
03708
03709 if (!fileInfo.isFile())
03710
03711 return false;
03712
03713 if (!fileInfo.isReadable())
03714 {
03715 QMessageBox::warning(this, tr("Problem in state restoration", "Message box window title"), tr("File %1 is not readable.").arg(name));
03716 return false;
03717 }
03718
03719
03720 QFile f(name);
03721 #if QT_VERSION >= 0x040000
03722 if (f.open(QIODevice::ReadOnly) == true)
03723 #else
03724 if (f.open(IO_ReadOnly) == true)
03725 #endif
03726 {
03727 QDomDocument doc;
03728 doc.setContent(&f);
03729 f.close();
03730 QDomElement main = doc.documentElement();
03731 initFromDOMElement(main);
03732 }
03733 else
03734 {
03735 #if QT_VERSION < 0x030200
03736 QMessageBox::warning(this, tr("Open file error", "Message box window title"), tr("Unable to open file %1").arg(name));
03737 #else
03738 QMessageBox::warning(this, tr("Open file error", "Message box window title"), tr("Unable to open file %1").arg(name) + ":\n" + f.errorString());
03739 #endif
03740 return false;
03741 }
03742
03743 return true;
03744 }
03745
03778 QDomElement QGLViewer::domElement(const QString& name, QDomDocument& document) const
03779 {
03780 QDomElement de = document.createElement(name);
03781 de.setAttribute("version", QGLViewerVersionString());
03782
03783 QDomElement stateNode = document.createElement("State");
03784
03785 stateNode.appendChild(DomUtils::QColorDomElement(foregroundColor(), "foregroundColor", document));
03786 stateNode.appendChild(DomUtils::QColorDomElement(backgroundColor(), "backgroundColor", document));
03787 stateNode.setAttribute("stereo", (displaysInStereo()?"true":"false"));
03788 stateNode.setAttribute("cameraMode", (cameraIsInRevolveMode()?"revolve":"fly"));
03789 de.appendChild(stateNode);
03790
03791 QDomElement displayNode = document.createElement("Display");
03792 displayNode.setAttribute("axisIsDrawn", (axisIsDrawn()?"true":"false"));
03793 displayNode.setAttribute("gridIsDrawn", (gridIsDrawn()?"true":"false"));
03794 displayNode.setAttribute("FPSIsDisplayed", (FPSIsDisplayed()?"true":"false"));
03795 displayNode.setAttribute("cameraIsEdited", (cameraIsEdited()?"true":"false"));
03796
03797 de.appendChild(displayNode);
03798
03799 QDomElement geometryNode = document.createElement("Geometry");
03800 geometryNode.setAttribute("fullScreen", (isFullScreen()?"true":"false"));
03801 if (isFullScreen())
03802 {
03803 geometryNode.setAttribute("prevPosX", QString::number(prevPos_.x()));
03804 geometryNode.setAttribute("prevPosY", QString::number(prevPos_.y()));
03805 }
03806 else
03807 {
03808 QWidget* tlw = topLevelWidget();
03809 geometryNode.setAttribute("width", QString::number(tlw->width()));
03810 geometryNode.setAttribute("height", QString::number(tlw->height()));
03811 geometryNode.setAttribute("posX", QString::number(tlw->pos().x()));
03812 geometryNode.setAttribute("posY", QString::number(tlw->pos().y()));
03813 }
03814 de.appendChild(geometryNode);
03815
03816
03817 if (cameraIsEdited())
03818 camera()->setZClippingCoefficient(previousCameraZClippingCoefficient_);
03819 de.appendChild(camera()->domElement("Camera", document));
03820 if (cameraIsEdited())
03821
03822 camera()->setZClippingCoefficient(5.0);
03823
03824 if (manipulatedFrame())
03825 de.appendChild(manipulatedFrame()->domElement("ManipulatedFrame", document));
03826
03827 return de;
03828 }
03829
03864 void QGLViewer::initFromDOMElement(const QDomElement& element)
03865 {
03866 const QString version = element.attribute("version");
03867
03868 if (version[0] != '2')
03869
03870 #if QT_VERSION >= 0x040000
03871 qWarning("State file created using QGLViewer version %s may not be correctly read.", version.toLatin1().constData());
03872 #else
03873 qWarning("State file created using QGLViewer version %s may not be correctly read.", version.latin1());
03874 #endif
03875
03876 QDomElement child=element.firstChild().toElement();
03877 bool tmpCameraIsEdited = cameraIsEdited();
03878 while (!child.isNull())
03879 {
03880 if (child.tagName() == "State")
03881 {
03882
03883
03884 setStereoDisplay(DomUtils::boolFromDom(child, "stereo", false));
03885 if ((child.attribute("cameraMode", "revolve") == "fly") && (cameraIsInRevolveMode()))
03886 toggleCameraMode();
03887
03888 QDomElement ch=child.firstChild().toElement();
03889 while (!ch.isNull())
03890 {
03891 if (ch.tagName() == "foregroundColor")
03892 setForegroundColor(DomUtils::QColorFromDom(ch));
03893 if (ch.tagName() == "backgroundColor")
03894 setBackgroundColor(DomUtils::QColorFromDom(ch));
03895 ch = ch.nextSibling().toElement();
03896 }
03897 }
03898
03899 if (child.tagName() == "Display")
03900 {
03901
03902 setAxisIsDrawn(DomUtils::boolFromDom(child, "axisIsDrawn", false));
03903 setGridIsDrawn(DomUtils::boolFromDom(child, "gridIsDrawn", false));
03904 setFPSIsDisplayed(DomUtils::boolFromDom(child, "FPSIsDisplayed", false));
03905
03906 tmpCameraIsEdited = DomUtils::boolFromDom(child, "cameraIsEdited", false);
03907
03908 }
03909
03910 if (child.tagName() == "Geometry")
03911 {
03912 setFullScreen(DomUtils::boolFromDom(child, "fullScreen", false));
03913
03914 if (isFullScreen())
03915 {
03916 prevPos_.setX(DomUtils::intFromDom(child, "prevPosX", 0));
03917 prevPos_.setY(DomUtils::intFromDom(child, "prevPosY", 0));
03918 }
03919 else
03920 {
03921 int width = DomUtils::intFromDom(child, "width", 600);
03922 int height = DomUtils::intFromDom(child, "height", 400);
03923 topLevelWidget()->resize(width, height);
03924 camera()->setScreenWidthAndHeight(this->width(), this->height());
03925
03926 QPoint pos;
03927 pos.setX(DomUtils::intFromDom(child, "posX", 0));
03928 pos.setY(DomUtils::intFromDom(child, "posY", 0));
03929 topLevelWidget()->move(pos);
03930 }
03931 }
03932
03933 if (child.tagName() == "Camera")
03934 {
03935 connectAllCameraKFIInterpolatedSignals(false);
03936 camera()->initFromDOMElement(child);
03937 connectAllCameraKFIInterpolatedSignals();
03938 }
03939
03940 if ((child.tagName() == "ManipulatedFrame") && (manipulatedFrame()))
03941 manipulatedFrame()->initFromDOMElement(child);
03942
03943 child = child.nextSibling().toElement();
03944 }
03945
03946
03947
03948
03949
03950 cameraIsEdited_ = tmpCameraIsEdited;
03951 if (cameraIsEdited_)
03952 {
03953 previousCameraZClippingCoefficient_ = camera()->zClippingCoefficient();
03954
03955 camera()->setZClippingCoefficient(5.0);
03956 }
03957 }
03958
03959 #ifndef DOXYGEN
03960
03962 void QGLViewer::saveToFile(const QString& fileName)
03963 {
03964 if (!fileName.isEmpty())
03965 setStateFileName(fileName);
03966
03967 qWarning("saveToFile() is deprecated, use saveStateToFile() instead.");
03968 saveStateToFile();
03969 }
03970
03973 bool QGLViewer::restoreFromFile(const QString& fileName)
03974 {
03975 if (!fileName.isEmpty())
03976 setStateFileName(fileName);
03977
03978 qWarning("restoreFromFile() is deprecated, use restoreStateFromFile() instead.");
03979 return restoreStateFromFile();
03980 }
03981 #endif
03982
04036 void QGLViewer::copyBufferToTexture(GLint internalFormat, GLenum format)
04037 {
04038 int h = 16;
04039 int w = 16;
04040
04041 while (w < width())
04042 w <<= 1;
04043 while (h < height())
04044 h <<= 1;
04045
04046 bool init = false;
04047
04048 if ((w != bufferTextureWidth_) || (h != bufferTextureHeight_))
04049 {
04050 bufferTextureWidth_ = w;
04051 bufferTextureHeight_ = h;
04052 bufferTextureMaxU_ = width() / float(bufferTextureWidth_);
04053 bufferTextureMaxV_ = height() / float(bufferTextureHeight_);
04054 init = true;
04055 }
04056
04057 if (bufferTextureId() == 0)
04058 {
04059 glGenTextures(1, &bufferTextureId_);
04060 glBindTexture(GL_TEXTURE_2D, bufferTextureId_);
04061 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
04062 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
04063 init = true;
04064 }
04065 else
04066 glBindTexture(GL_TEXTURE_2D, bufferTextureId_);
04067
04068 if ((format != previousBufferTextureFormat_) ||
04069 (internalFormat != previousBufferTextureInternalFormat_))
04070 {
04071 previousBufferTextureFormat_ = format;
04072 previousBufferTextureInternalFormat_ = internalFormat;
04073 init = true;
04074 }
04075
04076 if (init)
04077 {
04078 if (format == GL_NONE)
04079 format = internalFormat;
04080
04081 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, bufferTextureWidth_, bufferTextureHeight_, 0, format, GL_UNSIGNED_BYTE, NULL);
04082 }
04083
04084 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width(), height());
04085 }
04086
04093 GLuint QGLViewer::bufferTextureId() const
04094 {
04095 if (glIsTexture(bufferTextureId_))
04096 return bufferTextureId_;
04097 else
04098 return 0;
04099 }