qglviewer.cpp
1 /****************************************************************************
2 
3  Copyright (C) 2002-2013 Gilles Debunne. All rights reserved.
4 
5  This file is part of the QGLViewer library version 2.5.2.
6 
7  http://www.libqglviewer.com - contact@libqglviewer.com
8 
9  This file may be used under the terms of the GNU General Public License
10  versions 2.0 or 3.0 as published by the Free Software Foundation and
11  appearing in the LICENSE file included in the packaging of this file.
12  In addition, as a special exception, Gilles Debunne gives you certain
13  additional rights, described in the file GPL_EXCEPTION in this package.
14 
15  libQGLViewer uses dual licensing. Commercial/proprietary software must
16  purchase a libQGLViewer Commercial License.
17 
18  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
19  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 
21 *****************************************************************************/
22 
23 #include "domUtils.h"
24 #include "qglviewer.h"
25 #include "camera.h"
26 #include "keyFrameInterpolator.h"
27 #include "manipulatedCameraFrame.h"
28 
29 # include <QtAlgorithms>
30 # include <QTextEdit>
31 # include <QApplication>
32 # include <QFileInfo>
33 # include <QDateTime>
34 # include <QMessageBox>
35 # include <QPushButton>
36 # include <QTabWidget>
37 # include <QTextStream>
38 # include <QMouseEvent>
39 # include <QTimer>
40 # include <QImage>
41 # include <QDir>
42 # include <QUrl>
43 
44 using namespace std;
45 using namespace qglviewer;
46 
47 // Static private variable
48 QList<QGLViewer*> QGLViewer::QGLViewerPool_;
49 
50 
68 void QGLViewer::defaultConstructor()
69 {
70  // Test OpenGL context
71  // if (glGetString(GL_VERSION) == 0)
72  // qWarning("Unable to get OpenGL version, context may not be available - Check your configuration");
73 
74  int poolIndex = QGLViewer::QGLViewerPool_.indexOf(NULL);
75  setFocusPolicy(Qt::StrongFocus);
76 
77  if (poolIndex >= 0)
78  QGLViewer::QGLViewerPool_.replace(poolIndex, this);
79  else
80  QGLViewer::QGLViewerPool_.append(this);
81 
82  camera_ = new Camera();
83  setCamera(camera());
84 
85  setDefaultShortcuts();
86  setDefaultMouseBindings();
87 
88  setSnapshotFileName(tr("snapshot", "Default snapshot file name"));
89  initializeSnapshotFormats();
90  setSnapshotCounter(0);
91  setSnapshotQuality(95);
92 
93  fpsTime_.start();
94  fpsCounter_ = 0;
95  f_p_s_ = 0.0;
96  fpsString_ = tr("%1Hz", "Frames per seconds, in Hertz").arg("?");
97  visualHint_ = 0;
98  previousPathId_ = 0;
99  // prevPos_ is not initialized since pos() is not meaningful here.
100  // It will be set when setFullScreen(false) is called after setFullScreen(true)
101 
102  // #CONNECTION# default values in initFromDOMElement()
103  manipulatedFrame_ = NULL;
104  manipulatedFrameIsACamera_ = false;
105  mouseGrabberIsAManipulatedFrame_ = false;
106  mouseGrabberIsAManipulatedCameraFrame_ = false;
107  displayMessage_ = false;
108  connect(&messageTimer_, SIGNAL(timeout()), SLOT(hideMessage()));
109  messageTimer_.setSingleShot(true);
110  helpWidget_ = NULL;
111  setMouseGrabber(NULL);
112 
113  setSceneRadius(1.0);
114  showEntireScene();
115  setStateFileName(".qglviewer.xml");
116 
117  // #CONNECTION# default values in initFromDOMElement()
118  setAxisIsDrawn(false);
119  setGridIsDrawn(false);
120  setFPSIsDisplayed(false);
121  setCameraIsEdited(false);
122  setTextIsEnabled(true);
123  setStereoDisplay(false);
124  // Make sure move() is not called, which would call initializeGL()
125  fullScreen_ = false;
126  setFullScreen(false);
127 
128  animationTimerId_ = 0;
129  stopAnimation();
130  setAnimationPeriod(40); // 25Hz
131 
132  selectBuffer_ = NULL;
133  setSelectBufferSize(4*1000);
134  setSelectRegionWidth(3);
135  setSelectRegionHeight(3);
136  setSelectedName(-1);
137 
138  bufferTextureId_ = 0;
139  bufferTextureMaxU_ = 0.0;
140  bufferTextureMaxV_ = 0.0;
141  bufferTextureWidth_ = 0;
142  bufferTextureHeight_ = 0;
143  previousBufferTextureFormat_ = 0;
144  previousBufferTextureInternalFormat_ = 0;
145  currentlyPressedKey_ = Qt::Key(0);
146 
147  setAttribute(Qt::WA_NoSystemBackground);
148 
149  tileRegion_ = NULL;
150 }
151 
152 #if !defined QT3_SUPPORT
153 
160 QGLViewer::QGLViewer(QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags flags)
161  : QGLWidget(parent, shareWidget, flags)
162 { defaultConstructor(); }
163 
166 QGLViewer::QGLViewer(QGLContext *context, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags flags)
167  : QGLWidget(context, parent, shareWidget, flags)
168 { defaultConstructor(); }
169 
174 QGLViewer::QGLViewer(const QGLFormat& format, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags flags)
175  : QGLWidget(format, parent, shareWidget, flags)
176 { defaultConstructor(); }
177 #endif // QT3_SUPPORT
178 
184 {
185  // See closeEvent comment. Destructor is called (and not closeEvent) only when the widget is embedded.
186  // Hence we saveToFile here. It is however a bad idea if virtual domElement() has been overloaded !
187  // if (parent())
188  // saveStateToFileForAllViewers();
189 
190  QGLViewer::QGLViewerPool_.replace(QGLViewer::QGLViewerPool_.indexOf(this), NULL);
191 
192  delete camera();
193  delete[] selectBuffer_;
194  if (helpWidget())
195  {
196  // Needed for Qt 4 which has no main widget.
197  helpWidget()->close();
198  delete helpWidget_;
199  }
200 }
201 
202 
203 static QString QGLViewerVersionString()
204 {
205  return QString::number((QGLVIEWER_VERSION & 0xff0000) >> 16) + "." +
206  QString::number((QGLVIEWER_VERSION & 0x00ff00) >> 8) + "." +
207  QString::number(QGLVIEWER_VERSION & 0x0000ff);
208 }
209 
210 static Qt::KeyboardModifiers keyboardModifiersFromState(int state) {
211  // Convertion of keyboard modifiers and mouse buttons as an int is no longer supported : emulate
212  return Qt::KeyboardModifiers(state & 0xFF000000);
213 }
214 
215 
216 static Qt::MouseButton mouseButtonFromState(int state) {
217  // Convertion of keyboard modifiers and mouse buttons as an int is no longer supported : emulate
218  return Qt::MouseButton(state & 0xFFFF);
219 }
220 
240 {
241  glEnable(GL_LIGHT0);
242  glEnable(GL_LIGHTING);
243  glEnable(GL_DEPTH_TEST);
244  glEnable(GL_COLOR_MATERIAL);
245 
246  // Default colors
247  setForegroundColor(QColor(180, 180, 180));
248  setBackgroundColor(QColor(51, 51, 51));
249 
250  // Clear the buffer where we're going to draw
251  if (format().stereo())
252  {
253  glDrawBuffer(GL_BACK_RIGHT);
254  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
255  glDrawBuffer(GL_BACK_LEFT);
256  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
257  }
258  else
259  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
260 
261  // Calls user defined method. Default emits a signal.
262  init();
263 
264  // Give time to glInit to finish and then call setFullScreen().
265  if (isFullScreen())
266  QTimer::singleShot( 100, this, SLOT(delayedFullScreen()) );
267 }
268 
276 {
277  if (displaysInStereo())
278  {
279  for (int view=1; view>=0; --view)
280  {
281  // Clears screen, set model view matrix with shifted matrix for ith buffer
282  preDrawStereo(view);
283  // Used defined method. Default is empty
284  if (camera()->frame()->isManipulated())
285  fastDraw();
286  else
287  draw();
288  postDraw();
289  }
290  }
291  else
292  {
293  // Clears screen, set model view matrix...
294  preDraw();
295  // Used defined method. Default calls draw()
296  if (camera()->frame()->isManipulated())
297  fastDraw();
298  else
299  draw();
300  // Add visual hints: axis, camera, grid...
301  postDraw();
302  }
303  Q_EMIT drawFinished(true);
304 }
305 
318 {
319  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
320 
321  // GL_PROJECTION matrix
323  // GL_MODELVIEW matrix
325 
326  Q_EMIT drawNeeded();
327 }
328 
340 {
341  // Reset model view matrix to world coordinates origin
342  glMatrixMode(GL_MODELVIEW);
343  glPushMatrix();
345  // TODO restore model loadProjectionMatrixStereo
346 
347  // Save OpenGL state
348  glPushAttrib(GL_ALL_ATTRIB_BITS);
349 
350  // Set neutral GL state
351  glDisable(GL_TEXTURE_1D);
352  glDisable(GL_TEXTURE_2D);
353 #ifdef GL_TEXTURE_3D // OpenGL 1.2 Only...
354  glDisable(GL_TEXTURE_3D);
355 #endif
356 
357  glDisable(GL_TEXTURE_GEN_Q);
358  glDisable(GL_TEXTURE_GEN_R);
359  glDisable(GL_TEXTURE_GEN_S);
360  glDisable(GL_TEXTURE_GEN_T);
361 
362 #ifdef GL_RESCALE_NORMAL // OpenGL 1.2 Only...
363  glEnable(GL_RESCALE_NORMAL);
364 #endif
365 
366  glDisable(GL_COLOR_MATERIAL);
367  qglColor(foregroundColor());
368 
369  if (cameraIsEdited())
370  camera()->drawAllPaths();
371 
372  // Pivot point, line when camera rolls, zoom region
373  drawVisualHints();
374 
375  if (gridIsDrawn()) { glLineWidth(1.0); drawGrid(camera()->sceneRadius()); }
376  if (axisIsDrawn()) { glLineWidth(2.0); drawAxis(camera()->sceneRadius()); }
377 
378  // FPS computation
379  const unsigned int maxCounter = 20;
380  if (++fpsCounter_ == maxCounter)
381  {
382  f_p_s_ = 1000.0 * maxCounter / fpsTime_.restart();
383  fpsString_ = tr("%1Hz", "Frames per seconds, in Hertz").arg(f_p_s_, 0, 'f', ((f_p_s_ < 10.0)?1:0));
384  fpsCounter_ = 0;
385  }
386 
387  // Restore foregroundColor
388  float color[4];
389  color[0] = foregroundColor().red() / 255.0;
390  color[1] = foregroundColor().green() / 255.0;
391  color[2] = foregroundColor().blue() / 255.0;
392  color[3] = 1.0;
393  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
394  glDisable(GL_LIGHTING);
395  glDisable(GL_DEPTH_TEST);
396 
397  if (FPSIsDisplayed()) displayFPS();
398  if (displayMessage_) drawText(10, height()-10, message_);
399 
400  // Restore GL state
401  glPopAttrib();
402  glPopMatrix();
403 }
404 
410 void QGLViewer::preDrawStereo(bool leftBuffer)
411 {
412  // Set buffer to draw in
413  // Seems that SGI and Crystal Eyes are not synchronized correctly !
414  // That's why we don't draw in the appropriate buffer...
415  if (!leftBuffer)
416  glDrawBuffer(GL_BACK_LEFT);
417  else
418  glDrawBuffer(GL_BACK_RIGHT);
419 
420  // Clear the buffer where we're going to draw
421  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
422  // GL_PROJECTION matrix
423  camera()->loadProjectionMatrixStereo(leftBuffer);
424  // GL_MODELVIEW matrix
425  camera()->loadModelViewMatrixStereo(leftBuffer);
426 
427  Q_EMIT drawNeeded();
428 }
429 
438 {
439  draw();
440 }
441 
450 {
451  cameraIsEdited_ = edit;
452  if (edit)
453  {
454  previousCameraZClippingCoefficient_ = camera()->zClippingCoefficient();
455  // #CONNECTION# 5.0 also used in domElement() and in initFromDOMElement().
457  }
458  else
459  camera()->setZClippingCoefficient(previousCameraZClippingCoefficient_);
460 
461  Q_EMIT cameraIsEditedChanged(edit);
462 
463  update();
464 }
465 
466 // Key bindings. 0 means not defined
467 void QGLViewer::setDefaultShortcuts()
468 {
469  // D e f a u l t a c c e l e r a t o r s
470  setShortcut(DRAW_AXIS, Qt::Key_A);
471  setShortcut(DRAW_GRID, Qt::Key_G);
472  setShortcut(DISPLAY_FPS, Qt::Key_F);
473  setShortcut(ENABLE_TEXT, Qt::SHIFT+Qt::Key_Question);
474  setShortcut(EXIT_VIEWER, Qt::Key_Escape);
475  setShortcut(SAVE_SCREENSHOT, Qt::CTRL+Qt::Key_S);
476  setShortcut(CAMERA_MODE, Qt::Key_Space);
477  setShortcut(FULL_SCREEN, Qt::ALT+Qt::Key_Return);
478  setShortcut(STEREO, Qt::Key_S);
479  setShortcut(ANIMATION, Qt::Key_Return);
480  setShortcut(HELP, Qt::Key_H);
481  setShortcut(EDIT_CAMERA, Qt::Key_C);
482  setShortcut(MOVE_CAMERA_LEFT, Qt::Key_Left);
483  setShortcut(MOVE_CAMERA_RIGHT,Qt::Key_Right);
484  setShortcut(MOVE_CAMERA_UP, Qt::Key_Up);
485  setShortcut(MOVE_CAMERA_DOWN, Qt::Key_Down);
486  setShortcut(INCREASE_FLYSPEED, Qt::Key_Plus);
487  setShortcut(DECREASE_FLYSPEED, Qt::Key_Minus);
488  setShortcut(SNAPSHOT_TO_CLIPBOARD, Qt::CTRL+Qt::Key_C);
489 
490  keyboardActionDescription_[DISPLAY_FPS] = tr("Toggles the display of the FPS", "DISPLAY_FPS action description");
491  keyboardActionDescription_[SAVE_SCREENSHOT] = tr("Saves a screenshot", "SAVE_SCREENSHOT action description");
492  keyboardActionDescription_[FULL_SCREEN] = tr("Toggles full screen display", "FULL_SCREEN action description");
493  keyboardActionDescription_[DRAW_AXIS] = tr("Toggles the display of the world axis", "DRAW_AXIS action description");
494  keyboardActionDescription_[DRAW_GRID] = tr("Toggles the display of the XY grid", "DRAW_GRID action description");
495  keyboardActionDescription_[CAMERA_MODE] = tr("Changes camera mode (observe or fly)", "CAMERA_MODE action description");
496  keyboardActionDescription_[STEREO] = tr("Toggles stereo display", "STEREO action description");
497  keyboardActionDescription_[HELP] = tr("Opens this help window", "HELP action description");
498  keyboardActionDescription_[ANIMATION] = tr("Starts/stops the animation", "ANIMATION action description");
499  keyboardActionDescription_[EDIT_CAMERA] = tr("Toggles camera paths display", "EDIT_CAMERA action description"); // TODO change
500  keyboardActionDescription_[ENABLE_TEXT] = tr("Toggles the display of the text", "ENABLE_TEXT action description");
501  keyboardActionDescription_[EXIT_VIEWER] = tr("Exits program", "EXIT_VIEWER action description");
502  keyboardActionDescription_[MOVE_CAMERA_LEFT] = tr("Moves camera left", "MOVE_CAMERA_LEFT action description");
503  keyboardActionDescription_[MOVE_CAMERA_RIGHT] = tr("Moves camera right", "MOVE_CAMERA_RIGHT action description");
504  keyboardActionDescription_[MOVE_CAMERA_UP] = tr("Moves camera up", "MOVE_CAMERA_UP action description");
505  keyboardActionDescription_[MOVE_CAMERA_DOWN] = tr("Moves camera down", "MOVE_CAMERA_DOWN action description");
506  keyboardActionDescription_[INCREASE_FLYSPEED] = tr("Increases fly speed", "INCREASE_FLYSPEED action description");
507  keyboardActionDescription_[DECREASE_FLYSPEED] = tr("Decreases fly speed", "DECREASE_FLYSPEED action description");
508  keyboardActionDescription_[SNAPSHOT_TO_CLIPBOARD] = tr("Copies a snapshot to clipboard", "SNAPSHOT_TO_CLIPBOARD action description");
509 
510  // K e y f r a m e s s h o r t c u t k e y s
511  setPathKey(Qt::Key_F1, 1);
512  setPathKey(Qt::Key_F2, 2);
513  setPathKey(Qt::Key_F3, 3);
514  setPathKey(Qt::Key_F4, 4);
515  setPathKey(Qt::Key_F5, 5);
516  setPathKey(Qt::Key_F6, 6);
517  setPathKey(Qt::Key_F7, 7);
518  setPathKey(Qt::Key_F8, 8);
519  setPathKey(Qt::Key_F9, 9);
520  setPathKey(Qt::Key_F10, 10);
521  setPathKey(Qt::Key_F11, 11);
522  setPathKey(Qt::Key_F12, 12);
523 
524  setAddKeyFrameKeyboardModifiers(Qt::AltModifier);
525  setPlayPathKeyboardModifiers(Qt::NoModifier);
526 }
527 
528 // M o u s e b e h a v i o r
529 void QGLViewer::setDefaultMouseBindings()
530 {
531  const Qt::KeyboardModifiers cameraKeyboardModifiers = Qt::NoModifier;
532  const Qt::KeyboardModifiers frameKeyboardModifiers = Qt::ControlModifier;
533 
534  //#CONNECTION# toggleCameraMode()
535  for (int handler=0; handler<2; ++handler)
536  {
537  MouseHandler mh = (MouseHandler)(handler);
538  Qt::KeyboardModifiers modifiers = (mh == FRAME) ? frameKeyboardModifiers : cameraKeyboardModifiers;
539 
540  setMouseBinding(modifiers, Qt::LeftButton, mh, ROTATE);
541  setMouseBinding(modifiers, Qt::MidButton, mh, ZOOM);
542  setMouseBinding(modifiers, Qt::RightButton, mh, TRANSLATE);
543 
544  setMouseBinding(Qt::Key_R, modifiers, Qt::LeftButton, mh, SCREEN_ROTATE);
545 
546  setWheelBinding(modifiers, mh, ZOOM);
547  }
548 
549  // Z o o m o n r e g i o n
550  setMouseBinding(Qt::ShiftModifier, Qt::MidButton, CAMERA, ZOOM_ON_REGION);
551 
552  // S e l e c t
553  setMouseBinding(Qt::ShiftModifier, Qt::LeftButton, SELECT);
554 
555  setMouseBinding(Qt::ShiftModifier, Qt::RightButton, RAP_FROM_PIXEL);
556  // D o u b l e c l i c k
557  setMouseBinding(Qt::NoModifier, Qt::LeftButton, ALIGN_CAMERA, true);
558  setMouseBinding(Qt::NoModifier, Qt::MidButton, SHOW_ENTIRE_SCENE, true);
559  setMouseBinding(Qt::NoModifier, Qt::RightButton, CENTER_SCENE, true);
560 
561  setMouseBinding(frameKeyboardModifiers, Qt::LeftButton, ALIGN_FRAME, true);
562  // middle double click makes no sense for manipulated frame
563  setMouseBinding(frameKeyboardModifiers, Qt::RightButton, CENTER_FRAME, true);
564 
565  // A c t i o n s w i t h k e y m o d i f i e r s
566  setMouseBinding(Qt::Key_Z, Qt::NoModifier, Qt::LeftButton, ZOOM_ON_PIXEL);
567  setMouseBinding(Qt::Key_Z, Qt::NoModifier, Qt::RightButton, ZOOM_TO_FIT);
568 
569 #ifdef Q_OS_MAC
570  // Specific Mac bindings for touchpads. Double finger emulates a wheelEvent which zooms.
571  // There is no right button available : make Option key + left emulate the right button.
572  // A Control+Left indeed emulates a right click (OS X system configuration), but it does
573  // no seem to support dragging.
574  // Done at the end to override previous settings.
575  const Qt::KeyboardModifiers macKeyboardModifiers = Qt::AltModifier;
576 
577  setMouseBinding(macKeyboardModifiers, Qt::LeftButton, CAMERA, TRANSLATE);
578  setMouseBinding(macKeyboardModifiers, Qt::LeftButton, CENTER_SCENE, true);
579  setMouseBinding(frameKeyboardModifiers | macKeyboardModifiers, Qt::LeftButton, CENTER_FRAME, true);
580  setMouseBinding(frameKeyboardModifiers | macKeyboardModifiers, Qt::LeftButton, FRAME, TRANSLATE);
581 #endif
582 }
583 
600 void QGLViewer::setCamera(Camera* const camera)
601 {
602  if (!camera)
603  return;
604 
605  camera->setSceneRadius(sceneRadius());
606  camera->setSceneCenter(sceneCenter());
607  camera->setScreenWidthAndHeight(width(), height());
608 
609  // Disconnect current camera from this viewer.
610  disconnect(this->camera()->frame(), SIGNAL(manipulated()), this, SLOT(update()));
611  disconnect(this->camera()->frame(), SIGNAL(spun()), this, SLOT(update()));
612 
613  // Connect camera frame to this viewer.
614  connect(camera->frame(), SIGNAL(manipulated()), SLOT(update()));
615  connect(camera->frame(), SIGNAL(spun()), SLOT(update()));
616 
617  connectAllCameraKFIInterpolatedSignals(false);
618  camera_ = camera;
619  connectAllCameraKFIInterpolatedSignals();
620 
621  previousCameraZClippingCoefficient_ = this->camera()->zClippingCoefficient();
622 }
623 
624 void QGLViewer::connectAllCameraKFIInterpolatedSignals(bool connection)
625 {
626  for (QMap<int, KeyFrameInterpolator*>::ConstIterator it = camera()->kfi_.begin(), end=camera()->kfi_.end(); it != end; ++it)
627  {
628  if (connection)
629  connect(camera()->keyFrameInterpolator(it.key()), SIGNAL(interpolated()), SLOT(update()));
630  else
631  disconnect(camera()->keyFrameInterpolator(it.key()), SIGNAL(interpolated()), this, SLOT(update()));
632  }
633 
634  if (connection)
635  connect(camera()->interpolationKfi_, SIGNAL(interpolated()), SLOT(update()));
636  else
637  disconnect(camera()->interpolationKfi_, SIGNAL(interpolated()), this, SLOT(update()));
638 }
639 
656 void QGLViewer::drawLight(GLenum light, float scale) const
657 {
658  static GLUquadric* quadric = gluNewQuadric();
659 
660  const float length = sceneRadius() / 5.0 * scale;
661 
662  GLboolean lightIsOn;
663  glGetBooleanv(light, &lightIsOn);
664 
665  if (lightIsOn)
666  {
667  // All light values are given in eye coordinates
668  glPushMatrix();
669  glLoadIdentity();
670 
671  float color[4];
672  glGetLightfv(light, GL_DIFFUSE, color);
673  glColor4fv(color);
674 
675  float pos[4];
676  glGetLightfv(light, GL_POSITION, pos);
677 
678  if (pos[3] != 0.0)
679  {
680  glTranslatef(pos[0]/pos[3], pos[1]/pos[3], pos[2]/pos[3]);
681 
682  GLfloat cutOff;
683  glGetLightfv(light, GL_SPOT_CUTOFF, &cutOff);
684  if (cutOff != 180.0)
685  {
686  GLfloat dir[4];
687  glGetLightfv(light, GL_SPOT_DIRECTION, dir);
688  glMultMatrixd(Quaternion(Vec(0,0,1), Vec(dir)).matrix());
689  QGLViewer::drawArrow(length);
690  gluCylinder(quadric, 0.0, 0.7 * length * sin(cutOff * M_PI / 180.0), 0.7 * length * cos(cutOff * M_PI / 180.0), 12, 1);
691  }
692  else
693  gluSphere(quadric, 0.2*length, 10, 10);
694  }
695  else
696  {
697  // Directional light.
698  Vec dir(pos[0], pos[1], pos[2]);
699  dir.normalize();
700  Frame fr=Frame(camera()->cameraCoordinatesOf(4.0 * length * camera()->frame()->inverseTransformOf(dir)),
701  Quaternion(Vec(0,0,-1), dir));
702  glMultMatrixd(fr.matrix());
703  drawArrow(length);
704  }
705 
706  glPopMatrix();
707  }
708 }
709 
710 
741 void QGLViewer::drawText(int x, int y, const QString& text, const QFont& fnt)
742 {
743  if (!textIsEnabled())
744  return;
745 
746  if (tileRegion_ != NULL) {
747  renderText((x-tileRegion_->xMin) * width() / (tileRegion_->xMax - tileRegion_->xMin),
748  (y-tileRegion_->yMin) * height() / (tileRegion_->yMax - tileRegion_->yMin), text, scaledFont(fnt));
749  } else
750  renderText(x, y, text, fnt);
751 }
752 
764 void QGLViewer::displayMessage(const QString& message, int delay)
765 {
766  message_ = message;
767  displayMessage_ = true;
768  // Was set to single shot in defaultConstructor.
769  messageTimer_.start(delay);
770  if (textIsEnabled())
771  update();
772 }
773 
774 void QGLViewer::hideMessage()
775 {
776  displayMessage_ = false;
777  if (textIsEnabled())
778  update();
779 }
780 
781 
791 void QGLViewer::displayFPS()
792 {
793  drawText(10, int(1.5*((QApplication::font().pixelSize()>0)?QApplication::font().pixelSize():QApplication::font().pointSize())), fpsString_);
794 }
795 
828 {
829  glMatrixMode(GL_PROJECTION);
830  glPushMatrix();
831  glLoadIdentity();
832  if (tileRegion_ != NULL)
833  if (upward)
834  glOrtho(tileRegion_->xMin, tileRegion_->xMax, tileRegion_->yMin, tileRegion_->yMax, 0.0, -1.0);
835  else
836  glOrtho(tileRegion_->xMin, tileRegion_->xMax, tileRegion_->yMax, tileRegion_->yMin, 0.0, -1.0);
837  else
838  if (upward)
839  glOrtho(0, width(), 0, height(), 0.0, -1.0);
840  else
841  glOrtho(0, width(), height(), 0, 0.0, -1.0);
842 
843  glMatrixMode(GL_MODELVIEW);
844  glPushMatrix();
845  glLoadIdentity();
846 }
847 
853 {
854  glMatrixMode(GL_PROJECTION);
855  glPopMatrix();
856 
857  glMatrixMode(GL_MODELVIEW);
858  glPopMatrix();
859 }
860 
864 void QGLViewer::timerEvent(QTimerEvent *)
865 {
866  if (animationIsStarted())
867  {
868  animate();
869  update();
870  }
871 }
872 
875 {
876  animationTimerId_ = startTimer(animationPeriod());
877  animationStarted_ = true;
878 }
879 
882 {
883  animationStarted_ = false;
884  if (animationTimerId_ != 0)
885  killTimer(animationTimerId_);
886 }
887 
891 void QGLViewer::closeEvent(QCloseEvent *e)
892 {
893  // When the user clicks on the window close (x) button:
894  // - If the viewer is a top level window, closeEvent is called and then saves to file.
895  // - Otherwise, nothing happen s:(
896  // When the user press the EXIT_VIEWER keyboard shortcut:
897  // - If the viewer is a top level window, saveStateToFile() is also called
898  // - Otherwise, closeEvent is NOT called and keyPressEvent does the job.
899 
900  /* After tests:
901  E : Embedded widget
902  N : Widget created with new
903  C : closeEvent called
904  D : destructor called
905 
906  E N C D
907  y y
908  y n y
909  n y y
910  n n y y
911 
912  closeEvent is called iif the widget is NOT embedded.
913 
914  Destructor is called iif the widget is created on the stack
915  or if widget (resp. parent if embedded) is created with WDestructiveClose flag.
916 
917  closeEvent always before destructor.
918 
919  Close using qApp->closeAllWindows or (x) is identical.
920  */
921 
922  // #CONNECTION# Also done for EXIT_VIEWER in keyPressEvent().
923  saveStateToFile();
924  QGLWidget::closeEvent(e);
925 }
926 
936 void QGLViewer::select(const QMouseEvent* event)
937 {
938  // For those who don't derive but rather rely on the signal-slot mechanism.
939  Q_EMIT pointSelected(event);
940  select(event->pos());
941 }
942 
993 void QGLViewer::select(const QPoint& point)
994 {
995  beginSelection(point);
996  drawWithNames();
997  endSelection(point);
998  postSelection(point);
999 }
1000 
1012 void QGLViewer::beginSelection(const QPoint& point)
1013 {
1014  // Make OpenGL context current (may be needed with several viewers ?)
1015  makeCurrent();
1016 
1017  // Prepare the selection mode
1018  glSelectBuffer(selectBufferSize(), selectBuffer());
1019  glRenderMode(GL_SELECT);
1020  glInitNames();
1021 
1022  // Loads the matrices
1023  glMatrixMode(GL_PROJECTION);
1024  glLoadIdentity();
1025  static GLint viewport[4];
1026  camera()->getViewport(viewport);
1027  gluPickMatrix(point.x(), point.y(), selectRegionWidth(), selectRegionHeight(), viewport);
1028 
1029  // loadProjectionMatrix() first resets the GL_PROJECTION matrix with a glLoadIdentity().
1030  // The false parameter prevents this and hence multiplies the matrices.
1031  camera()->loadProjectionMatrix(false);
1032  // Reset the original (world coordinates) modelview matrix
1034 }
1035 
1072 void QGLViewer::endSelection(const QPoint& point)
1073 {
1074  Q_UNUSED(point);
1075 
1076  // Flush GL buffers
1077  glFlush();
1078 
1079  // Get the number of objects that were seen through the pick matrix frustum. Reset GL_RENDER mode.
1080  GLint nbHits = glRenderMode(GL_RENDER);
1081 
1082  if (nbHits <= 0)
1083  setSelectedName(-1);
1084  else
1085  {
1086  // Interpret results: each object created 4 values in the selectBuffer().
1087  // selectBuffer[4*i+1] is the object minimum depth value, while selectBuffer[4*i+3] is the id pushed on the stack.
1088  // Of all the objects that were projected in the pick region, we select the closest one (zMin comparison).
1089  // This code needs to be modified if you use several stack levels. See glSelectBuffer() man page.
1090  GLuint zMin = (selectBuffer())[1];
1091  setSelectedName((selectBuffer())[3]);
1092  for (int i=1; i<nbHits; ++i)
1093  if ((selectBuffer())[4*i+1] < zMin)
1094  {
1095  zMin = (selectBuffer())[4*i+1];
1096  setSelectedName((selectBuffer())[4*i+3]);
1097  }
1098  }
1099 }
1100 
1105 {
1106  if (selectBuffer_)
1107  delete[] selectBuffer_;
1108  selectBufferSize_ = size;
1109  selectBuffer_ = new GLuint[selectBufferSize()];
1110 }
1111 
1112 static QString mouseButtonsString(Qt::MouseButtons b)
1113 {
1114  QString result("");
1115  bool addAmpersand = false;
1116  if (b & Qt::LeftButton) { result += QGLViewer::tr("Left", "left mouse button"); addAmpersand=true; }
1117  if (b & Qt::MidButton) { if (addAmpersand) result += " & "; result += QGLViewer::tr("Middle", "middle mouse button"); addAmpersand=true; }
1118  if (b & Qt::RightButton) { if (addAmpersand) result += " & "; result += QGLViewer::tr("Right", "right mouse button"); }
1119  return result;
1120 }
1121 
1122 void QGLViewer::performClickAction(ClickAction ca, const QMouseEvent* const e)
1123 {
1124  // Note: action that need it should call update().
1125  switch (ca)
1126  {
1127  // # CONNECTION setMouseBinding prevents adding NO_CLICK_ACTION in clickBinding_
1128  // This case should hence not be possible. Prevents unused case warning.
1129  case NO_CLICK_ACTION :
1130  break;
1131  case ZOOM_ON_PIXEL :
1132  camera()->interpolateToZoomOnPixel(e->pos());
1133  break;
1134  case ZOOM_TO_FIT :
1136  break;
1137  case SELECT :
1138  select(e);
1139  update();
1140  break;
1141  case RAP_FROM_PIXEL :
1142  if (! camera()->setPivotPointFromPixel(e->pos()))
1144  setVisualHintsMask(1);
1145  update();
1146  break;
1147  case RAP_IS_CENTER :
1149  setVisualHintsMask(1);
1150  update();
1151  break;
1152  case CENTER_FRAME :
1153  if (manipulatedFrame())
1154  manipulatedFrame()->projectOnLine(camera()->position(), camera()->viewDirection());
1155  break;
1156  case CENTER_SCENE :
1157  camera()->centerScene();
1158  break;
1159  case SHOW_ENTIRE_SCENE :
1160  camera()->showEntireScene();
1161  break;
1162  case ALIGN_FRAME :
1163  if (manipulatedFrame())
1164  manipulatedFrame()->alignWithFrame(camera()->frame());
1165  break;
1166  case ALIGN_CAMERA :
1167  Frame * frame = new Frame();
1168  frame->setTranslation(camera()->pivotPoint());
1169  camera()->frame()->alignWithFrame(frame, true);
1170  delete frame;
1171  break;
1172  }
1173 }
1174 
1191 void QGLViewer::mousePressEvent(QMouseEvent* e)
1192 {
1193  //#CONNECTION# mouseDoubleClickEvent has the same structure
1194  //#CONNECTION# mouseString() concatenates bindings description in inverse order.
1195  ClickBindingPrivate cbp(e->modifiers(), e->button(), false, (Qt::MouseButtons)(e->buttons() & ~(e->button())), currentlyPressedKey_);
1196 
1197  if (clickBinding_.contains(cbp)) {
1198  performClickAction(clickBinding_[cbp], e);
1199  } else
1200  if (mouseGrabber())
1201  {
1202  if (mouseGrabberIsAManipulatedFrame_)
1203  {
1204  for (QMap<MouseBindingPrivate, MouseActionPrivate>::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it!=end; ++it)
1205  if ((it.value().handler == FRAME) && (it.key().button == e->button()))
1206  {
1207  ManipulatedFrame* mf = dynamic_cast<ManipulatedFrame*>(mouseGrabber());
1208  if (mouseGrabberIsAManipulatedCameraFrame_)
1209  {
1210  mf->ManipulatedFrame::startAction(it.value().action, it.value().withConstraint);
1211  mf->ManipulatedFrame::mousePressEvent(e, camera());
1212  }
1213  else
1214  {
1215  mf->startAction(it.value().action, it.value().withConstraint);
1216  mf->mousePressEvent(e, camera());
1217  }
1218  break;
1219  }
1220  }
1221  else
1223  update();
1224  }
1225  else
1226  {
1227  //#CONNECTION# wheelEvent has the same structure
1228  const MouseBindingPrivate mbp(e->modifiers(), e->button(), currentlyPressedKey_);
1229 
1230  if (mouseBinding_.contains(mbp))
1231  {
1232  MouseActionPrivate map = mouseBinding_[mbp];
1233  switch (map.handler)
1234  {
1235  case CAMERA :
1236  camera()->frame()->startAction(map.action, map.withConstraint);
1237  camera()->frame()->mousePressEvent(e, camera());
1238  break;
1239  case FRAME :
1240  if (manipulatedFrame())
1241  {
1242  if (manipulatedFrameIsACamera_)
1243  {
1244  manipulatedFrame()->ManipulatedFrame::startAction(map.action, map.withConstraint);
1245  manipulatedFrame()->ManipulatedFrame::mousePressEvent(e, camera());
1246  }
1247  else
1248  {
1249  manipulatedFrame()->startAction(map.action, map.withConstraint);
1251  }
1252  }
1253  break;
1254  }
1255  if (map.action == SCREEN_ROTATE)
1256  // Display visual hint line
1257  update();
1258  }
1259  else
1260  e->ignore();
1261  }
1262 }
1263 
1296 void QGLViewer::mouseMoveEvent(QMouseEvent* e)
1297 {
1298  if (mouseGrabber())
1299  {
1300  mouseGrabber()->checkIfGrabsMouse(e->x(), e->y(), camera());
1301  if (mouseGrabber()->grabsMouse())
1302  if (mouseGrabberIsAManipulatedCameraFrame_)
1303  (dynamic_cast<ManipulatedFrame*>(mouseGrabber()))->ManipulatedFrame::mouseMoveEvent(e, camera());
1304  else
1306  else
1307  setMouseGrabber(NULL);
1308  update();
1309  }
1310 
1311  if (!mouseGrabber())
1312  {
1313  //#CONNECTION# mouseReleaseEvent has the same structure
1314  if (camera()->frame()->isManipulated())
1315  {
1316  camera()->frame()->mouseMoveEvent(e, camera());
1317  // #CONNECTION# manipulatedCameraFrame::mouseMoveEvent specific if at the beginning
1318  if (camera()->frame()->action_ == ZOOM_ON_REGION)
1319  update();
1320  }
1321  else // !
1322  if ((manipulatedFrame()) && (manipulatedFrame()->isManipulated()))
1323  if (manipulatedFrameIsACamera_)
1324  manipulatedFrame()->ManipulatedFrame::mouseMoveEvent(e, camera());
1325  else
1327  else
1328  if (hasMouseTracking())
1329  {
1330  Q_FOREACH (MouseGrabber* mg, MouseGrabber::MouseGrabberPool())
1331  {
1332  mg->checkIfGrabsMouse(e->x(), e->y(), camera());
1333  if (mg->grabsMouse())
1334  {
1335  setMouseGrabber(mg);
1336  // Check that MouseGrabber is not disabled
1337  if (mouseGrabber() == mg)
1338  {
1339  update();
1340  break;
1341  }
1342  }
1343  }
1344  }
1345  }
1346 }
1347 
1353 void QGLViewer::mouseReleaseEvent(QMouseEvent* e)
1354 {
1355  if (mouseGrabber())
1356  {
1357  if (mouseGrabberIsAManipulatedCameraFrame_)
1358  (dynamic_cast<ManipulatedFrame*>(mouseGrabber()))->ManipulatedFrame::mouseReleaseEvent(e, camera());
1359  else
1361  mouseGrabber()->checkIfGrabsMouse(e->x(), e->y(), camera());
1362  if (!(mouseGrabber()->grabsMouse()))
1363  setMouseGrabber(NULL);
1364  // update();
1365  }
1366  else
1367  //#CONNECTION# mouseMoveEvent has the same structure
1368  if (camera()->frame()->isManipulated())
1369  {
1370  camera()->frame()->mouseReleaseEvent(e, camera());
1371  }
1372  else
1373  if ((manipulatedFrame()) && (manipulatedFrame()->isManipulated()))
1374  {
1375  if (manipulatedFrameIsACamera_)
1376  manipulatedFrame()->ManipulatedFrame::mouseReleaseEvent(e, camera());
1377  else
1379  }
1380  else
1381  e->ignore();
1382 
1383  // Not absolutely needed (see above commented code for the optimal version), but may reveal
1384  // useful for specific applications.
1385  update();
1386 }
1387 
1392 void QGLViewer::wheelEvent(QWheelEvent* e)
1393 {
1394  if (mouseGrabber())
1395  {
1396  if (mouseGrabberIsAManipulatedFrame_)
1397  {
1398  for (QMap<WheelBindingPrivate, MouseActionPrivate>::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it!=end; ++it)
1399  if (it.value().handler == FRAME)
1400  {
1401  ManipulatedFrame* mf = dynamic_cast<ManipulatedFrame*>(mouseGrabber());
1402  if (mouseGrabberIsAManipulatedCameraFrame_)
1403  {
1404  mf->ManipulatedFrame::startAction(it.value().action, it.value().withConstraint);
1405  mf->ManipulatedFrame::wheelEvent(e, camera());
1406  }
1407  else
1408  {
1409  mf->startAction(it.value().action, it.value().withConstraint);
1410  mf->wheelEvent(e, camera());
1411  }
1412  break;
1413  }
1414  }
1415  else
1416  mouseGrabber()->wheelEvent(e, camera());
1417  update();
1418  }
1419  else
1420  {
1421  //#CONNECTION# mousePressEvent has the same structure
1422  WheelBindingPrivate wbp(e->modifiers(), currentlyPressedKey_);
1423 
1424  if (wheelBinding_.contains(wbp))
1425  {
1426  MouseActionPrivate map = wheelBinding_[wbp];
1427  switch (map.handler)
1428  {
1429  case CAMERA :
1430  camera()->frame()->startAction(map.action, map.withConstraint);
1431  camera()->frame()->wheelEvent(e, camera());
1432  break;
1433  case FRAME :
1434  if (manipulatedFrame()) {
1435  if (manipulatedFrameIsACamera_)
1436  {
1437  manipulatedFrame()->ManipulatedFrame::startAction(map.action, map.withConstraint);
1438  manipulatedFrame()->ManipulatedFrame::wheelEvent(e, camera());
1439  }
1440  else
1441  {
1442  manipulatedFrame()->startAction(map.action, map.withConstraint);
1444  }
1445  }
1446  break;
1447  }
1448  }
1449  else
1450  e->ignore();
1451  }
1452 }
1453 
1459 {
1460  //#CONNECTION# mousePressEvent has the same structure
1461  ClickBindingPrivate cbp(e->modifiers(), e->button(), true, (Qt::MouseButtons)(e->buttons() & ~(e->button())), currentlyPressedKey_);
1462  if (clickBinding_.contains(cbp))
1463  performClickAction(clickBinding_[cbp], e);
1464  else
1465  if (mouseGrabber())
1467  else
1468  e->ignore();
1469 }
1470 
1476 {
1477  if (format().stereo())
1478  {
1479  stereo_ = stereo;
1480  if (!displaysInStereo())
1481  {
1482  glDrawBuffer(GL_BACK_LEFT);
1483  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1484  glDrawBuffer(GL_BACK_RIGHT);
1485  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1486  }
1487 
1488  Q_EMIT stereoChanged(stereo_);
1489 
1490  update();
1491  }
1492  else
1493  if (stereo)
1494  QMessageBox::warning(this, tr("Stereo not supported", "Message box window title"), tr("Stereo is not supported on this display."));
1495  else
1496  stereo_ = false;
1497 }
1498 
1503 void QGLViewer::setFullScreen(bool fullScreen)
1504 {
1505  if (fullScreen_ == fullScreen) return;
1506 
1507  fullScreen_ = fullScreen;
1508 
1509  QWidget* tlw = topLevelWidget();
1510 
1511  if (isFullScreen())
1512  {
1513  prevPos_ = topLevelWidget()->pos();
1514  tlw->showFullScreen();
1515  tlw->move(0,0);
1516  }
1517  else
1518  {
1519  tlw->showNormal();
1520  tlw->move(prevPos_);
1521  }
1522 }
1523 
1531 {
1532  if (!mouseGrabberIsEnabled(mouseGrabber))
1533  return;
1534 
1535  mouseGrabber_ = mouseGrabber;
1536 
1537  mouseGrabberIsAManipulatedFrame_ = (dynamic_cast<ManipulatedFrame*>(mouseGrabber) != NULL);
1538  mouseGrabberIsAManipulatedCameraFrame_ = ((dynamic_cast<ManipulatedCameraFrame*>(mouseGrabber) != NULL) &&
1539  (mouseGrabber != camera()->frame()));
1540  Q_EMIT mouseGrabberChanged(mouseGrabber);
1541 }
1542 
1544 void QGLViewer::setMouseGrabberIsEnabled(const qglviewer::MouseGrabber* const mouseGrabber, bool enabled)
1545 {
1546  if (enabled)
1547  disabledMouseGrabbers_.remove(reinterpret_cast<size_t>(mouseGrabber));
1548  else
1549  disabledMouseGrabbers_[reinterpret_cast<size_t>(mouseGrabber)];
1550 }
1551 
1552 QString QGLViewer::mouseActionString(QGLViewer::MouseAction ma)
1553 {
1554  switch (ma)
1555  {
1556  case QGLViewer::NO_MOUSE_ACTION : return QString::null;
1557  case QGLViewer::ROTATE : return QGLViewer::tr("Rotates", "ROTATE mouse action");
1558  case QGLViewer::ZOOM : return QGLViewer::tr("Zooms", "ZOOM mouse action");
1559  case QGLViewer::TRANSLATE : return QGLViewer::tr("Translates", "TRANSLATE mouse action");
1560  case QGLViewer::MOVE_FORWARD : return QGLViewer::tr("Moves forward", "MOVE_FORWARD mouse action");
1561  case QGLViewer::LOOK_AROUND : return QGLViewer::tr("Looks around", "LOOK_AROUND mouse action");
1562  case QGLViewer::MOVE_BACKWARD : return QGLViewer::tr("Moves backward", "MOVE_BACKWARD mouse action");
1563  case QGLViewer::SCREEN_ROTATE : return QGLViewer::tr("Rotates in screen plane", "SCREEN_ROTATE mouse action");
1564  case QGLViewer::ROLL : return QGLViewer::tr("Rolls", "ROLL mouse action");
1565  case QGLViewer::DRIVE : return QGLViewer::tr("Drives", "DRIVE mouse action");
1566  case QGLViewer::SCREEN_TRANSLATE : return QGLViewer::tr("Horizontally/Vertically translates", "SCREEN_TRANSLATE mouse action");
1567  case QGLViewer::ZOOM_ON_REGION : return QGLViewer::tr("Zooms on region for", "ZOOM_ON_REGION mouse action");
1568  }
1569  return QString::null;
1570 }
1571 
1572 QString QGLViewer::clickActionString(QGLViewer::ClickAction ca)
1573 {
1574  switch (ca)
1575  {
1576  case QGLViewer::NO_CLICK_ACTION : return QString::null;
1577  case QGLViewer::ZOOM_ON_PIXEL : return QGLViewer::tr("Zooms on pixel", "ZOOM_ON_PIXEL click action");
1578  case QGLViewer::ZOOM_TO_FIT : return QGLViewer::tr("Zooms to fit scene", "ZOOM_TO_FIT click action");
1579  case QGLViewer::SELECT : return QGLViewer::tr("Selects", "SELECT click action");
1580  case QGLViewer::RAP_FROM_PIXEL : return QGLViewer::tr("Sets pivot point", "RAP_FROM_PIXEL click action");
1581  case QGLViewer::RAP_IS_CENTER : return QGLViewer::tr("Resets pivot point", "RAP_IS_CENTER click action");
1582  case QGLViewer::CENTER_FRAME : return QGLViewer::tr("Centers manipulated frame", "CENTER_FRAME click action");
1583  case QGLViewer::CENTER_SCENE : return QGLViewer::tr("Centers scene", "CENTER_SCENE click action");
1584  case QGLViewer::SHOW_ENTIRE_SCENE : return QGLViewer::tr("Shows entire scene", "SHOW_ENTIRE_SCENE click action");
1585  case QGLViewer::ALIGN_FRAME : return QGLViewer::tr("Aligns manipulated frame", "ALIGN_FRAME click action");
1586  case QGLViewer::ALIGN_CAMERA : return QGLViewer::tr("Aligns camera", "ALIGN_CAMERA click action");
1587  }
1588  return QString::null;
1589 }
1590 
1591 static QString keyString(int key)
1592 {
1593 # if QT_VERSION >= 0x040100
1594  return QKeySequence(key).toString(QKeySequence::NativeText);
1595 # else
1596  return QString(QKeySequence(key));
1597 # endif
1598 }
1599 
1600 QString QGLViewer::formatClickActionPrivate(ClickBindingPrivate cbp)
1601 {
1602  bool buttonsBefore = cbp.buttonsBefore != Qt::NoButton;
1603  QString keyModifierString = keyString(cbp.modifiers + cbp.key);
1604  if (!keyModifierString.isEmpty()) {
1605 #ifdef Q_OS_MAC
1606  // modifiers never has a '+' sign. Add one space to clearly separate modifiers (and possible key) from button
1607  keyModifierString += " ";
1608 #else
1609  // modifiers might be of the form : 'S' or 'Ctrl+S' or 'Ctrl+'. For consistency, add an other '+' if needed, no spaces
1610  if (!keyModifierString.endsWith('+'))
1611  keyModifierString += "+";
1612 #endif
1613  }
1614 
1615  return tr("%1%2%3%4%5%6", "Modifier / button or wheel / double click / with / button / pressed")
1616  .arg(keyModifierString)
1617  .arg(mouseButtonsString(cbp.button)+(cbp.button == Qt::NoButton ? tr("Wheel", "Mouse wheel") : ""))
1618  .arg(cbp.doubleClick ? tr(" double click", "Suffix after mouse button") : "")
1619  .arg(buttonsBefore ? tr(" with ", "As in : Left button with Ctrl pressed") : "")
1620  .arg(buttonsBefore ? mouseButtonsString(cbp.buttonsBefore) : "")
1621  .arg(buttonsBefore ? tr(" pressed", "As in : Left button with Ctrl pressed") : "");
1622 }
1623 
1624 bool QGLViewer::isValidShortcutKey(int key) {
1625  return (key >= Qt::Key_Any && key < Qt::Key_Escape) || (key >= Qt::Key_F1 && key <= Qt::Key_F35);
1626 }
1627 
1628 #ifndef DOXYGEN
1629 
1633 void QGLViewer::setMouseBindingDescription(int state, QString description, bool doubleClick, Qt::MouseButtons buttonsBefore) {
1634  qWarning("setMouseBindingDescription(int state,...) is deprecated. Use the modifier/button equivalent");
1635  setMouseBindingDescription(keyboardModifiersFromState(state),
1636  mouseButtonFromState(state),
1637  description,
1638  doubleClick,
1639  buttonsBefore);
1640 }
1641 #endif
1642 
1647 void QGLViewer::setMouseBindingDescription(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, QString description, bool doubleClick, Qt::MouseButtons buttonsBefore)
1648 {
1649  setMouseBindingDescription(Qt::Key(0), modifiers, button, description, doubleClick, buttonsBefore);
1650 }
1651 
1681 void QGLViewer::setMouseBindingDescription(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, QString description, bool doubleClick, Qt::MouseButtons buttonsBefore)
1682 {
1683  ClickBindingPrivate cbp(modifiers, button, doubleClick, buttonsBefore, key);
1684 
1685  if (description.isEmpty())
1686  mouseDescription_.remove(cbp);
1687  else
1688  mouseDescription_[cbp] = description;
1689 }
1690 
1691 static QString tableLine(const QString& left, const QString& right)
1692 {
1693  static bool even = false;
1694  const QString tdtd("</b></td><td>");
1695  const QString tdtr("</td></tr>\n");
1696 
1697  QString res("<tr bgcolor=\"");
1698 
1699  if (even)
1700  res += "#eeeeff\">";
1701  else
1702  res += "#ffffff\">";
1703  res += "<td><b>" + left + tdtd + right + tdtr;
1704  even = !even;
1705 
1706  return res;
1707 }
1708 
1718 QString QGLViewer::mouseString() const
1719 {
1720  QString text("<center><table border=\"1\" cellspacing=\"0\" cellpadding=\"4\">\n");
1721  const QString trtd("<tr><td>");
1722  const QString tdtr("</td></tr>\n");
1723  const QString tdtd("</td><td>");
1724 
1725  text += QString("<tr bgcolor=\"#aaaacc\"><th align=\"center\">%1</th><th align=\"center\">%2</th></tr>\n").
1726  arg(tr("Button(s)", "Buttons column header in help window mouse tab")).arg(tr("Description", "Description column header in help window mouse tab"));
1727 
1728  QMap<ClickBindingPrivate, QString> mouseBinding;
1729 
1730  // User-defined mouse bindings come first.
1731  for (QMap<ClickBindingPrivate, QString>::ConstIterator itm=mouseDescription_.begin(), endm=mouseDescription_.end(); itm!=endm; ++itm)
1732  mouseBinding[itm.key()] = itm.value();
1733 
1734  for (QMap<ClickBindingPrivate, QString>::ConstIterator it=mouseBinding.begin(), end=mouseBinding.end(); it != end; ++it)
1735  {
1736  // Should not be needed (see setMouseBindingDescription())
1737  if (it.value().isNull())
1738  continue;
1739 
1740  text += tableLine(formatClickActionPrivate(it.key()), it.value());
1741  }
1742 
1743  // Optional separator line
1744  if (!mouseBinding.isEmpty())
1745  {
1746  mouseBinding.clear();
1747  text += QString("<tr bgcolor=\"#aaaacc\"><td colspan=2>%1</td></tr>\n").arg(tr("Standard mouse bindings", "In help window mouse tab"));
1748  }
1749 
1750  // Then concatenates the descriptions of wheelBinding_, mouseBinding_ and clickBinding_.
1751  // The order is significant and corresponds to the priorities set in mousePressEvent() (reverse priority order, last one overwrites previous)
1752  // #CONNECTION# mousePressEvent() order
1753  for (QMap<MouseBindingPrivate, MouseActionPrivate>::ConstIterator itmb=mouseBinding_.begin(), endmb=mouseBinding_.end();
1754  itmb != endmb; ++itmb)
1755  {
1756  ClickBindingPrivate cbp(itmb.key().modifiers, itmb.key().button, false, Qt::NoButton, itmb.key().key);
1757 
1758  QString text = mouseActionString(itmb.value().action);
1759 
1760  if (!text.isNull())
1761  {
1762  switch (itmb.value().handler)
1763  {
1764  case CAMERA: text += " " + tr("camera", "Suffix after action"); break;
1765  case FRAME: text += " " + tr("manipulated frame", "Suffix after action"); break;
1766  }
1767  if (!(itmb.value().withConstraint))
1768  text += "*";
1769  }
1770  mouseBinding[cbp] = text;
1771  }
1772 
1773  for (QMap<WheelBindingPrivate, MouseActionPrivate>::ConstIterator itw=wheelBinding_.begin(), endw=wheelBinding_.end(); itw != endw; ++itw)
1774  {
1775  ClickBindingPrivate cbp(itw.key().modifiers, Qt::NoButton, false, Qt::NoButton, itw.key().key);
1776 
1777  QString text = mouseActionString(itw.value().action);
1778 
1779  if (!text.isNull())
1780  {
1781  switch (itw.value().handler)
1782  {
1783  case CAMERA: text += " " + tr("camera", "Suffix after action"); break;
1784  case FRAME: text += " " + tr("manipulated frame", "Suffix after action"); break;
1785  }
1786  if (!(itw.value().withConstraint))
1787  text += "*";
1788  }
1789 
1790  mouseBinding[cbp] = text;
1791  }
1792 
1793  for (QMap<ClickBindingPrivate, ClickAction>::ConstIterator itcb=clickBinding_.begin(), endcb=clickBinding_.end(); itcb!=endcb; ++itcb)
1794  mouseBinding[itcb.key()] = clickActionString(itcb.value());
1795 
1796  for (QMap<ClickBindingPrivate, QString>::ConstIterator it2=mouseBinding.begin(), end2=mouseBinding.end(); it2 != end2; ++it2)
1797  {
1798  if (it2.value().isNull())
1799  continue;
1800 
1801  text += tableLine(formatClickActionPrivate(it2.key()), it2.value());
1802  }
1803 
1804  text += "</table></center>";
1805 
1806  return text;
1807 }
1808 
1823 void QGLViewer::setKeyDescription(int key, QString description)
1824 {
1825  if (description.isEmpty())
1826  keyDescription_.remove(key);
1827  else
1828  keyDescription_[key] = description;
1829 }
1830 
1831 QString QGLViewer::cameraPathKeysString() const
1832 {
1833  if (pathIndex_.isEmpty())
1834  return QString::null;
1835 
1836  QVector<int> keys;
1837  keys.reserve(pathIndex_.count());
1838  for (QMap<Qt::Key, int>::ConstIterator i = pathIndex_.begin(), endi=pathIndex_.end(); i != endi; ++i)
1839  keys.push_back(i.key());
1840  qSort(keys);
1841 
1842  QVector<int>::const_iterator it = keys.begin(), end = keys.end();
1843  QString res = keyString(*it);
1844 
1845  const int maxDisplayedKeys = 6;
1846  int nbDisplayedKeys = 0;
1847  int previousKey = (*it);
1848  int state = 0;
1849  ++it;
1850  while ((it != end) && (nbDisplayedKeys < maxDisplayedKeys-1))
1851  {
1852  switch (state)
1853  {
1854  case 0 :
1855  if ((*it) == previousKey + 1)
1856  state++;
1857  else
1858  {
1859  res += ", " + keyString(*it);
1860  nbDisplayedKeys++;
1861  }
1862  break;
1863  case 1 :
1864  if ((*it) == previousKey + 1)
1865  state++;
1866  else
1867  {
1868  res += ", " + keyString(previousKey);
1869  res += ", " + keyString(*it);
1870  nbDisplayedKeys += 2;
1871  state = 0;
1872  }
1873  break;
1874  default :
1875  if ((*it) != previousKey + 1)
1876  {
1877  res += ".." + keyString(previousKey);
1878  res += ", " + keyString(*it);
1879  nbDisplayedKeys += 2;
1880  state = 0;
1881  }
1882  break;
1883  }
1884  previousKey = *it;
1885  ++it;
1886  }
1887 
1888  if (state == 1)
1889  res += ", " + keyString(previousKey);
1890  if (state == 2)
1891  res += ".." + keyString(previousKey);
1892  if (it != end)
1893  res += "...";
1894 
1895  return res;
1896 }
1897 
1907 {
1908  QString text("<center><table border=\"1\" cellspacing=\"0\" cellpadding=\"4\">\n");
1909  text += QString("<tr bgcolor=\"#aaaacc\"><th align=\"center\">%1</th><th align=\"center\">%2</th></tr>\n").
1910  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"));
1911 
1912  QMap<int, QString> keyDescription;
1913 
1914  // 1 - User defined key descriptions
1915  for (QMap<int, QString>::ConstIterator kd=keyDescription_.begin(), kdend=keyDescription_.end(); kd!=kdend; ++kd)
1916  keyDescription[kd.key()] = kd.value();
1917 
1918  // Add to text in sorted order
1919  for (QMap<int, QString>::ConstIterator kb=keyDescription.begin(), endb=keyDescription.end(); kb!=endb; ++kb)
1920  text += tableLine(keyString(kb.key()), kb.value());
1921 
1922 
1923  // 2 - Optional separator line
1924  if (!keyDescription.isEmpty())
1925  {
1926  keyDescription.clear();
1927  text += QString("<tr bgcolor=\"#aaaacc\"><td colspan=2>%1</td></tr>\n").arg(QGLViewer::tr("Standard viewer keys", "In help window keys tab"));
1928  }
1929 
1930 
1931  // 3 - KeyboardAction bindings description
1932  for (QMap<KeyboardAction, unsigned int>::ConstIterator it=keyboardBinding_.begin(), end=keyboardBinding_.end(); it != end; ++it)
1933  if ((it.value() != 0) && ((!cameraIsInRotateMode()) || ((it.key() != INCREASE_FLYSPEED) && (it.key() != DECREASE_FLYSPEED))))
1934  keyDescription[it.value()] = keyboardActionDescription_[it.key()];
1935 
1936  // Add to text in sorted order
1937  for (QMap<int, QString>::ConstIterator kb2=keyDescription.begin(), endb2=keyDescription.end(); kb2!=endb2; ++kb2)
1938  text += tableLine(keyString(kb2.key()), kb2.value());
1939 
1940 
1941  // 4 - Camera paths keys description
1942  const QString cpks = cameraPathKeysString();
1943  if (!cpks.isNull())
1944  {
1945  text += "<tr bgcolor=\"#ccccff\"><td colspan=2>\n";
1946  text += QGLViewer::tr("Camera paths are controlled using the %1 keys (noted <i>Fx</i> below):", "Help window key tab camera keys").arg(cpks) + "</td></tr>\n";
1947  text += tableLine(keyString(playPathKeyboardModifiers()) + "<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>",
1948  QGLViewer::tr("Plays path (or resets saved position)"));
1949  text += tableLine(keyString(addKeyFrameKeyboardModifiers()) + "<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>",
1950  QGLViewer::tr("Adds a key frame to path (or defines a position)"));
1951  text += tableLine(keyString(addKeyFrameKeyboardModifiers()) + "<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>+<i>" + QGLViewer::tr("Fx", "Generic function key (F1..F12)") + "</i>",
1952  QGLViewer::tr("Deletes path (or saved position)"));
1953  }
1954  text += "</table></center>";
1955 
1956  return text;
1957 }
1958 
1961  help();
1962  helpWidget()->setCurrentIndex(3);
1963 }
1964 
1965 
1976 {
1977  Q_EMIT helpRequired();
1978 
1979  bool resize = false;
1980  int width=600;
1981  int height=400;
1982 
1983  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")};
1984 
1985  if (!helpWidget())
1986  {
1987  // Qt4 requires a NULL parent...
1988  helpWidget_ = new QTabWidget(NULL);
1989  helpWidget()->setWindowTitle(tr("Help", "Help window title"));
1990 
1991  resize = true;
1992  for (int i=0; i<4; ++i)
1993  {
1994  QTextEdit* tab = new QTextEdit(NULL);
1995  tab->setReadOnly(true);
1996 
1997  helpWidget()->insertTab(i, tab, label[i]);
1998  if (i==3) {
1999 # include "qglviewer-icon.xpm"
2000  QPixmap pixmap(qglviewer_icon);
2001  tab->document()->addResource(QTextDocument::ImageResource,
2002  QUrl("mydata://qglviewer-icon.xpm"), QVariant(pixmap));
2003  }
2004  }
2005  }
2006 
2007  for (int i=0; i<4; ++i)
2008  {
2009  QString text;
2010  switch (i)
2011  {
2012  case 0 : text = helpString(); break;
2013  case 1 : text = keyboardString(); break;
2014  case 2 : text = mouseString(); break;
2015  case 3 : text = QString("<center><br><img src=\"mydata://qglviewer-icon.xpm\">") + tr(
2016  "<h1>libQGLViewer</h1>"
2017  "<h3>Version %1</h3><br>"
2018  "A versatile 3D viewer based on OpenGL and Qt<br>"
2019  "Copyright 2002-%2 Gilles Debunne<br>"
2020  "<code>%3</code>").arg(QGLViewerVersionString()).arg("2014").arg("http://www.libqglviewer.com") +
2021  QString("</center>");
2022  break;
2023  default : break;
2024  }
2025 
2026  QTextEdit* textEdit = (QTextEdit*)(helpWidget()->widget(i));
2027  textEdit->setHtml(text);
2028  textEdit->setText(text);
2029 
2030  if (resize && (textEdit->height() > height))
2031  height = textEdit->height();
2032  }
2033 
2034  if (resize)
2035  helpWidget()->resize(width, height+40); // 40 pixels is ~ tabs' height
2036  helpWidget()->show();
2037  helpWidget()->raise();
2038 }
2039 
2066 void QGLViewer::keyPressEvent(QKeyEvent *e)
2067 {
2068  if (e->key() == 0)
2069  {
2070  e->ignore();
2071  return;
2072  }
2073 
2074  const Qt::Key key = Qt::Key(e->key());
2075 
2076  const Qt::KeyboardModifiers modifiers = e->modifiers();
2077 
2078  QMap<KeyboardAction, unsigned int>::ConstIterator it=keyboardBinding_.begin(), end=keyboardBinding_.end();
2079  const unsigned int target = key | modifiers;
2080  while ((it != end) && (it.value() != target))
2081  ++it;
2082 
2083  if (it != end)
2084  handleKeyboardAction(it.key());
2085  else
2086  if (pathIndex_.contains(Qt::Key(key)))
2087  {
2088  // Camera paths
2089  int index = pathIndex_[Qt::Key(key)];
2090 
2091  // not safe, but try to double press on two viewers at the same time !
2092  static QTime doublePress;
2093 
2094  if (modifiers == playPathKeyboardModifiers())
2095  {
2096  int elapsed = doublePress.restart();
2097  if ((elapsed < 250) && (index==previousPathId_))
2098  camera()->resetPath(index);
2099  else
2100  {
2101  // Stop previous interpolation before starting a new one.
2102  if (index != previousPathId_)
2103  {
2104  KeyFrameInterpolator* previous = camera()->keyFrameInterpolator(previousPathId_);
2105  if ((previous) && (previous->interpolationIsStarted()))
2106  previous->resetInterpolation();
2107  }
2108  camera()->playPath(index);
2109  }
2110  previousPathId_ = index;
2111  }
2112  else if (modifiers == addKeyFrameKeyboardModifiers())
2113  {
2114  int elapsed = doublePress.restart();
2115  if ((elapsed < 250) && (index==previousPathId_))
2116  {
2117  if (camera()->keyFrameInterpolator(index))
2118  {
2119  disconnect(camera()->keyFrameInterpolator(index), SIGNAL(interpolated()), this, SLOT(update()));
2120  if (camera()->keyFrameInterpolator(index)->numberOfKeyFrames() > 1)
2121  displayMessage(tr("Path %1 deleted", "Feedback message").arg(index));
2122  else
2123  displayMessage(tr("Position %1 deleted", "Feedback message").arg(index));
2124  camera()->deletePath(index);
2125  }
2126  }
2127  else
2128  {
2129  bool nullBefore = (camera()->keyFrameInterpolator(index) == NULL);
2130  camera()->addKeyFrameToPath(index);
2131  if (nullBefore)
2132  connect(camera()->keyFrameInterpolator(index), SIGNAL(interpolated()), SLOT(update()));
2133  int nbKF = camera()->keyFrameInterpolator(index)->numberOfKeyFrames();
2134  if (nbKF > 1)
2135  displayMessage(tr("Path %1, position %2 added", "Feedback message").arg(index).arg(nbKF));
2136  else
2137  displayMessage(tr("Position %1 saved", "Feedback message").arg(index));
2138  }
2139  previousPathId_ = index;
2140  }
2141  update();
2142  } else {
2143  if (isValidShortcutKey(key)) currentlyPressedKey_ = key;
2144  e->ignore();
2145  }
2146 }
2147 
2148 void QGLViewer::keyReleaseEvent(QKeyEvent * e) {
2149  if (isValidShortcutKey(e->key())) currentlyPressedKey_ = Qt::Key(0);
2150 }
2151 
2152 void QGLViewer::handleKeyboardAction(KeyboardAction id)
2153 {
2154  switch (id)
2155  {
2156  case DRAW_AXIS : toggleAxisIsDrawn(); break;
2157  case DRAW_GRID : toggleGridIsDrawn(); break;
2158  case DISPLAY_FPS : toggleFPSIsDisplayed(); break;
2159  case ENABLE_TEXT : toggleTextIsEnabled(); break;
2160  case EXIT_VIEWER : saveStateToFileForAllViewers(); qApp->closeAllWindows(); break;
2161  case SAVE_SCREENSHOT : saveSnapshot(false, false); break;
2162  case FULL_SCREEN : toggleFullScreen(); break;
2163  case STEREO : toggleStereoDisplay(); break;
2164  case ANIMATION : toggleAnimation(); break;
2165  case HELP : help(); break;
2166  case EDIT_CAMERA : toggleCameraIsEdited(); break;
2167  case SNAPSHOT_TO_CLIPBOARD : snapshotToClipboard(); break;
2168  case CAMERA_MODE :
2169  toggleCameraMode();
2170  displayMessage(cameraIsInRotateMode()?tr("Camera in observer mode", "Feedback message"):tr("Camera in fly mode", "Feedback message"));
2171  break;
2172 
2173  case MOVE_CAMERA_LEFT :
2174  camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(-10.0*camera()->flySpeed(), 0.0, 0.0)));
2175  update();
2176  break;
2177  case MOVE_CAMERA_RIGHT :
2178  camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec( 10.0*camera()->flySpeed(), 0.0, 0.0)));
2179  update();
2180  break;
2181  case MOVE_CAMERA_UP :
2182  camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(0.0, 10.0*camera()->flySpeed(), 0.0)));
2183  update();
2184  break;
2185  case MOVE_CAMERA_DOWN :
2186  camera()->frame()->translate(camera()->frame()->inverseTransformOf(Vec(0.0, -10.0*camera()->flySpeed(), 0.0)));
2187  update();
2188  break;
2189 
2190  case INCREASE_FLYSPEED : camera()->setFlySpeed(camera()->flySpeed() * 1.5); break;
2191  case DECREASE_FLYSPEED : camera()->setFlySpeed(camera()->flySpeed() / 1.5); break;
2192  }
2193 }
2194 
2199 void QGLViewer::resizeGL(int width, int height)
2200 {
2201  QGLWidget::resizeGL(width, height);
2202  glViewport( 0, 0, GLint(width), GLint(height) );
2203  camera()->setScreenWidthAndHeight(this->width(), this->height());
2204 }
2205 
2207 // K e y b o a r d s h o r t c u t s //
2209 
2227 void QGLViewer::setShortcut(KeyboardAction action, unsigned int key)
2228 {
2229  keyboardBinding_[action] = key;
2230 }
2231 
2247 unsigned int QGLViewer::shortcut(KeyboardAction action) const
2248 {
2249  if (keyboardBinding_.contains(action))
2250  return keyboardBinding_[action];
2251  else
2252  return 0;
2253 }
2254 
2255 #ifndef DOXYGEN
2256 void QGLViewer::setKeyboardAccelerator(KeyboardAction action, int key)
2257 {
2258  qWarning("setKeyboardAccelerator is deprecated. Use setShortcut instead.");
2259  setShortcut(action, key);
2260 }
2261 
2262 int QGLViewer::keyboardAccelerator(KeyboardAction action) const
2263 {
2264  qWarning("keyboardAccelerator is deprecated. Use shortcut instead.");
2265  return shortcut(action);
2266 }
2267 #endif
2268 
2270 
2286 Qt::Key QGLViewer::pathKey(int index) const
2287 {
2288  for (QMap<Qt::Key, int>::ConstIterator it = pathIndex_.begin(), end=pathIndex_.end(); it != end; ++it)
2289  if (it.value() == index)
2290  return it.key();
2291  return Qt::Key(0);
2292 }
2293 
2305 void QGLViewer::setPathKey(int key, int index)
2306 {
2307  if (key < 0)
2308  pathIndex_.remove(Qt::Key(-key));
2309  else
2310  pathIndex_[Qt::Key(key)] = index;
2311 }
2312 
2314 void QGLViewer::setPlayPathKeyboardModifiers(Qt::KeyboardModifiers modifiers)
2315 {
2316  playPathKeyboardModifiers_ = modifiers;
2317 }
2318 
2320 void QGLViewer::setAddKeyFrameKeyboardModifiers(Qt::KeyboardModifiers modifiers)
2321 {
2322  addKeyFrameKeyboardModifiers_ = modifiers;
2323 }
2324 
2334 Qt::KeyboardModifiers QGLViewer::addKeyFrameKeyboardModifiers() const
2335 {
2336  return addKeyFrameKeyboardModifiers_;
2337 }
2338 
2347 Qt::KeyboardModifiers QGLViewer::playPathKeyboardModifiers() const
2348 {
2349  return playPathKeyboardModifiers_;
2350 }
2351 
2352 #ifndef DOXYGEN
2353 // Deprecated methods
2354 Qt::KeyboardModifiers QGLViewer::addKeyFrameStateKey() const
2355 {
2356  qWarning("addKeyFrameStateKey has been renamed addKeyFrameKeyboardModifiers");
2357  return addKeyFrameKeyboardModifiers(); }
2358 
2359 Qt::KeyboardModifiers QGLViewer::playPathStateKey() const
2360 {
2361  qWarning("playPathStateKey has been renamed playPathKeyboardModifiers");
2362  return playPathKeyboardModifiers();
2363 }
2364 
2365 void QGLViewer::setAddKeyFrameStateKey(int buttonState)
2366 {
2367  qWarning("setAddKeyFrameStateKey has been renamed setAddKeyFrameKeyboardModifiers");
2368  setAddKeyFrameKeyboardModifiers(keyboardModifiersFromState(buttonState));
2369 }
2370 
2371 void QGLViewer::setPlayPathStateKey(int buttonState)
2372 {
2373  qWarning("setPlayPathStateKey has been renamed setPlayPathKeyboardModifiers");
2374  setPlayPathKeyboardModifiers(keyboardModifiersFromState(buttonState));
2375 }
2376 
2377 Qt::Key QGLViewer::keyFrameKey(int index) const
2378 {
2379  qWarning("keyFrameKey has been renamed pathKey.");
2380  return pathKey(index);
2381 }
2382 
2383 Qt::KeyboardModifiers QGLViewer::playKeyFramePathStateKey() const
2384 {
2385  qWarning("playKeyFramePathStateKey has been renamed playPathKeyboardModifiers.");
2386  return playPathKeyboardModifiers();
2387 }
2388 
2389 void QGLViewer::setKeyFrameKey(int index, int key)
2390 {
2391  qWarning("setKeyFrameKey is deprecated, use setPathKey instead, with swapped parameters.");
2392  setPathKey(key, index);
2393 }
2394 
2395 void QGLViewer::setPlayKeyFramePathStateKey(int buttonState)
2396 {
2397  qWarning("setPlayKeyFramePathStateKey has been renamed setPlayPathKeyboardModifiers.");
2398  setPlayPathKeyboardModifiers(keyboardModifiersFromState(buttonState));
2399 }
2400 #endif
2401 
2403 // M o u s e b e h a v i o r s t a t e k e y s //
2405 #ifndef DOXYGEN
2406 
2444 void QGLViewer::setHandlerKeyboardModifiers(MouseHandler handler, Qt::KeyboardModifiers modifiers)
2445 {
2446  qWarning("setHandlerKeyboardModifiers is deprecated, call setMouseBinding() instead");
2447 
2448  QMap<MouseBindingPrivate, MouseActionPrivate> newMouseBinding;
2449  QMap<WheelBindingPrivate, MouseActionPrivate> newWheelBinding;
2450  QMap<ClickBindingPrivate, ClickAction> newClickBinding_;
2451 
2452  QMap<MouseBindingPrivate, MouseActionPrivate>::Iterator mit;
2453  QMap<WheelBindingPrivate, MouseActionPrivate>::Iterator wit;
2454 
2455  // First copy unchanged bindings.
2456  for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit)
2457  if ((mit.value().handler != handler) || (mit.value().action == ZOOM_ON_REGION))
2458  newMouseBinding[mit.key()] = mit.value();
2459 
2460  for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit)
2461  if (wit.value().handler != handler)
2462  newWheelBinding[wit.key()] = wit.value();
2463 
2464  // Then, add modified bindings, that can overwrite the previous ones.
2465  for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit)
2466  if ((mit.value().handler == handler) && (mit.value().action != ZOOM_ON_REGION))
2467  {
2468  MouseBindingPrivate mbp(modifiers, mit.key().button, mit.key().key);
2469  newMouseBinding[mbp] = mit.value();
2470  }
2471 
2472  for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit)
2473  if (wit.value().handler == handler)
2474  {
2475  WheelBindingPrivate wbp(modifiers, wit.key().key);
2476  newWheelBinding[wbp] = wit.value();
2477  }
2478 
2479  // Same for button bindings
2480  for (QMap<ClickBindingPrivate, ClickAction>::ConstIterator cb=clickBinding_.begin(), end=clickBinding_.end(); cb != end; ++cb)
2481  if (((handler==CAMERA) && ((cb.value() == CENTER_SCENE) || (cb.value() == ALIGN_CAMERA))) ||
2482  ((handler==FRAME) && ((cb.value() == CENTER_FRAME) || (cb.value() == ALIGN_FRAME))))
2483  {
2484  ClickBindingPrivate cbp(modifiers, cb.key().button, cb.key().doubleClick, cb.key().buttonsBefore, cb.key().key);
2485  newClickBinding_[cbp] = cb.value();
2486  }
2487  else
2488  newClickBinding_[cb.key()] = cb.value();
2489 
2490  mouseBinding_ = newMouseBinding;
2491  wheelBinding_ = newWheelBinding;
2492  clickBinding_ = newClickBinding_;
2493 }
2494 
2495 void QGLViewer::setHandlerStateKey(MouseHandler handler, int buttonState)
2496 {
2497  qWarning("setHandlerStateKey has been renamed setHandlerKeyboardModifiers");
2498  setHandlerKeyboardModifiers(handler, keyboardModifiersFromState(buttonState));
2499 }
2500 
2501 void QGLViewer::setMouseStateKey(MouseHandler handler, int buttonState)
2502 {
2503  qWarning("setMouseStateKey has been renamed setHandlerKeyboardModifiers.");
2504  setHandlerKeyboardModifiers(handler, keyboardModifiersFromState(buttonState));
2505 }
2506 
2511 void QGLViewer::setMouseBinding(int state, MouseHandler handler, MouseAction action, bool withConstraint)
2512 {
2513  qWarning("setMouseBinding(int state, MouseHandler...) is deprecated. Use the modifier/button equivalent");
2514  setMouseBinding(keyboardModifiersFromState(state),
2515  mouseButtonFromState(state),
2516  handler,
2517  action,
2518  withConstraint);
2519 }
2520 #endif
2521 
2526 void QGLViewer::setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, MouseHandler handler, MouseAction action, bool withConstraint) {
2527  setMouseBinding(Qt::Key(0), modifiers, button, handler, action, withConstraint);
2528 }
2529 
2562 void QGLViewer::setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, MouseHandler handler, MouseAction action, bool withConstraint)
2563 {
2564  if ((handler == FRAME) && ((action == MOVE_FORWARD) || (action == MOVE_BACKWARD) ||
2565  (action == ROLL) || (action == LOOK_AROUND) ||
2566  (action == ZOOM_ON_REGION))) {
2567  qWarning("Cannot bind %s to FRAME", mouseActionString(action).toLatin1().constData());
2568  return;
2569  }
2570 
2571  if (button == Qt::NoButton) {
2572  qWarning("No mouse button specified in setMouseBinding");
2573  return;
2574  }
2575 
2576  MouseActionPrivate map;
2577  map.handler = handler;
2578  map.action = action;
2579  map.withConstraint = withConstraint;
2580 
2581  MouseBindingPrivate mbp(modifiers, button, key);
2582  if (action == NO_MOUSE_ACTION)
2583  mouseBinding_.remove(mbp);
2584  else
2585  mouseBinding_.insert(mbp, map);
2586 
2587  ClickBindingPrivate cbp(modifiers, button, false, Qt::NoButton, key);
2588  clickBinding_.remove(cbp);
2589 }
2590 
2591 #ifndef DOXYGEN
2592 
2596 void QGLViewer::setMouseBinding(int state, ClickAction action, bool doubleClick, Qt::MouseButtons buttonsBefore) {
2597  qWarning("setMouseBinding(int state, ClickAction...) is deprecated. Use the modifier/button equivalent");
2598  setMouseBinding(keyboardModifiersFromState(state),
2599  mouseButtonFromState(state),
2600  action,
2601  doubleClick,
2602  buttonsBefore);
2603 }
2604 #endif
2605 
2610 void QGLViewer::setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, ClickAction action, bool doubleClick, Qt::MouseButtons buttonsBefore)
2611 {
2612  setMouseBinding(Qt::Key(0), modifiers, button, action, doubleClick, buttonsBefore);
2613 }
2614 
2635 void QGLViewer::setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, ClickAction action, bool doubleClick, Qt::MouseButtons buttonsBefore)
2636 {
2637  if ((buttonsBefore != Qt::NoButton) && !doubleClick) {
2638  qWarning("Buttons before is only meaningful when doubleClick is true in setMouseBinding().");
2639  return;
2640  }
2641 
2642  if (button == Qt::NoButton) {
2643  qWarning("No mouse button specified in setMouseBinding");
2644  return;
2645  }
2646 
2647  ClickBindingPrivate cbp(modifiers, button, doubleClick, buttonsBefore, key);
2648 
2649  // #CONNECTION performClickAction comment on NO_CLICK_ACTION
2650  if (action == NO_CLICK_ACTION)
2651  clickBinding_.remove(cbp);
2652  else
2653  clickBinding_.insert(cbp, action);
2654 
2655  if ((!doubleClick) && (buttonsBefore == Qt::NoButton)) {
2656  MouseBindingPrivate mbp(modifiers, button, key);
2657  mouseBinding_.remove(mbp);
2658  }
2659 }
2660 
2665 void QGLViewer::setWheelBinding(Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint) {
2666  setWheelBinding(Qt::Key(0), modifiers, handler, action, withConstraint);
2667 }
2668 
2679 void QGLViewer::setWheelBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint)
2680 {
2681  //#CONNECTION# ManipulatedFrame::wheelEvent and ManipulatedCameraFrame::wheelEvent switches
2682  if ((action != ZOOM) && (action != MOVE_FORWARD) && (action != MOVE_BACKWARD) && (action != NO_MOUSE_ACTION)) {
2683  qWarning("Cannot bind %s to wheel", mouseActionString(action).toLatin1().constData());
2684  return;
2685  }
2686 
2687  if ((handler == FRAME) && (action != ZOOM) && (action != NO_MOUSE_ACTION)) {
2688  qWarning("Cannot bind %s to FRAME wheel", mouseActionString(action).toLatin1().constData());
2689  return;
2690  }
2691 
2692  MouseActionPrivate map;
2693  map.handler = handler;
2694  map.action = action;
2695  map.withConstraint = withConstraint;
2696 
2697  WheelBindingPrivate wbp(modifiers, key);
2698  if (action == NO_MOUSE_ACTION)
2699  wheelBinding_.remove(wbp);
2700  else
2701  wheelBinding_[wbp] = map;
2702 }
2703 
2709  mouseBinding_.clear();
2710  clickBinding_.clear();
2711  wheelBinding_.clear();
2712 }
2713 
2719  keyboardBinding_.clear();
2720  pathIndex_.clear();
2721 }
2722 
2728  qWarning("mouseAction(int state,...) is deprecated. Use the modifier/button equivalent");
2729  return mouseAction(Qt::Key(0), keyboardModifiersFromState(state), mouseButtonFromState(state));
2730 }
2731 
2746 QGLViewer::MouseAction QGLViewer::mouseAction(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button) const
2747 {
2748  MouseBindingPrivate mbp(modifiers, button, key);
2749  if (mouseBinding_.contains(mbp))
2750  return mouseBinding_[mbp].action;
2751  else
2752  return NO_MOUSE_ACTION;
2753 }
2754 
2759 int QGLViewer::mouseHandler(int state) const {
2760  qWarning("mouseHandler(int state,...) is deprecated. Use the modifier/button equivalent");
2761  return mouseHandler(Qt::Key(0), keyboardModifiersFromState(state), mouseButtonFromState(state));
2762 }
2763 
2776 int QGLViewer::mouseHandler(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button) const
2777 {
2778  MouseBindingPrivate mbp(modifiers, button, key);
2779  if (mouseBinding_.contains(mbp))
2780  return mouseBinding_[mbp].handler;
2781  else
2782  return -1;
2783 }
2784 
2785 
2786 #ifndef DOXYGEN
2787 
2791 int QGLViewer::mouseButtonState(MouseHandler handler, MouseAction action, bool withConstraint) const {
2792  qWarning("mouseButtonState() is deprecated. Use mouseButtons() and keyboardModifiers() instead");
2793  for (QMap<MouseBindingPrivate, MouseActionPrivate>::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it != end; ++it)
2794  if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) )
2795  return (int) it.key().modifiers | (int) it.key().button;
2796 
2797  return Qt::NoButton;
2798 }
2799 #endif
2800 
2808 void QGLViewer::getWheelActionBinding(MouseHandler handler, MouseAction action, bool withConstraint,
2809  Qt::Key& key, Qt::KeyboardModifiers& modifiers) const
2810 {
2811  for (QMap<WheelBindingPrivate, MouseActionPrivate>::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it != end; ++it)
2812  if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) ) {
2813  key = it.key().key;
2814  modifiers = it.key().modifiers;
2815  return;
2816  }
2817 
2818  key = Qt::Key(-1);
2819  modifiers = Qt::NoModifier;
2820 }
2821 
2829 void QGLViewer::getMouseActionBinding(MouseHandler handler, MouseAction action, bool withConstraint,
2830  Qt::Key& key, Qt::KeyboardModifiers& modifiers, Qt::MouseButton& button) const
2831 {
2832  for (QMap<MouseBindingPrivate, MouseActionPrivate>::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it != end; ++it)
2833  if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) ) {
2834  key = it.key().key;
2835  modifiers = it.key().modifiers;
2836  button = it.key().button;
2837  return;
2838  }
2839 
2840  key = Qt::Key(0);
2841  modifiers = Qt::NoModifier;
2842  button = Qt::NoButton;
2843 }
2844 
2851 QGLViewer::MouseAction QGLViewer::wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) const
2852 {
2853  WheelBindingPrivate wbp(modifiers, key);
2854  if (wheelBinding_.contains(wbp))
2855  return wheelBinding_[wbp].action;
2856  else
2857  return NO_MOUSE_ACTION;
2858 }
2859 
2864 int QGLViewer::wheelHandler(Qt::Key key, Qt::KeyboardModifiers modifiers) const
2865 {
2866  WheelBindingPrivate wbp(modifiers, key);
2867  if (wheelBinding_.contains(wbp))
2868  return wheelBinding_[wbp].handler;
2869  else
2870  return -1;
2871 }
2872 
2876 QGLViewer::ClickAction QGLViewer::clickAction(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button,
2877  bool doubleClick, Qt::MouseButtons buttonsBefore) const {
2878  ClickBindingPrivate cbp(modifiers, button, doubleClick, buttonsBefore, key);
2879  if (clickBinding_.contains(cbp))
2880  return clickBinding_[cbp];
2881  else
2882  return NO_CLICK_ACTION;
2883 }
2884 
2885 #ifndef DOXYGEN
2886 
2889 QGLViewer::MouseAction QGLViewer::wheelAction(Qt::KeyboardModifiers modifiers) const {
2890  qWarning("wheelAction() is deprecated. Use the new wheelAction() method with a key parameter instead");
2891  return wheelAction(Qt::Key(0), modifiers);
2892 }
2893 
2897 int QGLViewer::wheelHandler(Qt::KeyboardModifiers modifiers) const {
2898  qWarning("wheelHandler() is deprecated. Use the new wheelHandler() method with a key parameter instead");
2899  return wheelHandler(Qt::Key(0), modifiers);
2900 }
2901 
2905 int QGLViewer::wheelButtonState(MouseHandler handler, MouseAction action, bool withConstraint) const
2906 {
2907  qWarning("wheelButtonState() is deprecated. Use the wheelAction() and wheelHandler() instead");
2908  for (QMap<WheelBindingPrivate, MouseActionPrivate>::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it!=end; ++it)
2909  if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) )
2910  return it.key().key + it.key().modifiers;
2911 
2912  return -1;
2913 }
2914 
2919 QGLViewer::ClickAction QGLViewer::clickAction(int state, bool doubleClick, Qt::MouseButtons buttonsBefore) const {
2920  qWarning("clickAction(int state,...) is deprecated. Use the modifier/button equivalent");
2921  return clickAction(Qt::Key(0),
2922  keyboardModifiersFromState(state),
2923  mouseButtonFromState(state),
2924  doubleClick,
2925  buttonsBefore);
2926 }
2927 
2932 void QGLViewer::getClickButtonState(ClickAction action, int& state, bool& doubleClick, Qt::MouseButtons& buttonsBefore) const {
2933  qWarning("getClickButtonState(int state,...) is deprecated. Use the modifier/button equivalent");
2934  Qt::KeyboardModifiers modifiers;
2935  Qt::MouseButton button;
2936  Qt::Key key;
2937  getClickActionBinding(action, key, modifiers, button, doubleClick, buttonsBefore);
2938  state = (int) modifiers | (int) button | (int) key;
2939 }
2940 #endif
2941 
2949 void QGLViewer::getClickActionBinding(ClickAction action, Qt::Key& key, Qt::KeyboardModifiers& modifiers, Qt::MouseButton &button, bool& doubleClick, Qt::MouseButtons& buttonsBefore) const
2950 {
2951  for (QMap<ClickBindingPrivate, ClickAction>::ConstIterator it=clickBinding_.begin(), end=clickBinding_.end(); it != end; ++it)
2952  if (it.value() == action) {
2953  modifiers = it.key().modifiers;
2954  button = it.key().button;
2955  doubleClick = it.key().doubleClick;
2956  buttonsBefore = it.key().buttonsBefore;
2957  key = it.key().key;
2958  return;
2959  }
2960 
2961  modifiers = Qt::NoModifier;
2962  button = Qt::NoButton;
2963  doubleClick = false;
2964  buttonsBefore = Qt::NoButton;
2965  key = Qt::Key(0);
2966 }
2967 
2971 bool QGLViewer::cameraIsInRotateMode() const
2972 {
2973  //#CONNECTION# used in toggleCameraMode() and keyboardString()
2974  Qt::Key key;
2975  Qt::KeyboardModifiers modifiers;
2976  Qt::MouseButton button;
2977  getMouseActionBinding(CAMERA, ROTATE, false /*constraint*/, key, modifiers, button);
2978  return button != Qt::NoButton;
2979 }
2980 
2994 {
2995  Qt::Key key;
2996  Qt::KeyboardModifiers modifiers;
2997  Qt::MouseButton button;
2998  getMouseActionBinding(CAMERA, ROTATE, false /*constraint*/, key, modifiers, button);
2999  bool rotateMode = button != Qt::NoButton;
3000 
3001  if (!rotateMode) {
3002  getMouseActionBinding(CAMERA, MOVE_FORWARD, false /*constraint*/, key, modifiers, button);
3003  }
3004 
3005  //#CONNECTION# setDefaultMouseBindings()
3006  if (rotateMode)
3007  {
3008  camera()->frame()->updateSceneUpVector();
3009  camera()->frame()->stopSpinning();
3010 
3011  setMouseBinding(modifiers, Qt::LeftButton, CAMERA, MOVE_FORWARD);
3012  setMouseBinding(modifiers, Qt::MidButton, CAMERA, LOOK_AROUND);
3013  setMouseBinding(modifiers, Qt::RightButton, CAMERA, MOVE_BACKWARD);
3014 
3015  setMouseBinding(Qt::Key_R, modifiers, Qt::LeftButton, CAMERA, ROLL);
3016 
3017  setMouseBinding(Qt::NoModifier, Qt::LeftButton, NO_CLICK_ACTION, true);
3018  setMouseBinding(Qt::NoModifier, Qt::MidButton, NO_CLICK_ACTION, true);
3019  setMouseBinding(Qt::NoModifier, Qt::RightButton, NO_CLICK_ACTION, true);
3020 
3021  setWheelBinding(modifiers, CAMERA, MOVE_FORWARD);
3022  }
3023  else
3024  {
3025  // Should stop flyTimer. But unlikely and not easy.
3026  setMouseBinding(modifiers, Qt::LeftButton, CAMERA, ROTATE);
3027  setMouseBinding(modifiers, Qt::MidButton, CAMERA, ZOOM);
3028  setMouseBinding(modifiers, Qt::RightButton, CAMERA, TRANSLATE);
3029 
3030  setMouseBinding(Qt::Key_R, modifiers, Qt::LeftButton, CAMERA, SCREEN_ROTATE);
3031 
3032  setMouseBinding(Qt::NoModifier, Qt::LeftButton, ALIGN_CAMERA, true);
3033  setMouseBinding(Qt::NoModifier, Qt::MidButton, SHOW_ENTIRE_SCENE, true);
3034  setMouseBinding(Qt::NoModifier, Qt::RightButton, CENTER_SCENE, true);
3035 
3036  setWheelBinding(modifiers, CAMERA, ZOOM);
3037  }
3038 }
3039 
3041 // M a n i p u l a t e d f r a m e s //
3043 
3056 {
3057  if (manipulatedFrame())
3058  {
3060 
3061  if (manipulatedFrame() != camera()->frame())
3062  {
3063  disconnect(manipulatedFrame(), SIGNAL(manipulated()), this, SLOT(update()));
3064  disconnect(manipulatedFrame(), SIGNAL(spun()), this, SLOT(update()));
3065  }
3066  }
3067 
3068  manipulatedFrame_ = frame;
3069 
3070  manipulatedFrameIsACamera_ = ((manipulatedFrame() != camera()->frame()) &&
3071  (dynamic_cast<ManipulatedCameraFrame*>(manipulatedFrame()) != NULL));
3072 
3073  if (manipulatedFrame())
3074  {
3075  // Prevent multiple connections, that would result in useless display updates
3076  if (manipulatedFrame() != camera()->frame())
3077  {
3078  connect(manipulatedFrame(), SIGNAL(manipulated()), SLOT(update()));
3079  connect(manipulatedFrame(), SIGNAL(spun()), SLOT(update()));
3080  }
3081  }
3082 }
3083 
3084 #ifndef DOXYGEN
3085 // V i s u a l H i n t s //
3088 
3104 {
3105  // Pivot point cross
3106  if (visualHint_ & 1)
3107  {
3108  const float size = 15.0;
3109  Vec proj = camera()->projectedCoordinatesOf(camera()->pivotPoint());
3111  glDisable(GL_LIGHTING);
3112  glDisable(GL_DEPTH_TEST);
3113  glLineWidth(3.0);
3114  glBegin(GL_LINES);
3115  glVertex2f(proj.x - size, proj.y);
3116  glVertex2f(proj.x + size, proj.y);
3117  glVertex2f(proj.x, proj.y - size);
3118  glVertex2f(proj.x, proj.y + size);
3119  glEnd();
3120  glEnable(GL_DEPTH_TEST);
3122  }
3123 
3124  // if (visualHint_ & 2)
3125  // drawText(80, 10, "Play");
3126 
3127  // Screen rotate line
3128  ManipulatedFrame* mf = NULL;
3129  Vec pnt;
3130  if (camera()->frame()->action_ == SCREEN_ROTATE)
3131  {
3132  mf = camera()->frame();
3133  pnt = camera()->pivotPoint();
3134  }
3135  if (manipulatedFrame() && (manipulatedFrame()->action_ == SCREEN_ROTATE))
3136  {
3137  mf = manipulatedFrame();
3138  // Maybe useful if the mf is a manipCameraFrame...
3139  // pnt = manipulatedFrame()->pivotPoint();
3140  pnt = manipulatedFrame()->position();
3141  }
3142 
3143  if (mf)
3144  {
3145  pnt = camera()->projectedCoordinatesOf(pnt);
3147  glDisable(GL_LIGHTING);
3148  glDisable(GL_DEPTH_TEST);
3149  glLineWidth(3.0);
3150  glBegin(GL_LINES);
3151  glVertex2f(pnt.x, pnt.y);
3152  glVertex2f(mf->prevPos_.x(), mf->prevPos_.y());
3153  glEnd();
3154  glEnable(GL_DEPTH_TEST);
3156  }
3157 
3158  // Zoom on region: draw a rectangle
3159  if (camera()->frame()->action_ == ZOOM_ON_REGION)
3160  {
3162  glDisable(GL_LIGHTING);
3163  glDisable(GL_DEPTH_TEST);
3164  glLineWidth(2.0);
3165  glBegin(GL_LINE_LOOP);
3166  glVertex2i(camera()->frame()->pressPos_.x(), camera()->frame()->pressPos_.y());
3167  glVertex2i(camera()->frame()->prevPos_.x(), camera()->frame()->pressPos_.y());
3168  glVertex2i(camera()->frame()->prevPos_.x(), camera()->frame()->prevPos_.y());
3169  glVertex2i(camera()->frame()->pressPos_.x(), camera()->frame()->prevPos_.y());
3170  glEnd();
3171  glEnable(GL_DEPTH_TEST);
3173  }
3174 }
3175 
3179 void QGLViewer::setVisualHintsMask(int mask, int delay)
3180 {
3181  visualHint_ = visualHint_ | mask;
3182  QTimer::singleShot(delay, this, SLOT(resetVisualHints()));
3183 }
3184 
3187 {
3188  visualHint_ = 0;
3189 }
3190 #endif
3191 
3193 // A x i s a n d G r i d d i s p l a y l i s t s //
3195 
3205 void QGLViewer::drawArrow(float length, float radius, int nbSubdivisions)
3206 {
3207  static GLUquadric* quadric = gluNewQuadric();
3208 
3209  if (radius < 0.0)
3210  radius = 0.05 * length;
3211 
3212  const float head = 2.5*(radius / length) + 0.1;
3213  const float coneRadiusCoef = 4.0 - 5.0 * head;
3214 
3215  gluCylinder(quadric, radius, radius, length * (1.0 - head/coneRadiusCoef), nbSubdivisions, 1);
3216  glTranslatef(0.0, 0.0, length * (1.0 - head));
3217  gluCylinder(quadric, coneRadiusCoef * radius, 0.0, head * length, nbSubdivisions, 1);
3218  glTranslatef(0.0, 0.0, -length * (1.0 - head));
3219 }
3220 
3225 void QGLViewer::drawArrow(const Vec& from, const Vec& to, float radius, int nbSubdivisions)
3226 {
3227  glPushMatrix();
3228  glTranslatef(from[0],from[1],from[2]);
3229  const Vec dir = to-from;
3230  glMultMatrixd(Quaternion(Vec(0,0,1), dir).matrix());
3231  QGLViewer::drawArrow(dir.norm(), radius, nbSubdivisions);
3232  glPopMatrix();
3233 }
3234 
3253 void QGLViewer::drawAxis(float length)
3254 {
3255  const float charWidth = length / 40.0;
3256  const float charHeight = length / 30.0;
3257  const float charShift = 1.04 * length;
3258 
3259  GLboolean lighting, colorMaterial;
3260  glGetBooleanv(GL_LIGHTING, &lighting);
3261  glGetBooleanv(GL_COLOR_MATERIAL, &colorMaterial);
3262 
3263  glDisable(GL_LIGHTING);
3264 
3265  glBegin(GL_LINES);
3266  // The X
3267  glVertex3f(charShift, charWidth, -charHeight);
3268  glVertex3f(charShift, -charWidth, charHeight);
3269  glVertex3f(charShift, -charWidth, -charHeight);
3270  glVertex3f(charShift, charWidth, charHeight);
3271  // The Y
3272  glVertex3f( charWidth, charShift, charHeight);
3273  glVertex3f(0.0, charShift, 0.0);
3274  glVertex3f(-charWidth, charShift, charHeight);
3275  glVertex3f(0.0, charShift, 0.0);
3276  glVertex3f(0.0, charShift, 0.0);
3277  glVertex3f(0.0, charShift, -charHeight);
3278  // The Z
3279  glVertex3f(-charWidth, charHeight, charShift);
3280  glVertex3f( charWidth, charHeight, charShift);
3281  glVertex3f( charWidth, charHeight, charShift);
3282  glVertex3f(-charWidth, -charHeight, charShift);
3283  glVertex3f(-charWidth, -charHeight, charShift);
3284  glVertex3f( charWidth, -charHeight, charShift);
3285  glEnd();
3286 
3287  glEnable(GL_LIGHTING);
3288  glDisable(GL_COLOR_MATERIAL);
3289 
3290  float color[4];
3291  color[0] = 0.7f; color[1] = 0.7f; color[2] = 1.0f; color[3] = 1.0f;
3292  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
3293  QGLViewer::drawArrow(length, 0.01*length);
3294 
3295  color[0] = 1.0f; color[1] = 0.7f; color[2] = 0.7f; color[3] = 1.0f;
3296  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
3297  glPushMatrix();
3298  glRotatef(90.0, 0.0, 1.0, 0.0);
3299  QGLViewer::drawArrow(length, 0.01*length);
3300  glPopMatrix();
3301 
3302  color[0] = 0.7f; color[1] = 1.0f; color[2] = 0.7f; color[3] = 1.0f;
3303  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
3304  glPushMatrix();
3305  glRotatef(-90.0, 1.0, 0.0, 0.0);
3306  QGLViewer::drawArrow(length, 0.01*length);
3307  glPopMatrix();
3308 
3309  if (colorMaterial)
3310  glEnable(GL_COLOR_MATERIAL);
3311  if (!lighting)
3312  glDisable(GL_LIGHTING);
3313 }
3314 
3321 void QGLViewer::drawGrid(float size, int nbSubdivisions)
3322 {
3323  GLboolean lighting;
3324  glGetBooleanv(GL_LIGHTING, &lighting);
3325 
3326  glDisable(GL_LIGHTING);
3327 
3328  glBegin(GL_LINES);
3329  for (int i=0; i<=nbSubdivisions; ++i)
3330  {
3331  const float pos = size*(2.0*i/nbSubdivisions-1.0);
3332  glVertex2f(pos, -size);
3333  glVertex2f(pos, +size);
3334  glVertex2f(-size, pos);
3335  glVertex2f( size, pos);
3336  }
3337  glEnd();
3338 
3339  if (lighting)
3340  glEnable(GL_LIGHTING);
3341 }
3342 
3344 // S t a t i c m e t h o d s : Q G L V i e w e r P o o l //
3346 
3348 void QGLViewer::saveStateToFileForAllViewers()
3349 {
3350  Q_FOREACH (QGLViewer* viewer, QGLViewer::QGLViewerPool())
3351  {
3352  if (viewer)
3353  viewer->saveStateToFile();
3354  }
3355 }
3356 
3358 // S a v e s t a t e b e t w e e n s e s s i o n s //
3360 
3375 {
3376  QString name = stateFileName_;
3377 
3378  if (!name.isEmpty() && QGLViewer::QGLViewerIndex(this) > 0)
3379  {
3380  QFileInfo fi(name);
3381  if (fi.suffix().isEmpty())
3382  name += QString::number(QGLViewer::QGLViewerIndex(this));
3383  else
3384  name = fi.absolutePath() + '/' + fi.completeBaseName() + QString::number(QGLViewer::QGLViewerIndex(this)) + "." + fi.suffix();
3385  }
3386 
3387  return name;
3388 }
3389 
3398 {
3399  QString name = stateFileName();
3400 
3401  if (name.isEmpty())
3402  return;
3403 
3404  QFileInfo fileInfo(name);
3405 
3406  if (fileInfo.isDir())
3407  {
3408  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));
3409  return;
3410  }
3411 
3412  const QString dirName = fileInfo.absolutePath();
3413  if (!QFileInfo(dirName).exists())
3414  {
3415  QDir dir;
3416  if (!(dir.mkdir(dirName)))
3417  {
3418  QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to create directory %1").arg(dirName));
3419  return;
3420  }
3421  }
3422 
3423  // Write the DOM tree to file
3424  QFile f(name);
3425  if (f.open(QIODevice::WriteOnly))
3426  {
3427  QTextStream out(&f);
3428  QDomDocument doc("QGLVIEWER");
3429  doc.appendChild(domElement("QGLViewer", doc));
3430  doc.save(out, 2);
3431  f.flush();
3432  f.close();
3433  }
3434  else
3435  QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to save to file %1").arg(name) + ":\n" + f.errorString());
3436 }
3437 
3459 {
3460  QString name = stateFileName();
3461 
3462  if (name.isEmpty())
3463  return false;
3464 
3465  QFileInfo fileInfo(name);
3466 
3467  if (!fileInfo.isFile())
3468  // No warning since it would be displayed at first start.
3469  return false;
3470 
3471  if (!fileInfo.isReadable())
3472  {
3473  QMessageBox::warning(this, tr("Problem in state restoration", "Message box window title"), tr("File %1 is not readable.").arg(name));
3474  return false;
3475  }
3476 
3477  // Read the DOM tree form file
3478  QFile f(name);
3479  if (f.open(QIODevice::ReadOnly))
3480  {
3481  QDomDocument doc;
3482  doc.setContent(&f);
3483  f.close();
3484  QDomElement main = doc.documentElement();
3485  initFromDOMElement(main);
3486  }
3487  else
3488  {
3489  QMessageBox::warning(this, tr("Open file error", "Message box window title"), tr("Unable to open file %1").arg(name) + ":\n" + f.errorString());
3490  return false;
3491  }
3492 
3493  return true;
3494 }
3495 
3528 QDomElement QGLViewer::domElement(const QString& name, QDomDocument& document) const
3529 {
3530  QDomElement de = document.createElement(name);
3531  de.setAttribute("version", QGLViewerVersionString());
3532 
3533  QDomElement stateNode = document.createElement("State");
3534  // hasMouseTracking() is not saved
3535  stateNode.appendChild(DomUtils::QColorDomElement(foregroundColor(), "foregroundColor", document));
3536  stateNode.appendChild(DomUtils::QColorDomElement(backgroundColor(), "backgroundColor", document));
3537  DomUtils::setBoolAttribute(stateNode, "stereo", displaysInStereo());
3538  // Revolve or fly camera mode is not saved
3539  de.appendChild(stateNode);
3540 
3541  QDomElement displayNode = document.createElement("Display");
3542  DomUtils::setBoolAttribute(displayNode, "axisIsDrawn", axisIsDrawn());
3543  DomUtils::setBoolAttribute(displayNode, "gridIsDrawn", gridIsDrawn());
3544  DomUtils::setBoolAttribute(displayNode, "FPSIsDisplayed", FPSIsDisplayed());
3545  DomUtils::setBoolAttribute(displayNode, "cameraIsEdited", cameraIsEdited());
3546  // textIsEnabled() is not saved
3547  de.appendChild(displayNode);
3548 
3549  QDomElement geometryNode = document.createElement("Geometry");
3550  DomUtils::setBoolAttribute(geometryNode, "fullScreen", isFullScreen());
3551  if (isFullScreen())
3552  {
3553  geometryNode.setAttribute("prevPosX", QString::number(prevPos_.x()));
3554  geometryNode.setAttribute("prevPosY", QString::number(prevPos_.y()));
3555  }
3556  else
3557  {
3558  QWidget* tlw = topLevelWidget();
3559  geometryNode.setAttribute("width", QString::number(tlw->width()));
3560  geometryNode.setAttribute("height", QString::number(tlw->height()));
3561  geometryNode.setAttribute("posX", QString::number(tlw->pos().x()));
3562  geometryNode.setAttribute("posY", QString::number(tlw->pos().y()));
3563  }
3564  de.appendChild(geometryNode);
3565 
3566  // Restore original Camera zClippingCoefficient before saving.
3567  if (cameraIsEdited())
3568  camera()->setZClippingCoefficient(previousCameraZClippingCoefficient_);
3569  de.appendChild(camera()->domElement("Camera", document));
3570  if (cameraIsEdited())
3571  // #CONNECTION# 5.0 from setCameraIsEdited()
3573 
3574  if (manipulatedFrame())
3575  de.appendChild(manipulatedFrame()->domElement("ManipulatedFrame", document));
3576 
3577  return de;
3578 }
3579 
3614 void QGLViewer::initFromDOMElement(const QDomElement& element)
3615 {
3616  const QString version = element.attribute("version");
3617  // if (version != QGLViewerVersionString())
3618  if (version[0] != '2')
3619  // Patches for previous versions should go here when the state file syntax is modified.
3620  qWarning("State file created using QGLViewer version %s may not be correctly read.", version.toLatin1().constData());
3621 
3622  QDomElement child=element.firstChild().toElement();
3623  bool tmpCameraIsEdited = cameraIsEdited();
3624  while (!child.isNull())
3625  {
3626  if (child.tagName() == "State")
3627  {
3628  // #CONNECTION# default values from defaultConstructor()
3629  // setMouseTracking(DomUtils::boolFromDom(child, "mouseTracking", false));
3630  setStereoDisplay(DomUtils::boolFromDom(child, "stereo", false));
3631  //if ((child.attribute("cameraMode", "revolve") == "fly") && (cameraIsInRevolveMode()))
3632  // toggleCameraMode();
3633 
3634  QDomElement ch=child.firstChild().toElement();
3635  while (!ch.isNull())
3636  {
3637  if (ch.tagName() == "foregroundColor")
3638  setForegroundColor(DomUtils::QColorFromDom(ch));
3639  if (ch.tagName() == "backgroundColor")
3640  setBackgroundColor(DomUtils::QColorFromDom(ch));
3641  ch = ch.nextSibling().toElement();
3642  }
3643  }
3644 
3645  if (child.tagName() == "Display")
3646  {
3647  // #CONNECTION# default values from defaultConstructor()
3648  setAxisIsDrawn(DomUtils::boolFromDom(child, "axisIsDrawn", false));
3649  setGridIsDrawn(DomUtils::boolFromDom(child, "gridIsDrawn", false));
3650  setFPSIsDisplayed(DomUtils::boolFromDom(child, "FPSIsDisplayed", false));
3651  // See comment below.
3652  tmpCameraIsEdited = DomUtils::boolFromDom(child, "cameraIsEdited", false);
3653  // setTextIsEnabled(DomUtils::boolFromDom(child, "textIsEnabled", true));
3654  }
3655 
3656  if (child.tagName() == "Geometry")
3657  {
3658  setFullScreen(DomUtils::boolFromDom(child, "fullScreen", false));
3659 
3660  if (isFullScreen())
3661  {
3662  prevPos_.setX(DomUtils::intFromDom(child, "prevPosX", 0));
3663  prevPos_.setY(DomUtils::intFromDom(child, "prevPosY", 0));
3664  }
3665  else
3666  {
3667  int width = DomUtils::intFromDom(child, "width", 600);
3668  int height = DomUtils::intFromDom(child, "height", 400);
3669  topLevelWidget()->resize(width, height);
3670  camera()->setScreenWidthAndHeight(this->width(), this->height());
3671 
3672  QPoint pos;
3673  pos.setX(DomUtils::intFromDom(child, "posX", 0));
3674  pos.setY(DomUtils::intFromDom(child, "posY", 0));
3675  topLevelWidget()->move(pos);
3676  }
3677  }
3678 
3679  if (child.tagName() == "Camera")
3680  {
3681  connectAllCameraKFIInterpolatedSignals(false);
3682  camera()->initFromDOMElement(child);
3683  connectAllCameraKFIInterpolatedSignals();
3684  }
3685 
3686  if ((child.tagName() == "ManipulatedFrame") && (manipulatedFrame()))
3688 
3689  child = child.nextSibling().toElement();
3690  }
3691 
3692  // The Camera always stores its "real" zClippingCoef in domElement(). If it is edited,
3693  // its "real" coef must be saved and the coef set to 5.0, as is done in setCameraIsEdited().
3694  // BUT : Camera and Display are read in an arbitrary order. We must initialize Camera's
3695  // "real" coef BEFORE calling setCameraIsEdited. Hence this temp cameraIsEdited and delayed call
3696  cameraIsEdited_ = tmpCameraIsEdited;
3697  if (cameraIsEdited_)
3698  {
3699  previousCameraZClippingCoefficient_ = camera()->zClippingCoefficient();
3700  // #CONNECTION# 5.0 from setCameraIsEdited.
3702  }
3703 }
3704 
3705 #ifndef DOXYGEN
3706 
3708 void QGLViewer::saveToFile(const QString& fileName)
3709 {
3710  if (!fileName.isEmpty())
3711  setStateFileName(fileName);
3712 
3713  qWarning("saveToFile() is deprecated, use saveStateToFile() instead.");
3714  saveStateToFile();
3715 }
3716 
3719 bool QGLViewer::restoreFromFile(const QString& fileName)
3720 {
3721  if (!fileName.isEmpty())
3722  setStateFileName(fileName);
3723 
3724  qWarning("restoreFromFile() is deprecated, use restoreStateFromFile() instead.");
3725  return restoreStateFromFile();
3726 }
3727 #endif
3728 
3782 void QGLViewer::copyBufferToTexture(GLint internalFormat, GLenum format)
3783 {
3784  int h = 16;
3785  int w = 16;
3786  // Todo compare performance with qt code.
3787  while (w < width())
3788  w <<= 1;
3789  while (h < height())
3790  h <<= 1;
3791 
3792  bool init = false;
3793 
3794  if ((w != bufferTextureWidth_) || (h != bufferTextureHeight_))
3795  {
3796  bufferTextureWidth_ = w;
3797  bufferTextureHeight_ = h;
3798  bufferTextureMaxU_ = width() / float(bufferTextureWidth_);
3799  bufferTextureMaxV_ = height() / float(bufferTextureHeight_);
3800  init = true;
3801  }
3802 
3803  if (bufferTextureId() == 0)
3804  {
3805  glGenTextures(1, &bufferTextureId_);
3806  glBindTexture(GL_TEXTURE_2D, bufferTextureId_);
3807  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3808  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3809  init = true;
3810  }
3811  else
3812  glBindTexture(GL_TEXTURE_2D, bufferTextureId_);
3813 
3814  if ((format != previousBufferTextureFormat_) ||
3815  (internalFormat != previousBufferTextureInternalFormat_))
3816  {
3817  previousBufferTextureFormat_ = format;
3818  previousBufferTextureInternalFormat_ = internalFormat;
3819  init = true;
3820  }
3821 
3822  if (init)
3823  {
3824  if (format == GL_NONE)
3825  format = internalFormat;
3826 
3827  glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, bufferTextureWidth_, bufferTextureHeight_, 0, format, GL_UNSIGNED_BYTE, NULL);
3828  }
3829 
3830  glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width(), height());
3831 }
3832 
3840 {
3841  if (glIsTexture(bufferTextureId_))
3842  return bufferTextureId_;
3843  else
3844  return 0;
3845 }
QColor foregroundColor() const
Returns the foreground color used by the viewer.
Definition: qglviewer.h:182
QColor backgroundColor() const
Returns the background color of the viewer.
Definition: qglviewer.h:168
KeyFrameInterpolator * keyFrameInterpolator(int i) const
Returns the KeyFrameInterpolator that defines the Camera path number i.
Definition: camera.cpp:1664
virtual void timerEvent(QTimerEvent *)
Overloading of the QObject method.
Definition: qglviewer.cpp:864
A keyFrame Catmull-Rom Frame interpolator.
Vec projectedCoordinatesOf(const Vec &src, const Frame *frame=NULL) const
Returns the screen projected coordinates of a point src defined in the frame coordinate system...
Definition: camera.cpp:1584
virtual void beginSelection(const QPoint &point)
This method should prepare the selection.
Definition: qglviewer.cpp:1012
virtual void help()
Opens a modal help window that includes four tabs, respectively filled with helpString(), keyboardString(), mouseString() and about libQGLViewer.
Definition: qglviewer.cpp:1975
virtual void drawWithNames()
This method is called by select() and should draw selectable entities.
Definition: qglviewer.h:885
The ManipulatedCameraFrame class represents a ManipulatedFrame with Camera specific mouse bindings...
virtual QString mouseString() const
Returns a QString that describes the application mouse bindings, displayed in the help() window Mouse...
Definition: qglviewer.cpp:1718
virtual void initFromDOMElement(const QDomElement &element)
Restores the ManipulatedFrame state from a QDomElement created by domElement().
void toggleCameraMode()
Swaps between two predefined camera mouse bindings.
Definition: qglviewer.cpp:2993
void displayMessage(const QString &message, int delay=2000)
Briefly displays a message in the lower left corner of the widget.
Definition: qglviewer.cpp:764
void getMouseActionBinding(MouseHandler handler, MouseAction action, bool withConstraint, Qt::Key &key, Qt::KeyboardModifiers &modifiers, Qt::MouseButton &button) const
Returns the mouse and keyboard state that triggers action on handler withConstraint.
Definition: qglviewer.cpp:2829
Vec pivotPoint() const
The point the Camera pivots around with the QGLViewer::ROTATE mouse binding.
Definition: camera.cpp:1275
virtual void aboutQGLViewer()
Displays the help window "About" tab.
Definition: qglviewer.cpp:1960
A ManipulatedFrame is a Frame that can be rotated and translated using the mouse. ...
virtual void select(const QMouseEvent *event)
Simple wrapper method: calls select(event->pos()).
Definition: qglviewer.cpp:936
virtual void paintGL()
Main paint method, inherited from QGLWidget.
Definition: qglviewer.cpp:275
void setWheelBinding(Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint=true)
Defines a mouse wheel binding.
Definition: qglviewer.cpp:2665
float sceneRadius() const
Returns the scene radius.
Definition: qglviewer.h:206
void toggleCameraIsEdited()
Toggles the state of cameraIsEdited().
Definition: qglviewer.h:146
Qt::KeyboardModifiers addKeyFrameKeyboardModifiers() const
Returns the keyboard modifiers that must be pressed with a pathKey() to add the current camera positi...
Definition: qglviewer.cpp:2334
virtual void drawLight(GLenum light, float scale=1.0f) const
Draws a representation of light.
Definition: qglviewer.cpp:656
void setForegroundColor(const QColor &color)
Sets the foregroundColor() of the viewer, used to draw visual hints.
Definition: qglviewer.h:188
unsigned int shortcut(KeyboardAction action) const
Returns the keyboard shortcut associated to a given QGLViewer::KeyboardAction.
Definition: qglviewer.cpp:2247
virtual void mouseMoveEvent(QMouseEvent *)
Overloading of the QWidget method.
Definition: qglviewer.cpp:1296
void translate(Vec &t)
Same as translate(const Vec&) but t may be modified to satisfy the translation constraint().
Definition: frame.cpp:335
MouseAction
Defines the possible actions that can be binded to a mouse action (a click, followed by a mouse displ...
Definition: qglviewer.h:969
virtual void fastDraw()
Draws a simplified version of the scene to guarantee interactive camera displacements.
Definition: qglviewer.cpp:437
QFont scaledFont(const QFont &font) const
Return a possibly scaled version of font, used for snapshot rendering.
Definition: qglviewer.h:552
virtual void mousePressEvent(QMouseEvent *)
Overloading of the QWidget method.
Definition: qglviewer.cpp:1191
void saveToFile(const QString &fileName=QString::null)
This method is deprecated since version 1.3.9-5.
Definition: qglviewer.cpp:3708
virtual void checkIfGrabsMouse(int x, int y, const Camera *const camera)=0
Pure virtual method, called by the QGLViewers before they test if the MouseGrabber grabsMouse()...
virtual void preDrawStereo(bool leftBuffer=true)
Called before draw() (instead of preDraw()) when viewer displaysInStereo().
Definition: qglviewer.cpp:410
void alignWithFrame(const Frame *const frame, bool move=false, float threshold=0.0f)
Aligns the Frame with frame, so that two of their axis are parallel.
Definition: frame.cpp:1055
virtual void mouseDoubleClickEvent(QMouseEvent *const event, Camera *const camera)
Callback method called when the MouseGrabber grabsMouse() and a mouse button is double clicked...
Definition: mouseGrabber.h:235
virtual void drawAllPaths()
Draws all the Camera paths defined by the keyFrameInterpolator().
Definition: camera.cpp:1778
virtual void stopScreenCoordinatesSystem() const
Stops the pixel coordinate drawing block started by startScreenCoordinatesSystem().
Definition: qglviewer.cpp:852
void clearMouseBindings()
Clears all the default mouse bindings.
Definition: qglviewer.cpp:2708
void setFlySpeed(float speed)
Sets the Camera flySpeed().
Definition: camera.cpp:1268
void getClickActionBinding(ClickAction action, Qt::Key &key, Qt::KeyboardModifiers &modifiers, Qt::MouseButton &button, bool &doubleClick, Qt::MouseButtons &buttonsBefore) const
Returns the mouse and keyboard state that triggers action.
Definition: qglviewer.cpp:2949
int mouseHandler(int state) const
This method is deprecated since version 2.5.0.
Definition: qglviewer.cpp:2759
void helpRequired()
Signal emitted by the default QGLViewer::help() method.
const GLdouble * matrix() const
Returns the 4x4 OpenGL transformation matrix represented by the Frame.
Definition: frame.cpp:123
virtual void initFromDOMElement(const QDomElement &element)
Restores the Camera state from a QDomElement created by domElement().
Definition: camera.cpp:1869
double norm() const
Returns the norm of the vector.
Definition: vec.h:335
void setStateFileName(const QString &name)
Defines the stateFileName() used by saveStateToFile() and restoreStateFromFile(). ...
Definition: qglviewer.h:1059
MouseAction mouseAction(int state) const
This method is deprecated since version 2.5.0.
Definition: qglviewer.cpp:2727
qglviewer::ManipulatedFrame * manipulatedFrame() const
Returns the viewer's qglviewer::ManipulatedFrame.
Definition: qglviewer.h:262
int wheelButtonState(MouseHandler handler, MouseAction action, bool withConstraint=true) const
This method is deprecated since version 2.5.0.
Definition: qglviewer.cpp:2905
virtual void loadProjectionMatrixStereo(bool leftBuffer=true) const
Same as loadProjectionMatrix() but for a stereo setup.
Definition: camera.cpp:536
virtual void loadModelViewMatrix(bool reset=true) const
Loads the OpenGL GL_MODELVIEW matrix with the modelView matrix corresponding to the Camera...
Definition: camera.cpp:500
void setZClippingCoefficient(float coef)
Sets the zClippingCoefficient() value.
Definition: camera.h:268
void setMouseGrabberIsEnabled(const qglviewer::MouseGrabber *const mouseGrabber, bool enabled=true)
Sets the mouseGrabberIsEnabled() state.
Definition: qglviewer.cpp:1544
QGLViewer(QWidget *parent=0, const QGLWidget *shareWidget=0, Qt::WindowFlags flags=0)
Constructor.
Definition: qglviewer.cpp:160
virtual QString keyboardString() const
Returns a QString that describes the application keyboard shortcut bindings, and that will be display...
Definition: qglviewer.cpp:1906
ClickAction clickAction(int state, bool doubleClick, Qt::MouseButtons buttonsBefore) const
This method is deprecated since version 2.5.0.
Definition: qglviewer.cpp:2919
Qt::KeyboardModifiers playPathKeyboardModifiers() const
Returns the keyboard modifiers that must be pressed with a pathKey() to play a camera KeyFrame path...
Definition: qglviewer.cpp:2347
virtual void init()
Initializes the viewer OpenGL context.
Definition: qglviewer.h:762
GLuint * selectBuffer()
Returns a pointer to an array of GLuint.
Definition: qglviewer.h:844
virtual void startScreenCoordinatesSystem(bool upward=false) const
Modify the projection matrix so that drawing can be done directly with 2D screen coordinates.
Definition: qglviewer.cpp:827
KeyboardAction
Defines the different actions that can be associated with a keyboard shortcut using setShortcut()...
Definition: qglviewer.h:905
virtual bool restoreStateFromFile()
Restores the QGLViewer state from the stateFileName() file using initFromDOMElement().
Definition: qglviewer.cpp:3458
void saveSnapshot(bool automatic=true, bool overwrite=false)
Saves a snapshot of the current image displayed by the widget.
bool axisIsDrawn() const
Returns true if the world axis is drawn by the viewer.
Definition: qglviewer.h:97
ManipulatedCameraFrame * frame() const
Returns the ManipulatedCameraFrame attached to the Camera.
Definition: camera.h:334
Abstract class for objects that grab mouse focus in a QGLViewer.
Definition: mouseGrabber.h:130
virtual void setVisualHintsMask(int mask, int delay=2000)
Defines the mask that will be used to drawVisualHints().
Definition: qglviewer.cpp:3179
virtual void stopAnimation()
Stops animation.
Definition: qglviewer.cpp:881
bool textIsEnabled() const
Returns true if text display (see drawText()) is enabled.
Definition: qglviewer.h:113
void toggleFullScreen()
Toggles the state of isFullScreen().
Definition: qglviewer.h:357
virtual void endSelection(const QPoint &point)
This method is called by select() after scene elements were drawn by drawWithNames().
Definition: qglviewer.cpp:1072
virtual void loadModelViewMatrixStereo(bool leftBuffer=true) const
Same as loadModelViewMatrix() but for a stereo setup.
Definition: camera.cpp:591
void getWheelActionBinding(MouseHandler handler, MouseAction action, bool withConstraint, Qt::Key &key, Qt::KeyboardModifiers &modifiers) const
Returns the keyboard state that triggers action on handler withConstraint using the mouse wheel...
Definition: qglviewer.cpp:2808
bool isFullScreen() const
Returns true if the viewer is in fullScreen mode.
Definition: qglviewer.h:329
virtual void mouseReleaseEvent(QMouseEvent *)
Overloading of the QWidget method.
Definition: qglviewer.cpp:1353
void resetInterpolation()
Stops the interpolation and resets interpolationTime() to the firstTime().
int animationPeriod() const
The animation loop period, in milliseconds.
Definition: qglviewer.h:612
GLuint bufferTextureId() const
Returns the texture id of the texture created by copyBufferToTexture().
Definition: qglviewer.cpp:3839
void setFullScreen(bool fullScreen=true)
Sets the isFullScreen() state.
Definition: qglviewer.cpp:1503
void setHandlerKeyboardModifiers(MouseHandler handler, Qt::KeyboardModifiers modifiers)
This method has been deprecated since version 2.5.0.
Definition: qglviewer.cpp:2444
The Vec class represents 3D positions and 3D vectors.
Definition: vec.h:65
void showEntireScene()
Moves the Camera so that the entire scene is visible.
Definition: camera.cpp:987
int numberOfKeyFrames() const
Returns the number of keyFrames used by the interpolation.
bool gridIsDrawn() const
Returns true if a XY grid is drawn by the viewer.
Definition: qglviewer.h:101
MouseAction wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) const
Returns the MouseAction (if any) that is performed when using the wheel, when the modifiers and key k...
Definition: qglviewer.cpp:2851
void setScreenWidthAndHeight(int width, int height)
Sets Camera screenWidth() and screenHeight() (expressed in pixels).
Definition: camera.cpp:166
bool displaysInStereo() const
Returns true if the viewer displays in stereo.
Definition: qglviewer.h:349
QString stateFileName() const
Returns the state file name.
Definition: qglviewer.cpp:3374
void setTranslation(const Vec &translation)
Sets the translation() of the frame, locally defined with respect to the referenceFrame().
Definition: frame.h:201
void setStereoDisplay(bool stereo=true)
Sets the state of displaysInStereo().
Definition: qglviewer.cpp:1475
virtual void setPathKey(int key, int index=0)
Sets the pathKey() associated with the camera Key Frame path index.
Definition: qglviewer.cpp:2305
virtual void startAction(int ma, bool withConstraint=true)
Protected internal method used to handle mouse events.
int mouseButtonState(MouseHandler handler, MouseAction action, bool withConstraint=true) const
This method is deprecated since version 2.5.0.
Definition: qglviewer.cpp:2791
virtual void addKeyFrameToPath(int i)
Adds the current Camera position() and orientation() as a keyFrame to the path number i...
Definition: camera.cpp:1710
int selectRegionHeight() const
See the selectRegionWidth() documentation.
Definition: qglviewer.h:837
bool interpolationIsStarted() const
Returns true when the interpolation is being performed.
void toggleStereoDisplay()
Toggles the state of displaysInStereo().
Definition: qglviewer.h:359
void setMouseGrabber(qglviewer::MouseGrabber *mouseGrabber)
Directly defines the mouseGrabber().
Definition: qglviewer.cpp:1530
virtual QDomElement domElement(const QString &name, QDomDocument &document) const
Returns an XML QDomElement that represents the QGLViewer.
Definition: qglviewer.cpp:3528
void setManipulatedFrame(qglviewer::ManipulatedFrame *frame)
Sets the viewer's manipulatedFrame().
Definition: qglviewer.cpp:3055
virtual void loadProjectionMatrix(bool reset=true) const
Loads the OpenGL GL_PROJECTION matrix with the Camera projection matrix.
Definition: camera.cpp:463
Qt::Key pathKey(int index) const
Returns the keyboard key associated to camera Key Frame path index.
Definition: qglviewer.cpp:2286
void mouseGrabberChanged(qglviewer::MouseGrabber *mouseGrabber)
Signal emitted by setMouseGrabber() when the mouseGrabber() is changed.
void toggleAxisIsDrawn()
Toggles the state of axisIsDrawn().
Definition: qglviewer.h:138
virtual void resizeGL(int width, int height)
Callback method used when the widget size is modified.
Definition: qglviewer.cpp:2199
void setAxisIsDrawn(bool draw=true)
Sets the state of axisIsDrawn().
Definition: qglviewer.h:128
virtual void mouseReleaseEvent(QMouseEvent *const event, Camera *const camera)
Stops the ManipulatedFrame mouse manipulation.
virtual void wheelEvent(QWheelEvent *const event, Camera *const camera)
Overloading of MouseGrabber::wheelEvent().
void toggleGridIsDrawn()
Toggles the state of gridIsDrawn().
Definition: qglviewer.h:140
void setBackgroundColor(const QColor &color)
Sets the backgroundColor() of the viewer and calls qglClearColor().
Definition: qglviewer.h:186
virtual void wheelEvent(QWheelEvent *)
Overloading of the QWidget method.
Definition: qglviewer.cpp:1392
void interpolateToFitScene()
Interpolates the Camera on a one second KeyFrameInterpolator path so that the entire scene fits the s...
Definition: camera.cpp:913
virtual void wheelEvent(QWheelEvent *const event, Camera *const camera)
Callback method called when the MouseGrabber grabsMouse() and the mouse wheel is used.
Definition: mouseGrabber.h:247
virtual void postSelection(const QPoint &point)
This method is called at the end of the select() procedure.
Definition: qglviewer.h:894
virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera)
Modifies the ManipulatedFrame according to the mouse motion.
void projectOnLine(const Vec &origin, const Vec &direction)
Translates the Frame so that its position() lies on the line defined by origin and direction (defined...
Definition: frame.cpp:1133
void setSceneCenter(const Vec &center)
Sets the sceneCenter().
Definition: camera.cpp:733
A versatile 3D OpenGL viewer based on QGLWidget.
Definition: qglviewer.h:62
static void drawGrid(float size=1.0f, int nbSubdivisions=10)
Draws a grid in the XY plane, centered on (0,0,0) (defined in the current coordinate system)...
Definition: qglviewer.cpp:3321
MouseHandler
Defines the different mouse handlers: camera() or manipulatedFrame().
Definition: qglviewer.h:954
float zClippingCoefficient() const
Returns the coefficient used to position the near and far clipping planes.
Definition: camera.h:229
QTabWidget * helpWidget()
Returns a pointer to the help widget.
Definition: qglviewer.h:735
qglviewer::Camera * camera() const
Returns the associated qglviewer::Camera, never NULL.
Definition: qglviewer.h:250
virtual void deletePath(int i)
Deletes the keyFrameInterpolator() of index i.
Definition: camera.cpp:1762
void setShortcut(KeyboardAction action, unsigned int key)
Defines the shortcut() that triggers a given QGLViewer::KeyboardAction.
Definition: qglviewer.cpp:2227
bool FPSIsDisplayed() const
Returns true if the viewer displays the current frame rate (Frames Per Second).
Definition: qglviewer.h:108
void setGridIsDrawn(bool draw=true)
Sets the state of gridIsDrawn().
Definition: qglviewer.h:130
A perspective or orthographic camera.
Definition: camera.h:84
ClickAction
Defines the possible actions that can be binded to a mouse click using setMouseBinding(Qt::KeyboardMo...
Definition: qglviewer.h:960
void toggleTextIsEnabled()
Toggles the state of textIsEnabled().
Definition: qglviewer.h:144
The Quaternion class represents 3D rotations and orientations.
Definition: quaternion.h:66
void setMouseBindingDescription(int state, QString description, bool doubleClick=false, Qt::MouseButtons buttonsBefore=Qt::NoButton)
This method is deprecated since version 2.5.0.
Definition: qglviewer.cpp:1633
static const QList< QGLViewer * > & QGLViewerPool()
Returns a QList that contains pointers to all the created QGLViewers.
Definition: qglviewer.h:1085
void setFPSIsDisplayed(bool display=true)
Sets the state of FPSIsDisplayed().
Definition: qglviewer.h:132
void setPivotPoint(const Vec &point)
Changes the pivotPoint() to point (defined in the world coordinate system).
Definition: camera.cpp:770
void snapshotToClipboard()
Takes a snapshot of the current display and pastes it to the clipboard.
void setMouseBinding(int state, MouseHandler handler, MouseAction action, bool withConstraint=true)
This method is deprecated since version 2.5.0.
Definition: qglviewer.cpp:2511
bool grabsMouse() const
Returns true when the MouseGrabber grabs the QGLViewer's mouse events.
Definition: mouseGrabber.h:179
void getClickButtonState(ClickAction action, int &state, bool &doubleClick, Qt::MouseButtons &buttonsBefore) const
This method is deprecated since version 2.5.0.
Definition: qglviewer.cpp:2932
void centerScene()
Moves the Camera so that its sceneCenter() is projected on the center of the window.
Definition: camera.cpp:997
void setCamera(qglviewer::Camera *const camera)
Associates a new qglviewer::Camera to the viewer.
Definition: qglviewer.cpp:600
virtual void wheelEvent(QWheelEvent *const event, Camera *const camera)
This is an overload of ManipulatedFrame::wheelEvent().
virtual void playPath(int i)
Makes the Camera follow the path of keyFrameInterpolator() number i.
Definition: camera.cpp:1726
virtual void mouseReleaseEvent(QMouseEvent *const event, Camera *const camera)
Mouse release event callback method.
Definition: mouseGrabber.h:237
void drawText(int x, int y, const QString &text, const QFont &fnt=QFont())
Draws text at position x, y (expressed in screen coordinates pixels, origin in the upper left corner ...
Definition: qglviewer.cpp:741
qglviewer::Vec sceneCenter() const
Returns the scene center, defined in world coordinates.
Definition: qglviewer.h:215
void copyBufferToTexture(GLint internalFormat, GLenum format=GL_NONE)
Makes a copy of the current buffer into a texture.
Definition: qglviewer.cpp:3782
virtual void saveStateToFile()
Saves in stateFileName() an XML representation of the QGLViewer state, obtained from domElement()...
Definition: qglviewer.cpp:3397
bool cameraIsEdited() const
Returns true if the camera() is being edited in the viewer.
Definition: qglviewer.h:123
virtual void mousePressEvent(QMouseEvent *const event, Camera *const camera)
Initiates the ManipulatedFrame mouse manipulation.
virtual void mouseDoubleClickEvent(QMouseEvent *)
Overloading of the QWidget method.
Definition: qglviewer.cpp:1458
virtual void stopSpinning()
Stops the spinning motion started using startSpinning().
void pointSelected(const QMouseEvent *e)
Signal emitted by select().
bool isManipulated() const
Returns true when the ManipulatedFrame is being manipulated with the mouse.
virtual void drawVisualHints()
Draws viewer related visual hints.
Definition: qglviewer.cpp:3103
void drawNeeded()
Signal emitted by the default draw() method.
void setSelectedName(int id)
Set the selectedName() value.
Definition: qglviewer.h:859
static void drawArrow(float length=1.0f, float radius=-1.0f, int nbSubdivisions=12)
Draws a 3D arrow along the positive Z axis.
Definition: qglviewer.cpp:3205
virtual void resetVisualHints()
Reset the mask used by drawVisualHints().
Definition: qglviewer.cpp:3186
virtual void closeEvent(QCloseEvent *)
Overloading of the QWidget method.
Definition: qglviewer.cpp:891
void stereoChanged(bool on)
This signal is emitted whenever displaysInStereo() changes value.
virtual void draw()
The core method of the viewer, that draws the scene.
Definition: qglviewer.h:783
void getViewport(GLint viewport[4]) const
Fills viewport with the Camera OpenGL viewport.
Definition: camera.cpp:1502
virtual void setAddKeyFrameKeyboardModifiers(Qt::KeyboardModifiers modifiers)
Sets the addKeyFrameKeyboardModifiers() value.
Definition: qglviewer.cpp:2320
The Frame class represents a coordinate system, defined by a position and an orientation.
Definition: frame.h:121
double normalize()
Normalizes the Vec and returns its original norm.
Definition: vec.h:340
bool mouseGrabberIsEnabled(const qglviewer::MouseGrabber *const mouseGrabber)
Returns true if mouseGrabber is enabled.
Definition: qglviewer.h:301
qglviewer::MouseGrabber * mouseGrabber() const
Returns the current qglviewer::MouseGrabber, or NULL if no qglviewer::MouseGrabber currently grabs mo...
Definition: qglviewer.h:289
void toggleFPSIsDisplayed()
Toggles the state of FPSIsDisplayed().
Definition: qglviewer.h:142
int selectRegionWidth() const
Returns the width (in pixels) of a selection frustum, centered on the mouse cursor, that is used to select objects.
Definition: qglviewer.h:835
virtual void setPlayPathKeyboardModifiers(Qt::KeyboardModifiers modifiers)
Sets the playPathKeyboardModifiers() value.
Definition: qglviewer.cpp:2314
void setSelectBufferSize(int size)
Sets the selectBufferSize().
Definition: qglviewer.cpp:1104
virtual void startAnimation()
Starts the animation loop.
Definition: qglviewer.cpp:874
virtual ~QGLViewer()
Virtual destructor.
Definition: qglviewer.cpp:183
void clearShortcuts()
Clears all the default keyboard shortcuts.
Definition: qglviewer.cpp:2718
void cameraIsEditedChanged(bool edited)
This signal is emitted whenever cameraIsEdited() changes value.
virtual void initFromDOMElement(const QDomElement &element)
Restores the QGLViewer state from a QDomElement created by domElement().
Definition: qglviewer.cpp:3614
void toggleAnimation()
Calls startAnimation() or stopAnimation(), depending on animationIsStarted().
Definition: qglviewer.h:632
virtual void keyPressEvent(QKeyEvent *)
Overloading of the QWidget method.
Definition: qglviewer.cpp:2066
virtual void animate()
Scene animation method.
Definition: qglviewer.h:630
Vec position() const
Returns the position of the Frame, defined in the world coordinate system.
Definition: frame.cpp:537
void setCameraIsEdited(bool edit=true)
Starts (edit = true, default) or stops (edit=false) the edition of the camera().
Definition: qglviewer.cpp:449
static void drawAxis(float length=1.0f)
Draws an XYZ axis, with a given size (default is 1.0).
Definition: qglviewer.cpp:3253
virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera)
Callback method called when the MouseGrabber grabsMouse() and the mouse is moved while a button is pr...
Definition: mouseGrabber.h:243
void interpolateToZoomOnPixel(const QPoint &pixel)
Makes the Camera smoothly zoom on the pointUnderPixel() pixel.
Definition: camera.cpp:875
virtual void initializeGL()
Initializes the QGLViewer OpenGL context and then calls user-defined init().
Definition: qglviewer.cpp:239
int wheelHandler(Qt::Key key, Qt::KeyboardModifiers modifiers) const
Returns the MouseHandler (if any) that receives wheel events when the modifiers and key keyboard keys...
Definition: qglviewer.cpp:2864
virtual void mouseReleaseEvent(QMouseEvent *const event, Camera *const camera)
This is an overload of ManipulatedFrame::mouseReleaseEvent().
virtual void mousePressEvent(QMouseEvent *const event, Camera *const camera)
Callback method called when the MouseGrabber grabsMouse() and a mouse button is pressed.
Definition: mouseGrabber.h:231
virtual void startAction(int ma, bool withConstraint=true)
Protected internal method used to handle mouse events.
int selectBufferSize() const
Returns the selectBuffer() size.
Definition: qglviewer.h:820
virtual void resetPath(int i)
Resets the path of the keyFrameInterpolator() number i.
Definition: camera.cpp:1741
bool animationIsStarted() const
Return true when the animation loop is started.
Definition: qglviewer.h:597
void setSceneRadius(float radius)
Sets the sceneRadius() value.
Definition: camera.cpp:705
bool restoreFromFile(const QString &fileName=QString::null)
This function is deprecated since version 1.3.9-5.
Definition: qglviewer.cpp:3719
virtual QString helpString() const
Returns the QString displayed in the help() window main tab.
Definition: qglviewer.h:713
void setKeyDescription(int key, QString description)
Defines a custom keyboard shortcut description, that will be displayed in the help() window Keyboard ...
Definition: qglviewer.cpp:1823
virtual void postDraw()
Called after draw() to draw viewer visual hints.
Definition: qglviewer.cpp:339
virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera)
Overloading of ManipulatedFrame::mouseMoveEvent().
virtual void preDraw()
Sets OpenGL state before draw().
Definition: qglviewer.cpp:317
void drawFinished(bool automatic)
Signal emitted at the end of the QGLViewer::paintGL() method, when frame is drawn.
static int QGLViewerIndex(const QGLViewer *const viewer)
Returns the index of the QGLViewer viewer in the QGLViewerPool().
Definition: qglviewer.h:1095