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