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