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 
45 
46 // Mainwindow
47 
48 #include "OpenFlipper/Core/Core.hh"
49 #include "common/glew_wrappers.hh"
50 #include "OpenFlipper/BasePlugin/PluginFunctionsCore.hh"
51 
52 // Qt
53 #include <qgl.h>
54 
55 // stdc++
56 #include <csignal>
57 #include <regex>
58 
59 #include <QCommandLineParser>
60 
61 #if ( defined(WIN32))
62  #define NO_EXECINFO
63 #endif
64 
65 #ifndef NO_EXECINFO
66 #include <execinfo.h>
67 #endif
68 
69 #ifdef PYTHON_ENABLED
70  #include <PythonInterpreter/PythonInterpreter.hh>
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) override
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  // Write crash dump to console as well
101  StackWalker::OnOutput(szText);
102  }
103  };
104 #endif
105 
106 
107 /* ==========================================================
108  *
109  * Console for Windows to get additional output written via
110  * cerr, cout, ... that is not forwarded to log window
111  *
112  * ==========================================================*/
113 
114 #ifdef WIN32
115 
116 void connect_console()
117 {
118  FILE* check = freopen("CONIN$", "r", stdin);
119  if (check) {
120  std::cerr << "Error reopening stdin" << std::endl;
121  }
122  check = freopen("CONOUT$", "w", stdout);
123  if (check) {
124  std::cerr << "Error reopening stdout" << std::endl;
125  }
126  check = freopen("CONOUT$", "w", stderr);
127  if (check) {
128  std::cerr << "Error reopening stderr" << std::endl;
129  }
130  std::cout.clear();
131  std::cerr.clear();
132  std::cin.clear();
133  std::wcout.clear();
134  std::wcerr.clear();
135  std::wcin.clear();
136 }
137 
138  void attachConsole()
139  {
140  //try to attach the console of the parent process
141  if (AttachConsole(-1))
142  {
143  //if the console was attached change stdinput and output
144  connect_console();
145  }
146  else
147  {
148  //create and attach a new console if needed
149  #ifndef NDEBUG
150  //always open a console in debug mode
151  AllocConsole();
152  connect_console();
153 
154  return;
155  #endif
156  if (OpenFlipper::Options::logToConsole())
157  {
158  AllocConsole();
159  connect_console();
160  }
161  }
162  }
163 
164 #endif
165 
166 /* ==========================================================
167  *
168  * Linux function printing a full stack trace to the console
169  *
170  * ==========================================================*/
171 #ifndef NO_EXECINFO
172 
173 #if defined(__GLIBCXX__) || defined(__GLIBCPP__)
174 // GCC: implement demangling using cxxabi
175 #include <cxxabi.h>
176 std::string demangle(const std::string& _symbol)
177 {
178  int status;
179  char* demangled = abi::__cxa_demangle(_symbol.c_str(), nullptr, nullptr, &status);
180  if (demangled) {
181  std::string result{demangled};
182  free(demangled);
183  if (status == 0) {
184  return result;
185  }
186  else {
187  return _symbol;
188  }
189  }
190  else {
191  return _symbol;
192  }
193 }
194 #else
195 // other compiler environment: no demangling
196 std::string demangle(const std::string& _symbol)
197 {
198  return _symbol;
199 }
200 #endif
201 
202 void backtrace()
203 {
204  void *addresses[20];
205  char **strings;
206 
207  int size = backtrace(addresses, 20);
208  strings = backtrace_symbols(addresses, size);
209  std::cerr << "Stack frames: " << size << std::endl;
210  // line format:
211  // <path>(<mangled_name>+<offset>) [<address>]
212  std::regex line_format{R"(^\s*(.+)\((([^()]+)?\+(0x[0-9a-f]+))?\)\s+\[(0x[0-9a-f]+)\]\s*$)"};
213  for(int i = 0; i < size; i++) {
214  std::string line{strings[i]};
215  std::smatch match;
216  std::regex_match(line, match, line_format);
217  if (!match.empty()) {
218  auto file_name = match[1].str();
219  auto symbol = demangle(match[3].str());
220  auto offset = match[4].str();
221  auto address = match[5].str();
222  std::cerr << i << ":";
223  if (!file_name.empty()) std::cerr << " " << file_name << " ::";
224  if (!symbol.empty()) std::cerr << " " << symbol;
225  if (!offset.empty()) std::cerr << " (+" << offset << ")";
226  if (!address.empty()) std::cerr << " [" << address << "]";
227  std::cerr << std::endl;
228  }
229  }
230  free(strings);
231 }
232 #endif
233 
234 /* ==========================================================
235  *
236  * General segfault handler. This function is called if OpenFlipper
237  * crashes
238  *
239  * ==========================================================*/
240 void segfaultHandling (int) {
241 
242  // prevent infinite recursion if segfaultHandling() causes another segfault
243  std::signal(SIGSEGV, SIG_DFL);
244 
245 
246  std::cerr << "\n" << std::endl;
247  std::cerr << "\n" << std::endl;
248  std::cerr << "\33[31m" << "=====================================================" << std::endl;
249  std::cerr << "\33[31m" << "OpenFlipper or one of its plugins caused a Segfault." << std::endl;
250  std::cerr << "\33[31m" << "This should not happen,... Sorry :-(" << std::endl;
251  std::cerr << "\33[31m" << "=====================================================" << std::endl;
252  std::cerr << "\n" << std::endl;
253 
254  // Linux Handler
255 #ifndef NO_EXECINFO
256  std::cerr << "\33[0m" << "Trying a backtrace to show what happened last: " << std::endl;
257  backtrace();
258 
259  std::cerr << "\n" << std::endl;
260  std::cerr << "Backtrace completed, trying to abort now ..." << std::endl;
261 #endif
262 
263  // Windows handler via StackWalker
264 #ifdef WIN32
265  StackWalkerToConsole sw;
266  sw.ShowCallstack();
267 #endif
268 
269 
270  std::cerr << "Trying to get additional information (This might fail if the memory is corrupted)." << std::endl;
271 
272  if (OpenFlipper::Options::gui()) {
273  for ( unsigned int i = 0 ; i < 4 ; ++i) {
274  std::cerr << "DrawMode Viewer "<< i << " " << PluginFunctions::drawMode(i).description() << std::endl;
275  }
276  }
277 
278  std::abort();
279 }
280 
281 enum CommandLineParseResult
282 {
283  CommandLineOk,
284  CommandLineError,
285  CommandLineVersionRequested,
286  CommandLineHelpRequested
287 };
288 
289 
290 bool openPolyMeshes = false;
291 bool remoteControl = false;
292 
293 // Parse all options
294 CommandLineParseResult parseCommandLine(QCommandLineParser &parser, QString *errorMessage) {
295 
296  #ifndef WIN32
297  #ifndef __APPLE__
298  //workaround for bug with stereo mode on Qt5.7.0 and Qt5.7.1 on Linux
299  int QtVersionMajor, QtVersionMinor, QtVersionPatch;
300  if(sscanf(qVersion(),"%1d.%1d.%1d",&QtVersionMajor, &QtVersionMinor, &QtVersionPatch) == 3)
301  {
302  if(QtVersionMajor == 5 && QtVersionMinor >= 7)
303  {
304  if(QtVersionPatch < 2)
305  {
306  std::cerr << "The used Qt Version does not support stereo mode. Disabling stereo mode." << std::endl;
307  OpenFlipper::Options::stereo(false);
308  }
309  else
310  std::cerr << "Stereo Mode has not been tested for the used Qt Version." << std::endl;
311  }
312  }
313  #endif
314  #endif
315 
316 
317  parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
318 
319 
320  QCommandLineOption debugOption(QStringList() << "d" << "debug",QCoreApplication::translate("main", "Enable debugging mode"));
321  parser.addOption(debugOption);
322 
323  QCommandLineOption stereoOption("disable-stereo",QCoreApplication::translate("main", "Disable stereo mode"));
324  parser.addOption(stereoOption);
325 
326  QCommandLineOption batchOption(QStringList() << "b" << "batch",QCoreApplication::translate("main", "Batch mode, you have to provide a script for execution"));
327  parser.addOption(batchOption);
328 
329  QCommandLineOption logConsoleOption(QStringList() << "c" << "log-to-console",QCoreApplication::translate("main", "Write logger window contents to console"));
330  parser.addOption(logConsoleOption);
331 
332  QCommandLineOption remoteControlOption("remote-control",QCoreApplication::translate("main", "Batch mode accepting remote connections"));
333  parser.addOption(remoteControlOption);
334 
335  QCommandLineOption fulscreenOption(QStringList() << "f" << "fullscreen",QCoreApplication::translate("main", "Start in fullscreen mode"));
336  parser.addOption(fulscreenOption);
337 
338  QCommandLineOption hideLoggerOption(QStringList() << "l" << "hide-logger",QCoreApplication::translate("main", "Start with hidden log window"));
339  parser.addOption(hideLoggerOption);
340 
341  QCommandLineOption hideToolboxOption(QStringList() << "t" << "hide-toolbox",QCoreApplication::translate("main", "Start with hidden toolbox"));
342  parser.addOption(hideToolboxOption);
343 
344  QCommandLineOption noSplashOption("no-splash",QCoreApplication::translate("main", "Hide splash screen"));
345  parser.addOption(noSplashOption);
346 
347  QCommandLineOption polyMeshOption("p",QCoreApplication::translate("main", "Open files as PolyMeshes"));
348  parser.addOption(polyMeshOption);
349 
350  QCommandLineOption remotePortOption("remote-port",QCoreApplication::translate("main", "Remote port"),"portnumber");
351  parser.addOption(remotePortOption);
352 
353  QCommandLineOption coreProfileOption("core-profile",QCoreApplication::translate("main", "OpenGL Core Profile Mode"));
354  parser.addOption(coreProfileOption);
355 
356  QCommandLineOption glVersionOption("glVersion",QCoreApplication::translate("main","Request OpenGL version <major>.<minor> "),QCoreApplication::translate("main","< 1.0 | 1.1 | ... | 4.6 >"));
357  parser.addOption(glVersionOption);
358 
359  QCommandLineOption samplesOption("samples",QCoreApplication::translate("main","Overwrite multisampling sample count"),QCoreApplication::translate("main","< 0 | 1 | 2 | ... | 16 >"));
360  parser.addOption(samplesOption);
361 
362  QCommandLineOption glStereoOption("glStereo",QCoreApplication::translate("main","Overwrite OpenGL Stereo setting"),QCoreApplication::translate("main","< true | false >"));
363  parser.addOption(glStereoOption);
364 
365  QCommandLineOption profileOption("profile",QCoreApplication::translate("main","Request OpenGL context profile <profile> with profile set as compat or core"),QCoreApplication::translate("main","< compat | core >"));
366  parser.addOption(profileOption);
367 
368  QCommandLineOption pluginOptionsOption(QStringList() << "o" << "pluginoptions",QCoreApplication::translate("main", "Pass options to plugins"), "key1=value1;key2=value2;...");
369  parser.addOption(pluginOptionsOption);
370 
371  const QCommandLineOption helpOption = parser.addHelpOption();
372  const QCommandLineOption versionOption = parser.addVersionOption();
373 
374 
375  // Now parse the command line
376  if (!parser.parse(QCoreApplication::arguments())) {
377  *errorMessage = parser.errorText();
378  return CommandLineError;
379  }
380 
381  if (parser.isSet(helpOption))
382  return CommandLineHelpRequested;
383 
384  if (parser.isSet(versionOption))
385  return CommandLineVersionRequested;
386 
387  if (parser.isSet(debugOption)) {
388  OpenFlipper::Options::debug(true);
389  }
390 
391  if (parser.isSet(stereoOption)) {
392  OpenFlipper::Options::stereo(false);
393  }
394 
395  if (parser.isSet(batchOption)) {
396  OpenFlipper::Options::nogui(true);
397  }
398 
399  if (parser.isSet(logConsoleOption)) {
400  OpenFlipper::Options::logToConsole(true);
401  }
402 
403  if (parser.isSet(remoteControlOption)) {
404  OpenFlipper::Options::remoteControl(true);
405  }
406 
407  if (parser.isSet(fulscreenOption)) {
408  OpenFlipperSettings().setValue("Core/Gui/fullscreen",true);
409  }
410 
411  if (parser.isSet(hideLoggerOption)) {
412  OpenFlipper::Options::loggerState(OpenFlipper::Options::Hidden);
413  }
414 
415  if (parser.isSet(hideToolboxOption)) {
416  OpenFlipperSettings().setValue("Core/Gui/ToolBoxes/hidden",true);
417  }
418 
419  if (parser.isSet(noSplashOption)) {
420  OpenFlipperSettings().setValue("Core/Gui/splash",false);
421  }
422 
423  if (parser.isSet(polyMeshOption)) {
424  openPolyMeshes = true;
425  }
426 
427  if (parser.isSet(remotePortOption)) {
428  const QString port = parser.value("remote-port");
429  std::cerr << "Got port option : " << port.toStdString() << std::endl;
430  OpenFlipper::Options::remoteControl(port.toInt());
431  }
432  if(parser.isSet("samples"))
433  OpenFlipper::Options::samples(parser.value("samples").toInt(),true);
434  if(parser.isSet("glVersion"))
435  {
436  QStringList values = parser.value("glVersion").split(".");
437  QPair<int,int> version(
438  values[0].toInt(),
439  values[1].toInt());
440  OpenFlipper::Options::glVersion(version,true);
441  }
442 
443  if(parser.isSet("glStereo"))
444  OpenFlipper::Options::glStereo(parser.value("glStereo")=="true");
445 
446  if(parser.value(profileOption)=="core")
447  {
448  OpenFlipper::Options::coreProfile(true, true);
449  }
450  else
451  {
452  if(parser.value(profileOption)=="compat")
453  {
454  OpenFlipper::Options::coreProfile(false, true);
455  }
456  }
457  if(parser.isSet(coreProfileOption)) {
458  OpenFlipper::Options::coreProfile(true, true);
459  }
460  if(parser.isSet(pluginOptionsOption))
461  {
462  QStringList poptions = parser.value(pluginOptionsOption).split(";");
463  QVector<QPair<QString, QString>> pcloptions;
464  for(auto s : poptions)
465  {
466  auto kvp = s.split("=");
467 
468  // Only consider terms of the kind "key=value"
469  if(kvp.size() != 2u)
470  continue;
471 
472  auto key = kvp[0];
473  auto value = kvp[1];
474  pcloptions.push_back({key, value});
475  }
477  }
478 
479  return CommandLineOk;
480 }
481 
482 
483 namespace
484 {
485 
486 // Print human-readable GL profile strings
487 std::string profileToString(QSurfaceFormat::OpenGLContextProfile _profile)
488 {
489  if(_profile == QSurfaceFormat::CompatibilityProfile)
490  return "CompatibilityProfile";
491 
492  if(_profile == QSurfaceFormat::CoreProfile)
493  return "CoreProfile";
494 
495  if(_profile == QSurfaceFormat::NoProfile)
496  return "NoProfile";
497 
498  return "[Unknown]";
499 }
500 
501 // Check whether a specific context request can be fulfilled
502 // Can also return the format of the actually created context
503 bool verifySpecificContextFormat(QSurfaceFormat format, QSurfaceFormat* resultingFormat = nullptr)
504 {
505  // All created surfaces try to obey the given format
506  QSurfaceFormat::setDefaultFormat(format);
507 
508  // We need a temporary qApp to create a surface and test the current context
509  int tempArgC = 0;
510  QApplication tempApp(tempArgC, nullptr);
511  QOffscreenSurface *surface = new QOffscreenSurface();
512  surface->create();
513 
514  auto shareContext = QOpenGLContext::globalShareContext();
515  if(!shareContext)
516  {
517  std::cerr << "Error: Apparently no GL context was created!" << std::endl;
518  return false;
519  }
520 
521  // Make the globally shared OpenGLContext current
522  shareContext->makeCurrent(surface);
523 
524  // The opengl surface properties that have actually been applied
525  // (does not necessarily match the requested properties)
526  auto resultFormat = QOpenGLContext::globalShareContext()->format();
527 
528  // Return the format of the actually created context (may be identical to the requested one)
529  if(resultingFormat != nullptr)
530  *resultingFormat = resultFormat;
531 
532  auto curVersion = resultFormat.version();
533 
534  // Human-readable name of requested profile
535  auto reqProfileString = profileToString(format.profile());
536 
537  // Human-readable name of current profile
538  auto curProfileString = profileToString(resultFormat.profile());
539 
540 
541  // Example: OpenGL Version 4.6 -> 46
542  auto reqVersionInt = format.version().first * 10 + format.version().second;
543  auto curVersionInt = curVersion.first * 10 + curVersion.second;
544 
545 
546 
547  // We set the following guidelines:
548  // 1. Whenever the actually received GL version is < than the requested one, the context is not the one requested
549  // 2. If the received profile is not the requested one, the context is not the one requested
550 
551  if(curVersionInt < 32 && resultFormat.profile() == QSurfaceFormat::CoreProfile)
552  {
553  std::cerr << "Warning: Got an OpenGL core context with OpengGL version < 3.2 (" << curVersion.first << "." << curVersion.second << ")! This should not be possible." << std::endl;
554  return false;
555  }
556 
557  // Check whether the conditions above are met.
558  // If not, print some error to the console
559  if(curVersionInt < reqVersionInt ||
560  format.profile()!= resultFormat.profile() )
561  {
562  std::cout << "[OpenGL context] Requested: "
563  << format.version().first << "." << format.version().second << " (" << reqProfileString << ")"
564  << ", Actually created: "
565  << curVersion.first << "." << curVersion.second << " (" << curProfileString << ")"
566  << std::endl;
567  return false;
568  }
569 
570  std::cout << "[OpenGL context] Successfully created OpenGL context with version " << curVersion.first << "."
571  << curVersion.second << " (" << curProfileString << ")." << std::endl;
572 
573  return true;
574 }
575 
576 // Create a QSurfaceFormat from the most important properties like version and profile
577 QSurfaceFormat createFormat(QSurfaceFormat::OpenGLContextProfile _profile, int _glMajor, int _glMinor, int _multisamplingSamples, bool _stereo, bool _debugContext)
578 {
579  QSurfaceFormat format;
580  format.setVersion(_glMajor, _glMinor);
581  format.setProfile(_profile);
582  format.setSamples(_multisamplingSamples);
583  format.setStereo(_stereo);
584  if(_profile != QSurfaceFormat::CoreProfile)
585  format.setOption(QSurfaceFormat::DeprecatedFunctions);
586  if (_debugContext)
587  format.setOption(format.options() | QSurfaceFormat::DebugContext);
588 
589  return format;
590 }
591 
592 // This method tries to find the best possible OpenGL context format in the following order:
593 // 1. The profile/format requested via the settings
594 // 2. A 4.4 compatibility context (should contain all relevant GL functions)
595 // 3. A 3.2 core context (best choice e.g. on MacOS)
596 // 4. Return whatever context was applied instead of the requested ones
597 QSurfaceFormat getContextFormat()
598 {
599  auto reqProfile = OpenFlipper::Options::coreProfile() ? QSurfaceFormat::CoreProfile : QSurfaceFormat::CompatibilityProfile;
600  QPair<int,int> reqVersion = OpenFlipper::Options::glVersion();
601  auto reqSamples = OpenFlipper::Options::samples();
602  auto reqStereo = OpenFlipper::Options::glStereo();
603  bool debugContext = OpenFlipper::Options::debug();
604 
605 
606 
607  /*
608  // Debug: test all (possible and impossible) OpenGL versions and profiles and exit
609  for(int majo = 1; majo < 5; ++majo)
610  for(int mino = 0; mino < 10; ++mino)
611  {
612  std::cout << "========== " << majo << "." << mino << " ==========="<<std::endl;
613  verifySpecificContextFormat(createFormat(QSurfaceFormat::CoreProfile, majo, mino, reqSamples, reqStereo, debugContext));
614  verifySpecificContextFormat(createFormat(QSurfaceFormat::CompatibilityProfile, majo, mino, reqSamples, reqStereo, debugContext));
615  verifySpecificContextFormat(createFormat(QSurfaceFormat::NoProfile, majo, mino, reqSamples, reqStereo, debugContext));
616  std::cout << "================================" << std::endl;
617  std::cout << std::endl;
618  }
619  exit(0);
620  */
621 
622 
623 
624  QSurfaceFormat resultFormat;
625 
626 
627  std::cout << "[OpenGL context] Trying to create a " << reqVersion.first << "." << reqVersion.second << " " << profileToString(reqProfile) << " context (default from settings)..." << std::endl;
628  bool success = verifySpecificContextFormat(createFormat(reqProfile, reqVersion.first, reqVersion.second, reqSamples, reqStereo, debugContext), &resultFormat);
629 
630  // If that did not work...
631  if(!success)
632  {
633  std::cout << "[OpenGL context] Trying to create a 4.4 compat context..." << std::endl;
634  success = verifySpecificContextFormat(createFormat(QSurfaceFormat::CompatibilityProfile, 4, 4, reqSamples, reqStereo, debugContext), &resultFormat);
635 
636  if(!success)
637  {
638  std::cout << "[OpenGL context] Trying to create a 3.2 core context..." << std::endl;
639  success = verifySpecificContextFormat(createFormat(QSurfaceFormat::CoreProfile, 3, 2, reqSamples, reqStereo, debugContext), &resultFormat);
640  if(!success)
641  {
642  std::cerr << "[OpenGL context] Warning: Could not create any of the requested GL contexts." << std::endl;
643  std::cerr << "[OpenGL context] The following context (proposed by the graphics driver) will be created:" << std::endl;
644  std::cerr << "[OpenGL context] Profile: " << profileToString(resultFormat.profile()) << ", Version: "
645  << resultFormat.version().first << "." << resultFormat.version().second << std::endl;
646  std::cerr << "[OpenGL context] Please consider setting a supported OpenGL version and profile in the Options dialog." << std::endl;
647  }
648  }
649  }
650 
651  return resultFormat;
652 }
653 
654 }
655 
656 int main(int argc, char **argv)
657 {
658 
659  // Remove -psn_0_xxxxx argument which is automatically
660  // attached by MacOSX
661  for (int i = 0; i < argc; i++) {
662  if(strlen(argv[i]) > 4) {
663  if( ( (argv[i])[0] == '-' ) &&
664  ( (argv[i])[1] == 'p' ) &&
665  ( (argv[i])[2] == 's' ) &&
666  ( (argv[i])[3] == 'n' ) ) {
667  argc--;
668  argv[i] = (char *)"";
669  }
670  }
671  }
672 
673  OpenFlipper::Options::argc(&argc);
674  OpenFlipper::Options::argv(&argv);
675 
676  // Set organization and application names
677  QCoreApplication::setOrganizationName("VCI");
678  QCoreApplication::setApplicationName(TOSTRING(PRODUCT_STRING));
679  QCoreApplication::setApplicationVersion(OpenFlipper::Options::coreVersion());
680 
681  // initialize a core application to check for commandline parameters
682  QCoreApplication* coreApp = new QCoreApplication(argc, argv);
683 
684  OpenFlipper::Options::initializeSettings();
685 
686  QCommandLineParser parser;
687  QString errorMessage;
688 
689  // parse command line options
690  switch (parseCommandLine(parser, &errorMessage)) {
691  case CommandLineOk:
692  break;
693  case CommandLineError:
694  fputs(qPrintable(errorMessage), stderr);
695  fputs("\n\n", stderr);
696  fputs(qPrintable(parser.helpText()), stderr);
697  return 1;
698  case CommandLineVersionRequested:
699  printf("%s %s\n", qPrintable(QCoreApplication::applicationName()),
700  qPrintable(QCoreApplication::applicationVersion()));
701  return 0;
702  case CommandLineHelpRequested:
703  parser.showHelp();
704  Q_UNREACHABLE();
705  }
706 
707  // only one application is allowed so delete the core application
708  // once cmdline parsing is done
709  delete coreApp;
710 
711 
712 
713 #ifdef WIN32
714  //attach a console if necessary
715  attachConsole();
716 #endif
717 
718 #ifndef NO_CATCH_SIGSEGV
719  // Set a handler for segfaults
720  std::signal(SIGSEGV, segfaultHandling);
721 #endif
722 
723  OpenFlipper::Options::windowTitle(TOSTRING(PRODUCT_STRING)" v" + OpenFlipper::Options::coreVersion());
724 
725  if ( !OpenFlipper::Options::nogui() ) {
726 
727  // OpenGL check
728  QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
729  QApplication::setColorSpec( QApplication::CustomColor );
730 
731  // Try creating a valid OpenGL context
732  /******************************/
733 
734  // Get a valid context format
735  QSurfaceFormat resultFormat = getContextFormat();
736 
737  // Set temporary(!) OpenGL settings
738  OpenFlipper::Options::samples(resultFormat.samples(), true);
739  OpenFlipper::Options::glStereo(resultFormat.stereo(), true);
740  OpenFlipper::Options::glVersion(resultFormat.version(), true);
741  OpenFlipper::Options::coreProfile(resultFormat.profile() == QSurfaceFormat::CoreProfile, true);
742 
743  // Create the actual context
744  QSurfaceFormat::setDefaultFormat(resultFormat);
745  QApplication app(argc, argv);
746  QOffscreenSurface *surface = new QOffscreenSurface();
747  surface->create();
748 
749  // Make the globally shared OpenGLContext current
750  QOpenGLContext::globalShareContext()->makeCurrent(surface);
751  /******************************/
752 
753 
754  // Check whether there is OpenGL support. If not, return.
755  if ( !QGLFormat::hasOpenGL() ) {
756  std::cerr << "This system has no OpenGL support.\n";
757  return -1;
758  }
759 
760  // create core ( this also reads the ini files )
761  Core * w = new Core( );
762 #ifdef PYTHON_ENABLED
763  setCorePointer(w);
764 #endif
765 
766  QString tLang = OpenFlipperSettings().value("Core/Language/Translation","en_US").toString();
767 
768  if (tLang == "locale")
769  tLang = QLocale::system().name();
770 
771  // Install translator for qt internals
772  QTranslator qtTranslator;
773  qtTranslator.load("qt_" + tLang, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
774  app.installTranslator(&qtTranslator);
775 
776  // install translator for Core Application
777  QString translationDir = OpenFlipper::Options::translationsDirStr() + QDir::separator();
778  QDir dir(translationDir);
779  dir.setFilter(QDir::Files);
780 
781  QFileInfoList list = dir.entryInfoList();
782 
783  for (int i = 0; i < list.size(); ++i) {
784  QFileInfo fileInfo = list.at(i);
785 
786  if ( fileInfo.baseName().contains(tLang) ){
787  QTranslator* myAppTranslator = new QTranslator();
788 
789  if ( myAppTranslator->load( fileInfo.filePath() ) )
790  {
791  app.installTranslator(myAppTranslator);
792  } else
793  {
794  delete myAppTranslator;
795  }
796  }
797  }
798 
799  #ifndef __APPLE__
800  initGlew();
801  #endif
802 
803  // After setting all Options from command line, build the real gui
804  w->init();
805 
806  const QStringList positionalArguments = parser.positionalArguments();
807 
808  for ( auto file: positionalArguments ) {
809  w->commandLineOpen(file, openPolyMeshes);
810  }
811 
812  return app.exec();
813 
814  } else {
815 
816  QCoreApplication app(argc,argv);
817 
818  // create widget ( this also reads the ini files )
819  Core * w = new Core( );
820 
821 
822 #ifdef PYTHON_ENABLED
823  setCorePointer(w);
824 #endif
825 
826  // After setting all Options from command line, build the real gui
827  w->init();
828 
829  const QStringList positionalArguments = parser.positionalArguments();
830 
831  for ( auto file: positionalArguments ) {
832  w->commandLineOpen(file, openPolyMeshes);
833  }
834 
835  return app.exec();
836  }
837 
838  return 0;
839 }
Definition: Core.hh:132
void commandLineOpen(const QString &_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.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
#define TOSTRING(x)
QSettings object containing all program settings of OpenFlipper.
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.
DLLEXPORT void setPluginCommandLineOptions(QVector< QPair< QString, QString >> const &_pluginCommandLineOptions)
void init()
Second initialization stage.
Definition: Core.cc:192