qglviewer.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 
3  Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
4 
5  This file is part of the QGLViewer library version 2.6.3.
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 
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(unsigned int state) {
211  // Convertion of keyboard modifiers and mouse buttons as an int is no longer supported : emulate
212  return Qt::KeyboardModifiers(int(state & 0xFF000000));
213 }
214 
215 
216 static Qt::MouseButton mouseButtonFromState(unsigned 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.0f;
390  color[1] = foregroundColor().green() / 255.0f;
391  color[2] = foregroundColor().blue() / 255.0f;
392  color[3] = 1.0f;
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  {
455  // #CONNECTION# 5.0 also used in domElement() and in initFromDOMElement().
457  }
458  else
460 
461  Q_EMIT cameraIsEditedChanged(edit);
462 
463  update();
464 }
465 
466 // Key bindings. 0 means not defined
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
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. Two fingers emulate 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 
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 
618  camera_ = camera;
620 
622 }
623 
625 {
626  for (QMap<unsigned 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, qreal scale) const
657 {
658  static GLUquadric* quadric = gluNewQuadric();
659 
660  const qreal 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(int((x-tileRegion_->xMin) * width() / (tileRegion_->xMax - tileRegion_->xMin)),
748  int((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 
775 {
776  displayMessage_ = false;
777  if (textIsEnabled())
778  update();
779 }
780 
781 
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(int((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(int((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)) {
1199  } else
1200  if (mouseGrabber())
1201  {
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());
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  {
1243  {
1244  manipulatedFrame()->ManipulatedFrame::startAction(map.action, map.withConstraint);
1245  manipulatedFrame()->ManipulatedFrame::mousePressEvent(e, camera());
1246  }
1247  else
1248  {
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())
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()))
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  {
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  {
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  {
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());
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()) {
1436  {
1437  manipulatedFrame()->ManipulatedFrame::startAction(map.action, map.withConstraint);
1438  manipulatedFrame()->ManipulatedFrame::wheelEvent(e, camera());
1439  }
1440  else
1441  {
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))
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 
1536 
1539  (mouseGrabber != camera()->frame()));
1540  Q_EMIT mouseGrabberChanged(mouseGrabber);
1541 }
1542 
1545 {
1546  if (enabled)
1547  disabledMouseGrabbers_.remove(reinterpret_cast<size_t>(mouseGrabber));
1548  else
1549  disabledMouseGrabbers_[reinterpret_cast<size_t>(mouseGrabber)];
1550 }
1551 
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 
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(unsigned int key)
1592 {
1593 # if QT_VERSION >= 0x040100
1594  return QKeySequence(int(key)).toString(QKeySequence::NativeText);
1595 # else
1596  return QString(QKeySequence(key));
1597 # endif
1598 }
1599 
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 
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(unsigned int state, QString description, bool doubleClick, Qt::MouseButtons buttonsBefore) {
1634  qWarning("setMouseBindingDescription(int state,...) is deprecated. Use the modifier/button equivalent");
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(unsigned int key, QString description)
1824 {
1825  if (description.isEmpty())
1826  keyDescription_.remove(key);
1827  else
1828  keyDescription_[key] = description;
1829 }
1830 
1832 {
1833  if (pathIndex_.isEmpty())
1834  return QString::null;
1835 
1836  QVector<Qt::Key> keys;
1837  keys.reserve(pathIndex_.count());
1838  for (QMap<Qt::Key, unsigned int>::ConstIterator i = pathIndex_.begin(), endi=pathIndex_.end(); i != endi; ++i)
1839  keys.push_back(i.key());
1840  qSort(keys);
1841 
1842  QVector<Qt::Key>::const_iterator it = keys.begin(), end = keys.end();
1843  QString res = keyString(*it);
1844 
1845  const int maxDisplayedKeys = 6;
1846  int nbDisplayedKeys = 0;
1847  Qt::Key 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<unsigned int, QString> keyDescription;
1913 
1914  // 1 - User defined key descriptions
1915  for (QMap<unsigned 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<unsigned 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<unsigned 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  unsigned 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  {
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 
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;
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
2257 {
2258  qWarning("setKeyboardAccelerator is deprecated. Use setShortcut instead.");
2259  setShortcut(action, key);
2260 }
2261 
2263 {
2264  qWarning("keyboardAccelerator is deprecated. Use shortcut instead.");
2265  return shortcut(action);
2266 }
2267 #endif
2268 
2270 
2286 Qt::Key QGLViewer::pathKey(unsigned int index) const
2287 {
2288  for (QMap<Qt::Key, unsigned 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, unsigned int index)
2306 {
2307  Qt::Key k = Qt::Key(abs(key));
2308  if (key < 0)
2309  pathIndex_.remove(k);
2310  else
2311  pathIndex_[k] = index;
2312 }
2313 
2315 void QGLViewer::setPlayPathKeyboardModifiers(Qt::KeyboardModifiers modifiers)
2316 {
2317  playPathKeyboardModifiers_ = modifiers;
2318 }
2319 
2321 void QGLViewer::setAddKeyFrameKeyboardModifiers(Qt::KeyboardModifiers modifiers)
2322 {
2323  addKeyFrameKeyboardModifiers_ = modifiers;
2324 }
2325 
2335 Qt::KeyboardModifiers QGLViewer::addKeyFrameKeyboardModifiers() const
2336 {
2338 }
2339 
2348 Qt::KeyboardModifiers QGLViewer::playPathKeyboardModifiers() const
2349 {
2351 }
2352 
2353 #ifndef DOXYGEN
2354 // Deprecated methods
2355 Qt::KeyboardModifiers QGLViewer::addKeyFrameStateKey() const
2356 {
2357  qWarning("addKeyFrameStateKey has been renamed addKeyFrameKeyboardModifiers");
2358  return addKeyFrameKeyboardModifiers(); }
2359 
2360 Qt::KeyboardModifiers QGLViewer::playPathStateKey() const
2361 {
2362  qWarning("playPathStateKey has been renamed playPathKeyboardModifiers");
2363  return playPathKeyboardModifiers();
2364 }
2365 
2366 void QGLViewer::setAddKeyFrameStateKey(unsigned int buttonState)
2367 {
2368  qWarning("setAddKeyFrameStateKey has been renamed setAddKeyFrameKeyboardModifiers");
2370 }
2371 
2372 void QGLViewer::setPlayPathStateKey(unsigned int buttonState)
2373 {
2374  qWarning("setPlayPathStateKey has been renamed setPlayPathKeyboardModifiers");
2376 }
2377 
2378 Qt::Key QGLViewer::keyFrameKey(unsigned int index) const
2379 {
2380  qWarning("keyFrameKey has been renamed pathKey.");
2381  return pathKey(index);
2382 }
2383 
2384 Qt::KeyboardModifiers QGLViewer::playKeyFramePathStateKey() const
2385 {
2386  qWarning("playKeyFramePathStateKey has been renamed playPathKeyboardModifiers.");
2387  return playPathKeyboardModifiers();
2388 }
2389 
2390 void QGLViewer::setKeyFrameKey(unsigned int index, int key)
2391 {
2392  qWarning("setKeyFrameKey is deprecated, use setPathKey instead, with swapped parameters.");
2393  setPathKey(key, index);
2394 }
2395 
2396 void QGLViewer::setPlayKeyFramePathStateKey(unsigned int buttonState)
2397 {
2398  qWarning("setPlayKeyFramePathStateKey has been renamed setPlayPathKeyboardModifiers.");
2400 }
2401 #endif
2402 
2404 // M o u s e b e h a v i o r s t a t e k e y s //
2406 #ifndef DOXYGEN
2407 
2445 void QGLViewer::setHandlerKeyboardModifiers(MouseHandler handler, Qt::KeyboardModifiers modifiers)
2446 {
2447  qWarning("setHandlerKeyboardModifiers is deprecated, call setMouseBinding() instead");
2448 
2449  QMap<MouseBindingPrivate, MouseActionPrivate> newMouseBinding;
2450  QMap<WheelBindingPrivate, MouseActionPrivate> newWheelBinding;
2451  QMap<ClickBindingPrivate, ClickAction> newClickBinding_;
2452 
2453  QMap<MouseBindingPrivate, MouseActionPrivate>::Iterator mit;
2454  QMap<WheelBindingPrivate, MouseActionPrivate>::Iterator wit;
2455 
2456  // First copy unchanged bindings.
2457  for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit)
2458  if ((mit.value().handler != handler) || (mit.value().action == ZOOM_ON_REGION))
2459  newMouseBinding[mit.key()] = mit.value();
2460 
2461  for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit)
2462  if (wit.value().handler != handler)
2463  newWheelBinding[wit.key()] = wit.value();
2464 
2465  // Then, add modified bindings, that can overwrite the previous ones.
2466  for (mit = mouseBinding_.begin(); mit != mouseBinding_.end(); ++mit)
2467  if ((mit.value().handler == handler) && (mit.value().action != ZOOM_ON_REGION))
2468  {
2469  MouseBindingPrivate mbp(modifiers, mit.key().button, mit.key().key);
2470  newMouseBinding[mbp] = mit.value();
2471  }
2472 
2473  for (wit = wheelBinding_.begin(); wit != wheelBinding_.end(); ++wit)
2474  if (wit.value().handler == handler)
2475  {
2476  WheelBindingPrivate wbp(modifiers, wit.key().key);
2477  newWheelBinding[wbp] = wit.value();
2478  }
2479 
2480  // Same for button bindings
2481  for (QMap<ClickBindingPrivate, ClickAction>::ConstIterator cb=clickBinding_.begin(), end=clickBinding_.end(); cb != end; ++cb)
2482  if (((handler==CAMERA) && ((cb.value() == CENTER_SCENE) || (cb.value() == ALIGN_CAMERA))) ||
2483  ((handler==FRAME) && ((cb.value() == CENTER_FRAME) || (cb.value() == ALIGN_FRAME))))
2484  {
2485  ClickBindingPrivate cbp(modifiers, cb.key().button, cb.key().doubleClick, cb.key().buttonsBefore, cb.key().key);
2486  newClickBinding_[cbp] = cb.value();
2487  }
2488  else
2489  newClickBinding_[cb.key()] = cb.value();
2490 
2491  mouseBinding_ = newMouseBinding;
2492  wheelBinding_ = newWheelBinding;
2493  clickBinding_ = newClickBinding_;
2494 }
2495 
2496 void QGLViewer::setHandlerStateKey(MouseHandler handler, unsigned int buttonState)
2497 {
2498  qWarning("setHandlerStateKey has been renamed setHandlerKeyboardModifiers");
2500 }
2501 
2502 void QGLViewer::setMouseStateKey(MouseHandler handler, unsigned int buttonState)
2503 {
2504  qWarning("setMouseStateKey has been renamed setHandlerKeyboardModifiers.");
2506 }
2507 
2512 void QGLViewer::setMouseBinding(unsigned int state, MouseHandler handler, MouseAction action, bool withConstraint)
2513 {
2514  qWarning("setMouseBinding(int state, MouseHandler...) is deprecated. Use the modifier/button equivalent");
2516  mouseButtonFromState(state),
2517  handler,
2518  action,
2519  withConstraint);
2520 }
2521 #endif
2522 
2527 void QGLViewer::setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, MouseHandler handler, MouseAction action, bool withConstraint) {
2528  setMouseBinding(Qt::Key(0), modifiers, button, handler, action, withConstraint);
2529 }
2530 
2563 void QGLViewer::setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, MouseHandler handler, MouseAction action, bool withConstraint)
2564 {
2565  if ((handler == FRAME) && ((action == MOVE_FORWARD) || (action == MOVE_BACKWARD) ||
2566  (action == ROLL) || (action == LOOK_AROUND) ||
2567  (action == ZOOM_ON_REGION))) {
2568  qWarning("Cannot bind %s to FRAME", mouseActionString(action).toLatin1().constData());
2569  return;
2570  }
2571 
2572  if (button == Qt::NoButton) {
2573  qWarning("No mouse button specified in setMouseBinding");
2574  return;
2575  }
2576 
2577  MouseActionPrivate map;
2578  map.handler = handler;
2579  map.action = action;
2580  map.withConstraint = withConstraint;
2581 
2582  MouseBindingPrivate mbp(modifiers, button, key);
2583  if (action == NO_MOUSE_ACTION)
2584  mouseBinding_.remove(mbp);
2585  else
2586  mouseBinding_.insert(mbp, map);
2587 
2588  ClickBindingPrivate cbp(modifiers, button, false, Qt::NoButton, key);
2589  clickBinding_.remove(cbp);
2590 }
2591 
2592 #ifndef DOXYGEN
2593 
2597 void QGLViewer::setMouseBinding(unsigned int state, ClickAction action, bool doubleClick, Qt::MouseButtons buttonsBefore) {
2598  qWarning("setMouseBinding(int state, ClickAction...) is deprecated. Use the modifier/button equivalent");
2600  mouseButtonFromState(state),
2601  action,
2602  doubleClick,
2603  buttonsBefore);
2604 }
2605 #endif
2606 
2611 void QGLViewer::setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton button, ClickAction action, bool doubleClick, Qt::MouseButtons buttonsBefore)
2612 {
2613  setMouseBinding(Qt::Key(0), modifiers, button, action, doubleClick, buttonsBefore);
2614 }
2615 
2636 void QGLViewer::setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button, ClickAction action, bool doubleClick, Qt::MouseButtons buttonsBefore)
2637 {
2638  if ((buttonsBefore != Qt::NoButton) && !doubleClick) {
2639  qWarning("Buttons before is only meaningful when doubleClick is true in setMouseBinding().");
2640  return;
2641  }
2642 
2643  if (button == Qt::NoButton) {
2644  qWarning("No mouse button specified in setMouseBinding");
2645  return;
2646  }
2647 
2648  ClickBindingPrivate cbp(modifiers, button, doubleClick, buttonsBefore, key);
2649 
2650  // #CONNECTION performClickAction comment on NO_CLICK_ACTION
2651  if (action == NO_CLICK_ACTION)
2652  clickBinding_.remove(cbp);
2653  else
2654  clickBinding_.insert(cbp, action);
2655 
2656  if ((!doubleClick) && (buttonsBefore == Qt::NoButton)) {
2657  MouseBindingPrivate mbp(modifiers, button, key);
2658  mouseBinding_.remove(mbp);
2659  }
2660 }
2661 
2666 void QGLViewer::setWheelBinding(Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint) {
2667  setWheelBinding(Qt::Key(0), modifiers, handler, action, withConstraint);
2668 }
2669 
2680 void QGLViewer::setWheelBinding(Qt::Key key, Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint)
2681 {
2682  //#CONNECTION# ManipulatedFrame::wheelEvent and ManipulatedCameraFrame::wheelEvent switches
2683  if ((action != ZOOM) && (action != MOVE_FORWARD) && (action != MOVE_BACKWARD) && (action != NO_MOUSE_ACTION)) {
2684  qWarning("Cannot bind %s to wheel", mouseActionString(action).toLatin1().constData());
2685  return;
2686  }
2687 
2688  if ((handler == FRAME) && (action != ZOOM) && (action != NO_MOUSE_ACTION)) {
2689  qWarning("Cannot bind %s to FRAME wheel", mouseActionString(action).toLatin1().constData());
2690  return;
2691  }
2692 
2693  MouseActionPrivate map;
2694  map.handler = handler;
2695  map.action = action;
2696  map.withConstraint = withConstraint;
2697 
2698  WheelBindingPrivate wbp(modifiers, key);
2699  if (action == NO_MOUSE_ACTION)
2700  wheelBinding_.remove(wbp);
2701  else
2702  wheelBinding_[wbp] = map;
2703 }
2704 
2710  mouseBinding_.clear();
2711  clickBinding_.clear();
2712  wheelBinding_.clear();
2713 }
2714 
2720  keyboardBinding_.clear();
2721  pathIndex_.clear();
2722 }
2723 
2729  qWarning("mouseAction(int state,...) is deprecated. Use the modifier/button equivalent");
2730  return mouseAction(Qt::Key(0), keyboardModifiersFromState(state), mouseButtonFromState(state));
2731 }
2732 
2747 QGLViewer::MouseAction QGLViewer::mouseAction(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button) const
2748 {
2749  MouseBindingPrivate mbp(modifiers, button, key);
2750  if (mouseBinding_.contains(mbp))
2751  return mouseBinding_[mbp].action;
2752  else
2753  return NO_MOUSE_ACTION;
2754 }
2755 
2760 int QGLViewer::mouseHandler(unsigned int state) const {
2761  qWarning("mouseHandler(int state,...) is deprecated. Use the modifier/button equivalent");
2762  return mouseHandler(Qt::Key(0), keyboardModifiersFromState(state), mouseButtonFromState(state));
2763 }
2764 
2777 int QGLViewer::mouseHandler(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button) const
2778 {
2779  MouseBindingPrivate mbp(modifiers, button, key);
2780  if (mouseBinding_.contains(mbp))
2781  return mouseBinding_[mbp].handler;
2782  else
2783  return -1;
2784 }
2785 
2786 
2787 #ifndef DOXYGEN
2788 
2792 int QGLViewer::mouseButtonState(MouseHandler handler, MouseAction action, bool withConstraint) const {
2793  qWarning("mouseButtonState() is deprecated. Use mouseButtons() and keyboardModifiers() instead");
2794  for (QMap<MouseBindingPrivate, MouseActionPrivate>::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it != end; ++it)
2795  if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) )
2796  return (int) it.key().modifiers | (int) it.key().button;
2797 
2798  return Qt::NoButton;
2799 }
2800 #endif
2801 
2809 void QGLViewer::getWheelActionBinding(MouseHandler handler, MouseAction action, bool withConstraint,
2810  Qt::Key& key, Qt::KeyboardModifiers& modifiers) const
2811 {
2812  for (QMap<WheelBindingPrivate, MouseActionPrivate>::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it != end; ++it)
2813  if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) ) {
2814  key = it.key().key;
2815  modifiers = it.key().modifiers;
2816  return;
2817  }
2818 
2819  key = Qt::Key(-1);
2820  modifiers = Qt::NoModifier;
2821 }
2822 
2830 void QGLViewer::getMouseActionBinding(MouseHandler handler, MouseAction action, bool withConstraint,
2831  Qt::Key& key, Qt::KeyboardModifiers& modifiers, Qt::MouseButton& button) const
2832 {
2833  for (QMap<MouseBindingPrivate, MouseActionPrivate>::ConstIterator it=mouseBinding_.begin(), end=mouseBinding_.end(); it != end; ++it) {
2834  if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) ) {
2835  key = it.key().key;
2836  modifiers = it.key().modifiers;
2837  button = it.key().button;
2838  return;
2839  }
2840  }
2841 
2842  key = Qt::Key(0);
2843  modifiers = Qt::NoModifier;
2844  button = Qt::NoButton;
2845 }
2846 
2853 QGLViewer::MouseAction QGLViewer::wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) const
2854 {
2855  WheelBindingPrivate wbp(modifiers, key);
2856  if (wheelBinding_.contains(wbp))
2857  return wheelBinding_[wbp].action;
2858  else
2859  return NO_MOUSE_ACTION;
2860 }
2861 
2866 int QGLViewer::wheelHandler(Qt::Key key, Qt::KeyboardModifiers modifiers) const
2867 {
2868  WheelBindingPrivate wbp(modifiers, key);
2869  if (wheelBinding_.contains(wbp))
2870  return wheelBinding_[wbp].handler;
2871  else
2872  return -1;
2873 }
2874 
2878 QGLViewer::ClickAction QGLViewer::clickAction(Qt::Key key, Qt::KeyboardModifiers modifiers, Qt::MouseButton button,
2879  bool doubleClick, Qt::MouseButtons buttonsBefore) const {
2880  ClickBindingPrivate cbp(modifiers, button, doubleClick, buttonsBefore, key);
2881  if (clickBinding_.contains(cbp))
2882  return clickBinding_[cbp];
2883  else
2884  return NO_CLICK_ACTION;
2885 }
2886 
2887 #ifndef DOXYGEN
2888 
2891 QGLViewer::MouseAction QGLViewer::wheelAction(Qt::KeyboardModifiers modifiers) const {
2892  qWarning("wheelAction() is deprecated. Use the new wheelAction() method with a key parameter instead");
2893  return wheelAction(Qt::Key(0), modifiers);
2894 }
2895 
2899 int QGLViewer::wheelHandler(Qt::KeyboardModifiers modifiers) const {
2900  qWarning("wheelHandler() is deprecated. Use the new wheelHandler() method with a key parameter instead");
2901  return wheelHandler(Qt::Key(0), modifiers);
2902 }
2903 
2907 unsigned int QGLViewer::wheelButtonState(MouseHandler handler, MouseAction action, bool withConstraint) const
2908 {
2909  qWarning("wheelButtonState() is deprecated. Use the wheelAction() and wheelHandler() instead");
2910  for (QMap<WheelBindingPrivate, MouseActionPrivate>::ConstIterator it=wheelBinding_.begin(), end=wheelBinding_.end(); it!=end; ++it)
2911  if ( (it.value().handler == handler) && (it.value().action == action) && (it.value().withConstraint == withConstraint) )
2912  return it.key().key + it.key().modifiers;
2913 
2914  return -1;
2915 }
2916 
2921 QGLViewer::ClickAction QGLViewer::clickAction(unsigned int state, bool doubleClick, Qt::MouseButtons buttonsBefore) const {
2922  qWarning("clickAction(int state,...) is deprecated. Use the modifier/button equivalent");
2923  return clickAction(Qt::Key(0),
2925  mouseButtonFromState(state),
2926  doubleClick,
2927  buttonsBefore);
2928 }
2929 
2934 void QGLViewer::getClickButtonState(ClickAction action, unsigned int& state, bool& doubleClick, Qt::MouseButtons& buttonsBefore) const {
2935  qWarning("getClickButtonState(int state,...) is deprecated. Use the modifier/button equivalent");
2936  Qt::KeyboardModifiers modifiers;
2937  Qt::MouseButton button;
2938  Qt::Key key;
2939  getClickActionBinding(action, key, modifiers, button, doubleClick, buttonsBefore);
2940  state = (unsigned int) modifiers | (unsigned int) button | (unsigned int) key;
2941 }
2942 #endif
2943 
2951 void QGLViewer::getClickActionBinding(ClickAction action, Qt::Key& key, Qt::KeyboardModifiers& modifiers, Qt::MouseButton &button, bool& doubleClick, Qt::MouseButtons& buttonsBefore) const
2952 {
2953  for (QMap<ClickBindingPrivate, ClickAction>::ConstIterator it=clickBinding_.begin(), end=clickBinding_.end(); it != end; ++it)
2954  if (it.value() == action) {
2955  modifiers = it.key().modifiers;
2956  button = it.key().button;
2957  doubleClick = it.key().doubleClick;
2958  buttonsBefore = it.key().buttonsBefore;
2959  key = it.key().key;
2960  return;
2961  }
2962 
2963  modifiers = Qt::NoModifier;
2964  button = Qt::NoButton;
2965  doubleClick = false;
2966  buttonsBefore = Qt::NoButton;
2967  key = Qt::Key(0);
2968 }
2969 
2974 {
2975  //#CONNECTION# used in toggleCameraMode() and keyboardString()
2976  Qt::Key key;
2977  Qt::KeyboardModifiers modifiers;
2978  Qt::MouseButton button;
2979  getMouseActionBinding(CAMERA, ROTATE, true /*constraint*/, key, modifiers, button);
2980  return button != Qt::NoButton;
2981 }
2982 
2996 {
2997  Qt::Key key;
2998  Qt::KeyboardModifiers modifiers;
2999  Qt::MouseButton button;
3000  getMouseActionBinding(CAMERA, ROTATE, true /*constraint*/, key, modifiers, button);
3001  bool rotateMode = button != Qt::NoButton;
3002 
3003  if (!rotateMode) {
3004  getMouseActionBinding(CAMERA, MOVE_FORWARD, true /*constraint*/, key, modifiers, button);
3005  }
3006 
3007  //#CONNECTION# setDefaultMouseBindings()
3008  if (rotateMode)
3009  {
3011  camera()->frame()->stopSpinning();
3012 
3013  setMouseBinding(modifiers, Qt::LeftButton, CAMERA, MOVE_FORWARD);
3014  setMouseBinding(modifiers, Qt::MidButton, CAMERA, LOOK_AROUND);
3015  setMouseBinding(modifiers, Qt::RightButton, CAMERA, MOVE_BACKWARD);
3016 
3017  setMouseBinding(Qt::Key_R, modifiers, Qt::LeftButton, CAMERA, ROLL);
3018 
3019  setMouseBinding(Qt::NoModifier, Qt::LeftButton, NO_CLICK_ACTION, true);
3020  setMouseBinding(Qt::NoModifier, Qt::MidButton, NO_CLICK_ACTION, true);
3021  setMouseBinding(Qt::NoModifier, Qt::RightButton, NO_CLICK_ACTION, true);
3022 
3023  setWheelBinding(modifiers, CAMERA, MOVE_FORWARD);
3024  }
3025  else
3026  {
3027  // Should stop flyTimer. But unlikely and not easy.
3028  setMouseBinding(modifiers, Qt::LeftButton, CAMERA, ROTATE);
3029  setMouseBinding(modifiers, Qt::MidButton, CAMERA, ZOOM);
3030  setMouseBinding(modifiers, Qt::RightButton, CAMERA, TRANSLATE);
3031 
3032  setMouseBinding(Qt::Key_R, modifiers, Qt::LeftButton, CAMERA, SCREEN_ROTATE);
3033 
3034  setMouseBinding(Qt::NoModifier, Qt::LeftButton, ALIGN_CAMERA, true);
3035  setMouseBinding(Qt::NoModifier, Qt::MidButton, SHOW_ENTIRE_SCENE, true);
3036  setMouseBinding(Qt::NoModifier, Qt::RightButton, CENTER_SCENE, true);
3037 
3038  setWheelBinding(modifiers, CAMERA, ZOOM);
3039  }
3040 }
3041 
3043 // M a n i p u l a t e d f r a m e s //
3045 
3058 {
3059  if (manipulatedFrame())
3060  {
3062 
3063  if (manipulatedFrame() != camera()->frame())
3064  {
3065  disconnect(manipulatedFrame(), SIGNAL(manipulated()), this, SLOT(update()));
3066  disconnect(manipulatedFrame(), SIGNAL(spun()), this, SLOT(update()));
3067  }
3068  }
3069 
3070  manipulatedFrame_ = frame;
3071 
3073  (dynamic_cast<ManipulatedCameraFrame*>(manipulatedFrame()) != NULL));
3074 
3075  if (manipulatedFrame())
3076  {
3077  // Prevent multiple connections, that would result in useless display updates
3078  if (manipulatedFrame() != camera()->frame())
3079  {
3080  connect(manipulatedFrame(), SIGNAL(manipulated()), SLOT(update()));
3081  connect(manipulatedFrame(), SIGNAL(spun()), SLOT(update()));
3082  }
3083  }
3084 }
3085 
3086 #ifndef DOXYGEN
3087 // V i s u a l H i n t s //
3090 
3106 {
3107  // Pivot point cross
3108  if (visualHint_ & 1)
3109  {
3110  const qreal size = 15.0;
3111  Vec proj = camera()->projectedCoordinatesOf(camera()->pivotPoint());
3113  glDisable(GL_LIGHTING);
3114  glDisable(GL_DEPTH_TEST);
3115  glLineWidth(3.0);
3116  glBegin(GL_LINES);
3117  glVertex2d(proj.x - size, proj.y);
3118  glVertex2d(proj.x + size, proj.y);
3119  glVertex2d(proj.x, proj.y - size);
3120  glVertex2d(proj.x, proj.y + size);
3121  glEnd();
3122  glEnable(GL_DEPTH_TEST);
3124  }
3125 
3126  // if (visualHint_ & 2)
3127  // drawText(80, 10, "Play");
3128 
3129  // Screen rotate line
3130  ManipulatedFrame* mf = NULL;
3131  Vec pnt;
3132  if (camera()->frame()->action_ == SCREEN_ROTATE)
3133  {
3134  mf = camera()->frame();
3135  pnt = camera()->pivotPoint();
3136  }
3137  if (manipulatedFrame() && (manipulatedFrame()->action_ == SCREEN_ROTATE))
3138  {
3139  mf = manipulatedFrame();
3140  // Maybe useful if the mf is a manipCameraFrame...
3141  // pnt = manipulatedFrame()->pivotPoint();
3142  pnt = manipulatedFrame()->position();
3143  }
3144 
3145  if (mf)
3146  {
3147  pnt = camera()->projectedCoordinatesOf(pnt);
3149  glDisable(GL_LIGHTING);
3150  glDisable(GL_DEPTH_TEST);
3151  glLineWidth(3.0);
3152  glBegin(GL_LINES);
3153  glVertex2d(pnt.x, pnt.y);
3154  glVertex2i(mf->prevPos_.x(), mf->prevPos_.y());
3155  glEnd();
3156  glEnable(GL_DEPTH_TEST);
3158  }
3159 
3160  // Zoom on region: draw a rectangle
3161  if (camera()->frame()->action_ == ZOOM_ON_REGION)
3162  {
3164  glDisable(GL_LIGHTING);
3165  glDisable(GL_DEPTH_TEST);
3166  glLineWidth(2.0);
3167  glBegin(GL_LINE_LOOP);
3168  glVertex2i(camera()->frame()->pressPos_.x(), camera()->frame()->pressPos_.y());
3169  glVertex2i(camera()->frame()->prevPos_.x(), camera()->frame()->pressPos_.y());
3170  glVertex2i(camera()->frame()->prevPos_.x(), camera()->frame()->prevPos_.y());
3171  glVertex2i(camera()->frame()->pressPos_.x(), camera()->frame()->prevPos_.y());
3172  glEnd();
3173  glEnable(GL_DEPTH_TEST);
3175  }
3176 }
3177 
3181 void QGLViewer::setVisualHintsMask(int mask, int delay)
3182 {
3183  visualHint_ = visualHint_ | mask;
3184  QTimer::singleShot(delay, this, SLOT(resetVisualHints()));
3185 }
3186 
3189 {
3190  visualHint_ = 0;
3191 }
3192 #endif
3193 
3195 // A x i s a n d G r i d d i s p l a y l i s t s //
3197 
3207 void QGLViewer::drawArrow(qreal length, qreal radius, int nbSubdivisions)
3208 {
3209  static GLUquadric* quadric = gluNewQuadric();
3210 
3211  if (radius < 0.0)
3212  radius = 0.05 * length;
3213 
3214  const qreal head = 2.5*(radius / length) + 0.1;
3215  const qreal coneRadiusCoef = 4.0 - 5.0 * head;
3216 
3217  gluCylinder(quadric, radius, radius, length * (1.0 - head/coneRadiusCoef), nbSubdivisions, 1);
3218  glTranslated(0.0, 0.0, length * (1.0 - head));
3219  gluCylinder(quadric, coneRadiusCoef * radius, 0.0, head * length, nbSubdivisions, 1);
3220  glTranslated(0.0, 0.0, -length * (1.0 - head));
3221 }
3222 
3227 void QGLViewer::drawArrow(const Vec& from, const Vec& to, qreal radius, int nbSubdivisions)
3228 {
3229  glPushMatrix();
3230  glTranslated(from[0], from[1], from[2]);
3231  const Vec dir = to-from;
3232  glMultMatrixd(Quaternion(Vec(0,0,1), dir).matrix());
3233  QGLViewer::drawArrow(dir.norm(), radius, nbSubdivisions);
3234  glPopMatrix();
3235 }
3236 
3255 void QGLViewer::drawAxis(qreal length)
3256 {
3257  const qreal charWidth = length / 40.0;
3258  const qreal charHeight = length / 30.0;
3259  const qreal charShift = 1.04 * length;
3260 
3261  GLboolean lighting, colorMaterial;
3262  glGetBooleanv(GL_LIGHTING, &lighting);
3263  glGetBooleanv(GL_COLOR_MATERIAL, &colorMaterial);
3264 
3265  glDisable(GL_LIGHTING);
3266 
3267  glBegin(GL_LINES);
3268  // The X
3269  glVertex3d(charShift, charWidth, -charHeight);
3270  glVertex3d(charShift, -charWidth, charHeight);
3271  glVertex3d(charShift, -charWidth, -charHeight);
3272  glVertex3d(charShift, charWidth, charHeight);
3273  // The Y
3274  glVertex3d( charWidth, charShift, charHeight);
3275  glVertex3d(0.0, charShift, 0.0);
3276  glVertex3d(-charWidth, charShift, charHeight);
3277  glVertex3d(0.0, charShift, 0.0);
3278  glVertex3d(0.0, charShift, 0.0);
3279  glVertex3d(0.0, charShift, -charHeight);
3280  // The Z
3281  glVertex3d(-charWidth, charHeight, charShift);
3282  glVertex3d( charWidth, charHeight, charShift);
3283  glVertex3d( charWidth, charHeight, charShift);
3284  glVertex3d(-charWidth, -charHeight, charShift);
3285  glVertex3d(-charWidth, -charHeight, charShift);
3286  glVertex3d( charWidth, -charHeight, charShift);
3287  glEnd();
3288 
3289  glEnable(GL_LIGHTING);
3290  glDisable(GL_COLOR_MATERIAL);
3291 
3292  float color[4];
3293  color[0] = 0.7f; color[1] = 0.7f; color[2] = 1.0f; color[3] = 1.0f;
3294  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
3295  QGLViewer::drawArrow(length, 0.01*length);
3296 
3297  color[0] = 1.0f; color[1] = 0.7f; color[2] = 0.7f; color[3] = 1.0f;
3298  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
3299  glPushMatrix();
3300  glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
3301  QGLViewer::drawArrow(length, 0.01*length);
3302  glPopMatrix();
3303 
3304  color[0] = 0.7f; color[1] = 1.0f; color[2] = 0.7f; color[3] = 1.0f;
3305  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
3306  glPushMatrix();
3307  glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
3308  QGLViewer::drawArrow(length, 0.01*length);
3309  glPopMatrix();
3310 
3311  if (colorMaterial)
3312  glEnable(GL_COLOR_MATERIAL);
3313  if (!lighting)
3314  glDisable(GL_LIGHTING);
3315 }
3316 
3323 void QGLViewer::drawGrid(qreal size, int nbSubdivisions)
3324 {
3325  GLboolean lighting;
3326  glGetBooleanv(GL_LIGHTING, &lighting);
3327 
3328  glDisable(GL_LIGHTING);
3329 
3330  glBegin(GL_LINES);
3331  for (int i=0; i<=nbSubdivisions; ++i)
3332  {
3333  const qreal pos = size*(2.0*i/nbSubdivisions-1.0);
3334  glVertex2d(pos, -size);
3335  glVertex2d(pos, +size);
3336  glVertex2d(-size, pos);
3337  glVertex2d( size, pos);
3338  }
3339  glEnd();
3340 
3341  if (lighting)
3342  glEnable(GL_LIGHTING);
3343 }
3344 
3346 // 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 //
3348 
3351 {
3352  Q_FOREACH (QGLViewer* viewer, QGLViewer::QGLViewerPool())
3353  {
3354  if (viewer)
3355  viewer->saveStateToFile();
3356  }
3357 }
3358 
3360 // S a v e s t a t e b e t w e e n s e s s i o n s //
3362 
3377 {
3378  QString name = stateFileName_;
3379 
3380  if (!name.isEmpty() && QGLViewer::QGLViewerIndex(this) > 0)
3381  {
3382  QFileInfo fi(name);
3383  if (fi.suffix().isEmpty())
3384  name += QString::number(QGLViewer::QGLViewerIndex(this));
3385  else
3386  name = fi.absolutePath() + '/' + fi.completeBaseName() + QString::number(QGLViewer::QGLViewerIndex(this)) + "." + fi.suffix();
3387  }
3388 
3389  return name;
3390 }
3391 
3400 {
3401  QString name = stateFileName();
3402 
3403  if (name.isEmpty())
3404  return;
3405 
3406  QFileInfo fileInfo(name);
3407 
3408  if (fileInfo.isDir())
3409  {
3410  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));
3411  return;
3412  }
3413 
3414  const QString dirName = fileInfo.absolutePath();
3415  if (!QFileInfo(dirName).exists())
3416  {
3417  QDir dir;
3418  if (!(dir.mkdir(dirName)))
3419  {
3420  QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to create directory %1").arg(dirName));
3421  return;
3422  }
3423  }
3424 
3425  // Write the DOM tree to file
3426  QFile f(name);
3427  if (f.open(QIODevice::WriteOnly))
3428  {
3429  QTextStream out(&f);
3430  QDomDocument doc("QGLVIEWER");
3431  doc.appendChild(domElement("QGLViewer", doc));
3432  doc.save(out, 2);
3433  f.flush();
3434  f.close();
3435  }
3436  else
3437  QMessageBox::warning(this, tr("Save to file error", "Message box window title"), tr("Unable to save to file %1").arg(name) + ":\n" + f.errorString());
3438 }
3439 
3461 {
3462  QString name = stateFileName();
3463 
3464  if (name.isEmpty())
3465  return false;
3466 
3467  QFileInfo fileInfo(name);
3468 
3469  if (!fileInfo.isFile())
3470  // No warning since it would be displayed at first start.
3471  return false;
3472 
3473  if (!fileInfo.isReadable())
3474  {
3475  QMessageBox::warning(this, tr("Problem in state restoration", "Message box window title"), tr("File %1 is not readable.").arg(name));
3476  return false;
3477  }
3478 
3479  // Read the DOM tree form file
3480  QFile f(name);
3481  if (f.open(QIODevice::ReadOnly))
3482  {
3483  QDomDocument doc;
3484  doc.setContent(&f);
3485  f.close();
3486  QDomElement main = doc.documentElement();
3487  initFromDOMElement(main);
3488  }
3489  else
3490  {
3491  QMessageBox::warning(this, tr("Open file error", "Message box window title"), tr("Unable to open file %1").arg(name) + ":\n" + f.errorString());
3492  return false;
3493  }
3494 
3495  return true;
3496 }
3497 
3530 QDomElement QGLViewer::domElement(const QString& name, QDomDocument& document) const
3531 {
3532  QDomElement de = document.createElement(name);
3533  de.setAttribute("version", QGLViewerVersionString());
3534 
3535  QDomElement stateNode = document.createElement("State");
3536  // hasMouseTracking() is not saved
3537  stateNode.appendChild(DomUtils::QColorDomElement(foregroundColor(), "foregroundColor", document));
3538  stateNode.appendChild(DomUtils::QColorDomElement(backgroundColor(), "backgroundColor", document));
3539  DomUtils::setBoolAttribute(stateNode, "stereo", displaysInStereo());
3540  // Revolve or fly camera mode is not saved
3541  de.appendChild(stateNode);
3542 
3543  QDomElement displayNode = document.createElement("Display");
3544  DomUtils::setBoolAttribute(displayNode, "axisIsDrawn", axisIsDrawn());
3545  DomUtils::setBoolAttribute(displayNode, "gridIsDrawn", gridIsDrawn());
3546  DomUtils::setBoolAttribute(displayNode, "FPSIsDisplayed", FPSIsDisplayed());
3547  DomUtils::setBoolAttribute(displayNode, "cameraIsEdited", cameraIsEdited());
3548  // textIsEnabled() is not saved
3549  de.appendChild(displayNode);
3550 
3551  QDomElement geometryNode = document.createElement("Geometry");
3552  DomUtils::setBoolAttribute(geometryNode, "fullScreen", isFullScreen());
3553  if (isFullScreen())
3554  {
3555  geometryNode.setAttribute("prevPosX", QString::number(prevPos_.x()));
3556  geometryNode.setAttribute("prevPosY", QString::number(prevPos_.y()));
3557  }
3558  else
3559  {
3560  QWidget* tlw = topLevelWidget();
3561  geometryNode.setAttribute("width", QString::number(tlw->width()));
3562  geometryNode.setAttribute("height", QString::number(tlw->height()));
3563  geometryNode.setAttribute("posX", QString::number(tlw->pos().x()));
3564  geometryNode.setAttribute("posY", QString::number(tlw->pos().y()));
3565  }
3566  de.appendChild(geometryNode);
3567 
3568  // Restore original Camera zClippingCoefficient before saving.
3569  if (cameraIsEdited())
3571  de.appendChild(camera()->domElement("Camera", document));
3572  if (cameraIsEdited())
3573  // #CONNECTION# 5.0 from setCameraIsEdited()
3575 
3576  if (manipulatedFrame())
3577  de.appendChild(manipulatedFrame()->domElement("ManipulatedFrame", document));
3578 
3579  return de;
3580 }
3581 
3616 void QGLViewer::initFromDOMElement(const QDomElement& element)
3617 {
3618  const QString version = element.attribute("version");
3619  // if (version != QGLViewerVersionString())
3620  if (version[0] != '2')
3621  // Patches for previous versions should go here when the state file syntax is modified.
3622  qWarning("State file created using QGLViewer version %s may not be correctly read.", version.toLatin1().constData());
3623 
3624  QDomElement child=element.firstChild().toElement();
3625  bool tmpCameraIsEdited = cameraIsEdited();
3626  while (!child.isNull())
3627  {
3628  if (child.tagName() == "State")
3629  {
3630  // #CONNECTION# default values from defaultConstructor()
3631  // setMouseTracking(DomUtils::boolFromDom(child, "mouseTracking", false));
3632  setStereoDisplay(DomUtils::boolFromDom(child, "stereo", false));
3633  //if ((child.attribute("cameraMode", "revolve") == "fly") && (cameraIsInRevolveMode()))
3634  // toggleCameraMode();
3635 
3636  QDomElement ch=child.firstChild().toElement();
3637  while (!ch.isNull())
3638  {
3639  if (ch.tagName() == "foregroundColor")
3641  if (ch.tagName() == "backgroundColor")
3643  ch = ch.nextSibling().toElement();
3644  }
3645  }
3646 
3647  if (child.tagName() == "Display")
3648  {
3649  // #CONNECTION# default values from defaultConstructor()
3650  setAxisIsDrawn(DomUtils::boolFromDom(child, "axisIsDrawn", false));
3651  setGridIsDrawn(DomUtils::boolFromDom(child, "gridIsDrawn", false));
3652  setFPSIsDisplayed(DomUtils::boolFromDom(child, "FPSIsDisplayed", false));
3653  // See comment below.
3654  tmpCameraIsEdited = DomUtils::boolFromDom(child, "cameraIsEdited", false);
3655  // setTextIsEnabled(DomUtils::boolFromDom(child, "textIsEnabled", true));
3656  }
3657 
3658  if (child.tagName() == "Geometry")
3659  {
3660  setFullScreen(DomUtils::boolFromDom(child, "fullScreen", false));
3661 
3662  if (isFullScreen())
3663  {
3664  prevPos_.setX(DomUtils::intFromDom(child, "prevPosX", 0));
3665  prevPos_.setY(DomUtils::intFromDom(child, "prevPosY", 0));
3666  }
3667  else
3668  {
3669  int width = DomUtils::intFromDom(child, "width", 600);
3670  int height = DomUtils::intFromDom(child, "height", 400);
3671  topLevelWidget()->resize(width, height);
3672  camera()->setScreenWidthAndHeight(this->width(), this->height());
3673 
3674  QPoint pos;
3675  pos.setX(DomUtils::intFromDom(child, "posX", 0));
3676  pos.setY(DomUtils::intFromDom(child, "posY", 0));
3677  topLevelWidget()->move(pos);
3678  }
3679  }
3680 
3681  if (child.tagName() == "Camera")
3682  {
3684  camera()->initFromDOMElement(child);
3686  }
3687 
3688  if ((child.tagName() == "ManipulatedFrame") && (manipulatedFrame()))
3690 
3691  child = child.nextSibling().toElement();
3692  }
3693 
3694  // The Camera always stores its "real" zClippingCoef in domElement(). If it is edited,
3695  // its "real" coef must be saved and the coef set to 5.0, as is done in setCameraIsEdited().
3696  // BUT : Camera and Display are read in an arbitrary order. We must initialize Camera's
3697  // "real" coef BEFORE calling setCameraIsEdited. Hence this temp cameraIsEdited and delayed call
3698  cameraIsEdited_ = tmpCameraIsEdited;
3699  if (cameraIsEdited_)
3700  {
3702  // #CONNECTION# 5.0 from setCameraIsEdited.
3704  }
3705 }
3706 
3707 #ifndef DOXYGEN
3708 
3710 void QGLViewer::saveToFile(const QString& fileName)
3711 {
3712  if (!fileName.isEmpty())
3713  setStateFileName(fileName);
3714 
3715  qWarning("saveToFile() is deprecated, use saveStateToFile() instead.");
3716  saveStateToFile();
3717 }
3718 
3721 bool QGLViewer::restoreFromFile(const QString& fileName)
3722 {
3723  if (!fileName.isEmpty())
3724  setStateFileName(fileName);
3725 
3726  qWarning("restoreFromFile() is deprecated, use restoreStateFromFile() instead.");
3727  return restoreStateFromFile();
3728 }
3729 #endif
3730 
3784 void QGLViewer::copyBufferToTexture(GLint internalFormat, GLenum format)
3785 {
3786  int h = 16;
3787  int w = 16;
3788  // Todo compare performance with qt code.
3789  while (w < width())
3790  w <<= 1;
3791  while (h < height())
3792  h <<= 1;
3793 
3794  bool init = false;
3795 
3796  if ((w != bufferTextureWidth_) || (h != bufferTextureHeight_))
3797  {
3798  bufferTextureWidth_ = w;
3800  bufferTextureMaxU_ = width() / qreal(bufferTextureWidth_);
3801  bufferTextureMaxV_ = height() / qreal(bufferTextureHeight_);
3802  init = true;
3803  }
3804 
3805  if (bufferTextureId() == 0)
3806  {
3807  glGenTextures(1, &bufferTextureId_);
3808  glBindTexture(GL_TEXTURE_2D, bufferTextureId_);
3809  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3810  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3811  init = true;
3812  }
3813  else
3814  glBindTexture(GL_TEXTURE_2D, bufferTextureId_);
3815 
3816  if ((format != previousBufferTextureFormat_) ||
3817  (internalFormat != previousBufferTextureInternalFormat_))
3818  {
3820  previousBufferTextureInternalFormat_ = internalFormat;
3821  init = true;
3822  }
3823 
3824  if (init)
3825  {
3826  if (format == GL_NONE)
3827  format = GLenum(internalFormat);
3828 
3829  glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, bufferTextureWidth_, bufferTextureHeight_, 0, format, GL_UNSIGNED_BYTE, NULL);
3830  }
3831 
3832  glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width(), height());
3833 }
3834 
3842 {
3843  if (glIsTexture(bufferTextureId_))
3844  return bufferTextureId_;
3845  else
3846  return 0;
3847 }
virtual QString mouseString() const
Definition: qglviewer.cpp:1718
QString message_
Definition: qglviewer.h:1157
void setZClippingCoefficient(qreal coef)
Definition: camera.h:268
virtual void postDraw()
Definition: qglviewer.cpp:339
int selectRegionHeight() const
Definition: qglviewer.h:837
virtual void aboutQGLViewer()
Definition: qglviewer.cpp:1960
Qt::KeyboardModifiers playPathKeyboardModifiers() const
Definition: qglviewer.cpp:2348
virtual void wheelEvent(QWheelEvent *)
Definition: qglviewer.cpp:1392
void setScreenWidthAndHeight(int width, int height)
Definition: camera.cpp:166
void getWheelActionBinding(MouseHandler handler, MouseAction action, bool withConstraint, Qt::Key &key, Qt::KeyboardModifiers &modifiers) const
Definition: qglviewer.cpp:2809
void setDefaultMouseBindings()
Definition: qglviewer.cpp:529
static QString keyString(unsigned int key)
Definition: qglviewer.cpp:1591
A keyFrame Catmull-Rom Frame interpolator.
virtual void initFromDOMElement(const QDomElement &element)
bool fullScreen_
Definition: qglviewer.h:1142
Vec position() const
Definition: frame.cpp:537
virtual void timerEvent(QTimerEvent *)
Definition: qglviewer.cpp:864
void displayFPS()
Definition: qglviewer.cpp:791
void setCamera(qglviewer::Camera *const camera)
Definition: qglviewer.cpp:600
Qt::KeyboardModifiers addKeyFrameStateKey() const
Definition: qglviewer.cpp:2355
virtual void setPathKey(int key, unsigned int index=0)
Definition: qglviewer.cpp:2305
static QDomElement QColorDomElement(const QColor &color, const QString &name, QDomDocument &doc)
Definition: domUtils.h:141
QMap< unsigned int, QString > keyDescription_
Definition: qglviewer.h:1185
QTabWidget * helpWidget()
Definition: qglviewer.h:735
The ManipulatedCameraFrame class represents a ManipulatedFrame with Camera specific mouse bindings...
virtual void drawAllPaths()
Definition: camera.cpp:1778
void getMouseActionBinding(MouseHandler handler, MouseAction action, bool withConstraint, Qt::Key &key, Qt::KeyboardModifiers &modifiers, Qt::MouseButton &button) const
Definition: qglviewer.cpp:2830
virtual void resetVisualHints()
Definition: qglviewer.cpp:3188
static QString mouseActionString(QGLViewer::MouseAction ma)
Definition: qglviewer.cpp:1552
virtual void loadProjectionMatrixStereo(bool leftBuffer=true) const
Definition: camera.cpp:536
void getClickButtonState(ClickAction action, unsigned int &state, bool &doubleClick, Qt::MouseButtons &buttonsBefore) const
Definition: qglviewer.cpp:2934
void toggleFPSIsDisplayed()
Definition: qglviewer.h:142
A ManipulatedFrame is a Frame that can be rotated and translated using the mouse. ...
QString stateFileName() const
Definition: qglviewer.cpp:3376
virtual void setPlayKeyFramePathStateKey(unsigned int buttonState)
Definition: qglviewer.cpp:2396
virtual void setPlayPathKeyboardModifiers(Qt::KeyboardModifiers modifiers)
Definition: qglviewer.cpp:2315
unsigned int fpsCounter_
Definition: qglviewer.h:1152
Qt::KeyboardModifiers playPathKeyboardModifiers_
Definition: qglviewer.h:1189
virtual void checkIfGrabsMouse(int x, int y, const Camera *const camera)=0
virtual void animate()
Definition: qglviewer.h:630
static void drawGrid(qreal size=1.0, int nbSubdivisions=10)
Definition: qglviewer.cpp:3323
virtual void fastDraw()
Definition: qglviewer.cpp:437
qreal sceneRadius() const
Definition: qglviewer.h:206
static QString formatClickActionPrivate(ClickBindingPrivate cbp)
Definition: qglviewer.cpp:1600
virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera)
Definition: mouseGrabber.h:243
void setForegroundColor(const QColor &color)
Definition: qglviewer.h:188
bool axisIsDrawn() const
Definition: qglviewer.h:97
void interpolateToFitScene()
Definition: camera.cpp:913
qreal norm() const
Definition: vec.h:335
virtual void stopAnimation()
Definition: qglviewer.cpp:881
virtual ~QGLViewer()
Definition: qglviewer.cpp:183
virtual void stopScreenCoordinatesSystem() const
Definition: qglviewer.cpp:852
virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera)
void hideMessage()
Definition: qglviewer.cpp:774
QMap< ClickBindingPrivate, ClickAction > clickBinding_
Definition: qglviewer.h:1278
int previousBufferTextureInternalFormat_
Definition: qglviewer.h:1196
virtual void loadProjectionMatrix(bool reset=true) const
Definition: camera.cpp:463
void toggleAnimation()
Definition: qglviewer.h:632
QPoint prevPos_
Definition: qglviewer.h:1143
GLuint bufferTextureId_
Definition: qglviewer.h:1192
void setSceneCenter(const Vec &center)
Definition: camera.cpp:733
bool animationStarted_
Definition: qglviewer.h:1146
virtual void mouseReleaseEvent(QMouseEvent *const event, Camera *const camera)
virtual void saveStateToFile()
Definition: qglviewer.cpp:3399
Vec projectedCoordinatesOf(const Vec &src, const Frame *frame=NULL) const
Definition: camera.cpp:1584
QColor foregroundColor() const
Definition: qglviewer.h:182
void delayedFullScreen()
Definition: qglviewer.h:1112
void defaultConstructor()
Definition: qglviewer.cpp:68
int selectBufferSize() const
Definition: qglviewer.h:820
void clearMouseBindings()
Definition: qglviewer.cpp:2709
virtual void deletePath(unsigned int i)
Definition: camera.cpp:1762
void setMouseBinding(unsigned int state, MouseHandler handler, MouseAction action, bool withConstraint=true)
Definition: qglviewer.cpp:2512
void setMouseBindingDescription(unsigned int state, QString description, bool doubleClick=false, Qt::MouseButtons buttonsBefore=Qt::NoButton)
Definition: qglviewer.cpp:1633
QMap< KeyboardAction, QString > keyboardActionDescription_
Definition: qglviewer.h:1183
bool gridIsDrawn() const
Definition: qglviewer.h:101
virtual void loadModelViewMatrix(bool reset=true) const
Definition: camera.cpp:500
int bufferTextureHeight_
Definition: qglviewer.h:1194
static QList< QGLViewer * > QGLViewerPool_
Definition: qglviewer.h:1289
void setSceneRadius(qreal radius)
Definition: camera.cpp:705
void setFlySpeed(qreal speed)
Definition: camera.cpp:1268
void setMouseGrabberIsEnabled(const qglviewer::MouseGrabber *const mouseGrabber, bool enabled=true)
Definition: qglviewer.cpp:1544
unsigned int previousBufferTextureFormat_
Definition: qglviewer.h:1195
virtual void loadModelViewMatrixStereo(bool leftBuffer=true) const
Definition: camera.cpp:591
void drawText(int x, int y, const QString &text, const QFont &fnt=QFont())
Definition: qglviewer.cpp:741
int animationPeriod() const
Definition: qglviewer.h:612
void showEntireScene()
Definition: camera.cpp:987
#define M_PI
#define QGLVIEWER_VERSION
Definition: config.h:31
virtual void closeEvent(QCloseEvent *)
Definition: qglviewer.cpp:891
void setSelectedName(int id)
Definition: qglviewer.h:859
int mouseButtonState(MouseHandler handler, MouseAction action, bool withConstraint=true) const
Definition: qglviewer.cpp:2792
void setStereoDisplay(bool stereo=true)
Definition: qglviewer.cpp:1475
void getViewport(GLint viewport[4]) const
Definition: camera.cpp:1502
Qt::KeyboardModifiers playKeyFramePathStateKey() const
Definition: qglviewer.cpp:2384
void centerScene()
Definition: camera.cpp:997
void toggleCameraIsEdited()
Definition: qglviewer.h:146
virtual void mouseReleaseEvent(QMouseEvent *const event, Camera *const camera)
Definition: mouseGrabber.h:237
qglviewer::MouseGrabber * mouseGrabber_
Definition: qglviewer.h:1166
bool restoreFromFile(const QString &fileName=QString::null)
Definition: qglviewer.cpp:3721
ClickAction clickAction(unsigned int state, bool doubleClick, Qt::MouseButtons buttonsBefore) const
Definition: qglviewer.cpp:2921
static QString clickActionString(QGLViewer::ClickAction ca)
Definition: qglviewer.cpp:1572
Qt::KeyboardModifiers playPathStateKey() const
Definition: qglviewer.cpp:2360
qglviewer::Vec sceneCenter() const
Definition: qglviewer.h:215
virtual void initFromDOMElement(const QDomElement &element)
Definition: camera.cpp:1869
Abstract class for objects that grab mouse focus in a QGLViewer.
Definition: mouseGrabber.h:130
static int QGLViewerIndex(const QGLViewer *const viewer)
Definition: qglviewer.h:1095
void setMouseStateKey(MouseHandler handler, unsigned int buttonState)
Definition: qglviewer.cpp:2502
unsigned int previousPathId_
Definition: qglviewer.h:1130
void setGridIsDrawn(bool draw=true)
Definition: qglviewer.h:130
bool grabsMouse() const
Definition: mouseGrabber.h:179
QGLViewer(QWidget *parent=0, const QGLWidget *shareWidget=0, Qt::WindowFlags flags=0)
Definition: qglviewer.cpp:160
virtual void endSelection(const QPoint &point)
Definition: qglviewer.cpp:1072
static void drawAxis(qreal length=1.0)
Definition: qglviewer.cpp:3255
static QString QGLViewerVersionString()
Definition: qglviewer.cpp:203
void setHandlerKeyboardModifiers(MouseHandler handler, Qt::KeyboardModifiers modifiers)
Definition: qglviewer.cpp:2445
QString fpsString_
Definition: qglviewer.h:1153
qglviewer::MouseGrabber * mouseGrabber() const
Definition: qglviewer.h:289
ManipulatedCameraFrame * frame() const
Definition: camera.h:334
virtual void mouseMoveEvent(QMouseEvent *)
Definition: qglviewer.cpp:1296
virtual void select(const QMouseEvent *event)
Definition: qglviewer.cpp:936
virtual void mousePressEvent(QMouseEvent *const event, Camera *const camera)
bool mouseGrabberIsAManipulatedCameraFrame_
Definition: qglviewer.h:1168
virtual void setPlayPathStateKey(unsigned int buttonState)
Definition: qglviewer.cpp:2372
qreal y
Definition: vec.h:81
int visualHint_
Definition: qglviewer.h:1178
void setShortcut(KeyboardAction action, unsigned int key)
Definition: qglviewer.cpp:2227
The Vec class represents 3D positions and 3D vectors.
Definition: vec.h:65
const GLdouble * matrix() const
Definition: frame.cpp:123
virtual void draw()
Definition: qglviewer.h:783
virtual void startScreenCoordinatesSystem(bool upward=false) const
Definition: qglviewer.cpp:827
virtual void wheelEvent(QWheelEvent *const event, Camera *const camera)
GLuint * selectBuffer()
Definition: qglviewer.h:844
Qt::Key currentlyPressedKey_
Definition: qglviewer.h:1279
virtual void setAddKeyFrameKeyboardModifiers(Qt::KeyboardModifiers modifiers)
Definition: qglviewer.cpp:2321
void setWheelBinding(Qt::KeyboardModifiers modifiers, MouseHandler handler, MouseAction action, bool withConstraint=true)
Definition: qglviewer.cpp:2666
int mouseHandler(unsigned int state) const
Definition: qglviewer.cpp:2760
Qt::KeyboardModifiers addKeyFrameKeyboardModifiers() const
Definition: qglviewer.cpp:2335
void connectAllCameraKFIInterpolatedSignals(bool connection=true)
Definition: qglviewer.cpp:624
void copyBufferToTexture(GLint internalFormat, GLenum format=GL_NONE)
Definition: qglviewer.cpp:3784
virtual void initFromDOMElement(const QDomElement &element)
Definition: qglviewer.cpp:3616
unsigned int wheelButtonState(MouseHandler handler, MouseAction action, bool withConstraint=true) const
Definition: qglviewer.cpp:2907
static void saveStateToFileForAllViewers()
Definition: qglviewer.cpp:3350
void setTranslation(const Vec &translation)
Definition: frame.h:201
const Qt::KeyboardModifiers modifiers
Definition: qglviewer.h:1245
void setManipulatedFrame(qglviewer::ManipulatedFrame *frame)
Definition: qglviewer.cpp:3057
void mouseGrabberChanged(qglviewer::MouseGrabber *mouseGrabber)
void toggleAxisIsDrawn()
Definition: qglviewer.h:138
void setDefaultShortcuts()
Definition: qglviewer.cpp:467
QColor backgroundColor() const
Definition: qglviewer.h:168
void projectOnLine(const Vec &origin, const Vec &direction)
Definition: frame.cpp:1133
virtual void mouseDoubleClickEvent(QMouseEvent *const event, Camera *const camera)
Definition: mouseGrabber.h:235
QMap< unsigned int, KeyFrameInterpolator * > kfi_
Definition: camera.h:506
GLuint bufferTextureId() const
Definition: qglviewer.cpp:3841
static Qt::MouseButton mouseButtonFromState(unsigned int state)
Definition: qglviewer.cpp:216
int wheelHandler(Qt::Key key, Qt::KeyboardModifiers modifiers) const
Definition: qglviewer.cpp:2866
QFont scaledFont(const QFont &font) const
Definition: qglviewer.h:552
void setSelectBufferSize(int size)
Definition: qglviewer.cpp:1104
virtual QString keyboardString() const
Definition: qglviewer.cpp:1906
void interpolateToZoomOnPixel(const QPoint &pixel)
Definition: camera.cpp:875
void clearShortcuts()
Definition: qglviewer.cpp:2719
int selectBufferSize_
Definition: qglviewer.h:1173
static QString mouseButtonsString(Qt::MouseButtons b)
Definition: qglviewer.cpp:1112
static void setBoolAttribute(QDomElement &element, const QString &attribute, bool value)
Definition: domUtils.h:137
bool cameraIsEdited() const
Definition: qglviewer.h:123
void setFullScreen(bool fullScreen=true)
Definition: qglviewer.cpp:1503
virtual void startAnimation()
Definition: qglviewer.cpp:874
void setKeyDescription(unsigned int key, QString description)
Definition: qglviewer.cpp:1823
bool stereo_
Definition: qglviewer.h:1141
void setMouseGrabber(qglviewer::MouseGrabber *mouseGrabber)
Definition: qglviewer.cpp:1530
qglviewer::ManipulatedFrame * manipulatedFrame() const
Definition: qglviewer.h:262
virtual void init()
Definition: qglviewer.h:762
bool manipulatedFrameIsACamera_
Definition: qglviewer.h:1163
void snapshotToClipboard()
void setAxisIsDrawn(bool draw=true)
Definition: qglviewer.h:128
virtual QString helpString() const
Definition: qglviewer.h:713
virtual void drawWithNames()
Definition: qglviewer.h:885
void setFPSIsDisplayed(bool display=true)
Definition: qglviewer.h:132
void stereoChanged(bool on)
qglviewer::ManipulatedFrame * manipulatedFrame_
Definition: qglviewer.h:1162
virtual void wheelEvent(QWheelEvent *const event, Camera *const camera)
virtual void setAddKeyFrameStateKey(unsigned int buttonState)
Definition: qglviewer.cpp:2366
void cameraIsEditedChanged(bool edited)
bool displaysInStereo() const
Definition: qglviewer.h:349
virtual void mouseDoubleClickEvent(QMouseEvent *)
Definition: qglviewer.cpp:1458
void setHandlerStateKey(MouseHandler handler, unsigned int buttonState)
Definition: qglviewer.cpp:2496
QMap< WheelBindingPrivate, MouseActionPrivate > wheelBinding_
Definition: qglviewer.h:1277
int animationTimerId_
Definition: qglviewer.h:1148
bool mouseGrabberIsAManipulatedFrame_
Definition: qglviewer.h:1167
bool mouseGrabberIsEnabled(const qglviewer::MouseGrabber *const mouseGrabber)
Definition: qglviewer.h:301
KeyFrameInterpolator * keyFrameInterpolator(unsigned int i) const
Definition: camera.cpp:1664
void setStateFileName(const QString &name)
Definition: qglviewer.h:1059
static QColor QColorFromDom(const QDomElement &e)
Definition: domUtils.h:150
Qt::KeyboardModifiers addKeyFrameKeyboardModifiers_
Definition: qglviewer.h:1189
A versatile 3D OpenGL viewer based on QGLWidget.
Definition: qglviewer.h:62
void setCameraIsEdited(bool edit=true)
Definition: qglviewer.cpp:449
virtual void paintGL()
Definition: qglviewer.cpp:275
Qt::Key keyFrameKey(unsigned int index) const
Definition: qglviewer.cpp:2378
QMap< MouseBindingPrivate, MouseActionPrivate > mouseBinding_
Definition: qglviewer.h:1276
qreal bufferTextureMaxU_
Definition: qglviewer.h:1193
virtual void preDrawStereo(bool leftBuffer=true)
Definition: qglviewer.cpp:410
void toggleTextIsEnabled()
Definition: qglviewer.h:144
QString cameraPathKeysString() const
Definition: qglviewer.cpp:1831
void toggleStereoDisplay()
Definition: qglviewer.h:359
void setBackgroundColor(const QColor &color)
Definition: qglviewer.h:186
void translate(Vec &t)
Definition: frame.cpp:335
A perspective or orthographic camera.
Definition: camera.h:84
int selectRegionWidth() const
Definition: qglviewer.h:835
The Quaternion class represents 3D rotations and orientations.
Definition: quaternion.h:66
QMap< size_t, bool > disabledMouseGrabbers_
Definition: qglviewer.h:1169
void drawNeeded()
virtual void addKeyFrameToPath(unsigned int i)
Definition: camera.cpp:1710
virtual QDomElement domElement(const QString &name, QDomDocument &document) const
Definition: qglviewer.cpp:3530
virtual bool restoreStateFromFile()
Definition: qglviewer.cpp:3460
virtual void resetPath(unsigned int i)
Definition: camera.cpp:1741
bool cameraIsInRotateMode() const
Definition: qglviewer.cpp:2973
void performClickAction(ClickAction ca, const QMouseEvent *const e)
Definition: qglviewer.cpp:1122
virtual void setKeyFrameKey(unsigned int index, int key)
Definition: qglviewer.cpp:2390
virtual void drawVisualHints()
Definition: qglviewer.cpp:3105
const Qt::MouseButton button
Definition: qglviewer.h:1246
virtual void keyPressEvent(QKeyEvent *)
Definition: qglviewer.cpp:2066
bool FPSIsDisplayed() const
Definition: qglviewer.h:108
static bool boolFromDom(const QDomElement &e, const QString &attribute, bool defValue)
Definition: domUtils.h:114
MouseAction mouseAction(unsigned int state) const
Definition: qglviewer.cpp:2728
virtual void startAction(int ma, bool withConstraint=true)
virtual void mouseReleaseEvent(QMouseEvent *const event, Camera *const camera)
void toggleCameraMode()
Definition: qglviewer.cpp:2995
void setKeyboardAccelerator(KeyboardAction action, unsigned int key)
Definition: qglviewer.cpp:2256
virtual void preDraw()
Definition: qglviewer.cpp:317
QMap< Qt::Key, unsigned int > pathIndex_
Definition: qglviewer.h:1188
TileRegion * tileRegion_
Definition: qglviewer.h:1286
void alignWithFrame(const Frame *const frame, bool move=false, qreal threshold=0.0)
Definition: frame.cpp:1055
Vec pivotPoint() const
Definition: camera.cpp:1275
virtual void keyReleaseEvent(QKeyEvent *)
Definition: qglviewer.cpp:2148
The Frame class represents a coordinate system, defined by a position and an orientation.
Definition: frame.h:121
MouseAction wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) const
Definition: qglviewer.cpp:2853
bool isFullScreen() const
Definition: qglviewer.h:329
bool textIsEnabled() const
Definition: qglviewer.h:113
static int intFromDom(const QDomElement &e, const QString &attribute, int defValue)
Definition: domUtils.h:72
QTabWidget * helpWidget_
Definition: qglviewer.h:1295
void drawFinished(bool automatic)
void helpRequired()
QMap< KeyboardAction, unsigned int > keyboardBinding_
Definition: qglviewer.h:1184
virtual void playPath(unsigned int i)
Definition: camera.cpp:1726
Qt::Key pathKey(unsigned int index) const
Definition: qglviewer.cpp:2286
QTimer messageTimer_
Definition: qglviewer.h:1159
qreal normalize()
Definition: vec.h:340
virtual void setVisualHintsMask(int mask, int delay=2000)
Definition: qglviewer.cpp:3181
QString stateFileName_
Definition: qglviewer.h:1292
virtual void drawLight(GLenum light, qreal scale=1.0) const
Definition: qglviewer.cpp:656
static QString tableLine(const QString &left, const QString &right)
Definition: qglviewer.cpp:1691
qreal f_p_s_
Definition: qglviewer.h:1154
qreal previousCameraZClippingCoefficient_
Definition: qglviewer.h:1129
static Qt::KeyboardModifiers keyboardModifiersFromState(unsigned int state)
Definition: qglviewer.cpp:210
void toggleFullScreen()
Definition: qglviewer.h:357
static bool isValidShortcutKey(int key)
Definition: qglviewer.cpp:1624
qglviewer::Camera * camera_
Definition: qglviewer.h:1127
int main(int argc, char *argv[])
Definition: main.cpp:29
QMap< ClickBindingPrivate, QString > mouseDescription_
Definition: qglviewer.h:1272
void handleKeyboardAction(KeyboardAction id)
Definition: qglviewer.cpp:2152
virtual void help()
Definition: qglviewer.cpp:1975
unsigned int keyboardAccelerator(KeyboardAction action) const
Definition: qglviewer.cpp:2262
virtual void postSelection(const QPoint &point)
Definition: qglviewer.h:894
void saveSnapshot(bool automatic=true, bool overwrite=false)
virtual void resizeGL(int width, int height)
Definition: qglviewer.cpp:2199
unsigned int shortcut(KeyboardAction action) const
Definition: qglviewer.cpp:2247
static const QList< QGLViewer * > & QGLViewerPool()
Definition: qglviewer.h:1085
QTime fpsTime_
Definition: qglviewer.h:1151
qreal bufferTextureMaxV_
Definition: qglviewer.h:1193
virtual void wheelEvent(QWheelEvent *const event, Camera *const camera)
Definition: mouseGrabber.h:247
void toggleGridIsDrawn()
Definition: qglviewer.h:140
virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera)
GLuint * selectBuffer_
Definition: qglviewer.h:1174
bool animationIsStarted() const
Definition: qglviewer.h:597
int bufferTextureWidth_
Definition: qglviewer.h:1194
void getClickActionBinding(ClickAction action, Qt::Key &key, Qt::KeyboardModifiers &modifiers, Qt::MouseButton &button, bool &doubleClick, Qt::MouseButtons &buttonsBefore) const
Definition: qglviewer.cpp:2951
bool cameraIsEdited_
Definition: qglviewer.h:1128
qreal zClippingCoefficient() const
Definition: camera.h:229
virtual void initializeGL()
Definition: qglviewer.cpp:239
void saveToFile(const QString &fileName=QString::null)
Definition: qglviewer.cpp:3710
static void drawArrow(qreal length=1.0, qreal radius=-1.0, int nbSubdivisions=12)
Definition: qglviewer.cpp:3207
qreal x
Definition: vec.h:81
virtual void mouseReleaseEvent(QMouseEvent *)
Definition: qglviewer.cpp:1353
bool displayMessage_
Definition: qglviewer.h:1158
const Qt::MouseButtons buttonsBefore
Definition: qglviewer.h:1248
virtual void beginSelection(const QPoint &point)
Definition: qglviewer.cpp:1012
virtual void startAction(int ma, bool withConstraint=true)
virtual void mousePressEvent(QMouseEvent *const event, Camera *const camera)
Definition: mouseGrabber.h:231
virtual void mousePressEvent(QMouseEvent *)
Definition: qglviewer.cpp:1191
qglviewer::Camera * camera() const
Definition: qglviewer.h:250
void displayMessage(const QString &message, int delay=2000)
Definition: qglviewer.cpp:764
void pointSelected(const QMouseEvent *e)
void setPivotPoint(const Vec &point)
Definition: camera.cpp:770


octovis
Author(s): Kai M. Wurm , Armin Hornung
autogenerated on Wed Jun 5 2019 19:26:39