diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index b97d159420..150b507a87 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -22,7 +22,7 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include #include #include #include @@ -74,6 +74,8 @@ namespace { constexpr const char* _loggerCat = "main"; sgct::Engine* SgctEngine; +openspace::interaction::JoystickInputStates joystickInputStates; + constexpr const char* OpenVRTag = "OpenVR"; constexpr const char* SpoutTag = "Spout"; @@ -311,10 +313,10 @@ void mainInitFunc() { #endif // OPENSPACE_HAS_SPOUT } - std::string k = openspace::ConfigurationManager::KeyScreenshotUseDate; std::string screenshotPath = "${SCREENSHOTS}"; std::string screenshotNames = "OpenSpace"; - if (OsEng.configurationManager().hasKey(k)) { + + if (OsEng.configuration().shouldUseScreenshotDate) { std::time_t now = std::time(nullptr); std::tm* nowTime = std::localtime(&now); char mbstr[100]; @@ -345,12 +347,99 @@ void mainInitFunc() { } } + OsEng.setJoystickInputStates(joystickInputStates); + LTRACE("main::mainInitFunc(end)"); } void mainPreSyncFunc() { LTRACE("main::mainPreSyncFunc(begin)"); OsEng.preSynchronization(); + + // Query joystick status + using namespace openspace::interaction; + + for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; ++i) { + JoystickInputState& state = joystickInputStates[i]; + + int present = glfwJoystickPresent(i); + if (present == GLFW_TRUE) { + if (!state.isConnected) { + // Joystick was added + state.isConnected = true; + state.name = SgctEngine->getJoystickName(i); + + std::fill(state.axes.begin(), state.axes.end(), 0.f); + std::fill( + state.buttons.begin(), + state.buttons.end(), + JoystickAction::Idle + ); + } + + const float* axes = SgctEngine->getJoystickAxes(i, &state.nAxes); + if (state.nAxes > JoystickInputState::MaxAxes) { + LWARNING(fmt::format( + "Joystick/Gamepad {} has {} axes, but only {} axes are supported. " + "All excess axes are ignored", + state.name, + state.nAxes, + JoystickInputState::MaxAxes + )); + state.nAxes = JoystickInputState::MaxAxes; + } + std::memcpy(state.axes.data(), axes, state.nAxes * sizeof(float)); + + const unsigned char* buttons = SgctEngine->getJoystickButtons( + i, + &state.nButtons + ); + + if (state.nButtons > JoystickInputState::MaxButtons) { + LWARNING(fmt::format( + "Joystick/Gamepad {} has {} buttons, but only {} buttons are " + "supported. All excess buttons are ignored", + state.name, + state.nButtons, + JoystickInputState::MaxButtons + )); + state.nButtons = JoystickInputState::MaxButtons; + } + + for (int j = 0; j < state.nButtons; ++j) { + bool currentlyPressed = buttons[j] == GLFW_PRESS; + + if (currentlyPressed) { + switch (state.buttons[j]) { + case JoystickAction::Idle: + case JoystickAction::Release: + state.buttons[j] = JoystickAction::Press; + break; + case JoystickAction::Press: + case JoystickAction::Repeat: + state.buttons[j] = JoystickAction::Repeat; + break; + } + } + else { + switch (state.buttons[j]) { + case JoystickAction::Idle: + case JoystickAction::Release: + state.buttons[j] = JoystickAction::Idle; + break; + case JoystickAction::Press: + case JoystickAction::Repeat: + state.buttons[j] = JoystickAction::Release; + break; + } + } + } + } + else { + state.isConnected = false; + } + } + LTRACE("main::mainPreSyncFunc(end)"); } diff --git a/apps/Sync/main.cpp b/apps/Sync/main.cpp index 22ecaa259f..202b717c67 100644 --- a/apps/Sync/main.cpp +++ b/apps/Sync/main.cpp @@ -23,7 +23,6 @@ ****************************************************************************************/ #include -#include #include #include #include diff --git a/apps/TaskRunner/main.cpp b/apps/TaskRunner/main.cpp index 85a206d436..34219a479f 100644 --- a/apps/TaskRunner/main.cpp +++ b/apps/TaskRunner/main.cpp @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/data/assets/default.scene b/data/assets/default.scene index aa54ad4635..d5b4467a9c 100644 --- a/data/assets/default.scene +++ b/data/assets/default.scene @@ -12,6 +12,7 @@ assetHelper.requestAll(asset, 'scene/digitaluniverse') -- Load default key bindings applicable to most scenes asset.require('util/default_keybindings') asset.require('util/default_dashboard') +asset.require('util/default_joystick') asset.request('customization/globebrowsing') diff --git a/data/assets/util/default_joystick.asset b/data/assets/util/default_joystick.asset new file mode 100644 index 0000000000..64be2b36c3 --- /dev/null +++ b/data/assets/util/default_joystick.asset @@ -0,0 +1,136 @@ +local propertyHelper = asset.require('./property_helper') + +-- Allowed values for the second parameter of bindJoystickAxis: +-- "None" +-- "Orbit X" +-- "Orbit Y" +-- "Zoom In" +-- "Zoom Out" +-- "LocalRoll X" +-- "LocalRoll Y" +-- "GlobalRoll X" +-- "GlobalRoll Y" +-- "Pan X" +-- "Pan Y" +-- Third parameter determines whether the axis should be inverted +-- Fourth parameter determines whether the axis should be normalized from [-1,1] to [0,1] + + +local XBoxController = { + LeftThumbStick = { 0 , 1 }, + RightThumbStick = { 2, 3 }, + LeftTrigger = 4, + RightTrigger = 5, + A = 0, + B = 1, + X = 2, + Y = 3, + LB = 4, + RB = 5, + Select = 6, + Start = 7, + LeftStick = 8, + RightStick = 9, + DPad = { + Up = 10, + Right = 11, + Down = 12, + Left = 13 + } +} + +local PS4Controller = { + LeftThumbStick = { 0 , 1 }, + RightThumbStick = { 2, 5 }, + LeftTrigger = 3, + RightTrigger = 4, + A = 3, -- Triangle + B = 0, -- Square + X = 2, -- Circle + Y = 1, -- Cross + LB = 4, + RB = 5, + Select = 9, -- options + Start = 12, -- PS button + LeftStick = 10, + RightStick = 11, + DPad = { + Up = 14, + Right = 15, + Down = 16, + Left = 17 + } +} + +-- Variables to store the state of the joystick between frames +Joystick = {} +Joystick.State = {} +Joystick.State.IsInRollMode = false +Joystick.State.Axis = {} + +local bindLocalRoll = function(axis) +return [[ + -- We only want to store the current state in the first mode that is enabled, otherwise we will overwrite the backup + if not Joystick.State.IsInRollMode then + -- Save current axis state + Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized = openspace.navigation.joystickAxis(]] .. axis .. [[) + end + + -- Set new axis state + openspace.navigation.bindJoystickAxis(]] .. axis .. [[, "LocalRoll X", true); + Joystick.State.IsInRollMode = true + ]] +end + +local bindGlobalRoll = function(axis) + return [[ + -- We only want to store the current state in the first mode that is enabled, otherwise we will overwrite the backup + if not Joystick.State.IsInRollMode then + -- Save current axis state + Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized = openspace.navigation.joystickAxis(]] .. axis .. [[) + end + + -- Set new axis state + openspace.navigation.bindJoystickAxis(]] .. axis .. [[, "GlobalRoll X", true); + Joystick.State.IsInRollMode = true + ]] +end + +local unbindRoll = function(axis) + return [[ + -- Reset previous state + openspace.navigation.bindJoystickAxis(]] .. axis .. [[, Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized); +]] +end + +asset.onInitialize(function() + -- Set the controller to the connected controller + -- Currently: XBoxController or PS4Controller + local controller = XBoxController; + + openspace.navigation.setAxisDeadZone(controller.LeftThumbStick[1], 0.05) + openspace.navigation.setAxisDeadZone(controller.LeftThumbStick[2], 0.05) + openspace.navigation.setAxisDeadZone(controller.RightThumbStick[1], 0.05) + openspace.navigation.setAxisDeadZone(controller.RightThumbStick[2], 0.05) + openspace.navigation.setAxisDeadZone(controller.LeftTrigger, 0.05) + openspace.navigation.setAxisDeadZone(controller.RightTrigger, 0.05) + + openspace.navigation.bindJoystickAxis(controller.LeftThumbStick[1], "Orbit X"); + openspace.navigation.bindJoystickAxis(controller.LeftThumbStick[2], "Orbit Y", true); + openspace.navigation.bindJoystickAxis(controller.RightThumbStick[1], "Pan X", true); + openspace.navigation.bindJoystickAxis(controller.RightThumbStick[2], "Pan Y"); + openspace.navigation.bindJoystickAxis(controller.LeftTrigger, "Zoom Out", false, true); + openspace.navigation.bindJoystickAxis(controller.RightTrigger, "Zoom In", false, true); + + openspace.navigation.bindJoystickButton(controller.LB, bindLocalRoll(controller.RightThumbStick[1])) + openspace.navigation.bindJoystickButton(controller.LB, unbindRoll(controller.RightThumbStick[1]), "Release") + openspace.navigation.bindJoystickButton(controller.RB, bindGlobalRoll(controller.RightThumbStick[1])) + openspace.navigation.bindJoystickButton(controller.RB, unbindRoll(controller.RightThumbStick[1]), "Release") + + openspace.navigation.bindJoystickButton(controller.A, propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.ZoomFriction')) + openspace.navigation.bindJoystickButton(controller.B, propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RotationalFriction')) + openspace.navigation.bindJoystickButton(controller.DPad.Left, propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RollFriction')) + + openspace.navigation.bindJoystickButton(controller.X, "openspace.setPropertyValue('NavigationHandler.Origin', 'Earth')") + openspace.navigation.bindJoystickButton(controller.Y, "openspace.setPropertyValue('NavigationHandler.Origin', 'Mars')") +end) diff --git a/include/openspace/engine/configuration.h b/include/openspace/engine/configuration.h new file mode 100644 index 0000000000..1b2ef2760c --- /dev/null +++ b/include/openspace/engine/configuration.h @@ -0,0 +1,134 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___CONFIGURATION___H__ +#define __OPENSPACE_CORE___CONFIGURATION___H__ + +#include +#include +#include +#include +#include + +namespace openspace { + +namespace documentation { struct Documentation; } + +struct Configuration { + std::string windowConfiguration = "${CONFIG}/single.xml"; + std::string asset = "default"; + std::vector globalCustomizationScripts; + std::map pathTokens; + std::map fonts; + + struct Logging { + std::string level = "Info"; + std::string directory = "${BASE}"; + std::string performancePrefix = "PM-"; + bool forceImmediateFlush = false; + std::string capabilitiesVerbosity = "Default"; + std::vector logs; + }; + Logging logging; + + std::string scriptLog = ""; + + struct DocumentationInfo { + std::string lua = ""; + std::string property = ""; + std::string sceneProperty = ""; + std::string keyboard = ""; + std::string documentation = ""; + std::string factory = ""; + std::string license = ""; + }; + DocumentationInfo documentation; + + bool useMultithreadedInitialization = false; + + struct LoadingScreen { + bool isShowingMessages = true; + bool isShowingNodeNames = true; + bool isShowingProgressbar = true; + }; + LoadingScreen loadingScreen; + + bool isCheckingOpenGLState = false; + bool isLoggingOpenGLCalls = false; + + float shutdownCountdown = 0.f; + + bool shouldUseScreenshotDate = false; + + std::string onScreenTextScaling = "window"; + bool usePerSceneCache = false; + + bool isRenderingOnMasterDisabled = false; + bool isSceneTranslationOnMasterDisabled = false; + + std::map moduleConfigurations; + + std::string renderingMethod = "Framebuffer"; + + struct OpenGLDebugContext { + bool isActive = false; + bool isSynchronous = true; + struct IdentifierFilter { + std::string type = ""; + std::string source = ""; + unsigned int identifier = 0; + }; + std::vector identifierFilters; + std::vector severityFilters; + }; + OpenGLDebugContext openGLDebugContext; + + std::string serverPasskey = "17308"; + bool doesRequireSocketAuthentication = true; + std::vector clientAddressWhitelist = {}; + std::string webHelperLocation = ""; + std::string cefWebGuiUrl = ""; + + struct HTTPProxy { + bool usingHttpProxy = false; + std::string address; + unsigned int port = 0; + std::string authentication = "BASIC"; + std::string user; + std::string password; + }; + HTTPProxy httpProxy; + + + static documentation::Documentation Documentation; + ghoul::lua::LuaState state; +}; + +std::string findConfiguration(const std::string& filename = "openspace.cfg"); + +Configuration loadConfigurationFromFile(const std::string& filename); + +} // namespace openspace + +#endif // __OPENSPACE_CORE___CONFIGURATION___H__ diff --git a/include/openspace/engine/configurationmanager.h b/include/openspace/engine/configurationmanager.h deleted file mode 100644 index 63881b2dd3..0000000000 --- a/include/openspace/engine/configurationmanager.h +++ /dev/null @@ -1,282 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * 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. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_CORE___CONFIGURATIONMANAGER___H__ -#define __OPENSPACE_CORE___CONFIGURATIONMANAGER___H__ - -#include - -namespace openspace { - -namespace documentation { struct Documentation; } - -/** - * The ConfigurationManager takes care of loading the major configuration file - * openspace.cfg and making it available to the rest of the application. The - * exposed keys in the ghoul::Dictionary are declared in this class as static constants. - * The findConfiguration method walks the filesystem from a provided starting point until - * it found the requested file or throws a ghoul::RuntimeError if it could not find the - * file. The loadFromFile method then loads the file into a ghoul::Dictionary format. - */ -class ConfigurationManager : public ghoul::Dictionary { -public: - /// The key that stores the subdirectory containing all predefined path tokens - static constexpr const char* KeyPaths = "Paths"; - - /// The key that stores the location to the cache directory used to store all the - /// permanent and non-permanent cached files - static constexpr const char* KeyCachePath = "Paths.CACHE"; - - /// The key that stores the main directory for fonts - static constexpr const char* KeyFonts = "Fonts"; - - /// The key that stores the location of the SGCT configuration file that is used on - /// application launch - static constexpr const char* KeyConfigSgct = "SGCTConfig"; - - /// The key that defines a list of scripts for global customization that get executed - /// regardless of which scene is loaded - static constexpr const char* KeyGlobalCustomizationScripts = - "GlobalCustomizationScripts"; - - /// The part of the key that defines the type - // static constexpr const char* PartType = "Type"; - /// The part of the key that defines the file - // static constexpr const char* PartFile = "File"; - - /// The key that stores the Lua documentation - static constexpr const char* KeyLuaDocumentation = "LuaDocumentation"; - - /// The key that stores the scripting log - static constexpr const char* KeyScriptLog = "ScriptLog"; - - /// The key that stores the Scene Property documentation - static constexpr const char* KeyScenePropertyDocumentation = - "ScenePropertyDocumentation"; - - /// The key that stores the Root Property documentation - static constexpr const char* KeyPropertyDocumentation = "PropertyDocumentation"; - - /// The key that stores the keyboard bindings that should be stored - static constexpr const char* KeyKeyboardShortcuts = "KeyboardShortcuts"; - - /// The key that stores the main documentation - static constexpr const char* KeyDocumentation = "Documentation"; - - /// The key that stores the factory documentation values - static constexpr const char* KeyFactoryDocumentation = "FactoryDocumentation"; - /// The key that decides whether or not we should require incoming web socket - /// connections to authorize or not - static constexpr const char* KeyRequireSocketAuthentication = - "RequireSocketAuthentication"; - - /// The key that stores the location of the asset file that is initially loaded - static constexpr const char* KeyConfigAsset = "Asset"; - - /// The key that stores the scene license documentation values - static constexpr const char* KeySceneLicenseDocumentation = "LicenseDocumentation"; - - /// The key that stores the settings for determining log-related settings - static constexpr const char* KeyLogging = "Logging"; - - /// The key that stores the directory for Logging - static constexpr const char* LoggingDirectory = "Logging.LogDir"; - static constexpr const char* PartLogDir = "LogDir"; - - /// The key that stores the desired LogLevel for the whole application - /// \sa ghoul::logging::LogManager - static constexpr const char* KeyLoggingLogLevel = "Logging.LogLevel"; - static constexpr const char* PartLogLevel = "LogLevel"; - - /// The key that stores whether the log should be immediately flushed after a n - /// \sa ghoul::logging::LogManager - static constexpr const char* KeyLoggingImmediateFlush = "Logging.ImmediateFlush"; - static constexpr const char* PartImmediateFlush = "ImmediateFlush"; - - /// The key for prefixing PerformanceMeasurement logfiles - static constexpr const char* LoggingPerformancePrefix = "Logging.PerformancePrefix"; - static constexpr const char* PartLogPerformancePrefix = "PerformancePrefix"; - /// The key that stores a subdirectory with a description for additional - /// ghoul::logging::Log%s to be created - /// \sa LogFactory - static constexpr const char* KeyLoggingLogs = "Logging.Logs"; - static constexpr const char* PartLogs = "Logs"; - - /// The key that stores whether a log should be appended to or should be overwritten - static constexpr const char* PartAppend = "Append"; - - /// The key that stores the verbosity (None, Minimal, Default, Full) of the system - /// capabilities components - static constexpr const char* PartCapabilitiesVerbosity = "CapabilitiesVerbosity"; - - /// The key that stores the settings for determining Launcher-related settings - static constexpr const char* KeyLauncher = "Launcher"; - - /// The full key that stores the verbosity of the system capabilities component - static constexpr const char* KeyCapabilitiesVerbosity = - "Logging.CapabilitiesVerbosity"; - - /// The key that stores the time (in seconds) that the application will wait before - /// shutting down after the shutdown call is made - static constexpr const char* KeyShutdownCountdown = "ShutdownCountdown"; - - /// The key that stores whether the onscreen text should be scaled to the window size - /// or the window resolution - static constexpr const char* KeyOnScreenTextScaling = "OnScreenTextScaling"; - - /// The key that stores whether the master node should perform rendering just function - /// as a pure manager - static constexpr const char* KeyDisableMasterRendering = "DisableRenderingOnMaster"; - - /// The key that stores whether the master node should apply the scene transformation - static constexpr const char* KeyDisableSceneOnMaster = "DisableSceneOnMaster"; - - /// The key that stores the switch for enabling/disabling the rendering on a master - /// computer - static constexpr const char* KeyRenderingMethod = "RenderingMethod"; - - /// The key that determines whether a new cache folder is used for each scene file - static constexpr const char* KeyPerSceneCache = "PerSceneCache"; - - /// The key that stores the http proxy settings for the downloadmanager - static constexpr const char* KeyHttpProxy = "HttpProxy"; - - /// The key that stores the address of the http proxy - static constexpr const char* PartHttpProxyAddress = "Address"; - - /// The key that stores the port of the http proxy - static constexpr const char* PartHttpProxyPort = "Port"; - - /// The key that stores the authentication method of the http proxy - static constexpr const char* PartHttpProxyAuthentication = "Authentication"; - - /// Key that stores the username to use for authentication to access the http proxy - static constexpr const char* PartHttpProxyUser = "User"; - - /// Key that stores the password to use for authentication to access the http proxy - static constexpr const char* PartHttpProxyPassword = "Password"; - - /// The key that stores the dictionary containing information about debug contexts - static constexpr const char* KeyOpenGLDebugContext = "OpenGLDebugContext"; - - /// The part of the key storing whether an OpenGL Debug context should be created - static constexpr const char* PartActivate = "Activate"; - - /// The part of the key storing whether the debug callbacks are performed synchronous - static constexpr const char* PartSynchronous = "Synchronous"; - - /// The part of the key storing a list of identifiers that should be filtered out - static constexpr const char* PartFilterIdentifier = "FilterIdentifier"; - - /// The part of the key that stores the source of the ignored identifier - static constexpr const char* PartFilterIdentifierSource = "Source"; - - /// The part of the key that stores the type of the ignored identifier - static constexpr const char* PartFilterIdentifierType = "Type"; - - /// The part of the key that stores the identifier of the ignored identifier - static constexpr const char* PartFilterIdentifierIdentifier = "Identifier"; - - /// The part of the key storing a list of severities that should be filtered out - static constexpr const char* PartFilterSeverity = "PartFilterSeverity"; - - /// The part of the key storing whether the OpenGL state should be checked each call - static constexpr const char* KeyCheckOpenGLState = "CheckOpenGLState"; - - /// The part of the key storing whether the OpenGL state should be checked each call - static constexpr const char* KeyServerPasskey = "ServerPasskey"; - - /// Whitelist of client addresses that won't need autorization - static constexpr const char* KeyServerClientAddressWhitelist = - "ClientAddressWhitelist"; - - static constexpr const char* KeyLogEachOpenGLCall = "LogEachOpenGLCall"; - - /// This key determines whether the scene graph nodes should initialized multithreaded - static constexpr const char* KeyUseMultithreadedInitialization = - "UseMultithreadedInitialization"; - - /// The key under which all of the loading settings are grouped - static constexpr const char* KeyLoadingScreen = "LoadingScreen"; - - /// The part of the key storing whether the loading screen should display the message - /// about current status - static constexpr const char* KeyLoadingScreenShowMessage = - "LoadingScreen.ShowMessage"; - static constexpr const char* PartShowMessage = "ShowMessage"; - - /// The part of the key storing whether the loading screen should display node names - static constexpr const char* KeyLoadingScreenShowNodeNames = - "LoadingScreen.ShowNodeNames"; - static constexpr const char* PartShowNodeNames = "ShowNodeNames"; - - /// The part of the key storing whether the loading screen should contain a progress - /// bar - static constexpr const char* KeyLoadingScreenShowProgressbar = - "LoadingScreen.ShowProgressbar"; - static constexpr const char* PartShowProgressbar = "ShowProgressbar"; - - /// The key used to specify module specific configurations - static constexpr const char* KeyModuleConfigurations = "ModuleConfigurations"; - - /// The key used to specify whether screenshots should contain the current date - static constexpr const char* KeyScreenshotUseDate = "ScreenshotUseDate"; - - static constexpr const char* KeyWebHelperLocation = "WebHelperLocation"; - static constexpr const char* KeyCefWebGuiUrl = "CefWebGuiUrl"; - - /** - * Iteratively walks the directory structure starting with \p filename to find the - * base name compoenent of \p filename. The directory structure is searched by first - * searching the current directory and then moving iteratively to the the parent - * directory. - * \param filename The fully qualified filename to be searched for - * \return The path to the file that was found with the same base name as \p filename - * but higher up in the file structure. - * \throw ghoul::RuntimeError If the configuration could not be found - */ - static std::string findConfiguration(const std::string& filename); - - /** - * Load the provided configuration file (\p filename) into this Dictionary. All paths - * that are specified in the configuration file will automatically be registered in - * the ghoul::filesystem::FileSystem. - * \param filename The filename to be loaded - * \throw SpecificationError If the configuration file was not complete (i.e., did - * not specify the necessary keys KeyPaths, KeyPaths.KeyCache, KeyFonts, and - * KeyConfigSgct) - * \throw ghoul::lua::LuaRuntimeException If there was Lua-based error loading the - * configuration file - * \pre \p filename must not be empty - * \pre \p filename must exist - */ - void loadFromFile(const std::string& filename); - - - static documentation::Documentation Documentation(); -}; - -} // namespace openspace - -#endif // __OPENSPACE_CORE___CONFIGURATIONMANAGER___H__ diff --git a/include/openspace/engine/moduleengine.h b/include/openspace/engine/moduleengine.h index 57f6766e63..51cf4b43ec 100644 --- a/include/openspace/engine/moduleengine.h +++ b/include/openspace/engine/moduleengine.h @@ -33,6 +33,7 @@ #include #include +#include namespace ghoul::systemcapabilities { struct Version; } @@ -59,7 +60,7 @@ public: * \throw ghoul::RuntimeError If two modules in the default modules have the same * name */ - void initialize(const ghoul::Dictionary& moduleConfigurations); + void initialize(const std::map& moduleConfigurations); /** * Calls the initializeGL functions of all registered OpenSpaceModule%s. diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 8b2e3e49aa..efc6f9b511 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -25,6 +25,7 @@ #ifndef __OPENSPACE_CORE___OPENSPACEENGINE___H__ #define __OPENSPACE_CORE___OPENSPACEENGINE___H__ +#include #include #include #include @@ -43,7 +44,7 @@ namespace ghoul::fontrendering { class FontManager; } namespace openspace { class AssetManager; -class ConfigurationManager; +struct Configuration; class Dashboard; class DownloadManager; class GUI; @@ -60,9 +61,9 @@ class VirtualPropertyManager; class WindowWrapper; namespace interaction { - class NavigationHandler; class KeyBindingManager; -} + class NavigationHandler; +} // namespace interaction namespace gui { class GUI; } namespace properties { class PropertyOwner; } namespace scripting { @@ -111,6 +112,7 @@ public: void mouseButtonCallback(MouseButton button, MouseAction action); void mousePositionCallback(double x, double y); void mouseScrollWheelCallback(double posX, double posY); + void setJoystickInputStates(interaction::JoystickInputStates& states); void externalControlCallback(const char* receivedChars, int size, int clientId); void encode(); void decode(); @@ -119,8 +121,9 @@ public: void scheduleLoadSingleAsset(std::string assetPath); void toggleShutdownMode(); + const Configuration& configuration() const; + // Guaranteed to return a valid pointer - ConfigurationManager& configurationManager(); LuaConsole& console(); AssetManager& assetManager(); Dashboard& dashboard(); @@ -203,8 +206,9 @@ private: void runGlobalCustomizationScripts(); void configureLogging(); + std::unique_ptr _configuration; + // Components - std::unique_ptr _configurationManager; std::unique_ptr _scene; std::unique_ptr _assetManager; std::unique_ptr _dashboard; diff --git a/include/openspace/interaction/mousestate.h b/include/openspace/interaction/camerainteractionstates.h similarity index 70% rename from include/openspace/interaction/mousestate.h rename to include/openspace/interaction/camerainteractionstates.h index 91cebb327b..abf4abff56 100644 --- a/include/openspace/interaction/mousestate.h +++ b/include/openspace/interaction/camerainteractionstates.h @@ -22,56 +22,60 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_CORE___MOUSESTATE___H__ -#define __OPENSPACE_CORE___MOUSESTATE___H__ +#ifndef __OPENSPACE_CORE___INPUTDEVICESTATES___H__ +#define __OPENSPACE_CORE___INPUTDEVICESTATES___H__ #include -#include - #include namespace openspace::interaction { -struct MouseState { - MouseState(double scaleFactor); - void setFriction(double friction); - void setVelocityScaleFactor(double scaleFactor); +class InputState; - glm::dvec2 previousPosition; - DelayedVariable velocity; -}; - -class MouseStates { +class CameraInteractionStates { public: /** * \param sensitivity * \param velocityScaleFactor can be set to 60 to remove the inertia of the * interaction. Lower value will make it harder to move the camera. */ - MouseStates(double sensitivity, double velocityScaleFactor); - void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); + CameraInteractionStates(double sensitivity, double velocityScaleFactor); + virtual ~CameraInteractionStates() = default; + + virtual void updateStateFromInput(const InputState& inputState, double deltaTime) = 0; + void setRotationalFriction(double friction); void setHorizontalFriction(double friction); void setVerticalFriction(double friction); void setSensitivity(double sensitivity); void setVelocityScaleFactor(double scaleFactor); - glm::dvec2 globalRotationMouseVelocity() const; - glm::dvec2 localRotationMouseVelocity() const; - glm::dvec2 truckMovementMouseVelocity() const; - glm::dvec2 localRollMouseVelocity() const; - glm::dvec2 globalRollMouseVelocity() const; + glm::dvec2 globalRotationVelocity() const; + glm::dvec2 localRotationVelocity() const; + glm::dvec2 truckMovementVelocity() const; + glm::dvec2 localRollVelocity() const; + glm::dvec2 globalRollVelocity() const; + +protected: + struct InteractionState { + InteractionState(double scaleFactor); + void setFriction(double friction); + void setVelocityScaleFactor(double scaleFactor); + + glm::dvec2 previousPosition; + DelayedVariable velocity; + }; + -private: double _sensitivity; - MouseState _globalRotationMouseState; - MouseState _localRotationMouseState; - MouseState _truckMovementMouseState; - MouseState _localRollMouseState; - MouseState _globalRollMouseState; + InteractionState _globalRotationState; + InteractionState _localRotationState; + InteractionState _truckMovementState; + InteractionState _localRollState; + InteractionState _globalRollState; }; } // namespace openspace::interaction -#endif // __OPENSPACE_CORE___MOUSESTATE___H__ +#endif // __OPENSPACE_CORE___INPUTDEVICESTATES___H__ diff --git a/include/openspace/interaction/inputdevicestates.h b/include/openspace/interaction/inputdevicestates.h new file mode 100644 index 0000000000..11db6993a0 --- /dev/null +++ b/include/openspace/interaction/inputdevicestates.h @@ -0,0 +1,81 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___CAMERAINTERACTIONSTATES___H__ +#define __OPENSPACE_CORE___CAMERAINTERACTIONSTATES___H__ + +#include +#include + +namespace openspace::interaction { + +class InputState; + +class CameraInteractionStates { +public: + /** + * \param sensitivity + * \param velocityScaleFactor can be set to 60 to remove the inertia of the + * interaction. Lower value will make it harder to move the camera. + */ + CameraInteractionStates(double sensitivity, double velocityScaleFactor); + virtual ~CameraInteractionStates() = default; + + virtual void updateStateFromInput(const InputState& inputState, double deltaTime) = 0; + + void setRotationalFriction(double friction); + void setHorizontalFriction(double friction); + void setVerticalFriction(double friction); + void setSensitivity(double sensitivity); + void setVelocityScaleFactor(double scaleFactor); + + glm::dvec2 globalRotationVelocity() const; + glm::dvec2 localRotationVelocity() const; + glm::dvec2 truckMovementVelocity() const; + glm::dvec2 localRollVelocity() const; + glm::dvec2 globalRollVelocity() const; + +protected: + struct InteractionState { + InteractionState(double scaleFactor); + void setFriction(double friction); + void setVelocityScaleFactor(double scaleFactor); + + glm::dvec2 previousPosition; + DelayedVariable velocity; + }; + + + double _sensitivity; + + InteractionState _globalRotationState; + InteractionState _localRotationState; + InteractionState _truckMovementState; + InteractionState _localRollState; + InteractionState _globalRollState; +}; + +} // namespace openspace::interaction + +#endif // __OPENSPACE_CORE___CAMERAINTERACTIONSTATES___H__ diff --git a/include/openspace/interaction/inputstate.h b/include/openspace/interaction/inputstate.h index 7475a7942f..9ab85ffe8f 100644 --- a/include/openspace/interaction/inputstate.h +++ b/include/openspace/interaction/inputstate.h @@ -25,15 +25,15 @@ #ifndef __OPENSPACE_CORE___INPUTSTATE___H__ #define __OPENSPACE_CORE___INPUTSTATE___H__ +#include #include #include - #include - #include namespace openspace::interaction { +// This class represents the global input state of interaction devices class InputState { public: InputState() = default; @@ -45,22 +45,34 @@ public: void mousePositionCallback(double mouseX, double mouseY); void mouseScrollWheelCallback(double mouseScrollDelta); - // Accessors - const std::list>& getPressedKeys() const; - const std::list& getPressedMouseButtons() const; - glm::dvec2 getMousePosition() const; - double getMouseScrollDelta() const; + void setJoystickInputStates(JoystickInputStates& states); + // Accessors + const std::list>& pressedKeys() const; bool isKeyPressed(std::pair keyModPair) const; bool isKeyPressed(Key key) const; + + const std::list& pressedMouseButtons() const; + glm::dvec2 mousePosition() const; + double mouseScrollDelta() const; bool isMouseButtonPressed(MouseButton mouseButton) const; + const JoystickInputStates& joystickInputStates() const; + float joystickAxis(int i) const; + bool joystickButton(int i) const; + private: - // Input from keyboard and mouse + // Input from keyboard std::list> _keysDown; + + // Input from mouse std::list _mouseButtonsDown; glm::dvec2 _mousePosition; double _mouseScrollDelta; + + // Input from joysticks + // The memory is owned by the outer most main (apps/OpenSpace/main.cpp right now) + JoystickInputStates* _joystickInputStates = nullptr; }; } // namespace openspace::interaction diff --git a/include/openspace/interaction/joystickcamerastates.h b/include/openspace/interaction/joystickcamerastates.h new file mode 100644 index 0000000000..89e19488ee --- /dev/null +++ b/include/openspace/interaction/joystickcamerastates.h @@ -0,0 +1,122 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___JOYSTICKSTATE___H__ +#define __OPENSPACE_CORE___JOYSTICKSTATE___H__ + +#include + +#include +#include +#include +#include +#include + +namespace openspace::interaction { + +class JoystickCameraStates : public CameraInteractionStates { +public: + enum class AxisType { + None = 0, + OrbitX, + OrbitY, + ZoomIn, + ZoomOut, + LocalRollX, + LocalRollY, + GlobalRollX, + GlobalRollY, + PanX, + PanY + }; + + BooleanType(AxisInvert); + BooleanType(AxisNormalize); + BooleanType(ButtonCommandRemote); + + struct AxisInformation { + AxisType type = AxisType::None; + AxisInvert invert = AxisInvert::No; + AxisNormalize normalize = AxisNormalize::No; + + float deadzone = 0.f; + }; + + + JoystickCameraStates(double sensitivity, double velocityScaleFactor); + + void updateStateFromInput(const InputState& inputState, double deltaTime) override; + + void setAxisMapping( + int axis, + AxisType mapping, + AxisInvert shouldInvert = AxisInvert::No, + AxisNormalize shouldNormalize = AxisNormalize::No + ); + + AxisInformation axisMapping(int axis) const; + + void setDeadzone(int axis, float deadzone); + float deadzone(int axis) const; + + + void bindButtonCommand(int button, std::string command, JoystickAction action, + ButtonCommandRemote local); + void clearButtonCommand(int button); + std::vector buttonCommand(int button) const; + +private: + // We use an array for the axes and a map for the buttons since the axis are going to + // be accessed much more often and thus have to be more efficient. And storing a few + // extra AxisInformation that are not used will not matter that much; finding an axis + // location in a potential map each frame, however, would + + std::array _axisMapping; + + struct ButtonInformation { + std::string command; + JoystickAction action; + ButtonCommandRemote synchronization; + std::string documentation; + }; + + std::multimap _buttonMapping; +}; + +} // namespace openspace::interaction + +namespace std { + +std::string to_string(const openspace::interaction::JoystickCameraStates::AxisType& type); + +} // namespace std + +namespace ghoul { + +template <> +openspace::interaction::JoystickCameraStates::AxisType from_string(const std::string& string); + +} // namespace ghoul + +#endif // __OPENSPACE_CORE___JOYSTICKSTATE___H__ diff --git a/include/openspace/interaction/joystickinputstate.h b/include/openspace/interaction/joystickinputstate.h new file mode 100644 index 0000000000..baf75c43d5 --- /dev/null +++ b/include/openspace/interaction/joystickinputstate.h @@ -0,0 +1,126 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___JOYSTICKINPUTSTATE___H__ +#define __OPENSPACE_CORE___JOYSTICKINPUTSTATE___H__ + +#include +#include +#include +#include + +namespace openspace::interaction { + +/** + * Actions that any button of a joystick can have. Each button must be in one of these + * states + */ +enum class JoystickAction : uint8_t { + /// Idle state if the button is unpressed and has been unpressed since last frame + Idle = 0, + /// If the button has been pressed since the last frame + Press, + /// If the button has been pressed since longer than last frame + Repeat, + /// If the button was released since the last frame + Release +}; + +/** + * The input state of a single joystick. + */ +struct JoystickInputState { + /// The maximum number of supported axes + static const int MaxAxes = 8; + /// The maximum number of supported buttons + static const int MaxButtons = 32; + + /// Marks whether this joystick is connected. If this value is \c false, all other + /// members of this struct are undefined + bool isConnected = false; + + /// The name of this joystick + std::string name; + + /// The number of axes that this joystick supports + int nAxes = 0; + /// The values for each axis. Each value is in the range [-1, 1]. Only the first + /// \c nAxes values are defined values, the rest are undefined + std::array axes; + + /// The number of buttons that this joystick possesses + int nButtons = 0; + /// The status of each button. Only the first \c nButtons values are defined, the rest + /// are undefined + std::array buttons; +}; + +/// The maximum number of joysticks that are supported by this system. This number is +/// derived from the available GLFW constants +constexpr const int MaxJoysticks = 16; +struct JoystickInputStates : public std::array { + /** + * This function adds the contributions of all connected joysticks for the provided + * \p axis. After adding each joysticks contribution, the result is clamped to [-1,1]. + * If a joystick does not possess a particular axis, it's does not contribute to the + * sum. + * + * \param axis The numerical axis for which the values are added + * \return The summed axis values of all connected joysticks + * + * \pre \p axis must be 0 or positive + */ + float axis(int axis) const; + + /** + * This functions checks whether any connected joystick has its \p button in the + * passed \p action. Any joystick that does not posses the \p button, it will be + * ignored. + * + * \param button The button that is to be checked + * \param action The action which is checked for each button + * \return \c true if there is at least one joystick whose \param button is in the + * \p action state + * + * \pre \p button must be 0 or positive + */ + bool button(int button, JoystickAction action) const; +}; + +} // namespace openspace::interaction + +namespace std { + +std::string to_string(openspace::interaction::JoystickAction action); + +} // namespace std + +namespace ghoul { + +template <> +openspace::interaction::JoystickAction from_string(const std::string& str); + +} // namespace ghoul + +#endif // __OPENSPACE_CORE___JOYSTICKSTATE___H__ diff --git a/include/openspace/interaction/keybindingmanager.h b/include/openspace/interaction/keybindingmanager.h index c4a47d7631..11138eae38 100644 --- a/include/openspace/interaction/keybindingmanager.h +++ b/include/openspace/interaction/keybindingmanager.h @@ -79,7 +79,6 @@ public: void keyboardCallback(Key key, KeyModifier modifier, KeyAction action); private: - std::string generateJson() const override; std::multimap _keyLua; diff --git a/include/openspace/interaction/controller.h b/include/openspace/interaction/mousecamerastates.h similarity index 83% rename from include/openspace/interaction/controller.h rename to include/openspace/interaction/mousecamerastates.h index 6375de8aa6..6e45af34df 100644 --- a/include/openspace/interaction/controller.h +++ b/include/openspace/interaction/mousecamerastates.h @@ -22,30 +22,20 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_CORE___CONTROLLER___H__ -#define __OPENSPACE_CORE___CONTROLLER___H__ +#ifndef __OPENSPACE_CORE___MOUSECAMERASTATES___H__ +#define __OPENSPACE_CORE___MOUSECAMERASTATES___H__ -#include - -#include -#include +#include namespace openspace::interaction { -class NavigationHandler; - -class Controller { +class MouseCameraStates : public CameraInteractionStates { public: - Controller() : - _handler(nullptr) - {} + MouseCameraStates(double sensitivity, double velocityScaleFactor); - void setHandler(NavigationHandler* handler); - -protected: - NavigationHandler* _handler; + void updateStateFromInput(const InputState& inputState, double deltaTime) override; }; } // namespace openspace::interaction -#endif // __OPENSPACE_CORE___CONTROLLER___H__ +#endif // __OPENSPACE_CORE___MOUSECAMERASTATES___H__ diff --git a/include/openspace/interaction/navigationhandler.h b/include/openspace/interaction/navigationhandler.h index 9ab9e08f20..e906700333 100644 --- a/include/openspace/interaction/navigationhandler.h +++ b/include/openspace/interaction/navigationhandler.h @@ -29,6 +29,8 @@ #include #include +#include +#include #include #include #include @@ -63,7 +65,7 @@ public: void updateCamera(double deltaTime); // Accessors - ghoul::Dictionary getCameraStateDictionary(); + ghoul::Dictionary cameraStateDictionary(); SceneGraphNode* focusNode() const; glm::dvec3 focusNodeToCameraVector() const; glm::quat focusNodeToCameraRotation() const; @@ -74,10 +76,33 @@ public: // Callback functions void keyboardCallback(Key key, KeyModifier modifier, KeyAction action); + void mouseButtonCallback(MouseButton button, MouseAction action); void mousePositionCallback(double x, double y); void mouseScrollWheelCallback(double pos); + void setJoystickInputStates(JoystickInputStates& states); + + void setJoystickAxisMapping( + int axis, + JoystickCameraStates::AxisType mapping, + JoystickCameraStates::AxisInvert shouldInvert = JoystickCameraStates::AxisInvert::No, + JoystickCameraStates::AxisNormalize shouldNormalize = JoystickCameraStates::AxisNormalize::No + ); + + JoystickCameraStates::AxisInformation joystickAxisMapping(int axis) const; + + void setJoystickAxisDeadzone(int axis, float deadzone); + float joystickAxisDeadzone(int axis) const; + + void bindJoystickButtonCommand(int button, std::string command, JoystickAction action, + JoystickCameraStates::ButtonCommandRemote remote); + + void clearJoystickButtonCommand(int button); + std::vector joystickButtonCommand(int button) const; + + + void saveCameraStateToFile(const std::string& filepath); void restoreCameraStateFromFile(const std::string& filepath); diff --git a/include/openspace/interaction/orbitalnavigator.h b/include/openspace/interaction/orbitalnavigator.h index 1329158e79..fb49e46788 100644 --- a/include/openspace/interaction/orbitalnavigator.h +++ b/include/openspace/interaction/orbitalnavigator.h @@ -28,7 +28,8 @@ #include #include #include -#include +#include +#include #include #include @@ -50,11 +51,14 @@ public: OrbitalNavigator(); ~OrbitalNavigator(); - void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); - void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); + void updateStatesFromInput(const InputState& inputState, double deltaTime); + void updateCameraStateFromStates(Camera& camera, double deltaTime); + void setFocusNode(SceneGraphNode* focusNode); void startInterpolateCameraDirection(const Camera& camera); + JoystickCameraStates& joystickStates(); + bool followingNodeRotation() const; SceneGraphNode* focusNode() const; @@ -82,7 +86,9 @@ private: properties::FloatProperty _followFocusNodeRotationDistance; properties::FloatProperty _minimumAllowedDistance; - properties::FloatProperty _sensitivity; + + properties::FloatProperty _mouseSensitivity; + properties::FloatProperty _joystickSensitivity; properties::BoolProperty _useAdaptiveStereoscopicDepth; properties::FloatProperty _stereoscopicDepthOfFocusSurface; @@ -91,7 +97,8 @@ private: properties::FloatProperty _rotateToFocusInterpolationTime; properties::FloatProperty _stereoInterpolationTime; - MouseStates _mouseStates; + MouseCameraStates _mouseStates; + JoystickCameraStates _joystickStates; SceneGraphNode* _focusNode = nullptr; glm::dvec3 _previousFocusNodePosition; @@ -126,14 +133,14 @@ private: * \returns a local camera rotation modified with two degrees of freedom. */ glm::dquat rotateLocally(double deltaTime, - const glm::dquat& localCameraRotation) const; + const glm::dquat& localCameraRotation) const; /** * Interpolates the local rotation towards a 0 rotation. * \returns a modified local rotation interpolated towards 0. */ glm::dquat interpolateLocalRotation(double deltaTime, - const glm::dquat& localCameraRotation); + const glm::dquat& localCameraRotation); double interpolateCameraToSurfaceDistance(double deltaTime, @@ -147,10 +154,9 @@ private: * \returns a position vector adjusted in the horizontal direction. */ glm::dvec3 translateHorizontally(double deltaTime, const glm::dvec3& cameraPosition, - const glm::dvec3& objectPosition, - const glm::dquat& focusNodeRotationDiff, - const glm::dquat& globalCameraRotation, - const SurfacePositionHandle& positionHandle) const; + const glm::dvec3& objectPosition, const glm::dquat& focusNodeRotationDiff, + const glm::dquat& globalCameraRotation, + const SurfacePositionHandle& positionHandle) const; /* * Adds rotation to the camera position so that it follows the rotation of the focus @@ -158,35 +164,32 @@ private: * \returns a position updated with the rotation defined by focusNodeRotationDiff */ glm::dvec3 followFocusNodeRotation(const glm::dvec3& cameraPosition, - const glm::dvec3& objectPosition, - const glm::dquat& focusNodeRotationDiff) const; + const glm::dvec3& objectPosition, const glm::dquat& focusNodeRotationDiff) const; /** * Updates the global rotation so that it points towards the focus node. * \returns a global rotation quaternion defining a rotation towards the focus node. */ glm::dquat rotateGlobally(const glm::dquat& globalCameraRotation, - const glm::dvec3& objectPosition, - const glm::dquat& focusNodeRotationDiff, - const glm::dvec3& cameraPosition, - const SurfacePositionHandle& positionHandle) const; + const glm::dvec3& objectPosition, const glm::dquat& focusNodeRotationDiff, + const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle) const; /** * Translates the camera position towards or away from the focus node. * \returns a position vector adjusted in the vertical direction. */ glm::dvec3 translateVertically(double deltaTime, const glm::dvec3& cameraPosition, - const glm::dvec3& objectPosition, - const SurfacePositionHandle& positionHandle) const; + const glm::dvec3& objectPosition, + const SurfacePositionHandle& positionHandle) const; /** * Rotates the camera around the out vector of the surface. * \returns a quaternion adjusted to rotate around the out vector of the surface. */ glm::dquat rotateHorizontally(double deltaTime, - const glm::dquat& globalCameraRotation, - const glm::dvec3& cameraPosition, - const SurfacePositionHandle& positionHandle) const; + const glm::dquat& globalCameraRotation, const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle) const; /** * Push the camera out to the surface of the object. @@ -194,19 +197,16 @@ private: * above the actual surface of the object */ glm::dvec3 pushToSurface(double minHeightAboveGround, - const glm::dvec3& cameraPosition, - const glm::dvec3& objectPosition, - const SurfacePositionHandle& positionHandle) const; + const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition, + const SurfacePositionHandle& positionHandle) const; /** * Interpolates between rotationDiff and a 0 rotation. */ - glm::dquat interpolateRotationDifferential( - double deltaTime, double interpolationTime, - const glm::dquat& rotationDiff, - const glm::dvec3& objectPosition, - const glm::dvec3& cameraPosition, - const SurfacePositionHandle& positionHandle); + glm::dquat interpolateRotationDifferential(double deltaTime, + double interpolationTime, const glm::dquat& rotationDiff, + const glm::dvec3& objectPosition, const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle); /** * Get the vector from the camera to the surface of the focus object in world space. diff --git a/include/openspace/interaction/luaconsole.h b/include/openspace/rendering/luaconsole.h similarity index 100% rename from include/openspace/interaction/luaconsole.h rename to include/openspace/rendering/luaconsole.h diff --git a/modules/atmosphere/rendering/renderableatmosphere.cpp b/modules/atmosphere/rendering/renderableatmosphere.cpp index 7c42e0d450..cc3cdbd9e2 100644 --- a/modules/atmosphere/rendering/renderableatmosphere.cpp +++ b/modules/atmosphere/rendering/renderableatmosphere.cpp @@ -42,7 +42,6 @@ #include #include -#include #include #include #include diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index a2a17a3ca2..ff893d6891 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/modules/base/rendering/renderablesphericalgrid.cpp b/modules/base/rendering/renderablesphericalgrid.cpp index e59f0a274e..560d85b485 100644 --- a/modules/base/rendering/renderablesphericalgrid.cpp +++ b/modules/base/rendering/renderablesphericalgrid.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include #include diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.cpp b/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.cpp index b4c139a39b..99152c8343 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include // abspath #include @@ -142,64 +142,24 @@ GdalWrapper::GdalWrapper(size_t maximumCacheSize, size_t maximumMaximumCacheSize } void GdalWrapper::setGdalProxyConfiguration() { - ghoul::Dictionary proxySettings; - bool proxyEnabled = OsEng.configurationManager().getValue( - ConfigurationManager::KeyHttpProxy, proxySettings - ); - if (proxyEnabled) { - std::string proxyAddress, proxyPort, proxyUser, proxyPassword, - proxyAuth; + if (OsEng.configuration().httpProxy.usingHttpProxy) { + std::string address = OsEng.configuration().httpProxy.address; + unsigned int port = OsEng.configuration().httpProxy.port; + std::string user = OsEng.configuration().httpProxy.user; + std::string password = OsEng.configuration().httpProxy.password; + std::string auth = OsEng.configuration().httpProxy.authentication; + std::transform(auth.begin(), auth.end(), auth.begin(), ::toupper); - bool success = proxySettings.getValue( - ConfigurationManager::PartHttpProxyAddress, - proxyAddress - ); - success &= proxySettings.getValue( - ConfigurationManager::PartHttpProxyPort, - proxyPort - ); - proxySettings.getValue( - ConfigurationManager::PartHttpProxyAuthentication, - proxyAuth - ); + std::string proxy = address + ":" + std::to_string(port); + CPLSetConfigOption("GDAL_HTTP_PROXY", proxy.c_str()); + LDEBUG(fmt::format("Using proxy server {}", proxy)); - std::string proxyAuthString = "BASIC"; - if (proxyAuth == "basic" || proxyAuth == "") { - proxyAuthString = "BASIC"; - } else if (proxyAuth == "ntlm") { - proxyAuthString = "NTLM"; - } else if (proxyAuth == "digest") { - proxyAuthString = "DIGEST"; - } else if (proxyAuth == "any") { - proxyAuthString = "ANY"; - } else { - success = false; + if (!user.empty() && !password.empty()) { + std::string userPwd = user + ":" + password; + CPLSetConfigOption("GDAL_HTTP_PROXYUSERPWD", userPwd.c_str()); + CPLSetConfigOption("GDAL_HTTP_PROXYAUTH", auth.c_str()); + LDEBUG(fmt::format("Using authentication method: {}", auth)); } - - bool userAndPassword = proxySettings.getValue( - ConfigurationManager::PartHttpProxyUser, - proxyUser - ); - userAndPassword &= proxySettings.getValue( - ConfigurationManager::PartHttpProxyPassword, - proxyPassword - ); - - if (success) { - std::string proxy = proxyAddress + ":" + proxyPort; - CPLSetConfigOption("GDAL_HTTP_PROXY", proxy.c_str()); - LDEBUG(fmt::format("Using proxy server {}", proxy)); - if (userAndPassword) { - std::string proxyUserPwd = proxyUser + ":" + proxyPassword; - CPLSetConfigOption("GDAL_HTTP_PROXYUSERPWD", proxyUserPwd.c_str()); - CPLSetConfigOption("GDAL_HTTP_PROXYAUTH", proxyAuthString.c_str()); - LDEBUG(fmt::format("Using authentication method: {}", proxyAuthString)); - } - } else { - LERROR("Invalid proxy settings for GDAL"); - } - } else { - LDEBUG("Setting up GDAL without proxy server"); } } diff --git a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp index 80693eac88..14826c1b3a 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp @@ -38,8 +38,6 @@ #include #include -#include - #include #include #include diff --git a/modules/imgui/CMakeLists.txt b/modules/imgui/CMakeLists.txt index f590d19d58..01a5cf9ccf 100644 --- a/modules/imgui/CMakeLists.txt +++ b/modules/imgui/CMakeLists.txt @@ -33,6 +33,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/guifilepathcomponent.h ${CMAKE_CURRENT_SOURCE_DIR}/include/guiglobebrowsingcomponent.h ${CMAKE_CURRENT_SOURCE_DIR}/include/guihelpcomponent.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/guijoystickcomponent.h ${CMAKE_CURRENT_SOURCE_DIR}/include/guimissioncomponent.h ${CMAKE_CURRENT_SOURCE_DIR}/include/guiperformancecomponent.h ${CMAKE_CURRENT_SOURCE_DIR}/include/guiparallelcomponent.h @@ -51,6 +52,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/guifilepathcomponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/guiglobebrowsingcomponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/guihelpcomponent.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/guijoystickcomponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/guimissioncomponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/guiperformancecomponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/guiparallelcomponent.cpp diff --git a/modules/imgui/imguimodule.cpp b/modules/imgui/imguimodule.cpp index 86642533ba..81a3db3408 100644 --- a/modules/imgui/imguimodule.cpp +++ b/modules/imgui/imguimodule.cpp @@ -31,9 +31,9 @@ #include #include #include -#include #include #include +#include #include #include #include diff --git a/modules/imgui/include/gui.h b/modules/imgui/include/gui.h index f4646ec0ef..4626ea1cd6 100644 --- a/modules/imgui/include/gui.h +++ b/modules/imgui/include/gui.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -87,6 +88,7 @@ public: #ifdef OPENSPACE_MODULE_ISWA_ENABLED GuiIswaComponent _iswa; #endif // OPENSPACE_MODULE_ISWA_ENABLED + GuiJoystickComponent _joystick; GuiParallelComponent _parallel; GuiPropertyComponent _featuredProperties; diff --git a/src/interaction/controller.cpp b/modules/imgui/include/guijoystickcomponent.h similarity index 83% rename from src/interaction/controller.cpp rename to modules/imgui/include/guijoystickcomponent.h index 0b52cf7cf1..9b891d00e9 100644 --- a/src/interaction/controller.cpp +++ b/modules/imgui/include/guijoystickcomponent.h @@ -22,15 +22,20 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#ifndef __OPENSPACE_MODULE_IMGUI___GUIJOYSTICKCOMPONENT___H__ +#define __OPENSPACE_MODULE_IMGUI___GUIJOYSTICKCOMPONENT___H__ -#include +#include -namespace openspace::interaction { +namespace openspace::gui { -void Controller::setHandler(NavigationHandler* handler) { - _handler = handler; -} +class GuiJoystickComponent : public GuiComponent { +public: + GuiJoystickComponent(); -} // namespace openspace::interaction + void render() override; +}; +} // namespace openspace::gui + +#endif // __OPENSPACE_MODULE_IMGUI___GUIJOYSTICKCOMPONENT___H__ diff --git a/modules/imgui/src/gui.cpp b/modules/imgui/src/gui.cpp index 0e1ec88796..032080ef21 100644 --- a/modules/imgui/src/gui.cpp +++ b/modules/imgui/src/gui.cpp @@ -160,60 +160,6 @@ static void RenderDrawLists(ImDrawData* drawData) { } } - - //// Grow our buffer according to what we need - //size_t totalVertexCount = 0; - //for (int i = 0; i < nCommandLists; ++i) - // totalVertexCount += commandLists[i]->vtx_buffer.size(); - - //glBindBuffer(GL_ARRAY_BUFFER, vbo); - //size_t neededBufferSize = totalVertexCount * sizeof(ImDrawVert); - //if (neededBufferSize > vboMaxSize) { - // // Grow buffer - // vboMaxSize = neededBufferSize * 1.25f; - // glBufferData(GL_ARRAY_BUFFER, vboMaxSize, NULL, GL_STREAM_DRAW); - //} - - //// Copy and convert all vertices into a single contiguous buffer - //unsigned char* bufferData = reinterpret_cast( - // glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY) - // ); - - //if (!bufferData) { - // LFATAL("Error mapping ImGui buffer"); - // return; - //} - - //for (int i = 0; i < nCommandLists; ++i) { - // const ImDrawList* cmd_list = commandLists[i]; - // memcpy( - // bufferData, - // &cmd_list->vtx_buffer[0], - // cmd_list->vtx_buffer.size() * sizeof(ImDrawVert) - // ); - // bufferData += (cmd_list->vtx_buffer.size() * sizeof(ImDrawVert)); - //} - //glUnmapBuffer(GL_ARRAY_BUFFER); - //glBindBuffer(GL_ARRAY_BUFFER, 0); - //glBindVertexArray(vao); - - //int cmdOffset = 0; - //for (int i = 0; i < nCommandLists; ++i) { - // const ImDrawList* cmd_list = commandLists[i]; - // int vtxOffset = cmdOffset; - // for (const auto& pcmd : cmd_list->commands) { - // glScissor( - // static_cast(pcmd.clip_rect.x), - // static_cast(height - pcmd.clip_rect.w), - // static_cast(pcmd.clip_rect.z - pcmd.clip_rect.x), - // static_cast(pcmd.clip_rect.w - pcmd.clip_rect.y) - // ); - // glDrawArrays(GL_TRIANGLES, vtxOffset, pcmd.vtx_count); - // vtxOffset += pcmd.vtx_count; - // } - // cmdOffset = vtxOffset; - //} - glBindVertexArray(0); _program->deactivate(); glDisable(GL_SCISSOR_TEST); @@ -310,6 +256,7 @@ GUI::GUI() #ifdef GLOBEBROWSING_USE_GDAL addPropertySubOwner(_globeBrowsing); #endif // GLOBEBROWSING_USE_GDAL + addPropertySubOwner(_joystick); addPropertySubOwner(_filePath); addPropertySubOwner(_asset); _spaceTime.setEnabled(true); @@ -337,6 +284,7 @@ GUI::GUI() #ifdef OPENSPACE_MODULE_ISWA_ENABLED _iswa.setShowHelpTooltip(_showHelpText); #endif // OPENSPACE_MODULE_ISWA_ENABLED + _joystick.setShowHelpTooltip(_showHelpText); _parallel.setShowHelpTooltip(_showHelpText); _featuredProperties.setShowHelpTooltip(_showHelpText); }; @@ -363,6 +311,7 @@ GUI::GUI() #ifdef OPENSPACE_MODULE_ISWA_ENABLED _iswa.setShowHelpTooltipDelay(_helpTextDelay); #endif // OPENSPACE_MODULE_ISWA_ENABLED + _joystick.setShowHelpTooltipDelay(_helpTextDelay); _parallel.setShowHelpTooltipDelay(_helpTextDelay); _featuredProperties.setShowHelpTooltipDelay(_helpTextDelay); }; @@ -502,6 +451,7 @@ void GUI::initialize() { #ifdef GLOBEBROWSING_USE_GDAL _globeBrowsing.initialize(); #endif // GLOBEBROWSING_USE_GDAL + _joystick.initialize(); _performance.initialize(); _help.initialize(); _parallel.initialize(); @@ -525,6 +475,7 @@ void GUI::deinitialize() { _mission.deinitialize(); _parallel.deinitialize(); _help.deinitialize(); + _joystick.deinitialize(); _performance.deinitialize(); _globalProperty.deinitialize(); _moduleProperty.deinitialize(); @@ -629,6 +580,7 @@ void GUI::initializeGL() { _globalProperty.initializeGL(); _moduleProperty.initializeGL(); _featuredProperties.initializeGL(); + _joystick.initializeGL(); _performance.initializeGL(); _help.initializeGL(); #ifdef GLOBEBROWSING_USE_GDAL @@ -667,6 +619,7 @@ void GUI::deinitializeGL() { _performance.deinitializeGL(); _featuredProperties.deinitializeGL(); _globalProperty.deinitializeGL(); + _joystick.deinitializeGL(); _moduleProperty.deinitializeGL(); _screenSpaceProperty.deinitializeGL(); #ifdef GLOBEBROWSING_USE_GDAL @@ -744,6 +697,11 @@ void GUI::endFrame() { _iswa.render(); } #endif // OPENSPACE_MODULE_ISWA_ENABLED + + if (_joystick.isEnabled()) { + _joystick.render(); + } + if (_filePath.isEnabled()) { _filePath.render(); } @@ -883,6 +841,10 @@ void GUI::render() { ImGui::Checkbox("Mission Information", &mission); _mission.setEnabled(mission); + bool joystick = _joystick.isEnabled(); + ImGui::Checkbox("Joystick Information", &joystick); + _joystick.setEnabled(joystick); + bool filePath = _filePath.isEnabled(); ImGui::Checkbox("File Paths", &filePath); _filePath.setEnabled(filePath); diff --git a/modules/imgui/src/guijoystickcomponent.cpp b/modules/imgui/src/guijoystickcomponent.cpp new file mode 100644 index 0000000000..03c49fdbd6 --- /dev/null +++ b/modules/imgui/src/guijoystickcomponent.cpp @@ -0,0 +1,111 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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 + +namespace { + const ImVec2 Size = ImVec2(350, 500); +} // namespace + +namespace openspace::gui { + +GuiJoystickComponent::GuiJoystickComponent() + : GuiComponent("joystick_information", "Joystick Information") +{} + +void GuiJoystickComponent::render() { + using namespace interaction; + + ImGui::SetNextWindowCollapsed(_isCollapsed); + + bool v = _isEnabled; + ImGui::Begin("Joystick Information", &v, Size, 0.5f); + _isEnabled = v; + _isCollapsed = ImGui::IsWindowCollapsed(); + + const JoystickInputStates& states = + OsEng.navigationHandler().inputState().joystickInputStates(); + + for (int i = 0; i < states.size(); ++i) { + const JoystickInputState& state = states[i]; + if (!state.isConnected) { + continue; + } + + ImGui::Text("%s [%i]", state.name.c_str(), i); + ImGui::Text("%s", "Axes"); + for (int j = 0; j < state.nAxes; ++j) { + float f = state.axes[j]; + ImGui::SliderFloat( + std::to_string(j).c_str(), + &f, + -1.f, + 1.f + ); + } + ImGui::Text("%s", "Buttons"); + for (int j = 0; j < state.nButtons; ++j) { + ImGui::RadioButton( + std::to_string(j).c_str(), + state.buttons[j] == JoystickAction::Press || + state.buttons[j] == JoystickAction::Repeat + ); + } + + ImGui::Separator(); + } + + ImGui::Separator(); + ImGui::Separator(); + + ImGui::Text("%s", "Summed contributions"); + ImGui::Text("%s", "Axes"); + for (int i = 0; i < JoystickInputState::MaxAxes; ++i) { + float f = states.axis(i); + ImGui::SliderFloat( + std::to_string(i).c_str(), + &f, + -1.f, + 1.f + ); + } + ImGui::Text("%s", "Buttons"); + for (int i = 0; i < JoystickInputState::MaxButtons; ++i) { + ImGui::RadioButton( + std::to_string(i).c_str(), + states.button(i, JoystickAction::Press) || + states.button(i, JoystickAction::Repeat) + ); + } + + ImGui::End(); +} + +} // namespace openspace::gui diff --git a/modules/multiresvolume/rendering/renderablemultiresvolume.cpp b/modules/multiresvolume/rendering/renderablemultiresvolume.cpp index 2c4defa9fe..f23dd643e2 100644 --- a/modules/multiresvolume/rendering/renderablemultiresvolume.cpp +++ b/modules/multiresvolume/rendering/renderablemultiresvolume.cpp @@ -24,7 +24,6 @@ #include -#include #include #include #include diff --git a/modules/server/include/connection.h b/modules/server/include/connection.h index 3cc26508f2..c025a6b667 100644 --- a/modules/server/include/connection.h +++ b/modules/server/include/connection.h @@ -34,7 +34,6 @@ #include #include #include -#include #include "topic.h" diff --git a/modules/server/src/connection.cpp b/modules/server/src/connection.cpp index e6e4e7a0fb..bc7eab0b11 100644 --- a/modules/server/src/connection.cpp +++ b/modules/server/src/connection.cpp @@ -23,6 +23,7 @@ ****************************************************************************************/ #include + #include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include namespace { constexpr const char* _loggerCat = "ServerModule: Connection"; @@ -67,15 +69,7 @@ Connection::Connection(std::shared_ptr s, const std::string & _topicFactory.registerClass(BounceTopicKey); // see if the default config for requiring auth (on) is overwritten - const bool hasAuthConfiguration = OsEng.configurationManager().hasKeyAndValue( - ConfigurationManager::KeyRequireSocketAuthentication - ); - if (hasAuthConfiguration) { - _requireAuthorization = OsEng.configurationManager().value( - ConfigurationManager::KeyRequireSocketAuthentication); - } else { - _requireAuthorization = true; - } + _requireAuthorization = OsEng.configuration().doesRequireSocketAuthentication; } void Connection::handleMessage(std::string message) { @@ -186,16 +180,8 @@ void Connection::setAuthorized(const bool status) { } bool Connection::isWhitelisted() { - const bool hasWhitelist = OsEng.configurationManager().hasKeyAndValue( - ConfigurationManager::KeyServerClientAddressWhitelist); - - if (!hasWhitelist) { - return false; - } - - const auto whitelist = OsEng.configurationManager().value( - ConfigurationManager::KeyServerClientAddressWhitelist); - return whitelist.find(_address) != std::string::npos; + const std::vector& wl = OsEng.configuration().clientAddressWhitelist; + return std::find(wl.begin(), wl.end(), _address) != wl.end(); } } // namespace openspace diff --git a/modules/server/src/topics/authorizationtopic.cpp b/modules/server/src/topics/authorizationtopic.cpp index c693dad79c..dc7c811c4b 100644 --- a/modules/server/src/topics/authorizationtopic.cpp +++ b/modules/server/src/topics/authorizationtopic.cpp @@ -24,15 +24,18 @@ #include "include/authorizationtopic.h" +#include + namespace { -std::string _loggerCat = "AuthorizationTopic"; -} + constexpr const char* _loggerCat = "AuthorizationTopic"; +} // namespace namespace openspace { - AuthorizationTopic::AuthorizationTopic() - : Topic() - , _isAuthenticated(false) {}; +AuthorizationTopic::AuthorizationTopic() + : Topic() + , _isAuthenticated(false) +{}; bool AuthorizationTopic::isDone() { return _isAuthenticated; @@ -69,14 +72,7 @@ bool AuthorizationTopic::authorize(const std::string key) { } const std::string AuthorizationTopic::getKey() const { - bool hasConfigPassword = OsEng.configurationManager().hasKeyAndValue( - ConfigurationManager::KeyServerPasskey); - if (hasConfigPassword) { - return OsEng.configurationManager().value( - ConfigurationManager::KeyServerPasskey); - } - - return "17308"; + return OsEng.configuration().serverPasskey; } nlohmann::json AuthorizationTopic::message(const std::string& message, diff --git a/modules/server/src/topics/getpropertytopic.cpp b/modules/server/src/topics/getpropertytopic.cpp index d9e1c2387f..c109634d41 100644 --- a/modules/server/src/topics/getpropertytopic.cpp +++ b/modules/server/src/topics/getpropertytopic.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include diff --git a/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp b/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp index 9abaf7762f..4cb55d409e 100644 --- a/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp +++ b/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #include #include diff --git a/modules/sync/syncmodule.cpp b/modules/sync/syncmodule.cpp index 1a42018370..b206a5c177 100644 --- a/modules/sync/syncmodule.cpp +++ b/modules/sync/syncmodule.cpp @@ -30,7 +30,6 @@ #include #include -#include #include #include #include diff --git a/openspace.cfg b/openspace.cfg index a26f21e652..351927681a 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -2,136 +2,139 @@ -- require('scripts/configuration_helper.lua') -- which defines helper functions useful to customize the configuration -return { - -- Determines which SGCT configuration file is loaded, that is, if there rendering - -- occurs in a single window, a fisheye projection, or a dome cluster system +-- Determines which SGCT configuration file is loaded, that is, if there rendering +-- occurs in a single window, a fisheye projection, or a dome cluster system - -- A regular 1280x720 window - SGCTConfig = sgct.config.single{}, +-- A regular 1280x720 window +SGCTConfig = sgct.config.single{} - -- A regular 1920x1080 window - -- SGCTConfig = sgct.config.single{1920, 1080}, +-- A regular 1920x1080 window +-- SGCTConfig = sgct.config.single{1920, 1080} - -- A windowed 1920x1080 fullscreen - -- SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}, shared=true, name="WV_OBS_SPOUT1"}, +-- A windowed 1920x1080 fullscreen +-- SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}, shared=true, name="WV_OBS_SPOUT1"} - -- A 1k fisheye rendering - -- SGCTConfig = sgct.config.fisheye{1024, 1024}, +-- A 1k fisheye rendering +-- SGCTConfig = sgct.config.fisheye{1024, 1024} - -- A 4k fisheye rendering in a 1024x1024 window - -- SGCTConfig = sgct.config.fisheye{1024, 1024, res={4096, 4096}, quality="2k", tilt=27}, +-- A 4k fisheye rendering in a 1024x1024 window +-- SGCTConfig = sgct.config.fisheye{1024, 1024, res={4096, 4096}, quality="2k", tilt=27} - -- Streaming OpenSpace via Spout to OBS - -- SGCTConfig = sgct.config.single{2560, 1440, shared=true, name="WV_OBS_SPOUT1"}, +-- Streaming OpenSpace via Spout to OBS +-- SGCTConfig = sgct.config.single{2560, 1440, shared=true, name="WV_OBS_SPOUT1"} - -- SGCTConfig = "${CONFIG}/spout_output.xml", - -- SGCTConfig = "${CONFIG}/stereo.xml", +-- Stereo +-- SGCTConfig = "${CONFIG}/stereo.xml", - --SGCTConfig = "${CONFIG}/openvr_oculusRiftCv1.xml", - --SGCTConfig = "${CONFIG}/openvr_htcVive.xml", +-- Spout exit +-- SGCTConfig = "${CONFIG}/spout_output.xml" - -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description - -- of all entities that will be visible during an instance of OpenSpace - Asset = "default", - -- Asset = "default_full", - -- Asset = "newhorizons", - -- Asset = "rosetta", - -- Asset = "osirisrex", - -- Asset = "voyager", +--SGCTConfig = "${CONFIG}/openvr_oculusRiftCv1.xml" +--SGCTConfig = "${CONFIG}/openvr_htcVive.xml" - -- These scripts are executed after the initialization of each scene, thus making - -- it possible to have global overrides to default values or execute other scripts - -- regardless of the scene that is loaded - GlobalCustomizationScripts = { - "${SCRIPTS}/customization.lua" +-- Sets the scene that is to be loaded by OpenSpace. A scene file is a description +-- of all entities that will be visible during an instance of OpenSpace + +Asset = "default" +-- Asset = "default_full" +-- Asset = "newhorizons" +-- Asset = "rosetta" +-- Asset = "osirisrex" +-- Asset = "voyager" + +-- These scripts are executed after the initialization of each scene, thus making +-- it possible to have global overrides to default values or execute other scripts +-- regardless of the scene that is loaded +GlobalCustomizationScripts = { + "${SCRIPTS}/customization.lua" +} + +Paths = { + DATA = "${BASE}/data", + ASSETS = "${DATA}/assets", + FONTS = "${DATA}/fonts", + TASKS = "${DATA}/tasks", + SYNC = "${BASE}/sync", + SCREENSHOTS = "${BASE}/screenshots", + WEB = "${DATA}/web", + + CACHE = "${BASE}/cache", + CONFIG = "${BASE}/config", + DOCUMENTATION = "${BASE}/documentation", + LOGS = "${BASE}/logs", + MODULES = "${BASE}/modules", + SCRIPTS = "${BASE}/scripts", + SHADERS = "${BASE}/shaders" +} +Fonts = { + Mono = "${FONTS}/Bitstream-Vera-Sans-Mono/VeraMono.ttf", + Light = "${FONTS}/Roboto/Roboto-Regular.ttf", + Console = "${FONTS}/Inconsolata/Inconsolata-Regular.ttf", + Loading = "${FONTS}/Roboto/Roboto-Regular.ttf" +} +Logging = { + LogDir = "${LOGS}", + -- LogLevel = "Trace", + LogLevel = "Debug", + ImmediateFlush = true, + Logs = { + { Type = "html", File = "${LOGS}/log.html", Append = false } }, + CapabilitiesVerbosity = "Full" +} +ScriptLog = "${LOGS}/ScriptLog.txt" - Paths = { - DATA = "${BASE}/data", - ASSETS = "${DATA}/assets", - FONTS = "${DATA}/fonts", - TASKS = "${DATA}/tasks", - SYNC = "${BASE}/sync", - SCREENSHOTS = "${BASE}/screenshots", - WEB = "${DATA}/web", - - CACHE = "${BASE}/cache", - CONFIG = "${BASE}/config", - DOCUMENTATION = "${BASE}/documentation", - LOGS = "${BASE}/logs", - MODULES = "${BASE}/modules", - SCRIPTS = "${BASE}/scripts", - SHADERS = "${BASE}/shaders" - }, - Fonts = { - Mono = "${FONTS}/Bitstream-Vera-Sans-Mono/VeraMono.ttf", - Light = "${FONTS}/Roboto/Roboto-Regular.ttf", - Console = "${FONTS}/Inconsolata/Inconsolata-Regular.ttf", - Loading = "${FONTS}/Roboto/Roboto-Regular.ttf" - }, - Logging = { - LogDir = "${LOGS}", - -- LogLevel = "Trace", - LogLevel = "Debug", - ImmediateFlush = true, - Logs = { - { Type = "html", File = "${LOGS}/log.html", Append = false } - }, - CapabilitiesVerbosity = "Full" - }, - ScriptLog = "${LOGS}/ScriptLog.txt", - - Launcher = { - LogLevel = "None" - }, +Documentation = { LuaDocumentation = "${DOCUMENTATION}/LuaScripting.html", PropertyDocumentation = "${DOCUMENTATION}/Properties.html", ScenePropertyDocumentation = "${DOCUMENTATION}/SceneProperties.html", KeyboardShortcuts = "${DOCUMENTATION}/KeyboardMapping.html", Documentation = "${DOCUMENTATION}/Documentation.html", FactoryDocumentation = "${DOCUMENTATION}/FactoryDocumentation.html", - LicenseDocumentation = "${DOCUMENTATION}/License.html", - - UseMultithreadedInitialization = true, - LoadingScreen = { - ShowMessage = true, - ShowNodeNames = true, - ShowProgressbar = true - }, - CheckOpenGLState = false, - LogEachOpenGLCall = false, - - ShutdownCountdown = 3, - ScreenshotUseDate = true, - -- OnScreenTextScaling = "framebuffer", - -- PerSceneCache = true, - -- DisableRenderingOnMaster = true, - -- DisableSceneOnMaster = true, - ModuleConfigurations = { - Sync = { - SynchronizationRoot = "${SYNC}", - HttpSynchronizationRepositories = { - "data.openspaceproject.com/request" - } - } - }, - RenderingMethod = "Framebuffer", - OpenGLDebugContext = { - Activate = false, - FilterIdentifier = { - { Type = "Other", Source = "API", Identifier = 131185 }, - { Type = "Performance", Source = "API", Identifier = 131186 }, --Buffer performance warning: "copied/moved from VIDEO memory to HOST memory" - { Type = "Deprecated", Source = "API", Identifier = 7} -- API_ID_LINE_WIDTH deprecated behavior warning has been generated - }, --- FilterSeverity = { } - }, - --RenderingMethod = "ABuffer" -- alternative: "Framebuffer", - - ServerPasskey = "secret!", - ClientAddressWhitelist = "127.0.0.1 localhost", - WebHelperLocation = "${BASE}/bin/Release/openspace_web_helper", - -- CefWebGuiUrl = "file://${BASE_PATH}/gui/index.html#/onscreen/" - CefWebGuiUrl = "http://localhost:8080/#/onscreen/" } + +UseMultithreadedInitialization = true +LoadingScreen = { + ShowMessage = true, + ShowNodeNames = true, + ShowProgressbar = true +} +CheckOpenGLState = false +LogEachOpenGLCall = false + +ShutdownCountdown = 3 +ScreenshotUseDate = true +-- OnScreenTextScaling = "framebuffer" +-- PerSceneCache = true +-- DisableRenderingOnMaster = true +-- DisableSceneOnMaster = true +ModuleConfigurations = { + Sync = { + SynchronizationRoot = "${SYNC}", + HttpSynchronizationRepositories = { + "data.openspaceproject.com/request" + } + } +} +RenderingMethod = "Framebuffer" +OpenGLDebugContext = { + Activate = false, + FilterIdentifier = { + { Type = "Other", Source = "API", Identifier = 131185 }, + { Type = "Performance", Source = "API", Identifier = 131186 }, --Buffer performance warning: "copied/moved from VIDEO memory to HOST memory" + { Type = "Deprecated", Source = "API", Identifier = 7} -- API_ID_LINE_WIDTH deprecated behavior warning has been generated + }, +-- FilterSeverity = { } +} +--RenderingMethod = "ABuffer" -- alternative: "Framebuffer" + +ServerPasskey = "secret!" +ClientAddressWhitelist = { + "127.0.0.1", + "localhost" +} +WebHelperLocation = "${BASE}/bin/Release/openspace_web_helper" +-- CefWebGuiUrl = "file://${BASE_PATH}/gui/index.html#/onscreen/" +CefWebGuiUrl = "http://localhost:8080/#/onscreen/" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e592f4d3e2..a58f401cc2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,8 +31,10 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/documentation/documentationengine.cpp ${OPENSPACE_BASE_DIR}/src/documentation/documentationgenerator.cpp ${OPENSPACE_BASE_DIR}/src/documentation/verifier.cpp - ${OPENSPACE_BASE_DIR}/src/engine/configurationmanager.cpp - ${OPENSPACE_BASE_DIR}/src/engine/configurationmanager_doc.inl + ${OPENSPACE_BASE_DIR}/src/engine/configuration.cpp + ${OPENSPACE_BASE_DIR}/src/engine/configuration_doc.inl + # ${OPENSPACE_BASE_DIR}/src/engine/configurationmanager.cpp + # ${OPENSPACE_BASE_DIR}/src/engine/configurationmanager_doc.inl ${OPENSPACE_BASE_DIR}/src/engine/downloadmanager.cpp ${OPENSPACE_BASE_DIR}/src/engine/logfactory.cpp ${OPENSPACE_BASE_DIR}/src/engine/moduleengine.cpp @@ -42,15 +44,16 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/engine/virtualpropertymanager.cpp ${OPENSPACE_BASE_DIR}/src/engine/wrapper/sgctwindowwrapper.cpp ${OPENSPACE_BASE_DIR}/src/engine/wrapper/windowwrapper.cpp - ${OPENSPACE_BASE_DIR}/src/interaction/controller.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/camerainteractionstates.cpp ${OPENSPACE_BASE_DIR}/src/interaction/inputstate.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/joystickinputstate.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/joystickcamerastates.cpp ${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager.cpp ${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager_lua.inl ${OPENSPACE_BASE_DIR}/src/interaction/keyframenavigator.cpp - ${OPENSPACE_BASE_DIR}/src/interaction/luaconsole.cpp ${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler.cpp ${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler_lua.inl - ${OPENSPACE_BASE_DIR}/src/interaction/mousestate.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/mousecamerastates.cpp ${OPENSPACE_BASE_DIR}/src/interaction/orbitalnavigator.cpp ${OPENSPACE_BASE_DIR}/src/mission/mission.cpp ${OPENSPACE_BASE_DIR}/src/mission/missionmanager.cpp @@ -128,6 +131,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/rendering/framebufferrenderer.cpp ${OPENSPACE_BASE_DIR}/src/rendering/deferredcastermanager.cpp ${OPENSPACE_BASE_DIR}/src/rendering/loadingscreen.cpp + ${OPENSPACE_BASE_DIR}/src/rendering/luaconsole.cpp ${OPENSPACE_BASE_DIR}/src/rendering/raycastermanager.cpp ${OPENSPACE_BASE_DIR}/src/rendering/renderable.cpp ${OPENSPACE_BASE_DIR}/src/rendering/renderengine.cpp @@ -200,7 +204,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/documentation/documentationgenerator.h ${OPENSPACE_BASE_DIR}/include/openspace/documentation/verifier.h ${OPENSPACE_BASE_DIR}/include/openspace/documentation/verifier.inl - ${OPENSPACE_BASE_DIR}/include/openspace/engine/configurationmanager.h + ${OPENSPACE_BASE_DIR}/include/openspace/engine/configuration.h ${OPENSPACE_BASE_DIR}/include/openspace/engine/downloadmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/engine/logfactory.h ${OPENSPACE_BASE_DIR}/include/openspace/engine/moduleengine.h @@ -209,16 +213,17 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/engine/virtualpropertymanager.h ${OPENSPACE_BASE_DIR}/include/openspace/engine/wrapper/sgctwindowwrapper.h ${OPENSPACE_BASE_DIR}/include/openspace/engine/wrapper/windowwrapper.h - ${OPENSPACE_BASE_DIR}/include/openspace/interaction/controller.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.inl + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/camerainteractionstates.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/inputstate.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/interpolator.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/interpolator.inl + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/joystickinputstate.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/joystickcamerastates.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/keybindingmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/keyframenavigator.h - ${OPENSPACE_BASE_DIR}/include/openspace/interaction/luaconsole.h - ${OPENSPACE_BASE_DIR}/include/openspace/interaction/mousestate.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/mousecamerastates.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/navigationhandler.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/orbitalnavigator.h ${OPENSPACE_BASE_DIR}/include/openspace/mission/mission.h @@ -305,6 +310,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcasterlistener.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcastermanager.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/loadingscreen.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/luaconsole.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/raycasterlistener.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/raycastermanager.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/renderable.h diff --git a/src/documentation/core_registration.cpp b/src/documentation/core_registration.cpp index 0c1db348bc..01d5a297fe 100644 --- a/src/documentation/core_registration.cpp +++ b/src/documentation/core_registration.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -52,7 +51,6 @@ namespace openspace { void registerCoreClasses(documentation::DocumentationEngine& engine) { - engine.addDocumentation(ConfigurationManager::Documentation()); engine.addDocumentation(LogFactoryDocumentation()); engine.addDocumentation(Mission::Documentation()); engine.addDocumentation(Renderable::Documentation()); diff --git a/src/engine/configuration.cpp b/src/engine/configuration.cpp new file mode 100644 index 0000000000..f74e601bf5 --- /dev/null +++ b/src/engine/configuration.cpp @@ -0,0 +1,350 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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 + +namespace { + constexpr const char* BasePathToken = "${BASE}"; + // We can't use ${SCRIPTS} here as that hasn't been defined by this point + constexpr const char* InitialConfigHelper = + "${BASE}/scripts/configuration_helper.lua"; + + // Variable names for the openspace.cfg file + // These are also used in the _doc include file + constexpr const char* KeySGCTConfig = "SGCTConfig"; + constexpr const char* KeyAsset = "Asset"; + constexpr const char* KeyGlobalCustomizationScripts = "GlobalCustomizationScripts"; + constexpr const char* KeyPaths = "Paths"; + constexpr const char* KeyPathsCACHE = "Paths.CACHE"; + constexpr const char* KeyFonts = "Fonts"; + constexpr const char* KeyLogging = "Logging"; + constexpr const char* KeyLogDir = "LogDir"; + constexpr const char* KeyPerformancePrefix = "PerformancePrefix"; + constexpr const char* KeyLogLevel = "LogLevel"; + constexpr const char* KeyImmediateFlush = "ImmediateFlush"; + constexpr const char* KeyLogs = "Logs"; + constexpr const char* KeyCapabilitiesVerbosity = "CapabilitiesVerbosity"; + constexpr const char* KeyLuaDocumentation = "LuaDocumentation"; + constexpr const char* KeyPropertyDocumentation = "PropertyDocumentation"; + constexpr const char* KeyScriptLog = "ScriptLog"; + constexpr const char* KeyKeyboardShortcuts = "KeyboardShortcuts"; + constexpr const char* KeyDocumentation = "Documentation"; + constexpr const char* KeyFactoryDocumentation = "FactoryDocumentation"; + constexpr const char* KeyRequireSocketAuthentication = "RequireSocketAuthentication"; + constexpr const char* KeyServerPasskey = "ServerPasskey"; + constexpr const char* KeyClientAddressWhitelist = "ClientAddressWhitelist"; + constexpr const char* KeyLicenseDocumentation = "LicenseDocumentation"; + constexpr const char* KeyShutdownCountdown = "ShutdownCountdown"; + constexpr const char* KeyPerSceneCache = "PerSceneCache"; + constexpr const char* KeyOnScreenTextScaling = "OnScreenTextScaling"; + constexpr const char* KeyRenderingMethod = "RenderingMethod"; + constexpr const char* KeyDisableRenderingOnMaster = "DisableRenderingOnMaster"; + constexpr const char* KeyDisableSceneOnMaster = "DisableSceneOnMaster"; + constexpr const char* KeyScreenshotUseDate = "ScreenshotUseDate"; + constexpr const char* KeyHttpProxy = "HttpProxy"; + constexpr const char* KeyAddress = "Address"; + constexpr const char* KeyPort = "Port"; + constexpr const char* KeyAuthentication = "Authentication"; + constexpr const char* KeyUser = "User"; + constexpr const char* KeyPassword = "Password"; + constexpr const char* KeyOpenGLDebugContext = "OpenGLDebugContext"; + constexpr const char* KeyActivate = "Activate"; + constexpr const char* KeySynchronous = "Synchronous"; + constexpr const char* KeyFilterIdentifier = "FilterIdentifier"; + constexpr const char* KeyIdentifier = "Identifier"; + constexpr const char* KeySource = "Source"; + constexpr const char* KeyType = "Type"; + constexpr const char* KeyFilterSeverity = "FilterSeverity"; + constexpr const char* KeyCheckOpenGLState = "CheckOpenGLState"; + constexpr const char* KeyLogEachOpenGLCall = "LogEachOpenGLCall"; + constexpr const char* KeyUseMultithreadedInitialization = + "UseMultithreadedInitialization"; + constexpr const char* KeyLoadingScreen = "LoadingScreen"; + constexpr const char* KeyShowMessage = "ShowMessage"; + constexpr const char* KeyShowNodeNames = "ShowNodeNames"; + constexpr const char* KeyShowProgressbar = "ShowProgressbar"; + constexpr const char* KeyModuleConfigurations = "ModuleConfigurations"; +} // namespace + +#include "configuration_doc.inl" + +namespace openspace { + +template +void getValue(ghoul::lua::LuaState& L, const char* name, T& value) { + auto it = std::find_if( + Configuration::Documentation.entries.begin(), + Configuration::Documentation.entries.end(), + [name](const documentation::DocumentationEntry& e) { + return e.key == name; + } + ); + + bool isOptional = + it != Configuration::Documentation.entries.end() + ? it->optional : + true; + + lua_getglobal(L, name); + if (isOptional && lua_isnil(L, -1)) { + return; + } + + if (!isOptional && lua_isnil(L, -1)) { + documentation::TestResult testResult = { + false, + { { name, documentation::TestResult::Offense::Reason::MissingKey} }, + {} + }; + throw documentation::SpecificationError(std::move(testResult), "Configuration"); + } + + if constexpr (std::is_same_v>) { + ghoul::Dictionary d = ghoul::lua::value(L); + + std::vector res; + for (size_t i = 1; i <= d.size(); ++i) { + res.push_back(d.value(std::to_string(i))); + } + value = res; + } + else if constexpr (std::is_same_v>) { + ghoul::Dictionary d = ghoul::lua::value(L); + + std::map res; + for (size_t i = 0; i < d.size(); ++i) { + std::string key = d.keys()[i]; + std::string v = d.value(key); + res[std::move(key)] = std::move(v); + } + value = res; + } + else if constexpr (std::is_same_v>) { + ghoul::Dictionary d = ghoul::lua::value(L); + + std::map res; + for (size_t i = 0; i < d.size(); ++i) { + std::string key = d.keys()[i]; + ghoul::Dictionary v = d.value(key); + res[std::move(key)] = std::move(v); + } + value = res; + } + else if constexpr (std::is_same_v) { + Configuration::Logging& v = static_cast(value); + ghoul::Dictionary d = ghoul::lua::value(L); + + d.getValue(KeyLogLevel, v.level); + d.getValue(KeyLogDir, v.directory); + d.getValue(KeyPerformancePrefix, v.performancePrefix); + d.getValue(KeyImmediateFlush, v.forceImmediateFlush); + d.getValue(KeyCapabilitiesVerbosity, v.capabilitiesVerbosity); + + if (d.hasKeyAndValue(KeyLogs)) { + ghoul::Dictionary l = d.value(KeyLogs); + std::vector res; + for (size_t i = 1; i <= l.size(); ++i) { + res.push_back(l.value(std::to_string(i))); + } + v.logs = res; + } + } + else if constexpr (std::is_same_v) { + Configuration::DocumentationInfo& v = + static_cast(value); + ghoul::Dictionary d = ghoul::lua::value(L); + + d.getValue(KeyLuaDocumentation, v.lua); + d.getValue(KeyPropertyDocumentation, v.property); + d.getValue("ScenePropertyDocumentation", v.sceneProperty); + d.getValue(KeyKeyboardShortcuts, v.keyboard); + d.getValue(KeyDocumentation, v.documentation); + d.getValue(KeyFactoryDocumentation, v.factory); + d.getValue(KeyLicenseDocumentation, v.license); + } + else if constexpr (std::is_same_v) { + Configuration::LoadingScreen& v = + static_cast(value); + ghoul::Dictionary d = ghoul::lua::value(L); + + d.getValue(KeyShowMessage, v.isShowingMessages); + d.getValue(KeyShowNodeNames, v.isShowingNodeNames); + d.getValue(KeyShowProgressbar, v.isShowingProgressbar); + } + else if constexpr (std::is_same_v) { + Configuration::OpenGLDebugContext& v = + static_cast(value); + ghoul::Dictionary d = ghoul::lua::value(L); + + d.getValue(KeyActivate, v.isActive); + d.getValue(KeySynchronous, v.isSynchronous); + + if (d.hasKeyAndValue(KeyFilterIdentifier)) { + ghoul::Dictionary f = d.value(KeyFilterIdentifier); + + std::vector res; + for (size_t i = 1; i <= f.size(); ++i) { + Configuration::OpenGLDebugContext::IdentifierFilter filter; + ghoul::Dictionary fi = f.value(std::to_string(i)); + + double id = static_cast(filter.identifier); + fi.getValue(KeyIdentifier, id); + filter.identifier = static_cast(id); + fi.getValue(KeySource, filter.source); + fi.getValue(KeyType, filter.type); + + res.push_back(filter); + } + + v.identifierFilters = res; + } + + if (d.hasKeyAndValue(KeyFilterSeverity)) { + ghoul::Dictionary f = d.value(KeyFilterSeverity); + + std::vector res; + for (size_t i = 1; i <= f.size(); ++i) { + res.push_back(f.value(std::to_string(i))); + } + v.severityFilters = res; + } + } + else if constexpr (std::is_same_v) { + Configuration::HTTPProxy& v = static_cast(value); + ghoul::Dictionary d = ghoul::lua::value(L); + + d.getValue(KeyActivate, v.usingHttpProxy); + d.getValue(KeyAddress, v.address); + double p = static_cast(v.port); + d.getValue(KeyPort, p); + v.port = static_cast(p); + d.getValue(KeyAuthentication, v.authentication); + d.getValue(KeyUser, v.user); + d.getValue(KeyPassword, v.password); + } + else { + value = ghoul::lua::value(L); + } +} + +void parseLuaState(Configuration& configuration) { + using namespace ghoul::lua; + + // Shorten the rest of this function + Configuration& c = configuration; + LuaState& s = c.state; + + getValue(s, KeySGCTConfig, c.windowConfiguration); + getValue(s, KeyAsset, c.asset); + getValue(s, KeyGlobalCustomizationScripts, c.globalCustomizationScripts); + getValue(s, KeyPaths, c.pathTokens); + getValue(s, KeyFonts, c.fonts); + getValue(s, KeyScriptLog, c.scriptLog); + getValue(s, KeyUseMultithreadedInitialization, c.useMultithreadedInitialization); + getValue(s, KeyCheckOpenGLState, c.isCheckingOpenGLState); + getValue(s, KeyLogEachOpenGLCall, c.isLoggingOpenGLCalls); + getValue(s, KeyShutdownCountdown, c.shutdownCountdown); + getValue(s, KeyScreenshotUseDate, c.shouldUseScreenshotDate); + getValue(s, KeyOnScreenTextScaling, c.onScreenTextScaling); + getValue(s, KeyPerSceneCache, c.usePerSceneCache); + getValue(s, KeyDisableRenderingOnMaster, c.isRenderingOnMasterDisabled); + getValue(s, KeyDisableSceneOnMaster, c.isSceneTranslationOnMasterDisabled); + getValue(s, KeyRenderingMethod, c.renderingMethod); + getValue(s, KeyServerPasskey, c.serverPasskey); + getValue(s, KeyRequireSocketAuthentication, c.doesRequireSocketAuthentication); + getValue(s, KeyClientAddressWhitelist, c.clientAddressWhitelist); + getValue(s, "WebHelperLocation", c.webHelperLocation); + getValue(s, "CefWebGuiUrl", c.cefWebGuiUrl); + + getValue(s, KeyLogging, c.logging); + getValue(s, KeyDocumentation, c.documentation); + getValue(s, KeyLoadingScreen, c.loadingScreen); + getValue(s, KeyModuleConfigurations, c.moduleConfigurations); + getValue(s, KeyOpenGLDebugContext, c.openGLDebugContext); + getValue(s, KeyHttpProxy, c.httpProxy); +} + +std::string findConfiguration(const std::string& filename) { + using ghoul::filesystem::Directory; + + Directory directory = FileSys.currentDirectory(); + + while (true) { + std::string fullPath = FileSys.pathByAppendingComponent( + directory, + filename + ); + + if (FileSys.fileExists(fullPath)) { + // We have found the configuration file and can bail out + return fullPath; + } + + // Otherwise, we traverse the directory tree up + Directory nextDirectory = directory.parentDirectory( + ghoul::filesystem::Directory::AbsolutePath::Yes + ); + + if (directory.path() == nextDirectory.path()) { + // We have reached the root of the file system and did not find the file + throw ghoul::RuntimeError( + "Could not find configuration file '" + filename + "'", + "ConfigurationManager" + ); + } + directory = nextDirectory; + } +} + +Configuration loadConfigurationFromFile(const std::string& filename) { + ghoul_assert(!filename.empty(), "Filename must not be empty"); + ghoul_assert(FileSys.fileExists(filename), "File must exist"); + + Configuration result; + + // Register the base path as the directory where 'filename' lives + std::string basePath = ghoul::filesystem::File(filename).directoryName(); + FileSys.registerPathToken(BasePathToken, basePath); + + // If there is an initial config helper file, load it into the state + if (FileSys.fileExists(absPath(InitialConfigHelper))) { + ghoul::lua::runScriptFile(result.state, absPath(InitialConfigHelper)); + } + + // Load the configuration file into the state + ghoul::lua::runScriptFile(result.state, filename); + + parseLuaState(result); + + return result; +} + +} // namespace openspace diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configuration_doc.inl similarity index 74% rename from src/engine/configurationmanager_doc.inl rename to src/engine/configuration_doc.inl index a365448508..69b76c9381 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configuration_doc.inl @@ -27,22 +27,20 @@ namespace openspace { -documentation::Documentation ConfigurationManager::Documentation() { - using namespace documentation; - - return { - "OpenSpace Configuration", - "openspace_configuraion", +using namespace documentation; +documentation::Documentation Configuration::Documentation = { + "OpenSpace Configuration", + "openspace_configuraion", + { { - { - ConfigurationManager::KeyConfigSgct, + KeySGCTConfig, new StringAnnotationVerifier("A valid SGCT configuration file"), Optional::No, "The SGCT configuration file that determines the window and view frustum " "settings that are being used when OpenSpace is started." }, { - ConfigurationManager::KeyConfigAsset, + KeyAsset, new StringAnnotationVerifier( "A valid scene file as described in the Scene documentation" ), @@ -53,7 +51,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "the Scene documentation." }, { - ConfigurationManager::KeyGlobalCustomizationScripts, + KeyGlobalCustomizationScripts, new StringListVerifier, Optional::Yes, "This value names a list of scripts that get executed after initialization " @@ -61,7 +59,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "such as a global rebinding of keys from the default." }, { - ConfigurationManager::KeyPaths, + KeyPaths, new StringListVerifier, Optional::No, "A list of paths that are automatically registered with the file system. " @@ -69,14 +67,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "in all other configuration files or scripts." }, { - ConfigurationManager::KeyCachePath, - new StringVerifier, - Optional::No, - "The path to be used as a cache folder. If per scene caching is enabled, the " - "name of the scene will be appended to this folder" - }, - { - ConfigurationManager::KeyFonts, + KeyFonts, new StringListVerifier("Font paths loadable by FreeType"), Optional::Yes, "A list of all fonts that will automatically be loaded on startup. Each " @@ -84,23 +75,23 @@ documentation::Documentation ConfigurationManager::Documentation() { "for a font." }, { - ConfigurationManager::KeyLogging, + KeyLogging, new TableVerifier({ { - ConfigurationManager::PartLogDir, + KeyLogDir, new StringVerifier, Optional::Yes, "The directory for logs. Default value is \"${BASE}\"" }, { - ConfigurationManager::PartLogPerformancePrefix, + KeyPerformancePrefix, new StringVerifier, Optional::Yes, "A string to prefix PerformanceMeasurement logfiles." "Default value is \"PM-\"" }, { - ConfigurationManager::PartLogLevel, + KeyLogLevel, new StringInListVerifier( // List from logmanager.cpp::levelFromString { "Trace", "Debug", "Info", "Warning", "Error", "Fatal", "None" } @@ -112,7 +103,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "severities is: Debug < Info < Warning < Error < Fatal < None." }, { - ConfigurationManager::PartImmediateFlush, + KeyImmediateFlush, new BoolVerifier, Optional::Yes, "Determines whether error messages will be displayed immediately " @@ -122,7 +113,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "logged." }, { - ConfigurationManager::PartLogs, + KeyLogs, new TableVerifier({ { "*", @@ -138,7 +129,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "be used additionally." }, { - ConfigurationManager::PartCapabilitiesVerbosity, + KeyCapabilitiesVerbosity, new StringInListVerifier( // List from OpenspaceEngine::initialize { "None", "Minimal", "Default", "Full" } @@ -154,22 +145,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "other information." }, { - ConfigurationManager::KeyLuaDocumentation, - new StringVerifier, - Optional::Yes, - "The filename that will be created on startup containing the documentation " - "of available Lua functions that can be executed in scene files or per " - "console. Any existing file will be silently overwritten." - }, - { - ConfigurationManager::KeyPropertyDocumentation, - new StringVerifier, - Optional::Yes, - "The file that will be created on startup containing a list of all " - "properties in the scene. Any existing file will be silently overwritten." - }, - { - ConfigurationManager::KeyScriptLog, + KeyScriptLog, new StringVerifier, Optional::Yes, "The file that will be created on startup containing the log of all Lua " @@ -177,78 +153,84 @@ documentation::Documentation ConfigurationManager::Documentation() { "the results from previous runs) will be silently overwritten." }, { - ConfigurationManager::KeyKeyboardShortcuts, - new StringVerifier, + KeyDocumentation, + new TableVerifier({ + { + KeyLuaDocumentation, + new StringVerifier, + Optional::Yes, + "The filename that will be created on startup containing the " + "documentation of available Lua functions that can be executed in " + "scene files or per console. Any existing file will be silently " + "overwritten." + }, + { + KeyPropertyDocumentation, + new StringVerifier, + Optional::Yes, + "The file that will be created on startup containing a list of all " + "properties in the scene. Any existing file will be silently " + "overwritten." + }, + { + KeyKeyboardShortcuts, + new StringVerifier, + Optional::Yes, + "The file that will be created on startup containing the list of all " + "keyboard bindings with their respective Lua scripts. For each key, " + "it mentions which scripts will be executed in the current session." + }, + { + KeyDocumentation, + new StringVerifier, + Optional::Yes, + "The file that will be created on startup containing this " + "documentation. Any previous file in this location will be silently " + "overwritten." + }, + { + KeyFactoryDocumentation, + new StringVerifier, + Optional::Yes, + "The file that will be created on startup containing the factory " + "documentation which shows the different types of objects that can " + "be created in the current application configuration. Any previous " + "file in this location will be silently overritten." + }, + { + KeyLicenseDocumentation, + new StringVerifier, + Optional::Yes, + "The file that will be created on startup containing the scene " + "license information. Any previous file in this location will be " + "silently overwritten." + }, + }), Optional::Yes, - "The file that will be created on startup containing the list of all " - "keyboard bindings with their respective Lua scripts. For each key, it " - "mentions which scripts will be executed in the current session." + "All documentations that are generated at application startup." }, { - ConfigurationManager::KeyDocumentation, - new StringVerifier, - Optional::Yes, - "The file that will be created on startup containing this documentation. Any " - "previous file in this location will be silently overwritten." - }, - { - ConfigurationManager::KeyFactoryDocumentation, - new StringVerifier, - Optional::Yes, - "The file that will be created on startup containing the factory " - "documentation which shows the different types of objects that can be " - "created in the current application configuration. Any previous file in this " - "location will be silently overritten." - }, - { - ConfigurationManager::KeyRequireSocketAuthentication, + KeyRequireSocketAuthentication, new BoolVerifier, Optional::Yes, "If socket connections should be authenticated or not before they are " "allowed to get or set information. Defaults to 'true'." }, { - ConfigurationManager::KeyServerPasskey, + KeyServerPasskey, new StringVerifier, Optional::Yes, "Passkey to limit server access. Used to authorize incoming connections." }, { - ConfigurationManager::KeyServerClientAddressWhitelist, - new StringVerifier, + KeyClientAddressWhitelist, + new StringListVerifier, Optional::Yes, - "String containing white listed client IP addresses that won't need to be " + "String containing white listed client IP addresses that won't need to be" "authorized with the server. Space separated" }, { - ConfigurationManager::KeySceneLicenseDocumentation, - new StringVerifier, - Optional::Yes, - "The file that will be created on startup containing the scene license " - "information. Any previous file in this location will be silently " - "overwritten." - }, - { - ConfigurationManager::KeyLauncher, - new TableVerifier({ - { - ConfigurationManager::PartLogLevel, - new StringInListVerifier( - // List from logmanager.cpp::levelFromString - { "Trace", "Debug", "Info", "Warning", "Error", "Fatal", "None" } - ), - Optional::Yes, - "The severity of log messages that will be displayed. Only " - "messages of the selected level or higher will be displayed. All " - "levels below will be silently discarded. The order of " - "severities is: Debug < Info < Warning < Error < Fatal < None." - }, - }), - Optional::Yes, - "Configurations for the Launcher & syncing application." - }, - { - ConfigurationManager::KeyShutdownCountdown, + KeyShutdownCountdown, new DoubleGreaterEqualVerifier(0.0), Optional::Yes, "The countdown that the application will wait between pressing ESC and " @@ -256,7 +238,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "shutdown is aborted." }, { - ConfigurationManager::KeyPerSceneCache, + KeyPerSceneCache, new BoolVerifier, Optional::Yes, "If this is set to 'true', the name of the scene will be appended to the " @@ -265,7 +247,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "the caches should be retained. This value defaults to 'false'." }, { - ConfigurationManager::KeyOnScreenTextScaling, + KeyOnScreenTextScaling, new StringInListVerifier({ // Values from RenderEngine:updateRenderer "window", "framebuffer" @@ -277,7 +259,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "rendering resolution ('framebuffer'). This value defaults to 'window'." }, { - ConfigurationManager::KeyRenderingMethod, + KeyRenderingMethod, new StringInListVerifier( // List from RenderEngine::setRendererFromString { "Framebuffer", "ABuffer" } @@ -287,7 +269,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "support for at least OpenGL 4.3" }, { - ConfigurationManager::KeyDisableMasterRendering, + KeyDisableRenderingOnMaster, new BoolVerifier, Optional::Yes, "Toggles whether the master in a multi-application setup should be rendering " @@ -295,7 +277,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "the master computer does not have the resources to render a scene." }, { - ConfigurationManager::KeyDisableSceneOnMaster, + KeyDisableSceneOnMaster, new BoolVerifier, Optional::Yes, "Toggles whether a potential scene transformation matrix, for example as " @@ -305,7 +287,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "default is false." }, { - ConfigurationManager::KeyScreenshotUseDate, + KeyScreenshotUseDate, new BoolVerifier, Optional::Yes, "Toggles whether screenshots generated by OpenSpace contain the date when " @@ -314,22 +296,28 @@ documentation::Documentation ConfigurationManager::Documentation() { "individual frames pass beyond local midnight." }, { - ConfigurationManager::KeyHttpProxy, + KeyHttpProxy, new TableVerifier({ { - ConfigurationManager::PartHttpProxyAddress, + KeyActivate, + new BoolVerifier, + Optional::Yes, + "Determines whether the proxy is being used" + }, + { + KeyAddress, new StringVerifier, Optional::No, "The address of the http proxy" }, { - ConfigurationManager::PartHttpProxyPort, - new StringVerifier, + KeyPort, + new IntVerifier, Optional::No, "The port of the http proxy" }, { - ConfigurationManager::PartHttpProxyAuthentication, + KeyAuthentication, new StringInListVerifier( { "basic", "ntlm", "digest", "any" } ), @@ -337,13 +325,13 @@ documentation::Documentation ConfigurationManager::Documentation() { "The authentication method of the http proxy" }, { - ConfigurationManager::PartHttpProxyUser, + KeyUser, new StringVerifier, Optional::Yes, "The user of the http proxy" }, { - ConfigurationManager::PartHttpProxyPassword, + KeyPassword, new StringVerifier, Optional::Yes, "The password of the http proxy" @@ -354,16 +342,16 @@ documentation::Documentation ConfigurationManager::Documentation() { "No proxy will be used if this is left out." }, { - ConfigurationManager::KeyOpenGLDebugContext, + KeyOpenGLDebugContext, new TableVerifier({ { - ConfigurationManager::PartActivate, + KeyActivate, new BoolVerifier, Optional::No, "Determines whether the OpenGL context should be a debug context" }, { - ConfigurationManager::PartSynchronous, + KeySynchronous, new BoolVerifier, Optional::Yes, "Determines whether the OpenGL debug callbacks are performed " @@ -372,18 +360,18 @@ documentation::Documentation ConfigurationManager::Documentation() { "triggered the message. The default value is ." }, { - ConfigurationManager::PartFilterIdentifier, + KeyFilterIdentifier, new TableVerifier({{ "*", new TableVerifier({ { - ConfigurationManager::PartFilterIdentifierIdentifier, + KeyIdentifier, new IntVerifier, Optional::No, "The identifier that is to be filtered" }, { - ConfigurationManager::PartFilterIdentifierSource, + KeySource, new StringInListVerifier({ // Taken from ghoul::debugcontext.cpp "API", "Window System", "Shader Compiler", @@ -393,7 +381,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "The source of the identifier to be filtered" }, { - ConfigurationManager::PartFilterIdentifierType, + KeyType, new StringInListVerifier({ // Taken from ghoul::debugcontext.cpp "Error", "Deprecated", "Undefined", "Portability", @@ -411,7 +399,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "A list of OpenGL debug messages identifiers that are filtered" }, { - ConfigurationManager::PartFilterSeverity, + KeyFilterSeverity, new TableVerifier({ { "*", @@ -430,7 +418,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "Determines the settings for the creation of an OpenGL debug context.", }, { - ConfigurationManager::KeyCheckOpenGLState, + KeyCheckOpenGLState, new BoolVerifier, Optional::Yes, "Determines whether the OpenGL state is checked after each OpenGL function " @@ -438,7 +426,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "OpenGL errors easier. This defaults to 'false'." }, { - ConfigurationManager::KeyLogEachOpenGLCall, + KeyLogEachOpenGLCall, new BoolVerifier, Optional::Yes, "Determines whether each OpenGL call that happens should be logged using the " @@ -447,7 +435,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "defaults to 'false'." }, { - ConfigurationManager::KeyUseMultithreadedInitialization, + KeyUseMultithreadedInitialization, new BoolVerifier, Optional::Yes, "This value determines whether the initialization of the scene graph should " @@ -456,17 +444,17 @@ documentation::Documentation ConfigurationManager::Documentation() { "debugging support." }, { - ConfigurationManager::KeyLoadingScreen, + KeyLoadingScreen, new TableVerifier({ { - ConfigurationManager::PartShowMessage, + KeyShowMessage, new BoolVerifier, Optional::Yes, "If this value is set to 'true', the loading screen will display a " "message information about the current phase the loading is in." }, { - ConfigurationManager::PartShowNodeNames, + KeyShowNodeNames, new BoolVerifier, Optional::Yes, "If this value is set to 'true', the loading screen will display a " @@ -474,7 +462,7 @@ documentation::Documentation ConfigurationManager::Documentation() { "loaded, initialized)." }, { - ConfigurationManager::PartShowProgressbar, + KeyShowProgressbar, new BoolVerifier, Optional::Yes, "If this value is set to 'true', the loading screen will contain a " @@ -486,14 +474,12 @@ documentation::Documentation ConfigurationManager::Documentation() { "displayed while the scene graph is created and initialized." }, { - ConfigurationManager::KeyModuleConfigurations, + KeyModuleConfigurations, new TableVerifier, Optional::Yes, "Configurations for each module" } - } - }; -} - + } +}; } // namespace openspace diff --git a/src/engine/configurationmanager.cpp b/src/engine/configurationmanager.cpp deleted file mode 100644 index 9db7940a23..0000000000 --- a/src/engine/configurationmanager.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * 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 - -using std::string; - -#include "configurationmanager_doc.inl" - -namespace { - const char* _configurationFile = "openspace.cfg"; - const char* _keyBasePath = "BASE"; - // We can't use ${SCRIPTS} here as that hasn't been defined by this point - const char* _initialConfigHelper = "${BASE}/scripts/configuration_helper.lua"; -} // namespace - -namespace openspace { - -string ConfigurationManager::findConfiguration(const string& filename) { - using ghoul::filesystem::Directory; - - Directory directory = FileSys.currentDirectory(); - - while (true) { - std::string fullPath = FileSys.pathByAppendingComponent( - directory, - _configurationFile - ); - - if (FileSys.fileExists(fullPath)) { - // We have found the configuration file and can bail out - return fullPath; - } - - // Otherwise, we traverse the directory tree up - Directory nextDirectory = directory.parentDirectory( - ghoul::filesystem::Directory::AbsolutePath::Yes - ); - - if (directory.path() == nextDirectory.path()) { - // We have reached the root of the file system and did not find the file - throw ghoul::RuntimeError( - "Could not find configuration file '" + filename + "'", - "ConfigurationManager" - ); - } - directory = nextDirectory; - } -} - -void ConfigurationManager::loadFromFile(const string& filename) { - using ghoul::filesystem::FileSystem; - - ghoul_assert(!filename.empty(), "Filename must not be empty"); - ghoul_assert(FileSys.fileExists(filename), "File must exist"); - - // ${BASE} - string basePathToken = FileSystem::TokenOpeningBraces + string(_keyBasePath) + - FileSystem::TokenClosingBraces; - - // Retrieving the directory in which the configuration file lies - string basePath = ghoul::filesystem::File(filename).directoryName(); - FileSys.registerPathToken(basePathToken, basePath); - - ghoul::lua::LuaState state; - - if (FileSys.fileExists(absPath(_initialConfigHelper))) { - ghoul::lua::runScriptFile(state, absPath(_initialConfigHelper)); - } - - // Loading the configuration file into ourselves - ghoul::lua::loadDictionaryFromFile(filename, *this, state); - - // Perform testing against the documentation/specification - openspace::documentation::testSpecificationAndThrow( - ConfigurationManager::Documentation(), - *this, - "ConfigurationManager" - ); - - // Register all the paths - ghoul::Dictionary dictionary = value(KeyPaths); - - for (std::string key : dictionary.keys()) { - std::string p = dictionary.value(key); - std::string fullKey = - FileSystem::TokenOpeningBraces + key + FileSystem::TokenClosingBraces; - LDEBUGC("ConfigurationManager", - fmt::format("Registering path {}: {}", fullKey, p) - ); - - bool override = (basePathToken == fullKey); - if (override) { - LINFOC( - "ConfigurationManager", - fmt::format("Overriding base path with '{}'", p) - ); - } - - using Override = ghoul::filesystem::FileSystem::Override; - FileSys.registerPathToken( - std::move(fullKey), - std::move(p), - override ? Override::Yes : Override::No - ); - } - - // Remove the Paths dictionary from the configuration manager as those paths might - // change later and we don't want to be forced to keep our local copy up to date - removeKey(KeyPaths); -} - -} // namespace openspace diff --git a/src/engine/moduleengine.cpp b/src/engine/moduleengine.cpp index d43b403abd..547c11a30d 100644 --- a/src/engine/moduleengine.cpp +++ b/src/engine/moduleengine.cpp @@ -46,12 +46,15 @@ ModuleEngine::ModuleEngine() : properties::PropertyOwner({"Modules"}) {} -void ModuleEngine::initialize(const ghoul::Dictionary& moduleConfigurations) { +void ModuleEngine::initialize( + const std::map& moduleConfigurations) +{ for (OpenSpaceModule* m : AllModules()) { const std::string identifier = m->identifier(); + auto it = moduleConfigurations.find(identifier); ghoul::Dictionary configuration; - if (moduleConfigurations.hasKey(identifier)) { - moduleConfigurations.getValue(identifier, configuration); + if (it != moduleConfigurations.end()) { + configuration = it->second; } registerModule(std::unique_ptr(m), configuration); } diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 5b38e33d3c..5692c9b85a 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -28,16 +28,15 @@ #include #include -#include +#include #include #include #include #include #include #include -#include #include -#include +#include #include #include @@ -46,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -111,7 +111,6 @@ using namespace ghoul::cmdparser; namespace { constexpr const char* _loggerCat = "OpenSpaceEngine"; - constexpr const char* SgctDefaultConfigFile = "${CONFIG}/single.xml"; constexpr const char* SgctConfigArgumentCommand = "-config"; @@ -150,7 +149,7 @@ OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr; OpenSpaceEngine::OpenSpaceEngine(std::string programName, std::unique_ptr windowWrapper) - : _configurationManager(new ConfigurationManager) + : _configuration(new Configuration) , _scene(nullptr) , _dashboard(new Dashboard) , _downloadManager(nullptr) @@ -293,7 +292,7 @@ void OpenSpaceEngine::create(int argc, char** argv, // Parse commandline arguments std::vector args(argv, argv + argc); - const std::vector& arguments = + std::vector arguments = _engine->_commandlineParser->setCommandLine(args); bool showHelp = _engine->_commandlineParser->execute(); @@ -302,15 +301,14 @@ void OpenSpaceEngine::create(int argc, char** argv, requestClose = true; return; } - std::vector argumentsCopy = arguments; - sgctArguments = std::move(argumentsCopy); + + sgctArguments = std::move(arguments); // Find configuration std::string configurationFilePath = commandlineArgumentPlaceholders.configurationName; if (configurationFilePath.empty()) { LDEBUG("Finding configuration"); - configurationFilePath = - ConfigurationManager::findConfiguration(configurationFilePath); + configurationFilePath = findConfiguration(); } configurationFilePath = absPath(configurationFilePath); @@ -324,7 +322,7 @@ void OpenSpaceEngine::create(int argc, char** argv, // Loading configuration from disk LDEBUG("Loading configuration from disk"); try { - _engine->configurationManager().loadFromFile(configurationFilePath); + *_engine->_configuration = loadConfigurationFromFile(configurationFilePath); } catch (const documentation::SpecificationError& e) { LFATAL(fmt::format( @@ -346,19 +344,45 @@ void OpenSpaceEngine::create(int argc, char** argv, throw; } + + // Registering Path tokens. If the BASE path is set, it is the only one that will + // overwrite the default path of the cfg directory + for (const std::pair& path : + _engine->_configuration->pathTokens) + { + std::string fullKey = + FileSystem::TokenOpeningBraces + path.first + FileSystem::TokenClosingBraces; + LDEBUGC( + "ConfigurationManager", + fmt::format("Registering path {}: {}", fullKey, path.second) + ); + + bool override = (fullKey == "${BASE}"); + if (override) { + LINFOC( + "ConfigurationManager", + fmt::format("Overriding base path with '{}'", path.second) + ); + } + + using Override = ghoul::filesystem::FileSystem::Override; + FileSys.registerPathToken( + std::move(fullKey), + std::move(path.second), + override ? Override::Yes : Override::No + ); + } + + const bool hasCacheCommandline = !commandlineArgumentPlaceholders.cacheFolder.empty(); - const bool hasCacheConfig = _engine->configurationManager().hasKeyAndValue( - ConfigurationManager::KeyPerSceneCache - ); + const bool hasCacheConfig = _engine->_configuration->usePerSceneCache; std::string cacheFolder = absPath("${CACHE}"); if (hasCacheCommandline || hasCacheConfig) { if (hasCacheCommandline) { cacheFolder = commandlineArgumentPlaceholders.cacheFolder; } if (hasCacheConfig) { - std::string scene = _engine->configurationManager().value( - ConfigurationManager::KeyConfigAsset - ); + std::string scene = _engine->_configuration->asset; cacheFolder += "-" + ghoul::filesystem::File(scene).baseName(); } @@ -385,18 +409,8 @@ void OpenSpaceEngine::create(int argc, char** argv, LINFOC("OpenSpace Version", std::string(OPENSPACE_VERSION_STRING_FULL)); LINFOC("Commit", std::string(OPENSPACE_GIT_FULL)); - ghoul::Dictionary moduleConfigurations; - if (_engine->configurationManager().hasKeyAndValue( - ConfigurationManager::KeyModuleConfigurations)) - { - _engine->configurationManager().getValue( - ConfigurationManager::KeyModuleConfigurations, - moduleConfigurations - ); - } - // Register modules - _engine->_moduleEngine->initialize(moduleConfigurations); + _engine->_moduleEngine->initialize(_engine->_configuration->moduleConfigurations); // After registering the modules, the documentations for the available classes // can be added as well @@ -406,6 +420,8 @@ void OpenSpaceEngine::create(int argc, char** argv, } } + DocEng.addDocumentation(Configuration::Documentation); + // Create the cachemanager try { FileSys.createCacheManager(cacheFolder, CacheVersion); @@ -420,10 +436,8 @@ void OpenSpaceEngine::create(int argc, char** argv, // Determining SGCT configuration file LDEBUG("Determining SGCT configuration file"); - std::string sgctConfigurationPath = SgctDefaultConfigFile; - _engine->configurationManager().getValue( - ConfigurationManager::KeyConfigSgct, sgctConfigurationPath); - + std::string sgctConfigurationPath = _engine->_configuration->windowConfiguration; + if (!commandlineArgumentPlaceholders.sgctConfigurationName.empty()) { LDEBUG(fmt::format( "Overwriting SGCT configuration file with commandline argument: {}", @@ -509,27 +523,24 @@ void OpenSpaceEngine::initialize() { LDEBUG("Detecting capabilities"); SysCap.detectCapabilities(); - using Verbosity = ghoul::systemcapabilities::SystemCapabilitiesComponent::Verbosity; - Verbosity verbosity = Verbosity::Default; - if (configurationManager().hasKey(ConfigurationManager::KeyCapabilitiesVerbosity)) { - static const std::map VerbosityMap = { - { "None", Verbosity::None }, - { "Minimal", Verbosity::Minimal }, - { "Default", Verbosity::Default }, - { "Full", Verbosity::Full } - }; - std::string v = configurationManager().value( - ConfigurationManager::KeyCapabilitiesVerbosity - ); - ghoul_assert( - VerbosityMap.find(v) != VerbosityMap.end(), - "Missing check for syscaps verbosity in openspace.cfg documentation" - ); - verbosity = VerbosityMap.find(v)->second; - } + using Verbosity = ghoul::systemcapabilities::SystemCapabilitiesComponent::Verbosity; + static const std::map VerbosityMap = { + { "None", Verbosity::None }, + { "Minimal", Verbosity::Minimal }, + { "Default", Verbosity::Default }, + { "Full", Verbosity::Full } + }; + + std::string v = _engine->_configuration->logging.capabilitiesVerbosity; + ghoul_assert( + VerbosityMap.find(v) != VerbosityMap.end(), + "Missing check for syscaps verbosity in openspace.cfg documentation" + ); + Verbosity verbosity = VerbosityMap.find(v)->second; SysCap.logCapabilities(verbosity); + // Check the required OpenGL versions of the registered modules ghoul::systemcapabilities::Version version = _engine->_moduleEngine->requiredOpenGLVersion(); @@ -563,18 +574,11 @@ void OpenSpaceEngine::initialize() { scriptEngine().initialize(); writeStaticDocumentation(); - - if (configurationManager().hasKey(ConfigurationManager::KeyShutdownCountdown)) { - _shutdown.waitTime = static_cast(configurationManager().value( - ConfigurationManager::KeyShutdownCountdown - )); - } + + _shutdown.waitTime = _engine->_configuration->shutdownCountdown; if (!commandlineArgumentPlaceholders.sceneName.empty()) { - configurationManager().setValue( - ConfigurationManager::KeyConfigAsset, - commandlineArgumentPlaceholders.sceneName - ); + _engine->_configuration->asset = commandlineArgumentPlaceholders.sceneName; } // Initialize the NavigationHandler @@ -592,8 +596,7 @@ void OpenSpaceEngine::initialize() { func(); } - std::string assetPath = ""; - configurationManager().getValue(ConfigurationManager::KeyConfigAsset, assetPath); + std::string assetPath = _engine->_configuration->asset; _engine->_assetManager->initialize(); scheduleLoadSingleAsset(assetPath); @@ -606,26 +609,10 @@ void OpenSpaceEngine::scheduleLoadSingleAsset(std::string assetPath) { } std::unique_ptr OpenSpaceEngine::createLoadingScreen() { - bool showMessage = true; - constexpr const char* kMessage = ConfigurationManager::KeyLoadingScreenShowMessage; - if (configurationManager().hasKey(kMessage)) { - showMessage = configurationManager().value(kMessage); - } + bool showMessage = _configuration->loadingScreen.isShowingMessages; + bool showNodeNames = _configuration->loadingScreen.isShowingNodeNames; + bool showProgressbar = _configuration->loadingScreen.isShowingProgressbar; - bool showNodeNames = true; - constexpr const char* kNames = ConfigurationManager::KeyLoadingScreenShowNodeNames; - - if (configurationManager().hasKey(kNames)) { - showNodeNames = configurationManager().value(kNames); - } - - bool showProgressbar = true; - constexpr const char* kProgress = - ConfigurationManager::KeyLoadingScreenShowProgressbar; - - if (configurationManager().hasKey(kProgress)) { - showProgressbar = configurationManager().value(kProgress); - } return std::make_unique( LoadingScreen::ShowMessage(showMessage), LoadingScreen::ShowNodeNames(showNodeNames), @@ -656,12 +643,8 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) { _rootPropertyOwner->removePropertySubOwner(_scene.get()); } - bool multiThreadedInitialization = configurationManager().hasKeyAndValue( - ConfigurationManager::KeyUseMultithreadedInitialization - ) && configurationManager().value( - ConfigurationManager::KeyUseMultithreadedInitialization - ); - + bool multiThreadedInitialization = _configuration->useMultithreadedInitialization; + std::unique_ptr sceneInitializer; if (multiThreadedInitialization) { unsigned int nAvailableThreads = std::thread::hardware_concurrency(); @@ -796,29 +779,18 @@ void OpenSpaceEngine::deinitialize() { void OpenSpaceEngine::writeStaticDocumentation() { // If a LuaDocumentationFile was specified, generate it now - if (configurationManager().hasKey(ConfigurationManager::KeyLuaDocumentation)) { - _scriptEngine->writeDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeyLuaDocumentation - )) - ); + if (!_configuration->documentation.lua.empty()) { + _scriptEngine->writeDocumentation(absPath(_configuration->documentation.lua)); } // If a general documentation was specified, generate it now - if (configurationManager().hasKey(ConfigurationManager::KeyDocumentation)) { - DocEng.writeDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeyDocumentation - )) - ); + if (!_configuration->documentation.documentation.empty()) { + DocEng.writeDocumentation(absPath(_configuration->documentation.documentation)); } - // If a factory documentation was specified, generate it now - if (configurationManager().hasKey(ConfigurationManager::KeyFactoryDocumentation)) { + if (!_configuration->documentation.factory.empty()) { FactoryManager::ref().writeDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeyFactoryDocumentation - )) + absPath(_configuration->documentation.factory) ); } } @@ -857,87 +829,85 @@ void OpenSpaceEngine::runGlobalCustomizationScripts() { ghoul::lua::LuaState state; OsEng.scriptEngine().initializeLuaState(state); - std::string k = ConfigurationManager::KeyGlobalCustomizationScripts; - if (_configurationManager->hasKey(k)) { - ghoul::Dictionary dict = _configurationManager->value(k); - for (int i = 1; i <= static_cast(dict.size()); ++i) { - std::string script = absPath(dict.value(std::to_string(i))); - - if (FileSys.fileExists(script)) { - try { - LINFO(fmt::format("Running global customization script: {}", script)); - ghoul::lua::runScriptFile(state, script); - } catch (ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - } - else { - LDEBUG(fmt::format("Ignoring non-existing script file: {}", script)); + for (const std::string& script : _configuration->globalCustomizationScripts) { + std::string s = absPath(script); + if (FileSys.fileExists(s)) { + try { + LINFO(fmt::format("Running global customization script: {}", s)); + ghoul::lua::runScriptFile(state, s); + } catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); } } + else { + LDEBUG(fmt::format("Ignoring non-existing script file: {}", s)); + } } } void OpenSpaceEngine::loadFonts() { - ghoul::Dictionary fonts; - configurationManager().getValue(ConfigurationManager::KeyFonts, fonts); - _fontManager = std::make_unique(FontAtlasSize); - for (const std::string& key : fonts.keys()) { - std::string font = absPath(fonts.value(key)); + for (const std::pair& font : _configuration->fonts) { + std::string key = font.first; + std::string fontName = absPath(font.second); - if (!FileSys.fileExists(font)) { - LERROR(fmt::format("Could not find font '{}'", font)); + if (!FileSys.fileExists(fontName)) { + LERROR(fmt::format("Could not find font '{}' for key '{}'", fontName, key)); continue; } - LDEBUG(fmt::format("Registering font '{}' with key '{}'", font, key)); - bool success = _fontManager->registerFontPath(key, font); + LDEBUG(fmt::format("Registering font '{}' with key '{}'", fontName, key)); + bool success = _fontManager->registerFontPath(key, fontName); if (!success) { - LERROR(fmt::format("Error registering font '{}' with key '{}'", font, key)); + LERROR(fmt::format( + "Error registering font '{}' with key '{}'", fontName, key + )); } } + + try { + bool initSuccess = ghoul::fontrendering::FontRenderer::initialize(); + if (!initSuccess) { + LERROR("Error initializing default font renderer"); + } + + using FR = ghoul::fontrendering::FontRenderer; + FR::defaultRenderer().setFramebufferSize(_renderEngine->fontResolution()); + + FR::defaultProjectionRenderer().setFramebufferSize( + _renderEngine->renderingResolution() + ); + } + catch (const ghoul::RuntimeError& err) { + LERRORC(err.component, err.message); + } } void OpenSpaceEngine::configureLogging(bool consoleLog) { - constexpr const char* KeyLogLevel = ConfigurationManager::KeyLoggingLogLevel; - constexpr const char* KeyLogImmediateFlush = - ConfigurationManager::KeyLoggingImmediateFlush; - constexpr const char* KeyLogs = ConfigurationManager::KeyLoggingLogs; + // We previously initialized the LogManager with a console log to provide some logging + // until we know which logs should be added + LogManager::deinitialize(); - if (configurationManager().hasKeyAndValue(KeyLogLevel)) { - std::string logLevel = "Info"; - configurationManager().getValue(KeyLogLevel, logLevel); + LogLevel level = ghoul::logging::levelFromString(_configuration->logging.level); + bool immediateFlush = _configuration->logging.forceImmediateFlush; - 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 - ); - if (consoleLog) { - LogMgr.addLog(std::make_unique()); - } + using ImmediateFlush = ghoul::logging::LogManager::ImmediateFlush; + LogManager::initialize( + level, + immediateFlush ? ImmediateFlush::Yes : ImmediateFlush::No + ); + if (consoleLog) { + LogMgr.addLog(std::make_unique()); } - if (configurationManager().hasKeyAndValue(KeyLogs)) { - ghoul::Dictionary logs = configurationManager().value(KeyLogs); - - for (size_t i = 1; i <= logs.size(); ++i) { - ghoul::Dictionary logInfo = logs.value(std::to_string(i)); - - try { - LogMgr.addLog(createLog(logInfo)); - } - catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } + for (const ghoul::Dictionary& log : _configuration->logging.logs) { + try { + LogMgr.addLog(createLog(log)); + } + catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); } } @@ -963,40 +933,25 @@ void OpenSpaceEngine::configureLogging(bool consoleLog) { void OpenSpaceEngine::writeSceneDocumentation() { // Write keyboard documentation. - if (configurationManager().hasKey(ConfigurationManager::KeyKeyboardShortcuts)) { + if (!_configuration->documentation.keyboard.empty()) { keyBindingManager().writeDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeyKeyboardShortcuts - )) + absPath(_configuration->documentation.keyboard) ); } - if (configurationManager().hasKey(ConfigurationManager::KeySceneLicenseDocumentation)) - { + if (!_configuration->documentation.license.empty()) { _scene->writeSceneLicenseDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeySceneLicenseDocumentation - )) + absPath(_configuration->documentation.license) ); } - // If a PropertyDocumentationFile was specified, generate it now. - if (configurationManager().hasKey( - ConfigurationManager::KeyScenePropertyDocumentation - )) - { - _scene->writeDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeyScenePropertyDocumentation - )) - ); + if (!_configuration->documentation.sceneProperty.empty()) { + _scene->writeDocumentation(absPath(_configuration->documentation.sceneProperty)); } - if (configurationManager().hasKey(ConfigurationManager::KeyPropertyDocumentation)) { + if (!_configuration->documentation.property.empty()) { _rootPropertyOwner->writeDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeyPropertyDocumentation - )) + absPath(_configuration->documentation.property) ); } } @@ -1014,200 +969,149 @@ void OpenSpaceEngine::initializeGL() { } LTRACE("OpenSpaceEngine::initializeGL::Console::initialize(end)"); - if (_configurationManager->hasKey(ConfigurationManager::KeyOpenGLDebugContext)) { - LTRACE("OpenSpaceEngine::initializeGL::DebugContext(begin)"); - ghoul::Dictionary dict = _configurationManager->value( - ConfigurationManager::KeyOpenGLDebugContext - ); - bool debug = dict.value(ConfigurationManager::PartActivate); + LTRACE("OpenSpaceEngine::initializeGL::DebugContext(begin)"); + bool debugActive = _configuration->openGLDebugContext.isActive; - // Debug output is not available before 4.3 - const ghoul::systemcapabilities::Version minVersion = { 4, 3, 0 }; - if (OpenGLCap.openGLVersion() < minVersion) { - LINFO("OpenGL Debug context requested, but insufficient version available"); - debug = false; - } - - if (debug) { - using namespace ghoul::opengl::debug; - - bool synchronous = true; - if (dict.hasKey(ConfigurationManager::PartSynchronous)) { - synchronous = dict.value(ConfigurationManager::PartSynchronous); - } - - setDebugOutput(DebugOutput(debug), SynchronousOutput(synchronous)); - - if (dict.hasKey(ConfigurationManager::PartFilterIdentifier)) { - ghoul::Dictionary filterDict = dict.value( - ConfigurationManager::PartFilterIdentifier - ); - - for (size_t i = 1; i <= filterDict.size(); ++i) { - ghoul::Dictionary id = filterDict.value( - std::to_string(i) - ); - - const unsigned int identifier = static_cast( - id.value( - ConfigurationManager::PartFilterIdentifierIdentifier - ) - ); - - const std::string s = id.value( - ConfigurationManager::PartFilterIdentifierSource - ); - - const std::string t = id.value( - ConfigurationManager::PartFilterIdentifierType - ); - - setDebugMessageControl( - ghoul::from_string(s), - ghoul::from_string(t), - { identifier }, - Enabled::No - ); - } - } - - if (dict.hasKey(ConfigurationManager::PartFilterSeverity)) { - ghoul::Dictionary filterDict = dict.value( - ConfigurationManager::PartFilterIdentifier - ); - - for (size_t i = 1; i <= filterDict.size(); ++i) { - std::string severity = filterDict.value( - std::to_string(i) - ); - - setDebugMessageControl( - Source::DontCare, - Type::DontCare, - ghoul::from_string(severity), - Enabled::No - ); - } - } - - auto callback = [](Source source, Type type, Severity severity, - unsigned int id, std::string message) -> void - { - const std::string s = std::to_string(source); - const std::string t = std::to_string(type); - - const std::string category = - "OpenGL (" + s + ") [" + t + "] {" + std::to_string(id) + "}"; - switch (severity) { - case Severity::High: - LERRORC(category, message); - break; - case Severity::Medium: - LWARNINGC(category, message); - break; - case Severity::Low: - LINFOC(category, message); - break; - case Severity::Notification: - LDEBUGC(category, message); - break; - default: - throw ghoul::MissingCaseException(); - } - }; - ghoul::opengl::debug::setDebugCallback(callback); - } - LTRACE("OpenSpaceEngine::initializeGL::DebugContext(end)"); + // Debug output is not available before 4.3 + const ghoul::systemcapabilities::Version minVersion = { 4, 3, 0 }; + if (debugActive && OpenGLCap.openGLVersion() < minVersion) { + LINFO("OpenGL Debug context requested, but insufficient version available"); + debugActive = false; } + if (debugActive) { + using namespace ghoul::opengl::debug; + + bool synchronous = _configuration->openGLDebugContext.isSynchronous; + setDebugOutput(DebugOutput(debugActive), SynchronousOutput(synchronous)); + + using IdFilter = Configuration::OpenGLDebugContext::IdentifierFilter; + for (const IdFilter&f : _configuration->openGLDebugContext.identifierFilters) { + setDebugMessageControl( + ghoul::from_string(f.source), + ghoul::from_string(f.type), + { f.identifier }, + Enabled::No + ); + + } + + for (const std::string& sev : _configuration->openGLDebugContext.severityFilters) + { + setDebugMessageControl( + Source::DontCare, + Type::DontCare, + ghoul::from_string(sev), + Enabled::No + ); + } + + auto callback = [](Source source, Type type, Severity severity, + unsigned int id, std::string message) -> void + { + const std::string s = std::to_string(source); + const std::string t = std::to_string(type); + + const std::string category = + "OpenGL (" + s + ") [" + t + "] {" + std::to_string(id) + "}"; + switch (severity) { + case Severity::High: + LERRORC(category, message); + break; + case Severity::Medium: + LWARNINGC(category, message); + break; + case Severity::Low: + LINFOC(category, message); + break; + case Severity::Notification: + LDEBUGC(category, message); + break; + default: + throw ghoul::MissingCaseException(); + } + }; + ghoul::opengl::debug::setDebugCallback(callback); + } + LTRACE("OpenSpaceEngine::initializeGL::DebugContext(end)"); + // The ordering of the KeyCheckOpenGLState and KeyLogEachOpenGLCall are important as // the callback mask in glbinding is stateful for each context, and since // KeyLogEachOpenGLCall is more specific, we want it to be able to overwrite the // state from KeyCheckOpenGLState - if (_configurationManager->hasKey(ConfigurationManager::KeyCheckOpenGLState)) { - const bool val = _configurationManager->value( - ConfigurationManager::KeyCheckOpenGLState - ); - - if (val) { - using namespace glbinding; - setCallbackMaskExcept(CallbackMask::After, { "glGetError" }); - setAfterCallback([](const FunctionCall& f) { - const GLenum error = glGetError(); - switch (error) { - case GL_NO_ERROR: - break; - case GL_INVALID_ENUM: - LERRORC( - "OpenGL Invalid State", - fmt::format("Function {}: GL_INVALID_ENUM", f.toString()) - ); - break; - case GL_INVALID_VALUE: - LERRORC( - "OpenGL Invalid State", - fmt::format("Function {}: GL_INVALID_VALUE", f.toString()) - ); - break; - case GL_INVALID_OPERATION: - LERRORC( - "OpenGL Invalid State", - fmt::format("Function {}: GL_INVALID_OPERATION", f.toString()) - ); - break; - case GL_INVALID_FRAMEBUFFER_OPERATION: - LERRORC( - "OpenGL Invalid State", - fmt::format( - "Function {}: GL_INVALID_FRAMEBUFFER_OPERATION", - f.toString() - ) - ); - break; - case GL_OUT_OF_MEMORY: - LERRORC( - "OpenGL Invalid State", - fmt::format("Function {}: GL_OUT_OF_MEMORY", f.toString()) - ); - break; - default: - LERRORC( - "OpenGL Invalid State", - fmt::format("Unknown error code: {0:x}", error) - ); - } - }); - } + if (_configuration->isCheckingOpenGLState) { + using namespace glbinding; + // Infinite loop -- welcome to the danger zone + setCallbackMaskExcept(CallbackMask::After, { "glGetError" }); + setAfterCallback([](const FunctionCall& f) { + const GLenum error = glGetError(); + switch (error) { + case GL_NO_ERROR: + break; + case GL_INVALID_ENUM: + LERRORC( + "OpenGL Invalid State", + fmt::format("Function {}: GL_INVALID_ENUM", f.toString()) + ); + break; + case GL_INVALID_VALUE: + LERRORC( + "OpenGL Invalid State", + fmt::format("Function {}: GL_INVALID_VALUE", f.toString()) + ); + break; + case GL_INVALID_OPERATION: + LERRORC( + "OpenGL Invalid State", + fmt::format("Function {}: GL_INVALID_OPERATION", f.toString()) + ); + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + LERRORC( + "OpenGL Invalid State", + fmt::format( + "Function {}: GL_INVALID_FRAMEBUFFER_OPERATION", + f.toString() + ) + ); + break; + case GL_OUT_OF_MEMORY: + LERRORC( + "OpenGL Invalid State", + fmt::format("Function {}: GL_OUT_OF_MEMORY", f.toString()) + ); + break; + default: + LERRORC( + "OpenGL Invalid State", + fmt::format("Unknown error code: {0:x}", error) + ); + } + }); } - if (_configurationManager->hasKey(ConfigurationManager::KeyLogEachOpenGLCall)) { - const bool val = _configurationManager->value( - ConfigurationManager::KeyLogEachOpenGLCall - ); + if (_configuration->isLoggingOpenGLCalls) { + using namespace glbinding; + setCallbackMask(CallbackMask::After | CallbackMask::ParametersAndReturnValue); + glbinding::setAfterCallback([](const glbinding::FunctionCall& call) { + std::string arguments = std::accumulate( + call.parameters.begin(), + call.parameters.end(), + std::string("("), + [](std::string a, AbstractValue* v) { + return a + ", " + v->asString(); + } + ); - if (val) { - using namespace glbinding; - setCallbackMask(CallbackMask::After | CallbackMask::ParametersAndReturnValue); - glbinding::setAfterCallback([](const glbinding::FunctionCall& call) { - std::string arguments = std::accumulate( - call.parameters.begin(), - call.parameters.end(), - std::string("("), - [](std::string a, AbstractValue* v) { - return a + ", " + v->asString(); - } - ); + std::string returnValue = call.returnValue ? + " -> " + call.returnValue->asString() : + ""; - std::string returnValue = call.returnValue ? - " -> " + call.returnValue->asString() : - ""; - - LTRACEC( - "OpenGL", - call.function->name() + arguments + returnValue - ); - }); - } + LTRACEC( + "OpenGL", + call.function->name() + arguments + returnValue + ); + }); } try { @@ -1276,7 +1180,7 @@ void OpenSpaceEngine::preSynchronization() { } _renderEngine->updateScene(); - _navigationHandler->updateCamera(dt); + //_navigationHandler->updateCamera(dt); Camera* camera = _renderEngine->camera(); if (camera) { @@ -1512,6 +1416,10 @@ void OpenSpaceEngine::mouseScrollWheelCallback(double posX, double posY) { _navigationHandler->mouseScrollWheelCallback(posY); } +void OpenSpaceEngine::setJoystickInputStates(interaction::JoystickInputStates& states) { + _navigationHandler->setJoystickInputStates(states); +} + void OpenSpaceEngine::encode() { _syncEngine->encodeSyncables(); @@ -1681,9 +1589,8 @@ void OpenSpaceEngine::registerModuleMouseScrollWheelCallback( _moduleCallbacks.mouseScrollWheel.push_back(std::move(function)); } -ConfigurationManager& OpenSpaceEngine::configurationManager() { - ghoul_assert(_configurationManager, "ConfigurationManager must not be nullptr"); - return *_configurationManager; +const Configuration& OpenSpaceEngine::configuration() const { + return *_configuration; } LuaConsole& OpenSpaceEngine::console() { diff --git a/src/interaction/camerainteractionstates.cpp b/src/interaction/camerainteractionstates.cpp new file mode 100644 index 0000000000..ae0af29f03 --- /dev/null +++ b/src/interaction/camerainteractionstates.cpp @@ -0,0 +1,101 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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 + +namespace openspace::interaction { + +CameraInteractionStates::InteractionState::InteractionState(double scaleFactor) + : previousPosition(0.0, 0.0) + , velocity(scaleFactor, 1) +{} + +void CameraInteractionStates::InteractionState::setFriction(double friction) { + velocity.setFriction(friction); +} + +void CameraInteractionStates::InteractionState::setVelocityScaleFactor(double scaleFactor) +{ + velocity.setScaleFactor(scaleFactor); +} + +CameraInteractionStates::CameraInteractionStates(double sensitivity, + double velocityScaleFactor) + : _sensitivity(sensitivity) + , _globalRotationState(velocityScaleFactor) + , _localRotationState(velocityScaleFactor) + , _truckMovementState(velocityScaleFactor) + , _localRollState(velocityScaleFactor) + , _globalRollState(velocityScaleFactor) +{} + +void CameraInteractionStates::setRotationalFriction(double friction) { + _localRotationState.setFriction(friction); + _localRollState.setFriction(friction); + _globalRollState.setFriction(friction); +} + +void CameraInteractionStates::setHorizontalFriction(double friction) { + _globalRotationState.setFriction(friction); +} + +void CameraInteractionStates::setVerticalFriction(double friction) { + _truckMovementState.setFriction(friction); +} + +void CameraInteractionStates::setSensitivity(double sensitivity) { + _sensitivity = sensitivity; +} + +void CameraInteractionStates::setVelocityScaleFactor(double scaleFactor) { + _globalRotationState.setVelocityScaleFactor(scaleFactor); + _localRotationState.setVelocityScaleFactor(scaleFactor); + _truckMovementState.setVelocityScaleFactor(scaleFactor); + _localRollState.setVelocityScaleFactor(scaleFactor); + _globalRollState.setVelocityScaleFactor(scaleFactor); +} + +glm::dvec2 CameraInteractionStates::globalRotationVelocity() const{ + return _globalRotationState.velocity.get(); +} + +glm::dvec2 CameraInteractionStates::localRotationVelocity() const{ + return _localRotationState.velocity.get(); +} + +glm::dvec2 CameraInteractionStates::truckMovementVelocity() const{ + return _truckMovementState.velocity.get(); +} + +glm::dvec2 CameraInteractionStates::localRollVelocity() const{ + return _localRollState.velocity.get(); +} + +glm::dvec2 CameraInteractionStates::globalRollVelocity() const{ + return _globalRollState.velocity.get(); +} + +} // namespace openspace::interaction diff --git a/src/interaction/inputdevicestates.cpp b/src/interaction/inputdevicestates.cpp new file mode 100644 index 0000000000..9b1f05e8a7 --- /dev/null +++ b/src/interaction/inputdevicestates.cpp @@ -0,0 +1,101 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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 + +namespace openspace::interaction { + +CameraInteractionStates::InteractionState::InteractionState(double scaleFactor) + : previousPosition(0.0, 0.0) + , velocity(scaleFactor, 1) +{} + +void CameraInteractionStates::InteractionState::setFriction(double friction) { + velocity.setFriction(friction); +} + +void CameraInteractionStates::InteractionState::setVelocityScaleFactor(double scaleFactor) +{ + velocity.setScaleFactor(scaleFactor); +} + +CameraInteractionStates::CameraInteractionStates(double sensitivity, + double velocityScaleFactor) + : _sensitivity(sensitivity) + , _globalRotationState(velocityScaleFactor) + , _localRotationState(velocityScaleFactor) + , _truckMovementState(velocityScaleFactor) + , _localRollState(velocityScaleFactor) + , _globalRollState(velocityScaleFactor) +{} + +void CameraInteractionStates::setRotationalFriction(double friction) { + _localRotationState.setFriction(friction); + _localRollState.setFriction(friction); + _globalRollState.setFriction(friction); +} + +void CameraInteractionStates::setHorizontalFriction(double friction) { + _globalRotationState.setFriction(friction); +} + +void CameraInteractionStates::setVerticalFriction(double friction) { + _truckMovementState.setFriction(friction); +} + +void CameraInteractionStates::setSensitivity(double sensitivity) { + _sensitivity = sensitivity; +} + +void CameraInteractionStates::setVelocityScaleFactor(double scaleFactor) { + _globalRotationState.setVelocityScaleFactor(scaleFactor); + _localRotationState.setVelocityScaleFactor(scaleFactor); + _truckMovementState.setVelocityScaleFactor(scaleFactor); + _localRollState.setVelocityScaleFactor(scaleFactor); + _globalRollState.setVelocityScaleFactor(scaleFactor); +} + +glm::dvec2 CameraInteractionStates::globalRotationVelocity() const{ + return _globalRotationState.velocity.get(); +} + +glm::dvec2 CameraInteractionStates::localRotationVelocity() const{ + return _localRotationState.velocity.get(); +} + +glm::dvec2 CameraInteractionStates::truckMovementVelocity() const{ + return _truckMovementState.velocity.get(); +} + +glm::dvec2 CameraInteractionStates::localRollVelocity() const{ + return _localRollState.velocity.get(); +} + +glm::dvec2 CameraInteractionStates::globalRollVelocity() const{ + return _globalRollState.velocity.get(); +} + +} // namespace openspace::interaction diff --git a/src/interaction/inputstate.cpp b/src/interaction/inputstate.cpp index d22c2619b6..4976263f0b 100644 --- a/src/interaction/inputstate.cpp +++ b/src/interaction/inputstate.cpp @@ -24,8 +24,8 @@ #include +#include #include - #include namespace openspace::interaction { @@ -46,9 +46,7 @@ void InputState::mouseButtonCallback(MouseButton button, MouseAction action) { _mouseButtonsDown.push_back(button); } else if (action == MouseAction::Release) { - // Remove all key pressings for 'button' - _mouseButtonsDown.remove_if([button](MouseButton buttonInList) - { return button == buttonInList; }); + _mouseButtonsDown.remove(button); } } @@ -60,19 +58,23 @@ void InputState::mouseScrollWheelCallback(double mouseScrollDelta) { _mouseScrollDelta = mouseScrollDelta; } -const std::list >& InputState::getPressedKeys() const { +void InputState::setJoystickInputStates(JoystickInputStates& states) { + _joystickInputStates = &states; +} + +const std::list>& InputState::pressedKeys() const { return _keysDown; } -const std::list& InputState::getPressedMouseButtons() const { +const std::list& InputState::pressedMouseButtons() const { return _mouseButtonsDown; } -glm::dvec2 InputState::getMousePosition() const { +glm::dvec2 InputState::mousePosition() const { return _mousePosition; } -double InputState::getMouseScrollDelta() const { +double InputState::mouseScrollDelta() const { return _mouseScrollDelta; } @@ -92,4 +94,16 @@ bool InputState::isMouseButtonPressed(MouseButton mouseButton) const { mouseButton) != _mouseButtonsDown.end(); } +const JoystickInputStates& InputState::joystickInputStates() const { + return *_joystickInputStates; +} + +float InputState::joystickAxis(int i) const { + return _joystickInputStates->axis(i); +} + +bool InputState::joystickButton(int i) const{ + return _joystickInputStates->button(i, JoystickAction::Press); +} + } // namespace openspace::interaction diff --git a/src/interaction/joystickcamerastates.cpp b/src/interaction/joystickcamerastates.cpp new file mode 100644 index 0000000000..6309dfff5b --- /dev/null +++ b/src/interaction/joystickcamerastates.cpp @@ -0,0 +1,272 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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 + +namespace openspace::interaction { + +JoystickCameraStates::JoystickCameraStates(double sensitivity, double velocityScaleFactor) + : CameraInteractionStates(sensitivity, velocityScaleFactor) +{} + +void JoystickCameraStates::updateStateFromInput(const InputState& inputState, + double deltaTime) +{ + std::pair globalRotation = { false, glm::dvec2(0.0) }; + std::pair zoom = { false, 0.0 }; + std::pair localRoll = { false, glm::dvec2(0.0) }; + std::pair globalRoll = { false, glm::dvec2(0.0) }; + std::pair localRotation = { false, glm::dvec2(0.0) }; + + for (int i = 0; i < JoystickInputState::MaxAxes; ++i) { + AxisInformation t = _axisMapping[i]; + if (t.type == AxisType::None) { + continue; + } + + bool hasValue = true; + float value = inputState.joystickAxis(i); + + if (abs(value) <= t.deadzone) { + value = 0.f; + hasValue = false; + } + + if (t.normalize) { + value = (value + 1.f) / 2.f; + } + + if (t.invert) { + value *= -1.f; + } + + value *= _sensitivity; + + switch (t.type) { + case AxisType::None: + break; + case AxisType::OrbitX: + globalRotation.first = hasValue; + globalRotation.second.x = value; + break; + case AxisType::OrbitY: + globalRotation.first = hasValue; + globalRotation.second.y = value; + break; + case AxisType::ZoomIn: + zoom.first = hasValue; + zoom.second += value; + break; + case AxisType::ZoomOut: + zoom.first = hasValue; + zoom.second -= value; + break; + case AxisType::LocalRollX: + localRoll.first = hasValue; + localRoll.second.x = value; + break; + case AxisType::LocalRollY: + localRoll.first = hasValue; + localRoll.second.y = value; + break; + case AxisType::GlobalRollX: + globalRoll.first = hasValue; + globalRoll.second.x = value; + break; + case AxisType::GlobalRollY: + globalRoll.first = hasValue; + globalRoll.second.y = value; + break; + case AxisType::PanX: + localRotation.first = hasValue; + localRotation.second.x = value; + break; + case AxisType::PanY: + localRotation.first = hasValue; + localRotation.second.y = value; + break; + } + } + + if (globalRotation.first) { + _globalRotationState.velocity.set(globalRotation.second, deltaTime); + } + else { + _globalRotationState.velocity.decelerate(deltaTime); + } + + if (zoom.first) { + _truckMovementState.velocity.set(glm::dvec2(zoom.second), deltaTime); + } + else { + _truckMovementState.velocity.decelerate(deltaTime); + } + + if (localRoll.first) { + _localRollState.velocity.set(localRoll.second, deltaTime); + } + else { + _localRollState.velocity.decelerate(deltaTime); + } + + if (globalRoll.first) { + _globalRollState.velocity.set(globalRoll.second, deltaTime); + } + else { + _globalRollState.velocity.decelerate(deltaTime); + } + + if (localRotation.first) { + _localRotationState.velocity.set(localRotation.second, deltaTime); + } + else { + _localRotationState.velocity.decelerate(deltaTime); + } + + + for (int i = 0; i < JoystickInputState::MaxButtons; ++i) { + auto itRange = _buttonMapping.equal_range(i); + for (auto it = itRange.first; it != itRange.second; ++it) { + bool active = inputState.joystickInputStates().button(i, it->second.action); + + if (active) { + OsEng.scriptEngine().queueScript( + it->second.command, + scripting::ScriptEngine::RemoteScripting(it->second.synchronization) + ); + } + } + } +} + +void JoystickCameraStates::setAxisMapping(int axis, AxisType mapping, + AxisInvert shouldInvert, + AxisNormalize shouldNormalize) +{ + ghoul_assert(axis < JoystickInputState::MaxAxes, "axis must be < MaxAxes"); + + _axisMapping[axis] = { mapping, shouldInvert, shouldNormalize }; +} + +JoystickCameraStates::AxisInformation JoystickCameraStates::axisMapping(int axis) const { + return _axisMapping[axis]; +} + +void JoystickCameraStates::setDeadzone(int axis, float deadzone) { + _axisMapping[axis].deadzone = deadzone; +} + +float JoystickCameraStates::deadzone(int axis) const { + return _axisMapping[axis].deadzone; +} + +void JoystickCameraStates::bindButtonCommand(int button, std::string command, + JoystickAction action, + ButtonCommandRemote remote) +{ + _buttonMapping.insert({ + button, + { std::move(command), action, remote } + }); +} + +void JoystickCameraStates::clearButtonCommand(int button) { + for (auto it = _buttonMapping.begin(); it != _buttonMapping.end();) { + // If the current iterator is the button that we are looking for, delete it + // (std::multimap::erase will return the iterator to the next element for us) + if (it->first == button) { + it = _buttonMapping.erase(it); + } + else { + ++it; + } + } +} + +std::vector JoystickCameraStates::buttonCommand(int button) const { + std::vector result; + auto itRange = _buttonMapping.equal_range(button); + for (auto it = itRange.first; it != itRange.second; ++it) { + result.push_back(it->second.command); + } + return result; +} + + +} // namespace openspace::interaction + +namespace std { + +std::string to_string(const openspace::interaction::JoystickCameraStates::AxisType& type) +{ + using T = openspace::interaction::JoystickCameraStates::AxisType; + switch (type) { + case T::None: return "None"; + case T::OrbitX: return "Orbit X"; + case T::OrbitY: return "Orbit Y"; + case T::ZoomIn: return "Zoom In"; + case T::ZoomOut: return "Zoom Out"; + case T::LocalRollX: return "LocalRoll X"; + case T::LocalRollY: return "LocalRoll Y"; + case T::GlobalRollX: return "GlobalRoll X"; + case T::GlobalRollY: return "GlobalRoll Y"; + case T::PanX: return "Pan X"; + case T::PanY: return "Pan Y"; + default: return ""; + } +} + +} // namespace std + +namespace ghoul { + +template <> +openspace::interaction::JoystickCameraStates::AxisType from_string( + const std::string& string) +{ + using T = openspace::interaction::JoystickCameraStates::AxisType; + + static const std::map Map = { + { "None", T::None }, + { "Orbit X", T::OrbitX }, + { "Orbit Y", T::OrbitY }, + { "Zoom In", T::ZoomIn }, + { "Zoom Out", T::ZoomOut }, + { "LocalRoll X", T::LocalRollX }, + { "LocalRoll Y", T::LocalRollY }, + { "GlobalRoll X", T::GlobalRollX }, + { "GlobalRoll Y", T::GlobalRollY }, + { "Pan X", T::PanX }, + { "Pan Y", T::PanY } + }; + + return Map.at(string); +} + +} // namespace ghoul diff --git a/src/interaction/joystickinputstate.cpp b/src/interaction/joystickinputstate.cpp new file mode 100644 index 0000000000..a3c9ebaf5d --- /dev/null +++ b/src/interaction/joystickinputstate.cpp @@ -0,0 +1,100 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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 + +namespace openspace::interaction { + +float JoystickInputStates::axis(int axis) const { + ghoul_precondition(axis >= 0, "axis must be 0 or positive"); + + float res = std::accumulate( + begin(), + end(), + 0.f, + [axis](float value, const JoystickInputState& state) { + if (state.isConnected) { + value += state.axes[axis]; + } + return value; + } + ); + + // If multiple joysticks are connected, we might get values outside the -1,1 range by + // summing them up + glm::clamp(res, -1.f, 1.f); + return res; +} + +bool JoystickInputStates::button(int button, JoystickAction action) const { + ghoul_precondition(button >= 0, "button must be 0 or positive"); + + bool res = std::any_of( + begin(), + end(), + [button, action](const JoystickInputState& state) { + return state.isConnected ? (state.buttons[button] == action) : false; + } + ); + return res; +} + +} // namespace openspace::interaction + +namespace std { + +std::string to_string(openspace::interaction::JoystickAction action) { + switch (action) { + case openspace::interaction::JoystickAction::Idle: return "Idle"; + case openspace::interaction::JoystickAction::Press: return "Press"; + case openspace::interaction::JoystickAction::Repeat: return "Repeat"; + case openspace::interaction::JoystickAction::Release: return "Release"; + default: return ""; + } +} + +} // namespace std + +namespace ghoul { + +template <> +openspace::interaction::JoystickAction from_string(const std::string& string) { + static const std::map Map = { + { "Idle", openspace::interaction::JoystickAction::Idle }, + { "Press", openspace::interaction::JoystickAction::Press }, + { "Repeat", openspace::interaction::JoystickAction::Repeat }, + { "Release", openspace::interaction::JoystickAction::Release } + }; + + return Map.at(string); + +} + +} // namespace ghoul diff --git a/src/interaction/luaconsole.cpp b/src/interaction/luaconsole.cpp index d87905c31c..bb04359b78 100644 --- a/src/interaction/luaconsole.cpp +++ b/src/interaction/luaconsole.cpp @@ -22,7 +22,7 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include #include #include diff --git a/src/interaction/mousecamerastates.cpp b/src/interaction/mousecamerastates.cpp new file mode 100644 index 0000000000..c79edcf343 --- /dev/null +++ b/src/interaction/mousecamerastates.cpp @@ -0,0 +1,125 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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 + +namespace openspace::interaction { + +MouseCameraStates::MouseCameraStates(double sensitivity, double velocityScaleFactor) + : CameraInteractionStates(sensitivity, velocityScaleFactor) +{} + +void MouseCameraStates::updateStateFromInput(const InputState& inputState, double deltaTime) { + glm::dvec2 mousePosition = inputState.mousePosition(); + + bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1); + bool button2Pressed = inputState.isMouseButtonPressed(MouseButton::Button2); + bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3); + bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl) | + inputState.isKeyPressed(Key::RightControl); + bool keyShiftPressed = inputState.isKeyPressed(Key::LeftShift) | + inputState.isKeyPressed(Key::RightShift); + bool keyAltPressed = inputState.isKeyPressed(Key::LeftAlt) | + inputState.isKeyPressed(Key::RightAlt); + + // Update the mouse states + if (button1Pressed && !keyShiftPressed && !keyAltPressed) { + if (keyCtrlPressed) { + glm::dvec2 mousePositionDelta = + _localRotationState.previousPosition - mousePosition; + _localRotationState.velocity.set( + mousePositionDelta * _sensitivity, + deltaTime + ); + + _globalRotationState.previousPosition = mousePosition; + _globalRotationState.velocity.decelerate(deltaTime); + } + else { + glm::dvec2 mousePositionDelta = + _globalRotationState.previousPosition - mousePosition; + _globalRotationState.velocity.set( + mousePositionDelta * _sensitivity, + deltaTime + ); + + _localRotationState.previousPosition = mousePosition; + _localRotationState.velocity.decelerate(deltaTime); + } + } + else { // !button1Pressed + _localRotationState.previousPosition = mousePosition; + _localRotationState.velocity.decelerate(deltaTime); + + _globalRotationState.previousPosition = mousePosition; + _globalRotationState.velocity.decelerate(deltaTime); + } + if (button2Pressed || (keyAltPressed && button1Pressed)) { + glm::dvec2 mousePositionDelta = + _truckMovementState.previousPosition - mousePosition; + _truckMovementState.velocity.set( + mousePositionDelta * _sensitivity, + deltaTime + ); + } + else { // !button2Pressed + _truckMovementState.previousPosition = mousePosition; + _truckMovementState.velocity.decelerate(deltaTime); + } + if (button3Pressed || (keyShiftPressed && button1Pressed)) { + if (keyCtrlPressed) { + glm::dvec2 mousePositionDelta = + _localRollState.previousPosition - mousePosition; + _localRollState.velocity.set( + mousePositionDelta * _sensitivity, + deltaTime + ); + + _globalRollState.previousPosition = mousePosition; + _globalRollState.velocity.decelerate(deltaTime); + } + else { + glm::dvec2 mousePositionDelta = + _globalRollState.previousPosition - mousePosition; + _globalRollState.velocity.set( + mousePositionDelta * _sensitivity, + deltaTime + ); + + _localRollState.previousPosition = mousePosition; + _localRollState.velocity.decelerate(deltaTime); + } + } + else { // !button3Pressed + _globalRollState.previousPosition = mousePosition; + _globalRollState.velocity.decelerate(deltaTime); + + _localRollState.previousPosition = mousePosition; + _localRollState.velocity.decelerate(deltaTime); + } +} + +} // namespace openspace::interaction diff --git a/src/interaction/mousestate.cpp b/src/interaction/mousestate.cpp deleted file mode 100644 index 9325eaf650..0000000000 --- a/src/interaction/mousestate.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * 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 - -namespace openspace::interaction { - -MouseState::MouseState(double scaleFactor) - : previousPosition(0.0, 0.0) - , velocity(scaleFactor, 1) -{} - -void MouseState::setFriction(double friction) { - velocity.setFriction(friction); -} - -void MouseState::setVelocityScaleFactor(double scaleFactor) { - velocity.setScaleFactor(scaleFactor); -} - -MouseStates::MouseStates(double sensitivity, double velocityScaleFactor) - : _sensitivity(sensitivity) - , _globalRotationMouseState(velocityScaleFactor) - , _localRotationMouseState(velocityScaleFactor) - , _truckMovementMouseState(velocityScaleFactor) - , _localRollMouseState(velocityScaleFactor) - , _globalRollMouseState(velocityScaleFactor) -{ } - -void MouseStates::updateMouseStatesFromInput(const InputState& inputState, - double deltaTime) -{ - glm::dvec2 mousePosition = inputState.getMousePosition(); - - bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1); - bool button2Pressed = inputState.isMouseButtonPressed(MouseButton::Button2); - bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3); - bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl) | - inputState.isKeyPressed(Key::RightControl); - bool keyShiftPressed = inputState.isKeyPressed(Key::LeftShift) | - inputState.isKeyPressed(Key::RightShift); - bool keyAltPressed = inputState.isKeyPressed(Key::LeftAlt) | - inputState.isKeyPressed(Key::RightAlt); - - // Update the mouse states - if (button1Pressed && !keyShiftPressed && !keyAltPressed) { - if (keyCtrlPressed) { - glm::dvec2 mousePositionDelta = - _localRotationMouseState.previousPosition - mousePosition; - _localRotationMouseState.velocity.set( - mousePositionDelta * _sensitivity, deltaTime); - - _globalRotationMouseState.previousPosition = mousePosition; - _globalRotationMouseState.velocity.decelerate(deltaTime); - } - else { - glm::dvec2 mousePositionDelta = - _globalRotationMouseState.previousPosition - mousePosition; - _globalRotationMouseState.velocity.set( - mousePositionDelta * _sensitivity, deltaTime); - - _localRotationMouseState.previousPosition = mousePosition; - _localRotationMouseState.velocity.decelerate(deltaTime); - } - } - else { // !button1Pressed - _localRotationMouseState.previousPosition = mousePosition; - _localRotationMouseState.velocity.decelerate(deltaTime); - - _globalRotationMouseState.previousPosition = mousePosition; - _globalRotationMouseState.velocity.decelerate(deltaTime); - } - if (button2Pressed || (keyAltPressed && button1Pressed)) { - glm::dvec2 mousePositionDelta = - _truckMovementMouseState.previousPosition - mousePosition; - _truckMovementMouseState.velocity.set( - mousePositionDelta * _sensitivity, deltaTime); - } - else { // !button2Pressed - _truckMovementMouseState.previousPosition = mousePosition; - _truckMovementMouseState.velocity.decelerate(deltaTime); - } - if (button3Pressed || (keyShiftPressed && button1Pressed)) { - if (keyCtrlPressed) { - glm::dvec2 mousePositionDelta = - _localRollMouseState.previousPosition - mousePosition; - _localRollMouseState.velocity.set( - mousePositionDelta * _sensitivity, deltaTime); - - _globalRollMouseState.previousPosition = mousePosition; - _globalRollMouseState.velocity.decelerate(deltaTime); - } - else { - glm::dvec2 mousePositionDelta = - _globalRollMouseState.previousPosition - mousePosition; - _globalRollMouseState.velocity.set( - mousePositionDelta * _sensitivity, deltaTime); - - _localRollMouseState.previousPosition = mousePosition; - _localRollMouseState.velocity.decelerate(deltaTime); - } - } - else { // !button3Pressed - _globalRollMouseState.previousPosition = mousePosition; - _globalRollMouseState.velocity.decelerate(deltaTime); - - _localRollMouseState.previousPosition = mousePosition; - _localRollMouseState.velocity.decelerate(deltaTime); - } -} - -void MouseStates::setRotationalFriction(double friction) { - _localRotationMouseState.setFriction(friction); - _localRollMouseState.setFriction(friction); - _globalRollMouseState.setFriction(friction); -} - -void MouseStates::setHorizontalFriction(double friction) { - _globalRotationMouseState.setFriction(friction); -} - -void MouseStates::setVerticalFriction(double friction) { - _truckMovementMouseState.setFriction(friction); -} - -void MouseStates::setSensitivity(double sensitivity) { - _sensitivity = sensitivity; -} - -void MouseStates::setVelocityScaleFactor(double scaleFactor) { - _globalRotationMouseState.setVelocityScaleFactor(scaleFactor); - _localRotationMouseState.setVelocityScaleFactor(scaleFactor); - _truckMovementMouseState.setVelocityScaleFactor(scaleFactor); - _localRollMouseState.setVelocityScaleFactor(scaleFactor); - _globalRollMouseState.setVelocityScaleFactor(scaleFactor); -} - -glm::dvec2 MouseStates::globalRotationMouseVelocity() const{ - return _globalRotationMouseState.velocity.get(); -} - -glm::dvec2 MouseStates::localRotationMouseVelocity() const{ - return _localRotationMouseState.velocity.get(); -} - -glm::dvec2 MouseStates::truckMovementMouseVelocity() const{ - return _truckMovementMouseState.velocity.get(); -} - -glm::dvec2 MouseStates::localRollMouseVelocity() const{ - return _localRollMouseState.velocity.get(); -} - -glm::dvec2 MouseStates::globalRollMouseVelocity() const{ - return _globalRollMouseState.velocity.get(); -} - -} // namespace openspace::interaction diff --git a/src/interaction/navigationhandler.cpp b/src/interaction/navigationhandler.cpp index fb9631345a..2fff65ded4 100644 --- a/src/interaction/navigationhandler.cpp +++ b/src/interaction/navigationhandler.cpp @@ -153,8 +153,8 @@ void NavigationHandler::updateCamera(double deltaTime) { _keyframeNavigator->updateCamera(*_camera); } else { - _orbitalNavigator->updateMouseStatesFromInput(*_inputState, deltaTime); - _orbitalNavigator->updateCameraStateFromMouseStates(*_camera, deltaTime); + _orbitalNavigator->updateStatesFromInput(*_inputState, deltaTime); + _orbitalNavigator->updateCameraStateFromStates(*_camera, deltaTime); } _camera->setFocusPositionVec3(focusNode()->worldPosition()); } @@ -201,6 +201,10 @@ void NavigationHandler::keyboardCallback(Key key, KeyModifier modifier, KeyActio _inputState->keyboardCallback(key, modifier, action); } +void NavigationHandler::setJoystickInputStates(JoystickInputStates& states) { + _inputState->setJoystickInputStates(states); +} + void NavigationHandler::setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict) { bool readSuccessful = true; @@ -226,7 +230,7 @@ void NavigationHandler::setCameraStateFromDictionary(const ghoul::Dictionary& ca cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w)); } -ghoul::Dictionary NavigationHandler::getCameraStateDictionary() { +ghoul::Dictionary NavigationHandler::cameraStateDictionary() { glm::dvec3 cameraPosition; glm::dquat quat; glm::dvec4 cameraRotation; @@ -248,7 +252,7 @@ void NavigationHandler::saveCameraStateToFile(const std::string& filepath) { std::string fullpath = absPath(filepath); LINFO(fmt::format("Saving camera position: {}", filepath)); - ghoul::Dictionary cameraDict = getCameraStateDictionary(); + ghoul::Dictionary cameraDict = cameraStateDictionary(); // TODO : Should get the camera state as a dictionary and save the dictionary to // a file in form of a lua state and not use ofstreams here. @@ -293,6 +297,52 @@ void NavigationHandler::restoreCameraStateFromFile(const std::string& filepath) } } +void NavigationHandler::setJoystickAxisMapping(int axis, JoystickCameraStates::AxisType mapping, + JoystickCameraStates::AxisInvert shouldInvert, + JoystickCameraStates::AxisNormalize shouldNormalize) +{ + _orbitalNavigator->joystickStates().setAxisMapping( + axis, + mapping, + shouldInvert, + shouldNormalize + ); +} + +JoystickCameraStates::AxisInformation NavigationHandler::joystickAxisMapping(int axis) const { + return _orbitalNavigator->joystickStates().axisMapping(axis); +} + +void NavigationHandler::setJoystickAxisDeadzone(int axis, float deadzone) { + _orbitalNavigator->joystickStates().setDeadzone(axis, deadzone); +} + +float NavigationHandler::joystickAxisDeadzone(int axis) const { + return _orbitalNavigator->joystickStates().deadzone(axis); +} + +void NavigationHandler::bindJoystickButtonCommand(int button, std::string command, + JoystickAction action, + JoystickCameraStates::ButtonCommandRemote remote) +{ + _orbitalNavigator->joystickStates().bindButtonCommand( + button, + std::move(command), + action, + remote + ); +} + +void NavigationHandler::clearJoystickButtonCommand(int button) { + _orbitalNavigator->joystickStates().clearButtonCommand(button); +} + +std::vector NavigationHandler::joystickButtonCommand(int button) const { + return _orbitalNavigator->joystickStates().buttonCommand(button); +} + + + scripting::LuaLibrary NavigationHandler::luaLibrary() { return { "navigation", @@ -324,6 +374,62 @@ scripting::LuaLibrary NavigationHandler::luaLibrary() { {}, "void", "Reset the camera direction to point at the focus node" + }, + { + "bindJoystickAxis", + &luascriptfunctions::bindJoystickAxis, + {}, + "int, axisType [, isInverted, isNormalized]", + "Binds the axis identified by the first argument to be used as the type " + "identified by the second argument. If 'isInverted' is 'true', the axis " + "value is inverted, if 'isNormalized' is true the axis value is " + "normalized from [-1, 1] to [0,1]." + }, + { + "joystickAxis", + &luascriptfunctions::joystickAxis, + {}, + "int", + "Returns the joystick axis information for the passed axis. The " + "information that is returned is the current axis binding as a string, " + "whether the values are inverted as bool, and whether the value are " + "normalized as a bool" + }, + { + "setAxisDeadZone", + &luascriptfunctions::setJoystickAxisDeadzone, + {}, + "int, float", + "Sets the deadzone for a particular joystick axis which means that any " + "input less than this value is completely ignored." + }, + { + "bindJoystickButton", + &luascriptfunctions::bindJoystickButton, + {}, + "int, string [, string, bool]", + "Binds a Lua script to be executed when the joystick button identified " + "by the first argument is triggered. The third argument determines when " + "the script should be executed, this defaults to 'pressed', which means " + "that the script is run when the user presses the button. The last " + "argument determines whether the command is going to be executable " + "locally or remotely. The latter being the default." + }, + { + "clearJoystickButotn", + &luascriptfunctions::clearJoystickButton, + {}, + "int", + "Removes all commands that are currently bound to the button identified " + "by the first argument" + }, + { + "joystickButton", + &luascriptfunctions::joystickButton, + {}, + "int", + "Returns the script that is currently bound to be executed when the " + "provided button is pressed" } } }; diff --git a/src/interaction/navigationhandler_lua.inl b/src/interaction/navigationhandler_lua.inl index 8ad65f406e..5a640be04e 100644 --- a/src/interaction/navigationhandler_lua.inl +++ b/src/interaction/navigationhandler_lua.inl @@ -22,6 +22,9 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#include +#include + namespace openspace::luascriptfunctions { int restoreCameraStateFromFile(lua_State* L) { @@ -88,4 +91,130 @@ int resetCameraDirection(lua_State* L) { return 0; } +int bindJoystickAxis(lua_State* L) { + int n = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::bindJoystickAxis"); + + int axis = static_cast(lua_tonumber(L, 1)); + std::string axisType = lua_tostring(L, 2); + + bool shouldInvert = false; + if (n > 2) { + shouldInvert = lua_toboolean(L, 3); + } + + bool shouldNormalize = false; + if (n > 3) { + shouldNormalize = lua_toboolean(L, 4); + } + + OsEng.navigationHandler().setJoystickAxisMapping( + axis, + ghoul::from_string(axisType), + interaction::JoystickCameraStates::AxisInvert(shouldInvert), + interaction::JoystickCameraStates::AxisNormalize(shouldNormalize) + ); + + + return 0; +} + +int joystickAxis(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickAxis"); + + int axis = static_cast(lua_tonumber(L, 1)); + + using AI = interaction::JoystickCameraStates::AxisInformation; + AI info = OsEng.navigationHandler().joystickAxisMapping(axis); + + lua_settop(L, 0); + lua_pushstring(L, std::to_string(info.type).c_str()); + lua_pushboolean(L, info.invert); + lua_pushboolean(L, info.normalize); + + return 3; +} + +int setJoystickAxisDeadzone(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setJoystickAxisDeadzone"); + + int axis = static_cast(lua_tointeger(L, 1)); + float deadzone = static_cast(lua_tonumber(L, 2)); + + OsEng.navigationHandler().setJoystickAxisDeadzone(axis, deadzone); + + return 0; +} + +int joystickAxisDeadzone(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setJoystickAxisDeadzone"); + + int axis = static_cast(lua_tointeger(L, 1)); + + float deadzone = OsEng.navigationHandler().joystickAxisDeadzone(axis); + + lua_pushnumber(L, deadzone); + return 1; +} + +int bindJoystickButton(lua_State* L) { + int n = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::bindJoystickButton"); + + int button = static_cast(lua_tonumber(L, 1)); + std::string command = lua_tostring(L, 2); + + interaction::JoystickAction action = interaction::JoystickAction::Press; + if (n >= 3) { + action = ghoul::from_string(lua_tostring(L, 3)); + } + + bool isRemote = true; + if (n == 4) { + isRemote = lua_toboolean(L, 4); + } + + OsEng.navigationHandler().bindJoystickButtonCommand( + button, + std::move(command), + action, + interaction::JoystickCameraStates::ButtonCommandRemote(isRemote) + ); + + lua_settop(L, 0); + return 0; +} + +int clearJoystickButton(lua_State* L) { + int n = ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::bindJoystickButton"); + + int button = static_cast(lua_tonumber(L, 1)); + + OsEng.navigationHandler().clearJoystickButtonCommand(button); + + lua_settop(L, 0); + return 0; +} + +int joystickButton(lua_State* L) { + int n = ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::bindJoystickButton"); + + int button = static_cast(lua_tonumber(L, 1)); + + std::vector cmds = OsEng.navigationHandler().joystickButtonCommand( + button + ); + + std::string cmd = std::accumulate( + cmds.begin(), + cmds.end(), + std::string(), + [](std::string lhs, std::string rhs) { + return lhs + ";" + rhs; + } + ); + + lua_settop(L, 0); + lua_pushstring(L, cmd.c_str()); + return 1; +} + } // namespace openspace::luascriptfunctions diff --git a/src/interaction/orbitalnavigator.cpp b/src/interaction/orbitalnavigator.cpp index 137a723720..dc2287e04a 100644 --- a/src/interaction/orbitalnavigator.cpp +++ b/src/interaction/orbitalnavigator.cpp @@ -58,11 +58,18 @@ namespace { "disabled, the camera will zoom in or out forever." }; - static const openspace::properties::Property::PropertyInfo SensitivityInfo = { - "Sensitivity", - "Sensitivity", - "Determines the sensitivity of the camera motion. The lower the sensitivity is " - "the less impact a mouse mothion will have." + static const openspace::properties::Property::PropertyInfo MouseSensitivityInfo = { + "MouseSensitivity", + "Mouse Sensitivity", + "Determines the sensitivity of the camera motion thorugh the mouse. The lower " + "the sensitivity is the less impact a mouse motion will have." + }; + + static const openspace::properties::Property::PropertyInfo JoystickSensitivityInfo = { + "JoystickSensitivity", + "Joystick Sensitivity", + "Determines the sensitivity of the camera motion thorugh a joystick. The lower " + "the sensitivity is the less impact a joystick motion will have." }; static const openspace::properties::Property::PropertyInfo FrictionInfo = { @@ -148,8 +155,10 @@ OrbitalNavigator::OrbitalNavigator() : properties::PropertyOwner({ "OrbitalNavigator" }) , _followFocusNodeRotationDistance(FollowFocusNodeInfo, 5.0f, 0.0f, 20.f) , _minimumAllowedDistance(MinimumDistanceInfo, 10.0f, 0.0f, 10000.f) - , _sensitivity(SensitivityInfo, 15.0f, 1.0f, 50.f) - , _mouseStates(_sensitivity * pow(10.0, -4), 1 / (_friction.friction + 0.0000001)) + , _mouseSensitivity(MouseSensitivityInfo, 15.0f, 1.0f, 50.f) + , _joystickSensitivity(JoystickSensitivityInfo, 10.0f, 1.0f, 50.f) + , _mouseStates(_mouseSensitivity * 0.0001, 1 / (_friction.friction + 0.0000001)) + , _joystickStates(_joystickSensitivity * 0.1, 1 / (_friction.friction + 0.0000001)) , _useAdaptiveStereoscopicDepth(UseAdaptiveStereoscopicDepthInfo, true) , _staticViewScaleExponent(StaticViewScaleExponentInfo, 0.f, -30, 10) , _stereoscopicDepthOfFocusSurface(StereoscopicDepthOfFocusSurfaceInfo, 8, 0.25, 100) @@ -187,26 +196,33 @@ OrbitalNavigator::OrbitalNavigator() // Define callback functions for changed properties _friction.roll.onChange([&]() { _mouseStates.setRotationalFriction(_friction.roll); + _joystickStates.setRotationalFriction(_friction.roll); }); _friction.rotational.onChange([&]() { _mouseStates.setHorizontalFriction(_friction.rotational); + _joystickStates.setHorizontalFriction(_friction.rotational); }); _friction.zoom.onChange([&]() { _mouseStates.setVerticalFriction(_friction.zoom); + _joystickStates.setVerticalFriction(_friction.zoom); }); _friction.friction.onChange([&]() { _mouseStates.setVelocityScaleFactor(1 / (_friction.friction + 0.0000001)); + _joystickStates.setVelocityScaleFactor(1 / (_friction.friction + 0.0000001)); }); - _sensitivity.onChange([&]() { - _mouseStates.setSensitivity(_sensitivity * pow(10.0,-4)); + _mouseSensitivity.onChange([&]() { + _mouseStates.setSensitivity(_mouseSensitivity * pow(10.0, -4)); }); + _joystickSensitivity.onChange([&]() { + _joystickStates.setSensitivity(_joystickSensitivity * pow(10.0, -4)); + }); + addPropertySubOwner(_friction); addProperty(_followFocusNodeRotationDistance); addProperty(_minimumAllowedDistance); - addProperty(_sensitivity); addProperty(_useAdaptiveStereoscopicDepth); addProperty(_staticViewScaleExponent); @@ -214,17 +230,20 @@ OrbitalNavigator::OrbitalNavigator() addProperty(_rotateToFocusInterpolationTime); addProperty(_stereoInterpolationTime); + addProperty(_mouseSensitivity); + addProperty(_joystickSensitivity); } OrbitalNavigator::~OrbitalNavigator() {} -void OrbitalNavigator::updateMouseStatesFromInput(const InputState& inputState, +void OrbitalNavigator::updateStatesFromInput(const InputState& inputState, double deltaTime) { - _mouseStates.updateMouseStatesFromInput(inputState, deltaTime); + _mouseStates.updateStateFromInput(inputState, deltaTime); + _joystickStates.updateStateFromInput(inputState, deltaTime); } -void OrbitalNavigator::updateCameraStateFromMouseStates(Camera& camera, double deltaTime){ +void OrbitalNavigator::updateCameraStateFromStates(Camera& camera, double deltaTime){ if (_focusNode) { // Read the current state of the camera glm::dvec3 camPos = camera.positionVec3(); @@ -448,23 +467,31 @@ OrbitalNavigator::CameraRotationDecomposition glm::dquat OrbitalNavigator::roll(double deltaTime, const glm::dquat& localCameraRotation) const { - glm::dquat rollQuat = glm::angleAxis( - _mouseStates.localRollMouseVelocity().x * deltaTime, + glm::dquat mouseRollQuat = glm::angleAxis( + _mouseStates.localRollVelocity().x * deltaTime + + _joystickStates.localRollVelocity().x * deltaTime, glm::dvec3(0.0, 0.0, 1.0) ); - return localCameraRotation * rollQuat; + return localCameraRotation * mouseRollQuat; } glm::dquat OrbitalNavigator::rotateLocally(double deltaTime, const glm::dquat& localCameraRotation) const { - glm::dvec3 eulerAngles( - _mouseStates.localRotationMouseVelocity().y, - _mouseStates.localRotationMouseVelocity().x, + glm::dquat mouseRotationDiff = glm::dquat(glm::dvec3( + _mouseStates.localRotationVelocity().y, + _mouseStates.localRotationVelocity().x, 0.0 - ); - glm::dquat rotationDiff = glm::dquat(eulerAngles * deltaTime); - return localCameraRotation * rotationDiff; + ) * deltaTime); + + glm::dquat joystickRotationDiff = glm::dquat(glm::dvec3( + _joystickStates.localRotationVelocity().y, + _joystickStates.localRotationVelocity().x, + 0.0 + ) * deltaTime); + + + return localCameraRotation * joystickRotationDiff * mouseRotationDiff; } glm::dquat OrbitalNavigator::interpolateLocalRotation(double deltaTime, @@ -569,16 +596,21 @@ glm::dvec3 OrbitalNavigator::translateHorizontally(double deltaTime, 1.0; // Get rotation in camera space - glm::dvec3 eulerAngles = glm::dvec3( - -_mouseStates.globalRotationMouseVelocity().y * deltaTime, - -_mouseStates.globalRotationMouseVelocity().x * deltaTime, - 0) * speedScale; - glm::dquat rotationDiffCamSpace = glm::dquat(eulerAngles); + glm::dquat mouseRotationDiffCamSpace = glm::dquat(glm::dvec3( + -_mouseStates.globalRotationVelocity().y * deltaTime, + -_mouseStates.globalRotationVelocity().x * deltaTime, + 0) * speedScale); + + glm::dquat joystickRotationDiffCamSpace = glm::dquat(glm::dvec3( + -_joystickStates.globalRotationVelocity().y * deltaTime, + -_joystickStates.globalRotationVelocity().x * deltaTime, + 0) * speedScale); // Transform to world space glm::dquat rotationDiffWorldSpace = globalCameraRotation * - rotationDiffCamSpace * + joystickRotationDiffCamSpace * + mouseRotationDiffCamSpace * glm::inverse(globalCameraRotation); // Rotate and find the difference vector @@ -645,8 +677,12 @@ glm::dvec3 OrbitalNavigator::translateVertically( glm::dmat3(modelTransform) * centerToActualSurfaceModelSpace; glm::dvec3 actualSurfaceToCamera = posDiff - centerToActualSurface; + const double totalVelocity = + _joystickStates.truckMovementVelocity().y + + _mouseStates.truckMovementVelocity().y; + return cameraPosition - - actualSurfaceToCamera * _mouseStates.truckMovementMouseVelocity().y * deltaTime; + actualSurfaceToCamera * totalVelocity * deltaTime; } glm::dquat OrbitalNavigator::rotateHorizontally( @@ -662,12 +698,12 @@ glm::dquat OrbitalNavigator::rotateHorizontally( glm::dvec3 directionFromSurfaceToCamera = glm::normalize(glm::dmat3(modelTransform) * directionFromSurfaceToCameraModelSpace); - glm::dquat cameraRollRotation = - glm::angleAxis( - _mouseStates.globalRollMouseVelocity().x * - deltaTime, directionFromSurfaceToCamera - ); - return cameraRollRotation * globalCameraRotation; + glm::dquat mouseCameraRollRotation = glm::angleAxis( + _mouseStates.globalRollVelocity().x * deltaTime + + _joystickStates.globalRollVelocity().x * deltaTime, + directionFromSurfaceToCamera + ); + return mouseCameraRollRotation * globalCameraRotation; } glm::dvec3 OrbitalNavigator::pushToSurface( @@ -741,4 +777,9 @@ SurfacePositionHandle OrbitalNavigator::calculateSurfacePositionHandle( return posHandle; } +JoystickCameraStates& OrbitalNavigator::joystickStates() { + return _joystickStates; +} + + } // namespace openspace::interaction diff --git a/src/rendering/luaconsole.cpp b/src/rendering/luaconsole.cpp new file mode 100644 index 0000000000..bb04359b78 --- /dev/null +++ b/src/rendering/luaconsole.cpp @@ -0,0 +1,916 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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 + +namespace { + const char* HistoryFile = "ConsoleHistory"; + + const int NoAutoComplete = -1; + + const int MaximumHistoryLength = 1000; + + // A high number is chosen since we didn't have a version number before + // any small number might also be equal to the console history length + + const uint64_t CurrentVersion = 0xFEEE'FEEE'0000'0001; + + const openspace::Key CommandInputButton = openspace::Key::GraveAccent; + + const char* FontName = "Console"; + const float EntryFontSize = 14.0f; + const float HistoryFontSize = 11.0f; + + // Additional space between the entry text and the history (in pixels) + const float SeparatorSpace = 30.f; + + // Determines at which speed the console opens. + const float ConsoleOpenSpeed = 2.5; + + // The number of characters to display after the cursor + // when horizontal scrolling is required. + const int NVisibleCharsAfterCursor = 5; + + const static openspace::properties::Property::PropertyInfo VisibleInfo = { + "IsVisible", + "Is Visible", + "Determines whether the Lua console is shown on the screen or not. Toggling it " + "will fade the console in and out." + }; + + const static openspace::properties::Property::PropertyInfo RemoveScriptingInfo = { + "RemoteScripting", + "Remote scripting", + "Determines whether the entered commands will only be executed locally (if this " + "is disabled), or whether they will be send to connected remove instances." + }; + + const static openspace::properties::Property::PropertyInfo BackgroundColorInfo = { + "BackgroundColor", + "Background Color", + "Sets the background color of the console." + }; + + const static openspace::properties::Property::PropertyInfo HighlightColorInfo = { + "HighlightColor", + "Highlight Color", + "Sets the color of the lines below the console." + }; + + const static openspace::properties::Property::PropertyInfo SeparatorColorInfo = { + "SeparatorColor", + "Separator Color", + "Sets the color of the separator between the history part and the entry part of " + "the console." + }; + + const static openspace::properties::Property::PropertyInfo EntryTextColorInfo = { + "EntryTextColor", + "Entry Text Color", + "Sets the text color of the entry area of the console." + }; + + const static openspace::properties::Property::PropertyInfo HistoryTextColorInfo = { + "HistoryTextColor", + "History Text Color", + "Sets the text color of the history area of the console." + }; + + const static openspace::properties::Property::PropertyInfo HistoryLengthInfo = { + "HistoryLength", + "History Length", + "Determines the length of the history in number of lines." + }; +} // namespace + +namespace openspace { + +LuaConsole::LuaConsole() + : properties::PropertyOwner({ "LuaConsole" }) + , _isVisible(VisibleInfo, false) + , _remoteScripting(RemoveScriptingInfo, false) + , _backgroundColor( + BackgroundColorInfo, + glm::vec4(21.f / 255.f, 23.f / 255.f, 28.f / 255.f, 0.8f), + glm::vec4(0.f), + glm::vec4(1.f) + ) + , _highlightColor( + HighlightColorInfo, + glm::vec4(1.f, 1.f, 1.f, 0.f), + glm::vec4(0.f), + glm::vec4(1.f) + ) + , _separatorColor( + SeparatorColorInfo, + glm::vec4(0.4f, 0.4f, 0.4f, 0.f), + glm::vec4(0.f), + glm::vec4(1.f) + ) + , _entryTextColor( + EntryTextColorInfo, + glm::vec4(1.f, 1.f, 1.f, 1.f), + glm::vec4(0.f), + glm::vec4(1.f) + ) + , _historyTextColor( + HistoryTextColorInfo, + glm::vec4(1.0f, 1.0f, 1.0f, 0.65f), + glm::vec4(0.f), + glm::vec4(1.f) + ) + , _historyLength(HistoryLengthInfo, 13, 0, 100) + , _inputPosition(0) + , _activeCommand(0) + , _autoCompleteInfo({NoAutoComplete, false, ""}) + , _currentHeight(0.f) + , _targetHeight(0.f) + , _fullHeight(0.f) +{ + addProperty(_isVisible); + addProperty(_remoteScripting); + addProperty(_historyLength); + + _backgroundColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(_backgroundColor); + _highlightColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(_highlightColor); + _separatorColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(_separatorColor); + _entryTextColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(_entryTextColor); + _historyTextColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(_historyTextColor); +} + +void LuaConsole::initialize() { + const std::string filename = FileSys.cacheManager()->cachedFilename( + HistoryFile, + "", + ghoul::filesystem::CacheManager::Persistent::Yes + ); + + if (FileSys.fileExists(filename)) { + std::ifstream file(filename, std::ios::binary | std::ios::in); + + if (file.good()) { + // Read the number of commands from the history + uint64_t version; + file.read(reinterpret_cast(&version), sizeof(uint64_t)); + + if (version != CurrentVersion) { + LWARNINGC( + "LuaConsole", + fmt::format("Outdated console history version: {}", version) + ); + } + else { + int64_t nCommands; + file.read(reinterpret_cast(&nCommands), sizeof(int64_t)); + + for (int64_t i = 0; i < nCommands; ++i) { + int64_t length; + file.read(reinterpret_cast(&length), sizeof(int64_t)); + + std::vector tmp(length); + file.read(tmp.data(), length); + _commandsHistory.emplace_back(std::string(tmp.begin(), tmp.end())); + } + } + } + } + + _commands = _commandsHistory; + _commands.push_back(""); + _activeCommand = _commands.size() - 1; + + _program = ghoul::opengl::ProgramObject::Build( + "Console", + absPath("${SHADERS}/luaconsole.vert"), + absPath("${SHADERS}/luaconsole.frag") + ); + + _uniformCache.res = _program->uniformLocation("res"); + _uniformCache.color = _program->uniformLocation("color"); + _uniformCache.height = _program->uniformLocation("height"); + _uniformCache.ortho = _program->uniformLocation("ortho"); + + GLfloat data[] = { + 0.f, 0.f, + 1.f, 1.f, + 0.f, 1.f, + + 0.f, 0.f, + 1.f, 0.f, + 1.f, 1.f + }; + + glGenVertexArrays(1, &_vao); + glBindVertexArray(_vao); + glGenBuffers(1, &_vbo); + glBindBuffer(GL_ARRAY_BUFFER, _vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer( + 0, + 2, + GL_FLOAT, + GL_FALSE, + 2 * sizeof(GLfloat), + nullptr + ); + + glBindVertexArray(0); + + _font = OsEng.fontManager().font( + FontName, + EntryFontSize, + ghoul::fontrendering::FontManager::Outline::No + ); + + _historyFont = OsEng.fontManager().font( + FontName, + HistoryFontSize, + ghoul::fontrendering::FontManager::Outline::No + ); + + OsEng.parallelPeer().connectionEvent()->subscribe( + "luaConsole", + "statusChanged", + [this]() { + ParallelConnection::Status status = OsEng.parallelPeer().status(); + parallelConnectionChanged(status); + } + ); +} + +void LuaConsole::deinitialize() { + const std::string filename = FileSys.cacheManager()->cachedFilename( + HistoryFile, + "", + ghoul::filesystem::CacheManager::Persistent::Yes + ); + + // We want to limit the command history to a realistic value, so that it doesn't + // grow without bounds + if (_commandsHistory.size() > MaximumHistoryLength) { + _commandsHistory = std::vector( + _commandsHistory.end() - MaximumHistoryLength, + _commandsHistory.end() + ); + } + + std::ofstream file(filename, std::ios::binary); + if (file.good()) { + uint64_t version = CurrentVersion; + file.write(reinterpret_cast(&version), sizeof(uint64_t)); + + int64_t nCommands = _commandsHistory.size(); + file.write(reinterpret_cast(&nCommands), sizeof(int64_t)); + + for (const std::string& s : _commandsHistory) { + int64_t length = s.length(); + file.write(reinterpret_cast(&length), sizeof(int64_t)); + // We don't write the \0 at the end on purpose + file.write(s.c_str(), length); + } + } + + _program = nullptr; + + OsEng.parallelPeer().connectionEvent()->unsubscribe("luaConsole"); +} + +bool LuaConsole::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) { + if (action != KeyAction::Press && action != KeyAction::Repeat) { + return false; + } + + if (key == CommandInputButton) { + // Button left of 1 and above TAB + // How to deal with different keyboard languages? ---abock + if (_isVisible) { + if (_remoteScripting) { + _remoteScripting = false; + } + else { + _isVisible = false; + _commands.back() = ""; + _inputPosition = 0; + } + } + else { + _isVisible = true; + if (OsEng.parallelPeer().status() == ParallelConnection::Status::Host) { + _remoteScripting = true; + } + } + + return true; + } + + if (!_isVisible) { + return false; + } + + if (key == Key::Escape) { + _isVisible = false; + return true; + } + + + const bool modifierControl = (modifier == KeyModifier::Control); + const bool modifierShift = (modifier == KeyModifier::Shift); + + // Paste from clipboard + if (modifierControl && (key == Key::V || key == Key::Y)) { + addToCommand(sanitizeInput(ghoul::clipboardText())); + return true; + } + + // Copy to clipboard + if (modifierControl && key == Key::C) { + ghoul::setClipboardText(_commands.at(_activeCommand)); + return true; + } + + // Cut to clipboard + if (modifierControl && key == Key::X) { + ghoul::setClipboardText(_commands.at(_activeCommand)); + _commands.at(_activeCommand).clear(); + _inputPosition = 0; + } + + // Cut part after cursor to clipboard ("Kill") + if (modifierControl && key == Key::K) { + auto here = _commands.at(_activeCommand).begin() + _inputPosition; + auto end = _commands.at(_activeCommand).end(); + ghoul::setClipboardText(std::string(here, end)); + _commands.at(_activeCommand).erase(here, end); + } + + // Go to the previous character + if (key == Key::Left || (modifierControl && key == Key::B)) { + if (_inputPosition > 0) { + --_inputPosition; + } + return true; + } + + // Go to the next character + if (key == Key::Right || (modifierControl && key == Key::F)) { + _inputPosition = std::min( + _inputPosition + 1, + _commands.at(_activeCommand).length() + ); + return true; + } + + // Go to previous command + if (key == Key::Up) { + if (_activeCommand > 0) { + --_activeCommand; + } + _inputPosition = _commands.at(_activeCommand).length(); + return true; + } + + // Go to next command (the last is empty) + if (key == Key::Down) { + if (_activeCommand < _commands.size() - 1) { + ++_activeCommand; + } + _inputPosition = _commands.at(_activeCommand).length(); + return true; + } + + // Remove character before _inputPosition + if (key == Key::BackSpace) { + if (_inputPosition > 0) { + _commands.at(_activeCommand).erase(_inputPosition - 1, 1); + --_inputPosition; + } + return true; + } + + // Remove character after _inputPosition + if (key == Key::Delete) { + if (_inputPosition <= _commands.at(_activeCommand).size()) { + _commands.at(_activeCommand).erase(_inputPosition, 1); + } + return true; + } + + // Go to the beginning of command string + if (key == Key::Home || (modifierControl && key == Key::A)) { + _inputPosition = 0; + return true; + } + + // Go to the end of command string + if (key == Key::End || (modifierControl && key == Key::E)) { + _inputPosition = _commands.at(_activeCommand).size(); + return true; + } + + if (key == Key::Enter || key == Key::KeypadEnter) { + std::string cmd = _commands.at(_activeCommand); + if (cmd != "") { + using RemoteScripting = scripting::ScriptEngine::RemoteScripting; + OsEng.scriptEngine().queueScript( + cmd, + _remoteScripting ? RemoteScripting::Yes : RemoteScripting::No + ); + + // Only add the current command to the history if it hasn't been + // executed before. We don't want two of the same commands in a row + if (_commandsHistory.empty() || (cmd != _commandsHistory.back())) { + _commandsHistory.push_back(_commands.at(_activeCommand)); + } + } + + // Some clean up after the execution of the command + _commands = _commandsHistory; + _commands.push_back(""); + _activeCommand = _commands.size() - 1; + _inputPosition = 0; + return true; + } + + if (key == Key::Tab) { + // We get a list of all the available commands and initially find the first + // command that starts with how much we typed sofar. We store the index so + // that in subsequent "tab" presses, we will discard previous commands. This + // implements the 'hop-over' behavior. As soon as another key is pressed, + // everything is set back to normal + + // If the shift key is pressed, we decrement the current index so that we will + // find the value before the one that was previously found + if (_autoCompleteInfo.lastIndex != NoAutoComplete && modifierShift) { + _autoCompleteInfo.lastIndex -= 2; + } + std::vector allCommands = OsEng.scriptEngine().allLuaFunctions(); + std::sort(allCommands.begin(), allCommands.end()); + + std::string currentCommand = _commands.at(_activeCommand); + + // Check if it is the first time the tab has been pressed. If so, we need to + // store the already entered command so that we can later start the search + // from there. We will overwrite the 'currentCommand' thus making the storage + // necessary + if (!_autoCompleteInfo.hasInitialValue) { + _autoCompleteInfo.initialValue = currentCommand; + _autoCompleteInfo.hasInitialValue = true; + } + + for (int i = 0; i < static_cast(allCommands.size()); ++i) { + const std::string& command = allCommands[i]; + + // Check if the command has enough length (we don't want crashes here) + // Then check if the iterator-command's start is equal to what we want + // then check if we need to skip the first found values as the user has + // pressed TAB repeatedly + size_t fullLength = _autoCompleteInfo.initialValue.length(); + bool correctLength = command.length() >= fullLength; + + std::string commandLowerCase; + std::transform( + command.begin(), command.end(), + std::back_inserter(commandLowerCase), + [](char v) { return static_cast(tolower(v)); } + ); + + std::string initialValueLowerCase; + std::transform( + _autoCompleteInfo.initialValue.begin(), + _autoCompleteInfo.initialValue.end(), + std::back_inserter(initialValueLowerCase), + [](char v) { return static_cast(tolower(v)); } + ); + + bool correctCommand = + commandLowerCase.substr(0, fullLength) == initialValueLowerCase; + + if (correctLength && correctCommand && (i > _autoCompleteInfo.lastIndex)) { + // We found our index, so store it + _autoCompleteInfo.lastIndex = i; + + // We only want to auto-complete until the next separator "." + size_t pos = command.find('.', fullLength); + if (pos == std::string::npos) { + // If we don't find a separator, we autocomplete until the end + // Set the found command as active command + _commands.at(_activeCommand) = command + "();"; + // Set the cursor position to be between the brackets + _inputPosition = _commands.at(_activeCommand).size() - 2; + } + else { + // If we find a separator, we autocomplete until and including the + // separator unless the autocompletion would be the same that we + // already have (the case if there are multiple commands in the + // same group + std::string subCommand = command.substr(0, pos + 1); + if (subCommand == _commands.at(_activeCommand)) { + continue; + } + else { + _commands.at(_activeCommand) = command.substr(0, pos + 1); + _inputPosition = _commands.at(_activeCommand).length(); + // We only want to remove the autocomplete info if we just + // entered the 'default' openspace namespace + if (command.substr(0, pos + 1) == "openspace.") { + _autoCompleteInfo = { NoAutoComplete, false, "" }; + } + } + } + + break; + } + } + return true; + } + else { + // If any other key is pressed, we want to remove our previous findings + // The special case for Shift is necessary as we want to allow Shift+TAB + if (!modifierShift) { + _autoCompleteInfo = { NoAutoComplete, false, "" }; + } + } + + // We want to ignore the function keys as they don't translate to text anyway + if (key >= Key::F1 && key <= Key::F25) { + return false; + } + + // Do not consume modifier keys + switch (key) { + case Key::LeftShift: + case Key::RightShift: + case Key::LeftAlt: + case Key::RightAlt: + case Key::LeftControl: + case Key::RightControl: + return false; + default: + return true; + } +} + +void LuaConsole::charCallback(unsigned int codepoint, + [[maybe_unused]] KeyModifier modifier) +{ + if (!_isVisible) { + return; + } + + if (codepoint == static_cast(CommandInputButton)) { + return; + } + +#ifndef WIN32 + const bool modifierControl = (modifier == KeyModifier::Control); + + const int codepoint_C = 99; + const int codepoint_V = 118; + if (modifierControl && (codepoint == codepoint_C || codepoint == codepoint_V)) { + return; + } +#endif + + // Disallow all non ASCII characters for now + if (codepoint > 0x7f) { + return; + } + + addToCommand(std::string(1, static_cast(codepoint))); +} + +void LuaConsole::update() { + // Compute the height by simulating _historyFont number of lines and checking + // what the bounding box for that text would be. + using namespace ghoul::fontrendering; + const size_t nLines = std::min( + static_cast(_historyLength), + _commandsHistory.size() + ); + const auto bbox = FontRenderer::defaultRenderer().boundingBox( + *_historyFont, + std::string(nLines, '\n').c_str() + ); + + // Update the full height and the target height. + // Add the height of the entry line and space for a separator. + _fullHeight = (bbox.boundingBox.y + EntryFontSize + SeparatorSpace); + _targetHeight = _isVisible ? _fullHeight : 0; + + // The first frame is going to be finished in approx 10 us, which causes a floating + // point overflow when computing dHeight + const double frametime = std::max( + OsEng.windowWrapper().deltaTime(), + 1e-4 + ); + + // Update the current height. + // The current height is the offset that is used to slide + // the console in from the top. + const glm::ivec2 res = OsEng.windowWrapper().currentWindowResolution(); + const glm::vec2 dpiScaling = OsEng.windowWrapper().dpiScaling(); + const double dHeight = (_targetHeight - _currentHeight) * + std::pow(0.98, 1.0 / (ConsoleOpenSpeed / dpiScaling.y * frametime)); + + _currentHeight += static_cast(dHeight); + + _currentHeight = std::max(0.0f, _currentHeight); + _currentHeight = std::min(static_cast(res.y), _currentHeight); +} + +void LuaConsole::render() { + using namespace ghoul::fontrendering; + + // Don't render the console if it's collapsed. + if (_currentHeight < 1.0f) { + return; + } + + if (_program->isDirty()) { + _program->rebuildFromFile(); + + _uniformCache.res = _program->uniformLocation("res"); + _uniformCache.color = _program->uniformLocation("color"); + _uniformCache.height = _program->uniformLocation("height"); + _uniformCache.ortho = _program->uniformLocation("ortho"); + } + + const glm::vec2 dpiScaling = OsEng.windowWrapper().dpiScaling(); + const glm::ivec2 res = + glm::vec2(OsEng.windowWrapper().currentWindowResolution()) / dpiScaling; + + + // Render background + glDisable(GL_CULL_FACE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_DEPTH_TEST); + + _program->activate(); + + _program->setUniform(_uniformCache.res, res); + _program->setUniform(_uniformCache.color, _backgroundColor); + _program->setUniform(_uniformCache.height, _currentHeight / res.y); + _program->setUniform( + _uniformCache.ortho, + glm::ortho( + 0.f, static_cast(res.x), 0.f, static_cast(res.y) + ) + ); + + // Draw the background color + glBindVertexArray(_vao); + glDrawArrays(GL_TRIANGLES, 0, 6); + + // Draw the highlight lines above and below the background + _program->setUniform(_uniformCache.color, _highlightColor); + glDrawArrays(GL_LINES, 1, 4); + + // Draw the separator between the current entry box and the history + _program->setUniform(_uniformCache.color, _separatorColor); + _program->setUniform( + _uniformCache.height, + _currentHeight / res.y - 2.5f * EntryFontSize / res.y + ); + glDrawArrays(GL_LINES, 1, 2); + + _program->deactivate(); + + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + + // Render text on top of the background + glm::vec2 inputLocation = glm::vec2( + EntryFontSize / 2.f, + res.y - _currentHeight + EntryFontSize + ); + + // Render the current command + std::string currentCommand = _commands.at(_activeCommand); + // We chop off the beginning and end of the string until it fits on the screen (with + // a margin) this should be replaced as soon as the mono-spaced fonts work properly. + // Right now, every third character is a bit wider than the others + + size_t nChoppedCharsBeginning = 0, nChoppedCharsEnd = 0; + + const size_t inputPositionFromEnd = currentCommand.size() - _inputPosition; + while (true) { + using namespace ghoul::fontrendering; + // Compute the current width of the string and console prefix. + const float currentWidth = FontRenderer::defaultRenderer().boundingBox( + *_font, + "> %s", + currentCommand.c_str() + ).boundingBox.x + inputLocation.x; + + // Compute the overflow in pixels + const float overflow = currentWidth - res.x * 0.995f; + if (overflow <= 0.f) { + break; + } + + // Since the overflow is positive, at least one character needs to be removed. + const size_t nCharsOverflow = static_cast(std::min( + std::max(1.f, overflow / _font->glyph('m')->width()), + static_cast(currentCommand.size()) + )); + + // Do not hide the cursor and `NVisibleCharsAfterCursor` characters in the end. + const size_t maxAdditionalCharsToChopEnd = std::max( + 0, + static_cast(inputPositionFromEnd) - + (NVisibleCharsAfterCursor + 1) - + static_cast(nChoppedCharsEnd) + ); + + // Do not hide the cursor in the beginning. + const size_t maxAdditionalCharsToChopBeginning = std::max( + 0, + static_cast(_inputPosition) - 1 - + static_cast(nChoppedCharsBeginning) + ); + + // Prioritize chopping in the end of the string. + const size_t nCharsToChopEnd = std::min( + nCharsOverflow, + maxAdditionalCharsToChopEnd + ); + const size_t nCharsToChopBeginning = std::min( + nCharsOverflow - nCharsToChopEnd, + maxAdditionalCharsToChopBeginning + ); + + nChoppedCharsBeginning += nCharsToChopBeginning; + nChoppedCharsEnd += nCharsToChopEnd; + + const size_t displayLength = + _commands.at(_activeCommand).size() - + nChoppedCharsBeginning - nChoppedCharsEnd; + + currentCommand = _commands.at(_activeCommand).substr( + nChoppedCharsBeginning, + displayLength + ); + } + + RenderFontCr( + *_font, + inputLocation, + _entryTextColor, + "> %s", + currentCommand.c_str() + ); + + // Just offset the ^ marker slightly for a nicer look + inputLocation.y += 3 * dpiScaling.y; + + // Render the ^ marker below the text to show where the current entry point is + RenderFont( + *_font, + inputLocation, + _entryTextColor, + (std::string(_inputPosition - nChoppedCharsBeginning + 2, ' ') + "^").c_str() + ); + + glm::vec2 historyInputLocation = glm::vec2( + HistoryFontSize / 2.f, + res.y - HistoryFontSize * 1.5f + _fullHeight - _currentHeight + ); + + // @CPP: Replace with array_view + std::vector commandSubset; + if (_commandsHistory.size() < static_cast(_historyLength)) { + commandSubset = _commandsHistory; + } + else { + commandSubset = std::vector( + _commandsHistory.end() - _historyLength, + _commandsHistory.end() + ); + } + + for (const std::string& cmd : commandSubset) { + RenderFontCr( + *_historyFont, + historyInputLocation, + _historyTextColor, + "%s", + cmd.c_str() + ); + } + + // Computes the location for right justified text on the same y height as the entry + auto locationForRightJustifiedText = [&](const std::string& text) { + using namespace ghoul::fontrendering; + + const glm::vec2 loc = glm::vec2( + EntryFontSize / 2.f, + res.y - _currentHeight + EntryFontSize + ); + + const auto bbox = FontRenderer::defaultRenderer().boundingBox( + *_font, text.c_str() + ); + return glm::vec2( + loc.x + res.x - bbox.boundingBox.x - 10.f, + loc.y + ); + }; + + if (_remoteScripting) { + const glm::vec4 red(1, 0, 0, 1); + + ParallelConnection::Status status = OsEng.parallelPeer().status(); + const int nClients = + status != ParallelConnection::Status::Disconnected ? + OsEng.parallelPeer().nConnections() - 1 : + 0; + + const std::string nClientsText = + nClients == 1 ? + "Broadcasting script to 1 client" : + "Broadcasting script to " + std::to_string(nClients) + " clients"; + + const glm::vec2 loc = locationForRightJustifiedText(nClientsText); + RenderFont(*_font, loc, red, nClientsText.c_str()); + } else if (OsEng.parallelPeer().isHost()) { + const glm::vec4 lightBlue(0.4, 0.4, 1, 1); + + const std::string localExecutionText = "Local script execution"; + const glm::vec2 loc = locationForRightJustifiedText(localExecutionText); + RenderFont(*_font, loc, lightBlue, localExecutionText.c_str()); + } +} + +float LuaConsole::currentHeight() const { + return _currentHeight; +} + +void LuaConsole::addToCommand(std::string c) { + const size_t length = c.length(); + _commands.at(_activeCommand).insert(_inputPosition, std::move(c)); + _inputPosition += length; +} + +std::string LuaConsole::sanitizeInput(std::string str) { + // Remove carriage returns. + str.erase(std::remove(str.begin(), str.end(), '\r'), str.end()); + + // Replace newlines with spaces. + const std::function replace = [](char c) { + return c == '\n' ? ' ' : c; + }; + std::transform(str.begin(), str.end(), str.begin(), replace); + + return str; +} + +void LuaConsole::parallelConnectionChanged(const ParallelConnection::Status& status) { + _remoteScripting = (status == ParallelConnection::Status::Host); +} + +} // namespace openspace diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index b07dc76c7c..5d23e64583 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -27,19 +27,19 @@ #include #include -#include +#include #include #include #include -#include #include #include #include #include #include #include -#include #include +#include +#include #include #include #include @@ -261,22 +261,9 @@ RenderEngine::RenderEngine() _doPerformanceMeasurements.onChange([this](){ if (_doPerformanceMeasurements) { if (!_performanceManager) { - std::string loggingDir = "${BASE}"; - constexpr const char* KeyDir = ConfigurationManager::LoggingDirectory; - if (OsEng.configurationManager().hasKey(KeyDir)) { - loggingDir = OsEng.configurationManager().value(KeyDir); - } - - std::string prefix = "PM-"; - constexpr const char* KeyPrefix = - ConfigurationManager::LoggingPerformancePrefix; - if (OsEng.configurationManager().hasKey(KeyPrefix)) { - prefix = OsEng.configurationManager().value(KeyPrefix); - } - _performanceManager = std::make_shared( - loggingDir, - prefix + OsEng.configuration().logging.directory, + OsEng.configuration().logging.performancePrefix ); } } @@ -352,14 +339,9 @@ void RenderEngine::setRendererFromString(const std::string& renderingMethod) { void RenderEngine::initialize() { _frameNumber = 0; - std::string renderingMethod = DefaultRenderingMethod; - // If the user specified a rendering method that he would like to use, use that - ConfigurationManager& confManager = OsEng.configurationManager(); - if (confManager.hasKeyAndValue(KeyRenderingMethod)) { - renderingMethod = confManager.value(KeyRenderingMethod); - } - else { + std::string renderingMethod = OsEng.configuration().renderingMethod; + if (renderingMethod == "ABuffer") { using Version = ghoul::systemcapabilities::Version; // The default rendering method has a requirement of OpenGL 4.3, so if we are @@ -370,17 +352,9 @@ void RenderEngine::initialize() { } } - if (confManager.hasKey(ConfigurationManager::KeyDisableMasterRendering)) { - _disableMasterRendering = confManager.value( - ConfigurationManager::KeyDisableMasterRendering - ); - } - - if (confManager.hasKey(ConfigurationManager::KeyDisableSceneOnMaster)) { - _disableSceneTranslationOnMaster = confManager.value( - ConfigurationManager::KeyDisableSceneOnMaster - ); - } + _disableMasterRendering = OsEng.configuration().isRenderingOnMasterDisabled; + _disableSceneTranslationOnMaster = + OsEng.configuration().isSceneTranslationOnMasterDisabled; _raycasterManager = std::make_unique(); _deferredcasterManager = std::make_unique(); @@ -531,17 +505,12 @@ glm::ivec2 RenderEngine::renderingResolution() const { } glm::ivec2 RenderEngine::fontResolution() const { - std::string value; - bool hasValue = OsEng.configurationManager().getValue( - ConfigurationManager::KeyOnScreenTextScaling, - value - ); - if (hasValue && value == "framebuffer") { + const std::string& value = OsEng.configuration().onScreenTextScaling; + if (value == "framebuffer") { return OsEng.windowWrapper().getCurrentViewportSize(); //return OsEng.windowWrapper().currentWindowResolution(); } else { - // The default is to use the window size return OsEng.windowWrapper().currentWindowSize(); } } diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index b4a4f25e7c..beddbec00e 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include #include diff --git a/src/scripting/scriptengine.cpp b/src/scripting/scriptengine.cpp index d7839e0749..afc31763f8 100644 --- a/src/scripting/scriptengine.cpp +++ b/src/scripting/scriptengine.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include #include @@ -587,16 +587,8 @@ bool ScriptEngine::writeLog(const std::string& script) { // Check that logging is enabled and initialize if necessary if (!_logFileExists) { // If a ScriptLogFile was specified, generate it now - const bool hasFile = OsEng.configurationManager().hasKey( - ConfigurationManager::KeyScriptLog - ); - if (hasFile) { - OsEng.configurationManager().getValue( - ConfigurationManager::KeyScriptLog, - _logFilename - ); - - _logFilename = absPath(_logFilename); + if (!OsEng.configuration().scriptLog.empty()) { + _logFilename = absPath(OsEng.configuration().scriptLog); _logFileExists = true; LDEBUG(fmt::format( diff --git a/tests/main.cpp b/tests/main.cpp index af3fb23472..22dc7fc4ea 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -49,7 +49,6 @@ #define GHL_THROW_ON_ASSERT #endif // GHL_THROW_ON_ASSERTGHL_THROW_ON_ASSERT -#include #include #include #include