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