Developer Documentation
QGLViewerWidget.cc
1 /* ========================================================================= *
2  * *
3  * OpenMesh *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openmesh.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenMesh. *
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  * $Revision$ *
45  * $Date$ *
46  * *
47 \*===========================================================================*/
48 
49 //== INCLUDES =================================================================
50 
51 #ifdef _MSC_VER
52 # pragma warning(disable: 4267 4311 4305)
53 #endif
54 
55 #include <iomanip>
56 #include <iostream>
57 #include <sstream>
58 #include <algorithm>
59 // --------------------
60 #ifdef ARCH_DARWIN
61 # include <glut.h>
62 #else
63 # include <GL/glut.h>
64 #endif
65 // --------------------
66 #include <QApplication>
67 #include <QMenu>
68 #include <QCursor>
69 #include <QImage>
70 #include <QDateTime>
71 #include <QMouseEvent>
72 // --------------------
73 #include <OpenMesh/Apps/QtViewer/QGLViewerWidget.hh>
75 
76 #if !defined(M_PI)
77 # define M_PI 3.1415926535897932
78 #endif
79 
80 const double TRACKBALL_RADIUS = 0.6;
81 
82 
83 using namespace Qt;
84 using namespace OpenMesh;
85 
86 
87 //== IMPLEMENTATION ==========================================================
88 
89 std::string QGLViewerWidget::nomode_ = "";
90 
91 //----------------------------------------------------------------------------
92 
93 QGLViewerWidget::QGLViewerWidget( QWidget* _parent )
94  : QGLWidget( _parent )
95 {
96  init();
97 }
98 
99 //----------------------------------------------------------------------------
100 
101 QGLViewerWidget::
102 QGLViewerWidget( QGLFormat& _fmt, QWidget* _parent )
103  : QGLWidget( _fmt, _parent )
104 {
105  init();
106 }
107 
108 
109 //----------------------------------------------------------------------------
110 
111 void
112 QGLViewerWidget::init(void)
113 {
114  // qt stuff
115  setAttribute(Qt::WA_NoSystemBackground, true);
116  setFocusPolicy(Qt::StrongFocus);
117  setAcceptDrops( true );
118  setCursor(PointingHandCursor);
119 
120 
121  // popup menu
122 
123  popup_menu_ = new QMenu(this);
124  draw_modes_group_ = new QActionGroup(this);
125 
126  connect( draw_modes_group_, SIGNAL(triggered(QAction*)),
127  this, SLOT(slotDrawMode(QAction*)));
128 
129 
130  // init draw modes
131  n_draw_modes_ = 0;
132  //draw_mode_ = 3;
133  QAction *a;
134  a = add_draw_mode("Wireframe");
135  a->setShortcut(QKeySequence(Key_W));
136  add_draw_mode("Solid Flat");
137  a = add_draw_mode("Solid Smooth");
138  a->setShortcut(QKeySequence(Key_S));
139  a->setChecked(true);
140 
141  slotDrawMode(a);
142 }
143 
144 
145 //----------------------------------------------------------------------------
146 
147 QGLViewerWidget::~QGLViewerWidget()
148 {
149 }
150 
151 
152 //----------------------------------------------------------------------------
153 
154 void
155 QGLViewerWidget::setDefaultMaterial(void)
156 {
157  GLfloat mat_a[] = {0.1, 0.1, 0.1, 1.0};
158  GLfloat mat_d[] = {0.7, 0.7, 0.5, 1.0};
159  GLfloat mat_s[] = {1.0, 1.0, 1.0, 1.0};
160  GLfloat shine[] = {120.0};
161 
162  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_a);
163  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_d);
164  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_s);
165  glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shine);
166 }
167 
168 
169 //----------------------------------------------------------------------------
170 
171 void
172 QGLViewerWidget::setDefaultLight(void)
173 {
174  GLfloat pos1[] = { 0.1, 0.1, -0.02, 0.0};
175  GLfloat pos2[] = {-0.1, 0.1, -0.02, 0.0};
176  GLfloat pos3[] = { 0.0, 0.0, 0.1, 0.0};
177  GLfloat col1[] = { 0.7, 0.7, 0.8, 1.0};
178  GLfloat col2[] = { 0.8, 0.7, 0.7, 1.0};
179  GLfloat col3[] = { 1.0, 1.0, 1.0, 1.0};
180 
181  glEnable(GL_LIGHT0);
182  glLightfv(GL_LIGHT0,GL_POSITION, pos1);
183  glLightfv(GL_LIGHT0,GL_DIFFUSE, col1);
184  glLightfv(GL_LIGHT0,GL_SPECULAR, col1);
185 
186  glEnable(GL_LIGHT1);
187  glLightfv(GL_LIGHT1,GL_POSITION, pos2);
188  glLightfv(GL_LIGHT1,GL_DIFFUSE, col2);
189  glLightfv(GL_LIGHT1,GL_SPECULAR, col2);
190 
191  glEnable(GL_LIGHT2);
192  glLightfv(GL_LIGHT2,GL_POSITION, pos3);
193  glLightfv(GL_LIGHT2,GL_DIFFUSE, col3);
194  glLightfv(GL_LIGHT2,GL_SPECULAR, col3);
195 }
196 
197 
198 //----------------------------------------------------------------------------
199 
200 
201 void
202 QGLViewerWidget::initializeGL()
203 {
204  // OpenGL state
205  glClearColor(0.0, 0.0, 0.0, 0.0);
206  glDisable( GL_DITHER );
207  glEnable( GL_DEPTH_TEST );
208 
209  // Material
210  setDefaultMaterial();
211 
212  // Lighting
213  glLoadIdentity();
214  setDefaultLight();
215 
216  // Fog
217  GLfloat fogColor[4] = { 0.3, 0.3, 0.4, 1.0 };
218  glFogi(GL_FOG_MODE, GL_LINEAR);
219  glFogfv(GL_FOG_COLOR, fogColor);
220  glFogf(GL_FOG_DENSITY, 0.35);
221  glHint(GL_FOG_HINT, GL_DONT_CARE);
222  glFogf(GL_FOG_START, 5.0f);
223  glFogf(GL_FOG_END, 25.0f);
224 
225  // scene pos and size
226  glMatrixMode(GL_MODELVIEW);
227  glLoadIdentity();
228  glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_);
229  set_scene_pos(Vec3f(0.0, 0.0, 0.0), 1.0);
230 }
231 
232 
233 //----------------------------------------------------------------------------
234 
235 
236 void
237 QGLViewerWidget::resizeGL( int _w, int _h )
238 {
239  update_projection_matrix();
240  glViewport(0, 0, _w, _h);
241  updateGL();
242 }
243 
244 
245 //----------------------------------------------------------------------------
246 
247 
248 void
249 QGLViewerWidget::paintGL()
250 {
251  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
252  glMatrixMode( GL_PROJECTION );
253  glLoadMatrixd( projection_matrix_ );
254  glMatrixMode( GL_MODELVIEW );
255  glLoadMatrixd( modelview_matrix_ );
256 
257  if (draw_mode_)
258  {
259  assert(draw_mode_ <= n_draw_modes_);
260  draw_scene(draw_mode_names_[draw_mode_-1]);
261  }
262 }
263 
264 
265 //----------------------------------------------------------------------------
266 
267 
268 void
269 QGLViewerWidget::draw_scene(const std::string& _draw_mode)
270 {
271  if (_draw_mode == "Wireframe")
272  {
273  glDisable(GL_LIGHTING);
274  glutWireTeapot(0.5);
275  }
276 
277  else if (_draw_mode == "Solid Flat")
278  {
279  glEnable(GL_LIGHTING);
280  glShadeModel(GL_FLAT);
281  glutSolidTeapot(0.5);
282  }
283 
284  else if (_draw_mode == "Solid Smooth")
285  {
286  glEnable(GL_LIGHTING);
287  glShadeModel(GL_SMOOTH);
288  glutSolidTeapot(0.5);
289  }
290 }
291 
292 
293 //----------------------------------------------------------------------------
294 
295 
296 void
297 QGLViewerWidget::mousePressEvent( QMouseEvent* _event )
298 {
299  // popup menu
300  if (_event->button() == RightButton && _event->buttons()== RightButton )
301  {
302  popup_menu_->exec(QCursor::pos());
303  }
304 
305  else
306  {
307  last_point_ok_ = map_to_sphere( last_point_2D_=_event->pos(),
308  last_point_3D_ );
309  }
310 }
311 
312 
313 //----------------------------------------------------------------------------
314 
315 
316 void
317 QGLViewerWidget::mouseMoveEvent( QMouseEvent* _event )
318 {
319  QPoint newPoint2D = _event->pos();
320 
321  // Left button: rotate around center_
322  // Middle button: translate object
323  // Left & middle button: zoom in/out
324 
325 
326  Vec3f newPoint3D;
327  bool newPoint_hitSphere = map_to_sphere( newPoint2D, newPoint3D );
328 
329  float dx = newPoint2D.x() - last_point_2D_.x();
330  float dy = newPoint2D.y() - last_point_2D_.y();
331 
332  float w = width();
333  float h = height();
334 
335 
336 
337  // enable GL context
338  makeCurrent();
339 
340 
341  // move in z direction
342  if ( (_event->buttons() == (LeftButton+MidButton)) ||
343  (_event->buttons() == LeftButton && _event->modifiers() == ControlModifier))
344  {
345  float value_y = radius_ * dy * 3.0 / h;
346  translate(Vec3f(0.0, 0.0, value_y));
347  }
348 
349 
350  // move in x,y direction
351  else if ( (_event->buttons() == MidButton) ||
352  (_event->buttons() == LeftButton && _event->modifiers() == AltModifier) )
353  {
354  float z = - (modelview_matrix_[ 2]*center_[0] +
355  modelview_matrix_[ 6]*center_[1] +
356  modelview_matrix_[10]*center_[2] +
357  modelview_matrix_[14]) /
358  (modelview_matrix_[ 3]*center_[0] +
359  modelview_matrix_[ 7]*center_[1] +
360  modelview_matrix_[11]*center_[2] +
361  modelview_matrix_[15]);
362 
363  float aspect = w / h;
364  float near_plane = 0.01 * radius_;
365  float top = tan(fovy()/2.0f*M_PI/180.0f) * near_plane;
366  float right = aspect*top;
367 
368  translate(Vec3f( 2.0*dx/w*right/near_plane*z,
369  -2.0*dy/h*top/near_plane*z,
370  0.0f));
371  }
372 
373 
374 
375  // rotate
376  else if (_event->buttons() == LeftButton) {
377 
378  if (last_point_ok_) {
379  if ((newPoint_hitSphere = map_to_sphere(newPoint2D, newPoint3D))) {
380  Vec3f axis = last_point_3D_ % newPoint3D;
381  if (axis.sqrnorm() < 1e-7) {
382  axis = Vec3f(1, 0, 0);
383  } else {
384  axis.normalize();
385  }
386  // find the amount of rotation
387  Vec3f d = last_point_3D_ - newPoint3D;
388  float t = 0.5 * d.norm() / TRACKBALL_RADIUS;
389  if (t < -1.0)
390  t = -1.0;
391  else if (t > 1.0)
392  t = 1.0;
393  float phi = 2.0 * asin(t);
394  float angle = phi * 180.0 / M_PI;
395  rotate(axis, angle);
396  }
397  }
398 
399  }
400 
401 
402  // remember this point
403  last_point_2D_ = newPoint2D;
404  last_point_3D_ = newPoint3D;
405  last_point_ok_ = newPoint_hitSphere;
406 
407  // trigger redraw
408  updateGL();
409 }
410 
411 
412 //----------------------------------------------------------------------------
413 
414 
415 void
416 QGLViewerWidget::mouseReleaseEvent( QMouseEvent* /* _event */ )
417 {
418  last_point_ok_ = false;
419 }
420 
421 
422 //-----------------------------------------------------------------------------
423 
424 
425 void QGLViewerWidget::wheelEvent(QWheelEvent* _event)
426 {
427  // Use the mouse wheel to zoom in/out
428 
429  float d = -(float)_event->delta() / 120.0 * 0.2 * radius_;
430  translate(Vec3f(0.0, 0.0, d));
431  updateGL();
432  _event->accept();
433 }
434 
435 
436 //----------------------------------------------------------------------------
437 
438 
439 void QGLViewerWidget::keyPressEvent( QKeyEvent* _event)
440 {
441  switch( _event->key() )
442  {
443  case Key_Print:
444  slotSnapshot();
445  break;
446 
447  case Key_H:
448  std::cout << "Keys:\n";
449  std::cout << " Print\tMake snapshot\n";
450  std::cout << " C\tenable/disable back face culling\n";
451  std::cout << " F\tenable/disable fog\n";
452  std::cout << " I\tDisplay information\n";
453  std::cout << " N\tenable/disable display of vertex normals\n";
454  std::cout << " Shift N\tenable/disable display of face normals\n";
455  std::cout << " Shift P\tperformance check\n";
456  break;
457 
458  case Key_C:
459  if ( glIsEnabled( GL_CULL_FACE ) )
460  {
461  glDisable( GL_CULL_FACE );
462  std::cout << "Back face culling: disabled\n";
463  }
464  else
465  {
466  glEnable( GL_CULL_FACE );
467  std::cout << "Back face culling: enabled\n";
468  }
469  updateGL();
470  break;
471 
472  case Key_F:
473  if ( glIsEnabled( GL_FOG ) )
474  {
475  glDisable( GL_FOG );
476  std::cout << "Fog: disabled\n";
477  }
478  else
479  {
480  glEnable( GL_FOG );
481  std::cout << "Fog: enabled\n";
482  }
483  updateGL();
484  break;
485 
486  case Key_I:
487  std::cout << "Scene radius: " << radius_ << std::endl;
488  std::cout << "Scene center: " << center_ << std::endl;
489  break;
490 
491  case Key_P:
492  if (_event->modifiers() & ShiftModifier)
493  {
494  double fps = performance();
495  std::cout << "fps: "
496  << std::setiosflags (std::ios_base::fixed)
497  << fps << std::endl;
498  }
499  break;
500 
501  case Key_Q:
502  case Key_Escape:
503  qApp->quit();
504  }
505  _event->ignore();
506 }
507 
508 
509 //----------------------------------------------------------------------------
510 
511 
512 void
513 QGLViewerWidget::translate( const OpenMesh::Vec3f& _trans )
514 {
515  // Translate the object by _trans
516  // Update modelview_matrix_
517  makeCurrent();
518  glLoadIdentity();
519  glTranslated( _trans[0], _trans[1], _trans[2] );
520  glMultMatrixd( modelview_matrix_ );
521  glGetDoublev( GL_MODELVIEW_MATRIX, modelview_matrix_);
522 }
523 
524 
525 //----------------------------------------------------------------------------
526 
527 
528 void
529 QGLViewerWidget::rotate( const OpenMesh::Vec3f& _axis, float _angle )
530 {
531  // Rotate around center center_, axis _axis, by angle _angle
532  // Update modelview_matrix_
533 
534  Vec3f t( modelview_matrix_[0]*center_[0] +
535  modelview_matrix_[4]*center_[1] +
536  modelview_matrix_[8]*center_[2] +
537  modelview_matrix_[12],
538  modelview_matrix_[1]*center_[0] +
539  modelview_matrix_[5]*center_[1] +
540  modelview_matrix_[9]*center_[2] +
541  modelview_matrix_[13],
542  modelview_matrix_[2]*center_[0] +
543  modelview_matrix_[6]*center_[1] +
544  modelview_matrix_[10]*center_[2] +
545  modelview_matrix_[14] );
546 
547  makeCurrent();
548  glLoadIdentity();
549  glTranslatef(t[0], t[1], t[2]);
550  glRotated( _angle, _axis[0], _axis[1], _axis[2]);
551  glTranslatef(-t[0], -t[1], -t[2]);
552  glMultMatrixd(modelview_matrix_);
553  glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_);
554 }
555 
556 
557 //----------------------------------------------------------------------------
558 
559 
560 bool
561 QGLViewerWidget::map_to_sphere( const QPoint& _v2D, OpenMesh::Vec3f& _v3D )
562 {
563  // This is actually doing the Sphere/Hyperbolic sheet hybrid thing,
564  // based on Ken Shoemake's ArcBall in Graphics Gems IV, 1993.
565  double x = (2.0*_v2D.x() - width())/width();
566  double y = -(2.0*_v2D.y() - height())/height();
567  double xval = x;
568  double yval = y;
569  double x2y2 = xval*xval + yval*yval;
570 
571  const double rsqr = TRACKBALL_RADIUS*TRACKBALL_RADIUS;
572  _v3D[0] = xval;
573  _v3D[1] = yval;
574  if (x2y2 < 0.5*rsqr) {
575  _v3D[2] = sqrt(rsqr - x2y2);
576  } else {
577  _v3D[2] = 0.5*rsqr/sqrt(x2y2);
578  }
579 
580  return true;
581  }
582 
583 
584 //----------------------------------------------------------------------------
585 
586 
587 void
588 QGLViewerWidget::update_projection_matrix()
589 {
590  makeCurrent();
591  glMatrixMode( GL_PROJECTION );
592  glLoadIdentity();
593  gluPerspective(45.0, (GLfloat) width() / (GLfloat) height(),
594  0.01*radius_, 100.0*radius_);
595  glGetDoublev( GL_PROJECTION_MATRIX, projection_matrix_);
596  glMatrixMode( GL_MODELVIEW );
597 }
598 
599 
600 //----------------------------------------------------------------------------
601 
602 
603 void
604 QGLViewerWidget::view_all()
605 {
606  translate( Vec3f( -(modelview_matrix_[0]*center_[0] +
607  modelview_matrix_[4]*center_[1] +
608  modelview_matrix_[8]*center_[2] +
609  modelview_matrix_[12]),
610  -(modelview_matrix_[1]*center_[0] +
611  modelview_matrix_[5]*center_[1] +
612  modelview_matrix_[9]*center_[2] +
613  modelview_matrix_[13]),
614  -(modelview_matrix_[2]*center_[0] +
615  modelview_matrix_[6]*center_[1] +
616  modelview_matrix_[10]*center_[2] +
617  modelview_matrix_[14] +
618  3.0*radius_) ) );
619 }
620 
621 
622 //----------------------------------------------------------------------------
623 
624 
625 void
626 QGLViewerWidget::set_scene_pos( const OpenMesh::Vec3f& _cog, float _radius )
627 {
628  center_ = _cog;
629  radius_ = _radius;
630  glFogf( GL_FOG_START, 1.5*_radius );
631  glFogf( GL_FOG_END, 3.0*_radius );
632 
633  update_projection_matrix();
634  view_all();
635 }
636 
637 
638 //----------------------------------------------------------------------------
639 
640 
641 QAction*
642 QGLViewerWidget::add_draw_mode(const std::string& _s)
643 {
644  ++n_draw_modes_;
645  draw_mode_names_.push_back(_s);
646 
647  QActionGroup *grp = draw_modes_group_;
648  QAction* act = new QAction(tr(_s.c_str()), this);
649  act->setCheckable(true);
650  act->setData(n_draw_modes_);
651 
652  grp->addAction(act);
653  popup_menu_->addAction(act);
654  addAction(act, _s.c_str());
655 
656  return act;
657 }
658 
659 void QGLViewerWidget::addAction(QAction* act, const char * name)
660 {
661  names_to_actions[name] = act;
662  Super::addAction(act);
663 }
664 void QGLViewerWidget::removeAction(QAction* act)
665 {
666  ActionMap::iterator it = names_to_actions.begin(), e = names_to_actions.end();
667  ActionMap::iterator found = e;
668  for(; it!=e; ++it) {
669  if (it->second == act) {
670  found = it;
671  break;
672  }
673  }
674  if (found != e) {
675  names_to_actions.erase(found);
676 }
677  popup_menu_->removeAction(act);
678  draw_modes_group_->removeAction(act);
679  Super::removeAction(act);
680 }
681 
682 void QGLViewerWidget::removeAction(const char* name)
683 {
684  QString namestr = QString(name);
685  ActionMap::iterator e = names_to_actions.end();
686 
687  ActionMap::iterator found = names_to_actions.find(namestr);
688  if (found != e) {
689  removeAction(found->second);
690  }
691 }
692 
693 QAction* QGLViewerWidget::findAction(const char* name)
694 {
695  QString namestr = QString(name);
696  ActionMap::iterator e = names_to_actions.end();
697 
698  ActionMap::iterator found = names_to_actions.find(namestr);
699  if (found != e) {
700  return found->second;
701  }
702  return 0;
703 }
704 
705 //----------------------------------------------------------------------------
706 
707 
708 void
709 QGLViewerWidget::del_draw_mode(const std::string& _s)
710 {
711  QString cmp = _s.c_str();
712  QList<QAction*> actions_ = popup_menu_->actions();
713  QList<QAction*>::iterator it=actions_.begin(), e=actions_.end();
714  for(; it!=e; ++it) {
715  if ((*it)->text() == cmp) { break; }
716  }
717 
718 #if _DEBUG
719  assert( it != e );
720 #else
721  if ( it == e )
722  return;
723 #endif
724 
725  popup_menu_->removeAction(*it);
726  //QActionGroup *grp = draw_modes_group_;
727 
728 }
729 
730 
731 //----------------------------------------------------------------------------
732 
733 
734 void
735 QGLViewerWidget::slotDrawMode(QAction* _mode)
736 {
737  // save draw mode
738  draw_mode_ = _mode->data().toInt();
739  updateGL();
740 
741  // check selected draw mode
742  //popup_menu_->setItemChecked(draw_mode_, true);
743 }
744 
745 
746 //----------------------------------------------------------------------------
747 
748 
749 double
750 QGLViewerWidget::performance()
751 {
752  setCursor( Qt::WaitCursor );
753 
754  double fps(0.0);
755 
756  makeCurrent();
757  glMatrixMode(GL_MODELVIEW);
758  glPushMatrix();
759 
761 
762  unsigned int frames = 60;
763  const float angle = 360.0/(float)frames;
764  unsigned int i;
765  Vec3f axis;
766 
767  glFinish();
768 
769  timer.start();
770  for (i=0, axis=Vec3f(1,0,0); i<frames; ++i)
771  { rotate(axis, angle); paintGL(); swapBuffers(); }
772  timer.stop();
773 
774  qApp->processEvents();
775 
776  timer.cont();
777  for (i=0, axis=Vec3f(0,1,0); i<frames; ++i)
778  { rotate(axis, angle); paintGL(); swapBuffers(); }
779  timer.stop();
780 
781  qApp->processEvents();
782 
783  timer.cont();
784  for (i=0, axis=Vec3f(0,0,1); i<frames; ++i)
785  { rotate(axis, angle); paintGL(); swapBuffers(); }
786  timer.stop();
787 
788  glFinish();
789  timer.stop();
790 
791  glPopMatrix();
792  updateGL();
793 
794  fps = ( (3.0 * frames) / timer.seconds() );
795 
796  setCursor( PointingHandCursor );
797 
798  return fps;
799 }
800 
801 
802 void
803 QGLViewerWidget::slotSnapshot( void )
804 {
805  QImage image;
806  size_t w(width()), h(height());
807  GLenum buffer( GL_BACK );
808 
809  try
810  {
811  image = QImage(w, h, QImage::Format_RGB32);
812 
813  std::vector<GLubyte> fbuffer(3*w*h);
814 
815  qApp->processEvents();
816  makeCurrent();
817  updateGL();
818  glFinish();
819 
820  glReadBuffer( buffer );
821  glPixelStorei(GL_PACK_ALIGNMENT, 1);
822  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
823  paintGL();
824  glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, &fbuffer[0] );
825 
826  unsigned int x,y,offset;
827 
828  for (y=0; y<h; ++y) {
829  for (x=0; x<w; ++x) {
830  offset = 3*(y*w + x);
831  image.setPixel(x, h-y-1, qRgb(fbuffer[offset],
832  fbuffer[offset+1],
833  fbuffer[offset+2]));
834  }
835  }
836 
837 
838  QString name = "snapshot-";
839 #if defined(_MSC_VER)
840  {
841  std::stringstream s;
842  QDateTime dt = QDateTime::currentDateTime();
843  s << dt.date().year()
844  << std::setw(2) << std::setfill('0') << dt.date().month()
845  << std::setw(2) << std::setfill('0') << dt.date().day()
846  << std::setw(2) << std::setfill('0') << dt.time().hour()
847  << std::setw(2) << std::setfill('0') << dt.time().minute()
848  << std::setw(2) << std::setfill('0') << dt.time().second();
849  name += QString(s.str().c_str());
850  }
851 #else
852  name += QDateTime::currentDateTime().toString( "yyMMddhhmmss" );
853 #endif
854  name += ".png";
855 
856  image.save( name, "PNG");
857  }
858  catch( std::bad_alloc& )
859  {
860  qWarning("Mem Alloc Error");
861  }
862 
863 }
864 
865 
866 
867 //=============================================================================
void del_draw_mode(const std::string &_s)
delete draw mode from popup menu
virtual void draw_scene(const std::string &_draw_mode)
inherited drawing method
void start(void)
Start measurement.
void translate(const ACG::Vec3d &_vector, int _viewer)
Translate viewer pos by given vector.
QAction * add_draw_mode(const std::string &_s)
add draw mode to popup menu, and return the QAction created
double seconds(void) const
Returns measured time in seconds, if the timer is in state &#39;Stopped&#39;.
T angle(T _cos_angle, T _sin_angle)
Definition: MathDefs.hh:145
void rotate(const ACG::Vec3d &_axis, const double _angle, const ACG::Vec3d &_center, int _viewer)
Rotate Scene around axis.
auto normalize() -> decltype(*this/=std::declval< VectorT< S, DIM >>().norm())
Definition: Vector11T.hh:428
auto norm() const -> decltype(std::sqrt(std::declval< VectorT< S, DIM >>().sqrnorm()))
compute euclidean norm
Definition: Vector11T.hh:408
decltype(std::declval< S >()*std::declval< S >()) sqrnorm() const
compute squared euclidean norm
Definition: Vector11T.hh:396
void stop(void)
Stop measurement.
void cont(void)
Continue measurement.