Developer Documentation
viewerControl.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
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 
46 //=============================================================================
47 //
48 // CLASS CoreWidget - IMPLEMENTATION
49 //
50 //=============================================================================
51 
52 
53 //== INCLUDES =================================================================
54 
55 #include "CoreWidget.hh"
56 
57 
58 #include <QtConcurrent>
59 
60 
61 #include <OpenFlipper/widgets/snapshotDialog/SnapshotDialog.hh>
62 #include <cmath>
63 
64 #ifdef _MSC_VER
65  #include <ACG/Utils/VSToolsT.hh>
66 #endif
67 
68 #include <ACG/Scenegraph/MaterialNode.hh>
69 
70 //== IMPLEMENTATION ==========================================================
71 
72 //=============================================================================
73 
75 {
77 
78  if ( stereoActive_ ) {
79  statusBar_->showMessage(tr("Stereo enabled"));
80  stereoButton_->setIcon( QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"stereo.png") );
81  } else {
82  statusBar_->showMessage(tr("Stereo disabled"));
83  stereoButton_->setIcon( QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"mono.png") );
84  }
85 
87 
88  for ( unsigned int i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
89  examiner_widgets_[i]->properties()->stereo(stereoActive_);
90 }
91 
94 
95  QColor backCol((int)bc[0], (int)bc[1], (int)bc[2], (int)bc[3]);
96  QColor c = QColorDialog::getColor(backCol,this);
97 
98  if (c != backCol && c.isValid())
99  for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets(); ++i )
101  ((double) c.greenF()) ,
102  ((double) c.blueF()) ,
103  1.0));
104 
105  OpenFlipperSettings().setValue("Core/Gui/glViewer/defaultBackgroundColor",c);
106 
107 }
108 
111 
112  QColor backCol((int)bc[0], (int)bc[1], (int)bc[2], (int)bc[3]);
113  QColor c = QColorDialog::getColor(backCol,this);
114 
115  if (c != backCol && c.isValid())
117  ((double) c.greenF()) ,
118  ((double) c.blueF()) ,
119  1.0));
120 }
121 
122 
126 }
127 
129 void CoreWidget::slotSwitchWheels(bool _state) {
130  std::vector< glViewer* >::iterator it = examiner_widgets_.begin();
131 
132  for(; it != examiner_widgets_.end(); ++it)
133  _state ? (*it)->slotShowWheels() : (*it)->slotHideWheels();
134 }
135 
137 void CoreWidget::slotSwitchNavigation(bool _egomode) {
138  std::vector< glViewer* >::iterator it = examiner_widgets_.begin();
139 
140  for(; it != examiner_widgets_.end(); ++it) {
141  _egomode ? (*it)->navigationMode(glViewer::FIRSTPERSON_NAVIGATION) :
142  (*it)->navigationMode(glViewer::NORMAL_NAVIGATION);
143  }
144 }
145 
148  for ( int i = 0 ; i < PluginFunctions::viewers() ; ++i )
149  examiner_widgets_[i]->home();
150 }
151 
155 }
156 
157 
160  for ( int i = 0 ; i < PluginFunctions::viewers() ; ++i )
161  examiner_widgets_[i]->setHome();
162 }
163 
167 }
168 
169 
172  for ( int i = 0 ; i < PluginFunctions::viewers() ; ++i )
173  examiner_widgets_[i]->viewAll();
174 }
175 
178  examiner_widgets_[PluginFunctions::activeExaminer()]->toggleProjectionMode();
179 }
180 
183  // Find coordsys node
184  ACG::SceneGraph::BaseNode* node = 0;
185  node = PluginFunctions::getSceneGraphRootNode()->find("Core Coordsys Node");
186  if (node != 0) {
187  return dynamic_cast<ACG::SceneGraph::CoordsysNode*> (node)->getProjectionMode();
188  } else {
189  emit statusMessage(QString(tr("getCoordsysProjection(): Could not find coordsys node. Assuming default orthographic projection.")));
191  }
192 }
193 
196  // Find coordsys node
197  ACG::SceneGraph::BaseNode* node = 0;
198  node = PluginFunctions::getSceneGraphRootNode()->find("Core Coordsys Node");
199  if (node != 0) {
200  ACG::SceneGraph::CoordsysNode* cnode = dynamic_cast<ACG::SceneGraph::CoordsysNode*> (node);
203  }
204  else {
206  }
207  } else {
208  emit statusMessage(QString(tr("slotContextSwitchCoordsysProjection(): Could not find coordsys node, thus its projection mode will not be toggled.")));
209  }
210 
211  for ( unsigned int i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
212  examiner_widgets_[i]->updateGL();
213 }
214 
217  for ( int i = 0 ; i < PluginFunctions::viewers() ; ++i )
218  examiner_widgets_[i]->perspectiveProjection();
219 }
220 
223  for ( int i = 0 ; i < PluginFunctions::viewers() ; ++i )
224  examiner_widgets_[i]->orthographicProjection();
225 }
226 
227 
230  int enabledCount = 0;
231 
232  for ( int i = 0 ; i< PluginFunctions::viewers(); ++i ) {
234  enabledCount++;
235  }
236 
237  slotGlobalChangeAnimation (enabledCount == 0);
238 }
239 
242  for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
244 }
245 
249 }
250 
251 
254  int enabledCount = 0;
255 
256  for ( int i = 0 ; i< PluginFunctions::viewers(); ++i ) {
258  enabledCount++;
259  }
260 
261  slotGlobalChangeBackFaceCulling (enabledCount == 0);
262 }
263 
266  for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
268 
269 }
270 
272 void CoreWidget::slotLocalChangeBackFaceCulling(bool _backFaceCulling){
274 }
275 
276 
279  int enabledCount = 0;
280 
281  for ( int i = 0 ; i< PluginFunctions::viewers(); ++i ) {
283  enabledCount++;
284  }
285 
286  slotGlobalChangeTwoSidedLighting (enabledCount == 0);
287 }
288 
291  for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
293 }
294 
298 }
299 
300 
303  int enabledCount = 0;
304 
305  for ( int i = 0 ; i< PluginFunctions::viewers(); ++i ) {
307  enabledCount++;
308  }
309 
310  slotGlobalChangeMultisampling (enabledCount == 0);
311 }
312 
314 void CoreWidget::slotGlobalChangeMultisampling(bool _multisampling) {
315  for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
317 }
318 
320 void CoreWidget::slotLocalChangeMultisampling(bool _multisampling) {
322 }
323 
324 
327  int enabledCount = 0;
328 
329  for ( int i = 0 ; i< PluginFunctions::viewers(); ++i ) {
331  enabledCount++;
332  }
333 
334  slotGlobalChangeMipmapping (enabledCount == 0);
335 }
336 
339  for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
341 }
342 
346 }
347 
350 
351  QFileInfo fi(PluginFunctions::viewerProperties().snapshotName());
353 
354  // Add leading zeros
355  QString number = QString::number(counter);
356  while ( number.size() < 7 )
357  number = "0" + number;
358 
359  QString suggest = fi.baseName() + "." + number + ".";
360 
361  QString format="png";
362 
363  if (fi.completeSuffix() == "ppm")
364  format="ppmraw";
365 
366  if (fi.completeSuffix() == "jpg")
367  format="jpg";
368 
369  suggest += format;
370 
371  QFileDialog dialog(this);
372  dialog.setFileMode(QFileDialog::AnyFile);
373  dialog.setDefaultSuffix("png");
374  dialog.setNameFilter(tr("Images (*.png *.ppm *.jpg)"));
375  dialog.setFileMode(QFileDialog::AnyFile);
376  dialog.setOption(QFileDialog::DontConfirmOverwrite, false);
377  dialog.setDirectory( fi.path() );
378  dialog.selectFile( suggest );
379  dialog.setAcceptMode(QFileDialog::AcceptSave);
380  dialog.setWindowTitle(tr("Save Snapshot"));
381 
382  if (dialog.exec()){
383  QString newName = dialog.selectedFiles()[0];
384 
385  if (newName != fi.path() + OpenFlipper::Options::dirSeparator() + suggest)
387 
388  QImage image;
390 
391  image.save(newName);
392  }
393 }
394 
395 static QString suggestSnapshotFilename(QString mostRecentPath) {
396  if (mostRecentPath.isEmpty()) {
397  mostRecentPath = QString("%1%2snap.0000000.png")
398  .arg(OpenFlipperSettings().value("Core/CurrentDir").toString())
399  .arg(QDir::separator());
400  }
401 
402  QFileInfo fi(mostRecentPath);
403  QString path = fi.path();
404 
405  if (!fi.exists() && QFileInfo(path).isWritable()) {
406 #ifndef NDEBUG
407  std::cout << "suggestSnapshotFilename(): mostRecentPath feasible as "
408  "file name. Using it." << std::endl;
409 #endif
410  return mostRecentPath;
411  }
412 
413  if (!QFileInfo(path).isWritable()) {
414 #ifndef NDEBUG
415  std::cout << "suggestSnapshotFilename(): Most recent path invalid. "
416  "Doesn't exist. Returning empty string." << std::endl;
417 #endif
418  return QString();
419  }
420 
421  QString base_name = fi.completeBaseName();
422  QString suffix = fi.suffix();
423 
424  if (suffix.isEmpty())
425  suffix = "png";
426 
427  QRegExp base_name_re("(\\D*)(\\d+)?(.*)");
428  base_name_re.setPatternSyntax(QRegExp::RegExp2);
429  if (!base_name_re.exactMatch(base_name)) {
430 #ifndef NDEBUG
431  std::cout << "suggestSnapshotFilename(): Regexp didn't match. This "
432  "should be impossible." << std::endl;
433 #endif
434  return QString();
435  }
436 
437  QString pre = base_name_re.cap(1),
438  num = base_name_re.cap(2),
439  post = base_name_re.cap(3);
440 
441 #ifndef NDEBUG
442  std::cout << (QString("suggestSnapshotFilename(): Decomposition of "
443  "\"%1\": \"%2\", \"%3\", \"%4\"")
444  .arg(base_name)
445  .arg(pre)
446  .arg(num)
447  .arg(post)).toStdString() << std::endl;
448 #endif
449 
450  if (pre.isEmpty() && num.isEmpty() && post.isEmpty()) {
451  pre = "snap.";
452  }
453 
454  size_t num_len = num.length();
455  bool num_is_int;
456  int file_no = num.toInt(&num_is_int);
457  if (!num_is_int) {
458  file_no = 0;
459  num_len = 6;
460  }
461 
462  size_t sanity_counter = 0;
463  for (; sanity_counter < 100000; ++file_no, ++sanity_counter) {
464  QString suggested_file_name =
465  QString("%1%2%3%4%5.%6")
466  .arg(path)
467  .arg(QDir::separator())
468  .arg(pre)
469  .arg(file_no, num_len, 10, QLatin1Char('0'))
470  .arg(post)
471  .arg(suffix)
472  ;
473  QFileInfo suggested_fi(suggested_file_name);
474  if (!suggested_fi.exists()){
475 #ifndef NDEBUG
476  std::cout << "suggestSnapshotFilename(): Found a feasible file "
477  "name. Returning it." << std::endl;
478 #endif
479  return suggested_file_name;
480  }
481  }
482 
483 #ifndef NDEBUG
484  std::cout << "suggestSnapshotFilename(): No luck incrementing file_no. "
485  "Aborting, returning empty string." << std::endl;
486 #endif
487  return QString();
488 }
489 
492  int w = width();
493  int h = height();
494 
495  SnapshotDialog dialog(suggestSnapshotFilename(snapshotName_), false, w, h, 0);
496 
497  connect(&dialog, SIGNAL(resizeApplication(int,int)), this, SIGNAL(resizeApplication(int,int)) );
498 
499  bool ok = dialog.exec();
500 
501  if ( ok ){
502  QString newName = dialog.filename->text();
503 
504  OpenFlipperSettings().setValue("Core/CurrentDir", QFileInfo(newName).absolutePath() );
505 
506  snapshotName_ = newName;
507  dialog.hide();
508 
509  #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
510  QScreen* screen = window()->screen();
511  QPixmap pic = screen->grabWindow( winId() );
512  #else
513  QPixmap pic = QPixmap::grabWindow( winId() );
514  #endif
515 
516  QPainter painter (&pic);
517 
518  //so we have to add the content from the GLContext manually
519  for (std::vector< glViewer* >::iterator iter = examiner_widgets_.begin(); iter != examiner_widgets_.end(); ++iter)
520  {
521  if (*iter)
522  {
523  QImage fillImage;
524 
525  (*iter)->snapshot(fillImage, (*iter)->glWidth() , (*iter)->glHeight());
526 
527  QPoint localPos = QPoint((*iter)->pos().x(),(*iter)->pos().y());
528  QPointF pos = glView_->mapTo(this,localPos);
529  painter.drawImage(pos,fillImage);
530  }
531  }
532 
533  pic.save(newName);
534  }
535 
536  emit resizeApplication(w,h);
537 }
538 
541 
542  #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
543  QScreen* screen = window()->screen();
544  QPixmap pix = screen->grabWindow( winId() );
545  #else
546  QPixmap pix = QPixmap::grabWindow( winId() );
547  #endif
548 
549  // Write image asynchronously
550  QImage* pic = new QImage( pix.toImage() );
551  writeImageAsynchronously(pic, suggestSnapshotFilename(snapshotName_));
552 }
553 
554 void CoreWidget::viewerSnapshot(QString file_name, bool store_comments,
555  bool comments_visible_only, bool comments_targeted_only,
556  bool store_material_info, int snapshot_width, int snapshot_height,
557  bool snapshot_transparent, bool hide_coord_sys,
558  int snapshot_multisampling, bool store_view) {
559 
560  if (snapshot_height < 0) {
561  int w = glView_->width();
562  int h = glView_->height();
563  snapshot_height = static_cast<int>(round(
564  static_cast<double>(snapshot_width) / w * h));
565  }
566 
567  QString comments;
568  if (store_comments) {
570  comments_visible_only,
571  comments_targeted_only).join("\n");
572  }
573 
574  QString materials;
575  if (ACG::SceneGraph::Material::support_json_serialization() &&
576  //if (ACG::SceneGraph::Material::CP_JSON_SERIALIZABLE &&
577  store_material_info) {
579  comments_visible_only,
580  comments_targeted_only).join("\n");
581  }
582 
583  //now take the snapshot
584  switch ( baseLayout_->mode() ){
585 
586  case QtMultiViewLayout::SingleView:
587  {
588  QImage finalImage;
589 
590  examiner_widgets_[PluginFunctions::activeExaminer()]->snapshot(finalImage,
591  snapshot_width, snapshot_height,
592  snapshot_transparent, hide_coord_sys,
593  snapshot_multisampling);
594 
595  if (!comments.isEmpty())
596  finalImage.setText("Mesh Comments", comments);
597  if (!materials.isEmpty())
598  finalImage.setText("Mesh Materials", materials);
599  if (store_view) {
600  QSize window_size;
601  if (isMaximized())
602  window_size = QSize(-width(), -height());
603  else
604  window_size = QSize (width(), height());
605 
606  int splitter_size = 0;
607  if (OpenFlipperSettings().value("Core/Gui/ToolBoxes/ToolBoxOnTheRight",true).toBool())
608  splitter_size = toolSplitter_->sizes()[1];
609  else
610  splitter_size = toolSplitter_->sizes()[0];
611 
612  QString view;
613  examiner_widgets_[PluginFunctions::activeExaminer()]->encodeView(view, window_size, splitter_size);
614  finalImage.setText("View", view);
615  }
616  finalImage.save(file_name);
617 
618  break;
619  }
620  case QtMultiViewLayout::DoubleView:
621  {
622  int w = snapshot_height;
623 
624  double relSizeW = static_cast<double>( examiner_widgets_[0]->glWidth() / static_cast<double>( glScene_->width() ) );
625 
626  //Get the images
627  QImage img[2];
628  examiner_widgets_[0]->snapshot(
629  img[0], static_cast<int>(relSizeW * w),
630  snapshot_width, snapshot_transparent,
631  hide_coord_sys);
632  examiner_widgets_[1]->snapshot(
633  img[1], static_cast<int>(relSizeW * w),
634  snapshot_width, snapshot_transparent,
635  hide_coord_sys);
636 
637  QImage finalImage(img[0].width() + img[1].width() +2, img[0].height(),
638  QImage::Format_ARGB32_Premultiplied);
639 
640  QPainter painter(&finalImage);
641 
642  painter.fillRect(0,0,finalImage.width(),
643  finalImage.height(), QBrush(Qt::gray));
644 
645  painter.drawImage(QRectF( 0, 0, img[0].width(), img[0].height()),img[0],
646  QRectF( 0, 0, img[0].width(), img[0].height()) );
647  painter.drawImage(QRectF(img[0].width()+2, 0, img[1].width(), img[1].height()),img[1],
648  QRectF( 0, 0, img[1].width(), img[1].height()) );
649 
650  if (!comments.isEmpty())
651  finalImage.setText("Mesh Comments", comments);
652  finalImage.save(file_name);
653 
654  break;
655  }
656 
657  case QtMultiViewLayout::Grid:
658  {
659  // Relative size of first viewer (in relation to the other viewers
660  double relSizeW = (double)examiner_widgets_[0]->glWidth() / (double)glScene_->width();
661  double relSizeH = (double)examiner_widgets_[0]->glHeight() / (double)glScene_->height();
662 
663  QImage img0,img1,img2,img3;
664 
665  examiner_widgets_[0]->snapshot(img0,
666  (int)((double)snapshot_width * relSizeW),
667  (int)((double)snapshot_height * relSizeH),
668  snapshot_transparent, hide_coord_sys);
669  examiner_widgets_[1]->snapshot(img1,
670  (int)((double)snapshot_width * (1.0 - relSizeW)),
671  (int)((double)snapshot_height * relSizeH),
672  snapshot_transparent, hide_coord_sys);
673  examiner_widgets_[2]->snapshot(img2,
674  (int)((double)snapshot_width * relSizeW),
675  (int)((double)snapshot_height * (1.0 - relSizeH)),
676  snapshot_transparent, hide_coord_sys);
677  examiner_widgets_[3]->snapshot(img3,
678  (int)((double)snapshot_width * (1.0 - relSizeW)),
679  (int)((double)snapshot_height * (1.0 - relSizeH)),
680  snapshot_transparent, hide_coord_sys);
681 
682  QImage finalImage(img0.width() + img1.width()+2,
683  img0.height() + img2.height()+2,
684  QImage::Format_ARGB32_Premultiplied);
685 
686  QPainter painter(&finalImage);
687 
688  painter.fillRect(0,0,finalImage.width(), finalImage.height(), QBrush(Qt::gray));
689 
690  painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
691  QRectF( 0, 0, img0.width(), img0.height()) );
692  painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
693  QRectF( 0, 0, img1.width(), img1.height()) );
694  painter.drawImage(QRectF( 0,img0.height()+2, img2.width(), img2.height()),img2,
695  QRectF( 0, 0, img2.width(), img2.height()) );
696  painter.drawImage(QRectF(img0.width()+2, img0.height()+2, img3.width(), img3.height()),img3,
697  QRectF( 0, 0, img3.width(), img3.height()) );
698 
699  if (!comments.isEmpty())
700  finalImage.setText("Mesh Comments", comments);
701  finalImage.save(file_name);
702 
703  break;
704  }
705  case QtMultiViewLayout::HSplit:
706  {
707  // Relative size of first viewer (in relation to the other viewers
708  double relSizeW = (double)examiner_widgets_[0]->glWidth() / (double)glScene_->width();
709  double relSizeH1 = (double)examiner_widgets_[1]->glHeight() / (double)glScene_->height();
710  double relSizeH2 = (double)examiner_widgets_[2]->glHeight() / (double)glScene_->height();
711  double relSizeH3 = (double)examiner_widgets_[3]->glHeight() / (double)glScene_->height();
712 
713  QImage img0,img1,img2,img3;
714 
715  examiner_widgets_[0]->snapshot(img0,
716  (int)((double)snapshot_width * relSizeW), snapshot_height,
717  snapshot_transparent, hide_coord_sys);
718  examiner_widgets_[1]->snapshot(img1,
719  (int)((double)snapshot_width * (1.0 - relSizeW)),
720  relSizeH1 * (double)snapshot_height,
721  snapshot_transparent, hide_coord_sys);
722  examiner_widgets_[2]->snapshot(img2,
723  (int)((double)snapshot_width * (1.0 - relSizeW)),
724  relSizeH2 * (double)snapshot_height,
725  snapshot_transparent, hide_coord_sys);
726  examiner_widgets_[3]->snapshot(img3,
727  (int)((double)snapshot_width * (1.0 - relSizeW)),
728  relSizeH3 * (double)snapshot_height,
729  snapshot_transparent, hide_coord_sys);
730 
731  QImage finalImage(img0.width() + img1.width() +2, img0.height(), QImage::Format_ARGB32_Premultiplied);
732 
733  QPainter painter(&finalImage);
734 
735  painter.fillRect(0,0,finalImage.width(), finalImage.height(), QBrush(Qt::gray));
736 
737  painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
738  QRectF( 0, 0, img0.width(), img0.height()) );
739  painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
740  QRectF( 0, 0, img1.width(), img1.height()) );
741  painter.drawImage(QRectF(img0.width()+2, img1.height()+2, img2.width(), img2.height()),img2,
742  QRectF( 0, 0, img2.width(), img2.height()) );
743  painter.drawImage(QRectF(img0.width()+2, img1.height()+img2.height()+4, img3.width(),img3.height()),img3,
744  QRectF( 0, 0, img3.width(), img3.height()) );
745 
746  if (!comments.isEmpty())
747  finalImage.setText("Mesh Comments", comments);
748  finalImage.save(file_name);
749 
750  break;
751  }
752  default: break;
753 
754  }
755 }
756 
759  int w = glView_->width();
760  int h = glView_->height();
761 
762  SnapshotDialog dialog(suggestSnapshotFilename(snapshotName_), true, w, h, 0);
763 
764  if (!ACG::SceneGraph::Material::support_json_serialization())
765  dialog.metaData_storeMatInfo_cb->setVisible(false);
766 
767  bool ok = dialog.exec();
768 
769  if (ok){
770  QString newName = dialog.filename->text();
771 
772  OpenFlipperSettings().setValue("Core/CurrentDir", QFileInfo(newName).absolutePath() );
773 
774  snapshotName_ = newName;
775 
776  const bool storeComments = dialog.metaData_storeComments_cb->isChecked();
777  const bool comments_visible_only =
778  dialog.metaData_comments_visibleOnly_cb->isChecked();
779  const bool comments_targeted_only =
780  dialog.metaData_comments_targetedOnly_cb->isChecked();
781  const bool store_material_info =
782  dialog.metaData_storeMatInfo_cb->isChecked();
783  const int snapshot_width = dialog.snapWidth->value();
784  const int snapshot_height = dialog.snapHeight->value();
785  const bool snapshot_transparent = dialog.transparent->isChecked();
786  const bool hide_coord_sys = dialog.hideCoordsys->isChecked();
787  const int snapshot_multisampling =
788  dialog.multisampling->isChecked() ?
789  dialog.num_samples->value() : 1;
790  const bool store_view = dialog.metaData_storeView_cb->isChecked();
791 
792  viewerSnapshot(newName, storeComments, comments_visible_only,
793  comments_targeted_only, store_material_info, snapshot_width,
794  snapshot_height, snapshot_transparent, hide_coord_sys,
795  snapshot_multisampling, store_view);
796  }
797  //glView_->resize(w, h);
798 }
799 
802 
803  switch ( baseLayout_->mode() ){
804 
805  case QtMultiViewLayout::SingleView:
806  {
807  QImage* finalImage = new QImage();
808 
809  examiner_widgets_[PluginFunctions::activeExaminer()]->snapshot(*finalImage);
810 
811  writeImageAsynchronously(finalImage, suggestSnapshotFilename(snapshotName_));
812 
813  break;
814  }
815  case QtMultiViewLayout::DoubleView:
816  {
817  //Get the images
818  QImage img[2];
819  examiner_widgets_[0]->snapshot(img[0]);
820  examiner_widgets_[1]->snapshot(img[1]);
821 
822  QImage* finalImage = new QImage(img[0].width() + img[1].width() +2, img[0].height(), QImage::Format_ARGB32_Premultiplied);
823 
824  QPainter painter(finalImage);
825 
826  painter.fillRect(0,0,finalImage->width(), finalImage->height(), QBrush(Qt::gray));
827 
828  painter.drawImage(QRectF( 0, 0, img[0].width(), img[0].height()),img[0],
829  QRectF( 0, 0, img[0].width(), img[0].height()) );
830  painter.drawImage(QRectF(img[0].width()+2, 0, img[1].width(), img[1].height()),img[1],
831  QRectF( 0, 0, img[1].width(), img[1].height()) );
832 
833  writeImageAsynchronously(finalImage, suggestSnapshotFilename(snapshotName_));
834 
835  break;
836  }
837 
838  case QtMultiViewLayout::Grid:
839  {
840  QImage img0,img1,img2,img3;
841 
842  examiner_widgets_[0]->snapshot(img0);
843  examiner_widgets_[1]->snapshot(img1);
844  examiner_widgets_[2]->snapshot(img2);
845  examiner_widgets_[3]->snapshot(img3);
846 
847  QImage* finalImage = new QImage(img0.width() + img1.width() + 2, img0.height() + img2.height() + 2, QImage::Format_ARGB32_Premultiplied);
848 
849  QPainter painter(finalImage);
850 
851  painter.fillRect(0,0,finalImage->width(), finalImage->height(), QBrush(Qt::gray));
852 
853  painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
854  QRectF( 0, 0, img0.width(), img0.height()) );
855  painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
856  QRectF( 0, 0, img1.width(), img1.height()) );
857  painter.drawImage(QRectF( 0, img0.height()+2, img2.width(), img2.height()),img2,
858  QRectF( 0, 0, img2.width(), img2.height()) );
859  painter.drawImage(QRectF(img0.width()+2, img0.height()+2, img3.width(), img3.height()),img3,
860  QRectF( 0, 0, img3.width(), img3.height()) );
861 
862  writeImageAsynchronously(finalImage, suggestSnapshotFilename(snapshotName_));
863 
864  break;
865  }
866  case QtMultiViewLayout::HSplit:
867  {
868  QImage img0,img1,img2,img3;
869 
870  examiner_widgets_[0]->snapshot(img0);
871  examiner_widgets_[1]->snapshot(img1);
872  examiner_widgets_[2]->snapshot(img2);
873  examiner_widgets_[3]->snapshot(img3);
874 
875  QImage* finalImage = new QImage(img0.width() + img1.width() + 2, img0.height(), QImage::Format_ARGB32_Premultiplied);
876 
877  QPainter painter(finalImage);
878 
879  painter.fillRect(0,0,finalImage->width(), finalImage->height(), QBrush(Qt::gray));
880 
881  painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
882  QRectF( 0, 0, img0.width(), img0.height()) );
883  painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
884  QRectF( 0, 0, img1.width(), img1.height()) );
885  painter.drawImage(QRectF(img0.width()+2, img1.height()+2, img2.width(), img2.height()),img2,
886  QRectF( 0, 0, img2.width(), img2.height()) );
887  painter.drawImage(QRectF(img0.width()+2, img1.height()+img2.height()+4, img3.width(),img3.height()),img3,
888  QRectF( 0, 0, img3.width(), img3.height()) );
889 
890  writeImageAsynchronously(finalImage, suggestSnapshotFilename(snapshotName_));
891 
892  break;
893  }
894  default: break;
895 
896  }
897 }
898 
900  snapshotName_ = _name;
901 }
902 
903 
904 void writeImageQImage(QImage* _image, const QString _name) {
905 
906  _image->save(_name);
907  delete _image;
908 }
909 
910 void CoreWidget::writeImageAsynchronously(QImage* _image, const QString _name) {
911 
912  QFuture<void>* future = new QFuture<void>();
913  *future = QtConcurrent::run(writeImageQImage, _image, _name);
914  QFutureWatcher<void>* watcher = new QFutureWatcher<void>();
915  watcher->setFuture(*future);
916 
917  watcher_garbage_.insert(std::pair<QFutureWatcher<void>*,QFuture<void>*>(watcher, future));
918 
919  connect(watcher, SIGNAL(finished()), this, SLOT(delete_garbage()));
920 }
921 
922 
923 
924 void CoreWidget::delete_garbage() {
925 
926  QObject* obj = QObject::sender();
927  QFutureWatcher<void>* watcher = dynamic_cast<QFutureWatcher<void>*>(obj);
928  if(!watcher) {
929  return;
930  }
931 
932  map_mutex_.lock();
933 
934  std::map<QFutureWatcher<void>*,QFuture<void>*>::iterator f;
935  f = watcher_garbage_.find(watcher);
936  if(f != watcher_garbage_.end()) {
937  delete f->second;
938  delete f->first;
939  watcher_garbage_.erase(f);
940  }
941 
942  map_mutex_.unlock();
943 }
944 
947 }
948 
949 void CoreWidget::slotSetView( QString view ) {
950  examiner_widgets_[PluginFunctions::activeExaminer()]->actionSetView(view);
951 }
952 
954  const unsigned int viewerId = PluginFunctions::activeExaminer();
955 
956  QSize windowSize(0, 0);
957  int splitterWidth = 0;
958  QSize viewportSize(0, 0);
959  examiner_widgets_[viewerId]->decodeView (
960  view, &windowSize, &splitterWidth, &viewportSize);
961 
962  if (windowSize.height() != 0 && windowSize.width() != 0) {
963  if (windowSize.width() < 0) {
964  windowSize *= -1;
965  showNormal();
966  resize(windowSize);
967  showMaximized();
968  } else {
969  showNormal();
970  resize(windowSize);
971  }
972  }
973 
974  if (splitterWidth > 0) {
975  QList<int> splitter_sizes = toolSplitter_->sizes();
976  if (splitter_sizes.size() < 2) {
977  std::cerr << "The tool splitter has less than two children. This "
978  "shouldn't happen." << std::endl;
979  } else {
980  const size_t primary_idx = OpenFlipperSettings().value(
981  "Core/Gui/ToolBoxes/ToolBoxOnTheRight",true).toBool()
982  ? 1 : 0;
983 
984  const int diff = splitterWidth - splitter_sizes[primary_idx];
985  splitter_sizes[primary_idx] += diff;
986  splitter_sizes[1-primary_idx] -= diff;
987  }
988  toolSplitter_->setSizes(splitter_sizes);
989  }
990 
991  /*
992  * Viewport size has precedence. Manipulate window size so that the
993  * viewport size is matched exactly.
994  */
995  if (viewportSize.width() > 0 && viewportSize.height() > 0) {
996  /*
997  * Try twice: Sometimes sizes of elements get readjusted after resizing
998  * and the viewport will not have the desired size.
999  */
1000  for (int i = 0; i < 2; ++i) {
1001  const QSize cur_viewport_size = examiner_widgets_[viewerId]->size().toSize();
1002  if (cur_viewport_size != viewportSize) {
1003  std::cout << "Stored viewport size is " << viewportSize.width()
1004  << " x " << viewportSize.height() << ". Actual size is "
1005  << cur_viewport_size.width() << " x "
1006  << cur_viewport_size.height() << ". Resizing window."
1007  << std::endl;
1008 
1009  showNormal();
1010  QSize diff = viewportSize - cur_viewport_size;
1011  resize(size() + diff);
1012  const QSize new_viewport_size =
1013  examiner_widgets_[viewerId]->size().toSize();
1014  diff = viewportSize - new_viewport_size;
1015  if (diff.width() != 0) {
1016  std::cout << "New viewport size is "
1017  << new_viewport_size.width()
1018  << " x " << new_viewport_size.height() << "."
1019  << " Moving splitter by " << diff.width() << "."
1020  << std::endl;
1021  // Move splitter.
1022  QList<int> splitter_sizes = toolSplitter_->sizes();
1023  if (splitter_sizes.size() < 2) {
1024  std::cerr << "The tool splitter has less than two children. This "
1025  "shouldn't happen." << std::endl;
1026  } else {
1027  const size_t primary_idx = OpenFlipperSettings().value(
1028  "Core/Gui/ToolBoxes/ToolBoxOnTheRight",true).toBool()
1029  ? 0 : 1;
1030 
1031  splitter_sizes[primary_idx] += diff.width();
1032  splitter_sizes[1-primary_idx] -= diff.width();
1033  }
1034  toolSplitter_->setSizes(splitter_sizes);
1035 
1036  }
1037  } else {
1038  break;
1039  }
1040  }
1041  }
1042 }
1043 
1045 {
1046  QSize size;
1047  int splitterWidth;
1048  examiner_widgets_[PluginFunctions::activeExaminer()]->actionPasteView(&size,&splitterWidth);
1049 
1050  //resize the toolbox and splitter
1051  if (splitterWidth != -1)
1052  {
1053  QList<int> sizes;
1054 
1055  //std::cerr << "Sizes : " << size[0] << " " << size[1] << " " << sum_size << std::endl;
1056 
1057  bool onRight = OpenFlipperSettings().value("Core/Gui/ToolBoxes/ToolBoxOnTheRight",true).toBool();
1058  if (onRight)
1059  {
1060  sizes.push_back(size.width() - splitterWidth);
1061  sizes.push_back(splitterWidth);
1062  }
1063  else
1064  {
1065  sizes.push_back(splitterWidth);
1066  sizes.push_back(size.width() - splitterWidth);
1067  }
1068 
1069  toolSplitter_->setSizes(sizes);
1070  }
1071 
1072  //resize window
1073  if (size.isValid())
1074  {
1075  if (size == QSize(0,0))
1076  {
1077  showMaximized();
1078  }
1079  else
1080  {
1081  showNormal();
1082  resizeApplication(size.width(),size.height());
1083  }
1084  }
1085 }
1086 
1088  QSize size;
1089  if (isMaximized())
1090  size = QSize(0,0);
1091  else
1092  size = QSize (width(),height());
1093 
1094  int splitter_size = 0;
1095  if (OpenFlipperSettings().value("Core/Gui/ToolBoxes/ToolBoxOnTheRight",true).toBool())
1096  splitter_size = toolSplitter_->sizes()[1];
1097  else
1098  splitter_size = toolSplitter_->sizes()[0];
1099 
1100  const bool make_c_string = (QApplication::keyboardModifiers() & Qt::ControlModifier);
1102  size, splitter_size, make_c_string);
1103 }
1104 
1106 
1108  ACG::SceneGraph::BaseNode* coordSys = root->find("Core Coordsys Node");
1109 
1110  if (coordSys == 0){
1111  emit log( LOGERR, tr("CoordSys Node not found"));
1112  return;
1113  }
1114 
1115 if (_visible)
1116  coordSys->show();
1117  else
1118  coordSys->hide();
1119 
1120  for ( unsigned int i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
1121  examiner_widgets_[i]->updateGL();
1122 
1123 }
1124 
1125 void CoreWidget::slotSetViewingDirection(QAction* _action) {
1126 
1127  PluginFunctions::setFixedView( _action->data().toInt() );
1128  if (_action->data().toInt() != PluginFunctions::VIEW_FREE)
1130 
1131  // Update view
1133 }
1134 
1136 
1138  if (!_lock)
1139  PluginFunctions::setFixedView( PluginFunctions::VIEW_FREE );
1140 }
1141 
1144 }
1145 
1148 }
1149 
1152 }
1153 
1156 }
1157 
1158 //=============================================================================
void slotGlobalChangeBackFaceCulling(bool _backFaceCulling)
Set backface culling for all viewers.
void animation(bool _state)
set 2-sided lighting on/off
QtGLGraphicsView * glView_
graphics view that holds the gl scene
Definition: CoreWidget.hh:713
void slotLocalChangeAnimation(bool _animation)
Set the animation mode for active viewer.
void slotGlobalToggleAnimation()
If animation is disabled in all viewers, enable it in all viewers. Otherwise disable it...
void moveBack()
When using first person mode move backward.
void strafeRight()
When using first person mode strafe to the right.
void setEnabled(bool _enabled)
Enabled/Disables gl cursor painting.
void slotGlobalSetHomeView()
Set the home position for all viewers.
QToolButton * stereoButton_
Called by Plugins to add a Toolbar.
Definition: CoreWidget.hh:825
void slotContextSetHomeView()
Set the active viewers home position.
void twoSidedLighting(bool _state)
set 2-sided lighting on/off
ProjectionMode
projection mode
Definition: CoordsysNode.hh:88
void slotGlobalToggleMipmapping()
If mipmapping is disabled in all viewers, enable it in all viewers. Otherwise disable it...
void slotSetContextBackgroundColor()
Set Background Color for one viewer.
QString snapshotName_
Create a snapshot of the whole app with fileDialog.
Definition: CoreWidget.hh:1021
QtMultiViewLayout * baseLayout_
Base layout that holds gl views.
Definition: CoreWidget.hh:719
void show()
Show node: set status to Active.
Definition: BaseNode.hh:407
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node
void setProjectionMode(const ProjectionMode _mode)
set mode to either ORTHOGRAPHIC_PROJECTION or PERSPECTIVE_PROJECTION
QStringList collectObjectComments(bool visibleOnly, bool targetedOnly)
void mipmapping(bool _state)
set mipmapping on/off
QStringList collectObjectMaterials(bool visibleOnly, bool targetedOnly)
void slotGlobalChangeMipmapping(bool _multisampling)
Set mipmapping for all viewers.
unsigned int activeExaminer()
Get the id of the examiner which got the last mouse events.
void setFixedView(int _mode, int _viewer)
Set a fixed View for a viewer.
void slotSetViewingDirection(QAction *_action)
Change the viewing direction from context-menu.
bool backFaceCulling()
Get current state of backface culling.
void slotLockRotation(bool _lock)
Lock rotation in current examiner widget.
QtGLGraphicsScene * glScene_
graphics scene used to paint gl context and widgets
Definition: CoreWidget.hh:710
void applicationSnapshotDialog()
Create a snapshot of the whole app with fileDialog.
void slotExaminerSnapshot()
Create a snapshot of the last active examiner.
void slotLocalChangeTwoSidedLighting(bool _lighting)
Set two-sided lighting for active viewer.
void slotGlobalToggleTwoSidedLighting()
If two-sided lighting is disabled in all viewers, enable it in all viewers. Otherwise disable it...
int viewers()
Get the number of viewers.
void slotGlobalChangeAnimation(bool _animation)
Set the animation mode for all viewers.
void strafeLeft()
When using first person mode strafe to the left.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
void slotGlobalToggleBackFaceCulling()
If backface culling is disabled in all viewers, enable it in all viewers. Otherwise disable it...
void slotPasteView()
Paste the view to the last active examiner.
void applicationSnapshotName(QString _name)
Set the snapshot name.
void applicationSnapshot()
Create a snapshot of the whole app.
void snapshotBaseFileName(const QString &_fname)
void slotGlobalToggleMultisampling()
If multisampling is disabled in all viewers, enable it in all viewers. Otherwise disable it...
void hide()
Hide Node: set status to HideNode.
Definition: BaseNode.hh:405
void slotGlobalChangeTwoSidedLighting(bool _lighting)
Set two-sided lighting for all viewers.
void snapshotCounter(const int _counter)
ACG::Vec4f backgroundColor()
Get current background color.
bool stereoActive_
The viewer with id _viewerId changed its draw Mode.
Definition: CoreWidget.hh:1443
void slotGlobalChangeMultisampling(bool _multisampling)
Set multisampling for all viewers.
void slotGlobalOrthographicProjection()
Toggle projection mode of all viewers to orthographic projection.
void slotLocalChangeBackFaceCulling(bool _backFaceCulling)
Set backface culling for active viewer.
void slotContextViewAll()
Change view on active viewer to view complete scene.
void viewerSnapshot()
Create a snapshot of the whole app.
std::vector< glViewer *> examiner_widgets_
Examiner Widget.
Definition: CoreWidget.hh:677
void slotGlobalViewAll()
Change view on all viewers to view complete scene.
void slotSetView(QString view)
Set the supplied serialized view.
void slotToggleStereoMode()
Enable or disable Stereo.
void moveForward()
When using first person mode move forward.
void slotContextSwitchCoordsysProjection()
Toggle coordsys projection mode of the active viewer.
void multisampling(bool _state)
set multisampling on/off
void slotPasteViewAndWindow()
Paste the view, the window and toolbox size to the last active examiner.
Viewer::ViewerProperties & viewerProperties(int _id)
Get the viewer properties Use this functions to get basic viewer properties such as backgroundcolor o...
CursorPainter * cursorPainter_
Cursor handling.
Definition: CoreWidget.hh:750
MultiViewMode mode() const
Retruns current layout modes.
void slotContextSwitchProjection()
Toggle projection mode of the active viewer.
void allowRotation(bool _mode, int _viewer)
void slotLocalChangeMultisampling(bool _multisampling)
Set multisampling for active viewer.
ChildIter find(BaseNode *_node)
Definition: BaseNode.hh:346
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
void slotSwitchWheels(bool _state)
Show / hide wheels.
void slotSetViewAndWindowGeometry(QString view)
Set the supplied serialized view.
void slotContextHomeView()
Set the active viewer to home position.
void slotGlobalHomeView()
Set the viewer to home position.
void slotSetGlobalBackgroundColor()
Set Background Color for all viewers at once.
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
void slotCoordSysVisibility(bool _visible)
Hide coordinate systems in all viewers.
void viewerSnapshotDialog()
Create a snapshot of the whole app with fileDialog.
void slotGlobalPerspectiveProjection()
Toggle projection mode of all viewers to perspective projection.
QSplitter * toolSplitter_
Spliter between toplevel objects and toolbox.
Definition: CoreWidget.hh:731
ProjectionMode getProjectionMode() const
get current projection mode
void slotCopyView()
Copy view from the last active examiner.
void slotLocalChangeMipmapping(bool _mipmapping)
Set mipmapping for active viewer.
void slotSwitchNavigation(bool _egomode)
Switch navigation mode.
ACG::SceneGraph::CoordsysNode::ProjectionMode getCoordsysProjection()
Toggle coordsys projection mode of the active viewer.