Radium Engine  1.5.20
Loading...
Searching...
No Matches
BaseApplication.cpp
1#include <Gui/AboutDialog/AboutDialog.hpp>
2#include <Gui/BaseApplication.hpp>
3#include <Gui/MainWindowInterface.hpp>
4#include <Gui/Viewer/Viewer.hpp>
5
6#include <Core/CoreMacros.hpp>
7#include <Core/Resources/Resources.hpp>
8#include <Core/Tasks/Task.hpp>
9#include <Core/Tasks/TaskQueue.hpp>
10#include <Core/Types.hpp>
11#include <Core/Utils/Color.hpp>
12#include <Core/Utils/Log.hpp>
13#include <Core/Utils/StringUtils.hpp>
14#include <Core/Utils/Version.hpp>
15
16#include <Engine/Data/Texture.hpp>
17#include <Engine/Data/TextureManager.hpp>
18#include <Engine/RadiumEngine.hpp>
19#include <Engine/Rendering/RenderObject.hpp>
20#include <Engine/Scene/CameraComponent.hpp>
21#include <Engine/Scene/EntityManager.hpp>
22#include <Engine/Scene/GeometrySystem.hpp>
23#include <Engine/Scene/SkeletonBasedAnimationSystem.hpp>
25
26#include <PluginBase/RadiumPluginInterface.hpp>
27
28#include <IO/CameraLoader/CameraLoader.hpp>
29#ifdef IO_HAS_TINYPLY
30# include <IO/TinyPlyLoader/TinyPlyFileLoader.hpp>
31#endif
32#ifdef IO_HAS_ASSIMP
33# include <IO/AssimpLoader/AssimpFileLoader.hpp>
34#endif
35#ifdef IO_HAS_VOLUMES
36# include <IO/VolumesLoader/VolumeLoader.hpp>
37#endif
38#include <QCommandLineParser>
39#include <QDir>
40#include <QMenuBar>
41#include <QMessageBox>
42#include <QOpenGLContext>
43#include <QPluginLoader>
44#include <QTimer>
45
46// Const parameters : TODO : make config / command line options
47
48namespace Ra {
49namespace Gui {
50
51using namespace Core::Utils; // log
52using namespace Core::Asset;
53
54#ifdef GUI_IS_COMPILED_WITH_DEBUG_INFO
55static const bool expectPluginsDebug = true;
56#else
57static const bool expectPluginsDebug = false;
58#endif
59// the default priority for systems created here.
60constexpr int defaultSystemPriority = 1000;
61
63 char** argv,
64 QString applicationName,
65 QString organizationName ) :
66 QApplication( argc, argv ),
67 m_mainWindow( nullptr ),
68 m_engine( nullptr ),
69 m_taskQueue( nullptr ),
70 m_viewer( nullptr ),
71 m_frameTimer( new QTimer( this ) ),
72 m_frameCounter( 0 ),
73 m_frameCountBeforeUpdate( 60 ),
74 m_numFrames( 0 ),
75 m_maxThreads( RA_MAX_THREAD ),
76 m_realFrameRate( false ),
77 m_recordFrames( false ),
78 m_recordTimings( false ),
79 m_recordGraph( false ),
80 m_isAboutToQuit( false ) {
81 // Set application and organization names in order to ensure uniform
82 // QSettings configurations.
83 // \see http://doc.qt.io/qt-5/qsettings.html#QSettings-4
84 QCoreApplication::setOrganizationName( organizationName );
85 QCoreApplication::setApplicationName( applicationName );
86
87 m_targetFPS = 60; // Default
89 m_parser = new QCommandLineParser;
90
91 QCommandLineParser& parser { *m_parser };
92 parser.setApplicationDescription( "Radium Engine RPZ, TMTC" );
93 parser.addHelpOption();
94 parser.addVersionOption();
95
97 QCommandLineOption fpsOpt(
98 QStringList { "r", "framerate", "fps" },
99 "Control the application framerate, 0 to disable it (and run as fast as possible).",
100 "number",
101 "60" );
102 QCommandLineOption maxThreadsOpt(
103 QStringList { "m", "maxthreads", "max-threads" },
104 "Control the maximum number of threads. 0 will set to the number of cores available",
105 "number",
106 "0" );
107 QCommandLineOption numFramesOpt(
108 QStringList { "n", "numframes" }, "Run for a fixed number of frames.", "number", "0" );
109 QCommandLineOption pluginOpt( QStringList { "p", "plugins", "pluginsPath" },
110 "Set the path to the plugin dlls.",
111 "folder",
112 "Plugins" );
113 QCommandLineOption pluginLoadOpt(
114 QStringList { "l", "load", "loadPlugin" },
115 "Only load plugin with the given name (filename without the extension). If this option is "
116 "not used, all plugins in the plugins folder will be loaded. ",
117 "name" );
118 QCommandLineOption pluginIgnoreOpt( QStringList { "i", "ignore", "ignorePlugin" },
119 "Ignore plugins with the given name. If the name appears "
120 "within both load and ignore options, it will be ignored.",
121 "name" );
122 QCommandLineOption fileOpt( QStringList { "f", "file", "scene" },
123 "Open a scene file at startup.",
124 "file name",
125 "foo.bar" );
126
127 QCommandLineOption camOpt( QStringList { "c", "camera", "cam" },
128 "Open a camera file at startup",
129 "file name",
130 "foo.bar" );
131 QCommandLineOption recordOpt( QStringList { "s", "recordFrames" },
132 "Enable snapshot recording." );
133
134 QCommandLineOption datapathOpt( QStringList { "d", "data", "export" },
135 "Set the default data path and store it in the settings.",
136 "folder",
137 "./" );
139
140 parser.addOptions( { fpsOpt,
141 pluginOpt,
142 pluginLoadOpt,
143 pluginIgnoreOpt,
144 fileOpt,
145 camOpt,
146 maxThreadsOpt,
147 numFramesOpt,
148 recordOpt,
149 datapathOpt } );
150
151 if ( !parser.parse( this->arguments() ) ) {
152 LOG( logWARNING ) << "Command line parsing failed due to unsupported or missing options";
153 }
154 if ( parser.isSet( datapathOpt ) ) {
155 auto p = parser.value( datapathOpt ).toStdString();
157 QSettings settings;
158 settings.setValue( "data_path", p.c_str() );
159 }
160 else {
161 QSettings settings;
162 if ( settings.contains( "data_path" ) ) {
163 auto p = settings.value( "data_path" ).toString().toStdString();
165 }
166 }
167 if ( parser.isSet( fpsOpt ) ) m_targetFPS = parser.value( fpsOpt ).toUInt();
168 if ( parser.isSet( pluginOpt ) ) m_pluginPath = parser.value( pluginOpt ).toStdString();
169 if ( parser.isSet( numFramesOpt ) ) m_numFrames = parser.value( numFramesOpt ).toUInt();
170 if ( parser.isSet( maxThreadsOpt ) ) m_maxThreads = parser.value( maxThreadsOpt ).toUInt();
171 if ( parser.isSet( recordOpt ) ) {
172 m_recordFrames = true;
173 setContinuousUpdate( true );
174 }
175
176 {
177 std::time_t startTime = std::time( nullptr );
178 std::tm* startTm = std::localtime( &startTime );
180 ssTp << std::put_time( startTm, "%Y%m%d-%H%M%S" );
182 }
183
184 QDir().mkdir( m_exportFoldername.c_str() );
185
186 // Boilerplate print.
187 LOG( logINFO ) << "*** Radium Engine Base Application ***";
188 std::stringstream config;
189#if defined( CORE_DEBUG )
190 config << "Debug Build ";
191#else
192 config << "Release Build ";
193#endif
194#if defined( CORE_ENABLE_ASSERT )
195 config << "(with asserts) --";
196#else
197 config << " --";
198#endif
199
200#if defined( ARCH_X86 )
201 config << " 32 bits x86";
202#elif defined( ARCH_X64 )
203 config << " 64 bits x64";
204#endif
205 LOG( logINFO ) << config.str();
206
207 config.str( std::string() );
208 config << "Floating point format : ";
209#if defined( CORE_USE_DOUBLE )
210 config << "double precision";
211#else
212 config << "single precision";
213#endif
214 LOG( logINFO ) << config.str();
215
216 config.str( std::string() );
217 config << "core build: " << Version::compiler << " - " << Version::compileDate << " "
218 << Version::compileTime;
219 LOG( logINFO ) << config.str();
220
221 LOG( logINFO ) << "Git changeset: " << Version::gitChangeSet;
222
223 LOG( logINFO ) << "Qt Version: " << qVersion();
224
225 LOG( logINFO ) << "Max Thread: " << m_maxThreads;
226
227 LOG( logINFO ) << "Output data path : " << Ra::Core::Resources::getDataPath();
228
229#ifdef OS_MACOS
230 {
231 // Note on QSettings on macOS :
232 // macOS, since Maverick, cache the application settings and when changing the settings file
233 // outside of the application, one need to wait for the cache to being reloaded (reboot or
234 // wait a given duration). To force reload of QSettings, use `defaults read
235 // settingfile.plist` source :
236 // https://nethack.ch/2014/03/30/quick-tip-flush-os-x-mavericks-plist-file-cache/ That's why
237 // we display the QSettings filename here ...
238 QSettings settings;
239 LOG( logINFO ) << "Settings file : " << settings.fileName().toStdString();
240 }
241#endif
242
243 // Create the instance of the keymapping manager, before creating
244 // Qt main windows, which may throw events on Microsoft Windows
245 Gui::KeyMappingManager::createInstance();
246}
247
248void BaseApplication::initialize( const WindowFactory& factory,
249 const glbinding::Version& version ) {
250 // Create default format for Qt.
251 QSurfaceFormat format;
252 format.setVersion( version.majorVersion(), version.minorVersion() );
253 format.setProfile( QSurfaceFormat::CoreProfile );
254 format.setDepthBufferSize( 24 );
255 format.setStencilBufferSize( 8 );
256 format.setSamples( 16 );
257 format.setSwapBehavior( QSurfaceFormat::DoubleBuffer );
258 format.setSwapInterval( 0 );
259 QSurfaceFormat::setDefaultFormat( format );
260
261 // == Configure Engine and basic scene services //
262 // Create engine
263 m_engine = Engine::RadiumEngine::createInstance();
265
266 // Configure Engine basic scene services (non openGL dependant)
268
269 // == Configure OpenGL context and drawing/application window //
270 // Create main window.
271 m_mainWindow.reset( factory.createMainWindow() );
272 m_viewer = m_mainWindow->getViewer();
273 CORE_ASSERT( m_viewer != nullptr, "GUI was not initialized" );
275
276 // == Configure event management on the drawing/application window
277 // Connect the signals and allow all pending events to be processed
278 // (thus the viewer should have initialized the OpenGL context..)
280 m_mainWindow->show();
281
282 // processEvents();
283 CORE_ASSERT( m_viewer->getContext() != nullptr, "OpenGL context was not created" );
284 CORE_ASSERT( m_viewer->getContext()->isValid(), "OpenGL was not initialized" );
285
286 // == Configure Application plugins == //
287 // Initialize plugin context
288 m_pluginContext.m_engine = m_engine;
289 m_pluginContext.m_selectionManager = m_mainWindow->getSelectionManager();
290 m_pluginContext.m_timeline = m_mainWindow->getTimeline();
291 m_pluginContext.m_pickingManager = m_viewer->getPickingManager();
292 m_pluginContext.m_viewer = m_viewer;
293 m_pluginContext.m_exportDir = m_exportFoldername;
294
295 connect( &m_pluginContext,
297 this,
298 &BaseApplication::setContinuousUpdate );
299 connect(
300 &m_pluginContext, &Plugins::Context::askForUpdate, this, &BaseApplication::askForUpdate );
301
302 QCommandLineParser& parser { *m_parser };
303 // TODO at startup, only load "standard plugins". This must be extended.
304 auto pluginsPathOptional { Core::Resources::getRadiumPluginsPath() };
305 auto pluginsPath = pluginsPathOptional.value_or( "[[Default plugin path not found]]" );
306
307 // Load installed plugins plugins
308 if ( !loadPlugins(
309 pluginsPath, parser.values( "loadPlugin" ), parser.values( "ignorePlugin" ) ) ) {
310 LOG( logDEBUG ) << "No plugin found in default path " << pluginsPath;
311 }
312 // load supplemental plugins
313 {
314 QSettings settings;
315 QStringList pluginPaths = settings.value( "plugins/paths" ).value<QStringList>();
316 for ( const auto& s : pluginPaths ) {
318 s.toStdString(), parser.values( "loadPlugin" ), parser.values( "ignorePlugin" ) );
319 }
320 }
321 // == Configure bundled Radium::IO services == //
322 // Make builtin loaders the fallback if no plugins can load some file format
323#ifdef IO_HAS_TINYPLY
324 // Register before AssimpFileLoader, in order to ease override of such
325 // custom loader (first loader able to load is taking the file)
327 std::shared_ptr<FileLoaderInterface>( new IO::TinyPlyFileLoader() ) );
328#endif
330 std::shared_ptr<FileLoaderInterface>( new IO::CameraFileLoader() ) );
331#ifdef IO_HAS_ASSIMP
334#endif
335#ifdef IO_HAS_VOLUMES
337#endif
338 // Allow derived application to add custom plugins and services
340
341 // Create task queue with N-1 threads (we keep one for rendering),
342 // unless monothread CPU
343 uint numThreads =
344 std::max( m_maxThreads == 0 ? RA_MAX_THREAD : std::min( m_maxThreads, RA_MAX_THREAD ), 1u );
345 m_taskQueue = std::make_unique<Core::TaskQueue>( numThreads );
346
347 setupScene();
348 emit starting();
349
350 // Files have been required, load them.
351 if ( parser.isSet( "scene" ) ) {
352 for ( const auto& filename : parser.values( "scene" ) ) {
353 loadFile( filename );
354 }
355 }
356 // A camera has been required, load it.
357 if ( parser.isSet( "camera" ) ) {
358 if ( loadFile( parser.value( "camera" ) ) ) {
360 // loadFile call camera system handle asset loading, so cameras from the file are
361 // already loaded.
362 }
363 }
364
365 m_mainWindow->configure();
366
368
369 connect( m_frameTimer, &QTimer::timeout, this, &BaseApplication::updateRadiumFrameIfNeeded );
370 const int deltaTime( m_targetFPS == 0 ? 1 : 1000 / m_targetFPS );
371 m_frameTimer->start( deltaTime );
372}
373
375 // TODO : modify interface to allow the app to ask for specific systems registration
376 // Register the GeometrySystem converting loaded assets to meshes
378 "GeometrySystem", new Ra::Engine::Scene::GeometrySystem, defaultSystemPriority );
379 // Register the TimeSystem managing time dependant systems
380 Scalar dt = ( m_targetFPS == 0 ? 1_ra / 60_ra : 1_ra / m_targetFPS );
382 // Register the SkeletonBasedAnimationSystem converting loaded assets to
383 // skeletons and skinning data
384 m_engine->registerSystem( "SkeletonBasedAnimationSystem",
386 defaultSystemPriority );
387}
388
389void BaseApplication::addRadiumMenu() {
390 // add the "about" action
391 auto qtWnd = dynamic_cast<QMainWindow*>( m_mainWindow.get() );
392 if ( qtWnd ) {
393 auto windowMenuBar = m_mainWindow->menuBar();
394 auto mainMenu = windowMenuBar->findChild<QMenu*>( "Radium" );
395 if ( mainMenu == nullptr ) { mainMenu = windowMenuBar->addMenu( "Radium" ); }
396 auto aboutDiag = new AboutDialog( qtWnd );
397 aboutDiag->setModal( false );
398 mainMenu->addAction( "About", aboutDiag, &QDialog::show );
399 connect( aboutDiag, &AboutDialog::settings, this, &BaseApplication::editSettings );
400 connect( aboutDiag,
401 &AboutDialog::help,
402 m_mainWindow.get(),
403 &MainWindowInterface::displayHelpDialog );
404 }
405}
406
408 // initialize here the OpenGL part of the engine used by the application
410}
411
413 // Connect the signals to lambda calling virtual methods
414 // connect( m_viewer, &Gui::Viewer::requestEngineOpenGLInitialization, this,
415 // &BaseApplication::engineOpenGLInitialize );
418 } );
419 connect( m_viewer, &Gui::Viewer::glInitialized, this, &BaseApplication::initializeGl );
420
421 connect(
422 m_mainWindow.get(), &MainWindowInterface::closed, this, &BaseApplication::appNeedsToQuit );
423 connect( this, &QGuiApplication::lastWindowClosed, m_viewer, &Gui::WindowQt::cleanupGL );
424
425 connect( m_viewer, &Gui::Viewer::needUpdate, this, &BaseApplication::askForUpdate );
426}
427
428void BaseApplication::setupScene() {
429
430 using namespace Engine::Data::DrawPrimitives;
431
432 auto grid = Primitive( Engine::Scene::SystemEntity::uiCmp(),
433 Grid( Core::Vector3::Zero(),
434 Core::Vector3::UnitX(),
435 Core::Vector3::UnitZ(),
436 Core::Utils::Color::Grey( 0.6f ) ) );
437 grid->setPickable( false );
439
440 auto frame = Primitive( Engine::Scene::SystemEntity::uiCmp(),
441 Frame( Ra::Core::Transform::Identity(), 0.05f ) );
442 frame->setPickable( false );
444}
445
446bool BaseApplication::loadFile( QString path ) {
447 std::string filename = path.toLocal8Bit().data();
448 LOG( logINFO ) << "Loading file " << filename << "...";
449 bool res = m_engine->loadFile( filename );
450
451 if ( !res ) {
452 LOG( logERROR ) << "Aborting file loading !";
453
454 return false;
455 }
456
458
459 m_mainWindow->prepareDisplay();
460
461 emit loadComplete();
462 return true;
463}
464
465void BaseApplication::framesCountForStatsChanged( uint count ) {
466 m_frameCountBeforeUpdate = count;
467}
468
470 FrameTimerData timerData;
471 timerData.frameStart = Core::Utils::Clock::now();
472
473 // ----------
474 // 0. Compute time since last frame.
475 const Scalar dt =
476 m_realFrameRate ? Core::Utils::getIntervalSeconds( m_lastFrameStart, timerData.frameStart )
477 : 1.f / Scalar( m_targetFPS );
478 m_lastFrameStart = timerData.frameStart;
479
480 // ----------
481 // 1. Gather user input and dispatch it.
482 // Get picking results from last frame and forward it to the selection.
484
485 timerData.tasksStart = Core::Utils::Clock::now();
486
487 // ----------
488 // 2. Run the engine task queue.
489 m_engine->getTasks( m_taskQueue.get(), dt );
490
491 if ( m_recordGraph ) { m_taskQueue->printTaskGraph( std::cout ); }
492
493 // Run one frame of tasks
494 m_taskQueue->startTasks();
495 m_taskQueue->waitForTasks();
496 timerData.taskData = m_taskQueue->getTimerData();
497 m_taskQueue->flushTaskQueue();
498
499 timerData.tasksEnd = Core::Utils::Clock::now();
500
501 // run engine gpu tasks (need active context)
506
507 // also update gizmo manager to deal with annimation playing / reset
508 // m_viewer->getGizmoManager()->updateValues();
509
510 // update viewer internal time-dependant state
511 m_viewer->update( dt );
512
513 // ----------
514 // 3. Kickoff rendering
517
518 timerData.renderData = m_viewer->getRenderer()->getTimerData();
519
520 // ----------
521 // 4. Synchronize whatever needs synchronisation
523
524 // ----------
525 // 5. Frame end.
526 timerData.frameEnd = Core::Utils::Clock::now();
527 timerData.numFrame = m_frameCounter;
528
529 if ( m_recordTimings ) { timerData.print( std::cout ); }
530
531 m_timerData.push_back( timerData );
532
533 if ( m_recordFrames ) { recordFrame(); }
534
535 ++m_frameCounter;
536
537 if ( m_numFrames > 0 && m_frameCounter >= m_numFrames ) { appNeedsToQuit(); }
538
539 if ( m_frameCounter % m_frameCountBeforeUpdate == 0 ) {
540 emit( updateFrameStats( m_timerData ) );
541 m_timerData.clear();
542 }
543 m_mainWindow->onFrameComplete();
544}
545
546void BaseApplication::appNeedsToQuit() {
547 LOG( logDEBUG ) << "About to quit.";
548 m_isAboutToQuit = true;
549}
550
552 // Initialize opengl plugins added before openGL was ready
553 if ( !m_openGLPlugins.empty() ) {
554 for ( auto plugin : m_openGLPlugins ) {
555 plugin->openGlInitialize( m_pluginContext );
556 }
558 }
559}
560
561void BaseApplication::setRealFrameRate( bool on ) {
562 m_realFrameRate = on;
563}
564
565void BaseApplication::setRecordFrames( bool on ) {
566 setContinuousUpdate( on );
567 if ( on ) askForUpdate();
568 m_recordFrames = on;
569}
570
571void BaseApplication::recordFrame() {
572 std::stringstream filename;
573 filename << m_exportFoldername << "/radiumframe_" << std::setw( 6 ) << std::setfill( '0' )
574 << m_frameCounter << ".png";
575 m_viewer->grabFrame( filename.str() );
576}
577
578BaseApplication::~BaseApplication() {
579 emit stopping();
580 m_mainWindow->cleanup();
581 m_engine->cleanup();
582 Ra::Engine::RadiumEngine::destroyInstance();
583
584 // This will remove the directory if empty.
585 QDir().rmdir( m_exportFoldername.c_str() );
586}
587
589 const QStringList& loadList,
590 const QStringList& ignoreList ) {
591 QDir pluginsDir( qApp->applicationDirPath() );
592 bool result = pluginsDir.cd( pluginsPath.c_str() );
593
594 if ( result ) {
595 LOG( logINFO ) << " *** Loading Plugins from " << pluginsDir.absolutePath().toStdString()
596 << " ***";
597 }
598 else {
599 LOG( logDEBUG ) << "Cannot open specified plugins directory "
600 << pluginsDir.absolutePath().toStdString();
601 return false;
602 }
603 bool res = true;
604 uint pluginCpt = 0;
605
606 for ( const auto& filename : pluginsDir.entryList( QDir::Files ) ) {
607
608 std::string ext = Core::Utils::getFileExt( filename.toStdString() );
609#if defined( OS_WINDOWS )
610 std::string sysDllExt = "dll";
611#elif defined( OS_LINUX )
612 std::string sysDllExt = "so";
613#elif defined( OS_MACOS )
614 std::string sysDllExt = "dylib";
615#else
616 static_assert( false, "System configuration not handled" );
617#endif
618 if ( ext == sysDllExt ) {
619 std::string basename = Core::Utils::getBaseName( filename.toStdString(), false );
620
621 auto stringCmp = [basename]( const QString& str ) {
622 return str.toStdString() == basename;
623 };
624
625 if ( !loadList.empty() &&
626 std::find_if( loadList.begin(), loadList.end(), stringCmp ) == loadList.end() ) {
627 LOG( logDEBUG ) << "Ignoring " << filename.toStdString() << " (not on load list)";
628 continue;
629 }
630 if ( std::find_if( ignoreList.begin(), ignoreList.end(), stringCmp ) !=
631 ignoreList.end() ) {
632 LOG( logDEBUG ) << "Ignoring " << filename.toStdString() << " (on ignore list)";
633 continue;
634 }
635
636 QPluginLoader pluginLoader( pluginsDir.absoluteFilePath( filename ) );
637 // Force symbol resolution at load time.
638 pluginLoader.setLoadHints( QLibrary::ResolveAllSymbolsHint );
639
640 // Looking for Radium plugin signature on metadata
641 auto metadata = pluginLoader.metaData()["MetaData"].toObject();
642 if ( metadata.isEmpty() || !metadata.contains( "com.storm-irit.RadiumEngine" ) ||
643 metadata["com.storm-irit.RadiumEngine"].toString().compare( "plugin" ) != 0 ) {
644 LOG( logDEBUG ) << "File " << filename.toStdString() << " is not a Radium plugin.";
645 continue;
646 }
647
648 // detect if the plugin meets the minimal requirements
649 // if not, triggers a QDialog explaining the error, and abort the application
650 // We choose to stop the application to force all the plugins to be updated
651 if ( !metadata.contains( "isDebug" ) ) {
652 QMessageBox::critical( m_mainWindow.get(),
653 "Invalid plugin loaded (see Q_RADIUM_PLUGIN_METADATA)",
654 QString( "The application tried to load an unsupported "
655 "plugin. The application will stop.\n" ) +
656 QString( "Plugin path: " ) +
657 pluginsDir.absoluteFilePath( filename ) );
658 appNeedsToQuit();
659 return false;
660 }
661 bool isPluginDebug = metadata["isDebug"].toString().compare( "true" ) == 0;
662 if ( expectPluginsDebug == isPluginDebug ) {
663 const auto [it, success] = m_loadedPlugins.insert( { basename, pluginsPath } );
664 if ( !success ) {
665 LOG( logDEBUG )
666 << "Unable to load plugin " << basename << " from " << pluginsPath
667 << ".\n\t\tPlugin was already loaded from " << it->second;
668 continue;
669 }
670 LOG( logINFO ) << "Found plugin " << filename.toStdString();
671 // load the plugin
672 QObject* plugin = pluginLoader.instance();
673 if ( plugin ) {
674 auto loadedPlugin = qobject_cast<Plugins::RadiumPluginInterface*>( plugin );
675 if ( loadedPlugin ) {
676 ++pluginCpt;
677 loadedPlugin->registerPlugin( m_pluginContext );
678 m_mainWindow->updateUi( loadedPlugin );
679
680 if ( loadedPlugin->doAddRenderer() ) {
682 loadedPlugin->addRenderers( &tmpR );
683 CORE_ASSERT( !tmpR.empty(),
684 "This plugin is expected to add a renderer" );
685 for ( const auto& ptr : tmpR ) {
686 std::string name =
687 ptr->getRendererName() + "(" + filename.toStdString() + ")";
688 m_mainWindow->addRenderer( name, ptr );
689 }
690 }
691
692 if ( loadedPlugin->doAddFileLoader() ) {
694 loadedPlugin->addFileLoaders( &tmpL );
695 CORE_ASSERT( !tmpL.empty(),
696 "This plugin is expected to add file loaders" );
697 for ( auto& ptr : tmpL ) {
699 }
700 }
701
702 if ( loadedPlugin->doAddROpenGLInitializer() ) {
703 if ( m_viewer->isOpenGlInitialized() ) {
704 LOG( logDEBUG ) << "Direct OpenGL initialization for plugin "
705 << filename.toStdString();
706 // OpenGL is ready, initialize openGL part of the plugin
708 loadedPlugin->openGlInitialize( m_pluginContext );
710 }
711 else {
712 // Defer OpenGL initialisation
713 LOG( logDEBUG ) << "Defered OpenGL initialization for plugin "
714 << filename.toStdString();
715 m_openGLPlugins.push_back( loadedPlugin );
716 }
717 }
718 }
719 else {
720 LOG( logERROR ) << "Something went wrong while trying to cast plugin "
721 << filename.toStdString();
722 res = false;
723 }
724 }
725 else {
726 LOG( logERROR ) << "Something went wrong while trying to load plugin "
727 << filename.toStdString() << " : "
728 << pluginLoader.errorString().toStdString();
729 res = false;
730 }
731 }
732 else {
733 LOG( logERROR ) << "Skipped plugin " << filename.toStdString()
734 << " : invalid build mode. Full path: "
735 << pluginsDir.absoluteFilePath( filename ).toStdString();
736 res = false;
737 }
738 }
739 }
740
741 if ( pluginCpt == 0 ) { LOG( logINFO ) << "No plugin found or loaded."; }
742 else { LOG( logINFO ) << "Loaded " << pluginCpt << " plugins."; }
743
744 return res;
745}
746
747void BaseApplication::setRecordTimings( bool on ) {
748 m_recordTimings = on;
749}
750
751void BaseApplication::setRecordGraph( bool on ) {
752 m_recordGraph = on;
753}
754
756 QSettings settings;
757 QStringList pluginPaths = settings.value( "plugins/paths" ).value<QStringList>();
758 LOG( logINFO ) << "Registered plugin paths are : ";
759 for ( const auto& s : pluginPaths ) {
760 LOG( logINFO ) << s.toStdString();
761 }
762 pluginPaths.append( pluginDir.c_str() );
763 settings.setValue( "plugins/paths", pluginPaths );
764 loadPlugins( pluginDir, QStringList(), QStringList() );
765}
766
768 QSettings settings;
769 settings.setValue( "plugins/paths", QStringList() );
770}
771
773 QMessageBox notYetImplemented;
774 notYetImplemented.setText( "Settings editor is not yet available !" );
775 notYetImplemented.exec();
776}
777
779 std::string helpText { "<h1>BaseApplication command line parameters</h1><\n>" };
780 helpText += "<p>Not yet written.</p><br/><\n>";
781 return helpText;
782}
783
784} // namespace Gui
785} // namespace Ra
T c_str(T... args)
bool loadFile(const std::string &file)
void getTasks(Core::TaskQueue *taskQueue, Scalar dt)
void registerFileLoader(std::shared_ptr< Core::Asset::FileLoaderInterface > fileLoader)
bool setConstantTimeStep(Scalar dt, bool forceConstantTime=false)
Sets the time delta between two frames for Constant-time time flow.
bool registerSystem(const std::string &name, Scene::System *system, int priority=1)
const TimerData & getTimerData() const
Definition Renderer.hpp:555
Core::Utils::Index addRenderObject(Rendering::RenderObject *renderObject)
Add a new render object to the component. This adds the RO to the manager for drawing.
Definition Component.cpp:41
static UiComponent * uiCmp()
Access the UI Component.
void addPluginDirectory(const std::string &pluginDir)
Allow the user to register a specific plugin directory for the application.
std::unique_ptr< Gui::MainWindowInterface > m_mainWindow
Application main window and GUI root class.
bool m_recordGraph
If true, print the task graph;.
Engine::RadiumEngine * m_engine
Instance of the radium engine.
BaseApplication(int &argc, char **argv, QString applicationName="RadiumEngine", QString organizationName="STORM-IRIT")
bool m_recordFrames
If true, dump each frame to a PNG file.
virtual void addApplicationExtension()
void radiumFrame()
Advance the engine for one frame.
std::unique_ptr< Core::TaskQueue > m_taskQueue
Task queue for processing tasks.
std::map< std::string, std::string > m_loadedPlugins
maps name and paths of already loaded plugins
bool m_recordTimings
If true, print the detailed timings of each frame.
QTimer * m_frameTimer
Timer to wake us up at every frame start.
void clearPluginDirectories()
Remove all registered plugin directories (except the default Radium Bundle one)
Core::Utils::TimePoint m_lastFrameStart
Time since the last frame start.
uint m_targetFPS
Number of frames per second to generate.
void createConnections()
Create signal / slots connections.
void initialize(const WindowFactory &factory, const glbinding::Version &glVersion={ 4, 1 })
void stopping()
Fired when the engine is about to stop.
virtual std::string getHelpText() const
Get the html formatted help text.
std::vector< Ra::Plugins::RadiumPluginInterface * > m_openGLPlugins
Plugins that need to be initialized once OpenGL is ready.
bool m_realFrameRate
If true, use the wall clock to advance the engine. If false, use a fixed time step.
bool m_isAboutToQuit
True if the applicatioon is about to quit. prevent to use resources that are being released.
virtual void engineBaseInitialization()
Gui::Viewer * m_viewer
Pointer to OpenGL Viewer for render call (belongs to MainWindow).
bool loadPlugins(const std::string &pluginsPath, const QStringList &loadList, const QStringList &ignoreList)
void starting()
Fired when the engine has just started, before the frame timer is set.
std::string m_exportFoldername
Name of the folder where exported data goes.
virtual void engineOpenGLInitialize()
slot called when the OpenGL need to be initialized
void closed()
Emitted when the closed button has been hit.
void startRendering(const Scalar dt)
Start rendering (potentially asynchronously in a separate thread)
Definition Viewer.cpp:218
void swapBuffers()
Blocks until rendering is finished.
Definition Viewer.cpp:264
void requestEngineOpenGLInitialization()
virtual void update(const Scalar dt)
Update the internal viewer state to the (application) time dt.
Definition Viewer.cpp:211
PickingManager * getPickingManager()
Access to the feature picking manager.
Definition Viewer.cpp:207
QOpenGLContext * getContext() const
Access to the OpenGL context of the Viewer.
Definition Viewer.hpp:79
const Engine::Rendering::Renderer * getRenderer() const
Read-only access to renderer.
Definition Viewer.cpp:180
virtual void setupKeyMappingCallbacks()
add observers to keyMappingManager for gizmo, camera and viewer.
Definition Viewer.cpp:74
void grabFrame(const std::string &filename)
Write the current frame as an image. Supports either BMP or PNG file names.
Definition Viewer.cpp:318
void processPicking()
Emits signals corresponding to picking requests.
Definition Viewer.cpp:269
void cleanupGL()
call deinitializeGL if needed, with context activated
Definition WindowQt.cpp:160
This class loads scenes containing MESHES only (not point-clouds)
Loads density grid for volume data. This loader support 2 file formats for density grid data.
void askForUpdate()
ask for single-shot rendering update
void setContinuousUpdate(bool b)
enable continuous rendering update
T clear(T... args)
T count(T... args)
T data(T... args)
T empty(T... args)
T find_if(T... args)
T insert(T... args)
T localtime(T... args)
T max(T... args)
T min(T... args)
std::string getDataPath()
Get the current data path.
Definition Resources.cpp:70
optional< std::string > getRadiumPluginsPath()
Get the path of Radium embedded plugins.
Definition Resources.cpp:44
void pushDataPath(std::string datapath)
Push a new data path.
Definition Resources.cpp:82
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T push_back(T... args)
T put_time(T... args)
T setfill(T... args)
T setw(T... args)
T str(T... args)
This struct holds all timings for one frame of the engine.
T time(T... args)