Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
OpenFlipper.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 // Mainwindow
53 
54 #include "OpenFlipper/Core/Core.hh"
55 #include "common/glew_wrappers.hh"
56 
57 // Qt
58 #include <qgl.h>
59 
60 // stdc++
61 #include <csignal>
62 
63 #include <OpenFlipper/SimpleOpt/SimpleOpt.h>
64 
65 #if ( defined(WIN32))
66  #define NO_EXECINFO
67 #endif
68 
69 #ifndef NO_EXECINFO
70 #include <execinfo.h>
71 #endif
72 
73 #ifdef USE_OPENMP
74 #endif
75 
76 /* ==========================================================
77  *
78  * Stackwalker code. Used to get a backtrace if OpenFlipper
79  * crashes under windows
80  *
81  * ==========================================================*/
82 
83 
84 #ifdef WIN32
85  #include "StackWalker/StackWalker.hh"
86  #include <fstream>
87 
88  class StackWalkerToConsole : public StackWalker
89  {
90  protected:
91  virtual void OnOutput(LPCSTR szText)
92  {
93  // Writes crash dump to .OpenFlipper config directory
94  std::ofstream crashFile;
95  QString crashName = OpenFlipper::Options::configDirStr() + QDir::separator() + "CrashDump.txt";
96  crashFile.open(crashName.toLatin1(),std::ios::out | std::ios::app);
97  crashFile << szText;
98  crashFile.close();
99  }
100  };
101 #endif
102 
103 
104 /* ==========================================================
105  *
106  * Console for Windows to get additional output written via
107  * cerr, cout, ... that is not forwarded to log window
108  *
109  * ==========================================================*/
110 
111 #ifdef WIN32
112 
113  void attachConsole()
114  {
115  //try to attach the console of the parent process
116  if (AttachConsole(-1))
117  {
118  //if the console was attached change stdinput and output
119  FILE* check = freopen("CONIN$", "r", stdin);
120  if (check) {
121  std::cerr << "Error reopening stdin" << std::endl;
122  }
123  check = freopen("CONOUT$", "w", stdout);
124  if (check) {
125  std::cerr << "Error reopening stdout" << std::endl;
126  }
127  check = freopen("CONOUT$", "w", stderr);
128  if (check) {
129  std::cerr << "Error reopening stderr" << std::endl;
130  }
131  }
132  else
133  {
134  //create and attach a new console if needed
135  #ifndef NDEBUG
136  //always open a console in debug mode
137  AllocConsole();
138 
139  FILE* check = freopen("CONIN$", "r", stdin);
140  if (check) {
141  std::cerr << "Error reopening stdin" << std::endl;
142  }
143  check = freopen("CONOUT$", "w", stdout);
144  if (check) {
145  std::cerr << "Error reopening stdout" << std::endl;
146  }
147  check = freopen("CONOUT$", "w", stderr);
148  if (check) {
149  std::cerr << "Error reopening stderr" << std::endl;
150  }
151  return;
152  #endif
153  if (OpenFlipper::Options::logToConsole())
154  {
155  AllocConsole();
156 
157  FILE* check = freopen("CONIN$", "r", stdin);
158  if (check) {
159  std::cerr << "Error reopening stdin" << std::endl;
160  }
161  check = freopen("CONOUT$", "w", stdout);
162  if (check) {
163  std::cerr << "Error reopening stdout" << std::endl;
164  }
165  check = freopen("CONOUT$", "w", stderr);
166  if (check) {
167  std::cerr << "Error reopening stderr" << std::endl;
168  }
169  }
170  }
171  }
172 
173 #endif
174 
175 /* ==========================================================
176  *
177  * Linux function printing a full stack trace to the console
178  *
179  * ==========================================================*/
180 #ifndef NO_EXECINFO
181 void backtrace()
182 {
183  void *addresses[20];
184  char **strings;
185 
186  int size = backtrace(addresses, 20);
187  strings = backtrace_symbols(addresses, size);
188  std::cerr << "Stack frames: " << size << std::endl;
189  for(int i = 0; i < size; i++)
190  std::cerr << i << ": " << strings[i] << std::endl;
191  free(strings);
192 
193 }
194 #endif
195 
196 /* ==========================================================
197  *
198  * General segfault handler. This function is called if OpenFlipper
199  * crashes
200  *
201  * ==========================================================*/
202 void segfaultHandling (int) {
203 
204  // prevent infinite recursion if segfaultHandling() causes another segfault
205  std::signal(SIGSEGV, SIG_DFL);
206 
207 
208  std::cerr << "\n" << std::endl;
209  std::cerr << "\n" << std::endl;
210  std::cerr << "\33[31m" << "=====================================================" << std::endl;
211  std::cerr << "\33[31m" << "OpenFlipper or one of its plugins caused a Segfault." << std::endl;
212  std::cerr << "\33[31m" << "This should not happen,... Sorry :-(" << std::endl;
213  std::cerr << "\33[31m" << "=====================================================" << std::endl;
214  std::cerr << "\n" << std::endl;
215 
216  // Linux Handler
217 #ifndef NO_EXECINFO
218  std::cerr << "\33[0m" << "Trying a backtrace to show what happened last: " << std::endl;
219  backtrace();
220 
221  std::cerr << "\n" << std::endl;
222  std::cerr << "Backtrace completed, trying to abort now ..." << std::endl;
223 #endif
224 
225  // Windows handler via StackWalker
226 #ifdef WIN32
227  StackWalkerToConsole sw;
228  sw.ShowCallstack();
229 #endif
230 
231 
232  std::cerr << "Trying to get additional information (This might fail if the memory is corrupted)." << std::endl;
233 
234  if (OpenFlipper::Options::gui()) {
235  for ( unsigned int i = 0 ; i < 4 ; ++i) {
236  std::cerr << "DrawMode Viewer "<< i << " " << PluginFunctions::drawMode(i).description() << std::endl;
237  }
238  }
239 
240  std::abort();
241 }
242 
243 enum {OPT_HELP , OPT_STEREO, OPT_BATCH ,OPT_CONSOLE_LOG , OPT_DEBUGGING, OPT_FULLSCREEN,
244  OPT_HIDDDEN_LOGGER , OPT_NOSPLASH ,OPT_HIDDDEN_TOOLBOX , OPT_LOAD_POLYMESHES,
245  OPT_REMOTE, OPT_REMOTE_PORT};
246 
247 CSimpleOpt::SOption g_rgOptions[] = {
248  { OPT_DEBUGGING , (char*) "--debug" , SO_NONE },
249  { OPT_HELP , (char*) "-?" , SO_NONE },
250  { OPT_HELP , (char*) "--help" , SO_NONE },
251  { OPT_HELP , (char*) "-h" , SO_NONE },
252  { OPT_STEREO , (char*) "--disable-stereo" , SO_NONE },
253  { OPT_BATCH , (char*) "-b" , SO_NONE },
254  { OPT_CONSOLE_LOG , (char*) "-c" , SO_NONE },
255  { OPT_CONSOLE_LOG , (char*) "--log-to-console" , SO_NONE },
256  { OPT_FULLSCREEN , (char*) "-f" , SO_NONE },
257  { OPT_HIDDDEN_LOGGER , (char*) "-l" , SO_NONE },
258  { OPT_NOSPLASH , (char*) "--no-splash" , SO_NONE },
259  { OPT_HIDDDEN_TOOLBOX , (char*) "-t" , SO_NONE },
260  { OPT_LOAD_POLYMESHES , (char*) "-p" , SO_NONE },
261  { OPT_REMOTE , (char*) "--remote-control" , SO_NONE },
262  { OPT_REMOTE_PORT , (char*) "--remote-port" , SO_REQ_SEP },
263  SO_END_OF_OPTIONS // END
264 };
265 
266 void showHelp() {
267  std::cerr << "OpenFlipper [Options] <filenames> " << std::endl << std::endl;;
268  std::cerr << "Possible Options : " << std::endl;
269  std::cerr << std::endl;
270 
271  std::cerr << "Load/Save Options:" << std::endl;
272  std::cerr << " -p \t: Open files as PolyMeshes" << std::endl;
273  std::cerr << std::endl;
274 
275  std::cerr << "Gui Options:" << std::endl;
276  std::cerr << " -f \t\t: Start Fullscreen" << std::endl;
277  std::cerr << " -l \t\t: Start with hidden logger" << std::endl;
278  std::cerr << " -t \t\t: Start with hidden Toolbox" << std::endl;
279  std::cerr << " --no-splash \t: Disable splash screen" << std::endl;
280 
281  std::cerr << " --disable-stereo \t: Disable Stereo Mode" << std::endl;
282  std::cerr << std::endl;
283 
284  std::cerr << "Log options:" << std::endl;
285  std::cerr << " --log-to-console ( -c ) \t: Write logger window contents to console" << std::endl;
286  std::cerr << std::endl;
287 
288  std::cerr << "Other options:" << std::endl;
289  std::cerr << " -b \t: Batch mode, you have to provide a script for execution" << std::endl;
290  std::cerr << " --remote-control \t: Batch mode accepting remote connections" << std::endl;
291 
292  std::cerr << std::endl;
293 
294 
295  std::cerr << " -h \t: This help" << std::endl;
296 }
297 
298 
299 
300 
301 
302 
303 bool openPolyMeshes = false;
304 bool remoteControl = false;
305 
306 bool parseCommandLineOptions(CSimpleOpt& args){
307 
308  QString port;
309 
310 #ifndef WIN32
311 #ifndef __APPLE__
312  //workaround for bug with stereo mode on Qt5.7.0 and Qt5.7.1 on Linux
313  int QtVersionMajor, QtVersionMinor, QtVersionPatch;
314  if(sscanf(qVersion(),"%1d.%1d.%1d",&QtVersionMajor, &QtVersionMinor, &QtVersionPatch) == 3)
315  {
316  if(QtVersionMajor == 5 && QtVersionMinor >= 7)
317  {
318  if(QtVersionPatch < 2)
319  {
320  std::cerr << "The used Qt Version does not support stereo mode. Disabling stereo mode." << std::endl;
321  OpenFlipper::Options::stereo(false);
322  }
323  else
324  std::cerr << "Stereo Mode has not been tested for the used Qt Version." << std::endl;
325  }
326  }
327 #endif
328 #endif
329 
330  // while there are arguments left to process
331  while (args.Next()) {
332 
333  if (args.LastError() == SO_SUCCESS) {
334 
335  switch (args.OptionId() ) {
336  case OPT_BATCH:
337  OpenFlipper::Options::nogui(true);
338  break;
339  case OPT_CONSOLE_LOG:
340  OpenFlipper::Options::logToConsole(true);
341  break;
342  case OPT_DEBUGGING:
343  OpenFlipper::Options::debug(true);
344  break;
345  case OPT_STEREO:
346  OpenFlipper::Options::stereo(false);
347  break;
348  case OPT_HIDDDEN_TOOLBOX:
349  OpenFlipperSettings().setValue("Core/Gui/ToolBoxes/hidden",true);
350  break;
351  case OPT_HIDDDEN_LOGGER:
352  OpenFlipper::Options::loggerState(OpenFlipper::Options::Hidden);
353  break;
354  case OPT_FULLSCREEN:
355  OpenFlipperSettings().setValue("Core/Gui/fullscreen",false);
356  break;
357  case OPT_LOAD_POLYMESHES:
358  openPolyMeshes = true;
359  break;
360  case OPT_NOSPLASH:
361  OpenFlipperSettings().setValue("Core/Gui/splash",false);
362  break;
363  case OPT_REMOTE:
364  OpenFlipper::Options::remoteControl(true);
365  break;
366  case OPT_REMOTE_PORT:
367  port = args.OptionArg();
368  std::cerr << "Got option : " << port.toStdString() << std::endl;
369  OpenFlipper::Options::remoteControl(port.toInt());
370  break;
371  case OPT_HELP:
372  showHelp();
373  return 0;
374  }
375  } else {
376  std::cerr << "Invalid argument: " << args.OptionText() << std::endl;
377  showHelp();
378  return false;
379  }
380  }
381  return true;
382 }
383 
384 int main(int argc, char **argv)
385 {
386 
387  // Remove -psn_0_xxxxx argument which is automatically
388  // attached by MacOSX
389  for (int i = 0; i < argc; i++) {
390  if(strlen(argv[i]) > 4) {
391  if( ( (argv[i])[0] == '-' ) &&
392  ( (argv[i])[1] == 'p' ) &&
393  ( (argv[i])[2] == 's' ) &&
394  ( (argv[i])[3] == 'n' ) ) {
395  argc--;
396  argv[i] = (char *)"";
397  }
398  }
399  }
400 
401  OpenFlipper::Options::argc(&argc);
402  OpenFlipper::Options::argv(&argv);
403 
404  CSimpleOpt argBatch(argc, argv, g_rgOptions);
405 
406  //check only batchMode before the core is created
407  while (argBatch.Next())
408  if (argBatch.OptionId() == OPT_BATCH ){
409  OpenFlipper::Options::nogui(true);
410  break;
411  }
412 
413  CSimpleOpt args(argc, argv, g_rgOptions);
414 
415 #ifndef NO_CATCH_SIGSEGV
416  // Set a handler for segfaults
417  std::signal(SIGSEGV, segfaultHandling);
418 #endif
419 
420  OpenFlipper::Options::windowTitle(TOSTRING(PRODUCT_STRING)" v" + OpenFlipper::Options::coreVersion());
421 
422  if ( !OpenFlipper::Options::nogui() ) {
423 
424  // OpenGL check
425  QApplication::setColorSpec( QApplication::CustomColor );
426  QApplication app(argc,argv);
427 
428 #ifdef __APPLE__
429  // Set organization and application names
430  QCoreApplication::setOrganizationName("rwth-aachen.de");
431  QCoreApplication::setApplicationName("graphics.openflipper");
432 #endif
433 
434  if ( !QGLFormat::hasOpenGL() ) {
435  std::cerr << "This system has no OpenGL support.\n";
436  return -1;
437  }
438 
439 #ifndef __APPLE__
440  glutInit(&argc,argv);
441 #endif
442 
443  // create core ( this also reads the ini files )
444  Core * w = new Core( );
445 
446  if ( !parseCommandLineOptions(args) ) {
447  delete w;
448  return 1;
449  }
450 
451 #ifdef WIN32
452  //attach a console if necessary
453  attachConsole();
454 #endif
455 
456  QString tLang = OpenFlipperSettings().value("Core/Language/Translation","en_US").toString();
457 
458  if (tLang == "locale")
459  tLang = QLocale::system().name();
460 
461  // Install translator for qt internals
462  QTranslator qtTranslator;
463 // std::cerr << "Loading qt translations from: " << QLibraryInfo::location(QLibraryInfo::TranslationsPath).toStdString() << std::endl;
464 // if ( qtTranslator.load("qt_" + tLang, QLibraryInfo::location(QLibraryInfo::TranslationsPath)) )
465 // std::cerr << "Loaded" << std::endl;
466 // std::cerr << "Loading qt translations from: " << QLibraryInfo::location(QLibraryInfo::TranslationsPath).toStdString() << std::endl;
467  qtTranslator.load("qt_" + tLang, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
468 // std::cerr << "Loaded" << std::endl;
469 
470  app.installTranslator(&qtTranslator);
471 
472  // install translator for Core Application
473  QString translationDir = OpenFlipper::Options::translationsDirStr() + QDir::separator();
474 
475 // std::cerr << "Loading own translations from: " << QString(translationDir + " (" + tLang + ")").toStdString() << std::endl;
476 
477  QDir dir(translationDir);
478  dir.setFilter(QDir::Files);
479 
480  QFileInfoList list = dir.entryInfoList();
481 
482  for (int i = 0; i < list.size(); ++i) {
483  QFileInfo fileInfo = list.at(i);
484 
485  if ( fileInfo.baseName().contains(tLang) ){
486  QTranslator* myAppTranslator = new QTranslator();
487 
488  if ( myAppTranslator->load( fileInfo.filePath() ) ){
489 // std::cerr << "Loaded " << fileInfo.fileName().toStdString() << std::endl;
490 
491  app.installTranslator(myAppTranslator);
492  } else {
493  delete myAppTranslator;
494  }
495  }
496  }
497 
498  // After setting all Options from command line, build the real gui
499  w->init();
500 
501  #ifndef __APPLE__
502  initGlew();
503  #endif
504 
505  for ( int i = 0 ; i < args.FileCount(); ++i )
506  w->commandLineOpen(args.File(i), openPolyMeshes);
507 
508  return app.exec();
509 
510  } else {
511 
512  QCoreApplication app(argc,argv);
513 
514 #ifdef __APPLE__
515  // Set organization and application names
516  QCoreApplication::setOrganizationName("rwth-aachen.de");
517  QCoreApplication::setApplicationName("graphics.openflipper");
518 #endif
519 
520  // create widget ( this also reads the ini files )
521  Core * w = new Core( );
522 
523  if ( !parseCommandLineOptions(args) ) {
524  delete w;
525  return 1;
526  }
527 
528  // After setting all Options from command line, build the real gui
529  w->init();
530 
531  for ( int i = 0 ; i < args.FileCount(); ++i )
532  w->commandLineScript(args.File(i));
533 
534  return app.exec();
535  }
536 
537  return 0;
538 }
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Definition: Core.hh:139
void init()
Second initialization stage.
Definition: Core.cc:194
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
#define TOSTRING(x)
QSettings object containing all program settings of OpenFlipper.
ACG::SceneGraph::DrawModes::DrawMode drawMode(int _viewer)
Get the current draw Mode of a Viewer.
void commandLineOpen(const char *_filename, bool _asPolyMesh)
Load an object from the commandline on application start.
void commandLineScript(const char *_filename)
Load a script from the commandline on application start.