1 #include "Viewer.h"
2 #include <CGAL/Three/Scene_draw_interface.h>
3 #include <QMouseEvent>
4 #include <QKeyEvent>
5 #include <QSettings>
6 #include <QDebug>
7 #include <QSettings>
8 #include <QOpenGLShader>
9 #include <QFileDialog>
10 #include <QOpenGLShaderProgram>
11 #include <QOpenGLFramebufferObject>
12 #include <QMessageBox>
13 #include <QColorDialog>
14 #include <QInputDialog>
15 #include <cmath>
16 #include <QApplication>
17 #include <QOpenGLDebugLogger>
18 #include <QStyleFactory>
19 #include <QAction>
20 #include <QMultipleInputDialog.h>
21 #include <QRegularExpressionMatch>
22 #ifdef CGAL_USE_WEBSOCKETS
23 #include <QtWebSockets/QWebSocket>
24 #endif
25
26 #include <CGAL/Three/Three.h>
27
28 #include "ui_LightingDialog.h"
29 #include "CGAL_double_edit.h"
30
31 #if defined(_WIN32)
32 #include <QMimeData>
33 #include <QByteArray>
34 #include <QBuffer>
35 #endif
36 #define ORIGINAL_FOV 0.94853805396568136
37
38 class Viewer_impl {
39 public:
40 CGAL::Three::Scene_draw_interface* scene;
41 Viewer *viewer;
42 Viewer *shareViewer;
43 bool antialiasing;
44 bool twosides;
45 bool macro_mode;
46 bool inFastDrawing;
47 bool inDrawWithNames;
48 bool clipping;
49 bool projection_is_ortho;
50 bool cam_sharing;
51 bool scene_scaling;
52 GLfloat gl_point_size;
53 QVector4D clipbox[6];
54 QVector3D scaler;
55 QPainter *painter;
56
57 // L i g h t i n g
58 QVector4D position;
59 QVector4D ambient;
60 QVector4D diffuse;
61 QVector4D specular;
62 float spec_power;
63
64 //Back and Front Colors
65 QColor front_color;
66 QColor back_color;
67
68 // M e s s a g e s
69 QString message;
70 bool _displayMessage;
71 QTimer messageTimer;
72 QOpenGLFunctions_4_3_Core* _recentFunctions;
73 bool is_2d_selection_mode;
74
75 // D e p t h P e e l i n g
76 // \param pass the current pass in the Depth Peeling (transparency) algorithm.
77 // -1 means that no depth peeling is applied.
78 // \param writing_depth means that the color of the faces will be drawn in a grayscale
79 // according to the depth of the fragment in the shader. It is used by the transparency.
80 // \param fbo contains the texture used by the Depth Peeling algorithm.
81 // Should be NULL if pass <= 0;
82 int current_pass;
83 bool writing_depth;
84 int total_pass;
85 int current_total_pass;
86 QOpenGLFramebufferObject* dp_fbo;
87 QOpenGLDebugLogger *logger;
88
89
90 //! The buffers used to draw the axis system
91 QOpenGLBuffer buffer;
92 //! The VAO used to draw the axis system
93 QOpenGLVertexArrayObject vao;
94 //! The rendering program used to draw the distance
95 QOpenGLShaderProgram rendering_program_dist;
96 QList<TextItem*> distance_text;
97 //! Decides if the text is displayed in the drawVisualHints function.
98 bool has_text;
99 //! Decides if the distance between APoint and BPoint must be drawn;
100 bool distance_is_displayed;
101 bool i_is_pressed;
102 bool z_is_pressed;
103 QImage static_image;
104 //!Draws the distance between two selected points.
105 void showDistance(QPoint);
106 CGAL::qglviewer::Vec APoint;
107 CGAL::qglviewer::Vec BPoint;
108 bool is_d_pressed;
109 bool extension_is_found;
110 int quality;
111
112 TextRenderer *textRenderer;
113 //!Clears the distance display
114 void clearDistancedisplay();
115 void draw_aux(bool with_names, Viewer*);
116 //! Contains all the programs for the item rendering.
117 static std::vector<QOpenGLShaderProgram*> shader_programs;
118 QMatrix4x4 projectionMatrix;
119 void sendSnapshotToClipboard(Viewer*);
shaderPrograms()120 std::vector<QOpenGLShaderProgram*>& shaderPrograms()
121 {
122 return shader_programs;
123 }
124
125 #ifdef CGAL_USE_WEBSOCKETS
126 QWebSocket m_webSocket;
127 #endif
128 bool is_connected;
129 QString session;
130 QUrl m_url;
131 };
132
133 class LightingDialog :
134 public QDialog,
135 public Ui::LightingDialog
136 {
137 Q_OBJECT
138 public:
139 QColor ambient, diffuse, specular;
LightingDialog(Viewer_impl * d)140 LightingDialog(Viewer_impl* d)
141 {
142 setupUi(this);
143 position_lineEdit->setText(QString("%1,%2,%3")
144 .arg(d->position.x())
145 .arg(d->position.y())
146 .arg(d->position.z()));
147 QPalette palette;
148 ambient=QColor::fromRgbF(d->ambient.x(),
149 d->ambient.y(),
150 d->ambient.z());
151 palette.setColor(QPalette::Button,ambient);
152 ambientButton->setPalette(palette);
153 ambientButton->setStyle(QStyleFactory::create("Fusion"));
154
155 diffuse=QColor::fromRgbF(d->diffuse.x(),
156 d->diffuse.y(),
157 d->diffuse.z());
158 palette.setColor(QPalette::Button,diffuse);
159 diffuseButton->setPalette(palette);
160 diffuseButton->setStyle(QStyleFactory::create("Fusion"));
161
162 specular=QColor::fromRgbF(d->specular.x(),
163 d->specular.y(),
164 d->specular.z());
165 palette.setColor(QPalette::Button,specular);
166 specularButton->setPalette(palette);
167 specularButton->setStyle(QStyleFactory::create("Fusion"));
168 spec_powrSlider->setValue(static_cast<int>(d->spec_power));
169
170 connect(&ambient_dial, &QColorDialog::currentColorChanged, this, &LightingDialog::ambient_changed );
171 connect(&diffuse_dial, &QColorDialog::currentColorChanged, this, &LightingDialog::diffuse_changed );
172 connect(&spec_dial, &QColorDialog::currentColorChanged, this, &LightingDialog::specular_changed);
173
174 connect(ambientButton, &QPushButton::clicked,
175 [this](){
176 ambient_dial.setCurrentColor(ambient);
177 ambient_dial.exec();
178 ambient = ambient_dial.selectedColor();
179 QPalette palette;
180 palette.setColor(QPalette::Button, ambient);
181 ambientButton->setPalette(palette);
182 });
183 connect(diffuseButton, &QPushButton::clicked,
184 [this](){
185 diffuse_dial.setCurrentColor(diffuse);
186 diffuse_dial.exec();
187 diffuse = diffuse_dial.selectedColor();
188 QPalette palette;
189 palette.setColor(QPalette::Button, diffuse);
190 diffuseButton->setPalette(palette);
191 });
192 connect(specularButton, &QPushButton::clicked,
193 [this](){
194 spec_dial.setCurrentColor(specular);
195 spec_dial.exec();
196 specular = spec_dial.selectedColor();
197 QPalette palette;
198 palette.setColor(QPalette::Button, specular);
199 specularButton->setPalette(palette);
200 });
201
202 //D e f a u l t - S e t t i n g s
203 connect(buttonBox->button(QDialogButtonBox::StandardButton::RestoreDefaults), &QPushButton::clicked,
204 [this](){
205 position_lineEdit->setText(QString("0,0,1"));
206 ambient=QColor(77,77,77);
207 diffuse=QColor(204,204,204);
208 specular=QColor(0,0,0);
209 spec_powrSlider->setValue(51);
210 QPalette palette;
211 palette.setColor(QPalette::Button, ambient);
212 ambientButton->setPalette(palette);
213 palette.setColor(QPalette::Button, diffuse);
214 diffuseButton->setPalette(palette);
215 palette.setColor(QPalette::Button, specular);
216 specularButton->setPalette(palette);
217 });
218 }
219 private Q_SLOTS:
diffuse_changed()220 void diffuse_changed()
221 {
222 diffuse = diffuse_dial.currentColor();
223 s_diffuse_changed();
224 }
ambient_changed()225 void ambient_changed()
226 {
227 ambient = ambient_dial.currentColor();
228 s_ambient_changed();
229 }
specular_changed()230 void specular_changed()
231 {
232 specular = spec_dial.currentColor();
233 s_specular_changed();
234 }
235 Q_SIGNALS:
236 void s_diffuse_changed();
237 void s_ambient_changed();
238 void s_specular_changed();
239 private:
240 QColorDialog diffuse_dial;
241 QColorDialog ambient_dial;
242 QColorDialog spec_dial;
243 };
244
245 std::vector<QOpenGLShaderProgram*> Viewer_impl::shader_programs =
246 std::vector<QOpenGLShaderProgram*>(Viewer::NB_OF_PROGRAMS);
doBindings()247 void Viewer::doBindings()
248 {
249 QSettings viewer_settings;
250 // enable anti-aliasing
251 QString cam_pos = viewer_settings.value("cam_pos", QString("0.0,0.0,1.0")).toString();
252 d->position = QVector4D(cam_pos.split(",").at(0).toFloat(),
253 cam_pos.split(",").at(1).toFloat(),
254 cam_pos.split(",").at(2).toFloat(),
255 1.0f);
256
257 QString ambient = viewer_settings.value("ambient", QString("0.4,0.4,0.4")).toString();
258 d->ambient = QVector4D(ambient.split(",").at(0).toFloat(),
259 ambient.split(",").at(1).toFloat(),
260 ambient.split(",").at(2).toFloat(),
261 1.0f);
262
263 QString diffuse = viewer_settings.value("diffuse", QString("1.0,1.0,1.0")).toString();
264 d->diffuse = QVector4D(diffuse.split(",").at(0).toFloat(),
265 diffuse.split(",").at(1).toFloat(),
266 diffuse.split(",").at(2).toFloat(),
267 1.0f);
268
269 QString specular = viewer_settings.value("specular", QString("0.0,0.0,0.0")).toString();
270 d->specular = QVector4D(specular.split(",").at(0).toFloat(),
271 specular.split(",").at(1).toFloat(),
272 specular.split(",").at(2).toFloat(),
273 1.0f);
274
275 QString front_color = viewer_settings.value("front_color", QString("1.0,0.0,0.0")).toString();
276 d->front_color= QColor::fromRgbF(front_color.split(",").at(0).toFloat(),
277 front_color.split(",").at(1).toFloat(),
278 front_color.split(",").at(2).toFloat(),
279 1.0f);
280 QString back_color = viewer_settings.value("back_color", QString("0.0,0.0,1.0")).toString();
281 d->back_color= QColor::fromRgbF( back_color.split(",").at(0).toFloat(),
282 back_color.split(",").at(1).toFloat(),
283 back_color.split(",").at(2).toFloat(),
284 1.0f);
285 d->spec_power = viewer_settings.value("spec_power", 51.8).toFloat();
286 d->scene = nullptr;
287 d->projection_is_ortho = false;
288 d->cam_sharing = false;
289 d->twosides = false;
290 this->setProperty("draw_two_sides", false);
291 this->setProperty("back_front_shading", false);
292 d->macro_mode = false;
293 d->inFastDrawing = true;
294 d->inDrawWithNames = false;
295 d->clipping = false;
296 d->shader_programs.resize(NB_OF_PROGRAMS);
297 d->textRenderer = new TextRenderer();
298 d->is_2d_selection_mode = false;
299 d->is_connected = false;
300 d->scene_scaling = false;
301 d->scaler = QVector3D(1,1,1);
302
303 connect( d->textRenderer, SIGNAL(sendMessage(QString,int)),
304 this, SLOT(printMessage(QString,int)) );
305 connect(&d->messageTimer, SIGNAL(timeout()), SLOT(hideMessage()));
306 setShortcut(CGAL::qglviewer::EXIT_VIEWER, 0);
307 setKeyDescription(Qt::Key_T,
308 tr("Turn the camera by 180 degrees"));
309 setKeyDescription(Qt::Key_M,
310 tr("Toggle macro mode: useful to view details very near from the camera, "
311 "but decrease the z-buffer precision"));
312 setKeyDescription(Qt::Key_I + Qt::CTRL,
313 tr("Toggle the primitive IDs visibility of the selected Item, for the types selected in the context menu of the said item."));
314 setKeyDescription(Qt::Key_D,
315 tr("Disable the distance between two points visibility."));
316 setKeyDescription(Qt::Key_F5,
317 tr("Reload selected items if possible."));
318
319 //modify mouse bindings that have been updated
320 setMouseBinding(Qt::Key(0), Qt::NoModifier, Qt::LeftButton, CGAL::qglviewer::RAP_FROM_PIXEL, true, Qt::RightButton);
321 setMouseBinding(Qt::ShiftModifier, Qt::RightButton, CGAL::qglviewer::NO_CLICK_ACTION, false, Qt::NoButton);
322 setMouseBindingDescription(Qt::ShiftModifier, Qt::RightButton,
323 tr("Select and pop context menu"));
324 setMouseBinding(Qt::Key_R, Qt::NoModifier, Qt::LeftButton, CGAL::qglviewer::RAP_FROM_PIXEL);
325
326 //use the new API for these
327 setMouseBinding(Qt::ShiftModifier, Qt::LeftButton, CGAL::qglviewer::SELECT);
328
329 setMouseBindingDescription(Qt::Key_I, Qt::NoModifier, Qt::LeftButton,
330 tr("Show/hide the primitive ID of the types selected in the context menu of the picked item."));
331 setMouseBindingDescription(Qt::Key_D, Qt::NoModifier, Qt::LeftButton,
332 tr("Selects a point. When the second point is selected, "
333 "displays the two points and the distance between them."));
334 setMouseBindingDescription(Qt::Key_O, Qt::NoModifier, Qt::LeftButton,
335 tr("Move the camera orthogonally to the picked facet of a Scene_surface_mesh_item or "
336 "to the current selection of a Scene_points_with_normal_item."));
337 setKeyDescription(Qt::Key_F5,
338 tr("Reloads the selected item if possible."));
339 setKeyDescription(Qt::Key_F11,
340 tr("Toggle the viewer's fullscreen mode."));
341
342 prev_radius = sceneRadius();
343 d->has_text = false;
344 d->i_is_pressed = false;
345 d->z_is_pressed = false;
346 d->distance_is_displayed = false;
347 d->is_d_pressed = false;
348 d->viewer = this;
349 setTextIsEnabled(true);
350 }
351
Viewer(QWidget * parent,bool antialiasing)352 Viewer::Viewer(QWidget* parent, bool antialiasing)
353 : CGAL::Three::Viewer_interface(parent)
354 {
355 d = new Viewer_impl;
356 d->antialiasing = antialiasing;
357 doBindings();
358 }
359
Viewer(QWidget * parent,Viewer * sharedWidget,bool antialiasing)360 Viewer::Viewer(QWidget* parent,
361 Viewer* sharedWidget,
362 bool antialiasing)
363 : CGAL::Three::Viewer_interface(parent, sharedWidget)
364 {
365 d = new Viewer_impl;
366 d->viewer = this;
367 d->shareViewer = sharedWidget;
368 is_sharing = true;
369 d->antialiasing = antialiasing;
370 this->setProperty("draw_two_sides", false);
371 this->setProperty("back_front_shading", false);
372 this->setProperty("helpText", QString("This is a sub-viewer. It displays the scene "
373 "from another point of view. \n "));
374 is_ogl_4_3 = sharedWidget->is_ogl_4_3;
375 d->_recentFunctions = sharedWidget->d->_recentFunctions;
376 doBindings();
377 d->total_pass = sharedWidget->total_pass();
378 setOffset(sharedWidget->offset());
379 }
380
~Viewer()381 Viewer::~Viewer()
382 {
383 makeCurrent();
384 QSettings viewer_settings;
385 viewer_settings.setValue("cam_pos",
386 QString("%1,%2,%3")
387 .arg(d->position.x())
388 .arg(d->position.y())
389 .arg(d->position.z()));
390 viewer_settings.setValue("ambient",
391 QString("%1,%2,%3")
392 .arg(d->ambient.x())
393 .arg(d->ambient.y())
394 .arg(d->ambient.z()));
395 viewer_settings.setValue("diffuse",
396 QString("%1,%2,%3")
397 .arg(d->diffuse.x())
398 .arg(d->diffuse.y())
399 .arg(d->diffuse.z()));
400 viewer_settings.setValue("specular",
401 QString("%1,%2,%3")
402 .arg(d->specular.x())
403 .arg(d->specular.y())
404 .arg(d->specular.z()));
405 viewer_settings.setValue("spec_power",
406 d->spec_power);
407 viewer_settings.setValue("front_color",
408 QString("%1,%2,%3")
409 .arg(d->front_color.redF())
410 .arg(d->front_color.greenF())
411 .arg(d->front_color.blueF()));
412 viewer_settings.setValue("back_color",
413 QString("%1,%2,%3")
414 .arg(d->back_color.redF())
415 .arg(d->back_color.greenF())
416 .arg(d->back_color.blueF()));
417 makeCurrent();
418 d->vao.destroy();
419 if(d->_recentFunctions)
420 delete d->_recentFunctions;
421 if(d->painter)
422 delete d->painter;
423 if(d->textRenderer)
424 d->textRenderer->deleteLater();
425 delete d;
426
427 }
428
setScene(CGAL::Three::Scene_draw_interface * scene)429 void Viewer::setScene(CGAL::Three::Scene_draw_interface* scene)
430 {
431 d->scene = scene;
432 }
433
antiAliasing() const434 bool Viewer::antiAliasing() const
435 {
436 return d->antialiasing;
437 }
438
setAntiAliasing(bool b)439 void Viewer::setAntiAliasing(bool b)
440 {
441 d->antialiasing = b;
442 update();
443 }
444
setTwoSides(bool b)445 void Viewer::setTwoSides(bool b)
446 {
447 this->setProperty("draw_two_sides", b);
448 d->twosides = b;
449 update();
450 }
451
452
setBackFrontShading(bool b)453 void Viewer::setBackFrontShading(bool b)
454 {
455 this->setProperty("back_front_shading", b);
456 update();
457 }
458
459
setFastDrawing(bool b)460 void Viewer::setFastDrawing(bool b)
461 {
462 d->inFastDrawing = b;
463 update();
464 }
465
inFastDrawing() const466 bool Viewer::inFastDrawing() const
467 {
468 return (d->inFastDrawing
469 && (camera()->frame()->isSpinning()
470 || camera()->frame()->isManipulated()));
471 }
472
draw()473 void Viewer::draw()
474 {
475 glEnable(GL_DEPTH_TEST);
476 d->draw_aux(false, this);
477 }
478
fastDraw()479 void Viewer::fastDraw()
480 {
481 d->draw_aux(false, this);
482 }
483
init()484 void Viewer::init()
485 {
486 if(!isOpenGL_4_3())
487 {
488 std::cerr<<"The openGL context initialization failed "
489 "and the default context (2.0 ES) will be used. \n"
490 " This means, among other things, that no widelines can be displayed,"
491 " which makes selected edges harder to see." <<std::endl;
492 }
493 else
494 {
495 d->_recentFunctions = new QOpenGLFunctions_4_3_Core();
496 d->_recentFunctions->initializeOpenGLFunctions();
497 }
498 d->logger = new QOpenGLDebugLogger(this);
499 if(!d->logger->initialize())
500 qDebug()<<"logger could not init.";
501 else{
502 connect(d->logger, SIGNAL(messageLogged(QOpenGLDebugMessage)), this, SLOT(messageLogged(QOpenGLDebugMessage)));
503 d->logger->startLogging();
504 }
505 glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDARBPROC)this->context()->getProcAddress("glDrawArraysInstancedARB");
506 if(!glDrawArraysInstanced)
507 {
508 qDebug()<<"glDrawArraysInstancedARB : extension not found. Spheres will be displayed as points.";
509 d->extension_is_found = false;
510 }
511 else
512 d->extension_is_found = true;
513
514 glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORARBPROC)this->context()->getProcAddress("glVertexAttribDivisorARB");
515 if(!glDrawArraysInstanced)
516 {
517 qDebug()<<"glVertexAttribDivisorARB : extension not found. Spheres will be displayed as points.";
518 d->extension_is_found = false;
519 }
520 else
521 d->extension_is_found = true;
522 QSettings settings;
523 QString colorname = settings.value("background_color", "#ffffff").toString();
524 QColor bc(colorname);
525 setBackgroundColor(bc);
526 d->vao.create();
527 d->buffer.create();
528
529 //setting the program used for the distance
530 if(!is_linked)
531 {
532 //Vertex source code
533 const char vertex_source_dist[] =
534 {
535 "#version 150 \n"
536 "in vec4 vertex;\n"
537 "uniform mat4 mvp_matrix;\n"
538 "uniform float point_size;\n"
539 "void main(void)\n"
540 "{\n"
541 " gl_PointSize = point_size; \n"
542 " gl_Position = mvp_matrix * vertex; \n"
543 "} \n"
544 "\n"
545 };
546 const char vertex_source_comp_dist[] =
547 {
548 "attribute highp vec4 vertex;\n"
549 "uniform highp mat4 mvp_matrix;\n"
550 "uniform highp float point_size;\n"
551 "void main(void)\n"
552 "{\n"
553 " gl_PointSize = point_size; \n"
554 " gl_Position = mvp_matrix * vertex; \n"
555 "} \n"
556 "\n"
557 };
558 //Fragment source code
559 const char fragment_source_dist[] =
560 {
561 "#version 150 \n"
562 "out vec4 out_color; \n"
563 "void main(void) { \n"
564 "out_color = vec4(0.0,0.0,0.0,1.0); \n"
565 "} \n"
566 "\n"
567 };
568 const char fragment_source_comp_dist[] =
569 {
570 "void main(void) { \n"
571 "gl_FragColor = vec4(0.0,0.0,0.0,1.0); \n"
572 "} \n"
573 "\n"
574 };
575 QOpenGLShader vertex_shader(QOpenGLShader::Vertex);
576 QOpenGLShader fragment_shader(QOpenGLShader::Fragment);
577 if(isOpenGL_4_3())
578 {
579 if(!vertex_shader.compileSourceCode(vertex_source_dist))
580 {
581 std::cerr<<"Compiling vertex source FAILED"<<std::endl;
582 }
583
584 if(!fragment_shader.compileSourceCode(fragment_source_dist))
585 {
586 std::cerr<<"Compiling fragmentsource FAILED"<<std::endl;
587 }
588 }
589 else
590 {
591 if(!vertex_shader.compileSourceCode(vertex_source_comp_dist))
592 {
593 std::cerr<<"Compiling vertex source FAILED"<<std::endl;
594 }
595
596 if(!fragment_shader.compileSourceCode(fragment_source_comp_dist))
597 {
598 std::cerr<<"Compiling fragmentsource FAILED"<<std::endl;
599 }
600 }
601 if(!d->rendering_program_dist.addShader(&vertex_shader))
602 {
603 std::cerr<<"adding vertex shader FAILED"<<std::endl;
604 }
605 if(!d->rendering_program_dist.addShader(&fragment_shader))
606 {
607 std::cerr<<"adding fragment shader FAILED"<<std::endl;
608 }
609 if(!d->rendering_program_dist.link())
610 {
611 qDebug() << d->rendering_program_dist.log();
612 }
613 }
614 d->painter = new QPainter();
615 }
616
617 #include <QMouseEvent>
618
mousePressEvent(QMouseEvent * event)619 void Viewer::mousePressEvent(QMouseEvent* event)
620 {
621 makeCurrent();
622 if(event->button() == Qt::RightButton &&
623 event->modifiers().testFlag(Qt::ShiftModifier))
624 {
625 select(event->pos());
626 requestContextMenu(event->globalPos());
627 event->accept();
628 }
629 else if(!event->modifiers()
630 && event->button() == Qt::LeftButton
631 && d->i_is_pressed)
632 {
633 d->scene->printPrimitiveId(event->pos(), this);
634 }
635 else if(!event->modifiers()
636 && event->button() == Qt::LeftButton
637 && d->z_is_pressed)
638 {
639 d->scene->zoomToPosition(event->pos(), this);
640 }
641 else if(!event->modifiers()
642 && event->button() == Qt::LeftButton
643 && d->is_d_pressed)
644 {
645 d->showDistance(event->pos());
646 event->accept();
647 }
648 else{
649 makeCurrent();
650 CGAL::QGLViewer::mousePressEvent(event);
651 }
652 }
mouseDoubleClickEvent(QMouseEvent * event)653 void Viewer::mouseDoubleClickEvent(QMouseEvent* event)
654 {
655 makeCurrent();
656 CGAL::QGLViewer::mouseDoubleClickEvent(event);
657 }
658
659 #include <QContextMenuEvent>
contextMenuEvent(QContextMenuEvent * event)660 void Viewer::contextMenuEvent(QContextMenuEvent* event)
661 {
662 if(event->reason() != QContextMenuEvent::Mouse) {
663 requestContextMenu(event->globalPos());
664 event->accept();
665 }
666 else {
667 CGAL::QGLViewer::contextMenuEvent(event);
668 }
669 }
670
keyPressEvent(QKeyEvent * e)671 void Viewer::keyPressEvent(QKeyEvent* e)
672 {
673 if(!e->modifiers()) {
674 if(e->key() == Qt::Key_T) {
675 turnCameraBy180Degres();
676 return;
677 }
678 else if(e->key() == Qt::Key_M) {
679 d->macro_mode = ! d->macro_mode;
680 switch(camera()->type()){
681 case CGAL::qglviewer::Camera::PERSPECTIVE:
682 if(d->macro_mode) {
683 camera()->setZNearCoefficient(0.0005f);
684 } else {
685 camera()->setZNearCoefficient(0.005f);
686 }
687 break;
688 case CGAL::qglviewer::Camera::ORTHOGRAPHIC:
689 if(d->macro_mode) {
690 camera()->setOrthoZNear(-0.5f);
691 } else {
692 camera()->setOrthoZNear(0.0f);
693 }
694 break;
695 default:
696 break;
697 }
698 this->displayMessage(tr("Macro mode: %1").
699 arg(d->macro_mode ? tr("on") : tr("off")));
700
701
702
703 return;
704 }
705 else if(e->key() == Qt::Key_I) {
706 d->i_is_pressed = true;
707 }
708 else if(e->key() == Qt::Key_O) {
709 d->z_is_pressed = true;
710 }
711 else if(e->key() == Qt::Key_D) {
712 if(e->isAutoRepeat())
713 {
714 return;
715 }
716 if(!d->is_d_pressed)
717 {
718 d->clearDistancedisplay();
719 }
720 d->is_d_pressed = true;
721 update();
722 return;
723 }
724 }
725 else if(e->key() == Qt::Key_I && e->modifiers() & Qt::ControlModifier){
726 d->scene->printAllIds();
727 update();
728 return;
729 }
730
731 else if(e->key() == Qt::Key_C && e->modifiers() & Qt::ControlModifier){
732 d->sendSnapshotToClipboard(this);
733 return;
734 }
735
736 else if(e->key() == Qt::Key_S && e->modifiers() & Qt::ControlModifier){
737 this->saveSnapshot();
738 return;
739 }
740
741 //forward the event to the scene (item handling of the event)
742 if (! d->scene->keyPressEvent(e) )
743 CGAL::QGLViewer::keyPressEvent(e);
744 }
745
keyReleaseEvent(QKeyEvent * e)746 void Viewer::keyReleaseEvent(QKeyEvent *e)
747 {
748 if(e->key() == Qt::Key_I) {
749 d->i_is_pressed = false;
750 }
751 else if(e->key() == Qt::Key_O) {
752 d->z_is_pressed = false;
753 }
754 else if(!e->modifiers() && e->key() == Qt::Key_D)
755 {
756 if(e->isAutoRepeat())
757 {
758 return;
759 }
760 d->is_d_pressed = false;
761 }
762 CGAL::QGLViewer::keyReleaseEvent(e);
763 }
764
turnCameraBy180Degres()765 void Viewer::turnCameraBy180Degres() {
766 CGAL::qglviewer::Camera* camera = this->camera();
767 using CGAL::qglviewer::ManipulatedCameraFrame;
768
769 ManipulatedCameraFrame frame_from(*camera->frame());
770 camera->setViewDirection(-camera->viewDirection());
771 ManipulatedCameraFrame frame_to(*camera->frame());
772
773 camera->setOrientation(frame_from.orientation());
774 camera->interpolateTo(frame_to, 0.5f);
775 }
776
draw_aux(bool with_names,Viewer * viewer)777 void Viewer_impl::draw_aux(bool with_names, Viewer* viewer)
778 {
779 if(scene == nullptr)
780 return;
781 current_total_pass = viewer->inFastDrawing() ? total_pass/2 : total_pass;
782 viewer->setGlPointSize(2.f);
783 viewer->glEnable(GL_POLYGON_OFFSET_FILL);
784 viewer->glPolygonOffset(1.0f,1.0f);
785
786 if(!with_names && antialiasing)
787 {
788 viewer->glEnable(GL_BLEND);
789 viewer->glEnable(GL_LINE_SMOOTH);
790 viewer->glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
791 //viewer->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
792 viewer->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
793 }
794 else
795 {
796 viewer->glDisable(GL_BLEND);
797 viewer->glDisable(GL_LINE_SMOOTH);
798 viewer->glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
799 //viewer->glBlendFunc(GL_ONE, GL_ZERO);
800 viewer->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
801 }
802 inDrawWithNames = with_names;
803 if(with_names)
804 scene->drawWithNames(viewer);
805 else
806 scene->draw(viewer);
807 viewer->glDisable(GL_POLYGON_OFFSET_FILL);
808 }
809
inDrawWithNames() const810 bool Viewer::inDrawWithNames() const {
811 return d->inDrawWithNames;
812 }
813
drawWithNames()814 void Viewer::drawWithNames()
815 {
816 CGAL::QGLViewer::draw();
817 d->draw_aux(true, this);
818 }
819
postSelection(const QPoint & pixel)820 void Viewer::postSelection(const QPoint& pixel)
821 {
822 Q_EMIT selected(this->selectedName());
823 CGAL::qglviewer::Vec point;
824 bool found = true;
825 if(property("picked_point").isValid()) {
826 if(!property("picked_point").toList().isEmpty())
827 {
828 QList<QVariant> picked_point = property("picked_point").toList();
829 point = CGAL::qglviewer::Vec (picked_point[0].toDouble(),
830 picked_point[1].toDouble(),
831 picked_point[2].toDouble());
832 }
833 else{
834 found = false;
835 }
836 }
837 else{
838 point = camera()->pointUnderPixel(pixel, found) - offset();
839 }
840 if(found) {
841 QVector3D transformed_point(point.x,
842 point.y,
843 point.z);
844 if(d->scene_scaling)
845 {
846 transformed_point = QVector3D(
847 point.x+offset().x,
848 point.y+offset().y,
849 point.z+offset().z);
850 transformed_point = transformed_point/d->scaler;
851 transformed_point[0] -=offset().x ;
852 transformed_point[1] -=offset().y ;
853 transformed_point[2] -=offset().z ;
854 }
855 Q_EMIT selectedPoint(transformed_point.x(),
856 transformed_point.y(),
857 transformed_point.z());
858 CGAL::qglviewer::Vec dir;
859 CGAL::qglviewer::Vec orig;
860 if(d->projection_is_ortho)
861 {
862 dir = camera()->viewDirection();
863 orig = point;
864 }
865 else{
866 orig = camera()->position() - offset();
867 dir = point - orig;
868 }
869 this->setProperty("performing_selection", true);
870 Q_EMIT selectionRay(orig.x, orig.y, orig.z,
871 dir.x, dir.y, dir.z);
872 this->setProperty("performing_selection", false);
873 }
874 }
readFrame(QString s,CGAL::qglviewer::Frame & frame)875 bool CGAL::Three::Viewer_interface::readFrame(QString s, CGAL::qglviewer::Frame& frame)
876 {
877 QStringList list = s.split(" ", CGAL_QT_SKIP_EMPTY_PARTS);
878 if(list.size() != 7)
879 return false;
880 float vec[3];
881 for(int i = 0; i < 3; ++i)
882 {
883 bool ok;
884 vec[i] = list[i].toFloat(&ok);
885 if(!ok) return false;
886 }
887 double orient[4];
888 for(int i = 0; i < 4; ++i)
889 {
890 bool ok;
891 orient[i] = list[i + 3].toDouble(&ok);
892 if(!ok) return false;
893 }
894 frame.setPosition(CGAL::qglviewer::Vec(vec[0],
895 vec[1],
896 vec[2]));
897 frame.setOrientation(orient[0],
898 orient[1],
899 orient[2],
900 orient[3]);
901 return true;
902 }
903
dumpFrame(const CGAL::qglviewer::Frame & frame)904 QString CGAL::Three::Viewer_interface::dumpFrame(const CGAL::qglviewer::Frame& frame) {
905 const CGAL::qglviewer::Vec pos = frame.position();
906 const CGAL::qglviewer::Quaternion q = frame.orientation();
907
908 return QString("%1 %2 %3 %4 %5 %6 %7")
909 .arg(pos[0])
910 .arg(pos[1])
911 .arg(pos[2])
912 .arg(q[0])
913 .arg(q[1])
914 .arg(q[2])
915 .arg(q[3]);
916 }
917
moveCameraToCoordinates(QString s,float animation_duration)918 bool Viewer::moveCameraToCoordinates(QString s, float animation_duration) {
919 CGAL::qglviewer::Frame new_frame;
920 if(readFrame(s, new_frame)) {
921 camera()->interpolateTo(new_frame, animation_duration);
922 return true;
923 }
924 else
925 return false;
926 }
927
dumpCameraCoordinates()928 QString Viewer::dumpCameraCoordinates()
929 {
930 if(camera()->frame()) {
931 return dumpFrame(*camera()->frame());
932 } else {
933 return QString();
934 }
935 }
936
attribBuffers(int program_name) const937 void Viewer::attribBuffers(int program_name) const {
938 //ModelViewMatrix used for the transformation of the camera.
939 QMatrix4x4 mvp_mat;
940 // ModelView Matrix used for the lighting system
941 QMatrix4x4 mv_mat;
942 // transformation of the manipulated frame
943 QMatrix4x4 f_mat;
944 // ModelView Matrix that is modified just for the normal matrix in case of scene scaling
945 QMatrix4x4 norm_mat;
946
947 f_mat.setToIdentity();
948 //fills the MVP and MV matrices.
949 GLdouble d_mat[16];
950 this->camera()->getModelViewMatrix(d_mat);
951 for (int i=0; i<16; ++i)
952 mv_mat.data()[i] = GLfloat(d_mat[i]);
953 this->camera()->getModelViewProjectionMatrix(d_mat);
954 for (int i=0; i<16; ++i)
955 mvp_mat.data()[i] = GLfloat(d_mat[i]);
956
957 norm_mat = mv_mat;
958
959 if(d->scene_scaling){
960 mvp_mat.scale(d->scaler);
961 mv_mat.scale(d->scaler);
962 QVector3D scale_norm(1.0/d->scaler.x(), 1.0/d->scaler.y(), 1.0/d->scaler.z());
963 norm_mat.scale(scale_norm);
964 }
965
966 QOpenGLShaderProgram* program = getShaderProgram(program_name);
967 program->bind();
968 program->setUniformValue("point_size", getGlPointSize());
969 program->setUniformValue("mvp_matrix", mvp_mat);
970 QMatrix4x4 id_mat;
971 id_mat.setToIdentity();
972 program->setUniformValue("f_matrix", id_mat);
973 program->setUniformValue("is_clipbox_on", d->clipping);
974 if(d->clipping)
975 {
976 QMatrix4x4 clipbox1;
977 QMatrix4x4 clipbox2;
978 for(int i=0;i<12;++i)
979 {
980 clipbox1.data()[i]=d->clipbox[i/4][i%4];
981 clipbox2.data()[i]=d->clipbox[(i+12)/4][(i+12)%4];
982 }
983 program->setUniformValue("clipbox1", clipbox1);
984 program->setUniformValue("clipbox2", clipbox2);
985 }
986 QVector4D light_pos(d->position.x(),
987 d->position.y(),
988 d->position.z(),
989 1.0f);
990 switch(program_name)
991 {
992 case PROGRAM_WITH_LIGHT:
993 case PROGRAM_SPHERES:
994 case PROGRAM_CUTPLANE_SPHERES:
995 case PROGRAM_NO_SELECTION:
996 case PROGRAM_HEAT_INTENSITY:
997 program->setUniformValue("alpha", 1.0f); //overriden in item draw() if necessary
998 default:
999 break;
1000 }
1001 switch(program_name)
1002 {
1003 case PROGRAM_SPHERES:
1004 case PROGRAM_DARK_SPHERES:
1005 case PROGRAM_WITH_LIGHT:
1006 case PROGRAM_OLD_FLAT:
1007 program->setUniformValue("f_matrix",f_mat);
1008 default:
1009 break;
1010 }
1011
1012 switch(program_name)
1013 {
1014 case PROGRAM_WITH_LIGHT:
1015 case PROGRAM_C3T3:
1016 case PROGRAM_PLANE_TWO_FACES:
1017 case PROGRAM_INSTANCED:
1018 case PROGRAM_WITH_TEXTURE:
1019 case PROGRAM_CUTPLANE_SPHERES:
1020 case PROGRAM_SPHERES:
1021 case PROGRAM_OLD_FLAT:
1022 case PROGRAM_FLAT:
1023 case PROGRAM_NO_INTERPOLATION:
1024 case PROGRAM_HEAT_INTENSITY:
1025 program->setUniformValue("light_pos", light_pos);
1026 program->setUniformValue("light_diff",d->diffuse);
1027 program->setUniformValue("light_spec", d->specular);
1028 program->setUniformValue("light_amb", d->ambient);
1029 program->setUniformValue("spec_power", d->spec_power);
1030 program->setUniformValue("front_color", d->front_color);
1031 program->setUniformValue("back_color", d->back_color);
1032 program->setUniformValue("is_two_side", d->twosides);
1033 program->setUniformValue("back_front_shading", this->property("back_front_shading").toBool());
1034 break;
1035 }
1036 switch(program_name)
1037 {
1038 case PROGRAM_WITH_LIGHT:
1039 case PROGRAM_C3T3:
1040 case PROGRAM_PLANE_TWO_FACES:
1041 case PROGRAM_INSTANCED:
1042 case PROGRAM_CUTPLANE_SPHERES:
1043 case PROGRAM_SPHERES:
1044 case PROGRAM_OLD_FLAT:
1045 case PROGRAM_FLAT:
1046 case PROGRAM_NO_INTERPOLATION:
1047 case PROGRAM_HEAT_INTENSITY:
1048 program->setUniformValue("mv_matrix", mv_mat);
1049 program->setUniformValue("norm_matrix", norm_mat);
1050 break;
1051 case PROGRAM_WITHOUT_LIGHT:
1052 case PROGRAM_SOLID_WIREFRAME:
1053 break;
1054 case PROGRAM_WITH_TEXTURE:
1055 program->setUniformValue("mv_matrix", mv_mat);
1056 program->setUniformValue("norm_matrix", norm_mat);
1057 program->setUniformValue("s_texture",0);
1058 program->setUniformValue("f_matrix",f_mat);
1059 break;
1060 case PROGRAM_WITH_TEXTURED_EDGES:
1061 program->setUniformValue("s_texture",0);
1062 break;
1063 case PROGRAM_NO_SELECTION:
1064 program->setUniformValue("f_matrix",f_mat);
1065 break;
1066 }
1067 program->release();
1068 }
1069
beginSelection(const QPoint & point)1070 void Viewer::beginSelection(const QPoint &point)
1071 {
1072 CGAL::QGLViewer::beginSelection(point);
1073 d->scene->setPickedPixel(point);
1074 }
endSelection(const QPoint & point)1075 void Viewer::endSelection(const QPoint& point)
1076 {
1077 CGAL::QGLViewer::endSelection(point);
1078 //redraw the true scene for the glReadPixel in postSelection();
1079 d->draw_aux(false, this);
1080 }
1081
drawVisualHints()1082 void Viewer::drawVisualHints()
1083 {
1084
1085 CGAL::QGLViewer::drawVisualHints();
1086
1087 if(d->distance_is_displayed)
1088 {
1089 glDisable(GL_DEPTH_TEST);
1090 QMatrix4x4 mvpMatrix;
1091 double mat[16];
1092 camera()->getModelViewProjectionMatrix(mat);
1093 for(int i=0; i < 16; i++)
1094 {
1095 mvpMatrix.data()[i] = (float)mat[i];
1096 }
1097 if(!isOpenGL_4_3())
1098 {
1099 //draws the distance
1100 //nullifies the translation
1101 d->rendering_program_dist.bind();
1102 d->rendering_program_dist.setUniformValue("mvp_matrix", mvpMatrix);
1103 d->rendering_program_dist.setUniformValue("point_size", GLfloat(6.0f));
1104 d->vao.bind();
1105 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(2));
1106 glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(2));
1107 d->vao.release();
1108 d->rendering_program_dist.release();
1109 glEnable(GL_DEPTH_TEST);
1110 }
1111 else
1112 {
1113 QOpenGLShaderProgram* program = getShaderProgram(PROGRAM_SOLID_WIREFRAME);
1114 program->bind();
1115 QVector2D vp(width(), height());
1116 program->setUniformValue("viewport", vp);
1117 program->setUniformValue("near",(GLfloat)camera()->zNear());
1118 program->setUniformValue("far",(GLfloat)camera()->zFar());
1119 program->setUniformValue("width", GLfloat(3.0f));
1120 program->setAttributeValue("colors", QColor(Qt::black));
1121 program->setUniformValue("mvp_matrix", mvpMatrix);
1122 QMatrix4x4 f_mat;
1123 f_mat.setToIdentity();
1124 program->setUniformValue("f_matrix", f_mat);
1125 d->vao.bind();
1126 glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(2));
1127 d->vao.release();
1128 program->release();
1129
1130 program = getShaderProgram(PROGRAM_NO_SELECTION);
1131 program->bind();
1132 program->setAttributeValue("colors", QColor(Qt::black));
1133 program->setAttributeValue("point_size", 6.0f);
1134 program->setUniformValue("mvp_matrix", mvpMatrix);
1135 program->setUniformValue("f_matrix", f_mat);
1136 d->vao.bind();
1137 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(2));
1138 d->vao.release();
1139 program->release();
1140 }
1141
1142 }
1143 if (!d->painter->isActive())
1144 d->painter->begin(this);
1145 //So that the text is drawn in front of everything
1146 d->painter->beginNativePainting();
1147 glDisable(GL_DEPTH_TEST);
1148 d->painter->endNativePainting();
1149 //Prints the displayMessage
1150 QFont font = QFont();
1151 QFontMetrics fm(font);
1152 TextItem *message_text = new TextItem(float(10 +
1153 #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
1154 fm.horizontalAdvance(d->message)/2)
1155 #else
1156 fm.width(d->message)/2)
1157 #endif
1158 ,
1159 float(height()-20),
1160 0, d->message, false,
1161 QFont(), Qt::gray );
1162 if (d->_displayMessage)
1163 {
1164 d->textRenderer->addText(message_text);
1165 }
1166 d->textRenderer->draw(this, d->scaler);
1167
1168 if (d->_displayMessage)
1169 d->textRenderer->removeText(message_text);
1170 delete message_text;
1171 }
1172
declare_program(int name,const char * v_shader,const char * f_shader) const1173 QOpenGLShaderProgram* Viewer::declare_program(int name,
1174 const char* v_shader,
1175 const char* f_shader) const
1176 {
1177 // workaround constness issues in Qt
1178 Viewer* viewer = const_cast<Viewer*>(this);
1179
1180 if(d->shader_programs[name])
1181 {
1182 return d->shader_programs[name];
1183 }
1184
1185 else
1186 {
1187
1188 QOpenGLShaderProgram *program = new QOpenGLShaderProgram(viewer);
1189 if(!program->addShaderFromSourceFile(QOpenGLShader::Vertex,v_shader))
1190 {
1191 std::cerr<<"adding vertex shader FAILED"<<std::endl;
1192 }
1193 if(!program->addShaderFromSourceFile(QOpenGLShader::Fragment,f_shader))
1194 {
1195 std::cerr<<"adding fragment shader FAILED"<<std::endl;
1196 }
1197 if(isOpenGL_4_3())
1198 {
1199 if(strcmp(f_shader,":/cgal/Polyhedron_3/resources/shader_flat.frag" ) == 0)
1200 {
1201 if(!program->addShaderFromSourceFile(QOpenGLShader::Geometry,":/cgal/Polyhedron_3/resources/shader_flat.geom" ))
1202 {
1203 std::cerr<<"adding geometry shader FAILED"<<std::endl;
1204 }
1205 }
1206 if(strcmp(f_shader,":/cgal/Polyhedron_3/resources/solid_wireframe_shader.frag" ) == 0)
1207 {
1208 if(!program->addShaderFromSourceFile(QOpenGLShader::Geometry,":/cgal/Polyhedron_3/resources/solid_wireframe_shader.geom" ))
1209 {
1210 std::cerr<<"adding geometry shader FAILED"<<std::endl;
1211 }
1212 }
1213 if(strcmp(f_shader,":/cgal/Polyhedron_3/resources/no_interpolation_shader.frag" ) == 0)
1214 {
1215 if(!program->addShaderFromSourceFile(QOpenGLShader::Geometry,":/cgal/Polyhedron_3/resources/no_interpolation_shader.geom" ))
1216 {
1217 std::cerr<<"adding geometry shader FAILED"<<std::endl;
1218 }
1219 }
1220 }
1221 program->bindAttributeLocation("colors", 1);
1222 program->link();
1223 d->shader_programs[name] = program;
1224 return program;
1225 }
1226 }
getShaderProgram(int name) const1227 QOpenGLShaderProgram* Viewer::getShaderProgram(int name) const
1228 {
1229 switch(name)
1230 {
1231 case PROGRAM_C3T3:
1232 {
1233 QOpenGLShaderProgram* program = isOpenGL_4_3()
1234 ? declare_program(name, ":/cgal/Polyhedron_3/resources/shader_c3t3.vert" , ":/cgal/Polyhedron_3/resources/shader_c3t3.frag")
1235 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_c3t3.vert" ,
1236 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_c3t3.frag");
1237 program->setProperty("hasLight", true);
1238 program->setProperty("hasNormals", true);
1239 program->setProperty("hasCutPlane", true);
1240 program->setProperty("hasTransparency", true);
1241 program->setProperty("hasCenter", true);
1242 program->setProperty("hasSurfaceMode", true);
1243 return program;
1244 }
1245 case PROGRAM_C3T3_EDGES:
1246 {
1247 QOpenGLShaderProgram* program = isOpenGL_4_3()
1248 ? declare_program(name, ":/cgal/Polyhedron_3/resources/shader_c3t3_edges.vert" , ":/cgal/Polyhedron_3/resources/shader_c3t3_edges.frag")
1249 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_c3t3_edges.vert" ,
1250 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_c3t3_edges.frag");
1251 program->setProperty("hasCutPlane", true);
1252 program->setProperty("hasSurfaceMode", true);
1253 return program;
1254 }
1255 case PROGRAM_WITH_LIGHT:
1256 {
1257 QOpenGLShaderProgram* program = isOpenGL_4_3()
1258 ? declare_program(name, ":/cgal/Polyhedron_3/resources/shader_with_light.vert" , ":/cgal/Polyhedron_3/resources/shader_with_light.frag")
1259 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_with_light.vert" ,
1260 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_with_light.frag");
1261 program->setProperty("hasLight", true);
1262 program->setProperty("hasNormals", true);
1263 program->setProperty("hasTransparency", true);
1264 program->setProperty("hasFMatrix", true);
1265 return program;
1266 }
1267 case PROGRAM_HEAT_INTENSITY:
1268 {
1269 QOpenGLShaderProgram* program = isOpenGL_4_3()
1270 ? declare_program(name, ":/cgal/Polyhedron_3/resources/heat_intensity_shader.vert" , ":/cgal/Polyhedron_3/resources/heat_intensity_shader.frag")
1271 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/heat_intensity_shader.vert" ,
1272 ":/cgal/Polyhedron_3/resources/compatibility_shaders/heat_intensity_shader.frag");
1273 program->setProperty("hasLight", true);
1274 program->setProperty("hasNormals", true);
1275 program->setProperty("hasTransparency", true);
1276 program->setProperty("hasDistanceValues", true);
1277 return program;
1278 }
1279 case PROGRAM_WITHOUT_LIGHT:
1280 {
1281 QOpenGLShaderProgram* program = isOpenGL_4_3()
1282 ? declare_program(name, ":/cgal/Polyhedron_3/resources/shader_without_light.vert" , ":/cgal/Polyhedron_3/resources/shader_without_light.frag")
1283 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_without_light.vert" ,
1284 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_without_light.frag");
1285 program->setProperty("hasFMatrix", true);
1286 return program;
1287 }
1288 case PROGRAM_NO_SELECTION:
1289 {
1290 QOpenGLShaderProgram* program = isOpenGL_4_3()
1291 ? declare_program(name, ":/cgal/Polyhedron_3/resources/shader_without_light.vert" , ":/cgal/Polyhedron_3/resources/shader_no_light_no_selection.frag")
1292 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_without_light.vert" ,
1293 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_no_light_no_selection.frag");
1294 program->setProperty("hasFMatrix", true);
1295 program->setProperty("hasTransparency", true);
1296 return program;
1297 }
1298 case PROGRAM_WITH_TEXTURE:
1299 {
1300 QOpenGLShaderProgram* program = isOpenGL_4_3()
1301 ? declare_program(name, ":/cgal/Polyhedron_3/resources/shader_with_texture.vert" , ":/cgal/Polyhedron_3/resources/shader_with_texture.frag")
1302 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_with_texture.vert" ,
1303 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_with_texture.frag");
1304 program->setProperty("hasLight", true);
1305 program->setProperty("hasNormals", true);
1306 program->setProperty("hasFMatrix", true);
1307 program->setProperty("hasTexture", true);
1308 return program;
1309 }
1310 case PROGRAM_PLANE_TWO_FACES:
1311 {
1312 QOpenGLShaderProgram* program = isOpenGL_4_3()
1313 ?declare_program(name, ":/cgal/Polyhedron_3/resources/shader_without_light.vert" , ":/cgal/Polyhedron_3/resources/shader_plane_two_faces.frag")
1314 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_without_light.vert" ,
1315 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_plane_two_faces.frag");
1316 program->setProperty("hasLight", true);
1317 program->setProperty("hasNormals", true);
1318 program->setProperty("hasFMatrix", true);
1319 return program;
1320 }
1321 case PROGRAM_WITH_TEXTURED_EDGES:
1322 {
1323 QOpenGLShaderProgram* program = isOpenGL_4_3()
1324 ? declare_program(name, ":/cgal/Polyhedron_3/resources/shader_with_textured_edges.vert" , ":/cgal/Polyhedron_3/resources/shader_with_textured_edges.frag")
1325 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_with_textured_edges.vert" ,
1326 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_with_textured_edges.frag");
1327 program->setProperty("hasFMatrix", true);
1328 program->setProperty("hasTexture", true);
1329 return program;
1330 }
1331 case PROGRAM_INSTANCED:
1332 {
1333 QOpenGLShaderProgram* program = isOpenGL_4_3()
1334 ? declare_program(name, ":/cgal/Polyhedron_3/resources/shader_instanced.vert" , ":/cgal/Polyhedron_3/resources/shader_with_light.frag")
1335 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_instanced.vert" ,
1336 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_with_light.frag");
1337
1338 program->setProperty("hasLight", true);
1339 program->setProperty("hasNormals", true);
1340 program->setProperty("isInstanced", true);
1341 return program;
1342 }
1343 case PROGRAM_INSTANCED_WIRE:
1344 {
1345 QOpenGLShaderProgram* program = isOpenGL_4_3()
1346 ? declare_program(name, ":/cgal/Polyhedron_3/resources/shader_instanced.vert" , ":/cgal/Polyhedron_3/resources/shader_without_light.frag")
1347 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_instanced.vert" ,
1348 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_without_light.frag");
1349 program->setProperty("hasLight", true);
1350 program->setProperty("hasNormals", true);
1351 program->setProperty("hasCenter", true);
1352 program->setProperty("isInstanced", true);
1353 return program;
1354 }
1355 case PROGRAM_CUTPLANE_SPHERES:
1356 {
1357 QOpenGLShaderProgram* program = isOpenGL_4_3()
1358 ? declare_program(name, ":/cgal/Polyhedron_3/resources/shader_c3t3_spheres.vert" , ":/cgal/Polyhedron_3/resources/shader_c3t3.frag")
1359 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_c3t3_spheres.vert" ,
1360 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_c3t3.frag");
1361 program->setProperty("hasLight", true);
1362 program->setProperty("hasNormals", true);
1363 program->setProperty("hasCenter", true);
1364 program->setProperty("hasRadius", true);
1365 program->setProperty("isInstanced", true);
1366 program->setProperty("hasCutPlane", true);
1367 return program;
1368 }
1369 case PROGRAM_SPHERES:
1370 {
1371 QOpenGLShaderProgram* program = isOpenGL_4_3()
1372 ?declare_program(name, ":/cgal/Polyhedron_3/resources/shader_spheres.vert" , ":/cgal/Polyhedron_3/resources/shader_with_light.frag")
1373 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_spheres.vert" ,
1374 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_with_light.frag");
1375 program->setProperty("hasLight", true);
1376 program->setProperty("hasNormals", true);
1377 program->setProperty("hasCenter", true);
1378 program->setProperty("hasRadius", true);
1379 program->setProperty("hasTransparency", true);
1380 program->setProperty("isInstanced", true);
1381 program->setProperty("hasFMatrix", true);
1382 return program;
1383 }
1384 case PROGRAM_DARK_SPHERES:
1385 {
1386 QOpenGLShaderProgram* program = isOpenGL_4_3()
1387 ?declare_program(name, ":/cgal/Polyhedron_3/resources/shader_dark_spheres.vert" , ":/cgal/Polyhedron_3/resources/shader_no_light_no_selection.frag")
1388 : declare_program(name, ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_dark_spheres.vert" ,
1389 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_no_light_no_selection.frag");
1390 program->setProperty("hasCenter", true);
1391 program->setProperty("hasRadius", true);
1392 program->setProperty("isInstanced", true);
1393 program->setProperty("hasFMatrix", true);
1394 return program;
1395 }
1396 case PROGRAM_FLAT:
1397 {
1398 if(!isOpenGL_4_3())
1399 {
1400 std::cerr<<"An OpenGL context of version 4.3 is required for the program ("<<name<<")."<<std::endl;
1401 return nullptr;
1402 }
1403 QOpenGLShaderProgram* program = declare_program(name, ":/cgal/Polyhedron_3/resources/shader_flat.vert", ":/cgal/Polyhedron_3/resources/shader_flat.frag");
1404 program->setProperty("hasLight", true);
1405 program->setProperty("hasNormals", true);
1406 return program;
1407 }
1408 case PROGRAM_OLD_FLAT:
1409 {
1410 QOpenGLShaderProgram* program = isOpenGL_4_3()
1411 ? declare_program(name, ":/cgal/Polyhedron_3/resources/shader_with_light.vert", ":/cgal/Polyhedron_3/resources/shader_old_flat.frag")
1412 : declare_program(name,
1413 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_with_light.vert",
1414 ":/cgal/Polyhedron_3/resources/compatibility_shaders/shader_old_flat.frag");
1415 program->setProperty("hasLight", true);
1416 program->setProperty("hasNormals", true);
1417 return program;
1418 }
1419 case PROGRAM_SOLID_WIREFRAME:
1420 {
1421 if(!isOpenGL_4_3())
1422 {
1423 std::cerr<<"An OpenGL context of version 4.3 is required for the program ("<<name<<")."<<std::endl;
1424 return nullptr;
1425 }
1426 QOpenGLShaderProgram* program = declare_program(name,
1427 ":/cgal/Polyhedron_3/resources/solid_wireframe_shader.vert",
1428 ":/cgal/Polyhedron_3/resources/solid_wireframe_shader.frag");
1429 program->setProperty("hasViewport", true);
1430 program->setProperty("hasWidth", true);
1431 program->setProperty("hasFMatrix", true);
1432 return program;
1433 }
1434 case PROGRAM_NO_INTERPOLATION:
1435 {
1436 if(!isOpenGL_4_3())
1437 {
1438 std::cerr<<"An OpenGL context of version 4.3 is required for the program ("<<name<<")."<<std::endl;
1439 return nullptr;
1440 }
1441 QOpenGLShaderProgram* program = declare_program(name,
1442 ":/cgal/Polyhedron_3/resources/no_interpolation_shader.vert",
1443 ":/cgal/Polyhedron_3/resources/no_interpolation_shader.frag");
1444 program->setProperty("hasLight", true);
1445 program->setProperty("hasNormals", true);
1446 program->setProperty("drawLinesAdjacency", true);
1447 return program;
1448 }
1449 default:
1450 std::cerr<<"ERROR : Program not found."<<std::endl;
1451 return nullptr;
1452 }
1453 }
1454
wheelEvent(QWheelEvent * e)1455 void Viewer::wheelEvent(QWheelEvent* e)
1456 {
1457 if(e->modifiers().testFlag(Qt::ShiftModifier))
1458 {
1459 double delta = e->angleDelta().y();
1460 if(delta>0)
1461 {
1462 switch(camera()->type())
1463 {
1464 case CGAL::qglviewer::Camera::ORTHOGRAPHIC:
1465 camera()->setOrthoZNear(camera()->orthoZNear() + 0.01);
1466 break;
1467 case CGAL::qglviewer::Camera::PERSPECTIVE:
1468 camera()->setZNearCoefficient(camera()->zNearCoefficient() * 1.01);
1469 break;
1470 default:
1471 break;
1472 }
1473 }
1474 else
1475 switch(camera()->type())
1476 {
1477 case CGAL::qglviewer::Camera::ORTHOGRAPHIC:
1478 camera()->setOrthoZNear(camera()->orthoZNear() - 0.01);
1479 break;
1480 case CGAL::qglviewer::Camera::PERSPECTIVE:
1481 camera()->setZNearCoefficient(camera()->zNearCoefficient() / 1.01);
1482 break;
1483 default:
1484 break;
1485 }
1486 update();
1487 }
1488 else
1489 CGAL::QGLViewer::wheelEvent(e);
1490 }
1491
testDisplayId(double x,double y,double z)1492 bool Viewer::testDisplayId(double x, double y, double z)
1493 {
1494 return d->scene->testDisplayId(x,y,z,this);
1495 }
1496
getPainter()1497 QPainter* Viewer::getPainter(){return d->painter;}
1498
paintEvent(QPaintEvent *)1499 void Viewer::paintEvent(QPaintEvent *)
1500 {
1501 paintGL();
1502 }
1503
paintGL()1504 void Viewer::paintGL()
1505 {
1506 makeCurrent();
1507 if (!d->painter->isActive())
1508 d->painter->begin(this);
1509 if(d->is_2d_selection_mode)
1510 {
1511 d->painter->drawImage(QPoint(0,0), d->static_image);
1512 }
1513 else
1514 {
1515 d->painter->beginNativePainting();
1516 glClearColor(GLfloat(backgroundColor().redF()),
1517 GLfloat(backgroundColor().greenF()),
1518 GLfloat(backgroundColor().blueF()),
1519 1.f);
1520 glClearDepthf(1.0f);
1521 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1522 //set the default frustum
1523 if(d->projection_is_ortho)
1524 camera()->setType(CGAL::qglviewer::Camera::ORTHOGRAPHIC);
1525 else
1526 camera()->setType(CGAL::qglviewer::Camera::PERSPECTIVE);
1527 preDraw();
1528 draw();
1529 postDraw();
1530 d->painter->endNativePainting();
1531 }
1532 d->painter->end();
1533 doneCurrent();
1534 }
1535
displayMessage(const QString & _message,int delay)1536 void Viewer::displayMessage(const QString &_message, int delay)
1537 {
1538 d->message = _message;
1539 d->_displayMessage = true;
1540 // Was set to single shot in defaultConstructor.
1541 d->messageTimer.start(delay);
1542 if (textIsEnabled())
1543 update();
1544 }
hideMessage()1545 void Viewer::hideMessage()
1546 {
1547 d->_displayMessage = false;
1548 if (textIsEnabled())
1549 update();
1550 }
printMessage(QString _message,int ms_delay)1551 void Viewer::printMessage(QString _message, int ms_delay)
1552 {
1553 displayMessage(_message, ms_delay);
1554 }
1555
showDistance(QPoint pixel)1556 void Viewer_impl::showDistance(QPoint pixel)
1557 {
1558 static bool isAset = false;
1559 bool found;
1560 CGAL::qglviewer::Vec point;
1561 point = viewer->camera()->pointUnderPixel(pixel, found);
1562 if(!isAset && found)
1563 {
1564 //set APoint
1565 APoint = point;
1566 isAset = true;
1567 clearDistancedisplay();
1568 }
1569 else if (found)
1570 {
1571 //set BPoint
1572 BPoint = point;
1573 isAset = false;
1574
1575 // fills the buffers
1576 std::vector<float> v;
1577 v.resize(6);
1578 v[0] = float(APoint.x); v[1] = float(APoint.y); v[2] = float(APoint.z);
1579 v[3] = float(BPoint.x); v[4] = float(BPoint.y); v[5] = float(BPoint.z);
1580
1581 vao.bind();
1582 buffer.bind();
1583 buffer.allocate(v.data(),6*sizeof(float));
1584 rendering_program_dist.enableAttributeArray("vertex");
1585 rendering_program_dist.setAttributeBuffer("vertex",GL_FLOAT,0,3);
1586 buffer.release();
1587 vao.release();
1588 distance_is_displayed = true;
1589 double dist = std::sqrt((BPoint.x-APoint.x)/scaler.x()*(BPoint.x-APoint.x)/scaler.x() + (BPoint.y-APoint.y)/scaler.y()*(BPoint.y-APoint.y)/scaler.y() + (BPoint.z-APoint.z)/scaler.z()*(BPoint.z-APoint.z)/scaler.z());
1590 QFont font;
1591 font.setBold(true);
1592 TextItem *ACoord = new TextItem(float(APoint.x),
1593 float(APoint.y),
1594 float(APoint.z),
1595 QString("A(%1,%2,%3)")
1596 .arg(APoint.x/scaler.x()-viewer->offset().x, 0, 'g', 10)
1597 .arg(APoint.y/scaler.y()-viewer->offset().y, 0, 'g', 10)
1598 .arg(APoint.z/scaler.z()-viewer->offset().z, 0, 'g', 10), true, font, Qt::red, true);
1599 distance_text.append(ACoord);
1600 TextItem *BCoord = new TextItem(float(BPoint.x),
1601 float(BPoint.y),
1602 float(BPoint.z),
1603 QString("B(%1,%2,%3)")
1604 .arg(BPoint.x/scaler.x()-viewer->offset().x, 0, 'g', 10)
1605 .arg(BPoint.y/scaler.y()-viewer->offset().y, 0, 'g', 10)
1606 .arg(BPoint.z/scaler.z()-viewer->offset().z, 0, 'g', 10), true, font, Qt::red, true);
1607
1608 distance_text.append(BCoord);
1609 CGAL::qglviewer::Vec centerPoint = 0.5*(BPoint+APoint);
1610 TextItem *centerCoord = new TextItem(float(centerPoint.x),
1611 float(centerPoint.y),
1612 float(centerPoint.z),
1613 QString(" distance: %1").arg(dist), true, font, Qt::red, true);
1614
1615 distance_text.append(centerCoord);
1616 Q_FOREACH(TextItem* ti, distance_text)
1617 textRenderer->addText(ti);
1618 Q_EMIT(viewer->sendMessage(QString("First point : A(%1,%2,%3), second point : B(%4,%5,%6), distance between them : %7")
1619 .arg(APoint.x/scaler.x()-viewer->offset().x)
1620 .arg(APoint.y/scaler.y()-viewer->offset().y)
1621 .arg(APoint.z/scaler.z()-viewer->offset().z)
1622 .arg(BPoint.x/scaler.x()-viewer->offset().x)
1623 .arg(BPoint.y/scaler.y()-viewer->offset().y)
1624 .arg(BPoint.z/scaler.z()-viewer->offset().z)
1625 .arg(dist, 0, 'g', 10)));
1626 }
1627
1628 }
1629
clearDistancedisplay()1630 void Viewer_impl::clearDistancedisplay()
1631 {
1632 distance_is_displayed = false;
1633 Q_FOREACH(TextItem* ti, distance_text)
1634 {
1635 textRenderer->removeText(ti);
1636 delete ti;
1637 }
1638 distance_text.clear();
1639 }
1640
sendSnapshotToClipboard(Viewer * viewer)1641 void Viewer_impl::sendSnapshotToClipboard(Viewer *viewer)
1642 {
1643 QImage * snap = viewer->takeSnapshot(CGAL::qglviewer::TRANSPARENT_BACKGROUND, 2*viewer->size(), 1, true);
1644 if(snap)
1645 {
1646 #if defined(_WIN32)
1647 QApplication::clipboard()->setImage(*snap);
1648 QMimeData *mimeData = new QMimeData();
1649 QByteArray ba;
1650 QBuffer buffer(&ba);
1651 buffer.open(QIODevice::WriteOnly);
1652 snap->save(&buffer, "PNG"); // writes image into ba in PNG format
1653 buffer.close();
1654 mimeData->setData("PNG", ba);
1655 //According to the doc, the ownership of mime_data is transferred to
1656 //clipboard, so this is not a memory leak.
1657 QApplication::clipboard()->setMimeData(mimeData);
1658 #else
1659 QApplication::clipboard()->setImage(*snap);
1660 #endif
1661 delete snap;
1662 }
1663 }
SetOrthoProjection(bool b)1664 void Viewer::SetOrthoProjection(bool b)
1665 {
1666 d->projection_is_ortho = b;
1667 update();
1668 }
1669
updateIds(CGAL::Three::Scene_item * item)1670 void Viewer::updateIds(CGAL::Three::Scene_item * item)
1671 {
1672 //all ids are computed when they are displayed the first time.
1673 //Calling printPrimitiveIds twice hides and show the ids again, so they are re-computed.
1674
1675 d->scene->updatePrimitiveIds(item);
1676 d->scene->updatePrimitiveIds(item);
1677 }
1678
1679
textRenderer()1680 TextRenderer* Viewer::textRenderer()
1681 {
1682 return d->textRenderer;
1683 }
1684
isExtensionFound()1685 bool Viewer::isExtensionFound()
1686 {
1687 return d->extension_is_found;
1688
1689 }
1690
disableClippingBox()1691 void Viewer::disableClippingBox()
1692 {
1693 d->clipping = false;
1694 }
1695
enableClippingBox(QVector4D box[6])1696 void Viewer::enableClippingBox(QVector4D box[6])
1697 {
1698 d->clipping = true;
1699 for(int i=0; i<6; ++i)
1700 d->clipbox[i] = box[i];
1701 }
1702
openGL_4_3_functions()1703 QOpenGLFunctions_4_3_Core *Viewer::openGL_4_3_functions() { return d->_recentFunctions; }
1704
set2DSelectionMode(bool b)1705 void Viewer::set2DSelectionMode(bool b) { d->is_2d_selection_mode = b; }
1706
setStaticImage(QImage image)1707 void Viewer::setStaticImage(QImage image) { d->static_image = image; }
1708
staticImage() const1709 const QImage& Viewer:: staticImage() const { return d->static_image; }
1710
1711
setCurrentPass(int pass)1712 void Viewer::setCurrentPass(int pass) { d->current_pass = pass; }
1713
setDepthWriting(bool writing_depth)1714 void Viewer::setDepthWriting(bool writing_depth) { d->writing_depth = writing_depth; }
1715
setDepthPeelingFbo(QOpenGLFramebufferObject * fbo)1716 void Viewer::setDepthPeelingFbo(QOpenGLFramebufferObject* fbo) { d->dp_fbo = fbo; }
1717
currentPass() const1718 int Viewer::currentPass()const{ return d->current_pass; }
isDepthWriting() const1719 bool Viewer::isDepthWriting()const{ return d->writing_depth; }
depthPeelingFbo()1720 QOpenGLFramebufferObject *Viewer::depthPeelingFbo(){ return d->dp_fbo; }
total_pass()1721 float Viewer::total_pass()
1722 {
1723 return d->current_total_pass * 1.0f;
1724 }
setTotalPass(int p)1725 void Viewer::setTotalPass(int p)
1726 {
1727 d->total_pass = p;
1728 update();
1729 }
1730
messageLogged(QOpenGLDebugMessage msg)1731 void Viewer::messageLogged(QOpenGLDebugMessage msg)
1732 {
1733 //filter out useless warning
1734 // From those two links, we decided we didn't care for this warning:
1735 // https://community.khronos.org/t/vertex-shader-in-program-2-is-being-recompiled-based-on-gl-state/76019
1736 // https://stackoverflow.com/questions/12004396/opengl-debug-context-performance-warning
1737 if(msg.message().contains("is being recompiled"))
1738 return;
1739 QString error;
1740
1741 // Format based on severity
1742 switch (msg.severity())
1743 {
1744 case QOpenGLDebugMessage::NotificationSeverity:
1745 return;
1746 break;
1747 case QOpenGLDebugMessage::HighSeverity:
1748 error += "GL ERROR :";
1749 break;
1750 case QOpenGLDebugMessage::MediumSeverity:
1751 error += "GL WARNING :";
1752 break;
1753 case QOpenGLDebugMessage::LowSeverity:
1754 error += "GL NOTE :";
1755 break;
1756 default:
1757 break;
1758 }
1759
1760 error += " (";
1761
1762 // Format based on source
1763 #define CASE(c) case QOpenGLDebugMessage::c: error += #c; break
1764 switch (msg.source())
1765 {
1766 CASE(APISource);
1767 CASE(WindowSystemSource);
1768 CASE(ShaderCompilerSource);
1769 CASE(ThirdPartySource);
1770 CASE(ApplicationSource);
1771 CASE(OtherSource);
1772 CASE(InvalidSource);
1773 default:
1774 break;
1775 }
1776 #undef CASE
1777
1778 error += " : ";
1779
1780 // Format based on type
1781 #define CASE(c) case QOpenGLDebugMessage::c: error += #c; break
1782 switch (msg.type())
1783 {
1784 CASE(ErrorType);
1785 CASE(DeprecatedBehaviorType);
1786 CASE(UndefinedBehaviorType);
1787 CASE(PortabilityType);
1788 CASE(PerformanceType);
1789 CASE(OtherType);
1790 CASE(MarkerType);
1791 CASE(GroupPushType);
1792 CASE(GroupPopType);
1793 default:
1794 break;
1795 }
1796 #undef CASE
1797
1798 error += ")";
1799 qDebug() << qPrintable(error) << "\n" << qPrintable(msg.message()) << "\n";
1800 }
1801
setLighting()1802 void Viewer::setLighting()
1803 {
1804
1805 //save current settings;
1806 float prev_spec = d->spec_power;
1807 QVector4D prev_pos = d->position;
1808 QVector4D prev_ambient = d->ambient;
1809 QVector4D prev_diffuse = d->diffuse;
1810 QVector4D prev_spec_color = d->specular;
1811 //open dialog
1812 LightingDialog* dialog = new LightingDialog(d);
1813 //set specular
1814 connect(dialog->spec_powrSlider, &QSlider::valueChanged,
1815 [this, dialog]()
1816 {
1817 d->spec_power = dialog->spec_powrSlider->value();
1818 update();
1819 });
1820 //set position
1821 connect(dialog->position_lineEdit, &QLineEdit::editingFinished,
1822 [this, dialog]()
1823 {
1824 QStringList list = dialog->position_lineEdit->text().split(QRegExp(","), CGAL_QT_SKIP_EMPTY_PARTS);
1825 if (list.isEmpty()) return;
1826 if (list.size()!=3){
1827 QMessageBox *msgBox = new QMessageBox;
1828 msgBox->setWindowTitle("Error");
1829 msgBox->setText("ERROR : Input should consists of 3 floats.");
1830 msgBox->exec();
1831 return;
1832 }
1833 float coords[3];
1834 for(int j=0; j<3; ++j)
1835 {
1836 bool ok;
1837 coords[j] = list.at(j).toFloat(&ok);
1838 if(!ok)
1839 {
1840 QMessageBox *msgBox = new QMessageBox;
1841 msgBox->setWindowTitle("Error");
1842 msgBox->setText("ERROR : Coordinates are invalid.");
1843 msgBox->exec();
1844 return;
1845 }
1846 }
1847 d->position = QVector4D(coords[0], coords[1], coords[2], 1.0f);
1848 update();
1849 });
1850
1851
1852 //set ambient
1853 connect(dialog, &LightingDialog::s_ambient_changed,
1854 [this, dialog](){
1855 d->ambient=QVector4D((float)dialog->ambient.redF(),
1856 (float)dialog->ambient.greenF(),
1857 (float)dialog->ambient.blueF(),
1858 1.0f);
1859 update();
1860 });
1861
1862 //set diffuse
1863 connect(dialog, &LightingDialog::s_diffuse_changed,
1864 [this, dialog](){
1865 d->diffuse=QVector4D((float)dialog->diffuse.redF(),
1866 (float)dialog->diffuse.greenF(),
1867 (float)dialog->diffuse.blueF(),
1868 1.0f);
1869 update();
1870 });
1871 //set specular
1872 connect(dialog, &LightingDialog::s_specular_changed,
1873 [this, dialog](){
1874 d->specular=QVector4D((float)dialog->specular.redF(),
1875 (float)dialog->specular.greenF(),
1876 (float)dialog->specular.blueF(),
1877 1.0f);
1878 update();
1879
1880 });
1881
1882 //reset default
1883 connect(dialog->buttonBox->button(QDialogButtonBox::StandardButton::RestoreDefaults), &QPushButton::clicked,
1884 [this](){
1885 d->position = QVector4D(0,0,1,1);
1886 d->ambient=QVector4D(77.0f/255,77.0f/255,77.0f/255, 1.0);
1887 d->diffuse=QVector4D(204.0f/255,204.0f/255,204.0f/255,1.0);
1888 d->specular=QVector4D(0,0,0,1.0);
1889 d->spec_power = 51;
1890 update();
1891
1892 });
1893 if(!dialog->exec())
1894 {
1895 //restore previous settings
1896 d->spec_power = prev_spec;
1897 d->position = prev_pos;
1898 d->ambient = prev_ambient;
1899 d->diffuse = prev_diffuse;
1900 d->specular = prev_spec_color;
1901 return;
1902 }
1903 }
1904
setBackFrontColors()1905 void Viewer::setBackFrontColors()
1906 {
1907
1908 //save current settings;
1909
1910 QColor prev_front_color = d->front_color;
1911 QColor prev_back_color = d->back_color;
1912 QDialog *dialog = new QDialog(this);
1913 QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
1914 | QDialogButtonBox::Cancel, dialog);
1915
1916 connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
1917 connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
1918
1919 QGridLayout* layout = new QGridLayout(dialog);
1920 layout->addWidget(new QLabel("Front color: ",dialog),0,0);
1921 QPalette front_palette;
1922 front_palette.setColor(QPalette::Button, d->front_color);
1923 QPushButton* frontButton = new QPushButton(dialog);
1924 frontButton->setPalette(front_palette);
1925 QPalette back_palette;
1926 back_palette.setColor(QPalette::Button, d->back_color);
1927 QPushButton* backButton = new QPushButton(dialog);
1928 backButton->setPalette(back_palette);
1929 layout->addWidget(frontButton,0,1);
1930 layout->addWidget(new QLabel("Back color: ",dialog),1,0);
1931 layout->addWidget(backButton,1,1);
1932 layout->addWidget(buttonBox);
1933 dialog->setLayout(layout);
1934 connect(frontButton, &QPushButton::clicked,
1935 [this, dialog, frontButton](){
1936 QColorDialog *color_dial = new QColorDialog(dialog);
1937 color_dial->exec();
1938 QColor front_color = color_dial->selectedColor();
1939 QPalette palette;
1940 palette.setColor(QPalette::Button, front_color);
1941 frontButton->setPalette(palette);
1942 d->front_color= front_color;
1943 });
1944 connect(backButton, &QPushButton::clicked,
1945 [this, dialog, backButton](){
1946 QColorDialog *color_dial = new QColorDialog(dialog);
1947 color_dial->exec();
1948 QColor back_color = color_dial->selectedColor();
1949 QPalette palette;
1950 palette.setColor(QPalette::Button, back_color);
1951 backButton->setPalette(palette);
1952 d->back_color= back_color;
1953
1954 });
1955 if(!dialog->exec())
1956 {
1957 //restore previous settings
1958 d->front_color= prev_front_color;
1959 d->back_color= prev_back_color;
1960 return;
1961 }
1962 }
1963
setGlPointSize(const GLfloat & p)1964 void Viewer::setGlPointSize(const GLfloat &p) { d->gl_point_size = p; }
1965
getGlPointSize() const1966 const GLfloat& Viewer::getGlPointSize() const { return d->gl_point_size; }
1967
resetFov()1968 void Viewer::resetFov()
1969 {
1970 camera()->setHorizontalFieldOfView(ORIGINAL_FOV);
1971 }
1972
initializeGL()1973 void Viewer::initializeGL()
1974 {
1975 QGLViewer::initializeGL();
1976 doneInitGL(this);
1977 }
1978
makeCurrent()1979 void Viewer::makeCurrent()
1980 {
1981 CGAL::Three::Three::setCurrentViewer(this);
1982 QOpenGLWidget::makeCurrent();
1983 }
1984
clipBox() const1985 QVector4D* Viewer::clipBox() const
1986 {
1987 return d->clipbox;
1988 }
1989
isClipping() const1990 bool Viewer::isClipping() const
1991 {
1992 return d->clipping;
1993 }
1994
scaleScene()1995 void Viewer::scaleScene()
1996 {
1997 CGAL::Bbox_3 bbox = CGAL::Three::Three::scene()->bbox();
1998 if(!d->scene_scaling)
1999 {
2000 QMultipleInputDialog dialog ("Scale Scene", CGAL::Three::Three::mainWindow());
2001 DoubleEdit* x_val = dialog.add<DoubleEdit> ("Scale along X");
2002 DoubleEdit* y_val = dialog.add<DoubleEdit> ("Scale along Y");
2003 DoubleEdit* z_val = dialog.add<DoubleEdit> ("Scale along Z");
2004 x_val->setMinimum(0);
2005 y_val->setMinimum(0);
2006 z_val->setMinimum(0);
2007 if(bbox != CGAL::Bbox_3(0,0,0,0,0,0))
2008 {
2009 QPushButton* norm_button = dialog.add<QPushButton> ("");
2010 norm_button->setText("Normalize");
2011 norm_button->setToolTip("Automatically fill values to display the scene in a unit cube.");
2012
2013 connect(norm_button, &QPushButton::clicked, this,
2014 [x_val, y_val, z_val, &bbox](){
2015 x_val->setValue(1.0/(bbox.xmax()-bbox.xmin()));
2016 y_val->setValue(1.0/(bbox.ymax()-bbox.ymin()));
2017 z_val->setValue(1.0/(bbox.zmax()-bbox.zmin()));
2018 });
2019 }
2020 if (dialog.exec() != QDialog::Accepted)
2021 {
2022 parent()->findChild<QAction*>("actionScaleScene")->setChecked(false);
2023 return;
2024 }
2025 d->scaler.setX(x_val->text()==""?1.0:x_val->value());
2026 d->scaler.setY(y_val->text()==""?1.0:y_val->value());
2027 d->scaler.setZ(z_val->text()==""?1.0:z_val->value());
2028
2029 if(d->scaler.x() == 0.0 || d->scaler.y() == 0.0 || d->scaler.z()== 0.0)
2030 {
2031 parent()->findChild<QAction*>("actionScaleScene")->setChecked(false);
2032 return;
2033 }
2034 }
2035 else
2036 d->scaler = QVector3D(1,1,1);
2037
2038 CGAL::qglviewer::Vec vmin(((float)bbox.xmin()+offset().x)*d->scaler.x(), ((float)bbox.ymin()+offset().y)*d->scaler.y(), ((float)bbox.zmin()+offset().z)*d->scaler.z()),
2039 vmax(((float)bbox.xmax()+offset().x)*d->scaler.x(), ((float)bbox.ymax()+offset().y)*d->scaler.y(), ((float)bbox.zmax()+offset().z)*d->scaler.z());
2040 camera()->setPivotPoint((vmin+vmax)*0.5);
2041 camera()->setSceneBoundingBox(vmin, vmax);
2042 camera()->fitBoundingBox(vmin, vmax);
2043 d->scene_scaling = !d->scene_scaling;
2044 }
2045 #ifdef CGAL_USE_WEBSOCKETS
setShareCam(bool b,QString session)2046 void Viewer::setShareCam(bool b, QString session)
2047 {
2048 static bool init = false;
2049 if(b)
2050 {
2051 d->cam_sharing = b;
2052 d->session = session;
2053 QString ws_url
2054 = CGAL::Three::Three::mainWindow()->property("ws_url").toString();
2055 if(ws_url.isEmpty())
2056 {
2057 QMessageBox::warning(this, "Error", "No Server configured. Please go to Edit->Preferences->Network Settings and fill the \"Camera Synchronization Server\" Field.");
2058 }
2059 else{
2060 if(!init)
2061 {
2062 connect(&d->m_webSocket, &QWebSocket::connected, this, &Viewer::onSocketConnected);
2063 connect(&d->m_webSocket, &QWebSocket::disconnected, this,[this]()
2064 {
2065 d->is_connected = false;
2066 Viewer::socketClosed();
2067 });
2068 init = true;
2069 }
2070 d->m_webSocket.open(QUrl(ws_url));
2071 QApplication::setOverrideCursor(Qt::WaitCursor);
2072 QTimer::singleShot(1000, this, [this](){
2073 QApplication::restoreOverrideCursor();
2074 if(!d->is_connected){
2075 QMessageBox::warning(CGAL::Three::Three::mainWindow(),
2076 "Connection failure",
2077 "The requested server was not found.");
2078 setShareCam(false, "");
2079 }
2080 });
2081 }
2082 }
2083 else
2084 {
2085 QAction* action = findChild<QAction*>("actionShareCamera");
2086 action->setChecked(false);
2087 d->m_webSocket.close();
2088 }
2089 }
2090
onSocketConnected()2091 void Viewer::onSocketConnected()
2092 {
2093 connect(&d->m_webSocket, &QWebSocket::textMessageReceived,
2094 this, &Viewer::onTextMessageSocketReceived);
2095 connect(camera()->frame(), &CGAL::qglviewer::ManipulatedCameraFrame::manipulated,
2096 this, [this](){
2097 if(d->cam_sharing){
2098 QString cam_state = QString("[%1] %2").arg(d->session).arg(dumpCameraCoordinates());
2099 //send to server
2100 d->m_webSocket.sendTextMessage(cam_state);
2101 }
2102 });
2103 d->is_connected = true;
2104 }
2105
onTextMessageSocketReceived(QString message)2106 void Viewer::onTextMessageSocketReceived(QString message)
2107 {
2108 QString session;
2109 QString position;
2110 QRegularExpression re("\\[(.*)\\] (.*)");
2111 QRegularExpressionMatch match = re.match(message);
2112 session = match.captured(1);
2113 position = match.captured(2);
2114 if(session != d->session){
2115 return;
2116 }
2117 QStringList sl = position.split(" ");
2118 if(sl.size() != 7)
2119 return;
2120
2121 CGAL::qglviewer::Vec pos(sl[0].toDouble(),sl[1].toDouble(),sl[2].toDouble());
2122 CGAL::qglviewer::Quaternion q(sl[3].toDouble(),sl[4].toDouble(),
2123 sl[5].toDouble(),sl[6].toDouble());
2124 camera()->frame()->setPositionAndOrientation(pos, q);
2125 update();
2126 }
2127 #endif
2128
scaler() const2129 const QVector3D& Viewer::scaler()const { return d->scaler; }
showEntireScene()2130 void Viewer::showEntireScene()
2131 {
2132 CGAL::QGLViewer::showEntireScene();
2133 CGAL::Bbox_3 bbox = CGAL::Three::Three::scene()->bbox();
2134
2135 CGAL::qglviewer::Vec vmin(((float)bbox.xmin()+offset().x)*d->scaler.x(), ((float)bbox.ymin()+offset().y)*d->scaler.y(), ((float)bbox.zmin()+offset().z)*d->scaler.z()),
2136 vmax(((float)bbox.xmax()+offset().x)*d->scaler.x(), ((float)bbox.ymax()+offset().y)*d->scaler.y(), ((float)bbox.zmax()+offset().z)*d->scaler.z());
2137 camera()->setPivotPoint((vmin+vmax)*0.5);
2138 camera()->setSceneBoundingBox(vmin, vmax);
2139 camera()->fitBoundingBox(vmin, vmax);
2140 }
2141 #include "Viewer.moc"
2142