From 83ef5ed245d828574fb71ad1a649f222bc0072d4 Mon Sep 17 00:00:00 2001 From: GPayne Date: Wed, 15 Apr 2020 16:31:05 -0600 Subject: [PATCH] Switched profile-to-scene conversion from lua script to Profile class --- include/openspace/scene/profile.h | 10 + include/openspace/scene/profilefile.h | 8 +- scripts/convert_profile_to_scene.lua | 473 -------------------------- src/engine/openspaceengine.cpp | 41 +-- src/scene/profile.cpp | 31 +- 5 files changed, 52 insertions(+), 511 deletions(-) delete mode 100644 scripts/convert_profile_to_scene.lua diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 42e1e2b3fd..9bfabfde04 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -54,6 +54,16 @@ public: */ void saveCurrentSettingsToProfile(std::string filename); + /** + * Reads in a .profile file, converts it to scene/asset equivalent syntax, and + * writes the result to the specified output path. + * \param inProfilePath The .profile file to be converted + * \param outFilePath The output file path that will be written with the converted + * contents (in an .asset file) + */ + void convertToAssetFile(const std::string inProfilePath, + const std::string outFilePath); + /** * Returns the string contents of a profileFile object converted to scene/asset * equivalent syntax. diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 730c3cda18..82cfa0facd 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -137,22 +137,22 @@ public: /** * Updates the full string that defines the starting camera position. The format for - * this line is defined by ProfileFile::parseCamera and Profile::convertToAsset_camera + * this line is defined by ProfileFile::parseCamera & Profile::convertToAsset_camera * \param line The camera entry line to replace current camera entry */ void updateCamera(const std::string line); /** * Adds a new module line to the list of module lines to be analyzed by the profile - * at startup. The format for a module line is defined by ProfileFile::parseModule and - * Profile::convertToAsset_modules + * at startup. The format for a module line is defined by ProfileFile::parseModule + * and Profile::convertToAsset_modules * \param line The module name to be added */ void addModuleLine(const std::string line); /** * Adds a new asset to the list of assets to be loaded at startup. The format for an - * asset line is defined by ProfileFile::parseAsset and Profile::convertToAsset_assets + * asset line is defined by ProfileFile::parseAsset & Profile::convertToAsset_assets * \param line The asset name to be added */ void addAssetLine(const std::string line); diff --git a/scripts/convert_profile_to_scene.lua b/scripts/convert_profile_to_scene.lua deleted file mode 100644 index 0b852fe290..0000000000 --- a/scripts/convert_profile_to_scene.lua +++ /dev/null @@ -1,473 +0,0 @@ -version = '' -modulesTable = {} -assetsTable = {} -propertiesTable = {} -timeTable = {} -cameraTable = {} -markNodesTable = {} -keybindingsTable = {} -resultTable = {} -insideSection = false -currFunction = 'None' -currSection = 'None' -numLinesVersion = 0 -lineIndex = 1 - - -function printError(message) - print('Error @ line ' .. lineIndex .. ': ' .. message) -end - -function splitByTab(inputstr) - sep = "\t" - t = {} - for match in (inputstr .. sep):gmatch('(.-)' .. sep) do - table.insert(t, match) - end - return t; -end - -function parseVersion(line) - numLinesVersion = numLinesVersion + 1 - if numLinesVersion > 1 then - printError('Too many lines in Version section') - os.exit() - else - lineS = splitByTab(line) - if tableLen(lineS) > 1 then - printError('No tabs allowed in version entry') - os.exit() - else - version = line - end - end -end - -function parseMarkNodes(line) - lineS = splitByTab(line) - if tableLen(lineS) > 1 then - printError('No tabs allowed in MarkNodes entry') - os.exit() - else - table.insert(markNodesTable, line) - end -end - -function parseModule(line) - t = {} - t = splitByTab(line) - if tableLen(t) ~= 3 then - printError('3 fields requried in a Module entry') - os.exit() - else - table.insert(modulesTable, t) - end -end - -function parseAsset(line) - t = {} - t = splitByTab(line) - if tableLen(t) ~= 2 then - printError('2 fields required in a Asset entry') - os.exit() - else - local req = 'required' - if t[2] == 'requested' then - req = 'requested' - end - table.insert(assetsTable, {t[1], req}) - end -end - -function parseProperty(line) - t = {} - t = splitByTab(line) - if tableLen(t) ~= 3 then - printError('3 fields required in a Property entry') - os.exit() - elseif isBlank(t[1]) then - printError('Property set command (arg 1/3) is required') - os.exit() - elseif isBlank(t[2]) then - printError('Property name (arg 2/3) is required') - os.exit() - elseif isBlank(t[3]) then - printError('Property value to set (arg 3/3) is required') - os.exit() - end - - if t[1] ~= 'setPropertyValue' and t[1] ~= 'setPropertyValueSingle' then - printError('Property set command "' .. t[1] .. '" is not supported') - os.exit() - end - - table.insert(propertiesTable, t) -end - -function parseKeybinding(line) - local numReqFields = 6 - t = {} - t = splitByTab(line) - if tableLen(t) < numReqFields then - printError(numReqFields .. ' fields required in a Keybinding entry') - os.exit() - elseif isBlank(t[1]) then - printError('Keybinding key (arg 1/6) is required') - os.exit() - elseif isBlank(t[2]) then - printError('Keybinding documentation (arg 2/6) is required') - os.exit() - elseif isBlank(t[3]) then - printError('Keybinding name (arg 3/6) is required') - os.exit() - elseif isBlank(t[4]) then - printError('Keybinding GuiPath (arg 4/6) is required') - os.exit() - elseif isBlank(t[5]) then - printError('Keybinding local(T/F) (arg 5/6) is required') - os.exit() - elseif isBlank(t[6]) then - printError('Keybinding script to execute (arg 6/6) is required') - os.exit() - end - - --If there are more than 6 fields then combine the final fields together - --assuming that this is a lua script that contains tabs - if tableLen(t) > numReqFields then - for i=(numReqFields + 1),tableLen(t) do - t[numReqFields] = t[numReqFields]..t[i] - end - end - - if t[5] ~= 'true' and t[5] ~= 'false' then - printError('Keybinding local arg must be true or false') - os.exit() - end - - table.insert(keybindingsTable, { t[1], t[2], t[3], t[4], t[5], t[6] }) -end - -function parseTime(line) - t = {} - t = splitByTab(line) - if tableLen(t) ~= 2 then - printError('2 fields required in a Time entry') - os.exit() - elseif isBlank(t[1]) then - printError('Time set type (arg 1/2) is required') - os.exit() - elseif isBlank(t[2]) then - printError('Time value to set (arg 2/2) is required') - os.exit() - end - - if t[1] ~= 'absolute' and t[1] ~= 'relative' then - printError('Time set type "' .. t[1] .. '" is not supported') - os.exit() - end - - table.insert(timeTable, t) -end - -function parseCamera(line) - t = {} - t = splitByTab(line) - - local cmd = t[1] - if cmd == 'setNavigationState' then - if tableLen(t) ~= 8 then - printError('8 fields required in camera "setNavigationState" line') - os.exit() - elseif isBlank(t[2]) then - printError('Camera setNavigationState Anchor (arg 1/7) is required') - os.exit() - elseif isBlank(t[5]) then - printError('Camera setNavigationState position vector (arg 4/7) is required') - os.exit() - end - elseif cmd == 'goToGeo' then - if tableLen(t) ~= 5 then - printError('5 fields required in camera "goToGeo" line') - os.exit() - elseif isBlank(t[3]) then - printError('Camera goToGeo Latitude (arg 2/4) is required') - os.exit() - elseif isBlank(t[4]) then - printError('Camera goToGeo Longitude (arg 3/4) is required') - os.exit() - end - else - printError('Camera position command "' .. cmd .. '" is not supported') - os.exit() - end - - table.insert(cameraTable, t) -end - -function file_exists(file) - local f = io.open(file, 'rb') - if f then - f:close() - end - return f ~= nil -end - -function lines_from(file) - if not file_exists(file) then - return {} - end - lines = {} - for line in io.lines(file) do - lines[#lines + 1] = line - end - return lines -end - -function determineSection(header) - header = header:sub(2) - for _,i in pairs(parsingSections) do - if i.section == header then - currSection = i.section - currFunction = i.func - return true - end - end - return false -end - -function isBlank(line) - return line:match('%S') == nil -end - -function parseCurrentSection(line) - currFunction(line) -end - -function tableLen(T) - local size = 0 - for _ in pairs(T) do - size = size + 1 - end - return size -end - -function parseProfile(fileIn) - local lines = lines_from(fileIn) - - for k,v in pairs(lines) do - if insideSection then - if isBlank(v) then - insideSection = false - else - parseCurrentSection(v) - end - elseif v:sub(1, 1) == '#' then - if determineSection(v) then - insideSection = true - end - end - lineIndex = lineIndex + 1 - end - - resultTable['Version'] = version - resultTable['Module'] = modulesTable - resultTable['Asset'] = assetsTable - resultTable['Property'] = propertiesTable - resultTable['Time'] = timeTable - resultTable['Camera'] = cameraTable - resultTable['MarkNodes'] = markNodesTable - resultTable['Keybinding'] = keybindingsTable - - return resultTable -end - -function tableSize(T) - local size = 0 - for _ in pairs(T) do - size = size + 1 - end - return size -end - -function generateAsset(T, fileOut) - file = io.open(fileOut, 'w') - io.output(file) - - --Module section - for i,j in pairs(T['Module']) do - if not isBlank(j[2]) and not isBlank(j[3]) then - ModuleStr = ModuleStr .. 'if openspace.modules.isLoaded("' .. j[1] .. '") then\n' - ModuleStr = ModuleStr .. ' ' .. j[2] .. '\nelse\n' .. ' ' .. j[3] .. '\nend\n' - elseif not isBlank(j[3]) then - ModuleStr = ModuleStr .. 'if not openspace.modules.isLoaded("' .. j[1] .. '") then\n' - ModuleStr = ModuleStr .. ' ' .. j[3] .. '\nend\n' - elseif not isBlank(j[2]) then - ModuleStr = ModuleStr .. 'if openspace.modules.isLoaded("' .. j[1] .. '") then\n' - ModuleStr = ModuleStr .. ' ' .. j[2] .. '\nend\n' - end - end - - --Asset section - AssetStr = AssetStr .. 'asset.require("base");\n' - AssetStr = AssetStr .. 'local assetHelper = asset.require("util/asset_helper")\n' - AssetStr = AssetStr .. 'local propertyHelper = asset.require("util/property_helper")\n' - AssetStr = AssetStr .. 'local sceneHelper = asset.require("util/scene_helper")\n' - AssetStr = AssetStr .. 'local renderableHelper = asset.require("util/renderable_helper")\n' - local assetType = '' - for i,j in pairs(T['Asset']) do - if isBlank(j[2]) then - assetType = 'require' - else - if (j[2] == 'required') then - assetType = 'require' - elseif (j[2] == 'requested') then - assetType = 'request' - else - printError('Asset arg 2/2 must be either "required" or "requested"') - os.exit() - end - end - AssetStr = AssetStr .. 'asset.' .. assetType .. '("' .. j[1] .. '")\n' - end - - --Keybindings section - if not (tableSize(T['Keybinding']) == 0) then - KeyStr = KeyStr .. 'local Keybindings = {\n' - for i,j in pairs(T['Keybinding']) do - KeyStr = KeyStr..' {\n' - KeyStr = KeyStr..' Key = "' .. j[1] .. '",\n' - KeyStr = KeyStr..' Documentation = "' .. j[2] .. '",\n' - KeyStr = KeyStr..' Name = "' .. j[3] .. '",\n' - KeyStr = KeyStr..' GuiPath = "' .. j[4] .. '",\n' - KeyStr = KeyStr..' Local = ' .. j[5] .. ',\n' - KeyStr = KeyStr..' Command = ' .. j[6] .. '\n' - KeyStr = KeyStr..' },\n' - end - KeyStr = KeyStr.."}\n" - end - - --Time section - for i,j in pairs(T['Time']) do - if not (j[1] == 'absolute') and not (j[1] == 'relative') then - printError('Time arg 1/1 must be either "absolute" or "relative"') - os.exit() - elseif (j[1] == 'absolute') then - TimeStr = TimeStr .. ' openspace.time.setTime("' .. j[2] .. '")\n' - elseif (j[1] == 'relative') then - TimeStr = TimeStr .. ' local now = openspace.time.currentWallTime();' - TimeStr = TimeStr .. ' openspace.time.setTime(' - TimeStr = TimeStr .. 'openspace.time.advancedTime(now, "' .. j[2] .. '"))\n' - end - end - - --MarkNodes section - mkNodLen = tableSize(T['MarkNodes']) - if not (mkNodLen == 0) then - MarkNodesStr = MarkNodesStr .. ' openspace.markInterestingNodes({' - for i, j in pairs(T['MarkNodes']) do - MarkNodesStr = MarkNodesStr .. '"' .. j .. '"' - if (i < mkNodLen) then - MarkNodesStr = MarkNodesStr .. ', ' - end - end - MarkNodesStr = MarkNodesStr .. '})\n' - end - - --Property section - for i, j in pairs(T['Property']) do - if not (j[1] == 'setPropertyValue') and not (j[1] == 'setPropertyValueSingle') then - printError('Property arg 1/1 must be "setPropertyValue[Single]"') - os.exit() - else - PropertyStr = PropertyStr .. ' openspace.' .. j[1] .. '("' .. j[2] .. '", ' .. j[3] .. ')\n' - end - end - - --Camera section - for i,j in pairs(T['Camera']) do - if (j[1] == 'setNavigationState') then - CameraStr = CameraStr .. ' openspace.navigation.setNavigationState({' - CameraStr = CameraStr .. 'Anchor = ' .. j[2] .. ', ' - if not isBlank(j[3]) then - CameraStr = CameraStr .. 'Aim = ' .. j[3] .. ', ' - end - if not isBlank(j[4]) then - CameraStr = CameraStr .. 'ReferenceFrame = ' .. j[4] .. ', ' - end - CameraStr = CameraStr .. 'Position = {' .. j[5] .. '}, ' - if not isBlank(j[6]) then - CameraStr = CameraStr .. 'Up = {' .. j[6] .. '}, ' - end - if not isBlank(j[7]) then - CameraStr = CameraStr .. 'Yaw = ' .. j[7] .. ', ' - end - if not isBlank(j[8]) then - CameraStr = CameraStr .. 'Pitch = ' .. j[8] - end - CameraStr = CameraStr .. '})\n' - elseif (j[1] == 'goToGeo') then - CameraStr = CameraStr .. ' openspace.globebrowsing.goToGeo(' - if not isBlank(j[2]) then - CameraStr = CameraStr .. j[2] .. ', ' - end - CameraStr = CameraStr .. j[3] .. ', ' .. j[4] - if not isBlank(j[5]) then - CameraStr = CameraStr .. ', ' .. j[5] - end - CameraStr = CameraStr .. ')\n' - else - printError('Camera arg 1/1 must be "setNavigationState" or "goToGeo"') - os.exit() - end - end - - --Write the file - io.write(ModuleStr .. '\n') - io.write(AssetStr .. '\n') - io.write(KeyStr .. '\n') - io.write('asset.onInitialize(function ()\n') - io.write(TimeStr .. '\n') - if not (tableSize(T['Keybinding']) == 0) then - io.write(' sceneHelper.bindKeys(Keybindings)\n') - end - io.write(MarkNodesStr .. '\n') - io.write(PropertyStr .. '\n') - io.write(CameraStr .. '\n') - io.write('end)\n') - - io.close(file) -end - ---[[ -########################################################################################## - M a i n -########################################################################################## -]]-- - -ModuleStr = '' -AssetStr = '' -KeyStr = '' -TimeStr = '' -MarkNodesStr = '' -PropertyStr = '' -CameraStr = '' - -parsingSections = { - { section = 'Version', func = parseVersion }, - { section = 'Module', func = parseModule }, - { section = 'Asset', func = parseAsset }, - { section = 'Property', func = parseProperty }, - { section = 'Keybinding', func = parseKeybinding }, - { section = 'Time', func = parseTime }, - { section = 'Camera', func = parseCamera }, - { section = 'MarkNodes', func = parseMarkNodes } -} - -profilePathIn = openspace.profile.getProfileInputPath() -scenePathOut = openspace.profile.getSceneOutputPath() - -profileIn = profilePathIn .. '.profile' -assetOut = scenePathOut .. '.scene' - -local resultTable = parseProfile(profileIn) -generateAsset(resultTable, assetOut) diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 033ab87322..5f04e66c2a 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -99,8 +100,6 @@ namespace { constexpr const char* _loggerCat = "OpenSpaceEngine"; constexpr const int CacheVersion = 1; - constexpr const char* ProfileToSceneConverter - = "${BASE}/scripts/convert_profile_to_scene.lua"; } // namespace @@ -300,38 +299,14 @@ void OpenSpaceEngine::initialize() { // Convert profile to scene file (if was provided in configuration file) if (!global::configuration.profile.empty()) { - LINFO( - fmt::format("Run Lua script to convert {}.profile to scene", - global::configuration.profile) - ); - ghoul::lua::LuaState lState; - - // We can't use the absPath function here because we pass the path into the Lua - // function, which requires additional escaping - std::string inputProfilePath = generateFilePath("${ASSETS}"); - std::string outputScenePath = generateFilePath("${TEMPORARY}"); - - std::string setProfileFilenameInLuaState = fmt::format(R"( - openspace = {{}} - openspace.profile = {{}} - function openspace.profile.getFilename() - return "{}.profile" - end - function openspace.profile.getProfileInputPath() - return "{}" - end - function openspace.profile.getSceneOutputPath() - return "{}" - end - )", - global::configuration.profile, - inputProfilePath, - outputScenePath - ); - - ghoul::lua::runScript(lState, setProfileFilenameInLuaState); - ghoul::lua::runScriptFile(lState, absPath(ProfileToSceneConverter)); + std::string inputProfilePath = absPath("${ASSETS}"); + std::string outputScenePath = absPath("${TEMPORARY}"); + std::string inputProfile = inputProfilePath + "/" + global::configuration.profile + + ".profile"; + std::string outputAsset = outputScenePath + "/" + global::configuration.profile + + ".asset"; + global::profile.convertToAssetFile(inputProfile, outputAsset); // Set asset name to that of the profile because a new scene file will be // created with that name, and also because the profile name will override diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index b8af9a5bd6..57bb85fd89 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -48,7 +48,6 @@ namespace { constexpr const char* _loggerCat = "Profile"; constexpr const char* KeyIdentifier = "Identifier"; constexpr const char* KeyParent = "Parent"; - } // namespace namespace openspace { @@ -62,6 +61,36 @@ void Profile::saveCurrentSettingsToProfile(std::string filename) { std::string initProfile = global::configuration.profile; } +void Profile::convertToAssetFile(const std::string inProfilePath, + const std::string outFilePath) +{ + ProfileFile pf; + + pf.readFromFile(inProfilePath); + + std::ofstream outFile; + try { + outFile.open(outFilePath, std::ofstream::out); + } + catch (std::ofstream::failure& e) { + LERROR("Exception opening profile file for write: " + outFilePath); + } + + try { + outFile << convertToAsset(pf); + } + catch (std::ofstream::failure& e) { + LERROR("Data write error to file: " + outFilePath); + } + + try { + outFile.close(); + } + catch (std::ofstream::failure& e) { + LERROR("Exception closing profile file after write: " + outFilePath); + } +} + std::string Profile::convertToAsset(ProfileFile& pf) { std::string result;