Files
OpenSpace/src/engine/configuration.cpp
Alexander Bock 4952f8f977 Code cleanup branch (#618)
* Make height map fallback layer work again
  * Add documentation to joystick button bindings
  * Removed grouped property headers
  * Add new version number constant generated by CMake
  * Make Joystick deadzone work properly
  * Change the startup date on Earth to today
  * Fix key modifier handling
  * Add debugging indices for TreeNodeDebugging
  * Fix script schedule for OsirisRex
  * Do not open Mission schedule automatically
  * Upload default projection texture automatically

  * General code cleanup
  * Fix check_style_guide warnings
  * Remove .clang-format
  * MacOS compile fixes
  * Clang analyzer fixes
2018-06-10 04:47:34 +00:00

358 lines
16 KiB
C++

/*****************************************************************************************
* *
* 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 <openspace/engine/configuration.h>
#include <openspace/documentation/documentation.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/lua/ghoul_lua.h>
#include <ghoul/lua/lua_helper.h>
#include <ghoul/misc/assert.h>
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* 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 <typename T>
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");
}
// NOLINTNEXTLINE
if constexpr (std::is_same_v<T, std::vector<std::string>>) {
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
std::vector<std::string> res;
for (size_t i = 1; i <= d.size(); ++i) {
res.push_back(d.value<std::string>(std::to_string(i)));
}
value = res;
}
// NOLINTNEXTLINE
else if constexpr (std::is_same_v<T, std::map<std::string, std::string>>) {
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
std::map<std::string, std::string> res;
for (size_t i = 0; i < d.size(); ++i) {
std::string key = d.keys()[i];
std::string v = d.value<std::string>(key);
res[std::move(key)] = std::move(v);
}
value = res;
}
// NOLINTNEXTLINE
else if constexpr (std::is_same_v<T, std::map<std::string, ghoul::Dictionary>>) {
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
std::map<std::string, ghoul::Dictionary> res;
for (size_t i = 0; i < d.size(); ++i) {
std::string key = d.keys()[i];
ghoul::Dictionary v = d.value<ghoul::Dictionary>(key);
res[std::move(key)] = std::move(v);
}
value = res;
}
// NOLINTNEXTLINE
else if constexpr (std::is_same_v<T, Configuration::Logging>) {
Configuration::Logging& v = static_cast<Configuration::Logging&>(value);
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(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<ghoul::Dictionary>(KeyLogs)) {
ghoul::Dictionary l = d.value<ghoul::Dictionary>(KeyLogs);
std::vector<ghoul::Dictionary> res;
for (size_t i = 1; i <= l.size(); ++i) {
res.push_back(l.value<ghoul::Dictionary>(std::to_string(i)));
}
v.logs = res;
}
}
// NOLINTNEXTLINE
else if constexpr (std::is_same_v<T, Configuration::DocumentationInfo>) {
Configuration::DocumentationInfo& v =
static_cast<Configuration::DocumentationInfo&>(value);
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(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);
}
// NOLINTNEXTLINE
else if constexpr (std::is_same_v<T, Configuration::LoadingScreen>) {
Configuration::LoadingScreen& v =
static_cast<Configuration::LoadingScreen&>(value);
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
d.getValue(KeyShowMessage, v.isShowingMessages);
d.getValue(KeyShowNodeNames, v.isShowingNodeNames);
d.getValue(KeyShowProgressbar, v.isShowingProgressbar);
}
// NOLINTNEXTLINE
else if constexpr (std::is_same_v<T, Configuration::OpenGLDebugContext>) {
Configuration::OpenGLDebugContext& v =
static_cast<Configuration::OpenGLDebugContext&>(value);
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
d.getValue(KeyActivate, v.isActive);
d.getValue(KeySynchronous, v.isSynchronous);
if (d.hasKeyAndValue<ghoul::Dictionary>(KeyFilterIdentifier)) {
ghoul::Dictionary f = d.value<ghoul::Dictionary>(KeyFilterIdentifier);
std::vector<Configuration::OpenGLDebugContext::IdentifierFilter> res;
for (size_t i = 1; i <= f.size(); ++i) {
Configuration::OpenGLDebugContext::IdentifierFilter filter;
ghoul::Dictionary fi = f.value<ghoul::Dictionary>(std::to_string(i));
double id = static_cast<double>(filter.identifier);
fi.getValue(KeyIdentifier, id);
filter.identifier = static_cast<unsigned int>(id);
fi.getValue(KeySource, filter.source);
fi.getValue(KeyType, filter.type);
res.push_back(filter);
}
v.identifierFilters = res;
}
if (d.hasKeyAndValue<ghoul::Dictionary>(KeyFilterSeverity)) {
ghoul::Dictionary f = d.value<ghoul::Dictionary>(KeyFilterSeverity);
std::vector<std::string> res;
for (size_t i = 1; i <= f.size(); ++i) {
res.push_back(f.value<std::string>(std::to_string(i)));
}
v.severityFilters = res;
}
}
// NOLINTNEXTLINE
else if constexpr (std::is_same_v<T, Configuration::HTTPProxy>) {
Configuration::HTTPProxy& v = static_cast<Configuration::HTTPProxy&>(value);
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L);
d.getValue(KeyActivate, v.usingHttpProxy);
d.getValue(KeyAddress, v.address);
double p = static_cast<double>(v.port);
d.getValue(KeyPort, p);
v.port = static_cast<unsigned int>(p);
d.getValue(KeyAuthentication, v.authentication);
d.getValue(KeyUser, v.user);
d.getValue(KeyPassword, v.password);
}
else {
value = ghoul::lua::value<T>(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