Developer Documentation
QtBaseViewer.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 
43 
44 
45 
46 
47 //=============================================================================
48 //
49 // CLASS glViewer - IMPLEMENTATION
50 //
51 //=============================================================================
52 
53 
54 //== INCLUDES =================================================================
55 
56 #include <ACG/GL/acg_glew.hh>
57 
58 #include "QtBaseViewer.hh"
59 #include "QtGLViewerLayout.hh"
60 #include "PostProcessing.hh"
61 
62 #include <ACG/QtWidgets/QtWheel.hh>
63 #include <ACG/Scenegraph/CoordsysNode.hh>
65 #include <ACG/Scenegraph/StencilRefNode.hh>
66 #include <ACG/GL/GLError.hh>
67 #include <ACG/GL/IRenderer.hh>
68 
69 #include <QGraphicsWidget>
70 #include <QString>
71 #include <QBoxLayout>
72 #include <QtNetwork/QUdpSocket>
73 #include <QToolBar>
74 #include <QGraphicsSceneDragDropEvent>
75 #include <QPropertyAnimation>
76 
77 #include <QMimeData>
78 
79 #include <QClipboard>
80 #include <QApplication>
81 #include <QSplitter>
82 #include <QColorDialog>
83 
84 #include <QGraphicsView>
85 #include <QGraphicsProxyWidget>
86 
87 #include <QImageWriter>
88 
89 
90 #include <QOpenGLFramebufferObject>
91 
92 #ifdef max
93 # undef max
94 #endif
95 
96 #ifdef min
97 # undef min
98 #endif
99 
101 #include <OpenFlipper/common/ViewObjectMarker.hh>
102 
104 
105 #include <OpenFlipper/common/RendererInfo.hh>
106 #include <QOpenGLWidget>
107 
108 //== NAMESPACES ===============================================================
109 
110 
111 
112 //== IMPLEMENTATION ==========================================================
113 
114 static const char COPY_PASTE_VIEW_START_STRING[] =
115  "ACG::QtWidgets::QGLViewerWidget encoded view";
116 
117 //== IMPLEMENTATION ==========================================================
118 
119 
120 glViewer::glViewer( QGraphicsScene* _scene,
121  OFGLWidget* _glWidget,
122  Viewer::ViewerProperties& _properties,
123  QGraphicsWidget* _parent) :
124  QGraphicsWidget(_parent),
125  glareaGrabbed_(false),
126  projectionUpdateLocked_(false),
127  glScene_(_scene),
128  glWidget_(_glWidget),
129  glDebugLogger_(0),
130  pickCache_(0),
131  mouseCache_(nullptr),
132  updatePickCache_(true),
133  pickCacheSupported_(true),
134  constrainedRotationAxis_(std::numeric_limits<double>::quiet_NaN(), 0, 0),
135  clickEvent_(QEvent::MouseButtonPress, QPoint (), Qt::NoButton, Qt::NoButton, Qt::NoModifier),
136  properties_(_properties),
137  glstate_(0),
138  initialized_(false),
139  flyAnimationPerspective_(0),
140  flyAnimationOrthogonal_(0),
141  flyAngle_(0.0),
142  currentAnimationPos_(0.0),
143  flyMoveBack_(false),
144  postproc_(0)
145 {
146 
147  // widget stuff
148  createWidgets();
149 
150  // bind GL context to GL state class
151  glstate_ = new ACG::GLState(true, _glWidget->format().profile() != OFGLFormat::CoreProfile);
152 
154 
155  // state
156  isRotating_ = false;
157  lookAround_ = false;
158 
159  sceneGraphRoot_ = 0;
160 
161  normalsMode_ = NORMALIZE_NORMALS;
162  projectionMode_ = PERSPECTIVE_PROJECTION;
163  navigationMode_ = NORMAL_NAVIGATION;
164 
165  trackMouse_ = false;
166 
167  // Note: we start locked (initialization of updateLocked_)
168  // will be unlocked in initializeGL()
169 
170  QSizePolicy sp = sizePolicy();
171  sp.setHorizontalPolicy( QSizePolicy::Expanding );
172  sp.setVerticalPolicy( QSizePolicy::Expanding );
173  sp.setHorizontalStretch( 1 );
174  sp.setVerticalStretch( 1 );
175  setSizePolicy( sp );
176 
177  redrawTime_.start ();
178 
179  // timer for animation
180  timer_ = new QTimer( this );
181  connect( timer_, SIGNAL(timeout()), this, SLOT( slotAnimation()) );
182 
183  fovyModifier_ = 1.0;
184 
185  allowRotation_ = true;
186 
187 
188  connect( &properties_,SIGNAL(updated()), this, SLOT( slotPropertiesUpdated() ) );
189 
190 
191  //check for updated properties once
193 
194  setAcceptDrops(true);
195 
196  setHome();
197 
198  clickTimer_.setSingleShot (true);
199  connect (&clickTimer_, SIGNAL(timeout ()), this, SLOT(slotClickTimeout ()));
200 }
201 
202 
203 //-----------------------------------------------------------------------------
204 
205 
207 {
208  delete glstate_;
209 
210  deleteGLDebugLogger();
211  if (mouseCache_ != nullptr)
212  deleteQFBO(mouseCache_);
213 }
214 
215 
216 //-----------------------------------------------------------------------------
217 
218 
219 //QSizeF
220 //glViewer::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const
221 //{
222 // return QSizeF( 600, 600 );
223 //}
224 
225 //-----------------------------------------------------------------------------
226 
227 
229 
230  const GLuint prevFbo = ACG::GLState::getFramebufferDraw();
231  const GLuint prevReadFbo = ACG::GLState::getFramebufferRead();
232 
233 
234  // calling makeCurrent binds the default FBO when QOpenGLWidget is used
235  makeWidgetCurrent();
236 
237  //restore the previously bound FBO, if it was not 0 as Qt Documentation says we shall not bind 0
238  if(prevFbo != 0)
239  ACG::GLState::bindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFbo);
240  if(prevReadFbo != 0)
241  ACG::GLState::bindFramebuffer(GL_READ_FRAMEBUFFER, prevFbo);
242 
243 }
244 
245 
246 //-----------------------------------------------------------------------------
247 
249  unsigned int _maxPasses,
250  ACG::Vec3d _bbmin,
251  ACG::Vec3d _bbmax,
252  const bool _resetTrackBall)
253 {
254  sceneGraphRoot_ = _root;
255 
256  if (sceneGraphRoot_ )
257  {
258 
259  // set max number of render pass
260  glstate_->set_max_render_passes(_maxPasses);
261 
262  if ( ( _bbmin[0] > _bbmax[0] ) ||
263  ( _bbmin[1] > _bbmax[1] ) ||
264  ( _bbmin[2] > _bbmax[2] ) ) {
265 
266  // Invalid bounding box, try to recover
267  setScenePos( properties_.sceneCenter() , properties_.sceneRadius(), _resetTrackBall );
268 
269  // Update bounding box to match the scene geometry after recovery
270  _bbmin = ACG::Vec3d(-1.0,-1.0,-1.0);
271  _bbmax = ACG::Vec3d( 1.0, 1.0, 1.0);
272  } else {
273 
274  // For very small scenes, we set the scene radius to 0.1
275  // otherwise we take the real radius
276  if ( ( _bbmax - _bbmin ).max() < OpenFlipperSettings().value("Core/Gui/glViewer/minimalSceneSize",0.1).toDouble() ) {
277  setScenePos( ( _bbmin + _bbmax ) * 0.5,
278  OpenFlipperSettings().value("Core/Gui/glViewer/minimalSceneSize",0.1).toDouble(),
279  _resetTrackBall);
280 
281  } else {
282  setScenePos( ( _bbmin + _bbmax ) * 0.5,
283  ( _bbmax - _bbmin ).norm() * 0.5,
284  _resetTrackBall);
285  }
286 
287  }
288 
289  // remember the new bounding box for the state
290  glstate_->set_bounding_box(_bbmin,_bbmax);
291 
292  }
293 
294 
295  updateGL();
296 
297  emit(signalSceneGraphChanged(sceneGraphRoot_));
298 }
299 
300 
301 //-----------------------------------------------------------------------------
302 
303 
304 void glViewer::trackMouse(bool _track)
305 {
306  trackMouse_ = _track;
307 }
308 
309 
310 //-----------------------------------------------------------------------------
311 
313  // Find coordsys node
314  ACG::SceneGraph::BaseNode* node = 0;
315  node = PluginFunctions::getSceneGraphRootNode()->find("Core Coordsys Node");
316 
317  // set the projection mode for the coordinate system node
318  if (node != 0) {
319  ACG::SceneGraph::CoordsysNode* cnode = dynamic_cast<ACG::SceneGraph::CoordsysNode*> (node);
320  if (_mode == ORTHOGRAPHIC_PROJECTION) {
322  } else {
324  }
325  }
326 }
327 
328 
329 //-----------------------------------------------------------------------------
330 
331 
333 {
335  updateGL();
336 }
337 
338 
340 {
342  updateGL();
343 }
344 
345 
347 {
348  if (projectionMode_ == ORTHOGRAPHIC_PROJECTION)
350  else
352 
353  updateGL();
354 }
355 
356 
358 {
359  if ((projectionMode_ = _p) == ORTHOGRAPHIC_PROJECTION)
360  emit projectionModeChanged( true );
361  else
362  emit projectionModeChanged( false );
363 
365 
367 
368  emit viewChanged();
369 }
370 
372 {
373  if (navigationMode_ == NORMAL_NAVIGATION)
375  else
377 }
378 
379 
381 {
382  if ((navigationMode_ = _n) == NORMAL_NAVIGATION)
383  emit navigationModeChanged( true );
384  else
385  emit navigationModeChanged( false );
386 }
387 
388 void glViewer::setFOVY(double _fovy) {
389 
390  if(_fovy <= 0.0 || _fovy >= 180) {
391  std::cerr << "Error: Minimum or maximum fovy angle exceeded!" << std::endl;
392  return;
393  }
394 
395  OpenFlipperSettings().setValue("Core/Projection/FOVY", _fovy);
397 }
398 
400 {
401  if( projectionUpdateLocked_ )
402  return;
403 
404  makeCurrent();
405 
407 
408  const double aspect = _aspect ? _aspect : this->aspect_ratio();
409  // In stereo mode we have to use a perspective matrix
410  if ( projectionMode_ == PERSPECTIVE_PROJECTION)
411  {
412 
413  // Get fovy
414  const double fovy = this->field_of_view_vertical();
415 
416  glstate_->perspective(fovy, (GLdouble) aspect,
417  near_plane(), far_plane());
418  }
419  else
420  {
421 
423  -ortho_width() / aspect, ortho_width() / aspect,
424  near_plane(), far_plane() );
425  }
426 
427 }
428 
429 
430 //-----------------------------------------------------------------------------
431 
432 
433 void glViewer::setScenePos(const ACG::Vec3d& _center, double _radius, const bool _resetTrackBall)
434 {
435  if(_resetTrackBall) {
436  properties_.trackballCenter(_center);
437  }
438 
439  properties_.sceneCenter(_center);
440 
441  properties_.sceneRadius(_radius);
442  properties_.trackballRadius(_radius);
443 
445 
446  double nearPlane = std::max(0.0001f * properties_.sceneRadius(), -(c[2] + properties_.sceneRadius()));
447  double farPlane = std::max(0.0002f * properties_.sceneRadius(), -(c[2] - properties_.sceneRadius()));
448 
449  // Safety check, if near < 0
450  if ( nearPlane <= 0.0 ) {
451  std::cerr << "Error in BaseViewer drawScene, nearplane <= 0.0" << std::endl;
452  nearPlane = 0.000000000000001;
453  }
454 
455  // Safety check. Make sure that they are in the right order
456  if ( nearPlane > farPlane ) {
457  std::cerr << "Error in BaseViewer setScenePos, Nearplane > Farplane" << std::endl;
458  std::swap(nearPlane,farPlane);
459  }
460 
461  properties_.setPlanes(nearPlane,farPlane);
462 
464  updateGL();
465 
466  emit viewChanged();
467 }
468 
469 
470 //----------------------------------------------------------------------------
471 
472 
473 void glViewer::viewingDirection( const ACG::Vec3d& _dir, const ACG::Vec3d& _up )
474 {
475  // calc eye point for this direction
476  ACG::Vec3d eye = properties_.sceneCenter() - _dir * ( 3.0 * properties_.sceneRadius());
477 
480 
481  emit viewChanged();
482 }
483 
484 //-----------------------------------------------------------------------------
485 
486 void glViewer::lookAt(const ACG::Vec3d& _eye, const ACG::Vec3d& _center, const ACG::Vec3d& _up) {
487 
489  glstate_->lookAt(_eye, _center, _up);
490 
491  properties_.sceneCenter( _center );
492  properties_.sceneRadius( (properties_.sceneCenter() - _eye).norm() );
493 
494  emit viewChanged();
495 }
496 
497 //-----------------------------------------------------------------------------
498 
500 {
501  if (glstate_->compatibilityProfile())
502  {
503  makeCurrent();
504 
505  switch (normalsMode_ = _mode)
506  {
507  case DONT_TOUCH_NORMALS:
508  ACG::GLState::disable(GL_NORMALIZE);
509  break;
510 
511  case NORMALIZE_NORMALS:
512  ACG::GLState::enable(GL_NORMALIZE);
513  break;
514  }
515 
516  updateGL();
517  }
518 }
519 
520 
521 //-----------------------------------------------------------------------------
522 
523 
525 {
526  if (!properties_.updateLocked() && isVisible() )
527  {
528  updatePickCache_ = true;
529  update();
530 
531  emit viewUpdated();
532  }
533 }
534 
535 
536 
537 //-----------------------------------------------------------------------------
538 
539 
540 void glViewer::drawScene(double _aspect)
541 {
542 
543  // Inside the glWidget rendering, the system should not send extra updates
544  properties_.blockSignals(true);
545 
546  QTime timer;
547  timer.start();
548 
549  // *****************************************************************
550  // Adjust clipping planes
551  // *****************************************************************
552  // Far plane
554 
555  double nearPlane = std::max(0.0001f * properties_.sceneRadius(), -(c[2] + properties_.sceneRadius()));
556  double farPlane = std::max(0.0002f * properties_.sceneRadius(), -(c[2] - properties_.sceneRadius()));
557 
558  // Safety check, if near < 0
559  if ( nearPlane <= 0.0 ) {
560  std::cerr << "Error in BaseViewer drawScene, nearplane < 0" << std::endl;
561  nearPlane = 0.000000000000001;
562  }
563 
564  // Safety check. Make sure that they are in the right order
565  if ( nearPlane > farPlane ) {
566  std::cerr << "Error in BaseViewer drawScene, Nearplane > Farplane" << std::endl;
567  std::swap(nearPlane,farPlane);
568  }
569 
570  properties_.setPlanes(nearPlane,farPlane);
571 
572  updateProjectionMatrix(_aspect);
573 
574  // store time since last repaint in gl state and restart timer
575  glstate_->set_msSinceLastRedraw (redrawTime_.restart ());
576 
577  makeCurrent();
578  if(!glstate_->compatibilityProfile())
579  defaultVAO_.bind();
580 
581  // draw mono or stereo
582  // If stereo mode is selected, we have to provide multiple ways of rendering.
583 
584  // 1. Default internal pipeline : Directly to output buffer (no stereo support!)
585  // 2. Non default : Non-stereo Directly to output buffer (no stereo support!)
586  //
587  //
588 
589 // if (OpenFlipper::Options::stereoMode () == OpenFlipper::Options::OpenGL && OpenFlipper::Options::glStereo ())
590 // {
591 // // Stereo : Hardware support (OpenGL stereo : left and right buffer with offset eyes)
592 //
593 // return;
594 // }
595 // else if (OpenFlipper::Options::stereoMode () == OpenFlipper::Options::AnaglyphCustom && customAnaglyphSupported_)
596 // {
597 // //Stereo : No Hardware support (Left and right frame buffer with offset eyes)
598 // } else {
599 //
600 // }
601 
602  // save hardware backbuffer
603  GLuint backbufferFbo = 0;
604  GLuint backbufferTarget = 0;
605  glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&backbufferFbo);
606  glGetIntegerv(GL_DRAW_BUFFER, (GLint*)&backbufferTarget);
607 
608 
609 
610  // Render plugins do not have to worry about using scissor test for clearing their viewports later on.
611  glClearColor(properties_.backgroundColor()[0], properties_.backgroundColor()[1],
613  GLint curViewport[4];
614  glGetIntegerv(GL_VIEWPORT, curViewport);
615  glScissor(curViewport[0], curViewport[1], curViewport[2], curViewport[3]);
616  glEnable(GL_SCISSOR_TEST);
617  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
618  glDisable(GL_SCISSOR_TEST);
619 
620 
621 
622  // setup scene target fbo
623  if (!postproc_)
624  postproc_ = new PostProcessing();
625 
626  const int numPostProcessors = postProcessorManager().numActive(properties_.viewerId());
627 
628  bool stereoOpenGL = false;
629  bool stereoAnaglyph = false;
630  ACG::GLMatrixd projSave = glstate_->projection();
631  ACG::GLMatrixd projLR[2];
632 
633  if (properties_.stereo()) {
634  stereoOpenGL = OpenFlipper::Options::stereoMode () == OpenFlipper::Options::OpenGL && OpenFlipper::Options::glStereo ();
635  stereoAnaglyph = !stereoOpenGL;
637  }
638 
639  if (!stereoOpenGL && !stereoAnaglyph)
640  {
641  // setup render target fbo
643  properties_.multisampling() ? 16 : 0, -1);
644  }
645 
646 
647 
648  // Check if we use build in default renderer
649  if ( renderManager().activeId( properties_.viewerId() ) == 0 ) {
650  drawScene_mono();
651  } else {
652  RenderInterface* renderPlugin = renderManager().active( properties_.viewerId() )->plugin;
653 
654  // eventually set viewer id in IRenderer
655  ACG::IRenderer* shaderRenderPlugin = dynamic_cast<ACG::IRenderer*>(renderPlugin);
656 
657  if (shaderRenderPlugin)
658  {
659  shaderRenderPlugin->setViewerID( properties_.viewerId() );
660  shaderRenderPlugin->setCoreProfileMode( OpenFlipper::Options::coreProfile() );
661  }
662 
663  if (stereoOpenGL || stereoAnaglyph) {
664  // save current fbo
665  GLuint backbufferFbo = 0;
666  GLuint backbufferTarget = 0;
667  glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&backbufferFbo);
668  glGetIntegerv(GL_DRAW_BUFFER, (GLint*)&backbufferTarget);
669 
670  // setup stereo rendering
671 
672  // left eye: fbo 0
673  // right eye: fbo 1
674 
675  for (int eye = 0; eye < 2; ++eye) {
676  glstate_->set_projection(projLR[eye]);
677  if (stereoOpenGL && !numPostProcessors) {
678  // render directly into back_left
679  glDrawBuffer(eye ? GL_BACK_RIGHT : GL_BACK_LEFT);
680  glEnable(GL_SCISSOR_TEST);
681  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
682  glDisable(GL_SCISSOR_TEST);
683  }
684  else {
686  properties_.multisampling() ? 16 : 0, eye);
687  }
688 
689  renderPlugin->render(glstate_,properties_);
690  drawCursor();
691  }
692 
693  // restore projection
694  glstate_->set_projection(projSave);
695 
696  // restore backbuffer
697  glBindFramebuffer(GL_FRAMEBUFFER, backbufferFbo);
698  glDrawBuffer(backbufferTarget);
699  }
700  else {
701  renderPlugin->render(glstate_,properties_);
702  drawCursor();
703  }
704  }
705  checkGLError();
706 
707  // =================================================================================
708  // Post-Processing pipeline
709 
710 
712  glstate_,
713  glstate_->modelview(),
714  (stereoOpenGL || stereoAnaglyph) ? projLR[0] : glstate_->projection(),
715  projLR[1],
716  stereoOpenGL);
717 
718  if (stereoAnaglyph)
720 
721  // =================================================================================
722  glBindFramebuffer(GL_FRAMEBUFFER, backbufferFbo);
723  glDrawBuffer(backbufferTarget);
724  // unbind vbo for qt log window
725  ACG::GLState::bindBuffer(GL_ARRAY_BUFFER, 0);
726  ACG::GLState::activeTexture(GL_TEXTURE0);
727  ACG::GLState::bindTexture(GL_TEXTURE_2D, 0);
728 // fbo.release();
729 //
730 // QRect blitRect(0,0,glstate_->viewport_width(),glstate_->viewport_height());
731 //
732 // //
733 // //QTime time;
734 // //time.restart();
735 // QGLFramebufferObject::blitFramebuffer( 0 , blitRect, &fbo, blitRect , GL_COLOR_BUFFER_BIT );
736 // //std::cerr << "Elapsed for blit: " << time.elapsed() << std::endl;
737  glFinish();
738 
739  frame_time_ = timer.elapsed();
740 
741 
742  // Inside the glWidget rendering, the system should not send extra updates
743  properties_.blockSignals(false);
744 }
745 
746 
747 //-----------------------------------------------------------------------------
748 
749 
750 void glViewer::drawScene_mono()
751 {
752  if (sceneGraphRoot_) {
754  GLuint refBits = 0;
755  QSet<GLuint> references;
756 
757  if (oM)
758  {
759  glClear (GL_STENCIL_BUFFER_BIT);
760  ACG::GLState::enable (GL_STENCIL_TEST);
761  glStencilOp (GL_KEEP, GL_KEEP, GL_ZERO);
762  glStencilFunc (GL_ALWAYS, 0, ~0);
763 
765  o_it != PluginFunctions::objectsEnd(); ++o_it)
766  {
767  bool ok;
768  GLuint ref;
769 
770  ok = oM->stencilRefForObject(*o_it, ref);
771 
772  if (ok)
773  {
774  o_it->stencilRefNode ()->setReference (ref);
775  o_it->stencilRefNode ()->show ();
776  refBits |= ref;
777  references << ref;
778  }
779  else
780  o_it->stencilRefNode ()->hide ();
781  }
782  }
783 
784  // First pass
787 
788  // Second Pass for Blending operations
791 
792  if (oM)
793  {
794  if (oM->type() == ViewObjectMarker::PerBit)
795  {
796  references.clear ();
797  for (unsigned int i = 0; i < sizeof (GLuint) * 8; i++)
798  if (refBits & (1 << i))
799  references << (1 << i);
800  }
801 
802  glPushAttrib(GL_ALL_ATTRIB_BITS);
803 
804  ACG::GLState::enable(GL_BLEND);
805  ACG::GLState::disable(GL_DEPTH_TEST);
806 
807  if (glstate_->compatibilityProfile())
808  ACG::GLState::disable(GL_LIGHTING);
809 
810  ACG::GLState::disable(GL_DITHER);
811 
812  int vp_l, vp_b, vp_w, vp_h;
813  glstate_->get_viewport (vp_l, vp_b, vp_w, vp_h);
814 
815  glMatrixMode(GL_PROJECTION);
816  glPushMatrix ();
817  glLoadIdentity();
818  glOrtho(0, vp_w, vp_h, 0, 0, 1.0);
819  glMatrixMode(GL_MODELVIEW);
820  glPushMatrix ();
821  glLoadIdentity();
822 
823  glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
824 
825  foreach (unsigned int ref, references)
826  {
827  bool ok;
828  GLenum sfactor;
829  GLenum dfactor;
830  ACG::Vec4f color;
831  unsigned int mask = ~0;
832 
833  if (oM->type() == ViewObjectMarker::PerBit)
834  {
835  ok = oM->blendForStencilRefBit (ref, sfactor, dfactor, color);
836  mask = ref;
837  }
838  else
839  ok = oM->blendForStencilRefNumber (ref, sfactor, dfactor, color);
840 
841  if (!ok)
842  continue;
843 
844  glStencilFunc (GL_EQUAL, ref, mask);
845 
846  ACG::GLState::blendFunc (sfactor, dfactor);
847  glColor4f (color[0], color [1], color [2], color[3]);
848 
849  glBegin (GL_QUADS);
850  glVertex2i(0, 0);
851  glVertex2i(0, vp_h);
852  glVertex2i(vp_w, vp_h);
853  glVertex2i(vp_w, 0);
854  glEnd ();
855 
856  }
857 
858  glMatrixMode(GL_PROJECTION);
859  glPopMatrix ();
860  glMatrixMode(GL_MODELVIEW);
861  glPopMatrix ();
862 
863  glPopAttrib ();
864  ACG::GLState::disable (GL_STENCIL_TEST);
865  }
866 
867 
868  }
869 
870  drawCursor();
871 
872 }
873 
874 
876 {
878  {
880  // reset view transformation
882  // translate cursor position to 0,0
884  // paint cursor
887  }
888 }
889 
890 
892 {
893  home_modelview_ = glstate_->modelview();
894  home_inverse_modelview_ = glstate_->inverse_modelview();
895  homeOrthoWidth_ = properties_.orthoWidth();
896  home_center_ = properties_.trackballCenter();
897  home_radius_ = properties_.trackballRadius();
898 }
899 
900 
902 {
903  makeCurrent();
904  glstate_->set_modelview(home_modelview_, home_inverse_modelview_);
905  properties_.orthoWidth( homeOrthoWidth_ );
906  properties_.trackballCenter( home_center_ );
907  properties_.trackballRadius(home_radius_);
909  updateGL();
910 
911  emit viewChanged();
912 
913 }
914 
915 //-----------------------------------------------------------------------------
916 
918 {
919  makeCurrent();
920  // update scene graph (get new bounding box and set projection right, including near and far plane)
922 
923  unsigned int maxPases = 1;
924  ACG::Vec3d bbmin,bbmax;
925  // update scene bounding boxes
927 
928  // update scene properties (near, far plane, scene radius according to the computed bounding boxes)
929  sceneGraph ( PluginFunctions::getSceneGraphRootNode(), maxPases,bbmin,bbmax,true);
930 
931 
932  // update camera
933  // move center (in camera coords) to origin and translate in -z dir
935  - ACG::Vec3d(0.0, 0.0, 3.0 * properties_.sceneRadius()));
936 
938  double aspect = (double) glWidth() / (double) glHeight();
939  if (aspect > 1.0)
941 
944  updateGL();
945 
946  emit viewChanged();
947 
948 }
949 
950 
951 //-----------------------------------------------------------------------------
952 
953 
954 void glViewer::setView(const ACG::GLMatrixd& _modelview,
955  const ACG::GLMatrixd& _inverse_modelview)
956 {
957  makeCurrent();
958  glstate_->set_modelview(_modelview, _inverse_modelview);
959  updateGL();
960 
961  emit viewChanged();
962 }
963 
964 
965 //-----------------------------------------------------------------------------
966 
967 
969 {
970 
971  // lock update
973 
974  // init GL state
975  glstate_->initialize();
976 
977  // OpenGL state
978  ACG::GLState::enable(GL_DEPTH_TEST);
979 
980  if (glstate_->compatibilityProfile())
981  {
982  ACG::GLState::enable(GL_LIGHTING);
983  ACG::GLState::shadeModel(GL_FLAT);
984  }
985 
986  ACG::GLState::disable(GL_DITHER);
987 
988 
989  projectionMode( projectionMode_ );
990  normalsMode( normalsMode_ );
991 
992  // Update all settings which would require a redraw
993  applyProperties();
994 
995  // modelview
996  glstate_->translate(0.0, 0.0, -3.0);
997  setHome();
998 
999  // pixel transfer
1000  glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1001  glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
1002  glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
1003  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1004  glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1005  glPixelStorei(GL_PACK_SKIP_ROWS, 0);
1006  glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
1007  glPixelStorei(GL_PACK_ALIGNMENT, 1);
1008 
1009 
1010  // unlock update (we started locked)
1012 
1013  initialized_ = true;
1014 
1015  if (sceneGraphRoot_)
1016  {
1017  unsigned int maxPases = 1;
1018  ACG::Vec3d bbmin,bbmax;
1019  ACG::SceneGraph::analyzeSceneGraph(sceneGraphRoot_,maxPases,bbmin,bbmax);
1020 
1021  sceneGraph ( sceneGraphRoot_, maxPases,bbmin,bbmax,true);
1022  viewAll();
1023  }
1024 
1025 
1026  // qt opengl info
1027  startGLDebugLogger();
1028 }
1029 
1030 
1031 //-----------------------------------------------------------------------------
1032 
1033 
1034 void glViewer::paintGL(double _aspect)
1035 {
1036  if (!initialized_)
1037  initializeGL ();
1038 
1039 
1040  // some drivers in core profile require a VAO object to be bound for all buffer array operations
1041  if (!glstate_->compatibilityProfile())
1042  {
1043  if (!defaultVAO_.isSupported())
1044  std::cerr << "Error - using core profile, but required VAO is not supported!" << std::endl;
1045  else
1046  defaultVAO_.bind();
1047  }
1048 
1049 
1050  if (!properties_.updateLocked())
1051  {
1053 
1054  GLboolean dtenabled;
1055  glGetBooleanv(GL_DEPTH_TEST, &dtenabled);
1056  ACG::GLState::enable(GL_DEPTH_TEST);
1057 
1058  if (glstate_->compatibilityProfile())
1059  {
1060  glPushAttrib(GL_ALL_ATTRIB_BITS);
1061  ACG::GLState::enable(GL_LIGHTING);
1062 
1063  glMatrixMode(GL_PROJECTION);
1064  glPushMatrix();
1065 
1066  glMatrixMode(GL_MODELVIEW);
1067  glPushMatrix();
1068 
1069 
1070  normalsMode(normalsMode_);
1071 
1072  ACG::GLState::shadeModel(GL_FLAT);
1073  }
1074 
1075  ACG::GLState::disable(GL_DITHER);
1076 
1077 
1078  applyProperties();
1079 
1080  glstate_->setState();
1081 
1082  if (glstate_->compatibilityProfile())
1083  glColor4f(1.0,0.0,0.0,1.0);
1084 
1085  glstate_->clearBuffers ();
1086 
1088 
1089  // draw scene
1090  drawScene(_aspect);
1091 
1092  if (glstate_->compatibilityProfile())
1093  {
1094  glPopMatrix();
1095 
1096  glMatrixMode(GL_PROJECTION);
1097  glPopMatrix();
1098 
1099  glPopAttrib();
1100  }
1101  if(dtenabled)
1102  ACG::GLState::enable(GL_DEPTH_TEST);
1103  else
1104  ACG::GLState::disable(GL_DEPTH_TEST);
1105  }
1106  glBindBuffer(GL_ARRAY_BUFFER, 0);
1107  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
1108 }
1109 
1110 
1111 //-----------------------------------------------------------------------------
1112 
1113 
1114 void glViewer::resizeEvent(QGraphicsSceneResizeEvent *)
1115 {
1117  glstate_->viewport(scenePos().x(),
1118  scene()->height () - scenePos().y() - size().height (),
1119  size().width (), size().height (),
1120  scene()->width (), scene()->height ());
1121  update();
1122 
1123  emit viewChanged();
1124 }
1125 
1126 void glViewer::moveEvent (QGraphicsSceneMoveEvent *)
1127 {
1128  glstate_->viewport(scenePos().x(),
1129  scene()->height () - scenePos().y() - size().height (),
1130  size().width (), size().height (),
1131  scene()->width (), scene()->height ());
1132  update();
1133 
1134  emit viewChanged();
1135 }
1136 
1137 //-----------------------------------------------------------------------------
1138 
1139 void glViewer::encodeView(QString& _view, const QSize& _windowSize /*= QSize()*/,
1140  const int _splitterWidth /*=-1*/, const bool _make_c_string /*= false*/)
1141 {
1142  // Get current matrices
1143  const ACG::GLMatrixd m = glstate_->modelview();
1144  const ACG::GLMatrixd p = glstate_->projection();
1145 
1146  static const char *line_delim_c = " \\\n";
1147  static const char *line_delim_std = line_delim_c + 2;
1148  const char *line_delim = _make_c_string ? line_delim_c : line_delim_std;
1149 
1150  if (_make_c_string)
1151  _view += "\"";
1152 
1153  // Add modelview matrix to output
1154  _view += QString(COPY_PASTE_VIEW_START_STRING) + line_delim;
1155  _view += QString::number(m(0,0)) + " " + QString::number(m(0,1)) + " " + QString::number(m(0,2)) + " " + QString::number(m(0,3)) + line_delim;
1156  _view += QString::number(m(1,0)) + " " + QString::number(m(1,1)) + " " + QString::number(m(1,2)) + " " + QString::number(m(1,3)) + line_delim;
1157  _view += QString::number(m(2,0)) + " " + QString::number(m(2,1)) + " " + QString::number(m(2,2)) + " " + QString::number(m(2,3)) + line_delim;
1158  _view += QString::number(m(3,0)) + " " + QString::number(m(3,1)) + " " + QString::number(m(3,2)) + " " + QString::number(m(3,3)) + line_delim;
1159 
1160  // Add projection matrix to output
1161  _view += QString::number(p(0,0)) + " " + QString::number(p(0,1)) + " " + QString::number(p(0,2)) + " " + QString::number(p(0,3)) + line_delim;
1162  _view += QString::number(p(1,0)) + " " + QString::number(p(1,1)) + " " + QString::number(p(1,2)) + " " + QString::number(p(1,3)) + line_delim;
1163  _view += QString::number(p(2,0)) + " " + QString::number(p(2,1)) + " " + QString::number(p(2,2)) + " " + QString::number(p(2,3)) + line_delim;
1164  _view += QString::number(p(3,0)) + " " + QString::number(p(3,1)) + " " + QString::number(p(3,2)) + " " + QString::number(p(3,3)) + line_delim;
1165 
1166  // add gl width/height, current projection Mode and the ortho mode width to output
1167  _view += QString::number(_windowSize.width()) + " " + QString::number(_windowSize.height()) + " " + QString::number(_splitterWidth)+ " " + QString::number(projectionMode_) + " " + QString::number(properties_.orthoWidth()) + line_delim;;
1168 
1169  // Add viewer size
1170  _view += QString::fromUtf8("%1 %2").arg(size().width()).arg(size().height());
1171 
1172  if (_make_c_string)
1173  _view += "\"";
1174 
1175  _view += "\n";
1176 }
1177 
1178 
1179 //----------------------------------------------------------------------------
1180 
1181 
1182 bool glViewer::decodeView(const QString& _view,
1183  ACG::GLMatrixd &m, ACG::GLMatrixd &p, int &pMode, double &ortho_width,
1184  QSize *_windowSize /*= NULL*/,
1185  int* _splitterWidth /*= NULL*/, QSize *_viewportSize)
1186 {
1187  // Remove the magic from the string
1188  QString temp = _view;
1189  temp.remove(0,sizeof(COPY_PASTE_VIEW_START_STRING));
1190 
1191  //Split it into its components
1192  QStringList split = temp.split(QRegExp("[\\n\\s]"),QString::SkipEmptyParts);
1193 
1194  // New version
1195  if ( split.size() >= 37 ) {
1196 
1197  //*********************************************************
1198  // Parse the components
1199  // first, get the projection and the modelview matrices
1200  //*********************************************************
1201  for (int i = 0; i < 4; ++i)
1202  {
1203  for (int j = 0; j < 4; ++j)
1204  {
1205  m(i,j) = split[i*4 + j].toDouble();
1206  p(i,j) = split[i*4 + j +16 ].toDouble();
1207  }
1208  }
1209 
1210  //*********************************************************
1211  //parse the window size if requested
1212  //*********************************************************
1213  if (_windowSize)
1214  {
1215  //restore the old window size
1216  int w = split[32].toInt();
1217  int h = split[33].toInt();
1218  *_windowSize = QSize(w,h);
1219  }
1220 
1221  //*********************************************************
1222  //parse the splitter width for the toolboxes if requested
1223  //*********************************************************
1224  if (_splitterWidth) {
1225  *_splitterWidth = split[34].toInt();
1226  }
1227 
1228  //*********************************************************
1229  // Projection mode and orthogonal width
1230  //*********************************************************
1231  pMode = split[35].toInt();
1232  ortho_width = split[36].toDouble();
1233 
1234  if (_viewportSize && split.size() >= 39) {
1235  *_viewportSize = QSize(split[37].toInt(), split[38].toInt());
1236  }
1237 
1238  } else if ( split.size() == 36 ) { // Old Version
1239 
1240  //*********************************************************
1241  // Parse the components
1242  // first, get the projection and the modelview matrices
1243  //*********************************************************
1244  for (int i = 0; i < 4; ++i)
1245  {
1246  for (int j = 0; j < 4; ++j)
1247  {
1248  m(i,j) = split[i*4 + j].toDouble();
1249  p(i,j) = split[i*4 + j +16].toDouble();
1250  }
1251  }
1252 
1253  //*********************************************************
1254  //parse the window size if requested
1255  //*********************************************************
1256  if (_windowSize)
1257  {
1258  //restore the old window size
1259  int w = split[32].toInt();
1260  int h = split[33].toInt();
1261  *_windowSize = QSize(w,h);
1262  }
1263 
1264 
1265  //*********************************************************
1266  // Return -1 to inform, that the value is unknown
1267  //*********************************************************
1268  if (_splitterWidth) {
1269  *_splitterWidth = -1;
1270  }
1271 
1272  //*********************************************************
1273  // Projection mode and orthogonal width
1274  //*********************************************************
1275  pMode = split[34].toInt();
1276  ortho_width = split[35].toDouble();
1277 
1278  } else { // Garbage ?!
1279  std::cerr << "Unable to paste view ... wrong parameter count!! is" << split.size() << std::endl;
1280  return false;
1281  }
1282 
1283  return true;
1284 }
1285 
1286 bool glViewer::decodeView(const QString& _view, QSize *_windowSize /*= NULL*/,
1287  int* _splitterWidth /*= NULL*/, QSize *_viewportSize)
1288 {
1289  if (_view.left(sizeof(COPY_PASTE_VIEW_START_STRING)-1) != QString(COPY_PASTE_VIEW_START_STRING))
1290  {
1291  std::cerr << "No View was copied." << std::endl;
1292  return false;
1293  }
1294 
1295  ACG::GLMatrixd m, p;
1296  int pMode;
1297  double ortho_width;
1298 
1299  if (!decodeView(_view, m, p, pMode, ortho_width,
1300  _windowSize, _splitterWidth, _viewportSize))
1301  return false;
1302  properties_.orthoWidth(ortho_width);
1303 
1304  // Switch to our gl context
1305  makeCurrent();
1306 
1307  // set projection mode
1308  if (projectionMode_ != (ProjectionMode)pMode)
1310 
1311  // Apply new modelview matrix
1312  glstate_->set_modelview(m);
1313 
1314  updateGL();
1315 
1316  return true;
1317 }
1318 
1319 
1320 //-----------------------------------------------------------------------------
1321 
1322 
1323 void glViewer::actionCopyView(const QSize &_windowSize /*= QSize(-1,-1)*/, const int _splitterWidth /*= -1*/,
1324  const bool _make_c_string /*= false*/)
1325 {
1326  QString view;
1327  encodeView(view,_windowSize,_splitterWidth, _make_c_string);
1328  QApplication::clipboard()->setText(view);
1329 }
1330 
1331 
1332 //-----------------------------------------------------------------------------
1333 
1334 
1335 void glViewer::actionPasteView(QSize * _windowSize /*= NULL*/, int *_splitterWidth /*= NULL*/)
1336 {
1337  QString view;
1338  view = QApplication::clipboard()->text();
1339  decodeView(view,_windowSize,_splitterWidth);
1340 }
1341 
1342 void glViewer::actionSetView(QString view) {
1343  decodeView(view, 0, 0);
1344 }
1345 
1346 //-----------------------------------------------------------------------------
1347 
1348 void
1349 glViewer::createWidgets()
1350 {
1351  // Construct GL context & widget
1352 
1353  wheelZ_=new ACG::QtWidgets::QtWheel( 0,"wheel-z",ACG::QtWidgets::QtWheel::Vertical);
1354  wheelZ_->setMinimumSize(wheelZ_->sizeHint());
1355  wheelZ_->setMaximumSize(wheelZ_->sizeHint());
1356  connect(wheelZ_,SIGNAL(angleChangedBy(double)),
1357  this,SLOT(slotWheelZ(double)));
1358  wheelZ_->setToolTip( tr("Translate along <b>z-axis</b>."));
1359  wheelZ_->setWhatsThis( tr("Translate along <b>z-axis</b>."));
1360 
1361  wheelY_=new ACG::QtWidgets::QtWheel( 0,"wheel-y",ACG::QtWidgets::QtWheel::Horizontal);
1362  wheelY_->setMinimumSize(wheelY_->sizeHint());
1363  wheelY_->setMaximumSize(wheelY_->sizeHint());
1364  connect(wheelY_,SIGNAL(angleChangedBy(double)),
1365  this,SLOT(slotWheelY(double)));
1366  wheelY_->setToolTip(tr("Rotate around <b>y-axis</b>."));
1367  wheelY_->setWhatsThis( tr("Rotate around <b>y-axis</b>."));
1368 
1369  wheelX_=new ACG::QtWidgets::QtWheel( 0,"wheel-x" ,ACG::QtWidgets::QtWheel::Vertical);
1370  wheelX_->setMinimumSize(wheelX_->sizeHint());
1371  wheelX_->setMaximumSize(wheelX_->sizeHint());
1372  connect(wheelX_,SIGNAL(angleChangedBy(double)),
1373  this,SLOT(slotWheelX(double)));
1374  wheelX_->setToolTip(tr("Rotate around <b>x-axis</b>."));
1375  wheelX_->setWhatsThis( tr("Rotate around <b>x-axis</b>."));
1376 
1377  // Hide or show wheels (depending on ini option)
1378  if( ! OpenFlipperSettings().value("Core/Gui/glViewer/showControlWheels").toBool() )
1379  slotHideWheels();
1380 
1381  QGraphicsWidget *wheelX = glScene_->addWidget (wheelX_);
1382  QGraphicsWidget *wheelY = glScene_->addWidget (wheelY_);
1383  QGraphicsWidget *wheelZ = glScene_->addWidget (wheelZ_);
1384 
1385  wheelX_->setWindowOpacity (0.5);
1386  wheelY_->setWindowOpacity (0.5);
1387  wheelZ_->setWindowOpacity (0.5);
1388 
1389  wheelX->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
1390  wheelY->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
1391  wheelZ->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
1392 
1393  glBaseLayout_ = new QtGLViewerLayout;
1394  glBaseLayout_->addWheelX(wheelX);
1395  glBaseLayout_->addWheelY(wheelY);
1396  glBaseLayout_->addWheelZ(wheelZ);
1397 
1398  connect(wheelX_,SIGNAL(hideWheel()),this,SLOT(slotHideWheels()));
1399  connect(wheelY_,SIGNAL(hideWheel()),this,SLOT(slotHideWheels()));
1400  connect(wheelZ_,SIGNAL(hideWheel()),this,SLOT(slotHideWheels()));
1401 
1402  setLayout(glBaseLayout_);
1403 }
1404 
1405 //-----------------------------------------------------------------------------
1406 
1407 
1408 void glViewer::translate(const ACG::Vec3d& _trans)
1409 {
1410  makeCurrent();
1411  glstate_->translate(_trans[0], _trans[1], _trans[2], ACG::MULT_FROM_LEFT);
1412 
1413  updateGL();
1414 
1415  emit viewChanged();
1416 }
1417 
1418 
1419 //-----------------------------------------------------------------------------
1420 
1421 
1423 {
1424  makeCurrent();
1426 }
1427 
1428 
1429 //-----------------------------------------------------------------------------
1430 
1431 
1432 void glViewer::rotate(const ACG::Vec3d& _axis,
1433  double _angle,
1434  const ACG::Vec3d& _center)
1435 {
1436  makeCurrent();
1437  ACG::Vec3d t = glstate_->modelview().transform_point(_center);
1438  glstate_->translate(-t[0], -t[1], -t[2], ACG::MULT_FROM_LEFT);
1439  glstate_->rotate(_angle, _axis[0], _axis[1], _axis[2], ACG::MULT_FROM_LEFT);
1440  glstate_->translate( t[0], t[1], t[2], ACG::MULT_FROM_LEFT);
1441 
1442  updateGL();
1443 
1444  emit viewChanged();
1445 }
1446 
1447 
1448 //-----------------------------------------------------------------------------
1449 
1450 
1451 unsigned int glViewer::glWidth() const {
1452  return size().width();
1453 }
1454 unsigned int glViewer::glHeight() const {
1455  return size().height();
1456 }
1457 QSize glViewer::glSize() const {
1458  return QSize(size().width(),size().height());
1459 }
1460 QPoint glViewer::glMapFromGlobal( const QPoint& _pos ) const {
1461  QPoint p (scene()->views().front()->mapFromGlobal(_pos));
1462  QPointF f (mapFromScene(QPointF(p.x(), p.y ())));
1463  return QPoint (f.x(), f.y());
1464 }
1465 
1466 QPoint glViewer::glMapToGlobal( const QPoint& _pos ) const {
1467  QPointF f (mapToScene(QPointF(_pos.x(), _pos.y ())));
1468  QPoint p (f.x(), f.y());
1469  return scene()->views().front()->mapToGlobal(p);
1470 }
1471 
1472 double glViewer::field_of_view_vertical() const {
1473  return OpenFlipperSettings().value("Core/Projection/FOVY", 45.0).toDouble()
1474  + fovyModifier_;
1475 }
1476 
1477 
1478 //-----------------------------------------------------------------------------
1479 
1480 
1481 void glViewer::slotWheelX(double _dAngle)
1482 {
1484  updateGL();
1485 
1486  emit viewChanged();
1487 }
1488 
1489 void glViewer::slotWheelY(double _dAngle)
1490 {
1492  updateGL();
1493 
1494  emit viewChanged();
1495 }
1496 
1497 void glViewer::slotWheelZ(double _dist)
1498 {
1499  double dz = _dist * 0.5 / M_PI * properties_.sceneRadius() * 2.0;
1500  translate(ACG::Vec3d(0,0,dz));
1501  updateGL();
1502 
1503  emit viewChanged();
1504 }
1505 
1506 //-----------------------------------------------------------------------------
1507 
1508 
1510 {
1511  glareaGrabbed_ = true;
1512 
1513  if (properties_.cursorPainter()) {
1514  properties_.cursorPainter()->setCursor(Qt::BlankCursor);
1515  std::cerr << "grabGLArea: Blanking cursorpainter cursor" << std::endl;
1516  } else {
1517  setCursor(Qt::BlankCursor);
1518  std::cerr << "grabGLArea: Blanking qt cursor" << std::endl;
1519  }
1520  grabMouse();
1521  grabKeyboard();
1522 }
1523 
1525 {
1526  glareaGrabbed_ = false;
1527 
1528  ungrabMouse();
1529  ungrabKeyboard();
1530 
1531  if (properties_.cursorPainter()) {
1532  properties_.cursorPainter()->setCursor(Qt::ArrowCursor);
1533  std::cerr << "grabGLArea: Setting cursorPainter cursor to arrow" << std::endl;
1534  } else {
1535  setCursor(Qt::ArrowCursor);
1536  std::cerr << "grabGLArea: Setting qt cursor to arrow" << std::endl;
1537  }
1538 }
1539 
1540 
1541 //-----------------------------------------------------------------------------
1542 
1543 
1544 void glViewer::contextMenuEvent(QGraphicsSceneContextMenuEvent* _e)
1545 {
1546  emit signalMakeActive();
1547  glScene_->update ();
1548 
1549  QPoint p (_e->pos().x(), _e->pos().y());
1551 }
1552 
1553 
1554 //-----------------------------------------------------------------------------
1555 
1556 void glViewer::mousePressEvent(QGraphicsSceneMouseEvent* _e)
1557 {
1558  makeCurrent();
1559  QPoint p (_e->scenePos().x(), _e->scenePos().y());
1560  QMouseEvent me(QEvent::MouseButtonPress ,p, _e->screenPos(), _e->button(),
1561  _e->buttons(), _e->modifiers());
1562  _e->accept ();
1563 
1564  emit signalMakeActive();
1565  const GLuint prevFBO = ACG::GLState::getFramebufferDraw();
1566 
1567  //recreate FBO if gl area was resized
1568  if (mouseCache_ != nullptr && QFBOResized(mouseCache_))
1569  {
1570  deleteQFBO(mouseCache_);
1571  mouseCache_ = nullptr;
1572  }
1573 
1574  if (mouseCache_ == nullptr)
1575  {
1576  GLuint fboHandle;
1577  int samples = 0;
1578  createQFBO(mouseCache_, &fboHandle, glWidth() , glHeight(), &samples);
1579  }
1580 
1581  bindQFBO(mouseCache_);
1582 
1583  glScene_->update ();
1584 
1585  // right button pressed => popup menu (ignore here)
1586  if (allowConstrainedRotation() || _e->button() != Qt::RightButton )
1587  {
1588  switch (properties_.actionMode())
1589  {
1590  case Viewer::ExamineMode:
1591  if ((_e->modifiers() & Qt::ControlModifier)) // drag&drop
1592  emit startDragEvent( &me );
1593  else
1594  viewMouseEvent(&me); // examine
1595 
1596  if (clickTimer_.isActive ())
1597  {
1598  clickTime_ = QTime ();
1599  clickTimer_.stop ();
1600  }
1601  else
1602  {
1603  clickTime_.start ();
1604  clickEvent_ = me;
1605  }
1606  break;
1607 
1608  case Viewer::LightMode:
1609  emit(signalMouseEventLight(&me));
1610  break;
1611 
1612  case Viewer::PickingMode: // give event to application
1613  emit(signalMouseEvent(&me, properties_.pickMode() ));
1614  emit(signalMouseEvent(&me));
1615  break;
1616 
1617  case Viewer::QuestionMode: // give event to application
1618  emit(signalMouseEventIdentify(&me));
1619  break;
1620  }
1621  }
1622  //restore old FBO
1623  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT,prevFBO);
1624 }
1625 
1626 
1627 //-----------------------------------------------------------------------------
1628 
1629 
1630 void glViewer::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* _e)
1631 {
1632  QPoint p (_e->scenePos().x(), _e->scenePos().y());
1633  QMouseEvent me(QEvent::MouseButtonDblClick ,p, _e->screenPos(), _e->button(),
1634  _e->buttons(), _e->modifiers());
1635  _e->accept ();
1636 
1637  emit signalMakeActive();
1638  glScene_->update ();
1639 
1640  switch (properties_.actionMode())
1641  {
1642  case Viewer::ExamineMode:
1643  viewMouseEvent(&me);
1644  emit signalMouseEventClick (&me, true);
1645  break;
1646 
1647  case Viewer::LightMode:
1648  emit(signalMouseEventLight(&me));
1649  break;
1650 
1651  case Viewer::PickingMode: // give event to application
1652  emit(signalMouseEvent(&me, properties_.pickMode() ));
1653  emit(signalMouseEvent(&me));
1654  break;
1655 
1656  case Viewer::QuestionMode: // give event to application
1657  emit(signalMouseEventIdentify(&me));
1658  break;
1659  }
1660 }
1661 
1662 
1663 //-----------------------------------------------------------------------------
1664 
1665 
1666 void glViewer::mouseMoveEvent(QGraphicsSceneMouseEvent* _e)
1667 {
1668  QPoint p (_e->scenePos().x(), _e->scenePos().y());
1669  QMouseEvent me(QEvent::MouseMove ,p, _e->screenPos(), _e->button(),
1670  _e->buttons(), _e->modifiers());
1671  _e->accept();
1672 
1673  switch ( properties_.actionMode() )
1674  {
1675  case Viewer::ExamineMode:
1676  viewMouseEvent(&me);
1677  break;
1678 
1679  case Viewer::LightMode:
1680  emit(signalMouseEventLight(&me));
1681  break;
1682 
1683  case Viewer::PickingMode:
1684  // give event to application
1685  // deliver mouse moves with no button down, if tracking is enabled,
1686  if ((_e->buttons() & (Qt::LeftButton | Qt::MidButton | Qt::RightButton))
1687  || trackMouse_)
1688  {
1689  emit(signalMouseEvent(&me, properties_.pickMode() ));
1690  emit(signalMouseEvent(&me));
1691  }
1692  break;
1693 
1694  case Viewer::QuestionMode: // give event to application
1695  emit(signalMouseEventIdentify(&me));
1696  break;
1697 
1698  default: // avoid warning
1699  break;
1700  }
1701 }
1702 
1703 //-----------------------------------------------------------------------------
1704 
1705 
1706 void glViewer::mouseReleaseEvent(QGraphicsSceneMouseEvent* _e)
1707 {
1708  QPoint p (_e->scenePos().x(), _e->scenePos().y());
1709  QMouseEvent me(QEvent::MouseButtonRelease ,p, _e->screenPos(), _e->button(),
1710  _e->buttons(), _e->modifiers());
1711  _e->accept();
1712 
1713 // if (_event->button() == Qt::RightButton )
1714 // hidePopupMenus();
1715 
1716  if (_e->button() != Qt::RightButton || (properties_.actionMode() == Viewer::PickingMode) )
1717  {
1718  switch ( properties_.actionMode() )
1719  {
1720  case Viewer::ExamineMode:
1721  viewMouseEvent(&me);
1722 
1723  if (!clickTime_.isNull ())
1724  {
1725  int elapsed = clickTime_.elapsed ();
1726  QPoint diff = clickEvent_.pos () - me.pos ();
1727 
1728  if (abs (diff.x ()) <= 1 && abs (diff.y ()) <= 1 && elapsed <= QApplication::doubleClickInterval () / 2)
1729  {
1730  clickTimer_.setSingleShot (true);
1731  clickTimer_.setInterval (QApplication::doubleClickInterval () - elapsed);
1732  clickTimer_.start ();
1733  }
1734  else
1735  {
1736  clickTime_ = QTime ();
1737  clickTimer_.stop ();
1738  }
1739  }
1740  break;
1741 
1742  case Viewer::LightMode:
1743  emit(signalMouseEventLight(&me));
1744  break;
1745 
1746  case Viewer::PickingMode: // give event to application
1747  emit(signalMouseEvent(&me, properties_.pickMode() ));
1748  emit(signalMouseEvent(&me));
1749  break;
1750 
1751  case Viewer::QuestionMode: // give event to application
1752  emit(signalMouseEventIdentify(&me));
1753  break;
1754 
1755  default: // avoid warning
1756  break;
1757  }
1758  }
1759 
1760  isRotating_ = false;
1761 }
1762 
1763 
1764 //-----------------------------------------------------------------------------
1765 
1766 
1767 void glViewer::wheelEvent(QGraphicsSceneWheelEvent* _e)
1768 {
1769  QPoint p (_e->scenePos().x(), _e->scenePos().y());
1770  QWheelEvent we(p, _e->screenPos(), _e->delta(), _e->buttons(),
1771  _e->modifiers(), _e->orientation());
1772  _e->accept();
1773 
1774  switch ( properties_.actionMode() )
1775  {
1776  case Viewer::ExamineMode:
1777  viewWheelEvent(&we);
1778  break;
1779 
1780  case Viewer::PickingMode: // give event to application
1781  emit(signalWheelEvent(&we, properties_.pickMode() ));
1782  break;
1783 
1784  default: // avoid warning
1785  break;
1786  }
1787 
1788  isRotating_ = false;
1789 }
1790 
1791 //-----------------------------------------------------------------------------
1792 
1793 void glViewer::dragEnterEvent(QGraphicsSceneDragDropEvent* _e)
1794 {
1795  std::cerr << "dragEnter" << std::endl;
1796 
1797  QPoint p (_e->pos().x(), _e->pos().y());
1798  QDragEnterEvent de(p, _e->possibleActions(), _e->mimeData(), _e->buttons(),
1799  _e->modifiers ());
1800  emit dragEnterEvent(&de);
1801  _e->accept();
1802 }
1803 
1804 //-----------------------------------------------------------------------------
1805 
1806 
1807 void glViewer::dropEvent(QGraphicsSceneDragDropEvent* _e)
1808 {
1809  std::cerr << "drop" << std::endl;
1810 
1811  QPoint p (_e->pos().x(), _e->pos().y());
1812  QDropEvent de(p, _e->possibleActions(), _e->mimeData(), _e->buttons(),
1813  _e->modifiers ());
1814  emit dropEvent(&de);
1815  _e->accept();
1816 }
1817 
1818 //-----------------------------------------------------------------------------
1819 
1820 
1821 void glViewer::viewMouseEvent(QMouseEvent* _event) {
1822 
1823  if (navigationMode_ == NORMAL_NAVIGATION) {
1824 
1825  handleNormalNavigation(_event);
1826 
1827  } else if (navigationMode_ == FIRSTPERSON_NAVIGATION) {
1828 
1830  }
1831 
1832 }
1833 
1834 //----------------------------------------------------------------------------
1835 
1836 void glViewer::handleFirstPersonNavigation( QMouseEvent* _event) {
1837 
1838  // Ego-shooter navigation mode is selected
1839  QPointF f(mapFromScene(QPointF(_event->pos().x(), _event->pos().y())));
1840  QPoint pos(f.x(), f.y());
1841 
1842  switch (_event->type()) {
1843 
1844  case QEvent::MouseButtonPress: {
1845  lastPoint2D_ = pos;
1846  lookAround_ = true;
1847  break;
1848  }
1849 
1850  case QEvent::MouseButtonDblClick: {
1851  flyTo(_event->pos(), _event->button() == Qt::MidButton);
1852  break;
1853  }
1854 
1855  case QEvent::MouseMove: {
1856 
1857  if(!lookAround_) break;
1858 
1859  // Considering center point of screen as origin
1860  QPoint newpos = QPoint(pos.x() - glWidth() / 2, glHeight() / 2 - pos.y());
1861  QPoint oldpos = QPoint(lastPoint2D_.x() - glWidth() / 2, glHeight() / 2 - lastPoint2D_.y());
1862 
1863  double x = 2.0 * newpos.x() / glWidth();
1864  double y = 2.0 * newpos.y() / glHeight();
1865 
1866  double xo = 2.0 * oldpos.x() / glWidth();
1867  double yo = 2.0 * oldpos.y() / glHeight();
1868 
1869  double diffx = xo - x;
1870  double diffy = yo - y;
1871 
1874 
1875  rotate(yaxis, -diffx * 90, glstate_->eye());
1876  rotate(xaxis, diffy * 90, glstate_->eye());
1877 
1878  lastPoint2D_ = pos;
1879 
1880  updateGL();
1881  lastMoveTime_.restart();
1882 
1883  emit viewChanged();
1884 
1885  break;
1886  }
1887 
1888  case QEvent::MouseButtonRelease: {
1889  lookAround_ = false;
1890  break;
1891  }
1892 
1893  default: // avoid warning
1894  break;
1895  }
1896 }
1897 
1898 //----------------------------------------------------------------------------
1899 
1900 void glViewer::handleNormalNavigation( QMouseEvent* _event ) {
1901 
1902  makeCurrent();
1903  // Normal navigation mode is selected
1904  QPointF f(mapFromScene(QPointF(_event->pos().x(), _event->pos().y())));
1905  QPoint pos(f.x(), f.y());
1906 
1907  switch (_event->type()) {
1908 
1909  case QEvent::MouseButtonPress: {
1910 
1911  // Get the depth at the current mouse position ( projected )
1912  // This is used to do the translation in world coordinates
1913  // As the scene is rendered, we can get the depth directly from the framebuffer.
1914  GLfloat depth[1];
1915  GLint x2d = f.x() - scenePos().x();
1916  GLint y2d = glHeight() - (f.y() - scenePos().y());
1917  glReadPixels (x2d, y2d, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, depth);
1918  startDepth_ = depth[0];
1919 
1920  // shift key -> set rotation center
1921  if (_event->modifiers() & Qt::ShiftModifier) {
1922  ACG::Vec3d c;
1923  if (fast_pick(pos, c)) {
1925  properties_.trackballRadius( std::max(properties_.sceneRadius(), (c - glstate_->eye()).norm() * 0.9f) );
1926  }
1927  }
1928 
1930  lastPoint2D_ = pos;
1931  isRotating_ = true;
1932  timer_->stop();
1933 
1934  break;
1935  }
1936 
1937  case QEvent::MouseButtonDblClick: {
1938  flyTo(_event->pos(), _event->button() == Qt::MidButton);
1939  break;
1940  }
1941 
1942  case QEvent::MouseMove: {
1943  double factor = 1.0;
1944 
1945  if (_event->modifiers() == Qt::ShiftModifier)
1946  factor = properties_.wheelZoomFactorShift();
1947 
1948  // mouse button should be pressed
1949  if (_event->buttons() & (Qt::LeftButton | Qt::MidButton | Qt::RightButton)) {
1950  QPoint newPoint2D = pos;
1951 
1952  ACG::Vec3d newPoint3D;
1953  bool newPoint_hitSphere = mapToSphere(newPoint2D, newPoint3D);
1954 
1955  makeCurrent();
1956 
1957  // Left and middle button are pressed:
1958  // Translate along image planes normal direction -> zoom
1959  if ((_event->buttons() & Qt::LeftButton) && (_event->buttons() & Qt::MidButton)) {
1960  switch (projectionMode()) {
1961  case PERSPECTIVE_PROJECTION: {
1962  double value_y = properties_.sceneRadius() * ((newPoint2D.y() - lastPoint2D_.y())) * 3.0 / (double) glHeight();
1963  translate(ACG::Vec3d(0.0, 0.0, value_y * factor));
1964  updateGL();
1965  emit viewChanged();
1966  break;
1967  }
1968 
1969  case ORTHOGRAPHIC_PROJECTION: {
1970  double value_y = ((newPoint2D.y() - lastPoint2D_.y())) * properties_.orthoWidth() / (double) glHeight();
1971  properties_.orthoWidth( properties_.orthoWidth() - value_y * factor );
1973  updateGL();
1974  emit viewChanged();
1975  break;
1976  }
1977  }
1978  }
1979 
1980  // Middle button is pressed or if rotation is locked, left button can also be used
1981  // translation parallel to image plane
1982  // If an object was hit when the user started the translation,
1983  // the depth to the object is used to calculate the right translation vectors
1984  // such that the hitpoint stays below the mouse.
1985  else if ((_event->buttons() & Qt::MidButton) || (!allowRotation_ && (_event->buttons() & Qt::LeftButton)) ) {
1986 
1987  ACG::Vec3d translation;
1988 
1989 
1990  // if start depth is 1, no object was hit when starting translation
1991  if ( startDepth_ == 1 && projectionMode() != ORTHOGRAPHIC_PROJECTION ) {
1992  double value_x = properties_.sceneRadius() * ((newPoint2D.x() - lastPoint2D_.x())) * 2.0 / (double) glWidth();
1993  double value_y = properties_.sceneRadius() * ((newPoint2D.y() - lastPoint2D_.y())) * 2.0 / (double) glHeight();
1994  translation = ACG::Vec3d(value_x * factor, -value_y * factor, 0.0);
1995 
1996  } else {
1997  // Get the new mouse position in GL coordinates
1998  GLint x2dEnd = newPoint2D.x() - scenePos().x();
1999  GLint y2dEnd = glHeight() - (newPoint2D.y() - scenePos().y());
2000 
2001  // Get the last mouse position in GL coordinates
2002  GLint x2dStart = lastPoint2D_.x() - scenePos().x();
2003  GLint y2dStart = glHeight() - (lastPoint2D_.y() - scenePos().y());
2004 
2005  // unproject both to get translation vector
2006  ACG::Vec3d projectedStart(float(x2dStart),float(y2dStart),startDepth_);
2007  ACG::Vec3d projectedEnd(float(x2dEnd),float(y2dEnd),startDepth_);
2008  ACG::Vec3d unprojectedStart = glstate_->unproject(projectedStart);
2009  ACG::Vec3d unprojectedEnd = glstate_->unproject(projectedEnd);
2010 
2011  // calculate the difference and transform it with the modelview to get the right translation
2012  translation = unprojectedEnd - unprojectedStart;
2013  translation = glstate_->modelview().transform_vector(translation);
2014  }
2015 
2016  translate(translation);
2017 
2018  // left button pressed:
2019  // rotate the scene if rotation is not locked
2020  } else if (allowRotation_ && (_event->buttons() & Qt::LeftButton)) {
2021  ACG::Vec3d axis(1.0, 0.0, 0.0);
2022  double angle(0.0);
2023 
2024  if (lastPoint_hitSphere_) {
2025 
2026  if ((newPoint_hitSphere = mapToSphere(newPoint2D, newPoint3D))) {
2027  axis = lastPoint3D_ % newPoint3D;
2028  double cos_angle = (lastPoint3D_ | newPoint3D);
2029  if (fabs(cos_angle) < 1.0) {
2030  angle = acos(cos_angle) * 180.0 / M_PI * factor;
2031  angle *= 2.0; // inventor rotation
2032  }
2033  }
2034 
2035  rotate(axis, angle);
2036 
2037  }
2038 
2039  lastRotationAxis_ = axis;
2040  lastRotationAngle_ = angle;
2041  } else if (allowConstrainedRotation() && (_event->buttons() & Qt::RightButton)) {
2042  //ACG::Vec3d axis(constrainedRotationAxis_);
2043  //double angle(0.0);
2044 
2045  if (lastPoint_hitSphere_) {
2046 
2047  const QPoint dragVector = newPoint2D - lastPoint2D_;
2048  const double dragLength = dragVector.y();
2049  //ACG::Vec2d(dragVector.x(), dragVector.y()).norm();
2050  const double angle = -dragLength * factor;
2051 
2052  /*
2053  {
2054  makeCurrent();
2055  const ACG::Vec3d center =
2056  properties_.trackballCenter();
2057  const ACG::Vec3d t =
2058  startViewMatrix_.transform_point(center);
2059  glstate_->set_modelview(startViewMatrix_);
2060  glstate_->translate(-t[0], -t[1], -t[2],
2061  ACG::MULT_FROM_LEFT);
2062  glstate_->rotate(angle,
2063  constrainedRotationAxis_[0],
2064  constrainedRotationAxis_[1],
2065  constrainedRotationAxis_[2],
2066  ACG::MULT_FROM_LEFT);
2067  glstate_->translate(t[0], t[1], t[2],
2068  ACG::MULT_FROM_LEFT);
2069  }
2070  */
2071  ACG::Vec3d center(glWidth()/2.0, glHeight()/2.0, 0);
2072  rotate(constrainedRotationAxis_, angle, unproject(center));
2073 
2075  lastRotationAngle_ = angle;
2076  }
2077  }
2078 
2079  lastPoint2D_ = newPoint2D;
2080  lastPoint3D_ = newPoint3D;
2081  lastPoint_hitSphere_ = newPoint_hitSphere;
2082 
2083  updateGL();
2084  lastMoveTime_.restart();
2085  emit viewChanged();
2086  }
2087  break;
2088  }
2089 
2090  case QEvent::MouseButtonRelease: {
2091  lastPoint_hitSphere_ = false;
2092 
2093  // continue rotation ?
2094  if (isRotating_ && (_event->button() == Qt::LeftButton) && (!(_event->buttons() & Qt::MidButton))
2095  && (lastMoveTime_.elapsed() < 50) && properties_.animation())
2096  timer_->start(0);
2097  break;
2098  }
2099 
2100  default: // avoid warning
2101  break;
2102  }
2103 }
2104 
2105 //-----------------------------------------------------------------------------
2106 
2107 void glViewer::viewWheelEvent( QWheelEvent* _event)
2108 {
2109 
2110  // Default mouse wheel factor
2111  double factor = properties_.wheelZoomFactor();
2112 
2113  // Shift pressed, so we use the smaller factor
2114  if (_event->modifiers() == Qt::ShiftModifier)
2115  factor = properties_.wheelZoomFactorShift();
2116 
2117  // Mouse wheel inversion
2118  if (properties_.wheelInvert())
2119  factor *= -1.0;
2120 
2122  {
2123 
2124  // Control key : Modify field of view. Otherwise translate
2125  if ( _event->modifiers() & Qt::ControlModifier ) {
2126 
2127  // Most mouse types work in steps of 15 degrees, in which case the delta value is a
2128  // multiple of 120; i.e., 120 units * 1/8 = 15 degrees
2129  double numDegrees = double(_event->delta()) / 8.0;
2130  double numSteps = numDegrees / 15.0;
2131 
2132  // Update the fovy modifier
2133  // This modifier will be added to the default fov to get the zoom
2134  fovyModifier_ += numSteps * factor ;
2135 
2136  // Clamp to minimum
2137  if ( (OpenFlipperSettings().value("Core/Projection/FOVY", 45.0).toDouble() + fovyModifier_) < 1.0 )
2138  fovyModifier_ = 1.0 -OpenFlipperSettings().value("Core/Projection/FOVY", 45.0).toDouble();
2139 
2140  // Clamp to maximum
2141  if ( (OpenFlipperSettings().value("Core/Projection/FOVY", 45.0).toDouble() + fovyModifier_) > 179.0 )
2142  fovyModifier_ = 179.0-OpenFlipperSettings().value("Core/Projection/FOVY", 45.0).toDouble();
2143  } else {
2144 
2145 
2146  // Old style zoom (bad as it does not modify the projection but the modelview,
2147  // which kills e.g. Sky Boxes
2148  double d = -(double)_event->delta() / 120.0 * 0.2 * factor * properties_.trackballRadius() / 3.0;
2149  translate( ACG::Vec3d(0.0, 0.0, d) );
2150  }
2151 
2152 
2153 
2154  updateGL();
2155  }
2156  else
2157  {
2158  double d = (double)_event->delta() / 120.0 * 0.2 * factor * properties_.orthoWidth();
2160 
2161 
2163  updateGL();
2164  }
2165 
2166  emit viewChanged();
2167 }
2168 
2169 
2170 //-----------------------------------------------------------------------------
2171 
2172 
2173 bool glViewer::mapToSphere(const QPoint& _v2D, ACG::Vec3d& _v3D) const
2174 {
2175  if ( (_v2D.x() >= 0) && (_v2D.x() < (int)glWidth()) &&
2176  (_v2D.y() >= 0) && (_v2D.y() < (int)glHeight()) )
2177  {
2178  double x = (double)(_v2D.x() - ((double)glWidth() / 2.0)) / (double)glWidth();
2179  double y = (double)(((double)glHeight() / 2.0) - _v2D.y()) / (double)glHeight();
2180  double sinx = sin(M_PI * x * 0.5);
2181  double siny = sin(M_PI * y * 0.5);
2182  double sinx2siny2 = sinx * sinx + siny * siny;
2183 
2184  _v3D[0] = sinx;
2185  _v3D[1] = siny;
2186  _v3D[2] = sinx2siny2 < 1.0 ? sqrt(1.0 - sinx2siny2) : 0.0;
2187 
2188  return true;
2189  }
2190  else return false;
2191 }
2192 
2193 
2194 //-----------------------------------------------------------------------------
2195 
2196 
2198 {
2199  makeCurrent();
2201  updateGL();
2202 
2203  if (!properties_.updateLocked()) {
2204 
2205  static int msecs=0, count=0;
2206 
2207  msecs += frame_time_;
2208  if (count >= 10 && msecs >= 500) {
2209  char s[100];
2210  sprintf( s, "%.3f fps", (1000.0 * count / (float)msecs) );
2211  emit statusMessage(s,2000);
2212  count = msecs = 0;
2213  }
2214  else
2215  ++count;
2216  }
2217 }
2218 
2220 
2222 
2224 
2226 
2227  if (properties_.isCCWFront() )
2228  glFrontFace( GL_CCW );
2229  else
2230  glFrontFace( GL_CW );
2231 
2232  if ( properties_.backFaceCulling() )
2233  ACG::GLState::enable( GL_CULL_FACE );
2234  else
2235  ACG::GLState::disable( GL_CULL_FACE );
2236 
2237  // Make sure the right buffer is used in non stereo setup
2238  makeCurrent();
2239  ACG::GLState::drawBuffer(ACG::GLState::getFramebufferDraw() ? GL_COLOR_ATTACHMENT0 : GL_BACK);
2240 
2241  // Required for stereo toggling
2243 }
2244 
2246  makeCurrent();
2247  applyProperties();
2248  updateGL();
2249 }
2250 
2251 void glViewer::snapshot(QImage& _image, int _width, int _height, bool _alpha, bool _hideCoordsys, int samples) {
2252  makeCurrent();
2253 
2254  int w = 0, h = 0, bak_w = 0, bak_h = 0, left = 0, bottom = 0;
2255 
2258 
2259  // Get viewport data
2260  glstate_->get_viewport(left, bottom, w, h);
2261  double aspect = (double)w / (double)h;
2262 
2263  // Test if size is given:
2264  if(_width != 0 || _height != 0) {
2265 
2266  // Adapt dimensions if aspect ratio is demanded
2267  if(_width == 0) {
2268  _width = (int)((double)_height * aspect);
2269  }
2270  if(_height == 0) {
2271  _height = (int)((double)_width / aspect);
2272  }
2273  bak_w = w;
2274  bak_h = h;
2275  w = _width;
2276  h = _height;
2277 
2278  // Set new viewport
2279  glstate_->viewport(0, 0, w, h);
2280  aspect = (double)w / (double)h;
2281  }
2282 
2283  QFramebufferObject* fb = nullptr;
2284  GLuint hnd;
2285 
2286  if ( createQFBO(fb,&hnd,w,h,&samples) ){
2287 
2288  const GLuint prevFbo = ACG::GLState::getFramebufferDraw();
2289 
2290  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, hnd);
2291 
2292  // Turn alpha on if demanded
2293  ACG::Vec4f backColorBak;
2294  ACG::Vec4f newBack;
2295 
2296  bool formerCoordsysState = true;
2297  // Hide coordsys node if demanded
2298  if(_hideCoordsys) {
2299  // Find coordsys node
2300  ACG::SceneGraph::BaseNode* node = 0;
2301  node = sceneGraphRoot_->find("Core Coordsys Node");
2302  if(node != 0) {
2303  formerCoordsysState = node->visible();
2304  node->hide();
2305  } else {
2306  emit statusMessage(QString(tr("Could not find coordsys node, thus it will appear in the snapshot anyway.")));
2307  }
2308  }
2309 
2310  backColorBak = properties()->backgroundColor();
2311 
2312  newBack = ACG::Vec4f(backColorBak[0], backColorBak[1], backColorBak[2], (_alpha ? 0.0f : 1.0f));
2313  properties()->backgroundColor(newBack);
2314 
2315  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2316 
2317  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2318 
2319  // adjust blend function for alpha channel
2320  ACG::GLState::blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
2322 
2323  glEnable(GL_MULTISAMPLE);
2324  paintGL(aspect);
2325  glFinish();
2326 
2328 
2329  glDisable(GL_MULTISAMPLE);
2330 
2331  //Qt FrameBuffer "toImage" function returns QImage::Format_ARGB32_Premultiplied. not desired
2332  QFramebufferObject* temp = nullptr;
2333  GLuint tempHnd;
2334  int testSamples = -1;
2335  createQFBO(temp, &tempHnd, w, h, &testSamples);
2336  if (samples != 0)
2337  {
2338  //cannot directly read from a multisampled framebuffer.
2339  //create new one without sampling and read from it
2340  QRect rect(QPoint(0, 0), QSize(w,h));
2341 
2342  blitQFBO(temp, rect, fb, rect);
2343  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, tempHnd);
2344  }
2345 
2346  //get the framebuffer data
2347  _image = QImage(w,h,QImage::Format_ARGB32);
2348  glReadPixels(0,0,w,h,GL_BGRA,GL_UNSIGNED_INT_8_8_8_8_REV,reinterpret_cast<void*>(_image.bits()));
2349  _image = _image.mirrored(false,true);//convert from opengl to qt coordinates
2350 
2351 
2352  //cleanup
2353  ACG::GLState::bindFramebuffer(GL_FRAMEBUFFER_EXT, prevFbo);
2354 
2355  // Reset alpha settings
2356  if(_alpha)
2357  properties()->backgroundColor(backColorBak);
2358 
2359  if(_hideCoordsys) {
2360  // Find coordsys node
2361  ACG::SceneGraph::BaseNode* node = 0;
2362  node = sceneGraphRoot_->find("Core Coordsys Node");
2363  if(node != 0 && formerCoordsysState) {
2364  node->show();
2365  }
2366  }
2367 
2368  deleteQFBO(temp);
2369  }
2370 
2371  deleteQFBO(fb);
2372 
2373 
2374  if(_width != 0 || _height != 0) {
2375  // Reset viewport to former size
2376  glstate_->viewport(left, bottom, bak_w, bak_h);
2377  }
2378 
2381 }
2382 
2383 
2384 void glViewer::snapshot( int _width, int _height, bool _alpha, bool _hideCoordsys, int samples)
2385 {
2386  QImage image;
2387 
2388  // Capture image
2389  snapshot(image, _width, _height, _alpha, _hideCoordsys, samples);
2390 
2391  /*
2392  * Meta data
2393  */
2394  QString comments = PluginFunctions::collectObjectComments(true, false).join("\n");
2395  if (!comments.isEmpty())
2396  image.setText("Mesh Comments", comments);
2397  QString view;
2398  encodeView(view);
2399  image.setText("View", view);
2400 
2401  QFileInfo fi(properties_.snapshotName());
2402 
2403  QString fname = fi.path() + QDir::separator() +fi.baseName() + "." + QString::number(properties_.snapshotCounter()).rightJustified(7,'0') + "." + properties_.snapshotFileType().toLower();
2404 
2405  QImageWriter writer(fname);
2406  writer.setFormat(properties_.snapshotFileType().simplified().toLatin1());
2407 
2408  bool rval = writer.canWrite();
2409  if (rval)
2410  writer.write(image);
2411 
2412  if (rval)
2413  emit statusMessage (QString(tr("Snapshot: "))+fname,5000);
2414  else
2415  emit statusMessage (QString(tr("Could not save snapshot to ")) + fname + QString(tr(" Error: ")) + writer.errorString() );
2416 }
2417 
2418 void glViewer::slotHideWheels() {
2419  if (isVisible())
2420  {
2421  wheelX_->hide();
2422  wheelY_->hide();
2423  wheelZ_->hide();
2424  }
2425  else
2426  {
2427  show ();
2428  wheelX_->hide();
2429  wheelY_->hide();
2430  wheelZ_->hide();
2431  hide ();
2432  }
2433 }
2434 
2435 void glViewer::slotShowWheels() {
2436  if (isVisible())
2437  {
2438  wheelX_->show();
2439  wheelY_->show();
2440  wheelZ_->show();
2441  }
2442  else
2443  {
2444  show ();
2445  wheelX_->show();
2446  wheelY_->show();
2447  wheelZ_->show();
2448  hide ();
2449  }
2450 }
2451 
2452 bool glViewer::wheelsVisible() {
2453  // TODO: Return valid values
2454  return true;
2455 }
2456 
2457 //-----------------------------------------------------------------------------
2458 
2460 {
2461  emit signalMouseEventClick (&clickEvent_, false);
2462 }
2463 
2464 //-----------------------------------------------------------------------------
2465 
2467 {
2468  properties_.cursorPainter( _cursorPainter );
2469 }
2470 
2471 //-----------------------------------------------------------------------------
2472 
2473 void glViewer::updateCursorPosition (QPointF _scenePos)
2474 {
2475  if (!initialized_ || !sceneGraphRoot_ || !isVisible ())
2476  return;
2477 
2478  ACG::Vec3d tmp;
2479 
2480  size_t nodeIdx = 0;
2481  size_t targetIdx = 0;
2482 
2483 
2484  // ignore cursor if we are outside of our window
2485  if (!mapRectToScene(boundingRect ()).intersects (properties_.cursorPainter()->cursorBoundingBox().translated(_scenePos)))
2486  {
2488  }
2489  // only do real pick in stereo mode
2490  else if ( properties_.stereo() && OpenFlipperSettings().value("Core/Gui/glViewer/stereoMousePick",true).toBool() &&
2491  pick (ACG::SceneGraph::PICK_ANYTHING, _scenePos.toPoint(), nodeIdx, targetIdx, &tmp))
2492  {
2493  // the point we get back will contain the view transformation and we have to revert it
2496  }
2497  // only do real pick in stereo mode
2498  else
2499  {
2501 
2502  // reset modelview to ignore the view transformation
2504 
2505  // Project the depth value of the stereo mode zero paralax plane.
2506  // We need to use this depth to to get the cursor exactly on zero paralax plane in stereo mode
2507  double zerop = properties_.nearPlane() + ((properties_.farPlane() - properties_.nearPlane()) * OpenFlipperSettings().value("Core/Stereo/FocalLength").toDouble() );
2508  ACG::Vec3d zerod = glstate_->project (ACG::Vec3d (0.0, 0.0, -zerop));
2509 
2510  // unproject the cursor into the scene
2511  properties_.cursorPoint3D( glstate_->unproject (ACG::Vec3d (_scenePos.x(), scene()->height () - _scenePos.y(), zerod[2])) );
2512 
2514 
2516  }
2517 }
2518 
2519 //-----------------------------------------------------------------------------
2520 
2521 
2523  if(navigationMode_ == FIRSTPERSON_NAVIGATION) {
2524 
2526 
2527  dir *= -0.1;
2528 
2529  glstate_->translate(dir[0], dir[1], dir[2]);
2530 
2531  updateGL();
2532  lastMoveTime_.restart();
2533 
2534  emit viewChanged();
2535  }
2536 }
2537 
2539  if(navigationMode_ == FIRSTPERSON_NAVIGATION) {
2541 
2542  dir *= 0.1;
2543 
2544  glstate_->translate(dir[0], dir[1], dir[2]);
2545 
2546  updateGL();
2547  lastMoveTime_.restart();
2548 
2549  emit viewChanged();
2550  }
2551 }
2552 
2554  if(navigationMode_ == FIRSTPERSON_NAVIGATION) {
2555  ACG::Vec3d dir = glstate_->right();
2556 
2557  dir *= 0.1;
2558 
2559  glstate_->translate(dir[0], dir[1], dir[2]);
2560 
2561  updateGL();
2562  lastMoveTime_.restart();
2563 
2564  emit viewChanged();
2565  }
2566 }
2567 
2569  if(navigationMode_ == FIRSTPERSON_NAVIGATION) {
2570  ACG::Vec3d dir = glstate_->right();
2571 
2572  dir *= -0.1;
2573 
2574  glstate_->translate(dir[0], dir[1], dir[2]);
2575 
2576  updateGL();
2577  lastMoveTime_.restart();
2578 
2579  emit viewChanged();
2580  }
2581 }
2582 
2583 
2584 
2585 void glViewer::computeProjStereo( int _viewportWidth, int _viewportHeight, Viewer::ViewerProperties& _properties, ACG::GLMatrixd* _outLeft, ACG::GLMatrixd* _outRight )
2586 {
2587  double l, r, t, b, w, h, a, radians, wd2, ndfl, zerop, xrange;
2588 
2589  w = double(_viewportWidth);
2590  h = double(_viewportHeight);
2591  a = w / h;
2592 
2593  double fovy = OpenFlipperSettings().value("Core/Projection/FOVY", 45.0).toDouble();
2594  radians = fovy * 0.5 / 180.0 * M_PI;
2595  wd2 = _properties.nearPlane() * tan(radians);
2596  zerop = _properties.nearPlane() + ((_properties.farPlane() - _properties.nearPlane()) * OpenFlipperSettings().value("Core/Stereo/FocalDistance", 0.5).toDouble() );
2597  ndfl = _properties.nearPlane() / zerop ;
2598  xrange = a * wd2 * 2 * zerop / _properties.nearPlane();
2599 
2600  l = -a*wd2;
2601  r = a*wd2;
2602  t = wd2;
2603  b = -wd2;
2604 
2605  double offset = 0.5 * OpenFlipperSettings().value("Core/Stereo/EyeDistance", 0.07).toDouble() * xrange;
2606  double offset2 = offset * ndfl;
2607 
2608  if (_outLeft)
2609  {
2610  _outLeft->identity();
2611  _outLeft->frustum(l+offset2, r+offset2, b, t, _properties.nearPlane(), _properties.farPlane());
2612  _outLeft->translate(offset, 0.0, 0.0);
2613  }
2614 
2615  if (_outRight)
2616  {
2617  _outRight->identity();
2618  _outRight->frustum(l-offset2, r-offset2, b, t, _properties.nearPlane(), _properties.farPlane());
2619  _outRight->translate(-offset, 0.0, 0.0);
2620  }
2621 }
2622 
2623 
2624 //=============================================================================
2625 //=============================================================================
2626 
virtual void toggleProjectionMode()
toggle projection mode
double near_plane() const
Returns a chili cheese burger.
void animation(bool _state)
set 2-sided lighting on/off
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
Definition: GLState.cc:1507
virtual QSize sizeHint() const
reimplemented
Definition: QtWheel.cc:425
double sceneRadius()
Get radius of the current scene.
virtual void slotWheelY(double _dAngle)
process signals from wheelX_
unsigned int glWidth() const
get width of QGLWidget
void reset_modelview()
reset modelview matrix (load identity)
Definition: GLState.cc:370
static void blendFuncSeparate(GLenum _srcRGB, GLenum _dstRGB, GLenum _srcAlpha, GLenum _dstAlpha)
replaces glBlendFuncSeparate, supports locking
Definition: GLState.cc:1621
Vec3d viewing_direction() const
get viewing ray
Definition: GLState.hh:848
glViewer(QGraphicsScene *_scene, OFGLWidget *_glWidget, Viewer::ViewerProperties &_properties, QGraphicsWidget *_parent=0)
NormalsMode normalsMode() const
get treatment of normals
ACG::Vec3d unproject(const ACG::Vec3d &pt)
Framebuffer object that holds the pick cache.
void pop_modelview_matrix()
pop modelview matrix
Definition: GLState.cc:1026
double nearPlane()
Return distance to near Plane.
virtual void flyTo(const QPoint &_pos, bool _moveBack)
Animated flight to or away from a given point.
void set_clear_color(const Vec4f &_col)
set background color
Definition: GLState.cc:662
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *_event)
handle mouse release events
static void shadeModel(GLenum _mode)
replaces glShadeModel, supports locking
Definition: GLState.cc:1729
void trackMouse(bool _track)
Enable/disable mouse tracking (move events with no button press)
void resolveStereoAnyglyph(int _viewerID)
Resolve stereo buffers as anaglyph.
QSize glSize() const
get size of QGLWIdget
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *_event)
handle mouse move events
void setScenePos(const ACG::Vec3d &_center, double _radius, const bool _resetTrackBall=false)
QMouseEvent clickEvent_
mouse interaction position
bool updatePickCache_
Should the pick cache be updated.
double far_plane() const
Returns a peanut butter sandwich.
bool enabled()
Returns true if cursor painting is enabled and compatible cursor is set.
void twoSidedLighting(bool _state)
set 2-sided lighting on/off
QPoint glMapFromGlobal(const QPoint &_pos) const
map global to glarea coords
Vec3d up() const
get up-vector w.r.t. camera coordinates
Definition: GLState.cc:906
void viewport(int _left, int _bottom, int _width, int _height, int _glwidth=0, int _glheight=0)
set viewport (lower left corner, width, height, glcontext width, height)
Definition: GLState.cc:470
void updateCursorPosition(QPointF _scenePos)
will be called from CursorPainter to inform the viewer that the cursor position changed ...
void signalWheelEvent(QWheelEvent *, const std::string &)
Emitted in Pick mode. Uses pick mode.
virtual bool blendForStencilRefBit(GLuint _refbit, GLenum &_src, GLenum &_dst, ACG::Vec4f &_color)
void actionPasteView(QSize *_windowSize=NULL, int *_splitterWidth=NULL)
void setPlanes(double _near, double _far)
Set near and far plane at the same time.
double wheelZoomFactorShift()
Zoom factor when using mouse wheel and pressing shift.
void signalSceneGraphChanged(ACG::SceneGraph::BaseNode *_root)
scene graph has changed
void encodeView(QString &_view, const QSize &_windowSize=QSize(-1,-1), const int _toolBarWidth=-1, const bool _make_c_string=false)
virtual void makeCurrent()
Makes this widget the current widget for OpenGL operations.
int viewport_width() const
get viewport width
Definition: GLState.hh:822
void signalMakeActive()
make this widget active
void push_projection_matrix()
push projection matrix
Definition: GLState.cc:971
void setglState(ACG::GLState *_glState)
Pointer to the glState of the Viewer.
void rotate(const ACG::Vec3d &axis, double angle)
rotate the scene (around its center) and update modelview matrix
void viewWheelEvent(QWheelEvent *_event)
specialized viewer: handle wheel events
Vec3d project(const Vec3d &_point) const
project point in world coordinates to window coordinates
Definition: GLState.cc:640
void strafeLeft()
First person navigation: Strafe left.
VectorT< float, 4 > Vec4f
Definition: VectorT.hh:138
unsigned int glHeight() const
get height of QGLWidget
static void lockBlendFuncSeparate(bool _rgb=true, bool _alpha=true)
lock blend func
Definition: GLState.hh:328
ACG::Vec3d constrainedRotationAxis_
mouse interaction position
virtual void render(ACG::GLState *_glState, Viewer::ViewerProperties &_properties)
rendering function
void show()
Show node: set status to Active.
Definition: BaseNode.hh:407
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
Definition: GLState.cc:1868
virtual void moveEvent(QGraphicsSceneMoveEvent *_e)
handle move events
STL namespace.
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node
void drawMode(ACG::SceneGraph::DrawModes::DrawMode _mode)
set draw mode (No test if this mode is available!)
NavigationMode navigationMode() const
get current navigation mode
Viewer::ViewerProperties * properties()
Returns a pointer to the Viewer Status.
void setProjectionMode(const ProjectionMode _mode)
set mode to either ORTHOGRAPHIC_PROJECTION or PERSPECTIVE_PROJECTION
void get_viewport(int &_left, int &_bottom, int &_width, int &_height) const
get viewport
Definition: GLState.hh:816
void setCoordSysProjection(glViewer::ProjectionMode _mode)
helper function for setting the projection mode of the coordinate system node
Viewer::ActionMode actionMode()
get the action mode
void translate(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with translation matrix (x,y,z)
ACG::Vec3d trackballCenter()
Get virtual trackball center (rotation center when using mouse)
int setupScene(int _viewerID, int _width, int _height, int _samples=0, int _stereoEye=-1)
Bind fbo for scene rendering.
void startDragEvent(QMouseEvent *_event)
QStringList collectObjectComments(bool visibleOnly, bool targetedOnly)
void identity()
setup an identity matrix
void applyProperties()
virtual void resizeEvent(QGraphicsSceneResizeEvent *_e)
handle resize events
const QStringList ALL_OBJECTS
Iterable object range.
double trackballRadius()
Get trackball radius (rotation sphere when using mouse)
CursorPainter * cursorPainter()
Flag if stereo should be enabled for the current viewer.
RendererInfo * active(int _id)
Get the current active renderer.
virtual void viewAll()
view the whole scene
bool fast_pick(const QPoint &_mousePos, ACG::Vec3d &_hitPoint)
ACG::Vec3d lastPoint3D_
mouse interaction position
void translate(const ACG::Vec3d &trans)
translate the scene and update modelview matrix
void signalMouseEvent(QMouseEvent *, const std::string &)
VectorT< T, 3 > transform_point(const VectorT< T, 3 > &_v) const
transform point (x&#39;,y&#39;,z&#39;,1) = M * (x,y,z,1)
double wheelZoomFactor()
Zoom factor when using mouse wheel.
void actionCopyView(const QSize &_windowSize=QSize(-1,-1), const int _splitterWidth=-1, const bool _make_c_string=false)
void traverse_multipass(BaseNode *_node, Action &_action, const unsigned int &_pass)
Definition: SceneGraph.hh:254
ProjectionMode projectionMode() const
get current projection mode
void viewChanged()
This signal is emitted whenever the view is changed by the user.
void viewingDirection(const ACG::Vec3d &_dir, const ACG::Vec3d &_up)
set the viewing direction
ACG::Vec3d lastRotationAxis_
mouse interaction position
virtual void setFOVY(double _fovy)
Set fovy.
virtual void orthographicProjection()
set orthographic view (projectionMode(ORTHOGRAPHIC_PROJECTION))
QPoint glMapToGlobal(const QPoint &_pos) const
map glarea coords to global coords
void postProcess(int _viewerID, ACG::GLState *_glstate, const ACG::GLMatrixd &_modelview, const ACG::GLMatrixd &_proj1, const ACG::GLMatrixd &_proj2, bool _hwOpenGLStereo=false)
Perform all post processing.
bool backFaceCulling()
Get current state of backface culling.
void set_bounding_box(ACG::Vec3d _min, ACG::Vec3d _max)
Definition: GLState.cc:806
static GLuint getFramebufferDraw()
get current draw framebuffer of a target
Definition: GLState.cc:2074
void objectMarker(ViewObjectMarker *_marker)
set object marker for viewer
virtual void paintGL(double _aspect=0.0)
draw the scene. Triggered by updateGL().
void signalMouseEventClick(QMouseEvent *, bool _double)
void reset_projection()
reset projection matrix (load identity)
Definition: GLState.cc:334
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
virtual void mousePressEvent(QGraphicsSceneMouseEvent *_event)
handle mouse press events
NavigationMode
Navigation mode.
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *_event)
handle mouse double click events
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:651
double lastRotationAngle_
mouse interaction position
virtual void perspectiveProjection()
set perspective view (projectionMode(PERSPECTIVE_PROJECTION))
virtual void slotWheelZ(double _dist)
process signals from wheelZ_
Mark per returned reference bits.
void push_modelview_matrix()
push modelview matrix
Definition: GLState.cc:1010
void set_modelview(const GLMatrixd &_m)
set modelview
Definition: GLState.hh:728
QTime lastMoveTime_
mouse interaction position
bool initialized_
Have the viewer gl properties been initalized.
void perspective(double _fovY, double _aspect, double _near_plane, double _far_plane)
perspective projection
Definition: GLState.cc:448
Vec3d right() const
get right-vector w.r.t. camera coordinates
Definition: GLState.cc:918
void set_msSinceLastRedraw(unsigned int _ms)
set time passed since last redraw in milliseconds
Definition: GLState.hh:241
ProjectionMode
projection mode
const GLMatrixd & inverse_modelview() const
get inverse modelview matrix
Definition: GLState.hh:811
NormalsMode
Automatically normalize normals?
virtual bool stencilRefForObject(BaseObjectData *_obj, GLuint &_reference)=0
virtual void setHome()
set home position
void slotPropertiesUpdated()
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
Definition: GLState.cc:1527
bool allowConstrainedRotation()
mouse interaction position
virtual void setView(const ACG::GLMatrixd &_modelview, const ACG::GLMatrixd &_inverse_modelview)
set view, used for synchronizing
void slotClickTimeout()
Handle click timeout.
void setCursor(const QCursor &_cursor)
Sets the current used cursor.
QRectF cursorBoundingBox()
Bounding box of the cursor.
void allow_multisampling(bool _b)
Disable multisampling globally.
Definition: GLState.hh:1051
void viewMouseEvent(QMouseEvent *_event)
specialized viewer: hande mouse events
void moveForward()
First person navigation: Move forward.
static bool decodeView(const QString &_view, ACG::GLMatrixd &m, ACG::GLMatrixd &p, int &pMode, double &ortho_width, QSize *_windowSize=NULL, int *_splitterWidth=NULL, QSize *_viewportSize=NULL)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
pick any of the prior targets (should be implemented for all nodes)
Definition: PickTarget.hh:84
void ortho(double _left, double _right, double _bottom, double _top, double _near_plane, double _far_plane)
orthographic projection
Definition: GLState.cc:402
void setCoreProfileMode(bool _enable)
Tell renderer to use core or compatibility profile.
Definition: IRenderer.hh:483
void signalMouseEventIdentify(QMouseEvent *)
double ortho_width() const
Get width of the gl scene in orthogonal projection mode.
void analyzeSceneGraph(ACG::SceneGraph::BaseNode *_root, unsigned int &_maxPasses, ACG::Vec3d &_bbmin, ACG::Vec3d &_bbmax)
Analyze the SceneGraph <ACG/Scenegraph/SceneGraphAnalysis.hh>
virtual bool blendForStencilRefNumber(GLuint _reference, GLenum &_src, GLenum &_dst, ACG::Vec4f &_color)
bool wheelInvert()
Invert mouse wheel direction?
int viewport_height() const
get viewport height
Definition: GLState.hh:824
void hide()
Hide Node: set status to HideNode.
Definition: BaseNode.hh:405
void updateProjectionMatrix(double _aspect=0.0)
updates projection matrix
VectorT< T, 3 > transform_vector(const VectorT< T, 3 > &_v) const
transform vector (x&#39;,y&#39;,z&#39;,0) = A * (x,y,z,0)
ACG::Vec3d cursorPoint3D()
Flag if stereo should be enabled for the current viewer.
void paintCursor(ACG::GLState *_state)
Cursor painting function. The _state has to be setup that 0,0,0 is at the cursor position.
void set_max_render_passes(const unsigned int _max)
set maximum number of render passes
Definition: GLState.hh:996
void handleNormalNavigation(QMouseEvent *_event)
Navigate through scene if normal mode has been selected.
void snapshotCounter(const int _counter)
ACG::Vec4f backgroundColor()
Get current background color.
void addWheelX(QGraphicsWidget *_item)
Add Wheel Widget to Layout.
void pop_projection_matrix()
pop projection matrix
Definition: GLState.cc:989
void clearBuffers()
clear buffers viewport rectangle
Definition: GLState.cc:266
static void blendFunc(GLenum _sfactor, GLenum _dfactor)
replaces glBlendFunc, supports locking
Definition: GLState.hh:307
void setCursorPainter(CursorPainter *_cursorPainter)
sets the current cursor painter
static GLuint getFramebufferRead()
get current read framebuffer of a target
Definition: GLState.cc:2082
virtual void toggleNavigationMode()
toggle navigation mode
void signalCustomContextMenuRequested(const QPoint &)
void stereo(bool _stereo)
Flag if stereo should be enabled for the current viewer.
QPoint lastPoint2D_
mouse interaction position
void rotate(double _angle, double _x, double _y, double _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
rotate around axis (_x, _y, _z) by _angle
Definition: GLState.cc:564
static double deg(double _angle)
maps _angle from radiants to degrees (works also for clip()ped angles)
Definition: QtWheel.cc:440
static double clip(double _angle)
Definition: QtWheel.cc:436
QFramebufferObject * mouseCache_
Framebuffer object that holds the pick cache.
use provided normals as is
void viewUpdated()
This signal is emitted when the scene is repainted due to any event.
void signalMouseEventLight(QMouseEvent *)
void drawCursor()
draw the cursor
void strafeRight()
First person navigation: Strafe Right.
virtual void snapshot(int _width=0, int _height=0, bool _alpha=false, bool _hideCoordsys=false, int samples=1)
bool mapToSphere(const QPoint &_p, ACG::Vec3d &_result) const
virtual trackball: map 2D screen point to unit sphere
bool lastPoint_hitSphere_
mouse interaction position
void slotAnimation()
mouse interaction position
void multisampling(bool _state)
set multisampling on/off
unsigned int activeId(int _id)
Get the id of the active renderer.
void lookAt(const ACG::Vec3d &_eye, const ACG::Vec3d &_center, const ACG::Vec3d &_up)
Set look at transformation directly.
bool visible()
Is node visible (status == Active)?
Definition: BaseNode.hh:409
void unLockUpdate()
Unlock display locked by updateLock().
double fovyModifier_
mouse interaction position
float startDepth_
mouse interaction depth
std::string pickMode()
get active pick mode
int numActive(int _id)
Get the number of active post processors for viewer.
void snapshotFileType(const QString &_type)
virtual void initializeGL()
Return a resonable size hint.
virtual void slotWheelX(double _dAngle)
process signals from wheelX_
bool cursorPositionValid()
Flag if stereo should be enabled for the current viewer.
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:791
void handleFirstPersonNavigation(QMouseEvent *_event)
Navigate through scene if first person mode has been selected.
void grabGLArea()
get all Mouse & Key Events for GlWidget
void initModelviewMatrix()
initialize modelview matrix to identity
virtual void dragEnterEvent(QGraphicsSceneDragDropEvent *_e)
drag & drop for modelview copying
int viewerId()
Get the id of the viewer this viewerproperties belongs to.
virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *_e)
handle mouse press events
QTimer * timer_
mouse interaction position
virtual void updateGL()
Redraw scene. Triggers paint event for updating the view (cf. drawNow()).
double aspect_ratio() const
Returns the viewer&#39;s aspect ratio.
static void bindFramebuffer(GLenum _target, GLuint _framebuffer)
replaces glBindFramebuffer, supports locking
Definition: GLState.cc:2089
ChildIter find(BaseNode *_node)
Definition: BaseNode.hh:346
void set_projection(const GLMatrixd &_m)
set projection
Definition: GLState.hh:691
void frustum(Scalar left, Scalar right, Scalar bottom, Scalar top, Scalar near_plane, Scalar far_plane)
multiply self with a perspective projection matrix
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
ACG::Vec3d sceneCenter()
Get current scene center (rendering center)
Interface to add additional rendering functions from within plugins.
void set_twosided_lighting(bool _b)
set whether transparent or solid objects should be drawn
Definition: GLState.cc:822
virtual ~glViewer()
Destructor.
void setState()
set the whole stored gl state
Definition: GLState.cc:209
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
QOpenGLFramebufferObject QFramebufferObject
Framebuffer object that holds the pick cache.
static void drawBuffer(GLenum _mode)
replaces glDrawBuffer, supports locking
Definition: GLState.cc:2033
void releaseGLArea()
undo grabbing GLArea
void lookAt(const Vec3d &_eye, const Vec3d &_center, const Vec3d &_up)
set camera by lookAt
Definition: GLState.cc:515
void setViewerID(int _viewerID)
Set currently active viewer id.
Definition: IRenderer.cc:1519
const GLMatrixd & projection() const
get projection matrix
Definition: GLState.hh:786
virtual void dropEvent(QGraphicsSceneDragDropEvent *_e)
drag & drop for modelview copying
bool allowRotation_
mouse interaction position
virtual void home()
go to home pos
static void unlockBlendFuncSeparate()
unlock blend func
Definition: GLState.hh:330
QTime clickTime_
mouse interaction position
virtual void wheelEvent(QGraphicsSceneWheelEvent *_event)
handle mouse wheel events
double orthoWidth()
Get width of the gl scene in orthogonal projection mode (defaults to 2.0)
const DataType DATA_ALL(UINT_MAX)
Identifier for all available objects.
static void bindBuffer(GLenum _target, GLuint _buffer)
replaces glBindBuffer, supports locking
Definition: GLState.cc:1820
Viewer::ViewerProperties & properties_
All properties for this viewer.
Vec3d eye() const
get eye point
Definition: GLState.cc:886
void moveBack()
First person navigation: Move back.
void computeProjStereo(int _width, int _height, Viewer::ViewerProperties &_properties, ACG::GLMatrixd *_outLeft, ACG::GLMatrixd *_outRight)
Compute left and right eye projection matrix for stereo rendering.
void translate(double _x, double _y, double _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
translate by (_x, _y, _z)
Definition: GLState.cc:533
QTimer clickTimer_
mouse interaction position
static void activeTexture(GLenum _texunit)
replaces glActiveTexture, no locking support
Definition: GLState.cc:1857
void sceneGraph(ACG::SceneGraph::BaseNode *_root, unsigned int _maxPasses, ACG::Vec3d _bbmin, ACG::Vec3d _bbmax, const bool _resetTrackBall=false)
void initialize()
initialize all state variables (called by constructor)
Definition: GLState.cc:162
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121
ACG::GLState * glstate_
Gl State.
PostProcessing * postproc_
Post-Processing executor.
double farPlane()
Return distance to far Plane.
bool pick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, size_t &_nodeIdx, size_t &_targetIdx, ACG::Vec3d *_hitPointPtr=0)