/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2017 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED #include #endif #ifdef OPENSPACE_MODULE_ISWA_ENABLED #include #include #endif #if defined(_MSC_VER) && defined(OPENSPACE_ENABLE_VLD) #include #endif #ifdef WIN32 #include #endif #include "openspaceengine_lua.inl" using namespace openspace::scripting; using namespace ghoul::filesystem; using namespace ghoul::logging; using namespace ghoul::cmdparser; namespace { const std::string _loggerCat = "OpenSpaceEngine"; const std::string _sgctDefaultConfigFile = "${SGCT}/single.xml"; const std::string _defaultCacheLocation = "${BASE_PATH}/cache"; const std::string _sgctConfigArgumentCommand = "-config"; const std::string PreInitializeFunction = "preInitialization"; const std::string PostInitializationFunction = "postInitialization"; const int CacheVersion = 1; const int DownloadVersion = 1; struct { std::string configurationName; std::string sgctConfigurationName; std::string sceneName; std::string cacheFolder; } commandlineArgumentPlaceholders; } namespace openspace { namespace properties { class Property; } OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr; OpenSpaceEngine::OpenSpaceEngine(std::string programName, std::unique_ptr windowWrapper) : _configurationManager(new ConfigurationManager) , _interactionHandler(new interaction::InteractionHandler) , _renderEngine(new RenderEngine) , _scriptEngine(new scripting::ScriptEngine) , _scriptScheduler(new scripting::ScriptScheduler) , _networkEngine(new NetworkEngine) , _syncEngine(std::make_unique(new SyncBuffer(4096))) , _commandlineParser(new ghoul::cmdparser::CommandlineParser( programName, ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes )) , _console(new LuaConsole) , _moduleEngine(new ModuleEngine) , _settingsEngine(new SettingsEngine) , _timeManager(new TimeManager) , _downloadManager(nullptr) #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED , _gui(new gui::GUI) #endif , _parallelConnection(new ParallelConnection) , _windowWrapper(std::move(windowWrapper)) , _globalPropertyNamespace(new properties::PropertyOwner) , _isMaster(false) , _runTime(0.0) , _isInShutdownMode(false) , _shutdownCountdown(0.f) , _shutdownWait(0.f) , _isFirstRenderingFirstFrame(true) { _interactionHandler->setPropertyOwner(_globalPropertyNamespace.get()); _globalPropertyNamespace->addPropertySubOwner(_interactionHandler.get()); _globalPropertyNamespace->addPropertySubOwner(_settingsEngine.get()); _globalPropertyNamespace->addPropertySubOwner(_renderEngine.get()); FactoryManager::initialize(); FactoryManager::ref().addFactory( std::make_unique>(), "Renderable" ); FactoryManager::ref().addFactory( std::make_unique>(), "Translation" ); FactoryManager::ref().addFactory( std::make_unique>(), "Rotation" ); FactoryManager::ref().addFactory( std::make_unique>(), "Scale" ); SpiceManager::initialize(); Time::initialize(); TransformationManager::initialize(); } OpenSpaceEngine::~OpenSpaceEngine() { LINFO("_windowWrapper->isUsingSwapGroups(): " << _windowWrapper->isUsingSwapGroups()); LINFO("_windowWrapper->isSwapGroupMaster(): " << _windowWrapper->isSwapGroupMaster()); #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED _gui->deinitializeGL(); #endif _interactionHandler->deinitialize(); _renderEngine->deinitialize(); _globalPropertyNamespace = nullptr; _windowWrapper = nullptr; _parallelConnection = nullptr; _configurationManager = nullptr; _interactionHandler = nullptr; _renderEngine = nullptr; _scriptEngine = nullptr; _networkEngine = nullptr; _syncEngine = nullptr; _commandlineParser = nullptr; _console = nullptr; _moduleEngine = nullptr; _settingsEngine = nullptr; #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED _gui = nullptr; #endif } OpenSpaceEngine& OpenSpaceEngine::ref() { ghoul_assert(_engine, "OpenSpaceEngine not created"); return *_engine; } bool OpenSpaceEngine::create(int argc, char** argv, std::unique_ptr windowWrapper, std::vector& sgctArguments) { ghoul_assert(!_engine, "OpenSpaceEngine was already created"); ghoul_assert(windowWrapper != nullptr, "No Window Wrapper was provided"); ghoul::initialize(); // Initialize the LogManager and add the console log as this will be used every time // and we need a fall back if something goes wrong between here and when we add the // logs from the configuration file. If the user requested as specific loglevel in the // configuration file, we will deinitialize this LogManager and reinitialize it later // with the correct LogLevel LogManager::initialize( LogLevel::Debug, ghoul::logging::LogManager::ImmediateFlush::Yes ); LogMgr.addLog(std::make_unique()); LDEBUG("Initialize FileSystem"); #ifdef __APPLE__ ghoul::filesystem::File app(argv[0]); std::string dirName = app.directoryName(); LINFO("Setting starting directory to '" << dirName << "'"); FileSys.setCurrentDirectory(dirName); #endif // Sanity check of values if (argc < 1 || argv == nullptr) { LFATAL("No arguments were passed to this function"); return false; } // Create other objects LDEBUG("Creating OpenSpaceEngine"); _engine = new OpenSpaceEngine(std::string(argv[0]), std::move(windowWrapper)); // Query modules for commandline arguments _engine->gatherCommandlineArguments(); // Parse commandline arguments std::vector args(argv, argv + argc); std::shared_ptr> arguments = _engine->_commandlineParser->setCommandLine(args); bool showHelp = _engine->_commandlineParser->execute(); if (showHelp) { _engine->_commandlineParser->displayHelp(); return false; } sgctArguments = *arguments; // Find configuration std::string configurationFilePath = commandlineArgumentPlaceholders.configurationName; if (configurationFilePath.empty()) { LDEBUG("Finding configuration"); try { configurationFilePath = ConfigurationManager::findConfiguration(configurationFilePath); } catch (const ghoul::RuntimeError& e) { LFATALC(e.component, e.message); } } configurationFilePath = absPath(configurationFilePath); LINFO("Configuration Path: '" << configurationFilePath << "'"); // Loading configuration from disk LDEBUG("Loading configuration from disk"); try { _engine->configurationManager().loadFromFile(configurationFilePath); } catch (const ghoul::RuntimeError& e) { LFATAL("Loading of configuration file '" << configurationFilePath << "' failed"); LFATALC(e.component, e.message); return false; } bool hasCacheCommandline = !commandlineArgumentPlaceholders.cacheFolder.empty(); bool hasCacheConfiguration = _engine->configurationManager().hasKeyAndValue( ConfigurationManager::KeyPerSceneCache ); std::string cacheFolder = absPath("${CACHE}"); if (hasCacheCommandline) { cacheFolder = commandlineArgumentPlaceholders.cacheFolder; //FileSys.registerPathToken( // "${CACHE}", // commandlineArgumentPlaceholders.cacheFolder, // ghoul::filesystem::FileSystem::Override::Yes //); } if (hasCacheConfiguration) { std::string scene = _engine->configurationManager().value( ConfigurationManager::KeyConfigScene ); cacheFolder += "-" + ghoul::filesystem::File(scene).baseName(); } if (hasCacheCommandline || hasCacheConfiguration) { LINFO("Old cache: " << absPath("${CACHE}")); LINFO("New cache: " << cacheFolder); FileSys.registerPathToken( "${CACHE}", cacheFolder, ghoul::filesystem::FileSystem::Override::Yes ); } // Initialize the requested logs from the configuration file _engine->configureLogging(); LINFOC("OpenSpace Version", OPENSPACE_VERSION_MAJOR << "." << OPENSPACE_VERSION_MINOR << "." << OPENSPACE_VERSION_PATCH << " (" << OPENSPACE_VERSION_STRING << ")"); // Create directories that doesn't exist auto tokens = FileSys.tokens(); for (const std::string& token : tokens) { if (!FileSys.directoryExists(token)) { std::string p = absPath(token); LDEBUG("Directory '" << p << "' does not exist, creating."); FileSys.createDirectory(p, ghoul::filesystem::FileSystem::Recursive::Yes); } } // Register modules _engine->_moduleEngine->initialize(); registerCoreClasses(DocEng); // After registering the modules, the documentations for the available classes // can be added as well for (OpenSpaceModule* m : _engine->_moduleEngine->modules()) { for (auto&& doc : m->documentations()) { DocEng.addDocumentation(doc); } } // Create the cachemanager FileSys.createCacheManager( absPath("${" + ConfigurationManager::KeyCache + "}"), CacheVersion ); _engine->_console->initialize(); // Register the provided shader directories ghoul::opengl::ShaderPreprocessor::addIncludePath(absPath("${SHADERS}")); // Determining SGCT configuration file LDEBUG("Determining SGCT configuration file"); std::string sgctConfigurationPath = _sgctDefaultConfigFile; _engine->configurationManager().getValue( ConfigurationManager::KeyConfigSgct, sgctConfigurationPath); if (!commandlineArgumentPlaceholders.sgctConfigurationName.empty()) { LDEBUG("Overwriting SGCT configuration file with commandline argument: " << commandlineArgumentPlaceholders.sgctConfigurationName); sgctConfigurationPath = commandlineArgumentPlaceholders.sgctConfigurationName; } // Prepend the outgoing sgctArguments with the program name // as well as the configuration file that sgct is supposed to use sgctArguments.insert(sgctArguments.begin(), argv[0]); sgctArguments.insert(sgctArguments.begin() + 1, _sgctConfigArgumentCommand); sgctArguments.insert(sgctArguments.begin() + 2, absPath(sgctConfigurationPath)); return true; } void OpenSpaceEngine::destroy() { _engine->_moduleEngine->deinitialize(); _engine->_console->deinitialize(); _engine->_scriptEngine->deinitialize(); delete _engine; FactoryManager::deinitialize(); Time::deinitialize(); SpiceManager::deinitialize(); ghoul::fontrendering::FontRenderer::deinitialize(); LogManager::deinitialize(); ghoul::deinitialize(); } bool OpenSpaceEngine::initialize() { // clear the screen so the user don't have to see old buffer contents from the // graphics card LDEBUG("Clearing all Windows"); clearAllWindows(); LDEBUG("Adding system components"); // Detect and log OpenCL and OpenGL versions and available devices SysCap.addComponent( std::make_unique() ); SysCap.addComponent( std::make_unique() ); LDEBUG("Detecting capabilities"); SysCap.detectCapabilities(); using Verbosity = ghoul::systemcapabilities::SystemCapabilitiesComponent::Verbosity; Verbosity verbosity = Verbosity::Default; if (configurationManager().hasKeyAndValue( ConfigurationManager::KeyCapabilitiesVerbosity)) { std::map verbosityMap = { { "None", Verbosity::None }, { "Minimal", Verbosity::Minimal }, { "Default", Verbosity::Default }, { "Full", Verbosity::Full } }; std::string v = configurationManager().value(ConfigurationManager::KeyCapabilitiesVerbosity); if (verbosityMap.find(v) != verbosityMap.end()) verbosity = verbosityMap[v]; } SysCap.logCapabilities(verbosity); // Check the required OpenGL versions of the registered modules ghoul::systemcapabilities::OpenGLCapabilitiesComponent::Version version = _engine->_moduleEngine->requiredOpenGLVersion(); LINFO("Required OpenGL version: " << version.toString()); if (OpenGLCap.openGLVersion() < version) { LFATAL("Module required higher OpenGL version than is supported"); return false; } std::string requestURL = ""; bool success = configurationManager().getValue(ConfigurationManager::KeyDownloadRequestURL, requestURL); if (success) { _downloadManager = std::make_unique(requestURL, DownloadVersion); } // Register Lua script functions LDEBUG("Registering Lua libraries"); registerCoreClasses(*_scriptEngine); #ifdef OPENSPACE_MODULE_ISWA_ENABLED _scriptEngine->addLibrary(IswaManager::luaLibrary()); #endif // TODO: Maybe move all scenegraph and renderengine stuff to initializeGL scriptEngine().initialize(); writeDocumentation(); bool disableMasterRendering = false; configurationManager().getValue( ConfigurationManager::KeyDisableMasterRendering, disableMasterRendering); _renderEngine->setDisableRenderingOnMaster(disableMasterRendering); configurationManager().getValue( ConfigurationManager::KeyShutdownCountdown, _shutdownWait ); if (!commandlineArgumentPlaceholders.sceneName.empty()) configurationManager().setValue( ConfigurationManager::KeyConfigScene, commandlineArgumentPlaceholders.sceneName); // Initialize the SettingsEngine _settingsEngine->initialize(); _settingsEngine->setModules(_moduleEngine->modules()); // Initialize the InteractionHandler _interactionHandler->initialize(); // Load a light and a monospaced font loadFonts(); // Initialize the Scene Scene* sceneGraph = new Scene; sceneGraph->initialize(); std::string scenePath = ""; configurationManager().getValue(ConfigurationManager::KeyConfigScene, scenePath); sceneGraph->scheduleLoadSceneFile(scenePath); // Initialize the RenderEngine _renderEngine->setSceneGraph(sceneGraph); _renderEngine->initialize(); _renderEngine->setGlobalBlackOutFactor(0.0); _renderEngine->startFading(1, 3.0); // Run start up scripts try { runPreInitializationScripts(scenePath); } catch (const ghoul::RuntimeError& e) { LFATALC(e.component, e.message); } #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED LINFO("Initializing GUI"); _gui->initialize(); _gui->_globalProperty.setSource( [&]() { std::vector res = { _settingsEngine.get(), _interactionHandler.get(), _renderEngine.get() }; return res; } ); OsEng.gui()._screenSpaceProperty.setSource( [&]() { const auto& ssr = renderEngine().screenSpaceRenderables(); return std::vector(ssr.begin(), ssr.end()); } ); OsEng.gui()._property.setSource( [&]() { const auto& nodes = renderEngine().scene()->allSceneGraphNodes(); return std::vector(nodes.begin(), nodes.end()); } ); #ifdef OPENSPACE_MODULE_ISWA_ENABLED OsEng.gui()._iswa.setSource( [&]() { const auto& groups = IswaManager::ref().groups(); std::vector res; std::transform( groups.begin(), groups.end(), std::back_inserter(res), [](const auto& val) { return val.second.get(); } ); return res; } ); #endif #endif #ifdef OPENSPACE_MODULE_ISWA_ENABLED IswaManager::initialize(); #endif _syncEngine->addSyncables(Time::ref().getSyncables()); _syncEngine->addSyncables(_renderEngine->getSyncables()); _syncEngine->addSyncable(_scriptEngine.get()); LINFO("Finished initializing"); return true; } void OpenSpaceEngine::writeDocumentation() { // If a LuaDocumentationFile was specified, generate it now const std::string LuaDocumentationType = ConfigurationManager::KeyLuaDocumentation + "." + ConfigurationManager::PartType; const std::string LuaDocumentationFile = ConfigurationManager::KeyLuaDocumentation + "." + ConfigurationManager::PartFile; const bool hasLuaDocType = configurationManager().hasKey(LuaDocumentationType); const bool hasLuaDocFile = configurationManager().hasKey(LuaDocumentationFile); if (hasLuaDocType && hasLuaDocFile) { std::string luaDocumentationType; configurationManager().getValue(LuaDocumentationType, luaDocumentationType); std::string luaDocumentationFile; configurationManager().getValue(LuaDocumentationFile, luaDocumentationFile); luaDocumentationFile = absPath(luaDocumentationFile); _scriptEngine->writeDocumentation(luaDocumentationFile, luaDocumentationType); } // If a general documentation was specified, generate it now const std::string DocumentationType = ConfigurationManager::KeyDocumentation + '.' + ConfigurationManager::PartType; const std::string DocumentationFile = ConfigurationManager::KeyDocumentation + '.' + ConfigurationManager::PartFile; const bool hasDocumentationType = configurationManager().hasKey(DocumentationType); const bool hasDocumentationFile = configurationManager().hasKey(DocumentationFile); if (hasDocumentationType && hasDocumentationFile) { std::string documentationType; configurationManager().getValue(DocumentationType, documentationType); std::string documentationFile; configurationManager().getValue(DocumentationFile, documentationFile); documentationFile = absPath(documentationFile); DocEng.writeDocumentation(documentationFile, documentationType); } const std::string FactoryDocumentationType = ConfigurationManager::KeyFactoryDocumentation + '.' + ConfigurationManager::PartType; const std::string FactoryDocumentationFile = ConfigurationManager::KeyFactoryDocumentation + '.' + ConfigurationManager::PartFile; bool hasFactoryDocumentationType = configurationManager().hasKey(FactoryDocumentationType); bool hasFactoryDocumentationFile = configurationManager().hasKey(FactoryDocumentationFile); if (hasFactoryDocumentationType && hasFactoryDocumentationFile) { std::string type = configurationManager().value(FactoryDocumentationType); std::string file = configurationManager().value(FactoryDocumentationFile); FactoryManager::ref().writeDocumentation(absPath(file), type); } } bool OpenSpaceEngine::isInitialized() { return _engine != nullptr; } void OpenSpaceEngine::clearAllWindows() { _windowWrapper->clearAllWindows(glm::vec4(0.f, 0.f, 0.f, 1.f)); } void OpenSpaceEngine::gatherCommandlineArguments() { commandlineArgumentPlaceholders.configurationName = ""; _commandlineParser->addCommand(std::make_unique>( &commandlineArgumentPlaceholders.configurationName, "-config", "-c", "Provides the path to the OpenSpace configuration file" )); commandlineArgumentPlaceholders.sgctConfigurationName = ""; _commandlineParser->addCommand(std::make_unique>( &commandlineArgumentPlaceholders.sgctConfigurationName, "-sgct", "-s", "Provides the path to the SGCT configuration file, overriding the value set in " "the OpenSpace configuration file" )); commandlineArgumentPlaceholders.sceneName = ""; _commandlineParser->addCommand(std::make_unique>( &commandlineArgumentPlaceholders.sceneName, "-scene", "", "Provides the path to " "the scene file, overriding the value set in the OpenSpace configuration file" )); commandlineArgumentPlaceholders.cacheFolder = ""; _commandlineParser->addCommand(std::make_unique>( &commandlineArgumentPlaceholders.cacheFolder, "-cacheDir", "", "Provides the " "path to a cache file, overriding the value set in the OpenSpace configuration " "file" )); } void OpenSpaceEngine::runScripts(const ghoul::Dictionary& scripts) { for (size_t i = 1; i <= scripts.size(); ++i) { std::stringstream stream; stream << i; const std::string& key = stream.str(); const bool hasKey = scripts.hasKeyAndValue(key); if (!hasKey) { LERROR("The startup scripts have to be declared in a simple array format." " Startup scripts did not contain the key '" << key << "'"); break; } std::string scriptPath; scripts.getValue(key, scriptPath); std::string&& absoluteScriptPath = absPath(scriptPath); _engine->scriptEngine().runScriptFile(absoluteScriptPath); } } void OpenSpaceEngine::runPreInitializationScripts(const std::string& sceneDescription) { LINFO("Running Initialization scripts"); ghoul::lua::LuaState state; OsEng.scriptEngine().initializeLuaState(state); // First execute the script to get all global variables ghoul::lua::runScriptFile(state, absPath(sceneDescription)); // Get the preinitialize function lua_getglobal(state, PreInitializeFunction.c_str()); bool isFunction = lua_isfunction(state, -1); if (!isFunction) { LERROR("Error executing startup script '" << sceneDescription << "'. Scene '" << sceneDescription << "' does not have a function '" << PreInitializeFunction << "'"); return; } // And execute the preinitialize function int success = lua_pcall(state, 0, 0, 0); if (success != 0) { LERROR("Error executing '" << PreInitializeFunction << "': " << lua_tostring(state, -1)); } } void OpenSpaceEngine::runPostInitializationScripts(const std::string& sceneDescription) { LINFO("Running Setup scripts"); ghoul::lua::LuaState state; OsEng.scriptEngine().initializeLuaState(state); // First execute the script to get all global variables ghoul::lua::runScriptFile(state, absPath(sceneDescription)); // Get the preinitialize function lua_getglobal(state, PostInitializationFunction.c_str()); bool isFunction = lua_isfunction(state, -1); if (!isFunction) { LERROR("Error executing startup script '" << sceneDescription << "'. Scene '" << sceneDescription << "' does not have a function '" << PostInitializationFunction << "'"); return; } // And execute the preinitialize function int success = lua_pcall(state, 0, 0, 0); if (success != 0) { LERROR("Error executing '" << PostInitializationFunction << "': " << lua_tostring(state, -1) ); } } void OpenSpaceEngine::loadFonts() { ghoul::Dictionary fonts; configurationManager().getValue(ConfigurationManager::KeyFonts, fonts); const glm::ivec3 fontAtlasSize{1024, 1024, 1}; _fontManager = std::make_unique(fontAtlasSize); for (const std::string& key : fonts.keys()) { std::string font; fonts.getValue(key, font); font = absPath(font); if (!FileSys.fileExists(font)) { LERROR("Could not find font '" << font << "'"); continue; } LINFO("Registering font '" << font << "' with key '" << key << "'"); bool success = _fontManager->registerFontPath(key, font); if (!success) LERROR("Error registering font '" << font << "' with key '" << key << "'"); } try { bool initSuccess = ghoul::fontrendering::FontRenderer::initialize(); if (!initSuccess) LERROR("Error initializing default font renderer"); ghoul::fontrendering::FontRenderer::defaultRenderer().setFramebufferSize( _renderEngine->fontResolution() ); } catch (const ghoul::RuntimeError& err) { LERRORC(err.component, err.message); } } void OpenSpaceEngine::configureLogging() { const std::string KeyLogLevel = ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartLogLevel; const std::string KeyLogImmediateFlush = ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartImmediateFlush; const std::string KeyLogs = ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartLogs; if (configurationManager().hasKeyAndValue(KeyLogLevel)) { std::string logLevel; configurationManager().getValue(KeyLogLevel, logLevel); bool immediateFlush = false; configurationManager().getValue(KeyLogImmediateFlush, immediateFlush); LogLevel level = ghoul::logging::levelFromString(logLevel); LogManager::deinitialize(); using ImmediateFlush = ghoul::logging::LogManager::ImmediateFlush; LogManager::initialize( level, immediateFlush ? ImmediateFlush::Yes : ImmediateFlush::No ); LogMgr.addLog(std::make_unique()); } if (configurationManager().hasKeyAndValue(KeyLogs)) { ghoul::Dictionary logs; configurationManager().getValue(KeyLogs, logs); for (size_t i = 1; i <= logs.size(); ++i) { ghoul::Dictionary logInfo; logs.getValue(std::to_string(i), logInfo); try { LogMgr.addLog(createLog(logInfo)); } catch (const ghoul::RuntimeError& e) { LERRORC(e.component, e.message); } } } #ifdef WIN32 if (IsDebuggerPresent()) { LogMgr.addLog(std::make_unique()); } #endif // WIN32 #ifndef GHOUL_LOGGING_ENABLE_TRACE std::string logLevel; configurationManager().getValue(KeyLogLevel, logLevel); LogLevel level = ghoul::logging::levelFromString(logLevel); if (level == ghoul::logging::LogLevel::Trace) { LWARNING("Desired logging level is set to 'Trace' but application was " << "compiled without Trace support"); } #endif // GHOUL_LOGGING_ENABLE_TRACE } bool OpenSpaceEngine::initializeGL() { LINFO("Initializing Rendering Engine"); bool success = _renderEngine->initializeGL(); #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED LINFO("Initializing OnScreen GUI GL"); try { _gui->initializeGL(); } catch (const ghoul::RuntimeError& e) { LERROR(e.what()); } #endif LINFO("Finished initializing OpenGL"); // If using swapgroups, LINFO("_windowWrapper->isUsingSwapGroups(): " << _windowWrapper->isUsingSwapGroups()); LINFO("_windowWrapper->isSwapGroupMaster(): " << _windowWrapper->isSwapGroupMaster()); return success; } bool OpenSpaceEngine::isMaster(){ return _isMaster; } void OpenSpaceEngine::setMaster(bool master){ _isMaster = master; } double OpenSpaceEngine::runTime(){ return _runTime; } void OpenSpaceEngine::setRunTime(double d){ _runTime = d; } void OpenSpaceEngine::preSynchronization() { FileSys.triggerFilesystemEvents(); if (_isFirstRenderingFirstFrame) { _windowWrapper->setSynchronization(false); } _syncEngine->presync(_isMaster); if (_isMaster) { double dt = _windowWrapper->averageDeltaTime(); _timeManager->preSynchronization(dt); auto scheduledScripts = _scriptScheduler->progressTo(Time::ref().j2000Seconds()); for (auto it = scheduledScripts.first; it != scheduledScripts.second; ++it) { _scriptEngine->queueScript( *it, ScriptEngine::RemoteScripting::Yes ); } _interactionHandler->updateInputStates(dt); _renderEngine->updateSceneGraph(); _interactionHandler->updateCamera(dt); _renderEngine->camera()->invalidateCache(); _parallelConnection->preSynchronization(); } } void OpenSpaceEngine::postSynchronizationPreDraw() { _syncEngine->postsync(_isMaster); if (_isInShutdownMode) { if (_shutdownCountdown <= 0.f) { _windowWrapper->terminate(); } _shutdownCountdown -= _windowWrapper->averageDeltaTime(); } _renderEngine->updateSceneGraph(); _renderEngine->updateFade(); _renderEngine->updateRenderer(); _renderEngine->updateScreenSpaceRenderables(); _renderEngine->updateShaderPrograms(); if (!_isMaster) { _renderEngine->camera()->invalidateCache(); } // Step the camera using the current mouse velocities which are synced //_interactionHandler->updateCamera(); #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED if (_isMaster && _windowWrapper->isRegularRendering()) { glm::vec2 mousePosition = _windowWrapper->mousePosition(); //glm::ivec2 drawBufferResolution = _windowWrapper->currentDrawBufferResolution(); glm::ivec2 windowSize = _windowWrapper->currentWindowSize(); glm::ivec2 renderingSize = _windowWrapper->currentWindowResolution(); uint32_t mouseButtons = _windowWrapper->mouseButtons(2); double dt = std::max(_windowWrapper->averageDeltaTime(), 0.0); _gui->startFrame( static_cast(dt), glm::vec2(windowSize), _windowWrapper->dpiScaling(), mousePosition, mouseButtons ); } #endif // Testing this every frame has minimal impact on the performance --- abock // Debug build: 1-2 us ; Release build: <= 1 us using ghoul::logging::LogManager; int warningCounter = LogMgr.messageCounter(LogLevel::Warning); int errorCounter = LogMgr.messageCounter(LogLevel::Error); int fatalCounter = LogMgr.messageCounter(LogLevel::Fatal); if (warningCounter > 0) LWARNINGC("Logging", "Number of Warnings raised: " << warningCounter); if (errorCounter > 0) LWARNINGC("Logging", "Number of Errors raised: " << errorCounter); if (fatalCounter > 0) LWARNINGC("Logging", "Number of Fatals raised: " << fatalCounter); LogMgr.resetMessageCounters(); } void OpenSpaceEngine::render(const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) { _renderEngine->render(projectionMatrix, viewMatrix); } void OpenSpaceEngine::postDraw() { _renderEngine->postDraw(); bool showGui = _windowWrapper->hasGuiWindow() ? _windowWrapper->isGuiWindow() : true; if (showGui) { _renderEngine->renderScreenLog(); if (_console->isVisible()) _console->render(); #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED if (_isMaster && _windowWrapper->isRegularRendering()) _gui->endFrame(); #endif } if (_isInShutdownMode) { _renderEngine->renderShutdownInformation(_shutdownCountdown, _shutdownWait); } if (_isFirstRenderingFirstFrame) { _windowWrapper->setSynchronization(true); _isFirstRenderingFirstFrame = false; } } void OpenSpaceEngine::keyboardCallback(Key key, KeyModifier mod, KeyAction action) { if (_isMaster) { #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED if (_gui->isEnabled()) { bool isConsumed = _gui->keyCallback(key, mod, action); if (isConsumed) { return; } } #endif if (key == _console->commandInputButton()) { if (action == KeyAction::Press) { _console->toggleMode(); } } else if (!_console->isVisible()) { _interactionHandler->keyboardCallback(key, mod, action); } else { _console->keyboardCallback(key, mod, action); } } } void OpenSpaceEngine::charCallback(unsigned int codepoint, KeyModifier modifier) { if (_isMaster) { #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED if (_gui->isEnabled()) { const bool isConsumed = _gui->charCallback(codepoint, modifier); if (isConsumed) return; } #endif if (_console->isVisible()) { _console->charCallback(codepoint, modifier); } } } void OpenSpaceEngine::mouseButtonCallback(MouseButton button, MouseAction action) { if (_isMaster) { #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED if (_gui->isEnabled()) { const bool isConsumed = _gui->mouseButtonCallback(button, action); if (isConsumed /*&& action != MouseAction::Release*/) return; } #endif _interactionHandler->mouseButtonCallback(button, action); } } void OpenSpaceEngine::mousePositionCallback(double x, double y) { if (_isMaster) { _interactionHandler->mousePositionCallback(x, y); } } void OpenSpaceEngine::mouseScrollWheelCallback(double pos) { if (_isMaster) { #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED if (_gui->isEnabled()) { const bool isConsumed = _gui->mouseWheelCallback(pos); if (isConsumed) return; } #endif _interactionHandler->mouseScrollWheelCallback(pos); } } void OpenSpaceEngine::encode() { _syncEngine->encodeSyncables(); _networkEngine->publishStatusMessage(); _networkEngine->sendMessages(); } void OpenSpaceEngine::decode() { _syncEngine->decodeSyncables(); } void OpenSpaceEngine::externalControlCallback(const char* receivedChars, int size, int clientId) { if (size == 0) return; _networkEngine->handleMessage(std::string(receivedChars, size)); } void OpenSpaceEngine::toggleShutdownMode() { if (_isInShutdownMode) { // If we are already in shutdown mode, we want to disable it instead LINFO("Disabled shutdown mode"); _isInShutdownMode = false; } else { // Else, we hav eto enable it LINFO("Shutting down OpenSpace"); _shutdownCountdown = _shutdownWait; _isInShutdownMode = true; } } scripting::LuaLibrary OpenSpaceEngine::luaLibrary() { return { "", { { "toggleShutdown", &luascriptfunctions::toggleShutdown, "", "Toggles the shutdown mode that will close the application after the count" "down timer is reached" }, { "writeDocumentation", &luascriptfunctions::writeDocumentation, "", "Writes out documentation files" } } }; } bool OpenSpaceEngine::useBusyWaitForDecode() { return _settingsEngine->busyWaitForDecode(); } bool OpenSpaceEngine::logSGCTOutOfOrderErrors() { return _settingsEngine->logSGCTOutOfOrderErrors(); } void OpenSpaceEngine::enableBarrier() { _windowWrapper->setBarrier(true); } void OpenSpaceEngine::disableBarrier() { _windowWrapper->setBarrier(false); } NetworkEngine& OpenSpaceEngine::networkEngine() { ghoul_assert(_networkEngine, "NetworkEngine must not be nullptr"); return *_networkEngine; } ModuleEngine& OpenSpaceEngine::moduleEngine() { ghoul_assert(_moduleEngine, "ModuleEngine must not be nullptr"); return *_moduleEngine; } ConfigurationManager& OpenSpaceEngine::configurationManager() { ghoul_assert(_configurationManager, "ConfigurationManager must not be nullptr"); return *_configurationManager; } interaction::InteractionHandler& OpenSpaceEngine::interactionHandler() { ghoul_assert(_interactionHandler, "InteractionHandler must not be nullptr"); return *_interactionHandler; } RenderEngine& OpenSpaceEngine::renderEngine() { ghoul_assert(_renderEngine, "RenderEngine must not be nullptr"); return *_renderEngine; } ScriptEngine& OpenSpaceEngine::scriptEngine() { ghoul_assert(_scriptEngine, "ScriptEngine must not be nullptr"); return *_scriptEngine; } ScriptScheduler& OpenSpaceEngine::scriptScheduler(){ ghoul_assert(_scriptScheduler, "ScriptScheduler must not be nullptr"); return *_scriptScheduler; } LuaConsole& OpenSpaceEngine::console() { ghoul_assert(_console, "LuaConsole must not be nullptr"); return *_console; } #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED gui::GUI& OpenSpaceEngine::gui() { ghoul_assert(_gui, "GUI must not be nullptr"); return *_gui; } #endif ParallelConnection& OpenSpaceEngine::parallelConnection() { ghoul_assert(_parallelConnection, "ParallelConnection must not be nullptr"); return *_parallelConnection; } properties::PropertyOwner& OpenSpaceEngine::globalPropertyOwner() { ghoul_assert( _globalPropertyNamespace, "Global Property Namespace must not be nullptr" ); return *_globalPropertyNamespace; } WindowWrapper& OpenSpaceEngine::windowWrapper() { ghoul_assert(_windowWrapper, "Window Wrapper must not be nullptr"); return *_windowWrapper; } ghoul::fontrendering::FontManager& OpenSpaceEngine::fontManager() { ghoul_assert(_fontManager, "Font Manager must not be nullptr"); return *_fontManager; } DownloadManager& OpenSpaceEngine::downloadManager() { ghoul_assert(_downloadManager, "Download Manager must not be nullptr"); return *_downloadManager; } TimeManager& OpenSpaceEngine::timeManager() { ghoul_assert(_timeManager, "Download Manager must not be nullptr"); return *_timeManager; } } // namespace openspace