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)
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  auto key = kvp[0];
468  auto value = kvp[1];
469  pcloptions.push_back({key, value});
470  }
472  }
473 
474  return CommandLineOk;
475 }
476 
477 
478 namespace
479 {
480 
481 // Print human-readable GL profile strings
482 std::string profileToString(QSurfaceFormat::OpenGLContextProfile _profile)
483 {
484  if(_profile == QSurfaceFormat::CompatibilityProfile)
485  return "CompatibilityProfile";
486 
487  if(_profile == QSurfaceFormat::CoreProfile)
488  return "CoreProfile";
489 
490  if(_profile == QSurfaceFormat::NoProfile)
491  return "NoProfile";
492 
493  return "[Unknown]";
494 }
495 
496 // Check whether a specific context request can be fulfilled
497 // Can also return the format of the actually created context
498 bool verifySpecificContextFormat(QSurfaceFormat format, QSurfaceFormat* resultingFormat = nullptr)
499 {
500  // All created surfaces try to obey the given format
501  QSurfaceFormat::setDefaultFormat(format);
502 
503  // We need a temporary qApp to create a surface and test the current context
504  int tempArgC = 0;
505  QApplication tempApp(tempArgC, nullptr);
506  QOffscreenSurface *surface = new QOffscreenSurface();
507  surface->create();
508 
509  auto shareContext = QOpenGLContext::globalShareContext();
510  if(!shareContext)
511  {
512  std::cerr << "Error: Apparently no GL context was created!" << std::endl;
513  return false;
514  }
515 
516  // Make the globally shared OpenGLContext current
517  shareContext->makeCurrent(surface);
518 
519  // The opengl surface properties that have actually been applied
520  // (does not necessarily match the requested properties)
521  auto resultFormat = QOpenGLContext::globalShareContext()->format();
522 
523  // Return the format of the actually created context (may be identical to the requested one)
524  if(resultingFormat != nullptr)
525  *resultingFormat = resultFormat;
526 
527  auto curVersion = resultFormat.version();
528 
529  // Human-readable name of requested profile
530  auto reqProfileString = profileToString(format.profile());
531 
532  // Human-readable name of current profile
533  auto curProfileString = profileToString(resultFormat.profile());
534 
535 
536  // Example: OpenGL Version 4.6 -> 46
537  auto reqVersionInt = format.version().first * 10 + format.version().second;
538  auto curVersionInt = curVersion.first * 10 + curVersion.second;
539 
540 
541 
542  // We set the following guidelines:
543  // 1. Whenever the actually received GL version is < than the requested one, the context is not the one requested
544  // 2. If the received profile is not the requested one, the context is not the one requested
545 
546  if(curVersionInt < 32 && resultFormat.profile() == QSurfaceFormat::CoreProfile)
547  {
548  std::cerr << "Warning: Got an OpenGL core context with OpengGL version < 3.2 (" << curVersion.first << "." << curVersion.second << ")! This should not be possible." << std::endl;
549  return false;
550  }
551 
552  // Check whether the conditions above are met.
553  // If not, print some error to the console
554  if(curVersionInt < reqVersionInt ||
555  format.profile()!= resultFormat.profile() )
556  {
557  std::cout << "[OpenGL context] Requested: "
558  << format.version().first << "." << format.version().second << " (" << reqProfileString << ")"
559  << ", Actually created: "
560  << curVersion.first << "." << curVersion.second << " (" << curProfileString << ")"
561  << std::endl;
562  return false;
563  }
564 
565  std::cout << "[OpenGL context] Successfully created OpenGL context with version " << curVersion.first << "."
566  << curVersion.second << " (" << curProfileString << ")." << std::endl;
567 
568  return true;
569 }
570 
571 // Create a QSurfaceFormat from the most important properties like version and profile
572 QSurfaceFormat createFormat(QSurfaceFormat::OpenGLContextProfile _profile, int _glMajor, int _glMinor, int _multisamplingSamples, bool _stereo, bool _debugContext)
573 {
574  QSurfaceFormat format;
575  format.setVersion(_glMajor, _glMinor);
576  format.setProfile(_profile);
577  format.setSamples(_multisamplingSamples);
578  format.setStereo(_stereo);
579  if(_profile != QSurfaceFormat::CoreProfile)
580  format.setOption(QSurfaceFormat::DeprecatedFunctions);
581  if (_debugContext)
582  format.setOption(format.options() | QSurfaceFormat::DebugContext);
583 
584  return format;
585 }
586 
587 // This method tries to find the best possible OpenGL context format in the following order:
588 // 1. The profile/format requested via the settings
589 // 2. A 4.4 compatibility context (should contain all relevant GL functions)
590 // 3. A 3.2 core context (best choice e.g. on MacOS)
591 // 4. Return whatever context was applied instead of the requested ones
592 QSurfaceFormat getContextFormat()
593 {
594  auto reqProfile = OpenFlipper::Options::coreProfile() ? QSurfaceFormat::CoreProfile : QSurfaceFormat::CompatibilityProfile;
595  QPair<int,int> reqVersion = OpenFlipper::Options::glVersion();
596  auto reqSamples = OpenFlipper::Options::samples();
597  auto reqStereo = OpenFlipper::Options::glStereo();
598  bool debugContext = OpenFlipper::Options::debug();
599 
600 
601 
602  /*
603  // Debug: test all (possible and impossible) OpenGL versions and profiles and exit
604  for(int majo = 1; majo < 5; ++majo)
605  for(int mino = 0; mino < 10; ++mino)
606  {
607  std::cout << "========== " << majo << "." << mino << " ==========="<<std::endl;
608  verifySpecificContextFormat(createFormat(QSurfaceFormat::CoreProfile, majo, mino, reqSamples, reqStereo, debugContext));
609  verifySpecificContextFormat(createFormat(QSurfaceFormat::CompatibilityProfile, majo, mino, reqSamples, reqStereo, debugContext));
610  verifySpecificContextFormat(createFormat(QSurfaceFormat::NoProfile, majo, mino, reqSamples, reqStereo, debugContext));
611  std::cout << "================================" << std::endl;
612  std::cout << std::endl;
613  }
614  exit(0);
615  */
616 
617 
618 
619  QSurfaceFormat resultFormat;
620 
621 
622  std::cout << "[OpenGL context] Trying to create a " << reqVersion.first << "." << reqVersion.second << " " << profileToString(reqProfile) << " context (default from settings)..." << std::endl;
623  bool success = verifySpecificContextFormat(createFormat(reqProfile, reqVersion.first, reqVersion.second, reqSamples, reqStereo, debugContext), &resultFormat);
624 
625  // If that did not work...
626  if(!success)
627  {
628  std::cout << "[OpenGL context] Trying to create a 4.4 compat context..." << std::endl;
629  success = verifySpecificContextFormat(createFormat(QSurfaceFormat::CompatibilityProfile, 4, 4, reqSamples, reqStereo, debugContext), &resultFormat);
630 
631  if(!success)
632  {
633  std::cout << "[OpenGL context] Trying to create a 3.2 core context..." << std::endl;
634  success = verifySpecificContextFormat(createFormat(QSurfaceFormat::CoreProfile, 3, 2, reqSamples, reqStereo, debugContext), &resultFormat);
635  if(!success)
636  {
637  std::cerr << "[OpenGL context] Warning: Could not create any of the requested GL contexts." << std::endl;
638  std::cerr << "[OpenGL context] The following context (proposed by the graphics driver) will be created:" << std::endl;
639  std::cerr << "[OpenGL context] Profile: " << profileToString(resultFormat.profile()) << ", Version: "
640  << resultFormat.version().first << "." << resultFormat.version().second << std::endl;
641  std::cerr << "[OpenGL context] Please consider setting a supported OpenGL version and profile in the Options dialog." << std::endl;
642  }
643  }
644  }
645 
646  return resultFormat;
647 }
648 
649 }
650 
651 int main(int argc, char **argv)
652 {
653 
654  // Remove -psn_0_xxxxx argument which is automatically
655  // attached by MacOSX
656  for (int i = 0; i < argc; i++) {
657  if(strlen(argv[i]) > 4) {
658  if( ( (argv[i])[0] == '-' ) &&
659  ( (argv[i])[1] == 'p' ) &&
660  ( (argv[i])[2] == 's' ) &&
661  ( (argv[i])[3] == 'n' ) ) {
662  argc--;
663  argv[i] = (char *)"";
664  }
665  }
666  }
667 
668  OpenFlipper::Options::argc(&argc);
669  OpenFlipper::Options::argv(&argv);
670 
671  // Set organization and application names
672  QCoreApplication::setOrganizationName("VCI");
673  QCoreApplication::setApplicationName(TOSTRING(PRODUCT_STRING));
674  QCoreApplication::setApplicationVersion(OpenFlipper::Options::coreVersion());
675 
676  // initialize a core application to check for commandline parameters
677  QCoreApplication* coreApp = new QCoreApplication(argc, argv);
678 
679  OpenFlipper::Options::initializeSettings();
680 
681  QCommandLineParser parser;
682  QString errorMessage;
683 
684  // parse command line options
685  switch (parseCommandLine(parser, &errorMessage)) {
686  case CommandLineOk:
687  break;
688  case CommandLineError:
689  fputs(qPrintable(errorMessage), stderr);
690  fputs("\n\n", stderr);
691  fputs(qPrintable(parser.helpText()), stderr);
692  return 1;
693  case CommandLineVersionRequested:
694  printf("%s %s\n", qPrintable(QCoreApplication::applicationName()),
695  qPrintable(QCoreApplication::applicationVersion()));
696  return 0;
697  case CommandLineHelpRequested:
698  parser.showHelp();
699  Q_UNREACHABLE();
700  }
701 
702  // only one application is allowed so delete the core application
703  // once cmdline parsing is done
704  delete coreApp;
705 
706 
707 
708 #ifdef WIN32
709  //attach a console if necessary
710  attachConsole();
711 #endif
712 
713 #ifndef NO_CATCH_SIGSEGV
714  // Set a handler for segfaults
715  std::signal(SIGSEGV, segfaultHandling);
716 #endif
717 
718  OpenFlipper::Options::windowTitle(TOSTRING(PRODUCT_STRING)" v" + OpenFlipper::Options::coreVersion());
719 
720  if ( !OpenFlipper::Options::nogui() ) {
721 
722  // OpenGL check
723  QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
724  QApplication::setColorSpec( QApplication::CustomColor );
725 
726  // Try creating a valid OpenGL context
727  /******************************/
728 
729  // Get a valid context format
730  QSurfaceFormat resultFormat = getContextFormat();
731 
732  // Set temporary(!) OpenGL settings
733  OpenFlipper::Options::samples(resultFormat.samples(), true);
734  OpenFlipper::Options::glStereo(resultFormat.stereo(), true);
735  OpenFlipper::Options::glVersion(resultFormat.version(), true);
736  OpenFlipper::Options::coreProfile(resultFormat.profile() == QSurfaceFormat::CoreProfile, true);
737 
738  // Create the actual context
739  QSurfaceFormat::setDefaultFormat(resultFormat);
740  QApplication app(argc, argv);
741  QOffscreenSurface *surface = new QOffscreenSurface();
742  surface->create();
743 
744  // Make the globally shared OpenGLContext current
745  QOpenGLContext::globalShareContext()->makeCurrent(surface);
746  /******************************/
747 
748 
749  // Check whether there is OpenGL support. If not, return.
750  if ( !QGLFormat::hasOpenGL() ) {
751  std::cerr << "This system has no OpenGL support.\n";
752  return -1;
753  }
754 
755  // create core ( this also reads the ini files )
756  Core * w = new Core( );
757 #ifdef PYTHON_ENABLED
758  setCorePointer(w);
759 #endif
760 
761  QString tLang = OpenFlipperSettings().value("Core/Language/Translation","en_US").toString();
762 
763  if (tLang == "locale")
764  tLang = QLocale::system().name();
765 
766  // Install translator for qt internals
767  QTranslator qtTranslator;
768  qtTranslator.load("qt_" + tLang, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
769  app.installTranslator(&qtTranslator);
770 
771  // install translator for Core Application
772  QString translationDir = OpenFlipper::Options::translationsDirStr() + QDir::separator();
773  QDir dir(translationDir);
774  dir.setFilter(QDir::Files);
775 
776  QFileInfoList list = dir.entryInfoList();
777 
778  for (int i = 0; i < list.size(); ++i) {
779  QFileInfo fileInfo = list.at(i);
780 
781  if ( fileInfo.baseName().contains(tLang) ){
782  QTranslator* myAppTranslator = new QTranslator();
783 
784  if ( myAppTranslator->load( fileInfo.filePath() ) )
785  {
786  app.installTranslator(myAppTranslator);
787  } else
788  {
789  delete myAppTranslator;
790  }
791  }
792  }
793 
794  #ifndef __APPLE__
795  initGlew();
796  #endif
797 
798  // After setting all Options from command line, build the real gui
799  w->init();
800 
801  const QStringList positionalArguments = parser.positionalArguments();
802 
803  for ( auto file: positionalArguments ) {
804  w->commandLineOpen(file, openPolyMeshes);
805  }
806 
807  return app.exec();
808 
809  } else {
810 
811  QCoreApplication app(argc,argv);
812 
813  // create widget ( this also reads the ini files )
814  Core * w = new Core( );
815 
816 
817 #ifdef PYTHON_ENABLED
818  setCorePointer(w);
819 #endif
820 
821  // After setting all Options from command line, build the real gui
822  w->init();
823 
824  const QStringList positionalArguments = parser.positionalArguments();
825 
826  for ( auto file: positionalArguments ) {
827  w->commandLineOpen(file, openPolyMeshes);
828  }
829 
830  return app.exec();
831  }
832 
833  return 0;
834 }
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
Definition: Core.hh:132
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
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.
DLLEXPORT void setPluginCommandLineOptions(QVector< QPair< QString, QString >> const &_pluginCommandLineOptions)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
#define TOSTRING(x)
QSettings object containing all program settings of OpenFlipper.
void init()
Second initialization stage.
Definition: Core.cc:188