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 
45 //== INCLUDES =================================================================
46 
47 #ifdef _MSC_VER
48 #  pragma warning(disable: 4267 4311 4305)
49 #endif
50 
51 #include <iomanip>
52 
53 #include <GL/glut.h>
54 // #include <qnamespace.h>
55 #include <QApplication>
56 #include <QMenu>
57 #include <QCursor>
58 #include <QMouseEvent>
59 
60 #include <OpenMesh/Apps/VDProgMesh/Streaming/Client/QGLViewerWidget.hh>
61 #include <OpenMesh/Tools/Utils/Timer.hh>
62 
63 #if !defined(M_PI)
64 #  define M_PI 3.1415926535897931
65 #endif
66 
67 using namespace OpenMesh;
68 
69 
70 //== IMPLEMENTATION ==========================================================
71 
72 
QGLViewerWidget(QWidget * _parent,const char * _name)73 QGLViewerWidget::QGLViewerWidget( QWidget* _parent, const char* _name )
74   : QGLWidget( _parent )
75 {
76   // qt stuff
77   setWindowTitle(_name);
78 //   setBackgroundMode( NoBackground );
79   setFocusPolicy(Qt::StrongFocus);
80   setAcceptDrops( true );
81   setCursor(Qt::PointingHandCursor);
82 
83 
84   // popup menu
85   popup_menu_ = new QMenu("Draw Mode Menu", this);
86 
87   connect( popup_menu_, SIGNAL(activated(int)),
88 	   this, SLOT(slotPopupMenu(int)));
89 
90 
91   // init draw modes
92   n_draw_modes_ = 0;
93   add_draw_mode("Wireframe");
94   add_draw_mode("Solid Flat");
95   add_draw_mode("Solid Smooth");
96 
97   // for example
98   add_draw_mode("Colored");
99 
100   slotPopupMenu(2);
101 }
102 
103 
104 //----------------------------------------------------------------------------
105 
106 
~QGLViewerWidget()107 QGLViewerWidget::~QGLViewerWidget()
108 {
109 }
110 
111 
112 //----------------------------------------------------------------------------
113 
114 
115 void
initializeGL()116 QGLViewerWidget::initializeGL()
117 {
118   // OpenGL state
119   glClearColor(1.0, 1.0, 1.0, 0.0);
120   glDisable( GL_DITHER );
121   glEnable( GL_DEPTH_TEST );
122   glEnable( GL_CULL_FACE );
123 
124 
125   // material
126    GLfloat mat_a[] = {0.7, 0.6, 0.5, 1.0};
127    GLfloat mat_d[] = {0.8, 0.7, 0.6, 1.0};
128    GLfloat mat_s[] = {1.0, 1.0, 1.0, 1.0};
129    GLfloat shine[] = {120.0};
130 
131 //   GLfloat mat_a[] = {0.2, 0.2, 0.2, 1.0};
132 //   GLfloat mat_d[] = {0.4, 0.4, 0.4, 1.0};
133 //   GLfloat mat_s[] = {0.8, 0.8, 0.8, 1.0};
134 //   GLfloat shine[] = {128.0};
135   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,   mat_a);
136   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,   mat_d);
137   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  mat_s);
138   glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shine);
139 
140 
141   // lighting
142   glLoadIdentity();
143 
144   GLfloat pos1[] = { 0.1, 0.1, -0.02, 0.0};
145   GLfloat pos2[] = {-0.1, 0.1, -0.02, 0.0};
146   GLfloat pos3[] = { 0.0, 0.0, 0.1, 0.0};
147   GLfloat col1[] = {.05, .05, .4, 1.0};
148   GLfloat col2[] = {.4, .05, .05, 1.0};
149   GLfloat col3[] = {1.0, 1.0, 1.0, 1.0};
150 
151   glEnable(GL_LIGHT0);
152   glLightfv(GL_LIGHT0,GL_POSITION, pos1);
153   glLightfv(GL_LIGHT0,GL_DIFFUSE,  col1);
154   glLightfv(GL_LIGHT0,GL_SPECULAR, col1);
155 
156   glEnable(GL_LIGHT1);
157   glLightfv(GL_LIGHT1,GL_POSITION, pos2);
158   glLightfv(GL_LIGHT1,GL_DIFFUSE,  col2);
159   glLightfv(GL_LIGHT1,GL_SPECULAR, col2);
160 
161   glEnable(GL_LIGHT2);
162   glLightfv(GL_LIGHT2,GL_POSITION, pos3);
163   glLightfv(GL_LIGHT2,GL_DIFFUSE,  col3);
164   glLightfv(GL_LIGHT2,GL_SPECULAR, col3);
165 
166 
167   // Fog
168   GLfloat fogColor[4] = { 0.4, 0.4, 0.5, 1.0 };
169   glFogi(GL_FOG_MODE,    GL_LINEAR);
170   glFogfv(GL_FOG_COLOR,  fogColor);
171   glFogf(GL_FOG_DENSITY, 0.35);
172   glHint(GL_FOG_HINT,    GL_DONT_CARE);
173   glFogf(GL_FOG_START,    5.0f);
174   glFogf(GL_FOG_END,     25.0f);
175 
176   // scene pos and size
177   glMatrixMode(GL_MODELVIEW);
178   glLoadIdentity();
179   glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_);
180   set_scene_pos(Vec3f(0.0, 0.0, 0.0), 1.0);
181 }
182 
183 
184 //----------------------------------------------------------------------------
185 
186 
187 void
resizeGL(int _w,int _h)188 QGLViewerWidget::resizeGL( int _w, int _h )
189 {
190   update_projection_matrix();
191   glViewport(0, 0, _w, _h);
192   updateGL();
193 }
194 
195 
196 //----------------------------------------------------------------------------
197 
198 
199 void
paintGL()200 QGLViewerWidget::paintGL()
201 {
202   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
203   glMatrixMode( GL_PROJECTION );
204   glLoadMatrixd( projection_matrix_ );
205   glMatrixMode( GL_MODELVIEW );
206   glLoadMatrixd( modelview_matrix_ );
207 
208   if (draw_mode_)
209   {
210     assert(draw_mode_ <= n_draw_modes_);
211     draw_scene(draw_mode_names_[draw_mode_-1]);
212   }
213 }
214 
215 
216 //----------------------------------------------------------------------------
217 
218 
219 void
draw_scene(const std::string & _draw_mode)220 QGLViewerWidget::draw_scene(const std::string& _draw_mode)
221 {
222   if (_draw_mode == "Wireframe")
223   {
224     glDisable(GL_LIGHTING);
225     glutWireTeapot(0.5);
226   }
227 
228   else if (_draw_mode == "Solid Flat")
229   {
230     glEnable(GL_LIGHTING);
231     glShadeModel(GL_FLAT);
232     glutSolidTeapot(0.5);
233   }
234 
235   else if (_draw_mode == "Solid Smooth")
236   {
237     glEnable(GL_LIGHTING);
238     glShadeModel(GL_SMOOTH);
239     glutSolidTeapot(0.5);
240   }
241 
242 }
243 
244 
245 //----------------------------------------------------------------------------
246 
247 
248 void
mousePressEvent(QMouseEvent * _event)249 QGLViewerWidget::mousePressEvent( QMouseEvent* _event )
250 {
251   // popup menu
252   if (_event->button() == Qt::RightButton)
253   {
254     popup_menu_->exec(QCursor::pos());
255   }
256 
257   else
258   {
259     last_point_ok_ = map_to_sphere( last_point_2D_=_event->pos(),
260 				    last_point_3D_ );
261   }
262 }
263 
264 
265 //----------------------------------------------------------------------------
266 
267 
268 void
mouseMoveEvent(QMouseEvent * _event)269 QGLViewerWidget::mouseMoveEvent( QMouseEvent* _event )
270 {
271   QPoint newPoint2D = _event->pos();
272 
273   if ( (newPoint2D.x()<0) || (newPoint2D.x()>width()) ||
274        (newPoint2D.y()<0) || (newPoint2D.y()>height()) ) return;
275 
276 
277   // Left button: rotate around center_
278   // Middle button: translate object
279   // Left & middle button: zoom in/out
280 
281   Vec3f  newPoint3D;
282   bool   newPoint_hitSphere = map_to_sphere( newPoint2D, newPoint3D );
283 
284   float dx = newPoint2D.x() - last_point_2D_.x();
285   float dy = newPoint2D.y() - last_point_2D_.y();
286 
287   float w  = width();
288   float h  = height();
289 
290 
291 
292   // enable GL context
293   makeCurrent();
294 
295 
296   // move in z direction
297   if ( (_event->button() == Qt::LeftButton) && (_event->button() == Qt::MidButton))
298   {
299     float value_y = radius_ * dy * 3.0 / h;
300     translate(Vec3f(0.0, 0.0, value_y));
301   }
302 
303 
304   // move in x,y direction
305   else if (_event->button() == Qt::MidButton)
306   {
307     float z = - (modelview_matrix_[ 2]*center_[0] +
308 		 modelview_matrix_[ 6]*center_[1] +
309 		 modelview_matrix_[10]*center_[2] +
310 		 modelview_matrix_[14]) /
311                 (modelview_matrix_[ 3]*center_[0] +
312 	         modelview_matrix_[ 7]*center_[1] +
313 	         modelview_matrix_[11]*center_[2] +
314 	         modelview_matrix_[15]);
315 
316     float aspect     = w / h;
317     float near_plane = 0.01 * radius_;
318     float top        = tan(fovy()/2.0f*M_PI/180.0f) * near_plane;
319     float right      = aspect*top;
320 
321     translate(Vec3f( 2.0*dx/w*right/near_plane*z,
322 		    -2.0*dy/h*top/near_plane*z,
323 		     0.0f));
324   }
325 
326 
327 
328   // rotate
329   else if (_event->button() == Qt::LeftButton)
330   {
331     if (last_point_ok_)
332     {
333       if ( (newPoint_hitSphere = map_to_sphere(newPoint2D, newPoint3D)) )
334       {
335         Vec3f axis = last_point_3D_ % newPoint3D;
336         float cos_angle = (last_point_3D_ | newPoint3D);
337         if ( fabs(cos_angle) < 1.0 )
338         {
339           float angle = 2.0 * acos( cos_angle ) * 180.0 / M_PI;
340           rotate( axis, angle );
341         }
342       }
343     }
344   }
345 
346 
347   // remember this point
348   last_point_2D_ = newPoint2D;
349   last_point_3D_ = newPoint3D;
350   last_point_ok_ = newPoint_hitSphere;
351 
352   // trigger redraw
353   updateGL();
354 }
355 
356 
357 //----------------------------------------------------------------------------
358 
359 
360 void
mouseReleaseEvent(QMouseEvent *)361 QGLViewerWidget::mouseReleaseEvent( QMouseEvent* /* _event */ )
362 {
363    last_point_ok_ = false;
364 }
365 
366 
367 //-----------------------------------------------------------------------------
368 
369 
wheelEvent(QWheelEvent * _event)370 void QGLViewerWidget::wheelEvent(QWheelEvent* _event)
371 {
372   // Use the mouse wheel to zoom in/out
373 
374   float d = -(float)_event->delta() / 120.0 * 0.2 * radius_;
375   translate(Vec3f(0.0, 0.0, d));
376   updateGL();
377   _event->accept();
378 }
379 
380 
381 //----------------------------------------------------------------------------
382 
383 
keyPressEvent(QKeyEvent * _event)384 void QGLViewerWidget::keyPressEvent( QKeyEvent* _event)
385 {
386   switch( _event->key() )
387   {
388     case Qt::Key_C:
389       if ( glIsEnabled( GL_CULL_FACE ) )
390       {
391 	glDisable( GL_CULL_FACE );
392 	std::cout << "Back face culling: disabled\n";
393       }
394       else
395       {
396 	glEnable( GL_CULL_FACE );
397 	std::cout << "Back face culling: enabled\n";
398       }
399       updateGL();
400       break;
401 
402     case Qt::Key_I:
403       std::cout << "Radius: " << radius_ << std::endl;
404       std::cout << "Center: " << center_ << std::endl;
405       break;
406 
407     case Qt::Key_Space:
408     case Qt::Key_M:
409     {
410       double fps = performance();
411       std::cout << "fps: "
412 #if defined(OM_CC_GCC) && (OM_CC_VERSION < 30000)
413 		<< std::setiosflags (std::ios::fixed)
414 #else
415 		<< std::setiosflags (std::ios_base::fixed)
416 #endif
417 		<< fps << std::endl;
418     }
419     break;
420 
421     case Qt::Key_Q:
422     case Qt::Key_Escape:
423       qApp->quit();
424   }
425   _event->ignore();
426 }
427 
428 
429 //----------------------------------------------------------------------------
430 
431 
432 void
translate(const OpenMesh::Vec3f & _trans)433 QGLViewerWidget::translate( const OpenMesh::Vec3f& _trans )
434 {
435   // Translate the object by _trans
436   // Update modelview_matrix_
437   makeCurrent();
438   glLoadIdentity();
439   glTranslated( _trans[0], _trans[1], _trans[2] );
440   glMultMatrixd( modelview_matrix_ );
441   glGetDoublev( GL_MODELVIEW_MATRIX, modelview_matrix_);
442 }
443 
444 
445 //----------------------------------------------------------------------------
446 
447 
448 void
rotate(const OpenMesh::Vec3f & _axis,float _angle)449 QGLViewerWidget::rotate( const OpenMesh::Vec3f& _axis, float _angle )
450 {
451   // Rotate around center center_, axis _axis, by angle _angle
452   // Update modelview_matrix_
453 
454   Vec3f t( modelview_matrix_[0]*center_[0] +
455 	   modelview_matrix_[4]*center_[1] +
456 	   modelview_matrix_[8]*center_[2] +
457 	   modelview_matrix_[12],
458 	   modelview_matrix_[1]*center_[0] +
459 	   modelview_matrix_[5]*center_[1] +
460 	   modelview_matrix_[9]*center_[2] +
461 	   modelview_matrix_[13],
462 	   modelview_matrix_[2]*center_[0] +
463 	   modelview_matrix_[6]*center_[1] +
464 	   modelview_matrix_[10]*center_[2] +
465 	   modelview_matrix_[14] );
466 
467   makeCurrent();
468   glLoadIdentity();
469   glTranslatef(t[0], t[1], t[2]);
470   glRotated( _angle, _axis[0], _axis[1], _axis[2]);
471   glTranslatef(-t[0], -t[1], -t[2]);
472   glMultMatrixd(modelview_matrix_);
473   glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_);
474 }
475 
476 
477 //----------------------------------------------------------------------------
478 
479 
480 bool
map_to_sphere(const QPoint & _v2D,OpenMesh::Vec3f & _v3D)481 QGLViewerWidget::map_to_sphere( const QPoint& _v2D, OpenMesh::Vec3f& _v3D )
482 {
483   if ( (_v2D.x() >= 0) && (_v2D.x() <= width()) &&
484        (_v2D.y() >= 0) && (_v2D.y() <= height()) )
485   {
486     double x  = (double)(_v2D.x() - 0.5*width())  / (double)width();
487     double y  = (double)(0.5*height() - _v2D.y()) / (double)height();
488     double sinx         = sin(M_PI * x * 0.5);
489     double siny         = sin(M_PI * y * 0.5);
490     double sinx2siny2   = sinx * sinx + siny * siny;
491 
492     _v3D[0] = sinx;
493     _v3D[1] = siny;
494     _v3D[2] = sinx2siny2 < 1.0 ? sqrt(1.0 - sinx2siny2) : 0.0;
495 
496     return true;
497   }
498   else return false;
499 }
500 
501 
502 //----------------------------------------------------------------------------
503 
504 
505 void
update_projection_matrix()506 QGLViewerWidget::update_projection_matrix()
507 {
508   makeCurrent();
509   glMatrixMode( GL_PROJECTION );
510   glLoadIdentity();
511   gluPerspective(45.0, (GLfloat) width() / (GLfloat) height(),
512 		 0.01*radius_, 100.0*radius_);
513   glGetDoublev( GL_PROJECTION_MATRIX, projection_matrix_);
514   glMatrixMode( GL_MODELVIEW );
515 }
516 
517 
518 //----------------------------------------------------------------------------
519 
520 
521 void
view_all()522 QGLViewerWidget::view_all()
523 {
524   translate( Vec3f( -(modelview_matrix_[0]*center_[0] +
525 		      modelview_matrix_[4]*center_[1] +
526 		      modelview_matrix_[8]*center_[2] +
527 		      modelview_matrix_[12]),
528 		    -(modelview_matrix_[1]*center_[0] +
529 		      modelview_matrix_[5]*center_[1] +
530 		      modelview_matrix_[9]*center_[2] +
531 		      modelview_matrix_[13]),
532 		    -(modelview_matrix_[2]*center_[0] +
533 		      modelview_matrix_[6]*center_[1] +
534 		      modelview_matrix_[10]*center_[2] +
535 		      modelview_matrix_[14] +
536 		      3.0*radius_) ) );
537 }
538 
539 
540 //----------------------------------------------------------------------------
541 
542 
543 void
set_scene_pos(const OpenMesh::Vec3f & _cog,float _radius)544 QGLViewerWidget::set_scene_pos( const OpenMesh::Vec3f& _cog, float _radius )
545 {
546   center_ = _cog;
547   radius_ = _radius;
548   glFogf( GL_FOG_START,      _radius );
549   glFogf( GL_FOG_END,    4.0*_radius );
550 
551   update_projection_matrix();
552   view_all();
553 }
554 
555 
556 //----------------------------------------------------------------------------
557 
558 
559 void
add_draw_mode(std::string _s)560 QGLViewerWidget::add_draw_mode(std::string _s)
561 {
562   ++n_draw_modes_;
563 
564   // insert in popup menu
565   QString str( _s.c_str() );
566   popup_menu_->addAction( str );
567 
568   // store draw mode
569   draw_mode_names_.push_back(_s);
570 }
571 
572 
573 //----------------------------------------------------------------------------
574 
575 
576 void
slotPopupMenu(int _id)577 QGLViewerWidget::slotPopupMenu(int _id)
578 {
579   // set check status
580   for (int i=0; i < popup_menu_->actions().count(); ++i)
581     popup_menu_->actions()[i]->setChecked( i == _id );
582 
583   // save draw mode
584   draw_mode_ = _id;
585 }
586 
587 
588 //----------------------------------------------------------------------------
589 
590 
591 double
performance()592 QGLViewerWidget::performance()
593 {
594   setCursor( Qt::WaitCursor );
595 
596   double fps(0.0);
597 
598   makeCurrent();
599   glMatrixMode(GL_MODELVIEW);
600   glPushMatrix();
601 
602   OpenMesh::Utils::Timer timer;
603 
604   unsigned int  frames = 60;
605   const float   angle  = 360.0/(float)frames;
606   unsigned int  i;
607   Vec3f         axis;
608 
609   glFinish();
610   timer.start();
611 
612   for (i=0, axis=Vec3f(1,0,0); i<frames; ++i)
613   { rotate(axis, angle); paintGL(); swapBuffers(); }
614   for (i=0, axis=Vec3f(0,1,0); i<frames; ++i)
615   { rotate(axis, angle); paintGL(); swapBuffers(); }
616   for (i=0, axis=Vec3f(0,0,1); i<frames; ++i)
617   { rotate(axis, angle); paintGL(); swapBuffers(); }
618 
619   glFinish();
620   timer.stop();
621 
622   glPopMatrix();
623   updateGL();
624 
625   fps = ( (3.0 * frames) / timer.seconds() );
626 
627   setCursor( Qt::PointingHandCursor );
628 
629   return fps;
630 }
631 
632 //=============================================================================
633