diff --git a/.gitmodules b/.gitmodules index 4311e7851a..3e4cfb738b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,9 +10,6 @@ [submodule "modules/touch/ext/libTUIO11"] path = modules/touch/ext/libTUIO11 url = https://github.com/mkalten/TUIO11_CPP -[submodule "modules/sync/ext/libtorrent"] - path = modules/sync/ext/libtorrent - url = https://github.com/OpenSpace/libtorrent.git [submodule "apps/OpenSpace-MinVR/ext/minvr"] path = apps/OpenSpace-MinVR/ext/minvr url = https://github.com/OpenSpace/minvr @@ -26,3 +23,6 @@ [submodule "modules/fitsfilereader/ext/cfitsio"] path = modules/fitsfilereader/ext/cfitsio url = https://github.com/OpenSpace/cfitsio.git +[submodule "apps/OpenSpace-MinVR/ext/glfw"] + path = apps/OpenSpace-MinVR/ext/glfw + url = https://github.com/opensgct/glfw diff --git a/CMakeLists.txt b/CMakeLists.txt index dc5a7104df..724729bcad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,6 +285,11 @@ if (OPENSPACE_WITH_ABUFFER_RENDERER) target_compile_definitions(openspace-core PUBLIC "OPENSPACE_WITH_ABUFFER_RENDERER") endif () +option(OPENSPACE_WITH_INSTRUMENTATION "Add instrumentation options" OFF) +if (OPENSPACE_WITH_INSTRUMENTATION) + target_compile_definitions(openspace-core PUBLIC "OPENSPACE_WITH_INSTRUMENTATION") +endif () + # Just in case, create the bin directory add_custom_command( diff --git a/apps/OpenSpace-MinVR/CMakeLists.txt b/apps/OpenSpace-MinVR/CMakeLists.txt index 656da9b194..f58a2a13cc 100644 --- a/apps/OpenSpace-MinVR/CMakeLists.txt +++ b/apps/OpenSpace-MinVR/CMakeLists.txt @@ -50,7 +50,7 @@ target_include_directories(OpenSpace-MinVR PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ex target_include_directories(OpenSpace-MinVR PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ext/minvr/external/GLFW/src/include) -target_link_libraries(OpenSpace-MinVR libOpenSpace MinVR) +target_link_libraries(OpenSpace-MinVR openspace-core MinVR) # Web Browser and Web gui # Why not put these in the module's path? Because they do not have access to the diff --git a/apps/OpenSpace-MinVR/main.cpp b/apps/OpenSpace-MinVR/main.cpp index b4cde8364e..1b309b4b8d 100644 --- a/apps/OpenSpace-MinVR/main.cpp +++ b/apps/OpenSpace-MinVR/main.cpp @@ -200,7 +200,14 @@ void Handler::onVREvent(const VRDataIndex& eventData) { if (button == MouseButton::Right && action == MouseAction::Press) { windowingGlobals.mouseButtons |= 1 << 2; } - global::openSpaceEngine.mouseButtonCallback(button, action); + + using KM = KeyModifier; + KM mod = KM::NoModifier; + mod |= keyboardState.modifierShift ? KM::Shift : KM::NoModifier; + mod |= keyboardState.modifierCtrl ? KM::Control : KM::NoModifier; + mod |= keyboardState.modifierAlt ? KM::Alt : KM::NoModifier; + + global::openSpaceEngine.mouseButtonCallback(button, action, mod); } } @@ -341,6 +348,14 @@ int main(int argc, char** argv) { ghoul::initialize(); + // Register the path of the executable, + // to make it possible to find other files in the same directory. + FileSys.registerPathToken( + "${BIN}", + ghoul::filesystem::File(absPath(argv[0])).directoryName(), + ghoul::filesystem::FileSystem::Override::Yes + ); + // Create the OpenSpace engine and get arguments for the SGCT engine std::string windowConfiguration; try { diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index ff713b447a..e77ce29331 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -76,6 +76,8 @@ constexpr const bool EnableDetailedVtune = false; #include "nvToolsExt.h" #endif // OPENSPACE_HAS_NVTOOLS +using namespace openspace; + namespace { constexpr const char* _loggerCat = "main"; @@ -157,9 +159,9 @@ LONG WINAPI generateMiniDump(EXCEPTION_POINTERS* exceptionPointers) { std::string dumpFile = fmt::format( "OpenSpace_{}_{}_{}-{}-{}-{}-{}-{}-{}--{}--{}.dmp", - openspace::OPENSPACE_VERSION_MAJOR, - openspace::OPENSPACE_VERSION_MINOR, - openspace::OPENSPACE_VERSION_PATCH, + OPENSPACE_VERSION_MAJOR, + OPENSPACE_VERSION_MINOR, + OPENSPACE_VERSION_PATCH, stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, @@ -260,7 +262,7 @@ void mainInitFunc() { LTRACE("main::mainInitFunc(begin)"); LDEBUG("Initializing OpenSpace Engine started"); - openspace::global::openSpaceEngine.initialize(); + global::openSpaceEngine.initialize(); LDEBUG("Initializing OpenSpace Engine finished"); { @@ -287,7 +289,7 @@ void mainInitFunc() { LDEBUG("Initializing OpenGL in OpenSpace Engine started"); - openspace::global::openSpaceEngine.initializeGL(); + global::openSpaceEngine.initializeGL(); LDEBUG("Initializing OpenGL in OpenSpace Engine finished"); @@ -366,7 +368,7 @@ void mainInitFunc() { // std::string screenshotPath = "${SCREENSHOTS}"; - if (openspace::global::configuration.shouldUseScreenshotDate) { + if (global::configuration.shouldUseScreenshotDate) { std::time_t now = std::time(nullptr); std::tm* nowTime = std::localtime(&now); char mbstr[128]; @@ -412,13 +414,13 @@ void mainPreSyncFunc() { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainPreSyncFunc(begin)"); - openspace::global::openSpaceEngine.preSynchronization(); + global::openSpaceEngine.preSynchronization(); // Query joystick status - using namespace openspace::interaction; + using namespace interaction; for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; ++i) { - JoystickInputState& state = openspace::global::joystickInputStates[i]; + JoystickInputState& state = global::joystickInputStates[i]; int present = glfwJoystickPresent(i); if (present == GLFW_FALSE) { @@ -511,7 +513,7 @@ void mainPostSyncPreDrawFunc() { #endif // OPENSPACE_HAS_NVTOOLS LTRACE("main::postSynchronizationPreDraw(begin)"); - openspace::global::openSpaceEngine.postSynchronizationPreDraw(); + global::openSpaceEngine.postSynchronizationPreDraw(); #ifdef OPENVR_SUPPORT if (FirstOpenVRWindow) { @@ -559,7 +561,7 @@ void mainRenderFunc() { #endif try { - openspace::global::openSpaceEngine.render( + global::openSpaceEngine.render( SgctEngine->getModelMatrix(), viewMatrix, projectionMatrix @@ -591,7 +593,7 @@ void mainDraw2DFunc() { LTRACE("main::mainDraw2DFunc(begin)"); try { - openspace::global::openSpaceEngine.drawOverlays(); + global::openSpaceEngine.drawOverlays(); } catch (const ghoul::RuntimeError& e) { LERRORC(e.component, e.message); @@ -627,7 +629,7 @@ void mainPostDrawFunc() { } #endif // OPENVR_SUPPORT - openspace::global::openSpaceEngine.postDraw(); + global::openSpaceEngine.postDraw(); #ifdef OPENSPACE_HAS_SPOUT for (const SpoutWindow& w : SpoutWindows) { @@ -667,7 +669,7 @@ void mainPostDrawFunc() { -void mainKeyboardCallback(int key, int, int action, int mods) { +void mainKeyboardCallback(int key, int, int action, int modifiers) { #ifdef OPENSPACE_HAS_VTUNE if (EnableDetailedVtune) { __itt_frame_begin_v3(_vTune.keyboard, nullptr); @@ -675,11 +677,10 @@ void mainKeyboardCallback(int key, int, int action, int mods) { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainKeyboardCallback(begin)"); - openspace::global::openSpaceEngine.keyboardCallback( - openspace::Key(key), - openspace::KeyModifier(mods), - openspace::KeyAction(action) - ); + const Key k = Key(key); + const KeyModifier m = KeyModifier(modifiers); + const KeyAction a = KeyAction(action); + global::openSpaceEngine.keyboardCallback(k, m, a); LTRACE("main::mainKeyboardCallback(begin)"); #ifdef OPENSPACE_HAS_VTUNE @@ -699,11 +700,10 @@ void mainMouseButtonCallback(int key, int action, int modifiers) { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainMouseButtonCallback(begin)"); - openspace::global::openSpaceEngine.mouseButtonCallback( - openspace::MouseButton(key), - openspace::MouseAction(action), - openspace::KeyModifier(modifiers) - ); + const MouseButton k = MouseButton(key); + const MouseAction a = MouseAction(action); + const KeyModifier m = KeyModifier(modifiers); + global::openSpaceEngine.mouseButtonCallback(k, a, m); LTRACE("main::mainMouseButtonCallback(end)"); #ifdef OPENSPACE_HAS_VTUNE @@ -722,7 +722,7 @@ void mainMousePosCallback(double x, double y) { } #endif // OPENSPACE_HAS_VTUNE - openspace::global::openSpaceEngine.mousePositionCallback(x, y); + global::openSpaceEngine.mousePositionCallback(x, y); #ifdef OPENSPACE_HAS_VTUNE if (EnableDetailedVtune) { @@ -741,7 +741,7 @@ void mainMouseScrollCallback(double posX, double posY) { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainMouseScrollCallback(begin"); - openspace::global::openSpaceEngine.mouseScrollWheelCallback(posX, posY); + global::openSpaceEngine.mouseScrollWheelCallback(posX, posY); LTRACE("main::mainMouseScrollCallback(end)"); #ifdef OPENSPACE_HAS_VTUNE @@ -753,17 +753,15 @@ void mainMouseScrollCallback(double posX, double posY) { -void mainCharCallback(unsigned int codepoint, int mods) { +void mainCharCallback(unsigned int codepoint, int modifiers) { #ifdef OPENSPACE_HAS_VTUNE if (EnableDetailedVtune) { __itt_frame_begin_v3(_vTune.character, nullptr); } #endif // OPENSPACE_HAS_VTUNE - openspace::global::openSpaceEngine.charCallback( - codepoint, - openspace::KeyModifier(mods) - ); + const KeyModifier m = KeyModifier(modifiers); + global::openSpaceEngine.charCallback(codepoint, m); #ifdef OPENSPACE_HAS_VTUNE if (EnableDetailedVtune) { @@ -782,7 +780,7 @@ void mainEncodeFun() { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainEncodeFun(begin)"); - std::vector data = openspace::global::openSpaceEngine.encode(); + std::vector data = global::openSpaceEngine.encode(); _synchronizationBuffer.setVal(std::move(data)); sgct::SharedData::instance()->writeVector(&_synchronizationBuffer); @@ -806,7 +804,7 @@ void mainDecodeFun() { sgct::SharedData::instance()->readVector(&_synchronizationBuffer); std::vector data = _synchronizationBuffer.getVal(); - openspace::global::openSpaceEngine.decode(std::move(data)); + global::openSpaceEngine.decode(std::move(data)); LTRACE("main::mainDecodeFun(end)"); #ifdef OPENSPACE_HAS_VTUNE @@ -833,7 +831,7 @@ void mainLogCallback(const char* msg) { void setSgctDelegateFunctions() { - openspace::WindowDelegate& sgctDelegate = openspace::global::windowDelegate; + WindowDelegate& sgctDelegate = global::windowDelegate; sgctDelegate.terminate = []() { sgct::Engine::instance()->terminate(); }; sgctDelegate.setBarrier = [](bool enabled) { sgct::SGCTWindow::setBarrier(enabled); @@ -1101,7 +1099,7 @@ int main(int argc, char** argv) { ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes ); - openspace::CommandlineArguments commandlineArguments; + CommandlineArguments commandlineArguments; parser.addCommand(std::make_unique>( commandlineArguments.configurationName, "--file", "-f", "Provides the path to the OpenSpace configuration file. Only the '${TEMPORARY}' " @@ -1141,8 +1139,6 @@ int main(int argc, char** argv) { // Create the OpenSpace engine and get arguments for the SGCT engine std::string windowConfiguration; try { - using namespace openspace; - // Find configuration std::string configurationFilePath = commandlineArguments.configurationName; if (commandlineArguments.configurationName.empty()) { @@ -1178,16 +1174,17 @@ int main(int argc, char** argv) { // Determining SGCT configuration file LDEBUG("SGCT Configuration file: " + global::configuration.windowConfiguration); - windowConfiguration = openspace::global::configuration.windowConfiguration; + windowConfiguration = global::configuration.windowConfiguration; } - catch (const openspace::documentation::SpecificationError& e) { + catch (const documentation::SpecificationError& e) { LFATALC("main", "Loading of configuration file failed"); - for (const openspace::documentation::TestResult::Offense& o : e.result.offenses) { + for (const documentation::TestResult::Offense& o : e.result.offenses) { LERRORC(o.offender, ghoul::to_string(o.reason)); } - for (const openspace::documentation::TestResult::Warning& w : e.result.warnings) { + for (const documentation::TestResult::Warning& w : e.result.warnings) { LWARNINGC(w.offender, ghoul::to_string(w.reason)); } + ghoul::deinitialize(); exit(EXIT_FAILURE); } catch (const ghoul::RuntimeError& e) { @@ -1196,10 +1193,11 @@ int main(int argc, char** argv) { if (ghoul::logging::LogManager::isInitialized()) { LogMgr.flushLogs(); } + ghoul::deinitialize(); return EXIT_FAILURE; } - openspace::global::openSpaceEngine.registerPathTokens(); + global::openSpaceEngine.registerPathTokens(); // Prepend the outgoing sgctArguments with the program name // as well as the configuration file that sgct is supposed to use @@ -1293,8 +1291,8 @@ int main(int argc, char** argv) { auto cleanup = [&](bool isInitialized) { if (isInitialized) { - openspace::global::openSpaceEngine.deinitializeGL(); - openspace::global::openSpaceEngine.deinitialize(); + global::openSpaceEngine.deinitializeGL(); + global::openSpaceEngine.deinitialize(); } // Clear function bindings to avoid crash after destroying the OpenSpace Engine @@ -1321,6 +1319,8 @@ int main(int argc, char** argv) { } } #endif // OPENSPACE_HAS_SPOUT + + ghoul::deinitialize(); }; if (!initSuccess) { diff --git a/apps/Wormhole/main.cpp b/apps/Wormhole/main.cpp index 029ee407cb..a988789255 100644 --- a/apps/Wormhole/main.cpp +++ b/apps/Wormhole/main.cpp @@ -22,43 +22,26 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include +#include +#include #include #include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include +#include #include -#include namespace { - const std::string _loggerCat = "Wormhole"; -} + constexpr const char*_loggerCat = "Wormhole"; +} // namespace int main(int argc, char** argv) { using namespace openspace; + using namespace ghoul::cmdparser; std::vector arguments(argv, argv + argc); - ghoul::cmdparser::CommandlineParser commandlineParser( + CommandlineParser commandlineParser( "Wormhole", - ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes + CommandlineParser::AllowUnknownCommands::Yes ); std::stringstream defaultPassword; @@ -73,43 +56,43 @@ int main(int argc, char** argv) { std::chrono::system_clock::now().time_since_epoch().count() + 1 ) % 0xffffff); - std::string portString = ""; + std::string portString; commandlineParser.addCommand( std::make_unique>( portString, "--port", "-p", "Sets the port to listen on" - ) + ) ); - std::string password = ""; + std::string password; commandlineParser.addCommand( std::make_unique>( password, "--password", "-l", "Sets the password to use" - ) + ) ); - std::string changeHostPassword = ""; + std::string changeHostPassword; commandlineParser.addCommand( std::make_unique>( changeHostPassword, "--hostpassword", "-h", "Sets the host password to use" - ) + ) ); commandlineParser.setCommandLine(arguments); commandlineParser.execute(); - if (password == "") { + if (password.empty()) { password = defaultPassword.str(); } - if (changeHostPassword == "") { + if (changeHostPassword.empty()) { changeHostPassword = defaultChangeHostPassword.str(); } @@ -118,11 +101,11 @@ int main(int argc, char** argv) { int port = 25001; - if (portString != "") { + if (!portString.empty()) { try { port = std::stoi(portString); } - catch (...) { + catch (const std::invalid_argument&) { LERROR(fmt::format("Invalid port: {}", portString)); } } @@ -132,7 +115,9 @@ int main(int argc, char** argv) { server.setDefaultHostAddress("127.0.0.1"); LINFO(fmt::format("Server listening to port {}", port)); - while (std::cin.get() != 'q') {} + while (std::cin.get() != 'q') { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } server.stop(); LINFO("Server stopped"); diff --git a/data/assets/apollo8.scene b/data/assets/apollo8.scene index 3301a6720a..6ec4a8b9d5 100644 --- a/data/assets/apollo8.scene +++ b/data/assets/apollo8.scene @@ -12,14 +12,19 @@ local Keybindings = { { Key = "E", Command = "openspace.time.setPause(true);" .. - "openspace.setPropertyValue('*Trail.Renderable.Enabled', false)".. - "openspace.setPropertyValue('Scene.Apollo8LaunchTrail.Renderable.Enabled', false)".. - "openspace.sessionRecording.startPlayback('apollo8')", + "openspace.time.setDeltaTime(1);" .. + "openspace.time.setTime('1968 DEC 24 16:37:31');" .. + "openspace.navigation.setNavigationState({" .. + " Anchor = 'Apollo8'," .. + " Position = { 1.494592E1, 3.236777E1, -4.171296E1 }," .. + " ReferenceFrame = 'Root'," .. + " Up = { 0.960608E0, -0.212013E0, 0.179675E0 }" .. + "});" .. + "openspace.setPropertyValue('*Trail.Renderable.Enabled', false)", Documentation = "Jump to right before the earthrise photo", Name = "Set Earthrise time", GuiPath = "/Missions/Apollo/8", Local = false - }, { Key = "U", @@ -115,13 +120,7 @@ asset.onInitialize(function () openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.MinimumAllowedDistance', 0.000000); openspace.setPropertyValueSingle('Scene.Moon.Renderable.LodScaleFactor', 24.0); - openspace.navigation.setCameraState({ - Anchor = earthAsset.Earth.Identifier, - Position = { 0, 0, 0 }, - Rotation = { 0.758797, 0.221490, -0.605693, -0.091135 }, - }) - - openspace.globebrowsing.goToGeo(20, -60, 15000000) + openspace.globebrowsing.goToGeo(earthAsset.Earth.Identifier, 20, -60, 15000000) end) asset.onDeinitialize(function () diff --git a/data/assets/apollo_sites.scene b/data/assets/apollo_sites.scene index 2c59d6f25a..09721fe7d6 100644 --- a/data/assets/apollo_sites.scene +++ b/data/assets/apollo_sites.scene @@ -2,15 +2,15 @@ asset.require('./base') --moonrocks.scene local sceneHelper = asset.require('util/scene_helper') - -- local station2 = asset.require('scene/solarsystem/missions/apollo/bouldersstation2') -- local station6 = asset.require('scene/solarsystem/missions/apollo/bouldersstation6') -- local station7 = asset.require('scene/solarsystem/missions/apollo/bouldersstation7') +asset.require('scene/solarsystem/missions/apollo/apollo8') asset.require('scene/solarsystem/missions/apollo/apollo11') -asset.require('scene/solarsystem/missions/apollo/a11_lem') asset.require('scene/solarsystem/missions/apollo/a17_lem') asset.require('scene/solarsystem/missions/apollo/apollo_globebrowsing') asset.require('scene/solarsystem/missions/apollo/apollo_11_lem_flipbook') +asset.require('scene/solarsystem/missions/apollo/insignias_map') local Keybindings = { { @@ -37,11 +37,11 @@ local Keybindings = { }, { Key = "F11", - Command = "openspace.time.setTime('1969 JUL 20 20:17:40');" .. + Command = "openspace.time.setTime('1969 JUL 20 20:17:40');" .. "openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_11.Enabled', true);" .. "openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A11_M177481212_p_longlat.Enabled', true);" .. "openspace.setPropertyValueSingle('Scene.Moon.Renderable.LodScaleFactor', 20.11);" .. - "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Apollo11LemModel');" .. + "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Apollo11LemPosition');" .. "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);" .. "openspace.setPropertyValueSingle('Scene.Apollo11MoonTrail.Renderable.Enabled', true);" .. "openspace.setPropertyValueSingle('Scene.Apollo11LemTrail.Renderable.Enabled', true);", @@ -82,10 +82,14 @@ asset.onInitialize(function () sceneHelper.bindKeys(Keybindings) - openspace.markInterestingNodes({ "Moon", "Apollo11LemModel", "Apollo17LemModel", "Apollo11", "Apollo11LunarLander" }) + openspace.markInterestingNodes({ + "Moon", "Apollo11LemModel", "Apollo17LemModel", + "Apollo11", "Apollo11LunarLander", + -- "Station_2_Boulder2", "Station_6_Fragment1" + }) + openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.BlendMode', 0); -- To enable both sites by default, uncomment these lines - -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.BlendMode', 0.000000); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.Enabled', true); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_17.Enabled', true); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_LEM.Enabled', true); @@ -95,17 +99,19 @@ asset.onInitialize(function () -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_station7.BlendMode', 0.000000); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_11.Enabled', true); -- openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A11_M177481212_p_longlat.Enabled', true); - - openspace.navigation.setCameraState({ - Anchor = moonAsset.Moon.Identifier, - Position = { 0, 0, 0 }, - Rotation = { 0, 0, 0, 0 }, - }) - openspace.globebrowsing.goToGeo(20, -60, 15000000) + + openspace.setPropertyValueSingle('Scene.Apollo11LemDescentModel.Renderable.RotationVector', { 273.205475,6.904110,308.712311 }); + openspace.setPropertyValueSingle('Scene.Apollo11LemLandedModel.Renderable.RotationVector', { 273.205475,6.904110,308.712311 }); + + openspace.globebrowsing.goToGeo(moonAsset.Moon.Identifier, 20, -60, 15000000) openspace.setPropertyValueSingle("Scene.Moon.Renderable.PerformShading", false) end) asset.onDeinitialize(function () - openspace.removeInterestingNodes({ "Moon", "Apollo11Lem", "Apollo17Lem", "Apollo11", "Apollo11LunarLander" }) + openspace.removeInterestingNodes({ + "Moon", "Apollo11Lem", "Apollo17Lem", + "Apollo11", "Apollo11LemPosition", + -- "Station_6_Fragment1", "Station_6_Fragments_2_3" + }) end) diff --git a/data/assets/dawn.scene b/data/assets/dawn.scene index b519b87da2..8af4d7bf6d 100644 --- a/data/assets/dawn.scene +++ b/data/assets/dawn.scene @@ -10,10 +10,9 @@ asset.onInitialize(function () openspace.markInterestingNodes({ "Dawn", "Ceres", "Vesta" }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = DawnAsset.Dawn.Identifier, Position = { 526781518487.171326, 257168309890.072144, -1381125204152.817383 }, - Rotation = { -0.106166, 0.981574, -0.084545, 0.134513 }, }) end) diff --git a/data/assets/examples/basic.scene b/data/assets/examples/basic.scene index 182c4776fe..ec17991a57 100644 --- a/data/assets/examples/basic.scene +++ b/data/assets/examples/basic.scene @@ -1,8 +1,9 @@ local assetHelper = asset.require('util/asset_helper') local sceneHelper = asset.require('util/scene_helper') local propertyHelper = asset.require('util/property_helper') +local debugHelper = asset.require('util/debug_helper') --- At this point, a sceene needs basic spice data to load. +-- At this point, a scene needs basic spice data to load. asset.require('spice/base') asset.require('util/default_keybindings') @@ -12,10 +13,15 @@ asset.require('util/default_joystick') asset.require('util/webgui') local spheres = asset.require('examples/spheres') +debugHelper.registerCartesianAxes(asset, { + Parent = "Root", + Scale = 10 +}) + asset.onInitialize(function () - openspace.navigation.setCameraState({ - Anchor = spheres.ExampleSphere1.Identifier, - Position = { 20, 0, 0 }, - Rotation = { 0.758797, 0.221490, -0.605693, -0.091135 } + openspace.navigation.setNavigationState({ + Anchor = "Root", + Position = { 20, 20, 20 }, + Up = {0, 1, 0}, }) end) diff --git a/data/assets/gaia.scene b/data/assets/gaia.scene index 94d2f8ddbb..45213dfeaa 100644 --- a/data/assets/gaia.scene +++ b/data/assets/gaia.scene @@ -35,10 +35,9 @@ asset.onInitialize(function () openspace.markInterestingNodes({ "Gaia" }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = earthAsset.Earth.Identifier, Position = { 1000000000000.0, 1000000000000.0, 1000000000000.0 }, - Rotation = { 0.683224, -0.765934, -0.601234, -0.418073 }, }) end) diff --git a/data/assets/insight.scene b/data/assets/insight.scene index 3c02820e60..d185471418 100644 --- a/data/assets/insight.scene +++ b/data/assets/insight.scene @@ -60,10 +60,11 @@ asset.onInitialize(function () openspace.markInterestingNodes({ "Insight" }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = insightAsset.Insight.Identifier, - Position = { 0, 0, 0 }, - Rotation = { 0.758797, 0.221490, -0.605693, -0.091135 }, + Position = { 8.430115E0, -1.791710E1, 2.813660E0 }, + ReferenceFrame = "Root", + Up = { 0.494659E0,0.357162E0,0.792306E0 }, }) end) diff --git a/data/assets/juno.scene b/data/assets/juno.scene index 9ed6afaccd..f17e5c3f8b 100644 --- a/data/assets/juno.scene +++ b/data/assets/juno.scene @@ -18,10 +18,11 @@ asset.onInitialize(function () 28800, 57600, 115200, 230400, 460800, 921600, 1843200, 3686400, 7372800, 14745600 }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = junoAsset.Juno.Identifier, - Position = { 1837386367.601345, -389860693812.834839, 714830404470.398926 }, - Rotation = { -0.336540, 0.711402, -0.099212, 0.608937 }, + Position = { 1.243398E8, 7.176068E7, -1.519733E7 }, + ReferenceFrame = "Root", + Up = { -0.377400E0, 0.764573E0, 0.522492E0 }, }) end) diff --git a/data/assets/messenger.scene b/data/assets/messenger.scene index 850077d2b0..dc2f722880 100644 --- a/data/assets/messenger.scene +++ b/data/assets/messenger.scene @@ -33,10 +33,11 @@ asset.onInitialize(function () 28800, 57600, 115200, 230400, 460800, 921600, 1843200, 3686400, 7372800, 14745600 }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = "Mercury", - Position = { 526781518487.171326, 257168309890.072144, -1381125204152.817383 }, - Rotation = {0.180662, 0.021334, 0.979084, 0.091111}, + Position = { 2.423690E11, 1.979038E11, -2.241483E10 }, + ReferenceFrame = "Root", + Up = { -0.492046E0, 0.666088E0, 0.560551E0 } }) end) diff --git a/data/assets/newhorizons.scene b/data/assets/newhorizons.scene index 71f77d618a..9de5012f7d 100644 --- a/data/assets/newhorizons.scene +++ b/data/assets/newhorizons.scene @@ -255,10 +255,11 @@ asset.onInitialize(function () openspace.setPropertyValueSingle('Scene.Charon.Renderable.Enabled', false) openspace.setPropertyValueSingle("Scene.PlutoBarycenterTrail.Renderable.Enabled", false) - openspace.navigation.setCameraState({ - Anchor = NewHorizonsAsset.NewHorizons.Identifier, - Position = { 4662120063743.592773, 1263245003503.724854, -955413856565.788086 }, - Rotation = { 0.683224, -0.165934, 0.701234, 0.118073 }, + openspace.navigation.setNavigationState({ + Anchor = "NewHorizons", + ReferenceFrame = "Root", + Position = { -6.572656E1, -7.239404E1, -2.111890E1 }, + Up = { 0.102164, -0.362945, 0.926193 } }) end) diff --git a/data/assets/osirisrex.scene b/data/assets/osirisrex.scene index a53e817cd2..285fdb5252 100644 --- a/data/assets/osirisrex.scene +++ b/data/assets/osirisrex.scene @@ -134,10 +134,9 @@ asset.onInitialize(function () openspace.markInterestingNodes({ "OsirisRex", "BennuBarycenter", "Earth" }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = OsirisRexAsset.OsirisRex.Identifier, - Position = { 26974590199.661884, 76314608558.908020, -127086452897.101791 }, - Rotation = { 0.729548, -0.126024, 0.416827, 0.527382 }, + Position = { 26974590199.661884, 76314608558.908020, -127086452897.101791 } }) end) diff --git a/data/assets/rosetta.scene b/data/assets/rosetta.scene index 67d5dc7951..315c8804fc 100644 --- a/data/assets/rosetta.scene +++ b/data/assets/rosetta.scene @@ -134,10 +134,11 @@ asset.onInitialize(function () 28800, 57600, 115200, 230400, 460800, 921600, 1843200, 3686400, 7372800, 14745600 }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = Comet67PAsset.Comet67P.Identifier, - Position = { 526781518487.171326, 257168309890.072144, -1381125204152.817383 }, - Rotation = { -0.106166, 0.981574, -0.084545, 0.134513 }, + ReferenceFrame = "Root", + Position = { -7.294781E5 , -6.657894E5, 2.509047E6 }, + Up = { 0.146529E0, 0.944727E0, 0.293290E0 } }) openspace.setPropertyValue('Scene.67P.Renderable.PerformShading', false); diff --git a/data/assets/scene/milkyway/gaia/gaia_dr2_download_stars.asset b/data/assets/scene/milkyway/gaia/gaia_dr2_download_stars.asset index 4dac2821f8..d80419ac78 100644 --- a/data/assets/scene/milkyway/gaia/gaia_dr2_download_stars.asset +++ b/data/assets/scene/milkyway/gaia/gaia_dr2_download_stars.asset @@ -1,19 +1,30 @@ -- Download a dataset of 618 million stars (28 GB), already preprocessed and stored in a binary octree. -- The octree was generated from the full DR2 by filtering away all stars with a parallax error higher than 0.5 -- Max Star Per Node = 50,000 and max distance = 500kpc -asset.syncedResource({ +local gaia618Destination = asset.syncedResource({ Name = "Gaia DR2 618M Octree", Type = "HttpSynchronization", Identifier = "gaia_stars_618M_octree", Version = 1 }) +local gaia618DestinationExtracted = gaia618Destination + '/data'; -- Download the full DR2 dataset with 24 values per star (preprocessed with theReadFitsTask (gaia_read.task) into 8 binary files). -- From these files new subsets can be created with the ConstructOctreeTask (gaia_octree.task). -- Total size of download is 151 GB. -asset.syncedResource({ +local gaiaFull = asset.syncedResource({ Name = "Gaia DR2 Full Raw", Type = "HttpSynchronization", Identifier = "gaia_stars_dr2_raw", Version = 1 }) + +asset.onInitialize(function() + if not openspace.directoryExists(gaia618DestinationExtracted) then + openspace.printInfo("Extracted Gaia dataset") + openspace.unzipFile(gaia618Destination .. '/DR2_full_Octree[50kSPN,500dist]_50,50.zip', gaia618DestinationExtracted, true) + end +end) + +asset.export('GaiaDR2_618M', gaia618DestinationExtracted) +asset.export('GaiaFullDataset', gaiaFull) diff --git a/data/assets/scene/solarsystem/interstellar/oumuamua.asset b/data/assets/scene/solarsystem/interstellar/oumuamua.asset index 33758e6224..2b972b5c3a 100644 --- a/data/assets/scene/solarsystem/interstellar/oumuamua.asset +++ b/data/assets/scene/solarsystem/interstellar/oumuamua.asset @@ -20,7 +20,8 @@ local OumuamuaTrail = { Color = { 0.9, 0.9, 0.0 }, StartTime = "2014 JAN 01 00:00:00", EndTime = "2023 JAN 01 00:00:00", - SampleInterval = 60 + SampleInterval = 7000, + TimeStampSubsampleFactor = 1 }, GUI = { Name = "'Oumuamua Trail", diff --git a/data/assets/scene/solarsystem/missions/apollo/a11_lem.asset b/data/assets/scene/solarsystem/missions/apollo/a11_lem.asset index 2a9182d715..05b81e0af4 100644 --- a/data/assets/scene/solarsystem/missions/apollo/a11_lem.asset +++ b/data/assets/scene/solarsystem/missions/apollo/a11_lem.asset @@ -15,8 +15,8 @@ local Apollo11Lem = { Globe = moonAsset.Moon.Identifier, Longitude = -360+23.47306, Latitude = 0.67402, - FixedAltitude = -1927.65, - UseFixedAltitude = true + Altitude = -1927.65, + UseHeightMap = false }, }, GUI = { diff --git a/data/assets/scene/solarsystem/missions/apollo/a17_lem.asset b/data/assets/scene/solarsystem/missions/apollo/a17_lem.asset index 9d6f403071..3a88c8cf75 100644 --- a/data/assets/scene/solarsystem/missions/apollo/a17_lem.asset +++ b/data/assets/scene/solarsystem/missions/apollo/a17_lem.asset @@ -14,6 +14,7 @@ local Apollo17Lem = { Globe = moonAsset.Moon.Identifier, Longitude = -329.22833, Latitude = 20.19092, + UseHeightmap = true }, }, GUI = { diff --git a/data/assets/scene/solarsystem/missions/apollo/apollo11.asset b/data/assets/scene/solarsystem/missions/apollo/apollo11.asset index 64f5dcd9bd..ac1c6eb153 100644 --- a/data/assets/scene/solarsystem/missions/apollo/apollo11.asset +++ b/data/assets/scene/solarsystem/missions/apollo/apollo11.asset @@ -1,5 +1,8 @@ local assetHelper = asset.require('util/asset_helper') local sunTransforms = asset.require('scene/solarsystem/sun/transforms') +local descentKeyframes = asset.require('./apollo11_lem_descent.asset') +local descentRotationKeyframes = asset.require('./apollo11_lem_descent_rotation.asset') +local model = asset.require('scene/solarsystem/missions/apollo/lem_model') asset.require('spice/base') @@ -11,7 +14,7 @@ local kernelsFolder = asset.syncedResource({ }) local modelFolder = asset.syncedResource({ - Name = "Apollo Kernels", + Name = "Apollo Models", Type = "HttpSynchronization", Identifier = "apollo_11_models", Version = 1 @@ -24,7 +27,7 @@ local kernels = { kernelsFolder .. '/apollo11_orbits_full9km.bsp', kernelsFolder .. '/apollo11_orbits_lm9km.bsp', } - +--landing - 1969-07-20T20:17:40 local apolloSpiceId = "-911" local apolloLemSpiceId = "-911500" @@ -107,81 +110,44 @@ local Apollo11MoonTrail = { } } --- Uncomment if you want to follow the mock decent --- local Apollo11LemPosition = { --- Identifier = "Apollo11LemPosition", --- Parent = "Moon", --- TimeFrame = { --- Type = "TimeFrameInterval", --- Start = "1969 JUL 20 19:10:25.183", --- End = "1969 JUL 20 20:17:46.183" --- }, --- Transform = { --- Translation = { --- Type = "SpiceTranslation", --- Target = apolloLemSpiceId, --- Observer = "MOON", --- Frame = "MOON_ME", --- Kernels = kernels --- }, --- }, --- GUI = { --- Hidden = true, --- Name = "Apollo 11 Lunar Lander Position", --- Path = "/Solar System/Missions/Apollo/11" --- } --- } --- local Apollo11LunarLanderModel = { --- Identifier = "Apollo11LunarLander", --- Parent = Apollo11LemPosition.Identifier, --- Transform = { --- Rotation = { --- Type = "StaticRotation", --- Rotation = {0.0, 0.0, -3.1415/2} --- }, --- Scale = { --- Type = "StaticScale", --- Scale = 100.0 --- } --- }, --- TimeFrame = { --- Type = "TimeFrameInterval", --- Start = "1969 JUL 20 19:10:25.183", --- End = "1969 JUL 20 20:17:46.183" --- }, --- Renderable = { --- Type = "RenderableModel", --- Geometry = { --- Type = "MultiModelGeometry", --- GeometryFile = modelFolder .. "/lem_nasa.obj" --- }, --- ColorTexture = modelFolder .. "/gray.png", --- LightSources = assetHelper.getDefaultLightSources(sunTransforms.SolarSystemBarycenter.Identifier) --- }, --- GUI = { --- Hidden = false, --- Name = "Apollo 11 Lunar Lander", --- Path = "/Solar System/Missions/Apollo/11" --- } --- } - -local Apollo11LemTrail = { - Identifier = "Apollo11LemTrail", - Parent = "Moon", - Renderable = { - Type = "RenderableTrailTrajectory", - Translation = { +local lemTranslation = { + Type = "TimelineTranslation", + Keyframes = { + -- 20:14:30 is an arbitrary cutoff, but last 4 minutes data in descentKeyframes + -- begins at 20.14.40. Due to linear interpolation, we will get + -- a 10s linear transition to the location where the descentKeyframes start. + ['1969 JUL 20 20:14:30'] = { Type = "SpiceTranslation", Target = apolloLemSpiceId, Observer = "MOON", Frame = "IAU_MOON", Kernels = kernels }, - Color = {0.780000,0.940000,0.340000 }, + ['1969 JUL 20 20:14:40'] = { + Type = "TimelineTranslation", + Keyframes = descentKeyframes.keyframes + } + } +} + +local lemRotation = { + Type = "TimelineRotation", + Keyframes = descentRotationKeyframes.keyframes +} + + + +local Apollo11LemTrail = { + Identifier = "Apollo11LemTrail", + Parent = "Moon", + Renderable = { + Type = "RenderableTrailTrajectory", + Translation = lemTranslation, + Color = { 0.780000,0.940000,0.340000 }, StartTime = "1969 JUL 20 19:10:25.183", EndTime = "1969 JUL 20 20:17:46.183", - SampleInterval = 60, + SampleInterval = 2, EnableFade = false, Enabled = false, }, @@ -191,11 +157,91 @@ local Apollo11LemTrail = { } } +local Apollo11LemPosition = { + Identifier = "Apollo11LemPosition", + Parent = "Moon", + TimeFrame = { + Type = "TimeFrameInterval", + Start = "1969 JUL 20 19:10:25.183" + }, + Transform = { + Translation = lemTranslation, + Rotation = lemRotation + }, + GUI = { + Hidden = false, + Name = "Apollo 11 Lunar Lander Position", + Path = "/Solar System/Missions/Apollo/11" + } +} +--landing - 1969-07-20T20:17:40 + +local Apollo11LemDescentModel = { + Identifier = "Apollo11LemDescentModel", + Parent = Apollo11LemPosition.Identifier, + TimeFrame = { + Type = "TimeFrameInterval", + Start = "1969 JUL 19 19:38:29.183", + End = "1969 JUL 20 20:17:40.0" + }, + Transform = { + Scale = { + Type = "StaticScale", + Scale = 0.24 + } + }, + Renderable = { + Type = "RenderableModel", + Geometry = { + Type = "MultiModelGeometry", + GeometryFile = model.modelFolder .. "/lmremoved.obj" + }, + ColorTexture = model.modelFolder .. "/LM-2_ver2clean_u1_v1.jpeg", + LightSources = assetHelper.getDefaultLightSources(sunTransforms.SolarSystemBarycenter.Identifier) + }, + GUI = { + Hidden = false, + Name = "Apollo 11 Descent Lem", + Path = "/Solar System/Missions/Apollo/11" + } +} + +local Apollo11LemLandedModel = { + Identifier = "Apollo11LemLandedModel", + Parent = Apollo11LemPosition.Identifier, + TimeFrame = { + Type = "TimeFrameInterval", + Start = "1969 JUL 20 20:17:40.0" + }, + Transform = { + Scale = { + Type = "StaticScale", + Scale = 0.24 + } + }, + Renderable = { + Type = "RenderableModel", + Geometry = { + Type = "MultiModelGeometry", + GeometryFile = model.modelFolder .. "/LM-2_ver2clean.obj" + }, + ColorTexture = model.modelFolder .. "/LM-2_ver2clean_u1_v1.jpeg", + LightSources = assetHelper.getDefaultLightSources(sunTransforms.SolarSystemBarycenter.Identifier) + }, + GUI = { + Hidden = false, + Name = "Apollo 11 Landed Lem", + Path = "/Solar System/Missions/Apollo/11" + } +} + + local exportList = { - Apollo11Position, - -- Apollo11LemPosition, + Apollo11Position, + Apollo11LemPosition, Apollo11Model, - -- Apollo11LunarLanderModel, + Apollo11LemDescentModel, + Apollo11LemLandedModel, Apollo11MoonTrail, Apollo11LemTrail, } diff --git a/data/assets/scene/solarsystem/missions/apollo/apollo_globebrowsing.asset b/data/assets/scene/solarsystem/missions/apollo/apollo_globebrowsing.asset index aaab113192..fb9f1e14c5 100644 --- a/data/assets/scene/solarsystem/missions/apollo/apollo_globebrowsing.asset +++ b/data/assets/scene/solarsystem/missions/apollo/apollo_globebrowsing.asset @@ -2,36 +2,36 @@ local heightmaps = asset.syncedResource({ - Name = "Apollo Globebrowsing", + Name = "Apollo Globebrowsing Heightmaps", Type = "HttpSynchronization", Identifier = "apollo_globebrowsing_heightmaps", Version = 1 }) local basemaps = asset.syncedResource({ - Name = "Apollo Globebrowsing", + Name = "Apollo Globebrowsing Basemaps", Type = "HttpSynchronization", Identifier = "apollo_globebrowsing_basemaps", Version = 1 }) local naclighting = asset.syncedResource({ - Name = "Apollo Globebrowsing", + Name = "Apollo Globebrowsing NAC Lighting", Type = "HttpSynchronization", Identifier = "apollo_globebrowsing_naclighting", Version = 1 }) local stations = asset.syncedResource({ - Name = "Apollo 17 Globebrowsing", + Name = "Apollo 17 Globebrowsing Stations", Type = "HttpSynchronization", Identifier = "apollo_17_stations", Version = 1 }) asset.onInitialize(function () - openspace.globebrowsing.addBlendingLayersFromDirectory(heightmaps,"Moon") - openspace.globebrowsing.addBlendingLayersFromDirectory(basemaps,"Moon") - openspace.globebrowsing.addBlendingLayersFromDirectory(naclighting,"Moon") - openspace.globebrowsing.addBlendingLayersFromDirectory(stations,"Moon") + openspace.globebrowsing.addBlendingLayersFromDirectory(heightmaps, "Moon") + openspace.globebrowsing.addBlendingLayersFromDirectory(basemaps, "Moon") + openspace.globebrowsing.addBlendingLayersFromDirectory(naclighting, "Moon") + openspace.globebrowsing.addBlendingLayersFromDirectory(stations, "Moon") end) diff --git a/data/assets/scene/solarsystem/missions/apollo/bouldersstation2.asset b/data/assets/scene/solarsystem/missions/apollo/bouldersstation2.asset index 5723c970bc..2d096b99d0 100644 --- a/data/assets/scene/solarsystem/missions/apollo/bouldersstation2.asset +++ b/data/assets/scene/solarsystem/missions/apollo/bouldersstation2.asset @@ -33,8 +33,8 @@ local Station2Boulder1Holder = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.5294692, Latitude = 20.098824, - FixedAltitude = -2442.8, - UseFixedAltitude = true + Altitude = -2442.8, + UseHeightMap = false } }, GUI = { @@ -78,8 +78,8 @@ local Station2Boulder2Holder = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.5287892, Latitude = 20.098240, - FixedAltitude = -2434.6, - UseFixedAltitude = true + Altitude = -2434.6, + UseHeightMap = false } }, GUI = { @@ -123,8 +123,8 @@ local Station2Boulder3Holder = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.5294692, Latitude = 20.098610, - FixedAltitude = -2441.55, - UseFixedAltitude = true + Altitude = -2441.55, + UseHeightMap = false } }, GUI = { diff --git a/data/assets/scene/solarsystem/missions/apollo/bouldersstation6.asset b/data/assets/scene/solarsystem/missions/apollo/bouldersstation6.asset index dba9844a7c..919de3f9a8 100644 --- a/data/assets/scene/solarsystem/missions/apollo/bouldersstation6.asset +++ b/data/assets/scene/solarsystem/missions/apollo/bouldersstation6.asset @@ -37,6 +37,8 @@ local Station6Frag1Holder = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.80068, Latitude = 20.2903, + Altitude = -2562.6, + UseHeightmap = false } }, GUI = { @@ -54,6 +56,8 @@ local Station6Frag1Model = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.8007, Latitude = 20.2903, + Altitude = -2562.6, + UseHeightmap = false } }, Transform = { @@ -104,8 +108,8 @@ local Station6Frag2Model = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.80055, Latitude = 20.289808, - FixedAltitude = -2566.5, - UseFixedAltitude = true + Altitude = -2566.5, + UseHeightmap = false } }, Renderable = { @@ -140,8 +144,8 @@ local Station6Frag3Model = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.80053, Latitude = 20.29030, - FixedAltitude = -2563.0, - UseFixedAltitude = true + Altitude = -2563.0, + UseHeightMap = false } }, Renderable = { diff --git a/data/assets/scene/solarsystem/missions/apollo/bouldersstation7.asset b/data/assets/scene/solarsystem/missions/apollo/bouldersstation7.asset index 555d4fcb82..d2eab52355 100644 --- a/data/assets/scene/solarsystem/missions/apollo/bouldersstation7.asset +++ b/data/assets/scene/solarsystem/missions/apollo/bouldersstation7.asset @@ -34,8 +34,8 @@ local Station7BoulderHolder = { Globe = moonAsset.Moon.Identifier, Longitude = -360+30.8165882, Latitude = 20.2908556, - FixedAltitude = -2593.5, - UseFixedAltitude = true + Altitude = -2593.5, + UseHeightMap = true } }, GUI = { diff --git a/data/assets/scene/solarsystem/missions/apollo/lem_model.asset b/data/assets/scene/solarsystem/missions/apollo/lem_model.asset index cd592de5e8..dbc9210394 100644 --- a/data/assets/scene/solarsystem/missions/apollo/lem_model.asset +++ b/data/assets/scene/solarsystem/missions/apollo/lem_model.asset @@ -2,7 +2,7 @@ local modelFolder = asset.syncedResource({ Name = "Apollo Lem Models", Type = "HttpSynchronization", Identifier = "apollo_lem_model", - Version = 2 + Version = 3 }) asset.export('modelFolder', modelFolder) diff --git a/data/assets/scene/solarsystem/missions/dawn/vesta.asset b/data/assets/scene/solarsystem/missions/dawn/vesta.asset index d6b1735e36..64bfabfca8 100644 --- a/data/assets/scene/solarsystem/missions/dawn/vesta.asset +++ b/data/assets/scene/solarsystem/missions/dawn/vesta.asset @@ -20,7 +20,7 @@ local images = asset.syncedResource({ local models = asset.syncedResource({ Name = "Vesta Models", Type = "HttpSynchronization", - Identifier = "vesta_comet", + Identifier = "vesta_model", Version = 1 }) diff --git a/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset b/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset index 157b5dbbfd..7938f89387 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset @@ -14,7 +14,7 @@ local carpoGroup = { { Identifier = "Carpo", Parent = { - Name = parentIdentifier, + Identifier = parentIdentifier, Spice = parentSpice }, Spice = "CARPO", diff --git a/data/assets/scene/solarsystem/sssb/tesla_roadster.asset b/data/assets/scene/solarsystem/sssb/tesla_roadster.asset index 5fd6308fdc..ca2a577dff 100644 --- a/data/assets/scene/solarsystem/sssb/tesla_roadster.asset +++ b/data/assets/scene/solarsystem/sssb/tesla_roadster.asset @@ -20,7 +20,8 @@ local TeslaRoadsterTrail = { Color = { 0.9, 0.9, 0.0 }, StartTime = "2018 FEB 8 00:00:00", EndTime = "2022 FEB 7 00:00:00", - SampleInterval = 60 + SampleInterval = 3000, + TimeStampSubsampleFactor = 1 }, GUI = { Name = "Tesla Roadster Trail", diff --git a/data/assets/util/asset_helper.asset b/data/assets/util/asset_helper.asset index 8664122cbc..a785329785 100644 --- a/data/assets/util/asset_helper.asset +++ b/data/assets/util/asset_helper.asset @@ -42,6 +42,29 @@ local registerSceneGraphNodes = function (sceneAsset, nodes, override) end) end + +local registerScreenSpaceRenderables = function (sceneAsset, renderables, override) + override = override or false + if not override then + if tableLength(renderables) == 0 then + openspace.printWarning(sceneAsset.filePath .. ": Register function was called with an empty node list. Pass 'true' as third argument to silence this warning.") + return + end + end + + sceneAsset.onInitialize(function () + for i, node in ipairs(renderables) do + openspace.addScreenSpaceRenderable(node) + end + end) + sceneAsset.onDeinitialize(function () + for i = #renderables, 1, -1 do + renderable = renderables[i] + openspace.removeScreenSpaceRenderable(renderable.Identifier) + end + end) +end + local registerDashboardItems = function (dashboardAsset, items) dashboardAsset.onInitialize( function () @@ -176,6 +199,7 @@ end asset.export("registerSceneGraphNodes", registerSceneGraphNodes) asset.export("registerSceneGraphNodesAndExport", registerSceneGraphNodesAndExport) +asset.export("registerScreenSpaceRenderables", registerScreenSpaceRenderables) asset.export("registerSpiceKernels", registerSpiceKernels) asset.export("registerDashboardItems", registerDashboardItems) asset.export("requireAll", requireAll) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index d4d54451c5..b51a582660 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -1,18 +1,11 @@ +asset.require('./static_server') + local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "c603ad07d1407a7d3def43f1e203244cee1c06f6" -local backendHash = "84737f9785f12efbb12d2de9d511154c6215fe9c" - +local frontendHash = "2d1bb8d8d8478b6ed025ccc6f1e0ceacf04b6114" local dataProvider = "data.openspaceproject.com/files/webgui" -local backend = asset.syncedResource({ - Identifier = "WebGuiBackend", - Name = "Web Gui Backend", - Type = "UrlSynchronization", - Url = dataProvider .. "/backend/" .. backendHash .. "/backend.zip" -}) - local frontend = asset.syncedResource({ Identifier = "WebGuiFrontend", Name = "Web Gui Frontend", @@ -27,22 +20,21 @@ asset.onInitialize(function () openspace.unzipFile(frontend .. "/frontend.zip", dest, true) end - -- Unzip the frontend bundle - dest = backend .. "/backend" - if not openspace.directoryExists(dest) then - openspace.unzipFile(backend .. "/backend.zip", dest, true) - end + -- Serve the production GUI: + local directories = openspace.getPropertyValue("Modules.WebGui.Directories") + directories[#directories + 1] = "frontend" + directories[#directories + 1] = frontend .. '/frontend' + openspace.setPropertyValueSingle("Modules.WebGui.Directories", directories) + openspace.setPropertyValueSingle("Modules.WebGui.DefaultEndpoint", "frontend") - -- Do not serve the files if we are in webgui development mode. - -- In that case, you have to serve the webgui manually, using `npm start`. - if not guiCustomization.webguiDevelopmentMode then + if guiCustomization.webguiDevelopmentMode then + -- Route CEF to the deveopment version of the GUI. + -- This must be manually served using `npm start` + -- in the OpenSpace-WebGuiFrontend repository. openspace.setPropertyValueSingle( - "Modules.WebGui.ServerProcessEntryPoint", backend .. "/backend/backend.js" + "Modules.CefWebGui.GuiUrl", + "http://127.0.0.1:4690/frontend/#/onscreen" ) - openspace.setPropertyValueSingle( - "Modules.WebGui.WebDirectory", frontend .. "/frontend" - ) - openspace.setPropertyValueSingle("Modules.WebGui.ServerProcessEnabled", true) end -- The GUI contains date and simulation increment, @@ -54,5 +46,17 @@ asset.onInitialize(function () end) asset.onDeinitialize(function () - openspace.setPropertyValueSingle("Modules.WebGui.ServerProcessEnabled", false) + -- Remove the frontend endpoint + local directories = openspace.getPropertyValue("Modules.WebGui.Directories") + local newDirectories; + + openspace.setPropertyValueSingle("Modules.WebGui.DefaultEndpoint", "") + + for i = 0, #directories, 2 do + if (string.find(directories[i], "frontend") == nil) then + newDirectories[#newDirectories + 1] = directories[i] + newDirectories[#newDirectories + 1] = directories[i + 1] + end + end + openspace.setPropertyValueSingle("Modules.WebGui.Directories", newDirectories) end) diff --git a/data/assets/voyager.scene b/data/assets/voyager.scene index d91cc5254d..c5789bf926 100644 --- a/data/assets/voyager.scene +++ b/data/assets/voyager.scene @@ -47,10 +47,10 @@ asset.onInitialize(function () "Earth", "Voyager 1", "Voyager 2", "Jupiter", "Saturn", "Uranus", "Neptune" }) - openspace.navigation.setCameraState({ + openspace.navigation.setNavigationState({ Anchor = VoyagerAsset.Voyager_1.Identifier, - Position = { 526781518487.171326, 257168309890.072144, -1381125204152.817383 }, - Rotation = { -0.106166, 0.981574, -0.084545, 0.134513 }, + ReferenceFrame = "Root", + Position = { 526781518487.171326, 257168309890.072144, -1381125204152.817383 } }) end) diff --git a/include/openspace/interaction/interpolator.h b/include/openspace/interaction/interpolator.h index b2f79a9e55..54750bc1eb 100644 --- a/include/openspace/interaction/interpolator.h +++ b/include/openspace/interaction/interpolator.h @@ -51,7 +51,7 @@ public: private: std::function _transferFunction; - float _t = 0.f; + float _t = 1.f; float _interpolationTime = 1.f; float _scaledDeltaTime = 0.f; }; diff --git a/include/openspace/interaction/navigationhandler.h b/include/openspace/interaction/navigationhandler.h index 3ab99cd0e9..0da3db3ab8 100644 --- a/include/openspace/interaction/navigationhandler.h +++ b/include/openspace/interaction/navigationhandler.h @@ -25,13 +25,17 @@ #ifndef __OPENSPACE_CORE___NAVIGATIONHANDLER___H__ #define __OPENSPACE_CORE___NAVIGATIONHANDLER___H__ -#include - +#include +#include #include +#include +#include +#include #include #include #include #include +#include namespace openspace { class Camera; @@ -48,6 +52,25 @@ class OrbitalNavigator; class NavigationHandler : public properties::PropertyOwner { public: + struct NavigationState { + NavigationState() = default; + NavigationState(const ghoul::Dictionary& dictionary); + NavigationState(std::string anchor, std::string aim, std::string referenceFrame, + glm::dvec3 position, std::optional up = std::nullopt, + double yaw = 0.0, double pitch = 0.0); + + ghoul::Dictionary dictionary() const; + static documentation::Documentation Documentation(); + + std::string anchor; + std::string aim; + std::string referenceFrame; + glm::dvec3 position; + std::optional up; + double yaw = 0.0; + double pitch = 0.0; + }; + NavigationHandler(); ~NavigationHandler(); @@ -55,10 +78,10 @@ public: void deinitialize(); // Mutators + void setNavigationStateNextFame(NavigationState state); void setCamera(Camera* camera); void setInterpolationTime(float durationInSeconds); - void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict); void updateCamera(double deltaTime); void setEnableKeyFrameInteraction(); void setDisableKeyFrameInteraction(); @@ -66,12 +89,11 @@ public: void stopPlayback(); // Accessors - ghoul::Dictionary cameraStateDictionary(); Camera* camera() const; const InputState& inputState() const; const OrbitalNavigator& orbitalNavigator() const; OrbitalNavigator& orbitalNavigator(); - KeyframeNavigator& keyframeNavigator() const; + KeyframeNavigator& keyframeNavigator(); bool isKeyFrameInteractionEnabled() const; float interpolationTime() const; @@ -100,10 +122,14 @@ public: void clearJoystickButtonCommand(int button); std::vector joystickButtonCommand(int button) const; + NavigationState navigationState(const SceneGraphNode& referenceFrame) const; + void saveNavigationState(const std::string& filepath, + const std::string& referenceFrameIdentifier); - void saveCameraStateToFile(const std::string& filepath); - void restoreCameraStateFromFile(const std::string& filepath); + void loadNavigationState(const std::string& filepath); + + void setNavigationStateNextFrame(NavigationState state); /** * \return The Lua library that contains all Lua functions available to affect the @@ -112,15 +138,18 @@ public: static scripting::LuaLibrary luaLibrary(); private: - bool _cameraUpdatedFromScript = false; + void applyNavigationState(const NavigationHandler::NavigationState& ns); + bool _playbackModeEnabled = false; - std::unique_ptr _inputState; + InputState _inputState; Camera* _camera = nullptr; std::function _playbackEndCallback; - std::unique_ptr _orbitalNavigator; - std::unique_ptr _keyframeNavigator; + OrbitalNavigator _orbitalNavigator; + KeyframeNavigator _keyframeNavigator; + + std::optional _pendingNavigationState; properties::BoolProperty _useKeyFrameInteraction; }; diff --git a/include/openspace/interaction/orbitalnavigator.h b/include/openspace/interaction/orbitalnavigator.h index 3f60af50c6..0eff98c64c 100644 --- a/include/openspace/interaction/orbitalnavigator.h +++ b/include/openspace/interaction/orbitalnavigator.h @@ -38,6 +38,8 @@ #include #include +#include + namespace openspace { class SceneGraphNode; class Camera; @@ -58,6 +60,7 @@ public: Camera* camera() const; void setCamera(Camera* camera); + void clearPreviousState(); void setFocusNode(const std::string& focusNode); void setAnchorNode(const std::string& anchorNode); @@ -70,6 +73,7 @@ public: void resetNodeMovements(); JoystickCameraStates& joystickStates(); + const JoystickCameraStates& joystickStates() const; bool followingNodeRotation() const; const SceneGraphNode* anchorNode() const; @@ -146,10 +150,9 @@ private: const SceneGraphNode* _anchorNode = nullptr; const SceneGraphNode* _aimNode = nullptr; - glm::dvec3 _previousAnchorNodePosition; - glm::dquat _previousAnchorNodeRotation; - - glm::dvec3 _previousAimNodePosition; + std::optional_previousAnchorNodePosition; + std::optional _previousAnchorNodeRotation; + std::optional _previousAimNodePosition; double _currentCameraToSurfaceDistance = 0.0; bool _directlySetStereoDistance = false; diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 470f018fcb..26c5f5a094 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -221,7 +221,6 @@ private: double timestamp; }; ExternInteraction _externInteract; - bool _isRecording = false; double _timestampRecordStarted = 0.0; double _timestampPlaybackStarted_application = 0.0; double _timestampPlaybackStarted_simulation = 0.0; diff --git a/include/openspace/rendering/screenspacerenderable.h b/include/openspace/rendering/screenspacerenderable.h index 6f780f29b4..d5dfabef94 100644 --- a/include/openspace/rendering/screenspacerenderable.h +++ b/include/openspace/rendering/screenspacerenderable.h @@ -82,7 +82,7 @@ protected: void draw(glm::mat4 modelTransform); - virtual void bindTexture(); + virtual void bindTexture() = 0; virtual void unbindTexture(); properties::BoolProperty _enabled; @@ -106,10 +106,8 @@ protected: properties::TriggerProperty _delete; glm::ivec2 _objectSize; - UniformCache(occlusionDepth, alpha, modelTransform, viewProj, texture) _uniformCache; + UniformCache(alpha, modelTransform, viewProj, texture) _uniformCache; std::unique_ptr _shader; - - glm::vec2 _originalViewportSize; }; } // namespace openspace diff --git a/include/openspace/util/time.h b/include/openspace/util/time.h index aa8cf2e4c0..d784ac2426 100644 --- a/include/openspace/util/time.h +++ b/include/openspace/util/time.h @@ -65,7 +65,7 @@ public: */ static double convertTime(const std::string& time); - Time(double secondsJ2000 = -1); + explicit Time(double secondsJ2000 = -1); Time(const Time& other) = default; /** diff --git a/include/openspace/util/timeline.h b/include/openspace/util/timeline.h index b47d9cf4e3..81f2a9687b 100644 --- a/include/openspace/util/timeline.h +++ b/include/openspace/util/timeline.h @@ -44,7 +44,12 @@ struct KeyframeBase { */ template struct Keyframe : public KeyframeBase { - Keyframe(size_t i, double t, T p); + Keyframe(size_t i, double t, T d); + + Keyframe(Keyframe const&) = default; + Keyframe(Keyframe&&) = default; + Keyframe& operator=(Keyframe&&) = default; + Keyframe& operator=(Keyframe const&) = default; T data; }; @@ -56,7 +61,8 @@ class Timeline { public: virtual ~Timeline() = default; - void addKeyframe(double time, T data); + void addKeyframe(double time, const T& data); + void addKeyframe(double time, T&& data); void clearKeyframes(); void removeKeyframe(size_t id); void removeKeyframesBefore(double timestamp, bool inclusive = false); @@ -66,6 +72,7 @@ public: size_t nKeyframes() const; const Keyframe* firstKeyframeAfter(double timestamp, bool inclusive = false) const; const Keyframe* lastKeyframeBefore(double timestamp, bool inclusive = false) const; + const std::deque>& keyframes() const; private: diff --git a/include/openspace/util/timeline.inl b/include/openspace/util/timeline.inl index 79ccf4c51a..d2811a6aee 100644 --- a/include/openspace/util/timeline.inl +++ b/include/openspace/util/timeline.inl @@ -25,13 +25,25 @@ namespace openspace { template -Keyframe::Keyframe(size_t i, double t, T p) +Keyframe::Keyframe(size_t i, double t, T d) : KeyframeBase{ i, t } - , data(p) + , data(std::move(d)) {} template -void Timeline::addKeyframe(double timestamp, T data) { +void Timeline::addKeyframe(double timestamp, T&& data) { + Keyframe keyframe(++_nextKeyframeId, timestamp, std::move(data)); + const auto iter = std::upper_bound( + _keyframes.cbegin(), + _keyframes.cend(), + keyframe, + &compareKeyframeTimes + ); + _keyframes.insert(iter, std::move(keyframe)); +} + +template +void Timeline::addKeyframe(double timestamp, const T& data) { Keyframe keyframe(++_nextKeyframeId, timestamp, data); const auto iter = std::upper_bound( _keyframes.cbegin(), @@ -39,7 +51,7 @@ void Timeline::addKeyframe(double timestamp, T data) { keyframe, &compareKeyframeTimes ); - _keyframes.insert(iter, keyframe); + _keyframes.insert(iter, std::move(keyframe)); } template @@ -143,7 +155,7 @@ void Timeline::removeKeyframe(size_t id) { std::remove_if( _keyframes.begin(), _keyframes.end(), - [id] (Keyframe keyframe) { return keyframe.id == id; } + [id] (const Keyframe& keyframe) { return keyframe.id == id; } ), _keyframes.end() ); @@ -209,7 +221,7 @@ const Keyframe* Timeline::lastKeyframeBefore(double timestamp, bool inclus return &(*it); } -template +template const std::deque>& Timeline::keyframes() const { return _keyframes; } diff --git a/modules/base/CMakeLists.txt b/modules/base/CMakeLists.txt index de4b747968..2ce1e6846c 100644 --- a/modules/base/CMakeLists.txt +++ b/modules/base/CMakeLists.txt @@ -54,8 +54,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceframebuffer.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceimagelocal.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceimageonline.h - ${CMAKE_CURRENT_SOURCE_DIR}/translation/luatranslation.h - ${CMAKE_CURRENT_SOURCE_DIR}/translation/statictranslation.h + ${CMAKE_CURRENT_SOURCE_DIR}/rotation/timelinerotation.h ${CMAKE_CURRENT_SOURCE_DIR}/rotation/constantrotation.h ${CMAKE_CURRENT_SOURCE_DIR}/rotation/fixedrotation.h ${CMAKE_CURRENT_SOURCE_DIR}/rotation/luarotation.h @@ -65,6 +64,10 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/scale/timedependentscale.h ${CMAKE_CURRENT_SOURCE_DIR}/timeframe/timeframeinterval.h ${CMAKE_CURRENT_SOURCE_DIR}/timeframe/timeframeunion.h + ${CMAKE_CURRENT_SOURCE_DIR}/translation/luatranslation.h + ${CMAKE_CURRENT_SOURCE_DIR}/translation/statictranslation.h + ${CMAKE_CURRENT_SOURCE_DIR}/translation/timelinetranslation.h + ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -98,8 +101,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceframebuffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceimagelocal.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspaceimageonline.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/translation/luatranslation.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/translation/statictranslation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rotation/timelinerotation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rotation/constantrotation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rotation/fixedrotation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rotation/luarotation.cpp @@ -109,6 +111,9 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/scale/timedependentscale.cpp ${CMAKE_CURRENT_SOURCE_DIR}/timeframe/timeframeinterval.cpp ${CMAKE_CURRENT_SOURCE_DIR}/timeframe/timeframeunion.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/translation/luatranslation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/translation/statictranslation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/translation/timelinetranslation.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp index ead6089797..ba70bd6c2e 100644 --- a/modules/base/basemodule.cpp +++ b/modules/base/basemodule.cpp @@ -55,9 +55,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -131,6 +133,7 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) { auto fTranslation = FactoryManager::ref().factory(); ghoul_assert(fTranslation, "Ephemeris factory was not created"); + fTranslation->registerClass("TimelineTranslation"); fTranslation->registerClass("LuaTranslation"); fTranslation->registerClass("StaticTranslation"); @@ -141,6 +144,8 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) { fRotation->registerClass("FixedRotation"); fRotation->registerClass("LuaRotation"); fRotation->registerClass("StaticRotation"); + fRotation->registerClass("TimelineRotation"); + auto fScale = FactoryManager::ref().factory(); ghoul_assert(fScale, "Scale factory was not created"); @@ -198,6 +203,7 @@ std::vector BaseModule::documentations() const { FixedRotation::Documentation(), LuaRotation::Documentation(), StaticRotation::Documentation(), + TimelineRotation::Documentation(), LuaScale::Documentation(), StaticScale::Documentation(), @@ -205,6 +211,7 @@ std::vector BaseModule::documentations() const { LuaTranslation::Documentation(), StaticTranslation::Documentation(), + TimelineTranslation::Documentation(), TimeFrameInterval::Documentation(), TimeFrameUnion::Documentation(), diff --git a/modules/base/dashboard/dashboarditemframerate.cpp b/modules/base/dashboard/dashboarditemframerate.cpp index 006667a6f2..bdc10a49a0 100644 --- a/modules/base/dashboard/dashboarditemframerate.cpp +++ b/modules/base/dashboard/dashboarditemframerate.cpp @@ -289,7 +289,7 @@ void DashboardItemFramerate::render(glm::vec2& penPosition) { ); int nLines = output.empty() ? 0 : - (std::count(output.begin(), output.end(), '\n') + 1); + static_cast((std::count(output.begin(), output.end(), '\n') + 1)); penPosition.y -= _font->height() * static_cast(nLines); diff --git a/modules/base/rendering/renderabletrailtrajectory.cpp b/modules/base/rendering/renderabletrailtrajectory.cpp index 54f51f1c27..ee019b8827 100644 --- a/modules/base/rendering/renderabletrailtrajectory.cpp +++ b/modules/base/rendering/renderabletrailtrajectory.cpp @@ -226,8 +226,8 @@ void RenderableTrailTrajectory::update(const UpdateData& data) { for (int i = 0; i < nValues; ++i) { const glm::vec3 p = _translation->position({ {}, - _start + i * totalSampleInterval, - 0.0, + Time(_start + i * totalSampleInterval), + Time(0.0), false }); _vertexArray[i] = { p.x, p.y, p.z }; diff --git a/modules/base/rendering/screenspacedashboard.cpp b/modules/base/rendering/screenspacedashboard.cpp index 9f271d350c..d86376d06f 100644 --- a/modules/base/rendering/screenspacedashboard.cpp +++ b/modules/base/rendering/screenspacedashboard.cpp @@ -212,7 +212,6 @@ void ScreenSpaceDashboard::update() { if (global::windowDelegate.windowHasResized()) { const glm::ivec2 size = global::windowDelegate.currentWindowResolution(); _size = { 0.f, 0.f, size.x, size.y }; - _originalViewportSize = size; createFramebuffer(); } } diff --git a/modules/base/rendering/screenspaceframebuffer.cpp b/modules/base/rendering/screenspaceframebuffer.cpp index 28ba4d80e0..5a94669b99 100644 --- a/modules/base/rendering/screenspaceframebuffer.cpp +++ b/modules/base/rendering/screenspaceframebuffer.cpp @@ -106,15 +106,15 @@ void ScreenSpaceFramebuffer::render() { const glm::vec2& resolution = global::windowDelegate.currentWindowResolution(); const glm::vec4& size = _size.value(); - const float xratio = _originalViewportSize.x / (size.z - size.x); - const float yratio = _originalViewportSize.y / (size.w - size.y);; + const float xratio = resolution.x / (size.z - size.x); + const float yratio = resolution.y / (size.w - size.y);; if (!_renderFunctions.empty()) { glViewport( static_cast(-size.x * xratio), static_cast(-size.y * yratio), - static_cast(_originalViewportSize.x * xratio), - static_cast(_originalViewportSize.y * yratio) + static_cast(resolution.x * xratio), + static_cast(resolution.y * yratio) ); GLint defaultFBO = _framebuffer->getActiveObject(); _framebuffer->activate(); @@ -170,14 +170,16 @@ void ScreenSpaceFramebuffer::removeAllRenderFunctions() { } void ScreenSpaceFramebuffer::createFramebuffer() { + glm::vec2 resolution = global::windowDelegate.currentWindowResolution(); + _framebuffer = std::make_unique(); _framebuffer->activate(); _texture = std::make_unique(glm::uvec3( - _originalViewportSize.x, - _originalViewportSize.y, + resolution.x, + resolution.y, 1 )); - _objectSize = glm::ivec2(_originalViewportSize); + _objectSize = glm::ivec2(resolution); _texture->uploadTexture(); _texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); diff --git a/modules/base/rendering/screenspaceimagelocal.cpp b/modules/base/rendering/screenspaceimagelocal.cpp index a0751cf9f0..392a8952d0 100644 --- a/modules/base/rendering/screenspaceimagelocal.cpp +++ b/modules/base/rendering/screenspaceimagelocal.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -96,11 +97,30 @@ ScreenSpaceImageLocal::ScreenSpaceImageLocal(const ghoul::Dictionary& dictionary setGuiName("ScreenSpaceImageLocal " + std::to_string(iIdentifier)); } - _texturePath.onChange([this]() { _textureIsDirty = true; }); + _texturePath.onChange([this]() { + if (!FileSys.fileExists(FileSys.absolutePath(_texturePath))) { + LWARNINGC( + "ScreenSpaceImageLocal", + fmt::format("Image {} did not exist for {}", _texturePath, _identifier) + ); + } + else { + _textureIsDirty = true; + } + }); addProperty(_texturePath); if (dictionary.hasKey(TexturePathInfo.identifier)) { - _texturePath = dictionary.value(TexturePathInfo.identifier); + std::string path = dictionary.value(TexturePathInfo.identifier); + if (!FileSys.fileExists(FileSys.absolutePath(path))) { + LWARNINGC( + "ScreenSpaceImageLocal", + fmt::format("Image {} did not exist for {}", path, _identifier) + ); + } + else { + _texturePath = path; + } } } @@ -130,12 +150,13 @@ void ScreenSpaceImageLocal::update() { _objectSize = _texture->dimensions(); _textureIsDirty = false; } - } } void ScreenSpaceImageLocal::bindTexture() { - _texture->bind(); + if (_texture) { + _texture->bind(); + } } } // namespace openspace diff --git a/modules/base/shaders/screenspace_fs.glsl b/modules/base/shaders/screenspace_fs.glsl index 6d4e66856c..9dc5fd70ad 100644 --- a/modules/base/shaders/screenspace_fs.glsl +++ b/modules/base/shaders/screenspace_fs.glsl @@ -29,10 +29,8 @@ in vec2 vs_st; in vec4 vs_position; uniform sampler2D texture1; -uniform float OcclusionDepth; uniform float Alpha; - Fragment getFragment() { Fragment frag; diff --git a/modules/cefwebgui/cefwebguimodule.cpp b/modules/cefwebgui/cefwebguimodule.cpp index ecdbfc46b1..4a69090acf 100644 --- a/modules/cefwebgui/cefwebguimodule.cpp +++ b/modules/cefwebgui/cefwebguimodule.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -166,7 +165,15 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) } else { WebGuiModule* webGuiModule = global::moduleEngine.module(); _url = "http://127.0.0.1:" + - std::to_string(webGuiModule->port()) + "/#/onscreen"; + std::to_string(webGuiModule->port()) + "/frontend/#/onscreen"; + + _endpointCallback = webGuiModule->addEndpointChangeCallback( + [this](const std::string& endpoint, bool exists) { + if (exists && endpoint == "frontend" && _instance) { + _instance->reloadBrowser(); + } + } + ); } if (configuration.hasValue(GuiScaleInfo.identifier)) { @@ -204,6 +211,11 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) }); global::callback::deinitializeGL.emplace_back([this]() { + if (_endpointCallback != -1) { + WebGuiModule* webGuiModule = global::moduleEngine.module(); + webGuiModule->removeEndpointChangeCallback(_endpointCallback); + _endpointCallback = -1; + } _enabled = false; startOrStopGui(); }); diff --git a/modules/cefwebgui/cefwebguimodule.h b/modules/cefwebgui/cefwebguimodule.h index 81bf8231f4..d822b838a5 100644 --- a/modules/cefwebgui/cefwebguimodule.h +++ b/modules/cefwebgui/cefwebguimodule.h @@ -27,6 +27,8 @@ #include +#include + #include #include #include @@ -53,6 +55,8 @@ private: properties::StringProperty _url; properties::FloatProperty _guiScale; std::unique_ptr _instance; + + WebGuiModule::CallbackHandle _endpointCallback = -1; }; } // namespace openspace diff --git a/modules/cefwebgui/include/guirenderhandler.h b/modules/cefwebgui/include/guirenderhandler.h index 203ccf3eb9..b28a1875f5 100644 --- a/modules/cefwebgui/include/guirenderhandler.h +++ b/modules/cefwebgui/include/guirenderhandler.h @@ -39,8 +39,8 @@ public: GUIRenderHandler(); virtual ~GUIRenderHandler(); - void draw(); - void render(); + void draw() override; + void render() override; private: std::unique_ptr _programObject; diff --git a/modules/cefwebgui/shaders/gui_vs.glsl b/modules/cefwebgui/shaders/gui_vs.glsl index 2488aa7924..2323d505d3 100644 --- a/modules/cefwebgui/shaders/gui_vs.glsl +++ b/modules/cefwebgui/shaders/gui_vs.glsl @@ -31,8 +31,7 @@ uniform mat4 ortho; out vec2 Texcoord; void main() { - Texcoord = vec2(position.x + 1.0f, position.y - 1.0f) * 0.5; - Texcoord.y *= -1.0f; + Texcoord = vec2(position.x + 1.0f, position.y + 1.0f) * 0.5; gl_Position = vec4(position, 0.0, 1.0); } diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp index 171625c4e3..c29d1608a9 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp @@ -750,7 +750,6 @@ void RenderableBillboardsCloud::renderBillboards(const RenderData& data, _program->activate(); - const glm::dmat4 projMatrix = glm::dmat4(data.camera.projectionMatrix()); _program->setUniform( "screenSize", glm::vec2(global::renderEngine.renderingResolution()) diff --git a/modules/digitaluniverse/rendering/renderabledumeshes.cpp b/modules/digitaluniverse/rendering/renderabledumeshes.cpp index 8c4c84e4f3..ccaa706c03 100644 --- a/modules/digitaluniverse/rendering/renderabledumeshes.cpp +++ b/modules/digitaluniverse/rendering/renderabledumeshes.cpp @@ -77,19 +77,6 @@ namespace { "all point." }; - //constexpr openspace::properties::Property::PropertyInfo ScaleFactorInfo = { - // "ScaleFactor", - // "Scale Factor", - // "This value is used as a multiplicative factor that is applied to the apparent " - // "size of each point." - //}; - - constexpr openspace::properties::Property::PropertyInfo ColorInfo = { - "Color", - "Color", - "This value is used to define the color of the astronomical object." - }; - constexpr openspace::properties::Property::PropertyInfo TextColorInfo = { "TextColor", "Text Color", @@ -427,7 +414,7 @@ void RenderableDUMeshes::initializeGL() { } void RenderableDUMeshes::deinitializeGL() { - for (const std::pair& pair : _renderingMeshesMap) { + for (const std::pair& pair : _renderingMeshesMap) { for (int i = 0; i < pair.second.numU; ++i) { glDeleteVertexArrays(1, &pair.second.vaoArray[i]); glDeleteBuffers(1, &pair.second.vboArray[i]); @@ -483,7 +470,7 @@ void RenderableDUMeshes::renderMeshes(const RenderData&, _program->setUniform(_uniformCache.alphaValue, _alphaValue); //_program->setUniform(_uniformCache.scaleFactor, _scaleFactor); - for (const std::pair& pair : _renderingMeshesMap) { + for (const std::pair& pair : _renderingMeshesMap) { _program->setUniform(_uniformCache.color, _meshColorMap[pair.second.colorIndex]); for (size_t i = 0; i < pair.second.vaoArray.size(); ++i) { glBindVertexArray(pair.second.vaoArray[i]); diff --git a/modules/digitaluniverse/rendering/renderableplanescloud.cpp b/modules/digitaluniverse/rendering/renderableplanescloud.cpp index 7581b01f17..b06176406e 100644 --- a/modules/digitaluniverse/rendering/renderableplanescloud.cpp +++ b/modules/digitaluniverse/rendering/renderableplanescloud.cpp @@ -844,7 +844,7 @@ bool RenderablePlanesCloud::loadData() { bool RenderablePlanesCloud::loadTextures() { if (!_textureFileMap.empty()) { - for (const std::pair& pair : _textureFileMap) { + for (const std::pair& pair : _textureFileMap) { const auto& p = _textureMap.insert(std::make_pair( pair.first, ghoul::io::TextureReader::ref().loadTexture(pair.second) diff --git a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp index 1afc04feab..0e108d525f 100644 --- a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp +++ b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp @@ -771,7 +771,7 @@ void RenderableFieldlinesSequence::definePropertyCallbackFunctions() { }); _pJumpToStartBtn.onChange([this] { - global::timeManager.setTimeNextFrame(_startTimes[0]); + global::timeManager.setTimeNextFrame(Time(_startTimes[0])); }); } diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index 5d2bbafadf..7d46e40e1a 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -109,6 +109,11 @@ create_new_module( ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} ) +option(OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION "Instrumentation for GlobeBrowsing Performance" OFF) +if (OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION) + target_compile_definitions(openspace-module-globebrowsing INTERFACE "OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION") +endif () + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/gdal_data DESTINATION modules/globebrowsing) if (WIN32) diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index e17d676b3e..081fedebdc 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -100,6 +101,14 @@ namespace { "The maximum size of the MemoryAwareTileCache, on the CPU and GPU." }; +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + constexpr const openspace::properties::Property::PropertyInfo InstrumentationInfo = { + "SaveInstrumentationInfo", + "Save Instrumentation Info", + "If enabled, the instrumentation data is saved to disk at the end of the frame." + }; +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + openspace::GlobeBrowsingModule::Capabilities parseSubDatasets(char** subDatasets, int nSubdatasets) @@ -162,12 +171,24 @@ GlobeBrowsingModule::GlobeBrowsingModule() , _wmsCacheLocation(WMSCacheLocationInfo, "${BASE}/cache_gdal") , _wmsCacheSizeMB(WMSCacheSizeInfo, 1024) , _tileCacheSizeMB(TileCacheSizeInfo, 1024) +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + , _saveInstrumentation(InstrumentationInfo, false) +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION { addProperty(_wmsCacheEnabled); addProperty(_offlineMode); addProperty(_wmsCacheLocation); addProperty(_wmsCacheSizeMB); addProperty(_tileCacheSizeMB); + +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + _saveInstrumentation.onChange([&]() { + if (_saveInstrumentation) { + _frameInfo.lastSavedFrame = global::renderEngine.frameNumber(); + } + }); + addProperty(_saveInstrumentation); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION } void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) { @@ -234,6 +255,43 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) { // Render global::callback::render.emplace_back([&]() { _tileCache->update(); }); + // Postdraw +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + global::callback::postDraw.emplace_back([&]() { + // >= as we might have multiple frames per postDraw call (stereo rendering, + // fisheye, etc) + const uint16_t next = _frameInfo.lastSavedFrame + _frameInfo.saveEveryNthFrame; + const bool shouldSave = _saveInstrumentation && + global::renderEngine.frameNumber() >= next; + if (shouldSave) { + using K = const globebrowsing::RenderableGlobe*; + using V = std::vector; + for (const std::pair& i : _frameInfo.frames) { + std::string filename = fmt::format( + "_inst_globebrowsing_{}_{}_{}.txt", + i.first->owner()->identifier(), // Owner of the renderable has a name + _frameInfo.lastSavedFrame, + _frameInfo.saveEveryNthFrame + ); + std::ofstream file(absPath("${BIN}/" + filename)); + for (const FrameInfo& f : i.second) { + std::string line = fmt::format( + "{}\t{}\t{}\t{}", + f.iFrame, + f.nTilesRenderedLocal, + f.nTilesRenderedGlobal, + f.nTilesUploaded + ); + file << line << '\n'; + } + } + + _frameInfo.frames.clear(); + _frameInfo.lastSavedFrame = global::renderEngine.frameNumber(); + } + }); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + // Deinitialize global::callback::deinitialize.emplace_back([&]() { GdalWrapper::destroy(); }); @@ -338,16 +396,24 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { "goToGeo", &globebrowsing::luascriptfunctions::goToGeo, {}, - "number, number, number", - "Go to geographic coordinates latitude and longitude" + "[string], number, number, [number]", + "Go to geographic coordinates of a globe. The first (optional) argument is " + "the identifier of a scene graph node that has a RenderableGlobe attached. " + "If no globe is passed in, the current anchor will be used. " + "The second argument is latitude and the third is longitude (degrees). " + "North and East are expressed as positive angles, while South and West are " + "negative. The optional fourh argument is the altitude in meters. If no " + "altitude is provided, the altitude will be kept as the current distance to " + "the surface of the specified globe." }, { "getGeoPosition", &globebrowsing::luascriptfunctions::getGeoPosition, {}, - "name, latitude, longitude, altitude", - "Returns the specified surface position on the globe as three floating point " - "values" + "string, number, number, number", + "Returns the specified surface position on the globe identified by the first " + "argument, as three floating point values - latitude, longitude and altitude " + "(degrees and meters)." }, { "getGeoPositionForCamera", @@ -355,7 +421,7 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { {}, "void", "Get geographic coordinates of the camera poosition in latitude, " - "longitude, and altitude" + "longitude, and altitude (degrees and meters)." }, { "loadWMSCapabilities", @@ -395,29 +461,29 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { return res; } -void GlobeBrowsingModule::goToChunk(int x, int y, int level) { - Camera* cam = global::navigationHandler.camera(); - goToChunk(*cam, globebrowsing::TileIndex(x,y,level), glm::vec2(0.5f, 0.5f), true); +void GlobeBrowsingModule::goToChunk(const globebrowsing::RenderableGlobe& globe, + int x, int y, int level) +{ + goToChunk(globe, globebrowsing::TileIndex(x, y, level), glm::vec2(0.5f, 0.5f), true); } -void GlobeBrowsingModule::goToGeo(double latitude, double longitude) { +void GlobeBrowsingModule::goToGeo(const globebrowsing::RenderableGlobe& globe, + double latitude, double longitude) +{ using namespace globebrowsing; - Camera* cam = global::navigationHandler.camera(); goToGeodetic2( - *cam, + globe, Geodetic2{ glm::radians(latitude), glm::radians(longitude) }, true ); } -void GlobeBrowsingModule::goToGeo(double latitude, double longitude, - double altitude) +void GlobeBrowsingModule::goToGeo(const globebrowsing::RenderableGlobe& globe, + double latitude, double longitude, double altitude) { using namespace globebrowsing; - - Camera* cam = global::navigationHandler.camera(); goToGeodetic3( - *cam, + globe, { Geodetic2{ glm::radians(latitude), glm::radians(longitude) }, altitude @@ -437,32 +503,15 @@ glm::vec3 GlobeBrowsingModule::cartesianCoordinatesFromGeo( altitude }; - const glm::dvec3 positionModelSpace = globe.ellipsoid().cartesianPosition(pos); - //glm::dmat4 modelTransform = globe.modelTransform(); - //glm::dvec3 positionWorldSpace = glm::dvec3(modelTransform * - //glm::dvec4(positionModelSpace, 1.0)); - - return glm::vec3(positionModelSpace); + return glm::vec3(globe.ellipsoid().cartesianPosition(pos)); } -void GlobeBrowsingModule::goToChunk(Camera& camera, const globebrowsing::TileIndex& ti, +void GlobeBrowsingModule::goToChunk(const globebrowsing::RenderableGlobe& globe, + const globebrowsing::TileIndex& ti, glm::vec2 uv, bool doResetCameraDirection) { using namespace globebrowsing; - const RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); - if (!globe) { - LERROR("Focus node must have a RenderableGlobe renderable."); - return; - } - - // Camera position in model space - const glm::dvec3 camPos = camera.positionVec3(); - const glm::dmat4 inverseModelTransform = glm::inverse(globe->modelTransform()); - const glm::dvec3 cameraPositionModelSpace = glm::dvec3( - inverseModelTransform * glm::dvec4(camPos, 1) - ); - const GeodeticPatch patch(ti); const Geodetic2 corner = patch.corner(SOUTH_WEST); Geodetic2 positionOnPatch = patch.size(); @@ -473,32 +522,50 @@ void GlobeBrowsingModule::goToChunk(Camera& camera, const globebrowsing::TileInd corner.lon + positionOnPatch.lon }; - const glm::dvec3 positionOnEllipsoid = globe->ellipsoid().geodeticSurfaceProjection( + // Compute altitude + const glm::dvec3 cameraPosition = global::navigationHandler.camera()->positionVec3(); + SceneGraphNode* globeSceneGraphNode = dynamic_cast(globe.owner()); + if (!globeSceneGraphNode) { + LERROR( + "Cannot go to chunk. The renderable is not attached to a scene graph node." + ); + return; + } + const glm::dmat4 inverseModelTransform = globeSceneGraphNode->inverseModelTransform(); + const glm::dvec3 cameraPositionModelSpace = + glm::dvec3(inverseModelTransform * glm::dvec4(cameraPosition, 1.0)); + const SurfacePositionHandle posHandle = globe.calculateSurfacePositionHandle( cameraPositionModelSpace ); - const double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid); + + const Geodetic2 geo2 = globe.ellipsoid().cartesianToGeodetic2( + posHandle.centerToReferenceSurface + ); - goToGeodetic3(camera, {pointPosition, altitude}, doResetCameraDirection); + const double altitude = glm::length( + cameraPositionModelSpace - posHandle.centerToReferenceSurface + ); + + goToGeodetic3(globe, { pointPosition, altitude }, doResetCameraDirection); } -void GlobeBrowsingModule::goToGeodetic2(Camera& camera, globebrowsing::Geodetic2 geo2, +void GlobeBrowsingModule::goToGeodetic2(const globebrowsing::RenderableGlobe& globe, + globebrowsing::Geodetic2 geo2, bool doResetCameraDirection) { using namespace globebrowsing; - const RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); - if (!globe) { - LERROR("Focus node must have a RenderableGlobe renderable."); - return; + const glm::dvec3 cameraPosition = global::navigationHandler.camera()->positionVec3(); + SceneGraphNode* globeSceneGraphNode = dynamic_cast(globe.owner()); + if (!globeSceneGraphNode) { + LERROR("Error when going to Geodetic2"); } - interaction::NavigationHandler& nav = global::navigationHandler; - const glm::dvec3 cameraPosition = nav.camera()->positionVec3(); - const glm::dmat4 inverseModelTransform = - nav.orbitalNavigator().anchorNode()->inverseModelTransform(); + const glm::dmat4 inverseModelTransform = globeSceneGraphNode->inverseModelTransform(); + const glm::dvec3 cameraPositionModelSpace = glm::dvec3(inverseModelTransform * glm::dvec4(cameraPosition, 1.0)); - const SurfacePositionHandle posHandle = globe->calculateSurfacePositionHandle( + const SurfacePositionHandle posHandle = globe.calculateSurfacePositionHandle( cameraPositionModelSpace ); @@ -506,71 +573,58 @@ void GlobeBrowsingModule::goToGeodetic2(Camera& camera, globebrowsing::Geodetic2 posHandle.referenceSurfaceOutDirection * posHandle.heightToSurface; const double altitude = glm::length(cameraPositionModelSpace - centerToActualSurface); - goToGeodetic3(camera, { geo2, altitude }, doResetCameraDirection); + goToGeodetic3(globe, { geo2, altitude }, doResetCameraDirection); } -void GlobeBrowsingModule::goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3, +void GlobeBrowsingModule::goToGeodetic3(const globebrowsing::RenderableGlobe& globe, + globebrowsing::Geodetic3 geo3, bool doResetCameraDirection) { using namespace globebrowsing; + const glm::dvec3 positionModelSpace = globe.ellipsoid().cartesianPosition(geo3); - const RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); - if (!globe) { - LERROR("Focus node must have a RenderableGlobe renderable."); - return; - } - const glm::dvec3 positionModelSpace = globe->ellipsoid().cartesianPosition(geo3); - const glm::dmat4 modelTransform = globe->modelTransform(); - const glm::dvec3 positionWorldSpace = glm::dvec3(modelTransform * - glm::dvec4(positionModelSpace, 1.0)); - camera.setPositionVec3(positionWorldSpace); + const glm::dvec3 slightlyNorth = globe.ellipsoid().cartesianSurfacePosition( + Geodetic2{ geo3.geodetic2.lat + 0.001, geo3.geodetic2.lon } + ); - if (doResetCameraDirection) { - resetCameraDirection(camera, geo3.geodetic2); - } + interaction::NavigationHandler::NavigationState state; + state.anchor = globe.owner()->identifier(); + state.referenceFrame = globe.owner()->identifier(); + state.position = positionModelSpace; + state.up = slightlyNorth; + + global::navigationHandler.setNavigationStateNextFrame(state); } -void GlobeBrowsingModule::resetCameraDirection(Camera& camera, - globebrowsing::Geodetic2 geo2) +glm::dquat GlobeBrowsingModule::lookDownCameraRotation( + const globebrowsing::RenderableGlobe& globe, + glm::dvec3 cameraModelSpace, + globebrowsing::Geodetic2 geo2) { using namespace globebrowsing; - const RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); - if (!globe) { - LERROR("Focus node must have a RenderableGlobe renderable."); - return; - } - // Camera is described in world space - const glm::dmat4 modelTransform = globe->modelTransform(); + const glm::dmat4 modelTransform = globe.modelTransform(); // Lookup vector - const glm::dvec3 positionModelSpace = globe->ellipsoid().cartesianSurfacePosition( + const glm::dvec3 positionModelSpace = globe.ellipsoid().cartesianSurfacePosition( geo2 ); - const glm::dvec3 slightlyNorth = globe->ellipsoid().cartesianSurfacePosition( + const glm::dvec3 slightlyNorth = globe.ellipsoid().cartesianSurfacePosition( Geodetic2{ geo2.lat + 0.001, geo2.lon } ); const glm::dvec3 lookUpModelSpace = glm::normalize( slightlyNorth - positionModelSpace ); - const glm::dvec3 lookUpWorldSpace = glm::dmat3(modelTransform) * lookUpModelSpace; - - // Lookat vector - const glm::dvec3 lookAtWorldSpace = glm::dvec3( - modelTransform * glm::dvec4(positionModelSpace, 1.0) - ); - - // Eye position - const glm::dvec3 eye = camera.positionVec3(); // Matrix - const glm::dmat4 lookAtMatrix = glm::lookAt(eye, lookAtWorldSpace, lookUpWorldSpace); + const glm::dmat4 lookAtMatrix = + glm::lookAt(cameraModelSpace, positionModelSpace, lookUpModelSpace); // Set rotation const glm::dquat rotation = glm::quat_cast(inverse(lookAtMatrix)); - camera.setRotation(rotation); + return rotation; } const globebrowsing::RenderableGlobe* @@ -732,5 +786,27 @@ uint64_t GlobeBrowsingModule::wmsCacheSize() const { return size * 1024 * 1024; } +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION +void GlobeBrowsingModule::addFrameInfo(globebrowsing::RenderableGlobe* globe, + uint32_t nTilesRenderedLocal, + uint32_t nTilesRenderedGlobal, + uint32_t nTilesUploaded) +{ + auto it = _frameInfo.frames.find(globe); + if (it == _frameInfo.frames.end()) { + _frameInfo.frames[globe] = std::vector(); + _frameInfo.frames[globe].reserve(_frameInfo.saveEveryNthFrame); + } + else { + it->second.push_back({ + global::renderEngine.frameNumber(), + nTilesRenderedLocal, + nTilesRenderedGlobal, + nTilesUploaded + }); + } +} + +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION } // namespace openspace diff --git a/modules/globebrowsing/globebrowsingmodule.h b/modules/globebrowsing/globebrowsingmodule.h index 9db83196a9..89e397d8ab 100644 --- a/modules/globebrowsing/globebrowsingmodule.h +++ b/modules/globebrowsing/globebrowsingmodule.h @@ -53,9 +53,12 @@ public: GlobeBrowsingModule(); - void goToChunk(int x, int y, int level); - void goToGeo(double latitude, double longitude); - void goToGeo(double latitude, double longitude, double altitude); + void goToChunk(const globebrowsing::RenderableGlobe& globe, int x, int y, int level); + void goToGeo(const globebrowsing::RenderableGlobe& globe, + double latitude, double longitude); + + void goToGeo(const globebrowsing::RenderableGlobe& globe, + double latitude, double longitude, double altitude); glm::vec3 cartesianCoordinatesFromGeo(const globebrowsing::RenderableGlobe& globe, double latitude, double longitude, double altitude); @@ -90,17 +93,26 @@ public: std::string wmsCacheLocation() const; uint64_t wmsCacheSize() const; // bytes +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + void addFrameInfo(globebrowsing::RenderableGlobe* globe, uint32_t nTilesRenderedLocal, + uint32_t nTilesRenderedGlobal, uint32_t nTilesUploaded); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + protected: void internalInitialize(const ghoul::Dictionary&) override; private: - void goToChunk(Camera& camera, const globebrowsing::TileIndex& ti, glm::vec2 uv, - bool doResetCameraDirection); - void goToGeodetic2(Camera& camera, globebrowsing::Geodetic2 geo2, - bool doResetCameraDirection); - void goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3, - bool doResetCameraDirection); - void resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2); + void goToChunk(const globebrowsing::RenderableGlobe& globe, + const globebrowsing::TileIndex& ti, glm::vec2 uv, bool doResetCameraDirection); + + void goToGeodetic2(const globebrowsing::RenderableGlobe& globe, + globebrowsing::Geodetic2 geo2, bool doResetCameraDirection); + + void goToGeodetic3(const globebrowsing::RenderableGlobe& globe, + globebrowsing::Geodetic3 geo3, bool doResetCameraDirection); + + glm::dquat lookDownCameraRotation(const globebrowsing::RenderableGlobe& globe, + glm::dvec3 cameraPositionModelSpace, globebrowsing::Geodetic2 geo2); /** \return a comma separated list of layer group names. @@ -127,6 +139,26 @@ private: std::map _capabilitiesMap; std::multimap _urlList; + +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + struct FrameInfo { + uint64_t iFrame = 0; + uint32_t nTilesRenderedLocal = 0; + uint32_t nTilesRenderedGlobal = 0; + uint32_t nTilesUploaded = 0; + }; + + struct { + std::unordered_map< + globebrowsing::RenderableGlobe*, + std::vector + > frames; + + uint64_t lastSavedFrame = 0; + const uint16_t saveEveryNthFrame = 2048; + } _frameInfo; + properties::BoolProperty _saveInstrumentation; +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION }; } // namespace openspace diff --git a/modules/globebrowsing/globebrowsingmodule_lua.inl b/modules/globebrowsing/globebrowsingmodule_lua.inl index b9928a119f..0c6479b211 100644 --- a/modules/globebrowsing/globebrowsingmodule_lua.inl +++ b/modules/globebrowsing/globebrowsingmodule_lua.inl @@ -128,31 +128,79 @@ int deleteLayer(lua_State* L) { } int goToChunk(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::goToChunk"); + ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::goToChunk"); - const int x = ghoul::lua::value(L, 1); - const int y = ghoul::lua::value(L, 2); - const int level = ghoul::lua::value(L, 3); - lua_pop(L, 3); + const std::string& globeIdentifier = ghoul::lua::value(L, 1); + const int x = ghoul::lua::value(L, 2); + const int y = ghoul::lua::value(L, 3); + const int level = ghoul::lua::value(L, 4); + lua_pop(L, 4); - global::moduleEngine.module()->goToChunk(x, y, level); + SceneGraphNode* n = sceneGraphNode(globeIdentifier); + if (!n) { + return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); + } + + const RenderableGlobe* globe = dynamic_cast(n->renderable()); + if (!globe) { + return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); + } + + global::moduleEngine.module()->goToChunk(*globe, x, y, level); ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int goToGeo(lua_State* L) { - const int nArguments = ghoul::lua::checkArgumentsAndThrow(L, 2, 3, "lua::goToGeo"); + const int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToGeo"); - const double latitude = ghoul::lua::value(L, 1); - const double longitude = ghoul::lua::value(L, 2); + // Check if the user provided a Scene graph node identifier as the first argument. + // lua_isstring returns true for both numbers and strings, so better use !lua_isnumber + const bool providedGlobeIdentifier = !lua_isnumber(L, 1); + const int parameterOffset = providedGlobeIdentifier ? 1 : 0; - if (nArguments == 2) { - global::moduleEngine.module()->goToGeo(latitude, longitude); + const SceneGraphNode* n; + if (providedGlobeIdentifier) { + const std::string& globeIdentifier = ghoul::lua::value(L, 1); + n = sceneGraphNode(globeIdentifier); + if (!n) { + return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); + } } - else if (nArguments == 3) { - const double altitude = ghoul::lua::value(L, 3); + else { + n = global::navigationHandler.orbitalNavigator().anchorNode(); + if (!n) { + return ghoul::lua::luaError(L, "No anchor node is set."); + } + } + + const double latitude = ghoul::lua::value(L, parameterOffset + 1); + const double longitude = ghoul::lua::value(L, parameterOffset + 2); + + const RenderableGlobe* globe = dynamic_cast(n->renderable()); + if (!globe) { + if (providedGlobeIdentifier) { + return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); + } + else { + return ghoul::lua::luaError(L, + "Current anchor node is not a RenderableGlobe. " + "Either change the anchor to a globe, or specify a globe identifier " + "as the first argument" + ); + } + } + + if (nArguments == parameterOffset + 2) { global::moduleEngine.module()->goToGeo( + *globe, latitude, longitude + ); + } + else if (nArguments == parameterOffset + 3) { + const double altitude = ghoul::lua::value(L, parameterOffset + 3); + global::moduleEngine.module()->goToGeo( + *globe, latitude, longitude, altitude @@ -168,19 +216,19 @@ int goToGeo(lua_State* L) { int getGeoPosition(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::getGeoPosition"); - const std::string& name = ghoul::lua::value(L, 1); + const std::string& globeIdentifier = ghoul::lua::value(L, 1); const double latitude = ghoul::lua::value(L, 2); const double longitude = ghoul::lua::value(L, 3); const double altitude = ghoul::lua::value(L, 4); lua_pop(L, 4); - SceneGraphNode* n = sceneGraphNode(name); + SceneGraphNode* n = sceneGraphNode(globeIdentifier); if (!n) { - return ghoul::lua::luaError(L, "Unknown globe name: " + name); + return ghoul::lua::luaError(L, "Unknown globe identifier: " + globeIdentifier); } const RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { - return ghoul::lua::luaError(L, "Name must be a RenderableGlobe"); + return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); } GlobeBrowsingModule& mod = *(global::moduleEngine.module()); diff --git a/modules/globebrowsing/src/dashboarditemglobelocation.cpp b/modules/globebrowsing/src/dashboarditemglobelocation.cpp index 86ab30d9e0..3b6dcbf462 100644 --- a/modules/globebrowsing/src/dashboarditemglobelocation.cpp +++ b/modules/globebrowsing/src/dashboarditemglobelocation.cpp @@ -173,9 +173,16 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) { bool isEast = lon > 0.0; lon = std::abs(lon); - const double altitude = glm::length( + double altitude = glm::length( cameraPositionModelSpace - posHandle.centerToReferenceSurface ); + + if (glm::length(cameraPositionModelSpace) < + glm::length(posHandle.centerToReferenceSurface)) + { + altitude = -altitude; + } + std::pair dist = simplifyDistance(altitude); penPosition.y -= _font->height(); diff --git a/modules/globebrowsing/src/globelabelscomponent.cpp b/modules/globebrowsing/src/globelabelscomponent.cpp index 864b85d6c7..9cea901ce7 100644 --- a/modules/globebrowsing/src/globelabelscomponent.cpp +++ b/modules/globebrowsing/src/globelabelscomponent.cpp @@ -45,11 +45,10 @@ #include namespace { - constexpr const char* KeyLabels = "Labels"; - constexpr const char* KeyLabelsFileName = "FileName"; - constexpr const char* _loggerCat = "GlobeLabels"; + constexpr const char* KeyLabelsFileName = "FileName"; + constexpr const double LabelFadeRangeConst = 1500.0; constexpr const double RangeAngularCoefConst = 0.8; constexpr const float MinTransparencyValueConst = 0.009f; @@ -671,19 +670,10 @@ void GlobeLabelsComponent::renderLabels(const RenderData& data, float distToCamera, float fadeInVariable ) { - constexpr double DIST_EPS = 6000.0; - constexpr double SIN_EPS = 0.001; - glm::vec4 textColor = _labelsColor; textColor.a *= fadeInVariable; - glm::dmat4 invMP = glm::inverse(_globe->modelTransform()); - glm::dmat4 invCombinedView = glm::inverse(data.camera.combinedViewMatrix()); - - glm::dvec4 cameraPosWorld = invCombinedView * glm::dvec4(0.0, 0.0, 0.0, 1.0); - glm::dvec3 cameraPosObj = glm::dvec3(invMP * cameraPosWorld); glm::dvec4 cameraUpVecWorld = glm::dvec4(data.camera.lookUpVectorWorldSpace(), 0.0); - glm::dvec3 cameraLookUpObj = glm::dvec3(invMP * cameraUpVecWorld); glm::dmat4 VP = glm::dmat4(data.camera.sgctInternal.projectionMatrix()) * data.camera.combinedViewMatrix(); @@ -799,7 +789,7 @@ bool GlobeLabelsComponent::isLabelInFrustum(const glm::dmat4& MVMatrix, double bottomDistance = MVMatrix[3][3] + MVMatrix[3][1]; double topDistance = MVMatrix[3][3] - MVMatrix[3][1]; double nearDistance = MVMatrix[3][3] + MVMatrix[3][2]; - double farDistance = MVMatrix[3][3] - MVMatrix[3][2]; + // double farDistance = MVMatrix[3][3] - MVMatrix[3][2]; // Normalize Planes const double invMagLeft = 1.0 / glm::length(leftNormal); @@ -824,7 +814,7 @@ bool GlobeLabelsComponent::isLabelInFrustum(const glm::dmat4& MVMatrix, const double invMagFar = 1.0 / glm::length(farNormal); farNormal *= invMagFar; - farDistance *= invMagFar; + // farDistance *= invMagFar; constexpr const float Radius = 1.0; diff --git a/modules/globebrowsing/src/globetranslation.cpp b/modules/globebrowsing/src/globetranslation.cpp index 6c4a5ea2c9..560994bed4 100644 --- a/modules/globebrowsing/src/globetranslation.cpp +++ b/modules/globebrowsing/src/globetranslation.cpp @@ -58,20 +58,21 @@ namespace { "globe. The default value is 0.0" }; - constexpr openspace::properties::Property::PropertyInfo FixedAltitudeInfo = { - "FixedAltitude", - "Fixed Altitude", - "The altitude in meters of the location on the globe's surface. This value is " - "used if the 'UseFixedAltitude' property is 'true'. The default value is 10000km." + constexpr openspace::properties::Property::PropertyInfo AltitudeInfo = { + "Altitude", + "Altitude", + "The altitude in meters. " + "If the 'UseHeightmap' property is 'true', this is an offset from the actual " + "surface of the globe. If not, this is an offset from the reference ellipsoid." + "The default value is 0.0" }; - constexpr openspace::properties::Property::PropertyInfo UseFixedAltitudeInfo = { - "UseFixedAltitude", - "Use Fixed Altitude", - "If this value is 'true', the altitude specified in 'FixedAltitude' is used for " - "this translation. If it is 'false', the altitude will be computed based on the " - "height information that is available about the globe to which this translation " - "is attached. The default value is 'true'." + constexpr openspace::properties::Property::PropertyInfo UseHeightmapInfo = { + "UseHeightmap", + "Use Heightmap", + "If this value is 'true', the altitude specified in 'Altitude' will be treated " + "as an offset from the heightmap. Otherwise, it will be an offset from the " + "globe's reference ellipsoid. The default value is 'false'." }; } // namespace @@ -81,8 +82,8 @@ documentation::Documentation GlobeTranslation::Documentation() { using namespace openspace::documentation; return { - "Spice Translation", - "space_translation_spicetranslation", + "Globe Translation", + "space_translation_globetranslation", { { "Type", @@ -110,16 +111,16 @@ documentation::Documentation GlobeTranslation::Documentation() { LatitudeInfo.description, }, { - FixedAltitudeInfo.identifier, + AltitudeInfo.identifier, new DoubleVerifier, Optional::Yes, - FixedAltitudeInfo.description + AltitudeInfo.description }, { - UseFixedAltitudeInfo.identifier, + UseHeightmapInfo.identifier, new BoolVerifier, Optional::Yes, - UseFixedAltitudeInfo.description + UseHeightmapInfo.description } } }; @@ -129,8 +130,8 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) : _globe(GlobeInfo) , _longitude(LongitudeInfo, 0.0, -180.0, 180.0) , _latitude(LatitudeInfo, 0.0, -90.0, 90.0) - , _fixedAltitude(FixedAltitudeInfo, 1e8, 0.0, 1e12) - , _useFixedAltitude(UseFixedAltitudeInfo, false) + , _altitude(AltitudeInfo, 0.0, 0.0, 1e12) + , _useHeightmap(UseHeightmapInfo, false) { documentation::testSpecificationAndThrow( Documentation(), @@ -145,11 +146,11 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) if (dictionary.hasKey(LatitudeInfo.identifier)) { _latitude = dictionary.value(LatitudeInfo.identifier); } - if (dictionary.hasKey(FixedAltitudeInfo.identifier)) { - _fixedAltitude = dictionary.value(FixedAltitudeInfo.identifier); + if (dictionary.hasKey(AltitudeInfo.identifier)) { + _altitude = dictionary.value(AltitudeInfo.identifier); } - if (dictionary.hasKey(UseFixedAltitudeInfo.identifier)) { - _useFixedAltitude = dictionary.value(UseFixedAltitudeInfo.identifier); + if (dictionary.hasKey(UseHeightmapInfo.identifier)) { + _useHeightmap = dictionary.value(UseHeightmapInfo.identifier); } _globe.onChange([this]() { @@ -159,8 +160,13 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) _longitude.onChange([this]() { _positionIsDirty = true; }); _latitude.onChange([this]() { _positionIsDirty = true; }); - _fixedAltitude.onChange([this]() { _positionIsDirty = true; }); - _useFixedAltitude.onChange([this]() { _positionIsDirty = true; }); + _altitude.onChange([this]() { _positionIsDirty = true; }); + _useHeightmap.onChange([this]() { _positionIsDirty = true; }); + + addProperty(_longitude); + addProperty(_latitude); + addProperty(_altitude); + addProperty(_useHeightmap); } void GlobeTranslation::fillAttachedNode() { @@ -173,8 +179,10 @@ void GlobeTranslation::fillAttachedNode() { "GlobeTranslation", "Could not set attached node as it does not have a RenderableGlobe" ); - // Reset the globe name to it's previous name - _globe = _attachedNode->identifier(); + if (_attachedNode) { + // Reset the globe name to it's previous name + _globe = _attachedNode->identifier(); + } } } @@ -188,8 +196,8 @@ glm::dvec3 GlobeTranslation::position(const UpdateData&) const { _positionIsDirty = true; } - if (!_useFixedAltitude) { - // If we don't use the fixed altitude, we have to compute the height every frame + if (_useHeightmap) { + // If we use the heightmap, we have to compute the height every frame _positionIsDirty = true; } @@ -197,33 +205,35 @@ glm::dvec3 GlobeTranslation::position(const UpdateData&) const { return _position; } - GlobeBrowsingModule& mod = *(global::moduleEngine.module()); - glm::vec3 pos = mod.cartesianCoordinatesFromGeo( - *_attachedNode, - _latitude, - _longitude, - _fixedAltitude - ); - - if (_useFixedAltitude) { - _position = glm::dvec3(pos); - _positionIsDirty = true; - - return _position; - } - else { - SurfacePositionHandle h = _attachedNode->calculateSurfacePositionHandle(pos); - - pos = mod.cartesianCoordinatesFromGeo( + if (_useHeightmap) { + glm::vec3 groundPos = mod.cartesianCoordinatesFromGeo( *_attachedNode, _latitude, _longitude, - h.heightToSurface + 0.0 ); - _position = glm::dvec3(pos); + SurfacePositionHandle h = + _attachedNode->calculateSurfacePositionHandle(groundPos); + + _position = mod.cartesianCoordinatesFromGeo( + *_attachedNode, + _latitude, + _longitude, + h.heightToSurface + _altitude + ); + return _position; + } + else { + _position = mod.cartesianCoordinatesFromGeo( + *_attachedNode, + _latitude, + _longitude, + _altitude + ); + _positionIsDirty = false; return _position; } } diff --git a/modules/globebrowsing/src/globetranslation.h b/modules/globebrowsing/src/globetranslation.h index 7fbd943b7b..91c0bdf61b 100644 --- a/modules/globebrowsing/src/globetranslation.h +++ b/modules/globebrowsing/src/globetranslation.h @@ -49,8 +49,8 @@ private: properties::StringProperty _globe; properties::DoubleProperty _longitude; properties::DoubleProperty _latitude; - properties::DoubleProperty _fixedAltitude; - properties::BoolProperty _useFixedAltitude; + properties::DoubleProperty _altitude; + properties::BoolProperty _useHeightmap; RenderableGlobe* _attachedNode = nullptr; diff --git a/modules/globebrowsing/src/layer.cpp b/modules/globebrowsing/src/layer.cpp index 52e69b7731..e07f632bbb 100644 --- a/modules/globebrowsing/src/layer.cpp +++ b/modules/globebrowsing/src/layer.cpp @@ -341,9 +341,12 @@ void Layer::onChange(std::function callback) { _onChangeCallback = std::move(callback); } -void Layer::update() { +int Layer::update() { if (_tileProvider) { - tileprovider::update(*_tileProvider); + return tileprovider::update(*_tileProvider); + } + else { + return 0; } } diff --git a/modules/globebrowsing/src/layer.h b/modules/globebrowsing/src/layer.h index 4658468b90..908217611f 100644 --- a/modules/globebrowsing/src/layer.h +++ b/modules/globebrowsing/src/layer.h @@ -64,7 +64,8 @@ public: void onChange(std::function callback); - void update(); + // Return: number of tiles that were updated + int update(); glm::ivec2 tilePixelStartOffset() const; glm::ivec2 tilePixelSizeDifference() const; diff --git a/modules/globebrowsing/src/layergroup.cpp b/modules/globebrowsing/src/layergroup.cpp index f6088e8869..e0aff6f0af 100644 --- a/modules/globebrowsing/src/layergroup.cpp +++ b/modules/globebrowsing/src/layergroup.cpp @@ -91,15 +91,18 @@ void LayerGroup::deinitialize() { } } -void LayerGroup::update() { +int LayerGroup::update() { + int res = 0; _activeLayers.clear(); for (const std::unique_ptr& layer : _layers) { if (layer->enabled()) { - layer->update(); + res += layer->update(); _activeLayers.push_back(layer.get()); } } + + return res; } Layer* LayerGroup::addLayer(const ghoul::Dictionary& layerDict) { diff --git a/modules/globebrowsing/src/layergroup.h b/modules/globebrowsing/src/layergroup.h index 923cef7011..7db9a718de 100644 --- a/modules/globebrowsing/src/layergroup.h +++ b/modules/globebrowsing/src/layergroup.h @@ -48,7 +48,8 @@ struct LayerGroup : public properties::PropertyOwner { void deinitialize(); /// Updates all layers tile providers within this group - void update(); + /// Return: Number of tiles that were updated + int update(); Layer* addLayer(const ghoul::Dictionary& layerDict); void deleteLayer(const std::string& layerName); diff --git a/modules/globebrowsing/src/layermanager.cpp b/modules/globebrowsing/src/layermanager.cpp index 0f442d8bcf..ae677ada58 100644 --- a/modules/globebrowsing/src/layermanager.cpp +++ b/modules/globebrowsing/src/layermanager.cpp @@ -111,10 +111,12 @@ std::array LayerManager::layerGroups( return res; } -void LayerManager::update() { +int LayerManager::update() { + int res = 0; for (std::unique_ptr& layerGroup : _layerGroups) { - layerGroup->update(); + res += layerGroup->update(); } + return res; } void LayerManager::reset(bool includeDisabled) { diff --git a/modules/globebrowsing/src/layermanager.h b/modules/globebrowsing/src/layermanager.h index de7fbb4c62..36de309488 100644 --- a/modules/globebrowsing/src/layermanager.h +++ b/modules/globebrowsing/src/layermanager.h @@ -63,7 +63,8 @@ public: std::array layerGroups() const; - void update(); + // Return: Number of tiles updated + int update(); void reset(bool includeDisabled = false); void onChange(std::function callback); diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 6361670ee6..51c263d9c3 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -47,6 +47,13 @@ #include #include +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION +#include +#include +openspace::GlobeBrowsingModule* _module = nullptr; + +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + namespace { // Global flags to modify the RenderableGlobe constexpr const bool LimitLevelByAvailableData = true; @@ -176,7 +183,7 @@ namespace { }; constexpr openspace::properties::Property::PropertyInfo TargetLodScaleFactorInfo = { - "TargetLodScaleFactorInfo", + "TargetLodScaleFactor", "Target Level of Detail Scale Factor", "" // @TODO Missing documentation }; @@ -595,10 +602,13 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) if (dictionary.hasKeyAndValue(KeyLabels)) { _labelsDictionary = dictionary.value(KeyLabels); } + +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + _module = global::moduleEngine.module(); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION } void RenderableGlobe::initializeGL() { - if (!_labelsDictionary.empty()) { _globeLabelsComponent.initialize(_labelsDictionary, this); addPropertySubOwner(_globeLabelsComponent); @@ -745,7 +755,11 @@ void RenderableGlobe::update(const UpdateData& data) { _layerManager.reset(); _debugProperties.resetTileProviders = false; } +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + _nUploadedTiles = _layerManager.update(); +#else _layerManager.update(); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION if (_nLayersIsDirty) { std::array lgs = @@ -1034,6 +1048,14 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&) { } _localRenderer.program->deactivate(); +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + _module->addFrameInfo( + this, + std::min(localCount, ChunkBufferSize), + std::min(globalCount, ChunkBufferSize), + _nUploadedTiles + ); +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION if (_debugProperties.showChunkBounds || _debugProperties.showChunkAABB) { for (int i = 0; i < std::min(globalCount, ChunkBufferSize); ++i) { diff --git a/modules/globebrowsing/src/renderableglobe.h b/modules/globebrowsing/src/renderableglobe.h index 93022b532c..7886c0d3e2 100644 --- a/modules/globebrowsing/src/renderableglobe.h +++ b/modules/globebrowsing/src/renderableglobe.h @@ -274,6 +274,10 @@ private: // Labels GlobeLabelsComponent _globeLabelsComponent; ghoul::Dictionary _labelsDictionary; + +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION + int _nUploadedTiles = 0; +#endif // OPENSPACE_MODULE_GLOBEBROWSING_INSTRUMENTATION }; } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/src/tileprovider.cpp b/modules/globebrowsing/src/tileprovider.cpp index 0fe168fd78..ad72426685 100644 --- a/modules/globebrowsing/src/tileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider.cpp @@ -162,15 +162,17 @@ void initAsyncTileDataReader(DefaultTileProvider& t, TileTextureInitData initDat ); } -void initTexturesFromLoadedData(DefaultTileProvider& t) { +bool initTexturesFromLoadedData(DefaultTileProvider& t) { if (t.asyncTextureDataProvider) { std::optional tile = t.asyncTextureDataProvider->popFinishedRawTile(); if (tile) { const cache::ProviderTileKey key = { tile->tileIndex, t.uniqueIdentifier }; ghoul_assert(!t.tileCache->exist(key), "Tile must not be existing in cache"); t.tileCache->createTileAndPut(key, std::move(tile.value())); + return true; } } + return false; } @@ -1073,7 +1075,7 @@ TileDepthTransform depthTransform(TileProvider& tp) { -void update(TileProvider& tp) { +int update(TileProvider& tp) { switch (tp.type) { case Type::DefaultTileProvider: { DefaultTileProvider& t = static_cast(tp); @@ -1082,7 +1084,7 @@ void update(TileProvider& tp) { } t.asyncTextureDataProvider->update(); - initTexturesFromLoadedData(t); + bool hasUploaded = initTexturesFromLoadedData(t); if (t.asyncTextureDataProvider->shouldBeDeleted()) { t.asyncTextureDataProvider = nullptr; @@ -1091,6 +1093,9 @@ void update(TileProvider& tp) { tileTextureInitData(t.layerGroupID, t.padTiles, t.tilePixelSize) ); } + if (hasUploaded) { + return 1; + } break; } case Type::SingleImageTileProvider: @@ -1123,13 +1128,16 @@ void update(TileProvider& tp) { if (newCurrent) { t.currentTileProvider = newCurrent; } - update(*t.currentTileProvider); + if (t.currentTileProvider) { + update(*t.currentTileProvider); + } } break; } default: throw ghoul::MissingCaseException(); } + return 0; } diff --git a/modules/globebrowsing/src/tileprovider.h b/modules/globebrowsing/src/tileprovider.h index c367638374..c7e3cd5196 100644 --- a/modules/globebrowsing/src/tileprovider.h +++ b/modules/globebrowsing/src/tileprovider.h @@ -222,8 +222,10 @@ TileDepthTransform depthTransform(TileProvider& tp); /** * This method should be called once per frame. Here, TileProviders * are given the opportunity to update their internal state. + * + * \return The number of tiles that have been updated in this call */ -void update(TileProvider& tp); +int update(TileProvider& tp); /** * Provides a uniform way of all TileProviders to reload or diff --git a/modules/imgui/src/gui.cpp b/modules/imgui/src/gui.cpp index 51088e6abf..0767a812a4 100644 --- a/modules/imgui/src/gui.cpp +++ b/modules/imgui/src/gui.cpp @@ -53,32 +53,69 @@ namespace { constexpr const std::array UniformNames = { "tex", "ortho" }; - void addScreenSpaceRenderableLocal(std::string texturePath) { + void addScreenSpaceRenderableLocal(std::string identifier, std::string texturePath) { if (!FileSys.fileExists(absPath(texturePath))) { LWARNING(fmt::format("Could not find image '{}'", texturePath)); return; } - openspace::global::scriptEngine.queueScript( - fmt::format( + std::string script; + if (identifier.empty()) { + script = fmt::format( "openspace.addScreenSpaceRenderable({{\ Type = 'ScreenSpaceImageLocal',\ TexturePath = openspace.absPath('{}')\ }});", - std::move(texturePath) - ), + texturePath + ); + } + else { + script = fmt::format( + "openspace.addScreenSpaceRenderable({{\ + Type = 'ScreenSpaceImageLocal',\ + TexturePath = openspace.absPath('{}'),\ + Identifier = '{}',\ + Name = '{}'\ + }});", + texturePath, + identifier, + identifier + ); + } + + openspace::global::scriptEngine.queueScript( + script, openspace::scripting::ScriptEngine::RemoteScripting::Yes ); } - void addScreenSpaceRenderableOnline(std::string texturePath) { - openspace::global::scriptEngine.queueScript( - fmt::format( + void addScreenSpaceRenderableOnline(std::string identifier, std::string texturePath) { + std::string script; + if (identifier.empty()) { + script = fmt::format( "openspace.addScreenSpaceRenderable({{\ - Type = 'ScreenSpaceImageOnline', URL = '{}'\ + Type = 'ScreenSpaceImageOnline',\ + URL = '{}'\ }});", - std::move(texturePath) - ), + texturePath + ); + } + else { + script = fmt::format( + "openspace.addScreenSpaceRenderable({{\ + Type = 'ScreenSpaceImageOnline',\ + URL = '{}',\ + Identifier = '{}',\ + Name = '{}'\ + }});", + texturePath, + identifier, + identifier + ); + } + + openspace::global::scriptEngine.queueScript( + script, openspace::scripting::ScriptEngine::RemoteScripting::Yes ); } @@ -616,9 +653,16 @@ void GUI::render() { renderAndUpdatePropertyVisibility(); static const int addImageBufferSize = 256; + static char identifierBuffer[addImageBufferSize]; static char addImageLocalBuffer[addImageBufferSize]; static char addImageOnlineBuffer[addImageBufferSize]; + ImGui::InputText( + "Identifier for Local/Online Images", + identifierBuffer, + addImageBufferSize + ); + bool addImageLocal = ImGui::InputText( "Add Local Image", addImageLocalBuffer, @@ -626,7 +670,10 @@ void GUI::render() { ImGuiInputTextFlags_EnterReturnsTrue ); if (addImageLocal) { - addScreenSpaceRenderableLocal(std::string(addImageLocalBuffer)); + addScreenSpaceRenderableLocal( + std::string(identifierBuffer), + std::string(addImageLocalBuffer) + ); } bool addImageOnline = ImGui::InputText( @@ -637,7 +684,10 @@ void GUI::render() { ); if (addImageOnline) { - addScreenSpaceRenderableOnline(std::string(addImageOnlineBuffer)); + addScreenSpaceRenderableOnline( + std::string(identifierBuffer), + std::string(addImageOnlineBuffer) + ); } bool addDashboard = ImGui::Button("Add New Dashboard"); diff --git a/modules/server/src/topics/luascripttopic.cpp b/modules/server/src/topics/luascripttopic.cpp index f883410764..018159f0ba 100644 --- a/modules/server/src/topics/luascripttopic.cpp +++ b/modules/server/src/topics/luascripttopic.cpp @@ -69,7 +69,7 @@ namespace { return "[" + formatLuaString(it.key()) + "] = " + formatLua(it); } - std::string formatLuaTable(const nlohmann::json& json) { + std::string formatObjectAsLuaTable(const nlohmann::json& json) { std::string output = "{"; auto it = json.begin(); for (size_t i = 0; i < json.size(); ++i, ++it) { @@ -81,9 +81,24 @@ namespace { return output + "}"; } + std::string formatArrayAsLuaTable(const nlohmann::json& json) { + std::string output = "{"; + auto it = json.begin(); + for (size_t i = 0; i < json.size(); ++i, ++it) { + output += formatLua(it); + if (i < json.size() - 1) { + output += ","; + } + } + return output + "}"; + } + std::string formatLua(const nlohmann::json::const_iterator& it) { if (it->is_object()) { - return formatLuaTable(it->get()); + return formatObjectAsLuaTable(it->get()); + } + if (it->is_array()) { + return formatArrayAsLuaTable(it->get()); } if (it->is_number()) { return fmt::format("{:E}", it->get()); diff --git a/modules/server/src/topics/setpropertytopic.cpp b/modules/server/src/topics/setpropertytopic.cpp index 584f8c2fe8..2e40e4d99d 100644 --- a/modules/server/src/topics/setpropertytopic.cpp +++ b/modules/server/src/topics/setpropertytopic.cpp @@ -41,15 +41,29 @@ namespace { std::string escapedLuaString(const std::string& str) { std::string luaString; + for (const char& c : str) { switch (c) { - case '\'': - luaString += "\'"; - break; - default: - luaString += c; + case '\t': + luaString += "\\t"; // Replace tab with \t. + break; + case '"': + luaString += "\\\""; // Replace " with \". + break; + case '\\': + luaString += "\\\\"; // Replace \ with \\. + break; + case '\n': + luaString += "\\\\n"; // Replace newline with \n. + break; + case '\r': + luaString += "\\r"; // Replace carriage return with \r. + break; + default: + luaString += c; } } + return luaString; } diff --git a/modules/server/src/topics/timetopic.cpp b/modules/server/src/topics/timetopic.cpp index 4710d13c4f..60512f4516 100644 --- a/modules/server/src/topics/timetopic.cpp +++ b/modules/server/src/topics/timetopic.cpp @@ -32,7 +32,6 @@ #include namespace { - constexpr const char* _loggerCat = "TimeTopic"; constexpr const char* EventKey = "event"; constexpr const char* SubscribeEvent = "start_subscription"; constexpr const char* UnsubscribeEvent = "stop_subscription"; diff --git a/modules/space/rendering/renderablestars.cpp b/modules/space/rendering/renderablestars.cpp index 891ee0efb8..474e7158b3 100644 --- a/modules/space/rendering/renderablestars.cpp +++ b/modules/space/rendering/renderablestars.cpp @@ -773,7 +773,6 @@ void RenderableStars::renderPSFToTexture() { GLenum blendDestRGB; GLenum blendSrcAlpha; GLenum blendSrcRGB; - GLboolean depthMask; glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRGB); glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha); @@ -927,7 +926,6 @@ void RenderableStars::render(const RenderData& data, RendererTasks&) { glm::dmat4(data.modelTransform.rotation) * glm::dmat4(glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale))); - glm::dmat4 modelViewMatrix = data.camera.combinedViewMatrix() * modelMatrix; glm::dmat4 projectionMatrix = glm::dmat4(data.camera.projectionMatrix()); glm::dmat4 cameraViewProjectionMatrix = projectionMatrix * diff --git a/modules/space/rendering/renderablestars.h b/modules/space/rendering/renderablestars.h index 986fd5682f..272b6b9242 100644 --- a/modules/space/rendering/renderablestars.h +++ b/modules/space/rendering/renderablestars.h @@ -165,7 +165,6 @@ private: GLuint _psfVao = 0; GLuint _psfVbo = 0; GLuint _psfTexture = 0; - GLuint _discTexture = 0; GLuint _convolvedTexture = 0; }; diff --git a/modules/space/translation/horizonstranslation.cpp b/modules/space/translation/horizonstranslation.cpp index e50d284047..80dca66afe 100644 --- a/modules/space/translation/horizonstranslation.cpp +++ b/modules/space/translation/horizonstranslation.cpp @@ -179,7 +179,7 @@ void HorizonsTranslation::readHorizonsTextFile(const std::string& horizonsTextFi ); // Add position to stored timeline. - _timeline.addKeyframe(timeInJ2000, gPos); + _timeline.addKeyframe(timeInJ2000, std::move(gPos)); std::getline(fileStream, line); } diff --git a/modules/sync/CMakeLists.txt b/modules/sync/CMakeLists.txt index 28fde9802a..a263e5498f 100644 --- a/modules/sync/CMakeLists.txt +++ b/modules/sync/CMakeLists.txt @@ -24,8 +24,6 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) -option(OPENSPACE_MODULE_SYNC_USE_LIBTORRENT "Use libtorrent" OFF) - set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/syncmodule.h ${CMAKE_CURRENT_SOURCE_DIR}/syncs/httpsynchronization.h @@ -42,48 +40,4 @@ set(SOURCE_FILES ) source_group("Source Files" FILES ${SOURCE_FILES}) -if (OPENSPACE_MODULE_SYNC_USE_LIBTORRENT) - set(HEADER_FILES - ${HEADER_FILES} - ${CMAKE_CURRENT_SOURCE_DIR}/torrentclient.h - ${CMAKE_CURRENT_SOURCE_DIR}/syncs/torrentsynchronization.h - ) - set(SOURCE_FILES - ${SOURCE_FILES} - ${CMAKE_CURRENT_SOURCE_DIR}/torrentclient.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/syncs/torrentsynchronization.cpp - ) -endif () - - create_new_module("Sync" sync_module ${HEADER_FILES} ${SOURCE_FILES}) - -##### -# Libtorrent -##### - -if (OPENSPACE_MODULE_SYNC_USE_LIBTORRENT) - set(Boost_USE_STATIC_LIBS ON) - set(Boost_USE_MULTITHREADED ON) - set(LIBTORRENT_encryption OFF CACHE BOOL "Use OpenSSL Encryption" FORCE) - set(LIBTORRENT_shared OFF CACHE BOOL "Use Libtorrent as shared library" FORCE) - - include_external_library( - ${sync_module} - torrent-rasterbar - ${CMAKE_CURRENT_SOURCE_DIR}/ext/libtorrent - ) - target_include_directories( - ${sync_module} - SYSTEM PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/ext/libtorrent/include - ) - - target_compile_definitions(openspace-module-sync PUBLIC SYNC_USE_LIBTORRENT) - - mark_as_advanced(LIBTORRENT_build_examples LIBTORRENT_build_tests - LIBTORRENT_deprecated-functions LIBTORRENT_dht LIBTORRENT_encryption - LIBTORRENT_exceptions LIBTORRENT_exceptions LIBTORRENT_libiconv - LIBTORRENT_logging LIBTORRENT_shared LIBTORRENT_static_runtime - ) -endif () # OPENSPACE_MODULE_SYNC_USE_LIBTORRENT \ No newline at end of file diff --git a/modules/sync/ext/libtorrent b/modules/sync/ext/libtorrent deleted file mode 160000 index 22477e7430..0000000000 --- a/modules/sync/ext/libtorrent +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 22477e7430a643fc64e55a669e2ad0e87a67647e diff --git a/modules/sync/syncmodule.cpp b/modules/sync/syncmodule.cpp index 791254a3cd..6f920b85d4 100644 --- a/modules/sync/syncmodule.cpp +++ b/modules/sync/syncmodule.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -87,19 +86,6 @@ void SyncModule::internalInitialize(const ghoul::Dictionary& configuration) { } ); -#ifdef SYNC_USE_LIBTORRENT - fSynchronization->registerClass( - "TorrentSynchronization", - [this](bool, const ghoul::Dictionary& dictionary) { - return new TorrentSynchronization( - dictionary, - _synchronizationRoot, - _torrentClient - ); - } - ); -#endif // SYNC_USE_LIBTORRENT - fSynchronization->registerClass( "UrlSynchronization", [this](bool, const ghoul::Dictionary& dictionary) { @@ -113,17 +99,6 @@ void SyncModule::internalInitialize(const ghoul::Dictionary& configuration) { auto fTask = FactoryManager::ref().factory(); ghoul_assert(fTask, "No task factory existed"); fTask->registerClass("SyncAssetTask"); - -#ifdef SYNC_USE_LIBTORRENT - _torrentClient.initialize(); - global::callback::deinitialize.emplace_back([&]() { _torrentClient.deinitialize(); }); -#endif // SYNC_USE_LIBTORRENT -} - -void SyncModule::internalDeinitialize() { -#ifdef SYNC_USE_LIBTORRENT - _torrentClient.deinitialize(); -#endif // SYNC_USE_LIBTORRENT } std::string SyncModule::synchronizationRoot() const { @@ -140,10 +115,7 @@ std::vector SyncModule::httpSynchronizationRepositories() const { std::vector SyncModule::documentations() const { return { - HttpSynchronization::Documentation(), -#ifdef SYNC_USE_LIBTORRENT - TorrentSynchronization::Documentation() -#endif // SYNC_USE_LIBTORRENT + HttpSynchronization::Documentation() }; } diff --git a/modules/sync/syncmodule.h b/modules/sync/syncmodule.h index eef18e8b72..64cb7e412d 100644 --- a/modules/sync/syncmodule.h +++ b/modules/sync/syncmodule.h @@ -27,10 +27,6 @@ #include -#ifdef SYNC_USE_LIBTORRENT -#include -#endif // SYNC_USE_LIBTORRENT - namespace openspace { class SyncModule : public OpenSpaceModule { @@ -44,20 +40,12 @@ public: void addHttpSynchronizationRepository(std::string repository); std::vector httpSynchronizationRepositories() const; -#ifdef SYNC_USE_LIBTORRENT - TorrentClient& torrentClient(); -#endif // SYNC_USE_LIBTORRENT - std::vector documentations() const override; protected: void internalInitialize(const ghoul::Dictionary& configuration) override; - void internalDeinitialize() override; private: -#ifdef SYNC_USE_LIBTORRENT - TorrentClient _torrentClient; -#endif // SYNC_USE_LIBTORRENT std::vector _synchronizationRepositories; std::string _synchronizationRoot; }; diff --git a/modules/sync/syncs/torrentsynchronization.cpp b/modules/sync/syncs/torrentsynchronization.cpp deleted file mode 100644 index 2f3bfd1485..0000000000 --- a/modules/sync/syncs/torrentsynchronization.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2019 * - * * - * 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* KeyIdentifier = "Identifier"; - constexpr const char* KeyMagnet = "Magnet"; -} // namespace - -namespace openspace { - -documentation::Documentation TorrentSynchronization::Documentation() { - using namespace openspace::documentation; - return { - "TorrentSynchronization", - "torrent_synchronization", - { - { - KeyIdentifier, - new StringVerifier, - Optional::No, - "A unique identifier for this torrent" - }, - { - KeyMagnet, - new StringVerifier, - Optional::No, - "A magnet link identifying the torrent" - } - } - }; -} - -TorrentSynchronization::TorrentSynchronization(const ghoul::Dictionary& dict, - std::string synchronizationRoot, - TorrentClient& torrentClient) - : ResourceSynchronization(dict) - , _synchronizationRoot(std::move(synchronizationRoot)) - , _torrentClient(torrentClient) -{ - documentation::testSpecificationAndThrow( - Documentation(), - dict, - "TorrentSynchronization" - ); - - _identifier = dict.value(KeyIdentifier); - _magnetLink = dict.value(KeyMagnet); -} - -TorrentSynchronization::~TorrentSynchronization() { - cancel(); -} - -std::string TorrentSynchronization::uniformResourceName() const { - const size_t begin = _magnetLink.find("=urn") + 1; - const size_t end = _magnetLink.find('&', begin); - std::string xs = _magnetLink.substr( - begin, - (end == std::string::npos) ? end : (end - begin) - ); - - std::transform( - xs.begin(), - xs.end(), - xs.begin(), - [](char x) { return (x == ':') ? '.' : x; } - ); - return xs; -} - -std::string TorrentSynchronization::directory() { - ghoul::filesystem::Directory d( - _synchronizationRoot + - ghoul::filesystem::FileSystem::PathSeparator + - "torrent" + - ghoul::filesystem::FileSystem::PathSeparator + - _identifier + - ghoul::filesystem::FileSystem::PathSeparator + - uniformResourceName() - ); - - return FileSys.absPath(d); -} - -void TorrentSynchronization::start() { - if (_enabled) { - return; - } - begin(); - - if (hasSyncFile()) { - resolve(); - } - - _enabled = true; - try { - _torrentId = _torrentClient.addMagnetLink( - _magnetLink, - directory(), - [this](TorrentClient::TorrentProgress p) { - updateTorrentProgress(p); - } - ); - } catch (const TorrentError& e) { - LERRORC(name(), e.message); - if (!isResolved()) { - reject(); - } - } -} - -void TorrentSynchronization::cancel() { - if (_enabled) { - _torrentClient.removeTorrent(_torrentId); - _enabled = false; - reset(); - } -} - -void TorrentSynchronization::clear() { - cancel(); - // TODO: Remove all files from directory. -} - -bool TorrentSynchronization::hasSyncFile() { - const std::string& path = directory() + ".ossync"; - return FileSys.fileExists(path); -} - -void TorrentSynchronization::createSyncFile() { - const std::string& directoryName = directory(); - const std::string& filepath = directoryName + ".ossync"; - - FileSys.createDirectory(directoryName, ghoul::filesystem::FileSystem::Recursive::Yes); - - std::ofstream syncFile(filepath, std::ofstream::out); - syncFile << "Synchronized"; - syncFile.close(); -} - -size_t TorrentSynchronization::nSynchronizedBytes() { - std::lock_guard g(_progressMutex); - return _progress.nDownloadedBytes; -} - -size_t TorrentSynchronization::nTotalBytes() { - std::lock_guard g(_progressMutex); - return _progress.nTotalBytes; -} - -bool TorrentSynchronization::nTotalBytesIsKnown() { - std::lock_guard g(_progressMutex); - return _progress.nTotalBytesKnown; -} - -void TorrentSynchronization::updateTorrentProgress( - TorrentClient::TorrentProgress progress) -{ - std::lock_guard g(_progressMutex); - _progress = progress; - if (progress.finished && (state() == State::Syncing)) { - createSyncFile(); - resolve(); - } -} - -} // namespace openspace diff --git a/modules/sync/syncs/torrentsynchronization.h b/modules/sync/syncs/torrentsynchronization.h deleted file mode 100644 index 98f9811f4e..0000000000 --- a/modules/sync/syncs/torrentsynchronization.h +++ /dev/null @@ -1,77 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2019 * - * * - * 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_MODULE_SYNC___TORRENTSYNCHRONIZATION___H__ -#define __OPENSPACE_MODULE_SYNC___TORRENTSYNCHRONIZATION___H__ - -#ifdef SYNC_USE_LIBTORRENT - -#include - -#include - -namespace openspace { - -class TorrentSynchronizationJob; - -class TorrentSynchronization : public ResourceSynchronization { -public: - TorrentSynchronization(const ghoul::Dictionary& dict, std::string synchronizationRoot, - TorrentClient& client); - - virtual ~TorrentSynchronization(); - - std::string directory() override; - void start() override; - void cancel() override; - void clear() override; - - size_t nSynchronizedBytes() override; - size_t nTotalBytes() override; - bool nTotalBytesIsKnown() override; - - static documentation::Documentation Documentation(); - -private: - void updateTorrentProgress(TorrentClient::TorrentProgress p); - std::string uniformResourceName() const; - bool hasSyncFile(); - void createSyncFile(); - - std::atomic_bool _enabled = false; - - TorrentClient::TorrentId _torrentId = 0; - TorrentClient::TorrentProgress _progress; - std::mutex _progressMutex; - std::string _identifier; - std::string _magnetLink; - std::string _synchronizationRoot; - TorrentClient& _torrentClient; -}; - -} // namespace openspace - -#endif // SYNC_USE_LIBTORRENT - -#endif // __OPENSPACE_MODULE_SYNC___TORRENTSYNCHRONIZATION___H__ diff --git a/modules/sync/torrentclient.cpp b/modules/sync/torrentclient.cpp deleted file mode 100644 index e2379f9c67..0000000000 --- a/modules/sync/torrentclient.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2019 * - * * - * 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 - -#ifdef SYNC_USE_LIBTORRENT -#ifdef _MSC_VER -#pragma warning (push) -#pragma warning (disable : 4265) -#pragma warning (disable : 4996) -#endif // _MSC_VER - -#include -#include -#include -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning (pop) -#endif // _MSC_VER - - -namespace { - constexpr const char* _loggerCat = "TorrentClient"; - constexpr const std::chrono::milliseconds PollInterval(1000); -} // namespace - -#endif // SYNC_USE_LIBTORRENT - -namespace openspace { - -TorrentError::TorrentError(std::string msg) - : RuntimeError(std::move(msg), "TorrentClient") -{} - -void TorrentClient::initialize() { -#ifdef SYNC_USE_LIBTORRENT - libtorrent::settings_pack settings; - settings.set_str( - libtorrent::settings_pack::user_agent, - "OpenSpace/" + std::string(OPENSPACE_VERSION_NUMBER) - ); - - settings.set_str( - libtorrent::settings_pack::listen_interfaces, - "0.0.0.0:6881,0.0.0.0:20280,0.0.0.0:20285,0.0.0.0:20290" - ); - settings.set_bool(libtorrent::settings_pack::allow_multiple_connections_per_ip, true); - settings.set_bool(libtorrent::settings_pack::enable_upnp, true); - //settings.set_bool(libtorrent::settings_pack::ignore_limits_on_local_network, true); - settings.set_int(libtorrent::settings_pack::connection_speed, 20); - settings.set_int(libtorrent::settings_pack::active_downloads, -1); - settings.set_int(libtorrent::settings_pack::active_seeds, -1); - settings.set_int(libtorrent::settings_pack::active_limit, 30); - - settings.set_str( - libtorrent::settings_pack::dht_bootstrap_nodes, - "router.utorrent.com,dht.transmissionbt.com,router.bittorrent.com,\ -router.bitcomet.com" - ); - settings.set_int(libtorrent::settings_pack::dht_announce_interval, 15); - - _session.apply_settings(settings); - - libtorrent::error_code ec; - - _isInitialized = true; - _isActive = true; - - _torrentThread = std::thread([this]() { - while (_isActive) { - pollAlerts(); - std::unique_lock lock(_abortMutex); - _abortNotifier.wait_for(lock, PollInterval); - } - }); -#endif // SYNC_USE_LIBTORRENT -} - -void TorrentClient::deinitialize() { -#ifdef SYNC_USE_LIBTORRENT - if (!_isActive) { - return; - } - - _isActive = false; - _abortNotifier.notify_all(); - if (_torrentThread.joinable()) { - _torrentThread.join(); - } - - const std::vector& handles = _session.get_torrents(); - for (const lt::torrent_handle& h : handles) { - _session.remove_torrent(h); - } - _torrents.clear(); - - _session.abort(); - _isInitialized = false; -#endif // SYNC_USE_LIBTORRENT -} - -void TorrentClient::pollAlerts() { -#ifdef SYNC_USE_LIBTORRENT - // Libtorrent does not seem to reliably generate alerts for all added torrents. - // To make sure that the program does not keep waiting for already finished - // downsloads, we go through the whole list of torrents when polling. - // However, in theory, the commented code below should be more efficient: - /* - std::vector alerts; - { - std::lock_guard guard(_mutex); - _session->pop_alerts(&alerts); - } - for (lt::alert* a : alerts) { - if (const lt::torrent_alert* alert = - dynamic_cast(a)) - { - notify(alert->handle.id()); - } - } - */ - std::vector handles; - { - std::lock_guard guard(_mutex); - handles = _session.get_torrents(); - } - for (const lt::torrent_handle& h : handles) { - notify(h.id()); - } -#endif // SYNC_USE_LIBTORRENT -} - -TorrentClient::TorrentId TorrentClient::addTorrentFile( - [[ maybe_unused ]] const std::string& torrentFile, - [[maybe_unused]] const std::string& destination, - [[maybe_unused]] TorrentProgressCallback cb) -{ -#ifdef SYNC_USE_LIBTORRENT - std::lock_guard guard(_mutex); - - if (!_isInitialized) { - LERROR("Torrent session not initialized when adding torrent"); - return -1; - } - - libtorrent::error_code ec; - libtorrent::add_torrent_params p; - p.save_path = destination; - p.ti = std::make_shared(torrentFile, ec); - if (ec) { - LERROR(fmt::format("{}: {}", torrentFile, ec.message())); - } - const libtorrent::torrent_handle h = _session.add_torrent(p, ec); - if (ec) { - LERROR(fmt::format("{}: {}", torrentFile, ec.message())); - } - - TorrentId id = h.id(); - _torrents.emplace(id, Torrent{ id, h, std::move(cb) }); - return id; -#else // SYNC_USE_LIBTORRENT - throw TorrentError("SyncModule is compiled without libtorrent support"); -#endif // SYNC_USE_LIBTORRENT -} - -TorrentClient::TorrentId TorrentClient::addMagnetLink( - [[maybe_unused]] const std::string& magnetLink, - [[maybe_unused]] const std::string& destination, - [[maybe_unused]] TorrentProgressCallback cb) -{ -#ifdef SYNC_USE_LIBTORRENT - std::lock_guard guard(_mutex); - - // TODO: register callback! - if (!_isInitialized) { - LERROR("Torrent session not initialized when adding torrent"); - return -1; - } - libtorrent::error_code ec; - libtorrent::add_torrent_params p = libtorrent::parse_magnet_uri(magnetLink, ec); - if (ec) { - LERROR(fmt::format("{}: {}", magnetLink, ec.message())); - } - p.save_path = destination; - p.storage_mode = libtorrent::storage_mode_allocate; - const libtorrent::torrent_handle h = _session.add_torrent(p, ec); - if (ec) { - LERROR(fmt::format("{}: {}", magnetLink, ec.message())); - } - - TorrentId id = h.id(); - _torrents.emplace(id, Torrent{ id, h, std::move(cb) }); - return id; -#else // SYNC_USE_LIBTORRENT - throw TorrentError("SyncModule is compiled without libtorrent support"); -#endif // SYNC_USE_LIBTORRENT -} - -void TorrentClient::removeTorrent([[maybe_unused]] TorrentId id) { -#ifdef SYNC_USE_LIBTORRENT - std::lock_guard guard(_mutex); - - const auto it = _torrents.find(id); - if (it == _torrents.end()) { - return; - } - - const libtorrent::torrent_handle h = it->second.handle; - _session.remove_torrent(h); - - _torrents.erase(it); -#endif // SYNC_USE_LIBTORRENT -} - -void TorrentClient::notify([[maybe_unused]] TorrentId id) { -#ifdef SYNC_USE_LIBTORRENT - TorrentProgressCallback callback; - TorrentProgress progress; - - { - std::lock_guard guard(_mutex); - - const auto it = _torrents.find(id); - if (it == _torrents.end()) { - return; - } - - const libtorrent::torrent_handle h = it->second.handle; - const libtorrent::torrent_status status = h.status(); - - progress.finished = status.is_finished; - progress.nTotalBytesKnown = status.total_wanted > 0; - progress.nTotalBytes = status.total_wanted; - progress.nDownloadedBytes = status.total_wanted_done; - - callback = it->second.callback; - } - - callback(progress); -#endif // SYNC_USE_LIBTORRENT -} - -} // namespace openspace diff --git a/modules/sync/torrentclient.h b/modules/sync/torrentclient.h deleted file mode 100644 index e633e24fdf..0000000000 --- a/modules/sync/torrentclient.h +++ /dev/null @@ -1,125 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2019 * - * * - * 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_MODULE_SYNC___TORRENTCLIENT___H__ -#define __OPENSPACE_MODULE_SYNC___TORRENTCLIENT___H__ - -#ifdef SYNC_USE_LIBTORRENT - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef SYNC_USE_LIBTORRENT -#ifdef _MSC_VER -#pragma warning (push) -#pragma warning (disable : 4265) -#pragma warning (disable : 4996) -#endif // _MSC_VER - -// libtorrent defines a class with the name 'defer', which messes with out #define of the -// defer macro in ghoul/misc/defer.h -#undef defer - -#include -#include - -#ifdef _MSC_VER -#pragma warning (pop) -#endif // _MSC_VER - - -#else // SYNC_USE_LIBTORRENT -// Dummy definition to make TorrentClient compile, these is not actually used if -// SYNC_USE_LIBTORRENT is FALSE -namespace libtorrent { - using torrent_handle = void*; - using session = void*; -} // namespace libtorrent - -#endif // SYNC_USE_LIBTORRENT - -namespace openspace { - -struct TorrentError : public ghoul::RuntimeError { - explicit TorrentError(std::string msg); -}; - -class TorrentClient { -public: - struct TorrentProgress { - bool finished = false; - bool nTotalBytesKnown = false; - size_t nTotalBytes = 0; - size_t nDownloadedBytes = 0; - }; - - using TorrentProgressCallback = std::function; - using TorrentId = int32_t; - - void initialize(); - void deinitialize(); - - TorrentId addTorrentFile(const std::string& torrentFile, - const std::string& destination, TorrentProgressCallback cb); - - TorrentId addMagnetLink(const std::string& magnetLink, const std::string& destination, - TorrentProgressCallback cb); - - void removeTorrent(TorrentId id); - -private: - struct Torrent { - TorrentId id; - libtorrent::torrent_handle handle; - TorrentProgressCallback callback; - }; - - void notify(TorrentId id); - void pollAlerts(); - -#ifdef SYNC_USE_LIBTORRENT - libtorrent::session _session; - bool _isInitialized = false; - std::atomic_bool _isActive = false; -#endif // SYNC_USE_LIBTORRENT - - std::thread _torrentThread; - std::condition_variable _abortNotifier; - std::mutex _abortMutex; - std::mutex _mutex; - - std::unordered_map _torrents; -}; - -} // namespace openspace - -#endif // SYNC_USE_LIBTORRENT - -#endif // __OPENSPACE_MODULE_SYNC___TORRENTCLIENT___H__ diff --git a/modules/volume/rendering/renderabletimevaryingvolume.cpp b/modules/volume/rendering/renderabletimevaryingvolume.cpp index ffe7bd5034..d6a0ae9963 100644 --- a/modules/volume/rendering/renderabletimevaryingvolume.cpp +++ b/modules/volume/rendering/renderabletimevaryingvolume.cpp @@ -426,7 +426,7 @@ RenderableTimeVaryingVolume::Timestep* RenderableTimeVaryingVolume::timestepFrom void RenderableTimeVaryingVolume::jumpToTimestep(int target) { Timestep* t = timestepFromIndex(target); if (t) { - global::timeManager.setTimeNextFrame(t->metadata.time); + global::timeManager.setTimeNextFrame(Time(t->metadata.time)); } } diff --git a/modules/volume/tasks/generaterawvolumetask.cpp b/modules/volume/tasks/generaterawvolumetask.cpp index ea64003e33..e5942215ff 100644 --- a/modules/volume/tasks/generaterawvolumetask.cpp +++ b/modules/volume/tasks/generaterawvolumetask.cpp @@ -50,9 +50,6 @@ namespace { constexpr const char* KeyValueFunction = "ValueFunction"; constexpr const char* KeyLowerDomainBound = "LowerDomainBound"; constexpr const char* KeyUpperDomainBound = "UpperDomainBound"; - - constexpr const char* KeyMinValue = "MinValue"; - constexpr const char* KeyMaxValue = "MaxValue"; } // namespace namespace openspace { diff --git a/modules/volume/transferfunctionhandler.cpp b/modules/volume/transferfunctionhandler.cpp index 1bee321f4a..e3d01f1e8d 100644 --- a/modules/volume/transferfunctionhandler.cpp +++ b/modules/volume/transferfunctionhandler.cpp @@ -35,12 +35,6 @@ namespace { "All the envelopes used in the transfer function" }; - constexpr openspace::properties::Property::PropertyInfo HistogramInfo = { - "Histogram", - "Histogram", - "All the data" - }; - constexpr openspace::properties::Property::PropertyInfo DataUnitInfo = { "DataUnit", "DataUnit", diff --git a/modules/webbrowser/include/eventhandler.h b/modules/webbrowser/include/eventhandler.h index 1596a02cb0..3ef6bdce06 100644 --- a/modules/webbrowser/include/eventhandler.h +++ b/modules/webbrowser/include/eventhandler.h @@ -57,9 +57,9 @@ class BrowserInstance; class EventHandler { public: void initialize(); - void setBrowser(const CefRefPtr& browser); void setBrowserInstance(BrowserInstance* browserInstance); - void detachBrowser(); + void resetBrowserInstance(); + void touchPressCallback(const double x, const double y); void touchReleaseCallback(const double x, const double y); bool hasContentCallback(const double, const double); diff --git a/modules/webbrowser/include/screenspacebrowser.h b/modules/webbrowser/include/screenspacebrowser.h index 41b4a2eb0b..be83f58c71 100644 --- a/modules/webbrowser/include/screenspacebrowser.h +++ b/modules/webbrowser/include/screenspacebrowser.h @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef _MSC_VER #pragma warning (push) @@ -62,9 +63,11 @@ class WebKeyboardHandler; class ScreenSpaceBrowser : public ScreenSpaceRenderable { public: ScreenSpaceBrowser(const ghoul::Dictionary& dictionary); + virtual ~ScreenSpaceBrowser() = default; + + bool initializeGL() override; + bool deinitializeGL() override; - bool initialize() override; - bool deinitialize() override; void render() override; void update() override; bool isReady() const override; @@ -72,14 +75,18 @@ public: private: class ScreenSpaceRenderHandler : public WebRenderHandler { public: - void draw(); - void render(); + void draw() override; + void render() override; void setTexture(GLuint t); }; + void bindTexture() override; + properties::StringProperty _url; properties::Vec2Property _dimensions; + properties::TriggerProperty _reload; + CefRefPtr _renderHandler; CefRefPtr _keyboardHandler; std::unique_ptr _browserInstance; diff --git a/modules/webbrowser/src/eventhandler.cpp b/modules/webbrowser/src/eventhandler.cpp index 8cd3c96b3f..1231178231 100644 --- a/modules/webbrowser/src/eventhandler.cpp +++ b/modules/webbrowser/src/eventhandler.cpp @@ -361,7 +361,7 @@ void EventHandler::setBrowserInstance(BrowserInstance* browserInstance) { _browserInstance = browserInstance; } -void EventHandler::detachBrowser() { +void EventHandler::resetBrowserInstance() { _browserInstance = nullptr; } diff --git a/modules/webbrowser/src/screenspacebrowser.cpp b/modules/webbrowser/src/screenspacebrowser.cpp index 21c4e622bf..1c69bb0b4c 100644 --- a/modules/webbrowser/src/screenspacebrowser.cpp +++ b/modules/webbrowser/src/screenspacebrowser.cpp @@ -35,7 +35,6 @@ namespace { constexpr const char* KeyIdentifier = "Indentifier"; - constexpr const char* KeyUrl = "URL"; constexpr const char* _loggerCat = "ScreenSpaceBrowser"; const openspace::properties::Property::PropertyInfo DimensionsInfo = { @@ -44,11 +43,17 @@ namespace { "Set the dimensions of the web browser windows." }; const openspace::properties::Property::PropertyInfo UrlInfo = { + "Url", "URL", - "url", "The URL to load" }; + const openspace::properties::Property::PropertyInfo ReloadInfo = { + "Reload", + "Reload", + "Reload the web browser" + }; + } // namespace namespace openspace { @@ -65,6 +70,7 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary &dictionary) : ScreenSpaceRenderable(dictionary) , _url(UrlInfo) , _dimensions(DimensionsInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(3000.f)) + , _reload(ReloadInfo) { if (dictionary.hasKey(KeyIdentifier)) { setIdentifier(dictionary.value(KeyIdentifier)); @@ -74,17 +80,13 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary &dictionary) ++id; } - if (dictionary.hasKeyAndValue(KeyUrl)) { - _url = dictionary.value(KeyUrl); + if (dictionary.hasKeyAndValue(UrlInfo.identifier)) { + _url = dictionary.value(UrlInfo.identifier); } glm::vec2 windowDimensions = global::windowDelegate.currentSubwindowSize(); _dimensions = windowDimensions; - _texture = std::make_unique( - glm::uvec3(windowDimensions, 1.0f) - ); - _renderHandler = new ScreenSpaceRenderHandler(); _keyboardHandler = new WebKeyboardHandler(); _browserInstance = std::make_unique( @@ -94,9 +96,11 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary &dictionary) _url.onChange([this]() { _isUrlDirty = true; }); _dimensions.onChange([this]() { _isDimensionsDirty = true; }); + _reload.onChange([this]() { _browserInstance->reloadBrowser(); }); addProperty(_url); addProperty(_dimensions); + addProperty(_reload); WebBrowserModule* webBrowser = global::moduleEngine.module(); if (webBrowser) { @@ -104,17 +108,24 @@ ScreenSpaceBrowser::ScreenSpaceBrowser(const ghoul::Dictionary &dictionary) } } -bool ScreenSpaceBrowser::initialize() { - _originalViewportSize = global::windowDelegate.currentWindowSize(); +bool ScreenSpaceBrowser::initializeGL() { + _texture = std::make_unique( + glm::uvec3(_dimensions.value(), 1.0f) + ); + _renderHandler->setTexture(*_texture); createShaders(); + _browserInstance->initialize(); _browserInstance->loadUrl(_url); return isReady(); } -bool ScreenSpaceBrowser::deinitialize() { +bool ScreenSpaceBrowser::deinitializeGL() { + _renderHandler->setTexture(0); + _texture = nullptr; + std::string urlString; _url.getStringValue(urlString); LDEBUG(fmt::format("Deinitializing ScreenSpaceBrowser: {}", urlString)); @@ -125,11 +136,12 @@ bool ScreenSpaceBrowser::deinitialize() { if (webBrowser) { webBrowser->removeBrowser(_browserInstance.get()); _browserInstance.reset(); - return true; + } + else { + LWARNING("Could not find WebBrowserModule"); } - LWARNING("Could not find WebBrowserModule"); - return false; + return ScreenSpaceRenderable::deinitializeGL(); } void ScreenSpaceBrowser::render() { @@ -146,6 +158,8 @@ void ScreenSpaceBrowser::render() { } void ScreenSpaceBrowser::update() { + _objectSize = _texture->dimensions(); + if (_isUrlDirty) { _browserInstance->loadUrl(_url); _isUrlDirty = false; @@ -153,7 +167,6 @@ void ScreenSpaceBrowser::update() { if (_isDimensionsDirty) { _browserInstance->reshape(_dimensions.value()); - _originalViewportSize = _dimensions.value(); _isDimensionsDirty = false; } } @@ -162,4 +175,8 @@ bool ScreenSpaceBrowser::isReady() const { return _shader && _texture; } +void ScreenSpaceBrowser::bindTexture() { + _texture->bind(); +} + } // namespace openspace diff --git a/modules/webbrowser/src/webbrowserapp.cpp b/modules/webbrowser/src/webbrowserapp.cpp index 6ccfaefaf5..dc49bd8fa9 100644 --- a/modules/webbrowser/src/webbrowserapp.cpp +++ b/modules/webbrowser/src/webbrowserapp.cpp @@ -41,10 +41,11 @@ void WebBrowserApp::OnContextCreated(CefRefPtr, CefRefPtr, } void WebBrowserApp::OnBeforeCommandLineProcessing(const CefString&, - CefRefPtr) + CefRefPtr commandLine) { // command_line->AppendSwitch("disable-gpu"); // command_line->AppendSwitch("disable-gpu-compositing"); + commandLine->AppendSwitchWithValue("autoplay-policy", "no-user-gesture-required"); } } // namespace openspace diff --git a/modules/webbrowser/src/webrenderhandler.cpp b/modules/webbrowser/src/webrenderhandler.cpp index 555e88d721..204dea11c5 100644 --- a/modules/webbrowser/src/webrenderhandler.cpp +++ b/modules/webbrowser/src/webrenderhandler.cpp @@ -78,11 +78,13 @@ void WebRenderHandler::OnPaint(CefRefPtr, CefRenderHandler::PaintEle // Copy the updated rectangle line by line. for (int y = lowerUpdatingRectBound.y; y < upperUpdatingRectBound.y; ++y) { int lineOffset = y * w + lowerUpdatingRectBound.x; + // Chromium stores image upside down compared to OpenGL, so we flip it: + int invLineOffset = (h - y - 1) * w + lowerUpdatingRectBound.x; int rectWidth = upperUpdatingRectBound.x - lowerUpdatingRectBound.x; std::copy( reinterpret_cast(buffer) + lineOffset, reinterpret_cast(buffer) + lineOffset + rectWidth, - _browserBuffer.data() + lineOffset + _browserBuffer.data() + invLineOffset ); } @@ -123,14 +125,15 @@ void WebRenderHandler::updateTexture() { GL_TEXTURE_2D, 0, _lowerDirtyRectBound.x, - _lowerDirtyRectBound.y, + _browserBufferSize.y - _upperDirtyRectBound.y, _upperDirtyRectBound.x - _lowerDirtyRectBound.x, _upperDirtyRectBound.y - _lowerDirtyRectBound.y, GL_BGRA_EXT, GL_UNSIGNED_BYTE, reinterpret_cast( _browserBuffer.data() + - _lowerDirtyRectBound.y * _browserBufferSize.x + _lowerDirtyRectBound.x + (_browserBufferSize.y - _upperDirtyRectBound.y) * + _browserBufferSize.x + _lowerDirtyRectBound.x ) ); @@ -148,7 +151,7 @@ bool WebRenderHandler::hasContent(int x, int y) { if (_browserBuffer.empty()) { return false; } - int index = x + (_browserBufferSize.x * y); + int index = x + _browserBufferSize.x * (_browserBufferSize.y - y - 1); index = glm::clamp(index, 0, static_cast(_browserBuffer.size() - 1)); return _browserBuffer[index].a; } diff --git a/modules/webbrowser/webbrowsermodule.cpp b/modules/webbrowser/webbrowsermodule.cpp index c9181fa28c..bf11e5eb34 100644 --- a/modules/webbrowser/webbrowsermodule.cpp +++ b/modules/webbrowser/webbrowsermodule.cpp @@ -98,7 +98,7 @@ void WebBrowserModule::internalDeinitialize() { return; } - _eventHandler.detachBrowser(); + _eventHandler.resetBrowserInstance(); bool forceBrowserShutdown = true; for (BrowserInstance* browser : _browsers) { diff --git a/modules/webgui/webguimodule.cpp b/modules/webgui/webguimodule.cpp index 47f9ea7672..41a7f4c49f 100644 --- a/modules/webgui/webguimodule.cpp +++ b/modules/webgui/webguimodule.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -67,11 +68,34 @@ namespace { }; constexpr openspace::properties::Property::PropertyInfo - WebDirectoryInfo = + DirectoriesInfo = { - "WebDirectory", - "Web Directory", - "Directory from which to to serve static content", + "Directories", + "Directories", + "Directories from which to to serve static content, as a string list " + "with entries expressed as pairs, where every odd is the endpoint name and every " + "even is the directory.", + }; + + constexpr openspace::properties::Property::PropertyInfo + DefaultEndpointInfo = + { + "DefaultEndpoint", + "Default Endpoint", + "The 'default' endpoint. " + "The server will redirect http requests from / to /", + }; + + + constexpr openspace::properties::Property::PropertyInfo + ServedDirectoriesInfo = + { + "ServedDirectories", + "ServedDirectories", + "Directories that are currently served. This value is set by the server process, " + "as a verification of the actually served directories. For example, an onChange " + "callback can be registered to this, to reload browsers when the server is ready." + "Manual changes to this property have no effect." }; constexpr const char* DefaultAddress = "localhost"; @@ -82,16 +106,20 @@ namespace openspace { WebGuiModule::WebGuiModule() : OpenSpaceModule(WebGuiModule::Name) - , _enabled(ServerProcessEnabledInfo, false) + , _enabled(ServerProcessEnabledInfo, true) , _entryPoint(ServerProcessEntryPointInfo) - , _webDirectory(WebDirectoryInfo) + , _directories(DirectoriesInfo) + , _servedDirectories(ServedDirectoriesInfo) + , _defaultEndpoint(DefaultEndpointInfo) , _port(PortInfo, DefaultPort) , _address(AddressInfo, DefaultAddress) , _webSocketInterface(WebSocketInterfaceInfo, "") { addProperty(_enabled); addProperty(_entryPoint); - addProperty(_webDirectory); + addProperty(_directories); + addProperty(_servedDirectories); + addProperty(_defaultEndpoint); addProperty(_address); addProperty(_port); } @@ -104,6 +132,30 @@ std::string WebGuiModule::address() const { return _address; } +WebGuiModule::CallbackHandle WebGuiModule::addEndpointChangeCallback(EndpointCallback cb) +{ + CallbackHandle handle = _nextCallbackHandle++; + _endpointChangeCallbacks.push_back({ handle, std::move(cb) }); + return handle; +} + +void WebGuiModule::removeEndpointChangeCallback(CallbackHandle handle) { + const auto it = std::find_if( + _endpointChangeCallbacks.begin(), + _endpointChangeCallbacks.end(), + [handle](const std::pair& cb) { + return cb.first == handle; + } + ); + + ghoul_assert( + it != _endpointChangeCallbacks.end(), + "handle must be a valid callback handle" + ); + + _endpointChangeCallbacks.erase(it); +} + void WebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) { if (configuration.hasValue(PortInfo.identifier)) { _port = configuration.value(PortInfo.identifier); @@ -119,7 +171,7 @@ void WebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) { } auto startOrStop = [this]() { - if (_enabled) { + if (_enabled && !_entryPoint.value().empty()) { startProcess(); } else { stopProcess(); @@ -135,12 +187,46 @@ void WebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) { _enabled.onChange(startOrStop); _entryPoint.onChange(restartIfEnabled); - _webDirectory.onChange(restartIfEnabled); + _directories.onChange(restartIfEnabled); + _defaultEndpoint.onChange(restartIfEnabled); + _servedDirectories.onChange([this]() { + std::unordered_map newEndpoints; + std::vector list = _servedDirectories.value(); + for (int i = 0; i < list.size() - 1; i += 2) { + newEndpoints[list[i]] = newEndpoints[list[i + 1]]; + } + for (const std::pair& e : _endpoints) { + if (newEndpoints.find(e.first) == newEndpoints.end()) { + // This endpoint existed before but does not exist anymore. + notifyEndpointListeners(e.first, false); + } + } + for (const std::pair& e : newEndpoints) { + if (_endpoints.find(e.first) == _endpoints.end() || + newEndpoints[e.first] != e.second) + { + // This endpoint exists now but did not exist before, + // or the directory has changed. + notifyEndpointListeners(e.first, true); + } + } + _endpoints = newEndpoints; + }); _port.onChange(restartIfEnabled); startOrStop(); } +void WebGuiModule::notifyEndpointListeners(const std::string& endpoint, bool exists) { + using K = CallbackHandle; + using V = EndpointCallback; + for (const std::pair& it : _endpointChangeCallbacks) { + it.second(endpoint, exists); + } +} + void WebGuiModule::startProcess() { + _endpoints.clear(); + ServerModule* serverModule = global::moduleEngine.module(); const ServerInterface* serverInterface = serverModule->serverInterfaceByIdentifier(_webSocketInterface); @@ -157,25 +243,55 @@ void WebGuiModule::startProcess() { const std::string nodePath = absPath("${MODULE_WEBGUI}/ext/nodejs/node"); #endif + std::string formattedDirectories = "["; + + std::vector directories = _directories.value(); + bool first = true; + + for (const std::string& str : directories) { + if (!first) { + formattedDirectories += ","; + } + first = false; + + // Escape twice: First json, and then bash (which needs same escape sequences) + formattedDirectories += "\\\"" + escapedJson(escapedJson(str)) + "\\\""; + } + formattedDirectories += "]"; + + const std::string defaultEndpoint = _defaultEndpoint.value().empty() ? + "" : + " --redirect \"" + _defaultEndpoint.value() + "\""; + const std::string command = "\"" + nodePath + "\" " + "\"" + absPath(_entryPoint.value()) + "\"" + - " --directory \"" + absPath(_webDirectory.value()) + "\"" + + " --directories \"" + formattedDirectories + "\"" + + defaultEndpoint + " --http-port \"" + std::to_string(_port.value()) + "\" " + " --ws-address \"" + _address.value() + "\"" + - " --ws-port \"" + std::to_string(webSocketPort) + "\"" + + " --ws-port " + std::to_string(webSocketPort) + " --auto-close --local"; _process = std::make_unique( command, - _webDirectory.value(), + absPath("${BIN}"), [](const char* data, size_t n) { const std::string str(data, n); LDEBUG(fmt::format("Web GUI server output: {}", str)); + }, + [](const char* data, size_t n) { + const std::string str(data, n); + LERROR(fmt::format("Web GUI server error: {}", str)); } ); } void WebGuiModule::stopProcess() { + for (const auto& e : _endpoints) { + notifyEndpointListeners(e.first, false); + } + _endpoints.clear(); + if (_process) { _process->kill(); } diff --git a/modules/webgui/webguimodule.h b/modules/webgui/webguimodule.h index 1f721b0193..7419d1b44e 100644 --- a/modules/webgui/webguimodule.h +++ b/modules/webgui/webguimodule.h @@ -28,19 +28,27 @@ #include #include +#include #include #include #include #include +#include +#include namespace openspace { class WebGuiModule : public OpenSpaceModule { public: + using CallbackHandle = int; + using EndpointCallback = std::function; + static constexpr const char* Name = "WebGui"; WebGuiModule(); int port() const; std::string address() const; + CallbackHandle addEndpointChangeCallback(EndpointCallback cb); + void removeEndpointChangeCallback(CallbackHandle); protected: void internalInitialize(const ghoul::Dictionary&) override; @@ -48,15 +56,23 @@ protected: private: void startProcess(); void stopProcess(); + void notifyEndpointListeners(const std::string& endpoint, bool exists); std::unique_ptr _process; properties::BoolProperty _enabled; properties::StringProperty _entryPoint; - properties::StringProperty _webDirectory; + properties::StringListProperty _directories; + properties::StringListProperty _servedDirectories; + properties::StringProperty _defaultEndpoint; + + std::unordered_map _endpoints; properties::IntProperty _port; properties::StringProperty _address; properties::StringProperty _webSocketInterface; + + std::vector> _endpointChangeCallbacks; + int _nextCallbackHandle = 0; }; } // namespace openspace diff --git a/recordings/apollo8 b/recordings/apollo8 deleted file mode 100644 index c9cafbdcaa..0000000000 Binary files a/recordings/apollo8 and /dev/null differ diff --git a/src/documentation/core_registration.cpp b/src/documentation/core_registration.cpp index 3d7e026b94..1d8de7effb 100644 --- a/src/documentation/core_registration.cpp +++ b/src/documentation/core_registration.cpp @@ -58,6 +58,9 @@ namespace openspace { void registerCoreClasses(documentation::DocumentationEngine& engine) { engine.addDocumentation(LogFactoryDocumentation()); engine.addDocumentation(Mission::Documentation()); + engine.addDocumentation( + interaction::NavigationHandler::NavigationState::Documentation() + ); engine.addDocumentation(Renderable::Documentation()); engine.addDocumentation(Rotation::Documentation()); engine.addDocumentation(Scale::Documentation()); diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 52a268ca12..4bebd18ff7 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -811,7 +811,6 @@ void OpenSpaceEngine::deinitialize() { ghoul::logging::LogManager::deinitialize(); - ghoul::deinitialize(); LTRACE("deinitialize(end)"); @@ -1013,8 +1012,6 @@ void OpenSpaceEngine::preSynchronization() { } global::renderEngine.updateScene(); - //_navigationHandler->updateCamera(dt); - if (_scene) { Camera* camera = _scene->camera(); diff --git a/src/interaction/navigationhandler.cpp b/src/interaction/navigationhandler.cpp index c9b765a545..f4f0c21dc9 100644 --- a/src/interaction/navigationhandler.cpp +++ b/src/interaction/navigationhandler.cpp @@ -27,14 +27,17 @@ #include #include #include -#include -#include -#include #include +#include +#include #include +#include +#include #include #include #include +#include +#include #include namespace { @@ -43,7 +46,11 @@ namespace { constexpr const char* KeyAnchor = "Anchor"; constexpr const char* KeyAim = "Aim"; constexpr const char* KeyPosition = "Position"; - constexpr const char* KeyRotation = "Rotation"; + constexpr const char* KeyUp = "Up"; + constexpr const char* KeyYaw = "Yaw"; + constexpr const char* KeyPitch = "Pitch"; + constexpr const char* KeyReferenceFrame = "ReferenceFrame"; + const double Epsilon = 1E-7; constexpr const openspace::properties::Property::PropertyInfo KeyFrameInfo = { "UseKeyFrameInteraction", @@ -51,24 +58,101 @@ namespace { "If this is set to 'true' the entire interaction is based off key frames rather " "than using the mouse interaction." }; + } // namespace #include "navigationhandler_lua.inl" namespace openspace::interaction { + +ghoul::Dictionary +openspace::interaction::NavigationHandler::NavigationState::dictionary() const +{ + ghoul::Dictionary cameraDict; + cameraDict.setValue(KeyPosition, position); + cameraDict.setValue(KeyAnchor, anchor); + + if (anchor != referenceFrame) { + cameraDict.setValue(KeyReferenceFrame, referenceFrame); + } + if (!aim.empty()) { + cameraDict.setValue(KeyAim, aim); + } + if (up.has_value()) { + cameraDict.setValue(KeyUp, up.value()); + + if (std::abs(yaw) > Epsilon) { + cameraDict.setValue(KeyYaw, yaw); + } + if (std::abs(pitch) > Epsilon) { + cameraDict.setValue(KeyPitch, pitch); + } + } + + return cameraDict; +} + +openspace::interaction::NavigationHandler::NavigationState::NavigationState( + const ghoul::Dictionary& dictionary) +{ + const bool hasAnchor = dictionary.hasValue(KeyAnchor); + const bool hasPosition = dictionary.hasValue(KeyPosition); + if (!hasAnchor || !hasPosition) { + throw ghoul::RuntimeError( + "Position and Anchor need to be defined for navigation dictionary." + ); + } + + anchor = dictionary.value(KeyAnchor); + position = dictionary.value(KeyPosition); + + if (dictionary.hasValue(KeyReferenceFrame)) { + referenceFrame = dictionary.value(KeyReferenceFrame); + } + else { + referenceFrame = anchor; + } + if (dictionary.hasValue(KeyAim)) { + aim = dictionary.value(KeyAim); + } + + if (dictionary.hasValue(KeyUp)) { + up = dictionary.value(KeyUp); + + if (dictionary.hasValue(KeyYaw)) { + yaw = dictionary.value(KeyYaw); + } + if (dictionary.hasValue(KeyPitch)) { + pitch = dictionary.value(KeyPitch); + } + } +} + +openspace::interaction::NavigationHandler::NavigationState::NavigationState( + std::string anchor, + std::string aim, + std::string referenceFrame, + glm::dvec3 position, + std::optional up, + double yaw, + double pitch) + : anchor(std::move(anchor)) + , aim(std::move(aim)) + , referenceFrame(std::move(referenceFrame)) + , position(std::move(position)) + , up(std::move(up)) + , yaw(yaw) + , pitch(pitch) +{} + NavigationHandler::NavigationHandler() : properties::PropertyOwner({ "NavigationHandler" }) , _useKeyFrameInteraction(KeyFrameInfo, false) { - - _inputState = std::make_unique(); - _orbitalNavigator = std::make_unique(); - _keyframeNavigator = std::make_unique(); - // Add the properties addProperty(_useKeyFrameInteraction); - addPropertySubOwner(*_orbitalNavigator); + addPropertySubOwner(_orbitalNavigator); } NavigationHandler::~NavigationHandler() {} // NOLINT @@ -90,19 +174,25 @@ void NavigationHandler::deinitialize() { void NavigationHandler::setCamera(Camera* camera) { _camera = camera; - _orbitalNavigator->setCamera(camera); + _orbitalNavigator.setCamera(camera); } -const OrbitalNavigator& NavigationHandler::orbitalNavigator() const { - return *_orbitalNavigator; +void NavigationHandler::setNavigationStateNextFrame( + NavigationHandler::NavigationState state) +{ + _pendingNavigationState = std::move(state); } OrbitalNavigator& NavigationHandler::orbitalNavigator() { - return *_orbitalNavigator; + return _orbitalNavigator; } -KeyframeNavigator& NavigationHandler::keyframeNavigator() const { - return *_keyframeNavigator; +const OrbitalNavigator& NavigationHandler::orbitalNavigator() const { + return _orbitalNavigator; +} + +KeyframeNavigator& NavigationHandler::keyframeNavigator() { + return _keyframeNavigator; } bool NavigationHandler::isKeyFrameInteractionEnabled() const { @@ -110,33 +200,93 @@ bool NavigationHandler::isKeyFrameInteractionEnabled() const { } float NavigationHandler::interpolationTime() const { - return _orbitalNavigator->retargetInterpolationTime(); + return _orbitalNavigator.retargetInterpolationTime(); } void NavigationHandler::setInterpolationTime(float durationInSeconds) { - _orbitalNavigator->setRetargetInterpolationTime(durationInSeconds); + _orbitalNavigator.setRetargetInterpolationTime(durationInSeconds); } void NavigationHandler::updateCamera(double deltaTime) { - ghoul_assert(_inputState != nullptr, "InputState must not be nullptr"); ghoul_assert(_camera != nullptr, "Camera must not be nullptr"); - if (_cameraUpdatedFromScript) { - _cameraUpdatedFromScript = false; - } - else { - if (!_playbackModeEnabled && _camera) { - if (_useKeyFrameInteraction) { - _keyframeNavigator->updateCamera(*_camera, _playbackModeEnabled); - } - else { - _orbitalNavigator->updateStatesFromInput(*_inputState, deltaTime); - _orbitalNavigator->updateCameraStateFromStates(deltaTime); - } + if (_pendingNavigationState.has_value()) { + applyNavigationState(_pendingNavigationState.value()); + _orbitalNavigator.resetVelocities(); + _pendingNavigationState.reset(); + } else if (!_playbackModeEnabled && _camera) { + if (_useKeyFrameInteraction) { + _keyframeNavigator.updateCamera(*_camera, _playbackModeEnabled); + } + else { + _orbitalNavigator.updateStatesFromInput(_inputState, deltaTime); + _orbitalNavigator.updateCameraStateFromStates(deltaTime); } } } +void NavigationHandler::applyNavigationState(const NavigationHandler::NavigationState& ns) +{ + const SceneGraphNode* referenceFrame = sceneGraphNode(ns.referenceFrame); + const SceneGraphNode* anchor = sceneGraphNode(ns.anchor); + + if (!anchor) { + LERROR(fmt::format( + "Could not find scene graph node '{}' used as anchor.", ns.referenceFrame + )); + return; + } + if (!ns.aim.empty() && !sceneGraphNode(ns.aim)) { + LERROR(fmt::format( + "Could not find scene graph node '{}' used as aim.", ns.referenceFrame + )); + return; + } + if (!referenceFrame) { + LERROR(fmt::format( + "Could not find scene graph node '{}' used as reference frame.", + ns.referenceFrame) + ); + return; + } + + const glm::dvec3 anchorWorldPosition = anchor->worldPosition(); + const glm::dmat3 referenceFrameTransform = referenceFrame->worldRotationMatrix(); + + _orbitalNavigator.setAnchorNode(ns.anchor); + _orbitalNavigator.setAimNode(ns.aim); + + const SceneGraphNode* anchorNode = _orbitalNavigator.anchorNode(); + const SceneGraphNode* aimNode = _orbitalNavigator.aimNode(); + if (!aimNode) { + aimNode = anchorNode; + } + + const glm::dvec3 cameraPositionWorld = anchorWorldPosition + + glm::dvec3(referenceFrameTransform * glm::dvec4(ns.position, 1.0)); + + glm::dvec3 up = ns.up.has_value() ? + glm::normalize(referenceFrameTransform * ns.up.value()) : + glm::dvec3(0.0, 1.0, 0.0); + + // Construct vectors of a "neutral" view, i.e. when the aim is centered in view. + glm::dvec3 neutralView = + glm::normalize(aimNode->worldPosition() - cameraPositionWorld); + + glm::dquat neutralCameraRotation = glm::inverse(glm::quat_cast(glm::lookAt( + glm::dvec3(0.0), + neutralView, + up + ))); + + glm::dquat pitchRotation = glm::angleAxis(ns.pitch, glm::dvec3(1.f, 0.f, 0.f)); + glm::dquat yawRotation = glm::angleAxis(ns.yaw, glm::dvec3(0.f, -1.f, 0.f)); + + _camera->setPositionVec3(cameraPositionWorld); + _camera->setRotation(neutralCameraRotation * yawRotation * pitchRotation); + _orbitalNavigator.clearPreviousState(); +} + void NavigationHandler::setEnableKeyFrameInteraction() { _useKeyFrameInteraction = true; } @@ -150,8 +300,8 @@ void NavigationHandler::triggerPlaybackStart() { } void NavigationHandler::stopPlayback() { - _orbitalNavigator->resetVelocities(); - _orbitalNavigator->resetNodeMovements(); + _orbitalNavigator.resetVelocities(); + _orbitalNavigator.resetNodeMovements(); _playbackModeEnabled = false; } @@ -160,131 +310,120 @@ Camera* NavigationHandler::camera() const { } const InputState& NavigationHandler::inputState() const { - return *_inputState; + return _inputState; } void NavigationHandler::mouseButtonCallback(MouseButton button, MouseAction action) { - _inputState->mouseButtonCallback(button, action); + _inputState.mouseButtonCallback(button, action); } void NavigationHandler::mousePositionCallback(double x, double y) { - _inputState->mousePositionCallback(x, y); + _inputState.mousePositionCallback(x, y); } void NavigationHandler::mouseScrollWheelCallback(double pos) { - _inputState->mouseScrollWheelCallback(pos); + _inputState.mouseScrollWheelCallback(pos); } void NavigationHandler::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) { - _inputState->keyboardCallback(key, modifier, action); + _inputState.keyboardCallback(key, modifier, action); } -void NavigationHandler::setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict) +NavigationHandler::NavigationState NavigationHandler::navigationState( + const SceneGraphNode& referenceFrame) const { - bool readSuccessful = true; + const SceneGraphNode* anchor = _orbitalNavigator.anchorNode(); + const SceneGraphNode* aim = _orbitalNavigator.aimNode(); - std::string anchor; - std::string aim; - glm::dvec3 cameraPosition; - glm::dvec4 cameraRotation; // Need to read the quaternion as a vector first. - - readSuccessful &= cameraDict.getValue(KeyAnchor, anchor); - readSuccessful &= cameraDict.getValue(KeyPosition, cameraPosition); - readSuccessful &= cameraDict.getValue(KeyRotation, cameraRotation); - cameraDict.getValue(KeyAim, aim); // Aim is not required - - if (!readSuccessful) { - throw ghoul::RuntimeError( - "Position, Rotation and Focus need to be defined for camera dictionary." - ); + if (!aim) { + aim = anchor; } - // Set state - _orbitalNavigator->setAnchorNode(anchor); - _orbitalNavigator->setAimNode(aim); + const glm::dquat invNeutralRotation = glm::quat_cast(glm::lookAt( + glm::dvec3(0.0, 0.0, 0.0), + aim->worldPosition() - _camera->positionVec3(), + glm::normalize(_camera->lookUpVectorWorldSpace()) + )); - _camera->setPositionVec3(cameraPosition); - _camera->setRotation(glm::dquat( - cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w)); + glm::dquat localRotation = invNeutralRotation * _camera->rotationQuaternion(); + glm::dvec3 eulerAngles = glm::eulerAngles(localRotation); + + const double pitch = eulerAngles.x; + const double yaw = -eulerAngles.y; + + // Need to compensate by redisual roll left in local rotation: + const glm::dquat unroll = glm::angleAxis(eulerAngles.z, glm::dvec3(0, 0, 1)); + const glm::dvec3 neutralUp = + glm::inverse(invNeutralRotation) * unroll * _camera->lookUpVectorCameraSpace(); + + const glm::dmat3 invReferenceFrameTransform = + glm::inverse(referenceFrame.worldRotationMatrix()); + + const glm::dvec3 position = invReferenceFrameTransform * + (glm::dvec4(_camera->positionVec3() - anchor->worldPosition(), 1.0)); + + return NavigationState( + _orbitalNavigator.anchorNode()->identifier(), + _orbitalNavigator.aimNode() ? + _orbitalNavigator.aimNode()->identifier() : "", + referenceFrame.identifier(), + position, + invReferenceFrameTransform * neutralUp, yaw, pitch + ); } -ghoul::Dictionary NavigationHandler::cameraStateDictionary() { - glm::dvec3 cameraPosition; - glm::dquat quat; - glm::dvec4 cameraRotation; +void NavigationHandler::saveNavigationState(const std::string& filepath, + const std::string& referenceFrameIdentifier) +{ + const SceneGraphNode* referenceFrame = _orbitalNavigator.followingNodeRotation() ? + _orbitalNavigator.anchorNode() : + sceneGraph()->root(); - cameraPosition = _camera->positionVec3(); - quat = _camera->rotationQuaternion(); - cameraRotation = glm::dvec4(quat.w, quat.x, quat.y, quat.z); - - ghoul::Dictionary cameraDict; - cameraDict.setValue(KeyPosition, cameraPosition); - cameraDict.setValue(KeyRotation, cameraRotation); - cameraDict.setValue(KeyAnchor, _orbitalNavigator->anchorNode()->identifier()); - if (_orbitalNavigator->aimNode()) { - cameraDict.setValue(KeyAim, _orbitalNavigator->aimNode()->identifier()); - } - - return cameraDict; -} - -void NavigationHandler::saveCameraStateToFile(const std::string& filepath) { - if (!filepath.empty()) { - std::string fullpath = absPath(filepath); - LINFO(fmt::format("Saving camera position: {}", filepath)); - - ghoul::Dictionary cameraDict = cameraStateDictionary(); - - // TODO(abock): 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. - - std::ofstream ofs(fullpath.c_str()); - - glm::dvec3 p = _camera->positionVec3(); - glm::dquat q = _camera->rotationQuaternion(); - - ofs << "return {" << std::endl; - ofs << " " << KeyAnchor << " = " << "\"" << - _orbitalNavigator->anchorNode()->identifier() << "\"" - << "," << std::endl; - - if (_orbitalNavigator->aimNode()) { - ofs << " " << KeyAim << " = " << "\"" << - _orbitalNavigator->aimNode()->identifier() << "\"" - << "," << std::endl; + if (!referenceFrameIdentifier.empty()) { + referenceFrame = sceneGraphNode(referenceFrameIdentifier); + if (!referenceFrame) { + LERROR(fmt::format( + "Could not find node '{}' to use as reference frame", + referenceFrameIdentifier + )); + return; } + } - ofs << " " << KeyPosition << " = {" - << std::to_string(p.x) << ", " - << std::to_string(p.y) << ", " - << std::to_string(p.z) << "}," << std::endl; - ofs << " " << KeyRotation << " = {" - << std::to_string(q.w) << ", " - << std::to_string(q.x) << ", " - << std::to_string(q.y) << ", " - << std::to_string(q.z) << "}," << std::endl; - ofs << "}"<< std::endl; + if (!filepath.empty()) { + std::string absolutePath = absPath(filepath); + LINFO(fmt::format("Saving camera position: {}", absolutePath)); + ghoul::Dictionary cameraDict = navigationState(*referenceFrame).dictionary(); + ghoul::DictionaryLuaFormatter formatter; + + std::ofstream ofs(absolutePath.c_str()); + ofs << "return " << formatter.format(cameraDict); ofs.close(); } } -void NavigationHandler::restoreCameraStateFromFile(const std::string& filepath) { - LINFO(fmt::format("Reading camera state from file: {}", filepath)); - if (!FileSys.fileExists(filepath)) { - throw ghoul::FileNotFoundError(filepath, "CameraFilePath"); +void NavigationHandler::loadNavigationState(const std::string& filepath) { + const std::string absolutePath = absPath(filepath); + LINFO(fmt::format("Reading camera state from file: {}", absolutePath)); + + if (!FileSys.fileExists(absolutePath)) { + throw ghoul::FileNotFoundError(absolutePath, "NavigationState"); } - ghoul::Dictionary cameraDict; + ghoul::Dictionary navigationStateDictionary; try { - ghoul::lua::loadDictionaryFromFile(filepath, cameraDict); - setCameraStateFromDictionary(cameraDict); - _cameraUpdatedFromScript = true; + ghoul::lua::loadDictionaryFromFile(absolutePath, navigationStateDictionary); + openspace::documentation::testSpecificationAndThrow( + NavigationState::Documentation(), + navigationStateDictionary, + "NavigationState" + ); + setNavigationStateNextFrame(NavigationState(navigationStateDictionary)); } catch (ghoul::RuntimeError& e) { - LWARNING("Unable to set camera position"); - LWARNING(e.message); + LERROR(fmt::format("Unable to set camera position: {}", e.message)); } } @@ -293,7 +432,7 @@ void NavigationHandler::setJoystickAxisMapping(int axis, JoystickCameraStates::AxisInvert shouldInvert, JoystickCameraStates::AxisNormalize shouldNormalize) { - _orbitalNavigator->joystickStates().setAxisMapping( + _orbitalNavigator.joystickStates().setAxisMapping( axis, mapping, shouldInvert, @@ -304,15 +443,15 @@ void NavigationHandler::setJoystickAxisMapping(int axis, JoystickCameraStates::AxisInformation NavigationHandler::joystickAxisMapping(int axis) const { - return _orbitalNavigator->joystickStates().axisMapping(axis); + return _orbitalNavigator.joystickStates().axisMapping(axis); } void NavigationHandler::setJoystickAxisDeadzone(int axis, float deadzone) { - _orbitalNavigator->joystickStates().setDeadzone(axis, deadzone); + _orbitalNavigator.joystickStates().setDeadzone(axis, deadzone); } float NavigationHandler::joystickAxisDeadzone(int axis) const { - return _orbitalNavigator->joystickStates().deadzone(axis); + return _orbitalNavigator.joystickStates().deadzone(axis); } void NavigationHandler::bindJoystickButtonCommand(int button, std::string command, @@ -320,7 +459,7 @@ void NavigationHandler::bindJoystickButtonCommand(int button, std::string comman JoystickCameraStates::ButtonCommandRemote remote, std::string documentation) { - _orbitalNavigator->joystickStates().bindButtonCommand( + _orbitalNavigator.joystickStates().bindButtonCommand( button, std::move(command), action, @@ -330,11 +469,68 @@ void NavigationHandler::bindJoystickButtonCommand(int button, std::string comman } void NavigationHandler::clearJoystickButtonCommand(int button) { - _orbitalNavigator->joystickStates().clearButtonCommand(button); + _orbitalNavigator.joystickStates().clearButtonCommand(button); } std::vector NavigationHandler::joystickButtonCommand(int button) const { - return _orbitalNavigator->joystickStates().buttonCommand(button); + return _orbitalNavigator.joystickStates().buttonCommand(button); +} + +documentation::Documentation NavigationHandler::NavigationState::Documentation() { + using namespace documentation; + + return { + "Navigation State", + "core_navigation_state", + { + { + KeyAnchor, + new StringVerifier, + Optional::No, + "The identifier of the anchor node." + }, + { + KeyAim, + new StringVerifier, + Optional::Yes, + "The identifier of the aim node, if used." + }, + { + KeyReferenceFrame, + new StringVerifier, + Optional::Yes, + "The identifier of the scene graph node to use as reference frame. " + "If not specified, this will be the same as the anchor." + }, + { + KeyPosition, + new DoubleVector3Verifier, + Optional::No, + "The position of the camera relative to the anchor node, " + "expressed in meters in the specified reference frame." + }, + { + KeyUp, + new DoubleVector3Verifier, + Optional::Yes, + "The up vector expressed in the coordinate system of the reference frame." + }, + { + KeyYaw, + new DoubleVerifier, + Optional::Yes, + "The yaw angle in radians. " + "Positive angle means yawing camera to the right." + }, + { + KeyPitch, + new DoubleVerifier, + Optional::Yes, + "The pitch angle in radians. " + "Positive angle means pitching camera upwards." + }, + } + }; } scripting::LuaLibrary NavigationHandler::luaLibrary() { @@ -342,25 +538,33 @@ scripting::LuaLibrary NavigationHandler::luaLibrary() { "navigation", { { - "setCameraState", - &luascriptfunctions::setCameraState, + "setNavigationState", + &luascriptfunctions::setNavigationState, {}, - "object", - "Set the camera state" + "table", + "Set the navigation state. " + "The argument must be a valid Navigation State." }, { - "saveCameraStateToFile", - &luascriptfunctions::saveCameraStateToFile, + "saveNavigationState", + &luascriptfunctions::saveNavigationState, {}, - "string", - "Save the current camera state to file" + "string, [string]", + "Save the current navigation state to a file with the path given by the " + "first argument. The optoinal second argument is the scene graph node to " + "use as reference frame. By default, the reference frame will picked " + "based on whether the orbital navigator is currently following the " + "anchor node rotation. If it is, the anchor will be chosen as reference " + "frame. If not, the reference frame will be set to the scene graph root." }, { - "restoreCameraStateFromFile", - &luascriptfunctions::restoreCameraStateFromFile, + "loadNavigationState", + &luascriptfunctions::loadNavigationState, {}, "string", - "Restore the camera state from file" + "Load a navigation state from file. The file should be a lua file " + "returning the navigation state as a table formatted as a " + "Navigation State, such as the output files of saveNavigationState." }, { "retargetAnchor", diff --git a/src/interaction/navigationhandler_lua.inl b/src/interaction/navigationhandler_lua.inl index f2affeeea7..899859c36e 100644 --- a/src/interaction/navigationhandler_lua.inl +++ b/src/interaction/navigationhandler_lua.inl @@ -26,8 +26,8 @@ namespace openspace::luascriptfunctions { -int restoreCameraStateFromFile(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::restoreCameraStateFromFile"); +int loadNavigationState(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadNavigationState"); const std::string& cameraStateFilePath = ghoul::lua::value( L, @@ -39,27 +39,35 @@ int restoreCameraStateFromFile(lua_State* L) { return ghoul::lua::luaError(L, "filepath string is empty"); } - global::navigationHandler.restoreCameraStateFromFile(cameraStateFilePath); + global::navigationHandler.loadNavigationState(cameraStateFilePath); ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } -int setCameraState(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setCameraState"); +int setNavigationState(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setNavigationState"); - try { - ghoul::Dictionary dictionary; - ghoul::lua::luaDictionaryFromState(L, dictionary); - global::navigationHandler.setCameraStateFromDictionary(dictionary); - } catch (const ghoul::RuntimeError& e) { + ghoul::Dictionary navigationStateDictionary; + ghoul::lua::luaDictionaryFromState(L, navigationStateDictionary); + + using namespace openspace::documentation; + + TestResult r = testSpecification( + interaction::NavigationHandler::NavigationState::Documentation(), + navigationStateDictionary + ); + + if (!r.success) { lua_settop(L, 0); return ghoul::lua::luaError( L, - fmt::format("Could not set camera state: {}", e.what()) + fmt::format("Could not set camera state: {}", ghoul::to_string(r)) ); } + global::navigationHandler.setNavigationStateNextFrame(navigationStateDictionary); + // @CLEANUP: When luaDictionaryFromState doesn't leak space anymore, remove the next // line ---abock(2018-02-15) lua_settop(L, 0); @@ -67,21 +75,27 @@ int setCameraState(lua_State* L) { return 0; } -int saveCameraStateToFile(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::saveCameraStateToFile"); - - const std::string& cameraStateFilePath = ghoul::lua::value( +int saveNavigationState(lua_State* L) { + const int n = ghoul::lua::checkArgumentsAndThrow( L, - 1, - ghoul::lua::PopValue::Yes + { 1, 2 }, + "lua::saveNavigationState" ); + const std::string& cameraStateFilePath = ghoul::lua::value(L, 1); + + std::string referenceFrame = ""; + if (n > 1) { + referenceFrame = ghoul::lua::value(L, 2); + } + if (cameraStateFilePath.empty()) { return ghoul::lua::luaError(L, "filepath string is empty"); } - global::navigationHandler.saveCameraStateToFile(cameraStateFilePath); + global::navigationHandler.saveNavigationState(cameraStateFilePath, referenceFrame); + lua_settop(L, 0); ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } diff --git a/src/interaction/orbitalnavigator.cpp b/src/interaction/orbitalnavigator.cpp index a1ae0da15b..2ec2474bf9 100644 --- a/src/interaction/orbitalnavigator.cpp +++ b/src/interaction/orbitalnavigator.cpp @@ -365,20 +365,26 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { const glm::dvec3 anchorPos = _anchorNode->worldPosition(); const glm::dvec3 prevCameraPosition = _camera->positionVec3(); - const glm::dvec3 anchorDisplacement = anchorPos - _previousAnchorNodePosition; + const glm::dvec3 anchorDisplacement = _previousAnchorNodePosition.has_value() ? + (anchorPos - _previousAnchorNodePosition.value()) : + glm::dvec3(0.0); CameraPose pose = { _camera->positionVec3() + anchorDisplacement, _camera->rotationQuaternion() }; - if (_aimNode && _aimNode != _anchorNode) { + const bool hasPreviousPositions = + _previousAnchorNodePosition.has_value() && + _previousAimNodePosition.has_value(); + + if (_aimNode && _aimNode != _anchorNode && hasPreviousPositions) { const glm::dvec3 aimPos = _aimNode->worldPosition(); const glm::dvec3 cameraToAnchor = - _previousAnchorNodePosition - prevCameraPosition; + _previousAnchorNodePosition.value() - prevCameraPosition; Displacement anchorToAim = { - _previousAimNodePosition - _previousAnchorNodePosition, + _previousAimNodePosition.value() - _previousAnchorNodePosition.value(), aimPos - anchorPos }; @@ -413,8 +419,9 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { glm::dquat anchorRotation = glm::quat_cast(_anchorNode->worldRotationMatrix()); - glm::dquat anchorNodeRotationDiff = - _previousAnchorNodeRotation * glm::inverse(anchorRotation); + glm::dquat anchorNodeRotationDiff = _previousAnchorNodeRotation.has_value() ? + _previousAnchorNodeRotation.value() * glm::inverse(anchorRotation) : + glm::dquat(); _previousAnchorNodeRotation = anchorRotation; @@ -563,11 +570,17 @@ void OrbitalNavigator::setAnchorNode(const SceneGraphNode* anchorNode) { _anchorNode = anchorNode; if (_anchorNode) { - _previousAnchorNodePosition = _anchorNode->worldPosition(); - _previousAnchorNodeRotation = glm::quat_cast(_anchorNode->worldRotationMatrix()); + _previousAnchorNodePosition.reset(); + _previousAnchorNodeRotation.reset(); } } +void OrbitalNavigator::clearPreviousState() { + _previousAnchorNodePosition.reset(); + _previousAnchorNodeRotation.reset(); + _previousAimNodePosition.reset(); +} + void OrbitalNavigator::setAimNode(const SceneGraphNode* aimNode) { _retargetAimInterpolator.end(); _aimNode = aimNode; @@ -652,6 +665,9 @@ void OrbitalNavigator::setRetargetInterpolationTime(float durationInSeconds) { } bool OrbitalNavigator::followingNodeRotation() const { + if (_aimNode != nullptr && _aimNode != _anchorNode) { + return false; + } return _followRotationInterpolator.value() >= 1.0; } @@ -1219,4 +1235,8 @@ JoystickCameraStates& OrbitalNavigator::joystickStates() { return _joystickStates; } +const JoystickCameraStates& OrbitalNavigator::joystickStates() const { + return _joystickStates; +} + } // namespace openspace::interaction diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 89b3707e89..b46206e6d7 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -848,7 +848,7 @@ void SessionRecording::playbackCamera() { pbFrame.followFocusNodeRotation = (rotationFollowing == "F"); } if (_setSimulationTimeWithNextCameraKeyframe) { - global::timeManager.setTimeNextFrame(timeSim); + global::timeManager.setTimeNextFrame(Time(timeSim)); _setSimulationTimeWithNextCameraKeyframe = false; _saveRenderingCurrentRecordedTime = timeRec; } diff --git a/src/interaction/touchbar.mm b/src/interaction/touchbar.mm index de51a9fee7..f1762ced24 100644 --- a/src/interaction/touchbar.mm +++ b/src/interaction/touchbar.mm @@ -31,6 +31,7 @@ #include #include #include +#include using namespace openspace; @@ -44,8 +45,8 @@ using namespace openspace; #import static NSString* pauseResultId = @"com.openspaceproject.pause_resume"; -static NSString* showFullGuiId = @"com.openspaceproject.show_full_gui"; -static NSString* showSimpleGuiId = @"com.openspaceproject.show_simple_gui"; +static NSString* hideGuiId = @"com.openspaceproject.hide_gui"; +static NSString* hideOnScreenTextId = @"com.openspaceproject.hide_onscreen"; NSArray* focusIdentifiers; @@ -55,8 +56,8 @@ NSArray* focusIdentifiers; makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier; - (void)pauseResumeButtonAction:(id)sender; - (void)focusObjectAction:(id)sender; - - (void)fullGuiButtonAction:(id)sender; - - (void)simpleGuiButtonAction:(id)sender; + - (void)hideTextAction:(id)sender; + - (void)hideGuiAction:(id)sender; @end @implementation TouchBarDelegate @@ -66,7 +67,7 @@ NSArray* focusIdentifiers; touchBar.customizationIdentifier = @"com.openspaceproject.main_touch_bar"; - NSArray* objs = [@[showSimpleGuiId, showFullGuiId, + NSArray* objs = [@[hideGuiId, hideOnScreenTextId, NSTouchBarItemIdentifierFixedSpaceSmall, pauseResultId, NSTouchBarItemIdentifierFlexibleSpace] arrayByAddingObjectsFromArray: focusIdentifiers]; @@ -85,8 +86,6 @@ NSArray* focusIdentifiers; - (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier { - // @TODO(abock): Potential memory leak here by returning an alloc? - // Remove the unused variable warning (void)touchBar; @@ -112,38 +111,38 @@ NSArray* focusIdentifiers; return [touchBarItem autorelease]; } - if ([identifier isEqualToString:showFullGuiId]) { + if ([identifier isEqualToString:hideOnScreenTextId]) { NSButton* button = [NSButton - buttonWithTitle:@"Full GUI" - target:self action:@selector(fullGuiButtonAction:) + buttonWithTitle:@"Toggle Text" + target:self action:@selector(hideTextAction:) ]; NSCustomTouchBarItem* touchBarItem = [ [NSCustomTouchBarItem alloc] - initWithIdentifier:showFullGuiId + initWithIdentifier:hideOnScreenTextId ]; touchBarItem.view = button; touchBarItem.customizationLabel = NSLocalizedString( - @"Toggles the full GUI", + @"Toogles on-screen text", @"" ); return [touchBarItem autorelease]; } - if ([identifier isEqualToString:showSimpleGuiId]) { + if ([identifier isEqualToString:hideGuiId]) { NSButton* button = [NSButton - buttonWithTitle:@"Simple GUI" - target:self action:@selector(simpleGuiButtonAction:) + buttonWithTitle:@"Toggle GUI" + target:self action:@selector(hideGuiAction:) ]; NSCustomTouchBarItem* touchBarItem = [ [NSCustomTouchBarItem alloc] - initWithIdentifier:showSimpleGuiId + initWithIdentifier:hideGuiId ]; touchBarItem.view = button; touchBarItem.customizationLabel = NSLocalizedString( - @"Toggles the simple GUI", + @"Toggles the main GUI", @"" ); @@ -188,63 +187,40 @@ NSArray* focusIdentifiers; NSString* title = [button title]; + std::string str = fmt::format( + "openspace.setPropertyValueSingle('{}', '{}');\ + openspace.setPropertyValueSingle('{}', '');\ + openspace.setPropertyValueSingle('{}', '');", + "NavigationHandler.OrbitalNavigator.Anchor", std::string([title UTF8String]), + "NavigationHandler.OrbitalNavigator.Aim", + "NavigationHandler.OrbitalNavigator.RetargetAnchor" + ); global::scriptEngine.queueScript( - "openspace.setPropertyValue('NavigationHandler.Origin', '" + - std::string([title UTF8String]) + "');", + str, scripting::ScriptEngine::RemoteScripting::Yes ); } - - (void)fullGuiButtonAction:(id)sender { + - (void)hideTextAction:(id)sender { // Remove unused variable warning (void)sender; + global::scriptEngine.queueScript( - "local b = openspace.getPropertyValue(\ - 'Modules.ImGUI.Main.Enabled'\ - );\ - openspace.setPropertyValueSingle(\ - 'Modules.ImGUI.Main.Enabled',\ - not b\ - );\ - openspace.setPropertyValueSingle(\ - 'Modules.ImGUI.Main.IsHidden',\ - b\ - );", + "local isEnabled = openspace.getPropertyValue('Dashboard.IsEnabled');\ + openspace.setPropertyValueSingle('Dashboard.IsEnabled', not isEnabled);\ + openspace.setPropertyValueSingle('RenderEngine.ShowLog', not isEnabled);\ + openspace.setPropertyValueSingle('RenderEngine.ShowVersion', not isEnabled);\ + openspace.setPropertyValueSingle('RenderEngine.ShowCamera', not isEnabled)", scripting::ScriptEngine::RemoteScripting::No ); } - - (void)simpleGuiButtonAction:(id)sender { + - (void)hideGuiAction:(id)sender { // Remove unused variable warning (void)sender; global::scriptEngine.queueScript( -"local b = openspace.getPropertyValue('Modules.ImGUI.Main.FeaturedProperties.Enabled');\n\ -local c = openspace.getPropertyValue('Modules.ImGUI.Main.IsHidden');\n\ -openspace.setPropertyValue('Modules.ImGUI.*.Enabled', false);\n\ -if b and c then\n\ - -- This can happen if the main properties window is enabled, the main gui\n\ - -- is enabled and then closed again. So the main properties window is\n\ - -- enabled, but also all windows are hidden\n\ - openspace.setPropertyValueSingle('Modules.ImGUI.Main.IsHidden', false);\n\ - openspace.setPropertyValueSingle(\n\ - 'Modules.ImGUI.Main.FeaturedProperties.Enabled',\n\ - true\n\ - );\n\ - openspace.setPropertyValueSingle(\n\ - 'Modules.ImGUI.Main.SpaceTime.Enabled',\n\ - true\n\ - );\n\ -else\n\ - openspace.setPropertyValueSingle(\n\ - 'Modules.ImGUI.Main.FeaturedProperties.Enabled',\n\ - not b\n\ - );\n\ - openspace.setPropertyValueSingle(\n\ - 'Modules.ImGUI.Main.SpaceTime.Enabled',\n\ - not b\n\ - );\n\ - openspace.setPropertyValueSingle('Modules.ImGUI.Main.IsHidden', b);\n\ -end", + "local isEnabled = openspace.getPropertyValue('Modules.CefWebGui.Visible');\ + openspace.setPropertyValueSingle('Modules.CefWebGui.Visible', not isEnabled);", scripting::ScriptEngine::RemoteScripting::No ); } @@ -266,19 +242,18 @@ void showTouchbar() { [NSApplication sharedApplication].automaticCustomizeTouchBarMenuItemEnabled = YES; } - std::vector nodes = - global::renderEngine.scene()->allSceneGraphNodes(); + std::vector ns = global::renderEngine.scene()->allSceneGraphNodes(); std::sort( - nodes.begin(), - nodes.end(), + ns.begin(), + ns.end(), [](SceneGraphNode* lhs, SceneGraphNode* rhs) { return lhs->guiName() < rhs->guiName(); } ); NSMutableArray* ids = [[NSMutableArray alloc] init]; - for (SceneGraphNode* n : nodes) { + for (SceneGraphNode* n : ns) { const std::vector& tags = n->tags(); auto it = std::find(tags.begin(), tags.end(), "GUI.Interesting"); if (it != tags.end()) { diff --git a/src/network/parallelpeer.cpp b/src/network/parallelpeer.cpp index cef58ee498..684680b279 100644 --- a/src/network/parallelpeer.cpp +++ b/src/network/parallelpeer.cpp @@ -325,7 +325,7 @@ void ParallelPeer::dataMessageReceived(const std::vector& message) TimeKeyframeData timeKeyframeData; timeKeyframeData.delta = kfMessage._dt; timeKeyframeData.pause = kfMessage._paused; - timeKeyframeData.time = kfMessage._time; + timeKeyframeData.time = Time(kfMessage._time); timeKeyframeData.jump = kfMessage._requiresTimeJump; const double kfTimestamp = convertTimestamp(kfMessage._timestamp); diff --git a/src/openspace.cpp b/src/openspace.cpp index 439608d025..343b49c480 100644 --- a/src/openspace.cpp +++ b/src/openspace.cpp @@ -29,7 +29,7 @@ namespace openspace { std::string licenseText() { return "OpenSpace\n\ \n\ -Copyright (c) 2014-2018\n\ +Copyright (c) 2014-2019\n\ \n\ Permission is hereby granted, free of charge, to any person obtaining a copy of this\n\ software and associated documentation files (the \"Software\"), to deal in the Software\n\ diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index e4075bf055..6694af0fca 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -62,7 +62,6 @@ namespace openspace::performance { // The ghoul::SharedData block addressed by OpenSpacePerformanceMeasurementSharedData // will only get allocated once and contains the total number of allocated shared memory // blocks alongside a list of names of these blocks -// void PerformanceManager::CreateGlobalSharedMemory() { static_assert( @@ -70,6 +69,8 @@ void PerformanceManager::CreateGlobalSharedMemory() { "The global memory struct does not fit the allocated global memory space" ); + ghoul::SharedMemory::remove(GlobalSharedMemoryName); + if (ghoul::SharedMemory::exists(GlobalSharedMemoryName)) { ghoul::SharedMemory sharedMemory(GlobalSharedMemoryName); sharedMemory.acquireLock(); diff --git a/src/rendering/dashboard_lua.inl b/src/rendering/dashboard_lua.inl index a6544c6af6..3157fa3d01 100644 --- a/src/rendering/dashboard_lua.inl +++ b/src/rendering/dashboard_lua.inl @@ -48,7 +48,13 @@ int addDashboardItem(lua_State* L) { } lua_settop(L, 0); - global::dashboard.addDashboardItem(DashboardItem::createFromDictionary(d)); + try { + global::dashboard.addDashboardItem(DashboardItem::createFromDictionary(d)); + } + catch (const ghoul::RuntimeError& e) { + LERRORC("addDashboardItem", e.what()); + return ghoul::lua::luaError(L, "Error adding dashboard item"); + } ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 1ab0cf6be0..84908f38e7 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -144,11 +144,20 @@ namespace { }; constexpr openspace::properties::Property::PropertyInfo ShowFrameNumberInfo = { - "ShowFrameNumber", - "Show Frame Number", - "If this value is enabled, the current frame number is rendered into the window." + "ShowFrameInformation", + "Show Frame Information", + "If this value is enabled, the current frame number and frame times are rendered " + "into the window." }; +#ifdef OPENSPACE_WITH_INSTRUMENTATION + constexpr openspace::properties::Property::PropertyInfo SaveFrameInfo = { + "SaveFrameInformation", + "Save Frame Information", + "Saves the frame information to disk" + }; +#endif // OPENSPACE_WITH_INSTRUMENTATION + constexpr openspace::properties::Property::PropertyInfo DisableMasterInfo = { "DisableMasterRendering", "Disable Master Rendering", @@ -287,10 +296,14 @@ RenderEngine::RenderEngine() , _showCameraInfo(ShowCameraInfo, true) , _takeScreenshot(TakeScreenshotInfo) , _applyWarping(ApplyWarpingInfo, false) - , _showFrameNumber(ShowFrameNumberInfo, false) + , _showFrameInformation(ShowFrameNumberInfo, false) +#ifdef OPENSPACE_WITH_INSTRUMENTATION + , _saveFrameInformation(SaveFrameInfo, false) +#endif // OPENSPACE_WITH_INSTRUMENTATION , _disableMasterRendering(DisableMasterInfo, false) , _globalBlackOutFactor(GlobalBlackoutFactorInfo, 1.f, 0.f, 1.f) , _nAaSamples(AaSamplesInfo, 4, 1, 8) +<<<<<<< HEAD , _tmoOwner(TMOInfo) , _hdrExposure(HDRExposureInfo, 1.68f, 0.01f, 10.0f) , _maxWhite(MaxWhiteInfo, 4.f, 0.001f, 100.0f) @@ -302,6 +315,11 @@ RenderEngine::RenderEngine() , _value(ValueInfo, 1.f, 0.0f, 5.0f) , _lightness(LightnessInfo, 1.1f, 0.0f, 5.0f) , _colorSpace(ColorSpaceInfo, properties::OptionProperty::DisplayType::Dropdown) +======= + , _hdrExposure(HDRExposureInfo, 0.4f, 0.01f, 10.0f) + , _hdrBackground(BackgroundExposureInfo, 2.8f, 0.01f, 10.0f) + , _gamma(GammaInfo, 2.2f, 0.01f, 10.0f) +>>>>>>> master , _horizFieldOfView(HorizFieldOfViewInfo, 80.f, 1.f, 179.0f) , _globalRotation( GlobalRotationInfo, @@ -320,7 +338,11 @@ RenderEngine::RenderEngine() glm::vec3(0.f), glm::vec3(-glm::pi()), glm::vec3(glm::pi()) +<<<<<<< HEAD ) +======= + ) +>>>>>>> master { _doPerformanceMeasurements.onChange([this](){ global::performanceManager.setEnabled(_doPerformanceMeasurements); @@ -440,7 +462,15 @@ RenderEngine::RenderEngine() _takeScreenshot.onChange([this](){ _shouldTakeScreenshot = true; }); addProperty(_takeScreenshot); - addProperty(_showFrameNumber); + addProperty(_showFrameInformation); +#ifdef OPENSPACE_WITH_INSTRUMENTATION + _saveFrameInformation.onChange([&]() { + if (_saveFrameInformation) { + _frameInfo.lastSavedFrame = frameNumber(); + } + }); + addProperty(_saveFrameInformation); +#endif // OPENSPACE_WITH_INSTRUMENTATION addProperty(_globalRotation); addProperty(_screenSpaceRotation); @@ -538,12 +568,12 @@ void RenderEngine::initializeGL() { // development global::windowDelegate.setNearFarClippingPlane(0.001f, 1000.f); - //Set horizontal FOV value with whatever the field of view (in degrees) is of the + // Set horizontal FOV value with whatever the field of view (in degrees) is of the // initialized window _horizFieldOfView = static_cast(global::windowDelegate.getHorizFieldOfView()); - constexpr const float FontSizeBig = 50.f; - _fontBig = global::fontManager.font(KeyFontMono, FontSizeBig); + constexpr const float FontSizeFrameinfo = 32.f; + _fontFrameInfo = global::fontManager.font(KeyFontMono, FontSizeFrameinfo); constexpr const float FontSizeTime = 15.f; _fontDate = global::fontManager.font(KeyFontMono, FontSizeTime); constexpr const float FontSizeMono = 10.f; @@ -705,13 +735,18 @@ void RenderEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& viewMat ); } - if (_showFrameNumber) { + if (_showFrameInformation) { glm::vec2 penPosition = glm::vec2( fontResolution().x / 2 - 50, fontResolution().y / 3 ); - RenderFont(*_fontBig, penPosition, std::to_string(_frameNumber)); + std::string fn = std::to_string(_frameNumber); + std::string dt = std::to_string(global::windowDelegate.deltaTime()); + std::string avgDt = std::to_string(global::windowDelegate.averageDeltaTime()); + + std::string res = "Frame: " + fn + '\n' + "Dt: " + dt + '\n' + "Avg Dt: " + avgDt; + RenderFont(*_fontFrameInfo, penPosition, res); } ++_frameNumber; @@ -917,6 +952,35 @@ void RenderEngine::postDraw() { scene()->allSceneGraphNodes() ); } + +#ifdef OPENSPACE_WITH_INSTRUMENTATION + if (_saveFrameInformation) { + _frameInfo.frames.push_back({ + frameNumber(), + global::windowDelegate.deltaTime(), + global::windowDelegate.averageDeltaTime() + }); + } + + const uint16_t next = _frameInfo.lastSavedFrame + _frameInfo.saveEveryNthFrame; + const bool shouldSave = _saveFrameInformation && frameNumber() >= next; + if (shouldSave) { + std::string filename = fmt::format( + "_inst_renderengine_{}_{}.txt", + _frameInfo.lastSavedFrame, _frameInfo.saveEveryNthFrame + ); + std::ofstream file(absPath("${BIN}/" + filename)); + for (const FrameInfo& i : _frameInfo.frames) { + std::string line = fmt::format( + "{}\t{}\t{}", i.iFrame, i.deltaTime, i.avgDeltaTime + ); + file << line << '\n'; + } + + _frameInfo.frames.clear(); + _frameInfo.lastSavedFrame = frameNumber(); + } +#endif // OPENSPACE_WITH_INSTRUMENTATION } Scene* RenderEngine::scene() { diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index 98a2c4519f..d8aa117073 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -42,8 +42,8 @@ namespace { constexpr const char* KeyType = "Type"; constexpr const char* KeyTag = "Tag"; - constexpr const std::array UniformNames = { - "OcclusionDepth", "Alpha", "ModelTransform", "ViewProjectionMatrix", "texture1" + constexpr const std::array UniformNames = { + "Alpha", "ModelTransform", "ViewProjectionMatrix", "texture1" }; constexpr openspace::properties::Property::PropertyInfo EnabledInfo = { @@ -451,7 +451,6 @@ bool ScreenSpaceRenderable::initialize() { } bool ScreenSpaceRenderable::initializeGL() { - _originalViewportSize = global::windowDelegate.currentWindowResolution(); createShaders(); return isReady(); } @@ -523,15 +522,9 @@ glm::mat4 ScreenSpaceRenderable::scaleMatrix() { float textureRatio = static_cast(_objectSize.y) / static_cast(_objectSize.x); - float scalingRatioX = _originalViewportSize.x / resolution.x; - float scalingRatioY = _originalViewportSize.y / resolution.y; glm::mat4 scale = glm::scale( glm::mat4(1.f), - glm::vec3( - _scale * scalingRatioX, - _scale * scalingRatioY * textureRatio, - 1.f - ) + glm::vec3(_scale, _scale * textureRatio, 1.f) ); // Simulate orthographic projection by distance to plane. @@ -614,9 +607,8 @@ void ScreenSpaceRenderable::draw(glm::mat4 modelTransform) { unbindTexture(); } -void ScreenSpaceRenderable::bindTexture() {} - -void ScreenSpaceRenderable::unbindTexture() {} +void ScreenSpaceRenderable::unbindTexture() { +} } // namespace openspace diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 8fce29ad62..914242cf9a 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -374,14 +374,14 @@ void SceneGraphNode::update(const UpdateData& data) { } UpdateData newUpdateData = data; - _worldRotationCached = calculateWorldRotation(); - _worldScaleCached = calculateWorldScale(); // Assumes _worldRotationCached and _worldScaleCached have been calculated for parent _worldPositionCached = calculateWorldPosition(); + _worldRotationCached = calculateWorldRotation(); + _worldScaleCached = calculateWorldScale(); - newUpdateData.modelTransform.translation = worldPosition(); - newUpdateData.modelTransform.rotation = worldRotationMatrix(); - newUpdateData.modelTransform.scale = worldScale(); + newUpdateData.modelTransform.translation = _worldPositionCached; + newUpdateData.modelTransform.rotation = _worldRotationCached; + newUpdateData.modelTransform.scale = _worldScaleCached; glm::dmat4 translation = glm::translate( glm::dmat4(1.0), @@ -655,7 +655,7 @@ bool SceneGraphNode::hasGuiHintHidden() const { glm::dvec3 SceneGraphNode::calculateWorldPosition() const { // recursive up the hierarchy if there are parents available if (_parent) { - const glm::dvec3 wp = _parent->calculateWorldPosition(); + const glm::dvec3 wp = _parent->worldPosition(); const glm::dmat3 wrot = _parent->worldRotationMatrix(); const double ws = _parent->worldScale(); const glm::dvec3 p = position(); @@ -684,7 +684,7 @@ bool SceneGraphNode::isTimeFrameActive(const Time& time) const { glm::dmat3 SceneGraphNode::calculateWorldRotation() const { // recursive up the hierarchy if there are parents available if (_parent) { - return _parent->calculateWorldRotation() * rotationMatrix(); + return _parent->worldRotationMatrix() * rotationMatrix(); } else { return rotationMatrix(); @@ -694,7 +694,7 @@ glm::dmat3 SceneGraphNode::calculateWorldRotation() const { double SceneGraphNode::calculateWorldScale() const { // recursive up the hierarchy if there are parents available if (_parent) { - return _parent->calculateWorldScale() * scale(); + return _parent->worldScale() * scale(); } else { return scale(); diff --git a/src/util/time_lua.inl b/src/util/time_lua.inl index 9a197065e8..ac0115367e 100644 --- a/src/util/time_lua.inl +++ b/src/util/time_lua.inl @@ -333,12 +333,12 @@ int time_setTime(lua_State* L) { if (nArguments == 1) { if (isNumber) { double value = lua_tonumber(L, 1); - global::timeManager.setTimeNextFrame(value); + global::timeManager.setTimeNextFrame(Time(value)); return 0; } if (isString) { const char* time = lua_tostring(L, 1); - global::timeManager.setTimeNextFrame(Time::convertTime(time)); + global::timeManager.setTimeNextFrame(Time(Time::convertTime(time))); return 0; } ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); @@ -424,7 +424,7 @@ int time_interpolateTime(lua_State* L) { global::timeManager.interpolateTime(targetTime, duration); } else { - global::timeManager.setTimeNextFrame(targetTime); + global::timeManager.setTimeNextFrame(Time(targetTime)); } } return 0; @@ -486,7 +486,7 @@ int time_interpolateTimeRelative(lua_State* L) { } else { global::timeManager.setTimeNextFrame( - global::timeManager.time().j2000Seconds() + delta + Time(global::timeManager.time().j2000Seconds() + delta) ); } } diff --git a/src/util/timemanager.cpp b/src/util/timemanager.cpp index 4f31a86f23..d8e920d2a7 100644 --- a/src/util/timemanager.cpp +++ b/src/util/timemanager.cpp @@ -109,7 +109,7 @@ void TimeManager::interpolateTime(double targetTime, double durationSeconds) { const bool pause = isPaused(); const TimeKeyframeData current = { time(), deltaTime(), false, false }; - const TimeKeyframeData next = { targetTime, targetDeltaTime(), pause, false }; + const TimeKeyframeData next = { Time(targetTime), targetDeltaTime(), pause, false }; clearKeyframes(); addKeyframe(now, current); @@ -138,7 +138,7 @@ void TimeManager::preSynchronization(double dt) { if (newTime != _lastTime) { using K = const CallbackHandle; using V = TimeChangeCallback; - for (const std::pair& it : _timeChangeCallbacks) { + for (const std::pair& it : _timeChangeCallbacks) { it.second(); } } @@ -148,14 +148,14 @@ void TimeManager::preSynchronization(double dt) { { using K = const CallbackHandle; using V = TimeChangeCallback; - for (const std::pair& it : _deltaTimeChangeCallbacks) { + for (const std::pair& it : _deltaTimeChangeCallbacks) { it.second(); } } if (_timelineChanged) { using K = const CallbackHandle; using V = TimeChangeCallback; - for (const std::pair& it : _timelineChangeCallbacks) { + for (const std::pair& it : _timelineChangeCallbacks) { it.second(); } } @@ -193,12 +193,12 @@ TimeKeyframeData TimeManager::interpolate(double applicationTime) { } else if (hasPastKeyframes) { // Extrapolate based on last past keyframe const double deltaApplicationTime = applicationTime - lastPastKeyframe->timestamp; - Time predictedTime = { + Time predictedTime( lastPastKeyframe->data.time.j2000Seconds() + deltaApplicationTime * (lastPastKeyframe->data.pause ? 0.0 : lastPastKeyframe->data.delta) - }; - return TimeKeyframeData{ + ); + return TimeKeyframeData { predictedTime, lastPastKeyframe->data.delta, false, @@ -206,7 +206,7 @@ TimeKeyframeData TimeManager::interpolate(double applicationTime) { }; } // As the last option, fall back on the current time. - return TimeKeyframeData{ _currentTime, _targetDeltaTime, _timePaused, false }; + return TimeKeyframeData { _currentTime, _targetDeltaTime, _timePaused, false }; } void TimeManager::progressTime(double dt) { @@ -230,7 +230,7 @@ void TimeManager::progressTime(double dt) { using K = const CallbackHandle; using V = TimeChangeCallback; - for (const std::pair& it : _timeJumpCallbacks) { + for (const std::pair& it : _timeJumpCallbacks) { it.second(); } return; @@ -316,7 +316,7 @@ TimeKeyframeData TimeManager::interpolate(const Keyframe& past deltaAppTime; TimeKeyframeData data { - interpolatedTime, + Time(interpolatedTime), interpolatedDeltaTime, past.data.pause, past.data.jump @@ -532,9 +532,9 @@ void TimeManager::interpolateDeltaTime(double newDeltaTime, double interpolation } const double now = global::windowDelegate.applicationTime(); - - Time newTime = time().j2000Seconds() + - (_deltaTime + newDeltaTime) * 0.5 * interpolationDuration; + Time newTime( + time().j2000Seconds() + (_deltaTime + newDeltaTime) * 0.5 * interpolationDuration + ); TimeKeyframeData currentKeyframe = { time(), _deltaTime, false, false }; TimeKeyframeData futureKeyframe = { newTime, newDeltaTime, false, false }; @@ -556,8 +556,9 @@ void TimeManager::interpolatePause(bool pause, double interpolationDuration) { const double now = global::windowDelegate.applicationTime(); double targetDelta = pause ? 0.0 : _targetDeltaTime; - Time newTime = time().j2000Seconds() + - (_deltaTime + targetDelta) * 0.5 * interpolationDuration; + Time newTime( + time().j2000Seconds() + (_deltaTime + targetDelta) * 0.5 * interpolationDuration + ); TimeKeyframeData currentKeyframe = { time(), _deltaTime, false, false }; TimeKeyframeData futureKeyframe = { newTime, _targetDeltaTime, pause, false };