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.setConfirmOverwrite(true);
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::null;
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::null;
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::null;
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 
508  //grabs only the widget (espacially in windows)
509  //todo: deprecated in QT 5.0, use QScreen instead
510  QPixmap pic = QPixmap::grabWindow( winId() );
511 
512  QPainter painter (&pic);
513 
514  //so we have to add the content from the GLContext manually
515  for (std::vector< glViewer* >::iterator iter = examiner_widgets_.begin(); iter != examiner_widgets_.end(); ++iter)
516  {
517  if (*iter)
518  {
519  QImage fillImage;
520 
521  (*iter)->snapshot(fillImage, (*iter)->glWidth() , (*iter)->glHeight());
522 
523  QPoint localPos = QPoint((*iter)->pos().x(),(*iter)->pos().y());
524  QPointF pos = glView_->mapTo(this,localPos);
525  painter.drawImage(pos,fillImage);
526  }
527  }
528 
529  pic.save(newName);
530  }
531 
532  emit resizeApplication(w,h);
533 }
534 
537  // Write image asynchronously
538  QImage* pic = new QImage(QPixmap::grabWindow( winId() ).toImage());
539  writeImageAsynchronously(pic, suggestSnapshotFilename(snapshotName_));
540 }
541 
542 void CoreWidget::viewerSnapshot(QString file_name, bool store_comments,
543  bool comments_visible_only, bool comments_targeted_only,
544  bool store_material_info, int snapshot_width, int snapshot_height,
545  bool snapshot_transparent, bool hide_coord_sys,
546  int snapshot_multisampling, bool store_view) {
547 
548  if (snapshot_height < 0) {
549  int w = glView_->width();
550  int h = glView_->height();
551  snapshot_height = static_cast<int>(round(
552  static_cast<double>(snapshot_width) / w * h));
553  }
554 
555  QString comments;
556  if (store_comments) {
558  comments_visible_only,
559  comments_targeted_only).join("\n");
560  }
561 
562  QString materials;
563  if (ACG::SceneGraph::Material::support_json_serialization() &&
564  //if (ACG::SceneGraph::Material::CP_JSON_SERIALIZABLE &&
565  store_material_info) {
567  comments_visible_only,
568  comments_targeted_only).join("\n");
569  }
570 
571  //now take the snapshot
572  switch ( baseLayout_->mode() ){
573 
574  case QtMultiViewLayout::SingleView:
575  {
576  QImage finalImage;
577 
578  examiner_widgets_[PluginFunctions::activeExaminer()]->snapshot(finalImage,
579  snapshot_width, snapshot_height,
580  snapshot_transparent, hide_coord_sys,
581  snapshot_multisampling);
582 
583  if (!comments.isEmpty())
584  finalImage.setText("Mesh Comments", comments);
585  if (!materials.isEmpty())
586  finalImage.setText("Mesh Materials", materials);
587  if (store_view) {
588  QSize window_size;
589  if (isMaximized())
590  window_size = QSize(-width(), -height());
591  else
592  window_size = QSize (width(), height());
593 
594  int splitter_size = 0;
595  if (OpenFlipperSettings().value("Core/Gui/ToolBoxes/ToolBoxOnTheRight",true).toBool())
596  splitter_size = toolSplitter_->sizes()[1];
597  else
598  splitter_size = toolSplitter_->sizes()[0];
599 
600  QString view;
601  examiner_widgets_[PluginFunctions::activeExaminer()]->encodeView(view, window_size, splitter_size);
602  finalImage.setText("View", view);
603  }
604  finalImage.save(file_name);
605 
606  break;
607  }
608  case QtMultiViewLayout::DoubleView:
609  {
610  int w = snapshot_height;
611 
612  double relSizeW = static_cast<double>( examiner_widgets_[0]->glWidth() / static_cast<double>( glScene_->width() ) );
613 
614  //Get the images
615  QImage img[2];
616  examiner_widgets_[0]->snapshot(
617  img[0], static_cast<int>(relSizeW * w),
618  snapshot_width, snapshot_transparent,
619  hide_coord_sys);
620  examiner_widgets_[1]->snapshot(
621  img[1], static_cast<int>(relSizeW * w),
622  snapshot_width, snapshot_transparent,
623  hide_coord_sys);
624 
625  QImage finalImage(img[0].width() + img[1].width() +2, img[0].height(),
626  QImage::Format_ARGB32_Premultiplied);
627 
628  QPainter painter(&finalImage);
629 
630  painter.fillRect(0,0,finalImage.width(),
631  finalImage.height(), QBrush(Qt::gray));
632 
633  painter.drawImage(QRectF( 0, 0, img[0].width(), img[0].height()),img[0],
634  QRectF( 0, 0, img[0].width(), img[0].height()) );
635  painter.drawImage(QRectF(img[0].width()+2, 0, img[1].width(), img[1].height()),img[1],
636  QRectF( 0, 0, img[1].width(), img[1].height()) );
637 
638  if (!comments.isEmpty())
639  finalImage.setText("Mesh Comments", comments);
640  finalImage.save(file_name);
641 
642  break;
643  }
644 
645  case QtMultiViewLayout::Grid:
646  {
647  // Relative size of first viewer (in relation to the other viewers
648  double relSizeW = (double)examiner_widgets_[0]->glWidth() / (double)glScene_->width();
649  double relSizeH = (double)examiner_widgets_[0]->glHeight() / (double)glScene_->height();
650 
651  QImage img0,img1,img2,img3;
652 
653  examiner_widgets_[0]->snapshot(img0,
654  (int)((double)snapshot_width * relSizeW),
655  (int)((double)snapshot_height * relSizeH),
656  snapshot_transparent, hide_coord_sys);
657  examiner_widgets_[1]->snapshot(img1,
658  (int)((double)snapshot_width * (1.0 - relSizeW)),
659  (int)((double)snapshot_height * relSizeH),
660  snapshot_transparent, hide_coord_sys);
661  examiner_widgets_[2]->snapshot(img2,
662  (int)((double)snapshot_width * relSizeW),
663  (int)((double)snapshot_height * (1.0 - relSizeH)),
664  snapshot_transparent, hide_coord_sys);
665  examiner_widgets_[3]->snapshot(img3,
666  (int)((double)snapshot_width * (1.0 - relSizeW)),
667  (int)((double)snapshot_height * (1.0 - relSizeH)),
668  snapshot_transparent, hide_coord_sys);
669 
670  QImage finalImage(img0.width() + img1.width()+2,
671  img0.height() + img2.height()+2,
672  QImage::Format_ARGB32_Premultiplied);
673 
674  QPainter painter(&finalImage);
675 
676  painter.fillRect(0,0,finalImage.width(), finalImage.height(), QBrush(Qt::gray));
677 
678  painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
679  QRectF( 0, 0, img0.width(), img0.height()) );
680  painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
681  QRectF( 0, 0, img1.width(), img1.height()) );
682  painter.drawImage(QRectF( 0,img0.height()+2, img2.width(), img2.height()),img2,
683  QRectF( 0, 0, img2.width(), img2.height()) );
684  painter.drawImage(QRectF(img0.width()+2, img0.height()+2, img3.width(), img3.height()),img3,
685  QRectF( 0, 0, img3.width(), img3.height()) );
686 
687  if (!comments.isEmpty())
688  finalImage.setText("Mesh Comments", comments);
689  finalImage.save(file_name);
690 
691  break;
692  }
693  case QtMultiViewLayout::HSplit:
694  {
695  // Relative size of first viewer (in relation to the other viewers
696  double relSizeW = (double)examiner_widgets_[0]->glWidth() / (double)glScene_->width();
697  double relSizeH1 = (double)examiner_widgets_[1]->glHeight() / (double)glScene_->height();
698  double relSizeH2 = (double)examiner_widgets_[2]->glHeight() / (double)glScene_->height();
699  double relSizeH3 = (double)examiner_widgets_[3]->glHeight() / (double)glScene_->height();
700 
701  QImage img0,img1,img2,img3;
702 
703  examiner_widgets_[0]->snapshot(img0,
704  (int)((double)snapshot_width * relSizeW), snapshot_height,
705  snapshot_transparent, hide_coord_sys);
706  examiner_widgets_[1]->snapshot(img1,
707  (int)((double)snapshot_width * (1.0 - relSizeW)),
708  relSizeH1 * (double)snapshot_height,
709  snapshot_transparent, hide_coord_sys);
710  examiner_widgets_[2]->snapshot(img2,
711  (int)((double)snapshot_width * (1.0 - relSizeW)),
712  relSizeH2 * (double)snapshot_height,
713  snapshot_transparent, hide_coord_sys);
714  examiner_widgets_[3]->snapshot(img3,
715  (int)((double)snapshot_width * (1.0 - relSizeW)),
716  relSizeH3 * (double)snapshot_height,
717  snapshot_transparent, hide_coord_sys);
718 
719  QImage finalImage(img0.width() + img1.width() +2, img0.height(), QImage::Format_ARGB32_Premultiplied);
720 
721  QPainter painter(&finalImage);
722 
723  painter.fillRect(0,0,finalImage.width(), finalImage.height(), QBrush(Qt::gray));
724 
725  painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
726  QRectF( 0, 0, img0.width(), img0.height()) );
727  painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
728  QRectF( 0, 0, img1.width(), img1.height()) );
729  painter.drawImage(QRectF(img0.width()+2, img1.height()+2, img2.width(), img2.height()),img2,
730  QRectF( 0, 0, img2.width(), img2.height()) );
731  painter.drawImage(QRectF(img0.width()+2, img1.height()+img2.height()+4, img3.width(),img3.height()),img3,
732  QRectF( 0, 0, img3.width(), img3.height()) );
733 
734  if (!comments.isEmpty())
735  finalImage.setText("Mesh Comments", comments);
736  finalImage.save(file_name);
737 
738  break;
739  }
740  default: break;
741 
742  }
743 }
744 
747  int w = glView_->width();
748  int h = glView_->height();
749 
750  SnapshotDialog dialog(suggestSnapshotFilename(snapshotName_), true, w, h, 0);
751 
752  if (!ACG::SceneGraph::Material::support_json_serialization())
753  dialog.metaData_storeMatInfo_cb->setVisible(false);
754 
755  bool ok = dialog.exec();
756 
757  if (ok){
758  QString newName = dialog.filename->text();
759 
760  OpenFlipperSettings().setValue("Core/CurrentDir", QFileInfo(newName).absolutePath() );
761 
762  snapshotName_ = newName;
763 
764  const bool storeComments = dialog.metaData_storeComments_cb->isChecked();
765  const bool comments_visible_only =
766  dialog.metaData_comments_visibleOnly_cb->isChecked();
767  const bool comments_targeted_only =
768  dialog.metaData_comments_targetedOnly_cb->isChecked();
769  const bool store_material_info =
770  dialog.metaData_storeMatInfo_cb->isChecked();
771  const int snapshot_width = dialog.snapWidth->value();
772  const int snapshot_height = dialog.snapHeight->value();
773  const bool snapshot_transparent = dialog.transparent->isChecked();
774  const bool hide_coord_sys = dialog.hideCoordsys->isChecked();
775  const int snapshot_multisampling =
776  dialog.multisampling->isChecked() ?
777  dialog.num_samples->value() : 1;
778  const bool store_view = dialog.metaData_storeView_cb->isChecked();
779 
780  viewerSnapshot(newName, storeComments, comments_visible_only,
781  comments_targeted_only, store_material_info, snapshot_width,
782  snapshot_height, snapshot_transparent, hide_coord_sys,
783  snapshot_multisampling, store_view);
784  }
785  //glView_->resize(w, h);
786 }
787 
790 
791  switch ( baseLayout_->mode() ){
792 
793  case QtMultiViewLayout::SingleView:
794  {
795  QImage* finalImage = new QImage();
796 
797  examiner_widgets_[PluginFunctions::activeExaminer()]->snapshot(*finalImage);
798 
799  writeImageAsynchronously(finalImage, suggestSnapshotFilename(snapshotName_));
800 
801  break;
802  }
803  case QtMultiViewLayout::DoubleView:
804  {
805  //Get the images
806  QImage img[2];
807  examiner_widgets_[0]->snapshot(img[0]);
808  examiner_widgets_[1]->snapshot(img[1]);
809 
810  QImage* finalImage = new QImage(img[0].width() + img[1].width() +2, img[0].height(), QImage::Format_ARGB32_Premultiplied);
811 
812  QPainter painter(finalImage);
813 
814  painter.fillRect(0,0,finalImage->width(), finalImage->height(), QBrush(Qt::gray));
815 
816  painter.drawImage(QRectF( 0, 0, img[0].width(), img[0].height()),img[0],
817  QRectF( 0, 0, img[0].width(), img[0].height()) );
818  painter.drawImage(QRectF(img[0].width()+2, 0, img[1].width(), img[1].height()),img[1],
819  QRectF( 0, 0, img[1].width(), img[1].height()) );
820 
821  writeImageAsynchronously(finalImage, suggestSnapshotFilename(snapshotName_));
822 
823  break;
824  }
825 
826  case QtMultiViewLayout::Grid:
827  {
828  QImage img0,img1,img2,img3;
829 
830  examiner_widgets_[0]->snapshot(img0);
831  examiner_widgets_[1]->snapshot(img1);
832  examiner_widgets_[2]->snapshot(img2);
833  examiner_widgets_[3]->snapshot(img3);
834 
835  QImage* finalImage = new QImage(img0.width() + img1.width() + 2, img0.height() + img2.height() + 2, QImage::Format_ARGB32_Premultiplied);
836 
837  QPainter painter(finalImage);
838 
839  painter.fillRect(0,0,finalImage->width(), finalImage->height(), QBrush(Qt::gray));
840 
841  painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
842  QRectF( 0, 0, img0.width(), img0.height()) );
843  painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
844  QRectF( 0, 0, img1.width(), img1.height()) );
845  painter.drawImage(QRectF( 0, img0.height()+2, img2.width(), img2.height()),img2,
846  QRectF( 0, 0, img2.width(), img2.height()) );
847  painter.drawImage(QRectF(img0.width()+2, img0.height()+2, img3.width(), img3.height()),img3,
848  QRectF( 0, 0, img3.width(), img3.height()) );
849 
850  writeImageAsynchronously(finalImage, suggestSnapshotFilename(snapshotName_));
851 
852  break;
853  }
854  case QtMultiViewLayout::HSplit:
855  {
856  QImage img0,img1,img2,img3;
857 
858  examiner_widgets_[0]->snapshot(img0);
859  examiner_widgets_[1]->snapshot(img1);
860  examiner_widgets_[2]->snapshot(img2);
861  examiner_widgets_[3]->snapshot(img3);
862 
863  QImage* finalImage = new QImage(img0.width() + img1.width() + 2, img0.height(), QImage::Format_ARGB32_Premultiplied);
864 
865  QPainter painter(finalImage);
866 
867  painter.fillRect(0,0,finalImage->width(), finalImage->height(), QBrush(Qt::gray));
868 
869  painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
870  QRectF( 0, 0, img0.width(), img0.height()) );
871  painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
872  QRectF( 0, 0, img1.width(), img1.height()) );
873  painter.drawImage(QRectF(img0.width()+2, img1.height()+2, img2.width(), img2.height()),img2,
874  QRectF( 0, 0, img2.width(), img2.height()) );
875  painter.drawImage(QRectF(img0.width()+2, img1.height()+img2.height()+4, img3.width(),img3.height()),img3,
876  QRectF( 0, 0, img3.width(), img3.height()) );
877 
878  writeImageAsynchronously(finalImage, suggestSnapshotFilename(snapshotName_));
879 
880  break;
881  }
882  default: break;
883 
884  }
885 }
886 
888  snapshotName_ = _name;
889 }
890 
891 
892 void writeImageQImage(QImage* _image, const QString _name) {
893 
894  _image->save(_name);
895  delete _image;
896 }
897 
898 void CoreWidget::writeImageAsynchronously(QImage* _image, const QString _name) {
899 
900  QFuture<void>* future = new QFuture<void>();
901  *future = QtConcurrent::run(writeImageQImage, _image, _name);
902  QFutureWatcher<void>* watcher = new QFutureWatcher<void>();
903  watcher->setFuture(*future);
904 
905  watcher_garbage_.insert(std::pair<QFutureWatcher<void>*,QFuture<void>*>(watcher, future));
906 
907  connect(watcher, SIGNAL(finished()), this, SLOT(delete_garbage()));
908 }
909 
910 
911 
912 void CoreWidget::delete_garbage() {
913 
914  QObject* obj = QObject::sender();
915  QFutureWatcher<void>* watcher = dynamic_cast<QFutureWatcher<void>*>(obj);
916  if(!watcher) {
917  return;
918  }
919 
920  map_mutex_.lock();
921 
922  std::map<QFutureWatcher<void>*,QFuture<void>*>::iterator f;
923  f = watcher_garbage_.find(watcher);
924  if(f != watcher_garbage_.end()) {
925  delete f->second;
926  delete f->first;
927  watcher_garbage_.erase(f);
928  }
929 
930  map_mutex_.unlock();
931 }
932 
935 }
936 
937 void CoreWidget::slotSetView( QString view ) {
938  examiner_widgets_[PluginFunctions::activeExaminer()]->actionSetView(view);
939 }
940 
942  const unsigned int viewerId = PluginFunctions::activeExaminer();
943 
944  QSize windowSize(0, 0);
945  int splitterWidth = 0;
946  QSize viewportSize(0, 0);
947  examiner_widgets_[viewerId]->decodeView (
948  view, &windowSize, &splitterWidth, &viewportSize);
949 
950  if (windowSize.height() != 0 && windowSize.width() != 0) {
951  if (windowSize.width() < 0) {
952  windowSize *= -1;
953  showNormal();
954  resize(windowSize);
955  showMaximized();
956  } else {
957  showNormal();
958  resize(windowSize);
959  }
960  }
961 
962  if (splitterWidth > 0) {
963  QList<int> splitter_sizes = toolSplitter_->sizes();
964  if (splitter_sizes.size() < 2) {
965  std::cerr << "The tool splitter has less than two children. This "
966  "shouldn't happen." << std::endl;
967  } else {
968  const size_t primary_idx = OpenFlipperSettings().value(
969  "Core/Gui/ToolBoxes/ToolBoxOnTheRight",true).toBool()
970  ? 1 : 0;
971 
972  const int diff = splitterWidth - splitter_sizes[primary_idx];
973  splitter_sizes[primary_idx] += diff;
974  splitter_sizes[1-primary_idx] -= diff;
975  }
976  toolSplitter_->setSizes(splitter_sizes);
977  }
978 
979  /*
980  * Viewport size has precedence. Manipulate window size so that the
981  * viewport size is matched exactly.
982  */
983  if (viewportSize.width() > 0 && viewportSize.height() > 0) {
984  /*
985  * Try twice: Sometimes sizes of elements get readjusted after resizing
986  * and the viewport will not have the desired size.
987  */
988  for (int i = 0; i < 2; ++i) {
989  const QSize cur_viewport_size = examiner_widgets_[viewerId]->size().toSize();
990  if (cur_viewport_size != viewportSize) {
991  std::cout << "Stored viewport size is " << viewportSize.width()
992  << " x " << viewportSize.height() << ". Actual size is "
993  << cur_viewport_size.width() << " x "
994  << cur_viewport_size.height() << ". Resizing window."
995  << std::endl;
996 
997  showNormal();
998  QSize diff = viewportSize - cur_viewport_size;
999  resize(size() + diff);
1000  const QSize new_viewport_size =
1001  examiner_widgets_[viewerId]->size().toSize();
1002  diff = viewportSize - new_viewport_size;
1003  if (diff.width() != 0) {
1004  std::cout << "New viewport size is "
1005  << new_viewport_size.width()
1006  << " x " << new_viewport_size.height() << "."
1007  << " Moving splitter by " << diff.width() << "."
1008  << std::endl;
1009  // Move splitter.
1010  QList<int> splitter_sizes = toolSplitter_->sizes();
1011  if (splitter_sizes.size() < 2) {
1012  std::cerr << "The tool splitter has less than two children. This "
1013  "shouldn't happen." << std::endl;
1014  } else {
1015  const size_t primary_idx = OpenFlipperSettings().value(
1016  "Core/Gui/ToolBoxes/ToolBoxOnTheRight",true).toBool()
1017  ? 0 : 1;
1018 
1019  splitter_sizes[primary_idx] += diff.width();
1020  splitter_sizes[1-primary_idx] -= diff.width();
1021  }
1022  toolSplitter_->setSizes(splitter_sizes);
1023 
1024  }
1025  } else {
1026  break;
1027  }
1028  }
1029  }
1030 }
1031 
1033 {
1034  QSize size;
1035  int splitterWidth;
1036  examiner_widgets_[PluginFunctions::activeExaminer()]->actionPasteView(&size,&splitterWidth);
1037 
1038  //resize the toolbox and splitter
1039  if (splitterWidth != -1)
1040  {
1041  QList<int> sizes;
1042 
1043  //std::cerr << "Sizes : " << size[0] << " " << size[1] << " " << sum_size << std::endl;
1044 
1045  bool onRight = OpenFlipperSettings().value("Core/Gui/ToolBoxes/ToolBoxOnTheRight",true).toBool();
1046  if (onRight)
1047  {
1048  sizes.push_back(size.width() - splitterWidth);
1049  sizes.push_back(splitterWidth);
1050  }
1051  else
1052  {
1053  sizes.push_back(splitterWidth);
1054  sizes.push_back(size.width() - splitterWidth);
1055  }
1056 
1057  toolSplitter_->setSizes(sizes);
1058  }
1059 
1060  //resize window
1061  if (size.isValid())
1062  {
1063  if (size == QSize(0,0))
1064  {
1065  showMaximized();
1066  }
1067  else
1068  {
1069  showNormal();
1070  resizeApplication(size.width(),size.height());
1071  }
1072  }
1073 }
1074 
1076  QSize size;
1077  if (isMaximized())
1078  size = QSize(0,0);
1079  else
1080  size = QSize (width(),height());
1081 
1082  int splitter_size = 0;
1083  if (OpenFlipperSettings().value("Core/Gui/ToolBoxes/ToolBoxOnTheRight",true).toBool())
1084  splitter_size = toolSplitter_->sizes()[1];
1085  else
1086  splitter_size = toolSplitter_->sizes()[0];
1087 
1088  const bool make_c_string = (QApplication::keyboardModifiers() & Qt::ControlModifier);
1090  size, splitter_size, make_c_string);
1091 }
1092 
1094 
1096  ACG::SceneGraph::BaseNode* coordSys = root->find("Core Coordsys Node");
1097 
1098  if (coordSys == 0){
1099  emit log( LOGERR, tr("CoordSys Node not found"));
1100  return;
1101  }
1102 
1103 if (_visible)
1104  coordSys->show();
1105  else
1106  coordSys->hide();
1107 
1108  for ( unsigned int i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
1109  examiner_widgets_[i]->updateGL();
1110 
1111 }
1112 
1113 void CoreWidget::slotSetViewingDirection(QAction* _action) {
1114 
1115  PluginFunctions::setFixedView( _action->data().toInt() );
1116  if (_action->data().toInt() != PluginFunctions::VIEW_FREE)
1118 
1119  // Update view
1121 }
1122 
1124 
1126  if (!_lock)
1127  PluginFunctions::setFixedView( PluginFunctions::VIEW_FREE );
1128 }
1129 
1132 }
1133 
1136 }
1137 
1140 }
1141 
1144 }
1145 
1146 //=============================================================================
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
QString snapshotName_
Create a snapshot of the whole app with fileDialog.
Definition: CoreWidget.hh:1021
void slotLocalChangeMultisampling(bool _multisampling)
Set multisampling for active viewer.
void slotCopyView()
Copy view from the last active examiner.
void slotGlobalToggleTwoSidedLighting()
If two-sided lighting is disabled in all viewers, enable it in all viewers. Otherwise disable it...
void allowRotation(bool _mode, int _viewer)
void viewerSnapshotDialog()
Create a snapshot of the whole app with fileDialog.
void applicationSnapshotName(QString _name)
Set the snapshot name.
void slotGlobalToggleMultisampling()
If multisampling is disabled in all viewers, enable it in all viewers. Otherwise disable it...
void slotContextSwitchProjection()
Toggle projection mode of the active viewer.
void slotLockRotation(bool _lock)
Lock rotation in current examiner widget.
void setProjectionMode(const ProjectionMode _mode)
set mode to either ORTHOGRAPHIC_PROJECTION or PERSPECTIVE_PROJECTION
QToolButton * stereoButton_
Called by Plugins to add a Toolbar.
Definition: CoreWidget.hh:825
QStringList collectObjectComments(bool visibleOnly, bool targetedOnly)
CursorPainter * cursorPainter_
Cursor handling.
Definition: CoreWidget.hh:750
ACG::SceneGraph::CoordsysNode::ProjectionMode getCoordsysProjection()
Toggle coordsys projection mode of the active viewer.
QStringList collectObjectMaterials(bool visibleOnly, bool targetedOnly)
unsigned int activeExaminer()
Get the id of the examiner which got the last mouse events.
void slotLocalChangeTwoSidedLighting(bool _lighting)
Set two-sided lighting for active viewer.
void slotGlobalToggleAnimation()
If animation is disabled in all viewers, enable it in all viewers. Otherwise disable it...
void setFixedView(int _mode, int _viewer)
Set a fixed View for a viewer.
void slotLocalChangeBackFaceCulling(bool _backFaceCulling)
Set backface culling for active viewer.
void twoSidedLighting(bool _state)
set 2-sided lighting on/off
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
void slotExaminerSnapshot()
Create a snapshot of the last active examiner.
QtGLGraphicsScene * glScene_
graphics scene used to paint gl context and widgets
Definition: CoreWidget.hh:710
void animation(bool _state)
set 2-sided lighting on/off
bool stereoActive_
The viewer with id _viewerId changed its draw Mode.
Definition: CoreWidget.hh:1443
void slotSetContextBackgroundColor()
Set Background Color for one viewer.
void slotGlobalChangeAnimation(bool _animation)
Set the animation mode for all viewers.
int viewers()
Get the number of viewers.
void multisampling(bool _state)
set multisampling on/off
void moveForward()
When using first person mode move forward.
void slotPasteView()
Paste the view to the last active examiner.
void slotContextSwitchCoordsysProjection()
Toggle coordsys projection mode of the active viewer.
ProjectionMode getProjectionMode() const
get current projection mode
void slotSwitchNavigation(bool _egomode)
Switch navigation mode.
void slotGlobalChangeBackFaceCulling(bool _backFaceCulling)
Set backface culling for all viewers.
void slotContextSetHomeView()
Set the active viewers home position.
Viewer::ViewerProperties & viewerProperties(int _id)
Get the viewer properties Use this functions to get basic viewer properties such as backgroundcolor o...
void slotGlobalPerspectiveProjection()
Toggle projection mode of all viewers to perspective projection.
void slotSetViewingDirection(QAction *_action)
Change the viewing direction from context-menu.
ACG::Vec4f backgroundColor()
Get current background color.
void slotGlobalHomeView()
Set the viewer to home position.
void applicationSnapshotDialog()
Create a snapshot of the whole app with fileDialog.
void slotSetGlobalBackgroundColor()
Set Background Color for all viewers at once.
void slotLocalChangeMipmapping(bool _mipmapping)
Set mipmapping for active viewer.
void slotSetViewAndWindowGeometry(QString view)
Set the supplied serialized view.
void slotSetView(QString view)
Set the supplied serialized view.
void slotCoordSysVisibility(bool _visible)
Hide coordinate systems in all viewers.
void slotPasteViewAndWindow()
Paste the view, the window and toolbox size to the last active examiner.
ProjectionMode
projection mode
Definition: CoordsysNode.hh:88
void mipmapping(bool _state)
set mipmapping on/off
void slotContextHomeView()
Set the active viewer to home position.
ChildIter find(BaseNode *_node)
Definition: BaseNode.hh:346
void slotLocalChangeAnimation(bool _animation)
Set the animation mode for active viewer.
void moveBack()
When using first person mode move backward.
void snapshotCounter(const int _counter)
void applicationSnapshot()
Create a snapshot of the whole app.
void slotGlobalChangeMultisampling(bool _multisampling)
Set multisampling for all viewers.
bool backFaceCulling()
Get current state of backface culling.
void slotSwitchWheels(bool _state)
Show / hide wheels.
void show()
Show node: set status to Active.
Definition: BaseNode.hh:407
void setEnabled(bool _enabled)
Enabled/Disables gl cursor painting.
void slotContextViewAll()
Change view on active viewer to view complete scene.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
void slotGlobalChangeMipmapping(bool _multisampling)
Set mipmapping for all viewers.
std::vector< glViewer *> examiner_widgets_
Examiner Widget.
Definition: CoreWidget.hh:677
void hide()
Hide Node: set status to HideNode.
Definition: BaseNode.hh:405
QtMultiViewLayout * baseLayout_
Base layout that holds gl views.
Definition: CoreWidget.hh:719
MultiViewMode mode() const
Retruns current layout modes.
void slotGlobalSetHomeView()
Set the home position for all viewers.
void slotGlobalToggleBackFaceCulling()
If backface culling is disabled in all viewers, enable it in all viewers. Otherwise disable it...
void slotGlobalViewAll()
Change view on all viewers to view complete scene.
void slotGlobalOrthographicProjection()
Toggle projection mode of all viewers to orthographic projection.
QtGLGraphicsView * glView_
graphics view that holds the gl scene
Definition: CoreWidget.hh:713
void slotToggleStereoMode()
Enable or disable Stereo.
void slotGlobalChangeTwoSidedLighting(bool _lighting)
Set two-sided lighting for all viewers.
void snapshotBaseFileName(const QString &_fname)
void viewerSnapshot()
Create a snapshot of the whole app.
void strafeLeft()
When using first person mode strafe to the left.
QSplitter * toolSplitter_
Spliter between toplevel objects and toolbox.
Definition: CoreWidget.hh:731
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node
void slotGlobalToggleMipmapping()
If mipmapping is disabled in all viewers, enable it in all viewers. Otherwise disable it...
void strafeRight()
When using first person mode strafe to the right.