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