diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 75% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md index b025b07993..2366bc69ea 100644 --- a/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,4 +1,4 @@ ## How to contribute The easiest way to contribute is through a separate fork of the repository and submitting a pull-request. One of the core developers will judge the pull request and integrate it into the main `master` branch. Preferably, there is an accompanying issue (created by you or not) which is solved by the PR. In this case, feel free to use the phrase "(closes #XXX)" in the text of the pull request, where `XXX` is the number of the issue that you have solved. The PR should be in its own separate branch following the naming `pr/feature`, where `feature` is a short, descripting name of the additional feature or bug contained in the PR. -For more information we refer to the [Wiki](https://github.com/OpenSpace/OpenSpace/wiki). If there are any questions, feel free to contact us via [email](mailto:alexander.bock@me.com?subject=OpenSpace: Contributing). \ No newline at end of file +For more information we refer to the [Wiki](https://openspace.github.io). If there are any questions, feel free to contact us via [email](mailto:mail@alexanderbock.eu?subject=OpenSpace: Contributing). \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..6a26096403 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,7 @@ +<< Description of the problem >> + +<< What did you expect to happen >> +<< What did happen? >> + + +<< Attach screenshots, if possible >> \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3b19c172e0..c71edd624b 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ Thumbs.db # OpenSpace-generated folders and files /bin/ /cache/ +/cache-*/ /cache_gdal/ /documentation/ /logs/ diff --git a/ACKNOWLEDGMENTS.md b/ACKNOWLEDGMENTS.md new file mode 100644 index 0000000000..a6db596dc7 --- /dev/null +++ b/ACKNOWLEDGMENTS.md @@ -0,0 +1,3 @@ +OpenSpace is funded in part by NASA under award No NNX16AB93A. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Aeronautics and Space Administration. + +OpenSpace is also funded in part by the Knut & Alice Wallenberg Foundation in Sweden and the Swedish e-Science Research Centre. diff --git a/apps/OpenSpace/CMakeLists.txt b/apps/OpenSpace/CMakeLists.txt index 267eb2c182..1d2ad1b9b9 100644 --- a/apps/OpenSpace/CMakeLists.txt +++ b/apps/OpenSpace/CMakeLists.txt @@ -111,42 +111,20 @@ target_compile_definitions(OpenSpace PRIVATE begin_header("Dependency: SGCT") set(SGCT_TEXT OFF CACHE BOOL "" FORCE) -set(SGCT_BUILD_CSHARP_PROJECTS OFF CACHE BOOL "" FORCE) -set(SGCT_LIGHT_ONLY ON CACHE BOOL "" FORCE) -set(SGCT_CUSTOMOUTPUTDIRS OFF CACHE BOOL "" FORCE) -set(JPEG_TURBO_WITH_SIMD OFF CACHE BOOL "" FORCE) +set(SGCT_DEP_INCLUDE_FREETYPE OFF CACHE BOOL "" FORCE) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ext/sgct) target_include_directories(OpenSpace SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ext/sgct/include) -target_link_libraries( - OpenSpace - sgct_light glew glfw png16_static quat tinyxml2static turbojpeg-static - vrpn ${GLFW_LIBRARIES} -) +target_link_libraries(OpenSpace sgct) -mark_as_advanced(EXECUTABLE_OUTPUT_PATH GLFW_BUILD_DOCS GLFW_BUILD_EXAMPLES - GLFW_BUILD_TESTS GLFW_INSTALL GLFW_USE_HYBRID_HPG GLFW_USE_OSMESA GLFW_VULKAN_STATIC - INSTALL_BIN_DIR INSTALL_INC_DIR INSTALL_LIB_DIR INSTALL_MAN_DIR INSTALL_PKGCONFIG_DIR - IOKIT_LIBRARY JPEG_TURBO_FORCE32bit JPEG_TURBO_WITH_12BIT JPEG_TURBO_WITH_ARITH_DEC - JPEG_TURBO_WITH_ARITH_ENC JPEG_TURBO_WITH_JPEG7 JPEG_TURBO_WITH_JPEG8 - JPEG_TURBO_WITH_MEM_SRCDST JPEG_TURBO_WITH_SIMD JPEG_TURBO_WITH_TURBOJPEG LIB_SUFFIX - LIBRARY_OUTPUT_PATH M_LIBRARY SGCT_BUILD_ALUT SGCT_BUILD_CSHARP_PROJECTS - SGCT_CUSTOMOUTPUTDIRS SGCT_DOXYGEN SGCT_DOXYGEN_QUIET SGCT_EXAMPLES SGCT_INSTALL - SGCT_LIGHT_ONLY SGCT_NO_EXTERNAL_LIBRARIES SGCT_SPOUT_SUPPORT SGCT_TEXT - SGCT_USE_MSVC_RUNTIMES USE_MSVC_RUNTIME_LIBRARY_DLL -) - -set_folder_location(sgct_light "External") -set_folder_location(glew "External/SGCT") +set_folder_location(sgct "External") set_folder_location(glfw "External/SGCT") +set_folder_location(miniziplibstatic "External/SGCT") set_folder_location(png16_static "External/SGCT") set_folder_location(quat "External/SGCT") -set_folder_location(simd "External/SGCT") set_folder_location(tinyxml2static "External/SGCT") -set_folder_location(turbojpeg-static "External/SGCT") set_folder_location(vrpn "External/SGCT") set_folder_location(zlibstatic "External/SGCT") -set_folder_location(miniziplibstatic "External/SGCT") if (UNIX AND (NOT APPLE)) target_link_libraries(OpenSpace Xcursor Xinerama X11) diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 3622605062..df7c5414cc 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 3622605062ae61736426e3d8d26e98524ec1fc97 +Subproject commit df7c5414cc97783e0c32c212db746f49a83020a1 diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index ec47265306..e7f534c60c 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -41,21 +41,34 @@ #include #include #include -#include -#include -#include +//#include +#include +#define GLFW_EXPOSE_NATIVE_WIN32 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include +#include #ifdef WIN32 #include #include #include +#include #include #include #include -#include #endif // WIN32 #ifdef OPENVR_SUPPORT @@ -79,6 +92,7 @@ constexpr const bool EnableDetailedVtune = false; #endif // OPENSPACE_HAS_NVTOOLS using namespace openspace; +using namespace sgct; namespace { @@ -86,11 +100,15 @@ constexpr const char* _loggerCat = "main"; constexpr const char* SpoutTag = "Spout"; constexpr const char* OpenVRTag = "OpenVR"; -sgct::Engine* SgctEngine; -sgct::SharedVector _synchronizationBuffer; +// @TODO (abock, 2020-04-09): These state variables should disappear +const Window* currentWindow = nullptr; +const BaseViewport* currentViewport = nullptr; +Frustum::Mode currentFrustumMode; +glm::mat4 currentModelViewProjectionMatrix; +glm::mat4 currentModelMatrix; #ifdef OPENVR_SUPPORT -sgct::SGCTWindow* FirstOpenVRWindow = nullptr; +Window* FirstOpenVRWindow = nullptr; #endif #ifdef OPENSPACE_HAS_VTUNE @@ -144,6 +162,7 @@ std::vector SpoutWindows; #endif // OPENSPACE_HAS_SPOUT +} // // MiniDump generation @@ -214,55 +233,10 @@ LONG WINAPI generateMiniDump(EXCEPTION_POINTERS* exceptionPointers) { } #endif // WIN32 -// -// Detect OpenGL version -// -std::pair supportedOpenGLVersion() { - // Just create a window in order to retrieve the available OpenGL version before we - // create the real window - glfwInit(); - - // On OS X we need to explicitly set the version and specify that we are using CORE - // profile to be able to use glGetIntegerv(GL_MAJOR_VERSION, &major) and - // glGetIntegerv(GL_MINOR_VERSION, &minor) explicitly setting to OGL 3.3 CORE works - // since all Mac's now support at least 3.3 -#ifdef __APPLE__ - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); -#endif - - glfwWindowHint(GLFW_VISIBLE, GL_FALSE); - - // By creating an offscreen window, the user will not know that we created this window - GLFWwindow* offscreen = glfwCreateWindow(128, 128, "", nullptr, nullptr); - glfwMakeContextCurrent(offscreen); - - // Get the OpenGL version - int major, minor; - glGetIntegerv(GL_MAJOR_VERSION, &major); - glGetIntegerv(GL_MINOR_VERSION, &minor); - - // And get rid of the window again - glfwDestroyWindow(offscreen); - glfwWindowHint(GLFW_VISIBLE, GL_TRUE); - - return { major, minor }; -} - -// -// Context creation function -// -void mainContextCreationFunc(GLFWwindow* win) { - // @TODO (abock, 2020-02-10) Remove this after updating SGCT to 3.0 - TracyGpuContext -} - // // Init function // -void mainInitFunc() { +void mainInitFunc(GLFWwindow*) { ZoneScoped #ifdef OPENSPACE_HAS_VTUNE @@ -288,32 +262,33 @@ void mainInitFunc() { icons[0].width = x; icons[0].height = y; - const size_t nWindows = SgctEngine->getNumberOfWindows(); - for (size_t i = 0; i < nWindows; ++i) { - const sgct::SGCTWindow* windowPtr = SgctEngine->getWindowPtr(i); - glfwSetWindowIcon(windowPtr->getWindowHandle(), 1, icons); + for (const std::unique_ptr& window : Engine::instance().windows()) { + glfwSetWindowIcon(window->windowHandle(), 1, icons); } stbi_image_free(icons[0].pixels); } - + currentWindow = Engine::instance().windows().front().get(); + currentViewport = currentWindow->viewports().front().get(); LDEBUG("Initializing OpenGL in OpenSpace Engine started"); global::openSpaceEngine.initializeGL(); LDEBUG("Initializing OpenGL in OpenSpace Engine finished"); + // Find if we have at least one OpenVR window // Save reference to first OpenVR window, which is the one we will copy to the HMD. - for (size_t i = 0; i < SgctEngine->getNumberOfWindows(); ++i) { - if (SgctEngine->getWindowPtr(i)->checkIfTagExists(OpenVRTag)) { + for (const std::unique_ptr& window : Engine::instance().windows()) { + if (window->hasTag(OpenVRTag)) { #ifdef OPENVR_SUPPORT - FirstOpenVRWindow = SgctEngine->getWindowPtr(i); + FirstOpenVRWindow = window.get(); // If we have an OpenVRWindow, initialize OpenVR. - sgct::SGCTOpenVR::initialize( - SgctEngine->getNearClippingPlane(), SgctEngine->getFarClippingPlane() + sgct::OpenVR::initialize( + Engine::instance().nearClippingPlane(), + Engine::instance().farClippingPlane() ); #else LWARNING("OpenVR was requested, but program was compiled without VR support"); @@ -323,11 +298,9 @@ void mainInitFunc() { } } - const size_t nWindows = SgctEngine->getNumberOfWindows(); - for (size_t i = 0; i < nWindows; ++i) { - const sgct::SGCTWindow* windowPtr = SgctEngine->getWindowPtr(i); - - if (!windowPtr->checkIfTagExists(SpoutTag)) { + for (size_t i = 0; i < Engine::instance().windows().size(); ++i) { + Window& window = *Engine::instance().windows()[i]; + if (!window.hasTag(SpoutTag)) { continue; } @@ -336,34 +309,34 @@ void mainInitFunc() { w.windowId = i; - const sgct::SGCTWindow::StereoMode sm = windowPtr->getStereoMode(); - const bool hasStereo = (sm != sgct::SGCTWindow::No_Stereo) && - (sm < sgct::SGCTWindow::Side_By_Side_Stereo); + const Window::StereoMode sm = window.stereoMode(); + const bool hasStereo = (sm != Window::StereoMode::NoStereo) && + (sm < Window::StereoMode::SideBySide); if (hasStereo) { SpoutWindow::SpoutData& left = w.leftOrMain; left.handle = GetSpout(); left.initialized = left.handle->CreateSender( - (windowPtr->getName() + "_left").c_str(), - windowPtr->getXFramebufferResolution(), - windowPtr->getYFramebufferResolution() + (window.name() + "_left").c_str(), + window.framebufferResolution().x, + window.framebufferResolution().y ); SpoutWindow::SpoutData& right = w.right; right.handle = GetSpout(); right.initialized = right.handle->CreateSender( - (windowPtr->getName() + "_right").c_str(), - windowPtr->getXFramebufferResolution(), - windowPtr->getYFramebufferResolution() + (window.name() + "_right").c_str(), + window.framebufferResolution().x, + window.framebufferResolution().y ); } else { SpoutWindow::SpoutData& main = w.leftOrMain; main.handle = GetSpout(); main.initialized = main.handle->CreateSender( - windowPtr->getName().c_str(), - windowPtr->getXFramebufferResolution(), - windowPtr->getYFramebufferResolution() + window.name().c_str(), + window.framebufferResolution().x, + window.framebufferResolution().y ); } @@ -392,23 +365,8 @@ void mainInitFunc() { ); } - for (size_t i = 0; i < nWindows; ++i) { - sgct::SGCTWindow* w = SgctEngine->getWindowPtr(i); - const std::string screenshotNames = nWindows > 1 ? - fmt::format("OpenSpace_{}", i) : - "OpenSpace"; + Settings::instance().setCapturePath(absPath(screenshotPath)); - sgct_core::ScreenCapture* cpt0 = w->getScreenCapturePointer(0); - sgct_core::ScreenCapture* cpt1 = w->getScreenCapturePointer(1); - - if (cpt0) { - cpt0->setPathAndFileName(absPath(screenshotPath), screenshotNames); - } - - if (cpt1) { - cpt1->setPathAndFileName(absPath(screenshotPath), screenshotNames); - } - } LTRACE("main::mainInitFunc(end)"); #ifdef OPENSPACE_HAS_VTUNE @@ -421,10 +379,6 @@ void mainInitFunc() { void mainPreSyncFunc() { - // @TODO (abock, 2020-02-10) Remove this after merging SGCT version 3.0 - FrameMark - - ZoneScoped #ifdef OPENSPACE_HAS_VTUNE @@ -439,7 +393,7 @@ void mainPreSyncFunc() { } catch (const ghoul::RuntimeError& e) { LFATALC(e.component, e.message); - sgct::Engine::instance()->terminate(); + Engine::instance().terminate(); } // Query joystick status @@ -459,13 +413,13 @@ void mainPreSyncFunc() { if (!state.isConnected) { // Joystick was added state.isConnected = true; - state.name = sgct::Engine::getJoystickName(i); + state.name = glfwGetJoystickName(i); std::fill(state.axes.begin(), state.axes.end(), 0.f); std::fill(state.buttons.begin(), state.buttons.end(), JoystickAction::Idle); } - const float* axes = sgct::Engine::getJoystickAxes(i, &state.nAxes); + const float* axes = glfwGetJoystickAxes(i, &state.nAxes); if (state.nAxes > JoystickInputState::MaxAxes) { LWARNING(fmt::format( "Joystick/Gamepad {} has {} axes, but only {} axes are supported. " @@ -476,10 +430,7 @@ void mainPreSyncFunc() { } std::memcpy(state.axes.data(), axes, state.nAxes * sizeof(float)); - const unsigned char* buttons = sgct::Engine::getJoystickButtons( - i, - &state.nButtons - ); + const unsigned char* buttons = glfwGetJoystickButtons(i, &state.nButtons); if (state.nButtons > JoystickInputState::MaxButtons) { LWARNING(fmt::format( @@ -566,7 +517,7 @@ void mainPostSyncPreDrawFunc() { -void mainRenderFunc() { +void mainRenderFunc(const RenderData& data) { ZoneScoped #ifdef OPENSPACE_HAS_VTUNE @@ -579,10 +530,31 @@ void mainRenderFunc() { #endif // OPENSPACE_HAS_NVTOOLS LTRACE("main::mainRenderFunc(begin)"); - glm::mat4 viewMatrix = SgctEngine->getCurrentViewMatrix() * - glm::translate(glm::mat4(1.f), sgct::Engine::getDefaultUserPtr()->getPos()); + currentWindow = &data.window; + currentViewport = &data.viewport; + currentFrustumMode = data.frustumMode; - glm::mat4 projectionMatrix = SgctEngine->getCurrentProjectionMatrix(); + glm::vec3 pos; + std::memcpy( + glm::value_ptr(pos), + &Engine::instance().defaultUser().posMono().x, + sizeof(vec3) + ); + + glm::mat4 viewMatrix; + std::memcpy( + glm::value_ptr(viewMatrix), + data.viewMatrix.values, + sizeof(mat4) + ); + viewMatrix = viewMatrix * glm::translate(glm::mat4(1.f), pos); + + glm::mat4 projectionMatrix; + std::memcpy( + glm::value_ptr(projectionMatrix), + data.projectionMatrix.values, + sizeof(mat4) + ); #ifdef OPENVR_SUPPORT bool currentWindowIsHMD = FirstOpenVRWindow == SgctEngine->getCurrentWindowPtr(); if (sgct::SGCTOpenVR::isHMDActive() && currentWindowIsHMD) { @@ -593,11 +565,15 @@ void mainRenderFunc() { #endif try { - global::openSpaceEngine.render( - SgctEngine->getModelMatrix(), - viewMatrix, - projectionMatrix + glm::mat4 modelMatrix; + std::memcpy( + glm::value_ptr(modelMatrix), + data.modelMatrix.values, + sizeof(mat4) ); + currentModelMatrix = modelMatrix; + currentModelViewProjectionMatrix = modelMatrix * viewMatrix * projectionMatrix; + global::openSpaceEngine.render(modelMatrix, viewMatrix, projectionMatrix); } catch (const ghoul::RuntimeError& e) { LERRORC(e.component, e.message); @@ -616,7 +592,7 @@ void mainRenderFunc() { -void mainDraw2DFunc() { +void mainDraw2DFunc(const RenderData& data) { ZoneScoped #ifdef OPENSPACE_HAS_VTUNE @@ -626,6 +602,10 @@ void mainDraw2DFunc() { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainDraw2DFunc(begin)"); + currentWindow = &data.window; + currentViewport = &data.viewport; + currentFrustumMode = data.frustumMode; + try { global::openSpaceEngine.drawOverlays(); } @@ -661,7 +641,7 @@ void mainPostDrawFunc() { #ifdef OPENVR_SUPPORT if (FirstOpenVRWindow) { // Copy the first OpenVR window to the HMD - sgct::SGCTOpenVR::copyWindowToHMD(FirstOpenVRWindow); + sgct::OpenVR::copyWindowToHMD(FirstOpenVRWindow); } #endif // OPENVR_SUPPORT @@ -669,26 +649,26 @@ void mainPostDrawFunc() { #ifdef OPENSPACE_HAS_SPOUT for (const SpoutWindow& w : SpoutWindows) { - sgct::SGCTWindow* window = SgctEngine->getWindowPtr(w.windowId); + sgct::Window& window = *Engine::instance().windows()[w.windowId]; if (w.leftOrMain.initialized) { - const GLuint texId = window->getFrameBufferTexture(sgct::Engine::LeftEye); + const GLuint texId = window.frameBufferTexture(Window::TextureIndex::LeftEye); glBindTexture(GL_TEXTURE_2D, texId); w.leftOrMain.handle->SendTexture( texId, GL_TEXTURE_2D, - window->getXFramebufferResolution(), - window->getYFramebufferResolution() + window.framebufferResolution().x, + window.framebufferResolution().y ); } if (w.right.initialized) { - const GLuint texId = window->getFrameBufferTexture(sgct::Engine::RightEye); + const GLuint texId = window.frameBufferTexture(Window::TextureIndex::RightEye); glBindTexture(GL_TEXTURE_2D, texId); w.right.handle->SendTexture( texId, GL_TEXTURE_2D, - window->getXFramebufferResolution(), - window->getYFramebufferResolution() + window.framebufferResolution().x, + window.framebufferResolution().y ); } } @@ -705,7 +685,9 @@ void mainPostDrawFunc() { -void mainKeyboardCallback(int key, int, int action, int modifiers) { +void mainKeyboardCallback(sgct::Key key, sgct::Modifier modifiers, sgct::Action action, + int) +{ ZoneScoped #ifdef OPENSPACE_HAS_VTUNE @@ -715,7 +697,7 @@ void mainKeyboardCallback(int key, int, int action, int modifiers) { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainKeyboardCallback(begin)"); - const Key k = Key(key); + const openspace::Key k = openspace::Key(key); const KeyModifier m = KeyModifier(modifiers); const KeyAction a = KeyAction(action); global::openSpaceEngine.keyboardCallback(k, m, a); @@ -730,7 +712,9 @@ void mainKeyboardCallback(int key, int, int action, int modifiers) { -void mainMouseButtonCallback(int key, int action, int modifiers) { +void mainMouseButtonCallback(sgct::MouseButton key, sgct::Modifier modifiers, + sgct::Action action) +{ ZoneScoped #ifdef OPENSPACE_HAS_VTUNE @@ -740,9 +724,9 @@ void mainMouseButtonCallback(int key, int action, int modifiers) { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainMouseButtonCallback(begin)"); - const MouseButton k = MouseButton(key); - const MouseAction a = MouseAction(action); - const KeyModifier m = KeyModifier(modifiers); + const openspace::MouseButton k = openspace::MouseButton(key); + const openspace::MouseAction a = openspace::MouseAction(action); + const openspace::KeyModifier m = openspace::KeyModifier(modifiers); global::openSpaceEngine.mouseButtonCallback(k, a, m); LTRACE("main::mainMouseButtonCallback(end)"); @@ -818,7 +802,7 @@ void mainCharCallback(unsigned int codepoint, int modifiers) { -void mainEncodeFun() { +std::vector mainEncodeFun() { ZoneScoped #ifdef OPENSPACE_HAS_VTUNE @@ -828,9 +812,7 @@ void mainEncodeFun() { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainEncodeFun(begin)"); - std::vector data = global::openSpaceEngine.encode(); - _synchronizationBuffer.setVal(std::move(data)); - sgct::SharedData::instance()->writeVector(&_synchronizationBuffer); + std::vector data = global::openSpaceEngine.encode(); LTRACE("main::mainEncodeFun(end)"); #ifdef OPENSPACE_HAS_VTUNE @@ -838,11 +820,13 @@ void mainEncodeFun() { __itt_frame_end_v3(_vTune.encode, nullptr); } #endif // OPENSPACE_HAS_VTUNE + + return data; } -void mainDecodeFun() { +void mainDecodeFun(const std::vector& data, unsigned int) { ZoneScoped #ifdef OPENSPACE_HAS_VTUNE @@ -852,9 +836,7 @@ void mainDecodeFun() { #endif // OPENSPACE_HAS_VTUNE LTRACE("main::mainDecodeFun(begin)"); - sgct::SharedData::instance()->readVector(&_synchronizationBuffer); - std::vector data = _synchronizationBuffer.getVal(); - global::openSpaceEngine.decode(std::move(data)); + global::openSpaceEngine.decode(data); LTRACE("main::mainDecodeFun(end)"); #ifdef OPENSPACE_HAS_VTUNE @@ -866,17 +848,24 @@ void mainDecodeFun() { -void mainLogCallback(const char* msg) { +void mainLogCallback(Log::Level level, const char* message) { ZoneScoped - std::string message = msg; - if (message.empty() || message == ".") { - // We don't want the empty '.' message that SGCT sends while it is waiting for - // connections from other network nodes - return; - } + std::string msg = message; // Remove the trailing \n that is passed along - LINFOC("SGCT", message.substr(0, message.size() - 1)); + switch (level) { + case Log::Level::Debug: + LDEBUGC("SGCT", msg.substr(0, msg.size() - 1)); + break; + case Log::Level::Info: + LINFOC("SGCT", msg.substr(0, msg.size() - 1)); + break; + case Log::Level::Warning: + LWARNINGC("SGCT", msg.substr(0, msg.size() - 1)); + break; + case Log::Level::Error: + LERRORC("SGCT", msg.substr(0, msg.size() - 1)); + break; } } // namespace @@ -884,140 +873,102 @@ void mainLogCallback(const char* msg) { void setSgctDelegateFunctions() { WindowDelegate& sgctDelegate = global::windowDelegate; - sgctDelegate.terminate = []() { sgct::Engine::instance()->terminate(); }; + sgctDelegate.terminate = []() { Engine::instance().terminate(); }; sgctDelegate.setBarrier = [](bool enabled) { ZoneScoped - sgct::SGCTWindow::setBarrier(enabled); + sgct::Window::setBarrier(enabled); }; sgctDelegate.setSynchronization = [](bool enabled) { ZoneScoped - sgct_core::ClusterManager::instance()->setUseIgnoreSync(enabled); - }; - sgctDelegate.clearAllWindows = [](const glm::vec4& clearColor) { - ZoneScoped - - size_t n = sgct::Engine::instance()->getNumberOfWindows(); - for (size_t i = 0; i < n; ++i) { - glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GLFWwindow* w = sgct::Engine::instance()->getWindowPtr(i)->getWindowHandle(); - glfwSwapBuffers(w); - } + sgct::ClusterManager::instance().setUseIgnoreSync(enabled); }; sgctDelegate.windowHasResized = []() { ZoneScoped - return sgct::Engine::instance()->getCurrentWindowPtr()->isWindowResized(); + return currentWindow->isWindowResized(); }; sgctDelegate.averageDeltaTime = []() { ZoneScoped - return sgct::Engine::instance()->getAvgDt(); - }; - sgctDelegate.deltaTimeStandardDeviation = []() { - ZoneScoped - - return sgct::Engine::instance()->getDtStandardDeviation(); + return Engine::instance().statistics().avgDt( + Engine::instance().currentFrameNumber() + ); }; sgctDelegate.minDeltaTime = []() { ZoneScoped - return sgct::Engine::instance()->getMinDt(); + return Engine::instance().statistics().minDt(); }; sgctDelegate.maxDeltaTime = []() { ZoneScoped - return sgct::Engine::instance()->getMaxDt(); + return Engine::instance().statistics().maxDt(); }; sgctDelegate.deltaTime = []() { ZoneScoped - return sgct::Engine::instance()->getDt(); + return Engine::instance().statistics().dt(); }; sgctDelegate.applicationTime = []() { ZoneScoped return sgct::Engine::getTime(); }; - sgctDelegate.mousePosition = []() { - ZoneScoped - - int id = sgct::Engine::instance()->getCurrentWindowPtr()->getId(); - double posX, posY; - sgct::Engine::getMousePos(id, &posX, &posY); - return glm::vec2(posX, posY); - }; - sgctDelegate.mouseButtons = [](int maxNumber) { - ZoneScoped - - int id = sgct::Engine::instance()->getCurrentWindowPtr()->getId(); - uint32_t result = 0; - for (int i = 0; i < maxNumber; ++i) { - bool button = (sgct::Engine::getMouseButton(id, i) != 0); - if (button) { - result |= (1 << i); - } - } - return result; - }; sgctDelegate.currentWindowSize = []() { ZoneScoped - return glm::ivec2( - sgct::Engine::instance()->getCurrentWindowPtr()->getXResolution(), - sgct::Engine::instance()->getCurrentWindowPtr()->getYResolution()); + return glm::ivec2(currentWindow->resolution().x, currentWindow->resolution().y); }; sgctDelegate.currentSubwindowSize = []() { ZoneScoped - auto window = sgct::Engine::instance()->getCurrentWindowPtr(); - if (sgct::Engine::instance()->getCurrentWindowPtr()->getNumberOfViewports() > 1) { - sgct_core::Viewport* viewport = - sgct::Engine::instance()->getCurrentWindowPtr()->getViewport(0); - return glm::ivec2(window->getXResolution()*viewport->getXSize(), window->getYResolution()*viewport->getYSize()); + if (currentWindow->viewports().size() > 1) { + const Viewport& viewport = *currentWindow->viewports().front(); + return glm::ivec2( + currentWindow->resolution().x * viewport.size().x, + currentWindow->resolution().y * viewport.size().y + ); } - switch (window->getStereoMode()) { - case sgct::SGCTWindow::Side_By_Side_Stereo: - case sgct::SGCTWindow::Side_By_Side_Inverted_Stereo: - return glm::ivec2(window->getXResolution() / 2, window->getYResolution()); - case sgct::SGCTWindow::Top_Bottom_Stereo: - case sgct::SGCTWindow::Top_Bottom_Inverted_Stereo: - return glm::ivec2(window->getXResolution(), window->getYResolution() / 2); + switch (currentWindow->stereoMode()) { + case Window::StereoMode::SideBySide: + case Window::StereoMode::SideBySideInverted: + return glm::ivec2( + currentWindow->resolution().x / 2, + currentWindow->resolution().y + ); + case Window::StereoMode::TopBottom: + case Window::StereoMode::TopBottomInverted: + return glm::ivec2( + currentWindow->resolution().x, + currentWindow->resolution().y / 2 + ); default: - return glm::ivec2(window->getXResolution(), window->getYResolution()); + return glm::ivec2( + currentWindow->resolution().x, + currentWindow->resolution().y + ); } }; - sgctDelegate.currentWindowResolution = []() { - ZoneScoped - - int x, y; - auto window = sgct::Engine::instance()->getCurrentWindowPtr(); - window->getFinalFBODimensions(x, y); - return glm::ivec2(x, y); - }; sgctDelegate.currentDrawBufferResolution = []() { ZoneScoped - sgct_core::Viewport* viewport = - sgct::Engine::instance()->getCurrentWindowPtr()->getViewport(0); + Viewport* viewport = currentWindow->viewports().front().get(); if (viewport != nullptr) { - if (viewport->hasSubViewports() && viewport->getNonLinearProjectionPtr()) { - int res = viewport->getNonLinearProjectionPtr()->getCubemapResolution(); + if (viewport->hasSubViewports() && viewport->nonLinearProjection()) { + int res = viewport->nonLinearProjection()->cubemapResolution(); return glm::ivec2(res, res); } - else if (sgct::Engine::instance()->getCurrentWindowPtr()->getNumberOfViewports() > 1) { - int x, y; - auto window = sgct::Engine::instance()->getCurrentWindowPtr(); - window->getFinalFBODimensions(x, y); - return glm::ivec2(x*viewport->getXSize(), y*viewport->getYSize()); + else if (currentWindow->viewports().size() > 1) { + // @TODO (abock, 2020-04-09) This should probably be based on the current + // viewport? + ivec2 dim = currentWindow->finalFBODimensions(); + return glm::ivec2(dim.x * viewport->size().x, dim.y * viewport->size().y); } else { - int x, y; - auto window = sgct::Engine::instance()->getCurrentWindowPtr(); - window->getFinalFBODimensions(x, y); - return glm::ivec2(x, y); + ivec2 dim = currentWindow->finalFBODimensions(); + return glm::ivec2(dim.x, dim.y); } } return glm::ivec2(-1, -1); @@ -1025,35 +976,23 @@ void setSgctDelegateFunctions() { sgctDelegate.currentViewportSize = []() { ZoneScoped - sgct_core::Viewport* viewport = - sgct::Engine::instance()->getCurrentWindowPtr()->getViewport(0); - if (viewport != nullptr) { - int x = 0; - int y = 0; - sgct::Engine::instance()->getCurrentViewportSize(x, y); - return glm::ivec2(x, y); + if (currentViewport != nullptr) { + vec2 size = currentViewport->size(); + return glm::ivec2(size.x, size.y); } return glm::ivec2(-1, -1); }; sgctDelegate.dpiScaling = []() { ZoneScoped - return glm::vec2( - sgct::Engine::instance()->getCurrentWindowPtr()->getXScale(), - sgct::Engine::instance()->getCurrentWindowPtr()->getYScale() - ); - }; - sgctDelegate.currentNumberOfAaSamples = []() { - ZoneScoped - - return sgct::Engine::instance()->getCurrentWindowPtr()->getNumberOfAASamples(); + vec2 scale = currentWindow->scale(); + return glm::vec2(scale.x, scale.y); }; sgctDelegate.hasGuiWindow = []() { ZoneScoped - auto engine = sgct::Engine::instance(); - for (size_t i = 0; i < engine->getNumberOfWindows(); ++i) { - if (engine->getWindowPtr(i)->checkIfTagExists("GUI")) { + for (const std::unique_ptr& window : Engine::instance().windows()) { + if (window->hasTag("GUI")) { return true; } } @@ -1062,77 +1001,36 @@ void setSgctDelegateFunctions() { sgctDelegate.isGuiWindow = []() { ZoneScoped - return sgct::Engine::instance()->getCurrentWindowPtr()->checkIfTagExists("GUI"); + return currentWindow->hasTag("GUI"); }; sgctDelegate.isMaster = []() { ZoneScoped - return sgct::Engine::instance()->isMaster(); - }; - sgctDelegate.isUsingSwapGroups = []() { - ZoneScoped - - return sgct::SGCTWindow::isUsingSwapGroups(); - }; - sgctDelegate.isSwapGroupMaster = []() { - ZoneScoped - - return sgct::SGCTWindow::isSwapGroupMaster(); - }; - sgctDelegate.viewProjectionMatrix = []() { - ZoneScoped - - return sgct::Engine::instance()->getCurrentModelViewProjectionMatrix(); + return Engine::instance().isMaster(); }; sgctDelegate.modelMatrix = []() { ZoneScoped - return sgct::Engine::instance()->getModelMatrix(); + return currentModelMatrix; }; sgctDelegate.setNearFarClippingPlane = [](float nearPlane, float farPlane) { ZoneScoped - sgct::Engine::instance()->setNearAndFarClippingPlanes(nearPlane, farPlane); - }; - sgctDelegate.setEyeSeparationDistance = [](float distance) { - ZoneScoped - - sgct::Engine::instance()->setEyeSeparation(distance); - }; - sgctDelegate.viewportPixelCoordinates = []() { - ZoneScoped - - sgct::SGCTWindow* window = sgct::Engine::instance()->getCurrentWindowPtr(); - if (!window || !window->getCurrentViewport()) { - return glm::ivec4(0); - } - else { - const int* data = sgct::Engine::instance()->getCurrentViewportPixelCoords(); - return glm::ivec4(data[0], data[2], data[1], data[3]); - } - }; - sgctDelegate.sendMessageToExternalControl = [](const std::vector& message) { - ZoneScoped - - sgct::Engine::instance()->sendMessageToExternalControl( - message.data(), - static_cast(message.size()) - ); + Engine::instance().setNearAndFarClippingPlanes(nearPlane, farPlane); }; sgctDelegate.isFisheyeRendering = []() { ZoneScoped - sgct::SGCTWindow* w = sgct::Engine::instance()->getCurrentWindowPtr(); - return dynamic_cast( - w->getViewport(0)->getNonLinearProjectionPtr() + return dynamic_cast( + currentWindow->viewports().front()->nonLinearProjection() ) != nullptr; }; sgctDelegate.takeScreenshot = [](bool applyWarping) { ZoneScoped - sgct::SGCTSettings::instance()->setCaptureFromBackBuffer(applyWarping); - sgct::Engine::instance()->takeScreenshot(); - return sgct::Engine::instance()->getScreenShotNumber(); + Settings::instance().setCaptureFromBackBuffer(applyWarping); + Engine::instance().takeScreenshot(); + return Engine::instance().screenShotNumber(); }; sgctDelegate.swapBuffer = []() { ZoneScoped @@ -1144,12 +1042,12 @@ void setSgctDelegateFunctions() { sgctDelegate.nWindows = []() { ZoneScoped - return static_cast(sgct::Engine::instance()->getNumberOfWindows()); + return static_cast(Engine::instance().windows().size()); }; sgctDelegate.currentWindowId = []() { ZoneScoped - return sgct::Engine::instance()->getCurrentWindowPtr()->getId(); + return currentWindow->id(); }; sgctDelegate.openGLProcedureAddress = [](const char* func) { ZoneScoped @@ -1160,23 +1058,22 @@ void setSgctDelegateFunctions() { ZoneScoped return static_cast( - sgct::Engine::instance()->getWindowPtr(0)->getHorizFieldOfViewDegrees() + Engine::instance().windows().front()->horizFieldOfViewDegrees() ); }; sgctDelegate.setHorizFieldOfView = [](float hFovDeg) { ZoneScoped - sgct::SGCTWindow* w = sgct::Engine::instance()->getWindowPtr(0); - w->setHorizFieldOfView(hFovDeg); + Engine::instance().windows().front()->setHorizFieldOfView(hFovDeg); }; #ifdef WIN32 sgctDelegate.getNativeWindowHandle = [](size_t windowIndex) -> void* { ZoneScoped - sgct::SGCTWindow* w = sgct::Engine::instance()->getWindowPtr(windowIndex); + Window* w = Engine::instance().windows()[windowIndex].get(); if (w) { - HWND hWnd = glfwGetWin32Window(w->getWindowHandle()); - return reinterpret_cast(hWnd); + HWND hWnd = glfwGetWin32Window(w->windowHandle()); + return reinterpret_cast(hWnd); } return nullptr; }; @@ -1184,19 +1081,17 @@ void setSgctDelegateFunctions() { sgctDelegate.frustumMode = []() { ZoneScoped - using FM = sgct_core::Frustum::FrustumMode; - switch (sgct::Engine::instance()->getCurrentFrustumMode()) { - case FM::MonoEye: return WindowDelegate::Frustum::Mono; - case FM::StereoLeftEye: return WindowDelegate::Frustum::LeftEye; - case FM::StereoRightEye: return WindowDelegate::Frustum::RightEye; + switch (currentFrustumMode) { + default: + case Frustum::Mode::MonoEye: return WindowDelegate::Frustum::Mono; + case Frustum::Mode::StereoLeftEye: return WindowDelegate::Frustum::LeftEye; + case Frustum::Mode::StereoRightEye: return WindowDelegate::Frustum::RightEye; } }; - sgctDelegate.swapGroupFrameNumber = []() { + sgctDelegate.swapGroupFrameNumber = []() -> uint64_t { ZoneScoped - unsigned int fn = 0; - sgct::Engine::instance()->getCurrentWindowPtr()->getSwapGroupFrameNumber(fn); - return static_cast(fn); + return currentWindow->swapGroupFrameNumber(); }; } @@ -1366,59 +1261,45 @@ int main(int argc, char** argv) { arguments.insert(arguments.begin() + 2, absPath(windowConfiguration)); // Need to set this before the creation of the sgct::Engine - sgct::MessageHandler::instance()->setLogToConsole(false); - sgct::MessageHandler::instance()->setShowTime(false); - sgct::MessageHandler::instance()->setLogToCallback(true); - sgct::MessageHandler::instance()->setLogCallback(mainLogCallback); + + Log::instance().setLogToConsole(false); + Log::instance().setShowTime(false); + Log::instance().setLogCallback(mainLogCallback); #ifdef __APPLE__ glfwWindowHint(GLFW_STENCIL_BITS, 8); #endif LDEBUG("Creating SGCT Engine"); - SgctEngine = new sgct::Engine(arguments); + std::vector arg(argv + 1, argv + argc); + Configuration config = parseArguments(arg); + config::Cluster cluster = loadCluster(windowConfiguration); - // Bind functions - SgctEngine->setContextCreationCallback(mainContextCreationFunc); - SgctEngine->setInitOGLFunction(mainInitFunc); - SgctEngine->setPreSyncFunction(mainPreSyncFunc); - SgctEngine->setPostSyncPreDrawFunction(mainPostSyncPreDrawFunc); - SgctEngine->setDrawFunction(mainRenderFunc); - SgctEngine->setDraw2DFunction(mainDraw2DFunc); - SgctEngine->setPostDrawFunction(mainPostDrawFunc); - SgctEngine->setKeyboardCallbackFunction(mainKeyboardCallback); - SgctEngine->setMouseButtonCallbackFunction(mainMouseButtonCallback); - SgctEngine->setMousePosCallbackFunction(mainMousePosCallback); - SgctEngine->setMouseScrollCallbackFunction(mainMouseScrollCallback); - SgctEngine->setCharCallbackFunction(mainCharCallback); + Engine::Callbacks callbacks; + callbacks.initOpenGL = mainInitFunc; + callbacks.preSync = mainPreSyncFunc; + callbacks.postSyncPreDraw = mainPostSyncPreDrawFunc; + callbacks.draw = mainRenderFunc; + callbacks.draw2D = mainDraw2DFunc; + callbacks.postDraw = mainPostDrawFunc; + callbacks.keyboard = mainKeyboardCallback; + callbacks.mouseButton = mainMouseButtonCallback; + callbacks.mousePos = mainMousePosCallback; + callbacks.mouseScroll = mainMouseScrollCallback; + callbacks.character = mainCharCallback; + callbacks.encode = mainEncodeFun; + callbacks.decode = mainDecodeFun; + Log::instance().setNotifyLevel(Log::Level::Debug); - // Disable the immediate exit of the application when the ESC key is pressed - SgctEngine->setExitKey(SGCT_KEY_UNKNOWN); - - sgct::MessageHandler::instance()->setNotifyLevel(sgct::MessageHandler::NOTIFY_ALL); - - // Set encode and decode functions - // NOTE: starts synchronizing before init functions - sgct::SharedData::instance()->setEncodeFunction(mainEncodeFun); - sgct::SharedData::instance()->setDecodeFunction(mainDecodeFun); - - // Try to open a window - LDEBUG("Initialize SGCT Engine"); - std::map, sgct::Engine::RunMode> versionMapping = { - { { 3, 3 }, sgct::Engine::RunMode::OpenGL_3_3_Core_Profile }, - { { 4, 0 }, sgct::Engine::RunMode::OpenGL_4_0_Core_Profile }, - { { 4, 1 }, sgct::Engine::RunMode::OpenGL_4_1_Core_Profile }, - { { 4, 2 }, sgct::Engine::RunMode::OpenGL_4_2_Core_Profile }, - { { 4, 3 }, sgct::Engine::RunMode::OpenGL_4_3_Core_Profile }, - { { 4, 4 }, sgct::Engine::RunMode::OpenGL_4_4_Core_Profile }, - { { 4, 5 }, sgct::Engine::RunMode::OpenGL_4_5_Core_Profile }, - { { 4, 6 }, sgct::Engine::RunMode::OpenGL_4_6_Core_Profile } - }; - - - std::pair version = supportedOpenGLVersion(); - LINFO(fmt::format("Detected OpenGL version: {}.{}", version.first, version.second)); - bool initSuccess = SgctEngine->init(versionMapping[version]); + try { + Engine::create(cluster, callbacks, config); + } + catch (...) { + Engine::destroy(); + global::openSpaceEngine.deinitialize(); + ghoul::deinitialize(); + throw; + } #ifdef __APPLE__ // Workaround for OpenGL bug that Apple introduced in 10.14 Mojave that prevents an @@ -1431,9 +1312,8 @@ int main(int argc, char** argv) { // machine. If the loading screen shows up without doing anything to the window, it // is fixed. With the bug, the rendering stays gray even well after the main render // loop has started -- 2018-10-28 abock - size_t n = sgct::Engine::instance()->getNumberOfWindows(); - for (size_t i = 0; i < n; ++i) { - GLFWwindow* w = sgct::Engine::instance()->getWindowPtr(i)->getWindowHandle(); + for (const std::unique_ptr& window : Engine::instance().windows()) { + GLFWwindow* w = window->windowHandle(); int x, y; glfwGetWindowPos(w, &x, &y); glfwSetWindowPos(w, x + 1, y + 1); @@ -1448,53 +1328,39 @@ int main(int argc, char** argv) { // Do not print message if slaves are waiting for the master // Only timeout after 15 minutes - SgctEngine->setSyncParameters(false, 15.f * 60.f); + Engine::instance().setSyncParameters(false, 15.f * 60.f); - auto cleanup = [&](bool isInitialized) { - if (isInitialized) { - global::openSpaceEngine.deinitializeGL(); - global::openSpaceEngine.deinitialize(); - } + LINFO("Starting rendering loop"); + Engine::instance().render(); + LINFO("Ending rendering loop"); - // Clear function bindings to avoid crash after destroying the OpenSpace Engine - sgct::MessageHandler::instance()->setLogToCallback(false); - sgct::MessageHandler::instance()->setLogCallback(nullptr); + global::openSpaceEngine.deinitializeGL(); + global::openSpaceEngine.deinitialize(); - LDEBUG("Destroying SGCT Engine"); - delete SgctEngine; + // Clear function bindings to avoid crash after destroying the OpenSpace Engine + Log::instance().setLogCallback(nullptr); + + LDEBUG("Destroying SGCT Engine"); + Engine::destroy(); #ifdef OPENVR_SUPPORT - // Clean up OpenVR - sgct::SGCTOpenVR::shutdown(); + // Clean up OpenVR + sgct::SGCTOpenVR::shutdown(); #endif #ifdef OPENSPACE_HAS_SPOUT - for (SpoutWindow& w : SpoutWindows) { - if (w.leftOrMain.handle) { - w.leftOrMain.handle->ReleaseReceiver(); - w.leftOrMain.handle->Release(); - } - if (w.right.handle) { - w.right.handle->ReleaseReceiver(); - w.right.handle->Release(); - } + for (SpoutWindow& w : SpoutWindows) { + if (w.leftOrMain.handle) { + w.leftOrMain.handle->ReleaseReceiver(); + w.leftOrMain.handle->Release(); } + if (w.right.handle) { + w.right.handle->ReleaseReceiver(); + w.right.handle->Release(); + } + } #endif // OPENSPACE_HAS_SPOUT - ghoul::deinitialize(); - }; - - if (!initSuccess) { - LFATAL("Initializing failed"); - cleanup(false); - return EXIT_FAILURE; - } - - LINFO("Starting rendering loop"); - SgctEngine->render(); - LINFO("Ending rendering loop"); - - cleanup(true); - + ghoul::deinitialize(); exit(EXIT_SUCCESS); } diff --git a/config/fullscreen1080.xml b/config/fullscreen1080.xml index 35506aeb09..3b7f94c4cc 100644 --- a/config/fullscreen1080.xml +++ b/config/fullscreen1080.xml @@ -1,24 +1,24 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/config/gui_projector.xml b/config/gui_projector.xml index 42c3971235..9f50aa7037 100644 --- a/config/gui_projector.xml +++ b/config/gui_projector.xml @@ -1,33 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/openvr_htcVive.xml b/config/openvr_htcVive.xml index ee6ea4df20..c5ab46597a 100644 --- a/config/openvr_htcVive.xml +++ b/config/openvr_htcVive.xml @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/config/openvr_oculusRiftCv1.xml b/config/openvr_oculusRiftCv1.xml index 9db0689cbc..665715fb53 100644 --- a/config/openvr_oculusRiftCv1.xml +++ b/config/openvr_oculusRiftCv1.xml @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/config/single.xml b/config/single.xml index a434c31d0b..6ec2d5a125 100644 --- a/config/single.xml +++ b/config/single.xml @@ -1,24 +1,24 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/config/single_fisheye.xml b/config/single_fisheye.xml index 8a03730f5e..e27230e520 100644 --- a/config/single_fisheye.xml +++ b/config/single_fisheye.xml @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - + + + + --> + + + + + + + + + + + + + + + + + + + diff --git a/config/single_fisheye_gui.xml b/config/single_fisheye_gui.xml index b4a201f4c6..6eb46bbabb 100644 --- a/config/single_fisheye_gui.xml +++ b/config/single_fisheye_gui.xml @@ -1,53 +1,53 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + --> + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + diff --git a/config/single_gui.xml b/config/single_gui.xml index 6c200087d5..3404e572e3 100644 --- a/config/single_gui.xml +++ b/config/single_gui.xml @@ -1,33 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/single_sbs_stereo.xml b/config/single_sbs_stereo.xml index 87ee3a33ec..595d92cafb 100644 --- a/config/single_sbs_stereo.xml +++ b/config/single_sbs_stereo.xml @@ -1,30 +1,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/single_two_win.xml b/config/single_two_win.xml index ae110d2148..ed1b09fc04 100644 --- a/config/single_two_win.xml +++ b/config/single_two_win.xml @@ -1,32 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/spherical_mirror.xml b/config/spherical_mirror.xml index 2243582544..fc98729758 100644 --- a/config/spherical_mirror.xml +++ b/config/spherical_mirror.xml @@ -1,34 +1,34 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/spherical_mirror_gui.xml b/config/spherical_mirror_gui.xml index 14a48ad2e2..c946cbecd2 100644 --- a/config/spherical_mirror_gui.xml +++ b/config/spherical_mirror_gui.xml @@ -1,6 +1,6 @@ - + @@ -27,7 +27,7 @@ - + diff --git a/config/spout_output.xml b/config/spout_output.xml index f40a169c32..bac296112f 100644 --- a/config/spout_output.xml +++ b/config/spout_output.xml @@ -1,29 +1,19 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/config/two_nodes.xml b/config/two_nodes.xml index 5feb265138..e47946d5ef 100644 --- a/config/two_nodes.xml +++ b/config/two_nodes.xml @@ -1,41 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/data/assets/asteroids.scene b/data/assets/asteroids.scene new file mode 100644 index 0000000000..d7c1175baf --- /dev/null +++ b/data/assets/asteroids.scene @@ -0,0 +1,34 @@ +asset.require('./base') + +local earthAsset = asset.require('scene/solarsystem/planets/earth/earth') + +asset.require('scene/solarsystem/sssb/amor_asteroid') +asset.require('scene/solarsystem/sssb/apollo_asteroid') +asset.require('scene/solarsystem/sssb/aten_asteroid') +asset.require('scene/solarsystem/sssb/atira_asteroid') +asset.require('scene/solarsystem/sssb/centaur_asteroid') +asset.require('scene/solarsystem/sssb/chiron-type_comet') +asset.require('scene/solarsystem/sssb/encke-type_comet') +asset.require('scene/solarsystem/sssb/halley-type_comet') +asset.require('scene/solarsystem/sssb/inner_main_belt_asteroid') +asset.require('scene/solarsystem/sssb/jupiter_trojan_asteroid') +asset.require('scene/solarsystem/sssb/jupiter-family_comet') +asset.require('scene/solarsystem/sssb/main_belt_asteroid') +asset.require('scene/solarsystem/sssb/mars-crossing_asteroid') +asset.require('scene/solarsystem/sssb/outer_main_belt_asteroid') +asset.require('scene/solarsystem/sssb/transneptunian_object_asteroid') +asset.require('scene/solarsystem/sssb/pha') + +asset.onInitialize(function () + local now = openspace.time.currentWallTime() + -- Jump back one day to be able to show complete weather data on Earth. + openspace.time.setTime(openspace.time.advancedTime(now, "-1d")) + + openspace.globebrowsing.goToGeo("Earth", 58.5877, 16.1924, 2.7e12) + + openspace.markInterestingNodes({ "Earth", "Mars", "Moon", "Sun" }) +end) + +asset.onDeinitialize(function () + openspace.removeInterestingNodes({ "Earth", "Mars", "Moon", "Sun" }) +end) diff --git a/data/assets/default.scene b/data/assets/default.scene index 606d5852d5..31a2e83d4f 100644 --- a/data/assets/default.scene +++ b/data/assets/default.scene @@ -2,7 +2,6 @@ asset.require('./base') local earthAsset = asset.require('scene/solarsystem/planets/earth/earth') asset.require('scene/solarsystem/planets/earth/satellites/satellites.asset') -asset.require('scene/solarsystem/sssb/pha') asset.onInitialize(function () local now = openspace.time.currentWallTime() diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/satellites.asset b/data/assets/scene/solarsystem/planets/earth/satellites/satellites.asset index 44c81c4ef8..601b4033f4 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/satellites.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/satellites.asset @@ -1 +1 @@ -asset.request('./satellites_interesting') +asset.require('./satellites_interesting') diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/satellites_interesting.asset b/data/assets/scene/solarsystem/planets/earth/satellites/satellites_interesting.asset index 7d257cfc8b..71151f4358 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/satellites_interesting.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/satellites_interesting.asset @@ -1,6 +1,6 @@ -asset.request('./misc/brightest') -asset.request('./communications/geostationary') -asset.request('./navigation/gps') -asset.request('./misc/spacestations') -asset.request('./misc/iss') -asset.request('./misc/tle-new') +asset.require('./misc/brightest') +asset.require('./communications/geostationary') +asset.require('./navigation/gps') +asset.require('./misc/spacestations') +asset.require('./misc/iss') +asset.require('./misc/tle-new') diff --git a/data/assets/scene/solarsystem/sssb/amor_asteroid.asset b/data/assets/scene/solarsystem/sssb/amor_asteroid.asset new file mode 100644 index 0000000000..b091b688fc --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/amor_asteroid.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'amor_asteroid', 'sssb_data_amor_asteroid') +local object = sharedSssb.createSssbGroupObject('sssb_data_amor_asteroid.csv', "Amor Asteroids", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 4 +object.Renderable.TrailFade = 11 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/apollo_asteroid.asset b/data/assets/scene/solarsystem/sssb/apollo_asteroid.asset new file mode 100644 index 0000000000..8c86d4e990 --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/apollo_asteroid.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'apollo_asteroid', 'sssb_data_apollo_asteroid') +local object = sharedSssb.createSssbGroupObject('sssb_data_apollo_asteroid.csv', "Apollo Asteroids", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 6 +object.Renderable.TrailFade = 10 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/aten_asteroid.asset b/data/assets/scene/solarsystem/sssb/aten_asteroid.asset new file mode 100644 index 0000000000..1dd7af7f10 --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/aten_asteroid.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'aten_asteroid', 'sssb_data_aten_asteroid') +local object = sharedSssb.createSssbGroupObject('sssb_data_aten_asteroid.csv', "Aten Asteroids", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 2 +object.Renderable.TrailFade = 18 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/atira_asteroid.asset b/data/assets/scene/solarsystem/sssb/atira_asteroid.asset new file mode 100644 index 0000000000..1029f31430 --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/atira_asteroid.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'atira_asteroid', 'sssb_data_atira_asteroid') +local object = sharedSssb.createSssbGroupObject('sssb_data_atira_asteroid.csv', "Atira Asteroids", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 2 +object.Renderable.TrailFade = 25 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/c2019y4atlas.asset b/data/assets/scene/solarsystem/sssb/c2019y4atlas.asset new file mode 100644 index 0000000000..27acaa4adf --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/c2019y4atlas.asset @@ -0,0 +1,48 @@ +local assetHelper = asset.require('util/asset_helper') +local sunTransforms = asset.require('scene/solarsystem/sun/transforms') + +local orbit = asset.syncedResource({ + Name = "Comet C/2019 Y4 ATLAS", + Type = "HttpSynchronization", + Identifier = "horizons_c2019y4atlas", + Version = 1 +}) .. "/c2019y4atlas.txt" + +local C2019Y4AtlasTrail = { + Identifier = "C2019Y4AtlasTrail", + Parent = sunTransforms.SolarSystemBarycenter.Identifier, + Renderable = { + Type = "RenderableTrailTrajectory", + Translation = { + Type = "HorizonsTranslation", + HorizonsTextFile = orbit + }, + Color = { 0.533333, 0.850980, 0.996078 }, + EnableFade = false, + StartTime = "1950 JAN 1 0:00:00", + EndTime = "2100 JAN 1 00:00:00", + SampleInterval = 35000, + TimeStampSubsampleFactor = 1 + }, + GUI = { + Name = "C2019 Y4 Atlas Trail", + Path = "/Solar System/Comets" + } +} + +local C2019Y4AtlasPosition = { + Identifier = "C2019Y4AtlasPosition", + Parent = sunTransforms.SolarSystemBarycenter.Identifier, + Transform = { + Translation = { + Type = "HorizonsTranslation", + HorizonsTextFile = orbit + }, + }, + GUI = { + Name = "C 2019 Y4 Atlas", + Path = "/Solar System/Comets" + } +} + +assetHelper.registerSceneGraphNodesAndExport(asset, {C2019Y4AtlasPosition, C2019Y4AtlasTrail }) diff --git a/data/assets/scene/solarsystem/sssb/centaur_asteroid.asset b/data/assets/scene/solarsystem/sssb/centaur_asteroid.asset new file mode 100644 index 0000000000..68d97d2d9c --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/centaur_asteroid.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'centaur_asteroid', 'sssb_data_centaur_asteroid') +local object = sharedSssb.createSssbGroupObject('sssb_data_centaur_asteroid.csv', "Centaur Asteroids", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 6 +object.Renderable.TrailFade = 18 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/chiron-type_comet.asset b/data/assets/scene/solarsystem/sssb/chiron-type_comet.asset new file mode 100644 index 0000000000..e19c58b335 --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/chiron-type_comet.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'chiron-type_comet', 'sssb_data_chiron-type_comet') +local object = sharedSssb.createSssbGroupObject('sssb_data_chiron-type_comet.csv', "Chiron-type Comets", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 10 +object.Renderable.TrailFade = 25 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/encke-type_comet.asset b/data/assets/scene/solarsystem/sssb/encke-type_comet.asset new file mode 100644 index 0000000000..451433e6f1 --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/encke-type_comet.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'encke-type_comet', 'sssb_data_encke-type_comet') +local object = sharedSssb.createSssbGroupObject('sssb_data_encke-type_comet.csv', "Encke-type Comets", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 2 +object.Renderable.TrailFade = 23 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/halley-type_comet.asset b/data/assets/scene/solarsystem/sssb/halley-type_comet.asset new file mode 100644 index 0000000000..c92a0e1c83 --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/halley-type_comet.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'halley-type_comet', 'sssb_data_halley-type_comet') +local object = sharedSssb.createSssbGroupObject('sssb_data_halley-type_comet.csv', "Halley-type Comets", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 9 +object.Renderable.TrailFade = 18 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/inner_main_belt_asteroid.asset b/data/assets/scene/solarsystem/sssb/inner_main_belt_asteroid.asset new file mode 100644 index 0000000000..02426fdbeb --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/inner_main_belt_asteroid.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'inner_main_belt_asteroid', 'sssb_data_inner_main_belt_asteroid') +local object = sharedSssb.createSssbGroupObject('sssb_data_inner_main_belt_asteroid.csv', "Inner Main Asteroid Belt", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 1 +object.Renderable.TrailFade = 0.5 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/jupiter-family_comet.asset b/data/assets/scene/solarsystem/sssb/jupiter-family_comet.asset new file mode 100644 index 0000000000..b42e8ac0be --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/jupiter-family_comet.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'jupiter-family_comet', 'sssb_data_jupiter-family_comet') +local object = sharedSssb.createSssbGroupObject('sssb_data_jupiter-family_comet.csv', "Jupiter-family Comets", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 10 +object.Renderable.TrailFade = 28 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/jupiter_trojan_asteroid.asset b/data/assets/scene/solarsystem/sssb/jupiter_trojan_asteroid.asset new file mode 100644 index 0000000000..6be40249c7 --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/jupiter_trojan_asteroid.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'jupiter_trojan_asteroid', 'sssb_data_jupiter_trojan_asteroid') +local object = sharedSssb.createSssbGroupObject('sssb_data_jupiter_trojan_asteroid.csv', "Jupiter Trojan Asteroids", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 1 +object.Renderable.TrailFade = 5 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/main_belt_asteroid.asset b/data/assets/scene/solarsystem/sssb/main_belt_asteroid.asset new file mode 100644 index 0000000000..503a00dc04 --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/main_belt_asteroid.asset @@ -0,0 +1,11 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'main_belt_asteroid', 'sssb_data_main_belt_asteroid') +local object = sharedSssb.createSssbGroupObject('sssb_data_main_belt_asteroid.csv', "Main Asteroid Belt", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 1 +object.Renderable.TrailFade = 0.1 +object.Renderable.UpperLimit = 50000 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/mars-crossing_asteroid.asset b/data/assets/scene/solarsystem/sssb/mars-crossing_asteroid.asset new file mode 100644 index 0000000000..98cdda1f80 --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/mars-crossing_asteroid.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'mars-crossing_asteroid', 'sssb_data_mars-crossing_asteroid') +local object = sharedSssb.createSssbGroupObject('sssb_data_mars-crossing_asteroid.csv', "Mars-crossing Asteroids", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 1 +object.Renderable.TrailFade = 13 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/outer_main_belt_asteroid.asset b/data/assets/scene/solarsystem/sssb/outer_main_belt_asteroid.asset new file mode 100644 index 0000000000..995b7623ea --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/outer_main_belt_asteroid.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'outer_main_belt_asteroid', 'sssb_data_outer_main_belt_asteroid') +local object = sharedSssb.createSssbGroupObject('sssb_data_outer_main_belt_asteroid.csv', "Outer Main Asteroid Belt", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 1 +object.Renderable.TrailFade = 2 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/pha.asset b/data/assets/scene/solarsystem/sssb/pha.asset index 5ba2b2e4eb..4a66174fdf 100644 --- a/data/assets/scene/solarsystem/sssb/pha.asset +++ b/data/assets/scene/solarsystem/sssb/pha.asset @@ -2,7 +2,9 @@ local assetHelper = asset.require('util/asset_helper') local sharedSssb = asset.require('./sssb_shared') local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'pha', 'sssb_data_pha') -local object = sharedSssb.createSssbGroupObject("sssb_data_pha.csv", filepath, { 0.75, 0.2, 0.2 }) +local object = sharedSssb.createSssbGroupObject('sssb_data_pha.csv', "Potentially Hazardous Asteroids", filepath, { 0.75, 0.2, 0.2 }) object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 3 +object.Renderable.TrailFade = 17 assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/scene/solarsystem/sssb/sssb_shared.asset b/data/assets/scene/solarsystem/sssb/sssb_shared.asset index d67679baff..ea494d0fff 100644 --- a/data/assets/scene/solarsystem/sssb/sssb_shared.asset +++ b/data/assets/scene/solarsystem/sssb/sssb_shared.asset @@ -13,7 +13,7 @@ function downloadSssbDatabaseFile(sceneAsset, name, identifier) }) end -local createSssbGroupObject = function(filename, sssbFolder, trailColor) +local createSssbGroupObject = function(filename, guiName, sssbFolder, trailColor) assert(filename, "'filename' needs to be provided") assert(sssbFolder, "'sssbFolder' needs to be provided") trailColor = trailColor or { 0.75, 0.1, 0.1 } @@ -27,10 +27,11 @@ local createSssbGroupObject = function(filename, sssbFolder, trailColor) Path = sssbFolder.."/"..filename, Segments = 200, Color = trailColor, - Fade = 0.5, + TrailFade = 0.5, }, GUI = { - Path = "/Solar System/Small Solar System Body" + Path = "/Solar System/Small Bodies", + Name = guiName } } end diff --git a/data/assets/scene/solarsystem/sssb/transneptunian_object_asteroid.asset b/data/assets/scene/solarsystem/sssb/transneptunian_object_asteroid.asset new file mode 100644 index 0000000000..5ef5e3b1e9 --- /dev/null +++ b/data/assets/scene/solarsystem/sssb/transneptunian_object_asteroid.asset @@ -0,0 +1,10 @@ +local assetHelper = asset.require('util/asset_helper') +local sharedSssb = asset.require('./sssb_shared') + +local filepath = sharedSssb.downloadSssbDatabaseFile(asset, 'transneptunian_object_asteroid', 'sssb_data_transneptunian_object_asteroid') +local object = sharedSssb.createSssbGroupObject('sssb_data_transneptunian_object_asteroid.csv', "Transneptunian Object Asteroids", filepath, { 0.9, 0.3, 0.1 }) +object.Renderable.Enabled = false +object.Renderable.SegmentQuality = 8 +object.Renderable.TrailFade = 10 + +assetHelper.registerSceneGraphNodesAndExport(asset, { object }) diff --git a/data/assets/util/tle_helper.asset b/data/assets/util/tle_helper.asset index 92293479c3..9aa08a3c71 100644 --- a/data/assets/util/tle_helper.asset +++ b/data/assets/util/tle_helper.asset @@ -11,7 +11,8 @@ function downloadTLEFile(sceneAsset, url, name, filename) Name = "Satellite TLE Data (" .. name .. ")", Type = "UrlSynchronization", Identifier = "satellite_tle_data_" .. identifier, - Url = url + Url = url, + Override = true } if (filename ~= '') then @@ -81,7 +82,7 @@ function satellites(title, file, color, group) Renderable = { Type = "RenderableSatellites", Path = file, - Segments = 120, + SegmentQuality = 3, Color = color, Fade = 1.5 }, diff --git a/ext/ghoul b/ext/ghoul index 0461bf1f44..df1522a1fe 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 0461bf1f44b58e04fb21d929b0f385e1120da7b4 +Subproject commit df1522a1fe6f02b4d03cd36478d9d36f4384e93e diff --git a/include/openspace/engine/globals.h b/include/openspace/engine/globals.h index 60b0a8479a..0bf76957f5 100644 --- a/include/openspace/engine/globals.h +++ b/include/openspace/engine/globals.h @@ -124,7 +124,8 @@ static VersionChecker& versionChecker = detail::gVersionChecker(); static VirtualPropertyManager& virtualPropertyManager = detail::gVirtualPropertyManager(); static WindowDelegate& windowDelegate = detail::gWindowDelegate(); static configuration::Configuration& configuration = detail::gConfiguration(); -static interaction::InteractionMonitor& interactionMonitor = detail::gInteractionMonitor(); +static interaction::InteractionMonitor& interactionMonitor = + detail::gInteractionMonitor(); static interaction::JoystickInputStates& joystickInputStates = detail::gJoystickInputStates(); static interaction::WebsocketInputStates& websocketInputStates = diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index efceb720b4..76c06f8fd7 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -88,8 +88,8 @@ public: void touchDetectionCallback(TouchInput input); void touchUpdateCallback(TouchInput input); void touchExitCallback(TouchInput input); - std::vector encode(); - void decode(std::vector data); + std::vector encode(); + void decode(std::vector data); void scheduleLoadSingleAsset(std::string assetPath); void toggleShutdownMode(); @@ -125,6 +125,8 @@ private: bool _hasScheduledAssetLoading = false; std::string _scheduledAssetPathToLoad; + glm::vec2 _mousePosition; + //grabs json from each module to pass to the documentation engine. std::string _documentationJson; diff --git a/include/openspace/engine/syncengine.h b/include/openspace/engine/syncengine.h index 5b5b4f2d89..67902b34ee 100644 --- a/include/openspace/engine/syncengine.h +++ b/include/openspace/engine/syncengine.h @@ -53,13 +53,13 @@ public: * Encodes all added Syncables in the injected SyncBuffer. * This method is only called on the SGCT master node */ - std::vector encodeSyncables(); + std::vector encodeSyncables(); /** * Decodes the SyncBuffer into the added Syncables. * This method is only called on the SGCT slave nodes */ - void decodeSyncables(std::vector data); + void decodeSyncables(std::vector data); /** * Invokes the presync method of all added Syncables diff --git a/include/openspace/engine/windowdelegate.h b/include/openspace/engine/windowdelegate.h index 1bef12d181..0fd27ba589 100644 --- a/include/openspace/engine/windowdelegate.h +++ b/include/openspace/engine/windowdelegate.h @@ -40,8 +40,6 @@ struct WindowDelegate { void (*setSynchronization)(bool enabled) = [](bool) {}; - void (*clearAllWindows)(const glm::vec4& clearColor) = [](const glm::vec4&) {}; - bool (*windowHasResized)() = []() { return false; }; double (*averageDeltaTime)() = []() { return 0.0; }; @@ -56,52 +54,29 @@ struct WindowDelegate { double (*applicationTime)() = []() { return 0.0; }; - glm::vec2 (*mousePosition)() = []() { return glm::vec2(0.f); }; - - uint32_t (*mouseButtons)(int maxNumber) = [](int) { return uint32_t(0); }; - glm::ivec2 (*currentWindowSize)() = []() { return glm::ivec2(0); }; glm::ivec2 (*currentSubwindowSize)() = []() { return glm::ivec2(0); }; - glm::ivec2 (*currentWindowResolution)() = []() { return glm::ivec2(0); }; - glm::ivec2 (*currentDrawBufferResolution)() = []() { return glm::ivec2(0); }; glm::ivec2 (*currentViewportSize)() = []() { return glm::ivec2(0); }; glm::vec2 (*dpiScaling)() = []() { return glm::vec2(1.f); }; - int (*currentNumberOfAaSamples)() = []() { return 1; }; - bool (*hasGuiWindow)() = []() { return false; }; bool (*isGuiWindow)() = []() { return false; }; - bool (*isMaster)() = []() { return false; }; - - int (*clusterId)() = []() { return 0; }; - - bool (*isUsingSwapGroups)() = []() { return false; }; - - bool (*isSwapGroupMaster)() = []() { return false; }; - - glm::mat4 (*viewProjectionMatrix)() = []() { return glm::mat4(1.f); }; + bool (*isMaster)() = []() { return true; }; glm::mat4 (*modelMatrix)() = []() { return glm::mat4(1.f); }; void (*setNearFarClippingPlane)(float near, float far) = [](float, float) {}; - void (*setEyeSeparationDistance)(float distance) = [](float) {}; - - glm::ivec4 (*viewportPixelCoordinates)() = []() { return glm::ivec4(0, 0, 0, 0); }; - - void (*sendMessageToExternalControl)(const std::vector& message) = - [](const std::vector&) {}; - bool (*isFisheyeRendering)() = []() { return false; }; - unsigned int(*takeScreenshot)(bool applyWarping) = [](bool) { return 0u; }; + unsigned int (*takeScreenshot)(bool applyWarping) = [](bool) { return 0u; }; void (*swapBuffer)() = []() {}; @@ -112,9 +87,9 @@ struct WindowDelegate { double (*getHorizFieldOfView)() = []() { return 0.0; }; void (*setHorizFieldOfView)(float hFovDeg) = [](float) { }; - - void* (*getNativeWindowHandle)(size_t windowIndex) = [](size_t) -> void* { - return nullptr; + + void* (*getNativeWindowHandle)(size_t windowIndex) = [](size_t) -> void* { + return nullptr; }; using GLProcAddress = void(*)(void); diff --git a/include/openspace/interaction/mousecamerastates.h b/include/openspace/interaction/mousecamerastates.h index f592dc0ed1..719dcd6926 100644 --- a/include/openspace/interaction/mousecamerastates.h +++ b/include/openspace/interaction/mousecamerastates.h @@ -34,6 +34,11 @@ public: MouseCameraStates(double sensitivity, double velocityScaleFactor); void updateStateFromInput(const InputState& inputState, double deltaTime) override; + + void setInvertMouseButton(bool value); + +private: + bool _isMouseButtonInverted = false; }; } // namespace openspace::interaction diff --git a/include/openspace/interaction/navigationhandler.h b/include/openspace/interaction/navigationhandler.h index 66b1e3942b..24d3ef495b 100644 --- a/include/openspace/interaction/navigationhandler.h +++ b/include/openspace/interaction/navigationhandler.h @@ -135,7 +135,7 @@ public: WebsocketCameraStates::AxisInvert::No, WebsocketCameraStates::AxisNormalize shouldNormalize = WebsocketCameraStates::AxisNormalize::No); - + NavigationState navigationState() const; NavigationState navigationState(const SceneGraphNode& referenceFrame) const; diff --git a/include/openspace/interaction/orbitalnavigator.h b/include/openspace/interaction/orbitalnavigator.h index 623cc5fd3f..c453691809 100644 --- a/include/openspace/interaction/orbitalnavigator.h +++ b/include/openspace/interaction/orbitalnavigator.h @@ -79,10 +79,10 @@ public: JoystickCameraStates& joystickStates(); const JoystickCameraStates& joystickStates() const; - + WebsocketCameraStates& websocketStates(); const WebsocketCameraStates& websocketStates() const; - + ScriptCameraStates& scriptStates(); const ScriptCameraStates& scriptStates() const; @@ -160,6 +160,8 @@ private: properties::FloatProperty _stereoInterpolationTime; properties::FloatProperty _followRotationInterpolationTime; + properties::BoolProperty _invertMouseButtons; + MouseCameraStates _mouseStates; JoystickCameraStates _joystickStates; WebsocketCameraStates _websocketStates; @@ -246,19 +248,22 @@ private: * Translates the horizontal direction. If far from the anchor object, this will * result in an orbital rotation around the object. This function does not affect the * rotation but only the position. - * \returns a position vector adjusted in the horizontal direction. + * + * \return a position vector adjusted in the horizontal direction. */ glm::dvec3 translateHorizontally(double deltaTime, const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition, const glm::dquat& globalCameraRotation, const SurfacePositionHandle& positionHandle) const; /** - * Moves the camera along a vector, camPosToCenterPosDiff, until it reaches the focusLimit. - * The velocity of the zooming depend on distFromCameraToFocus and the final frame - * where the camera stops moving depends on the distance set in the variable focusLimit. - * The bool determines whether to move/fly towards the focus node or away from it. - * \returns a new position of the camera, closer to the focusLimit than the previous - * position. + * Moves the camera along a vector, camPosToCenterPosDiff, until it reaches the + * focusLimit. The velocity of the zooming depend on distFromCameraToFocus and the + * final frame where the camera stops moving depends on the distance set in the + * variable focusLimit. The bool determines whether to move/fly towards the focus node + * or away from it. + * + * \return a new position of the camera, closer to the focusLimit than the previous + * position */ glm::dvec3 moveCameraAlongVector(const glm::dvec3& camPos, double distFromCameraToFocus, const glm::dvec3& camPosToCenterPosDiff, @@ -267,14 +272,16 @@ private: /* * Adds rotation to the camera position so that it follows the rotation of the anchor * node defined by the differential anchorNodeRotationDiff. - * \returns a position updated with the rotation defined by anchorNodeRotationDiff + * + * \return a position updated with the rotation defined by anchorNodeRotationDiff */ glm::dvec3 followAnchorNodeRotation(const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition, const glm::dquat& anchorNodeRotationDiff) const; /** * Updates the global rotation so that it points towards the anchor node. - * \returns a global rotation quaternion defining a rotation towards the anchor node. + * + * \return a global rotation quaternion defining a rotation towards the anchor node */ glm::dquat rotateGlobally(const glm::dquat& globalCameraRotation, const glm::dquat& aimNodeRotationDiff, @@ -290,7 +297,8 @@ private: /** * Rotates the camera around the out vector of the surface. - * \returns a quaternion adjusted to rotate around the out vector of the surface. + * + * \return a quaternion adjusted to rotate around the out vector of the surface */ glm::dquat rotateHorizontally(double deltaTime, const glm::dquat& globalCameraRotation, @@ -298,8 +306,9 @@ private: /** * Push the camera out to the surface of the object. - * \returns a position vector adjusted to be at least minHeightAboveGround meters - * above the actual surface of the object + * + * \return a position vector adjusted to be at least minHeightAboveGround meters + * above the actual surface of the object */ glm::dvec3 pushToSurface(double minHeightAboveGround, const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition, diff --git a/include/openspace/interaction/websocketcamerastates.h b/include/openspace/interaction/websocketcamerastates.h index 0b0bc5c4a9..d7bbd66613 100644 --- a/include/openspace/interaction/websocketcamerastates.h +++ b/include/openspace/interaction/websocketcamerastates.h @@ -106,7 +106,8 @@ private: namespace ghoul { template <> -std::string to_string(const openspace::interaction::WebsocketCameraStates::AxisType& type); +std::string to_string( + const openspace::interaction::WebsocketCameraStates::AxisType& type); template <> openspace::interaction::WebsocketCameraStates::AxisType diff --git a/include/openspace/interaction/websocketinputstate.h b/include/openspace/interaction/websocketinputstate.h index 576e0c4c24..3068e22294 100644 --- a/include/openspace/interaction/websocketinputstate.h +++ b/include/openspace/interaction/websocketinputstate.h @@ -84,9 +84,9 @@ constexpr const int MaxWebsockets = 16; struct WebsocketInputStates : public std::unordered_map { /** * This function adds the contributions of all connected websockets for the provided - * \p axis. After adding each websockets contribution, the result is clamped to [-1,1]. - * If a websocket does not possess a particular axis, it's does not contribute to the - * sum. + * \p axis. After adding each websockets contribution, the result is clamped to + * [-1,1]. If a websocket does not possess a particular axis, it's does not contribute + * to the sum. * * \param axis The numerical axis for which the values are added * \return The summed axis values of all connected websockets diff --git a/include/openspace/rendering/abufferrenderer.h b/include/openspace/rendering/abufferrenderer.h index 275d41c897..3505c13292 100644 --- a/include/openspace/rendering/abufferrenderer.h +++ b/include/openspace/rendering/abufferrenderer.h @@ -80,7 +80,6 @@ public: void setLightness(float lightness) override; void setColorSpace(unsigned int colorspace) override; - void enableBloom(bool enable) override; void enableHistogram(bool enable) override; diff --git a/include/openspace/rendering/framebufferrenderer.h b/include/openspace/rendering/framebufferrenderer.h index 70330f2243..52df76befd 100644 --- a/include/openspace/rendering/framebufferrenderer.h +++ b/include/openspace/rendering/framebufferrenderer.h @@ -71,17 +71,17 @@ public: void updateHDRAndFiltering(); void updateFXAA(); void updateDownscaledVolume(); - + void setResolution(glm::ivec2 res) override; void setHDRExposure(float hdrExposure) override; void setGamma(float gamma) override; void setHue(float hue) override; void setValue(float value) override; void setSaturation(float sat) override; - + void enableFXAA(bool enable) override; void setDisableHDR(bool disable) override; - + void update() override; void performRaycasterTasks(const std::vector& tasks); void performDeferredTasks(const std::vector& tasks); @@ -114,7 +114,7 @@ private: void updateDownscaleTextures(); void updateExitVolumeTextures(); void writeDownscaledVolume(); - + std::map _raycastData; RaycasterProgObjMap _exitPrograms; RaycasterProgObjMap _raycastPrograms; @@ -131,7 +131,7 @@ private: UniformCache(hdrFeedingTexture, blackoutFactor, hdrExposure, gamma, Hue, Saturation, Value) _hdrUniformCache; UniformCache(renderedTexture, inverseScreenSize) _fxaaUniformCache; - UniformCache(downscaledRenderedVolume, downscaledRenderedVolumeDepth) + UniformCache(downscaledRenderedVolume, downscaledRenderedVolumeDepth) _writeDownscaledVolumeUniformCache; GLint _defaultFBO; @@ -158,7 +158,7 @@ private: GLuint hdrFilteringFramebuffer; GLuint hdrFilteringTexture; } _hdrBuffers; - + struct { GLuint fxaaFramebuffer; GLuint fxaaTexture; @@ -176,18 +176,18 @@ private: bool _dirtyDeferredcastData; bool _dirtyRaycastData; bool _dirtyResolution; - + glm::ivec2 _resolution = glm::ivec2(0); int _nAaSamples; bool _enableFXAA = true; bool _disableHDR = false; - + float _hdrExposure = 3.7f; float _gamma = 0.95f; float _hue = 1.f; float _saturation = 1.f; float _value = 1.f; - + ghoul::Dictionary _rendererData; }; diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index 5216060d6d..29f12f2c4a 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -211,7 +211,7 @@ private: properties::BoolProperty _disableMasterRendering; properties::FloatProperty _globalBlackOutFactor; - + properties::BoolProperty _enableFXAA; properties::BoolProperty _disableHDRPipeline; @@ -221,13 +221,13 @@ private: properties::FloatProperty _hue; properties::FloatProperty _saturation; properties::FloatProperty _value; - + properties::FloatProperty _horizFieldOfView; properties::Vec3Property _globalRotation; properties::Vec3Property _screenSpaceRotation; properties::Vec3Property _masterRotation; - + uint64_t _frameNumber = 0; unsigned int _latestScreenshotNumber = 0; diff --git a/include/openspace/rendering/volumeraycaster.h b/include/openspace/rendering/volumeraycaster.h index 29c159f442..1534c51ff8 100644 --- a/include/openspace/rendering/volumeraycaster.h +++ b/include/openspace/rendering/volumeraycaster.h @@ -139,7 +139,7 @@ public: private: /** - * Maximum number of integration steps to be executed by the volume integrator. + * Maximum number of integration steps to be executed by the volume integrator. */ int _rayCastMaxSteps = 1000; diff --git a/include/openspace/scene/scale.h b/include/openspace/scene/scale.h index ee4a113b20..117db6bafd 100644 --- a/include/openspace/scene/scale.h +++ b/include/openspace/scene/scale.h @@ -48,8 +48,8 @@ public: virtual bool initialize(); - double scaleValue() const; - virtual double scaleValue(const UpdateData& data) const = 0; + glm::dvec3 scaleValue() const; + virtual glm::dvec3 scaleValue(const UpdateData& data) const = 0; virtual void update(const UpdateData& data); static documentation::Documentation Documentation(); @@ -60,7 +60,7 @@ protected: private: bool _needsUpdate = true; double _cachedTime = -std::numeric_limits::max(); - double _cachedScale = 1.0; + glm::dvec3 _cachedScale = glm::dvec3(1.0); }; } // namespace openspace diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index 86bffe0658..81a3fa92c4 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -122,13 +122,13 @@ public: glm::dvec3 position() const; const glm::dmat3& rotationMatrix() const; - double scale() const; + glm::dvec3 scale() const; glm::dvec3 worldPosition() const; const glm::dmat3& worldRotationMatrix() const; glm::dmat4 modelTransform() const; glm::dmat4 inverseModelTransform() const; - double worldScale() const; + glm::dvec3 worldScale() const; bool isTimeFrameActive(const Time& time) const; SceneGraphNode* parent() const; @@ -152,7 +152,7 @@ public: private: glm::dvec3 calculateWorldPosition() const; glm::dmat3 calculateWorldRotation() const; - double calculateWorldScale() const; + glm::dvec3 calculateWorldScale() const; void computeScreenSpaceData(RenderData& newData); std::atomic _state = State::Loaded; @@ -185,7 +185,7 @@ private: // Cached transform data glm::dvec3 _worldPositionCached = glm::dvec3(0.0); glm::dmat3 _worldRotationCached = glm::dmat3(1.0); - double _worldScaleCached = 1.0; + glm::dvec3 _worldScaleCached = glm::dvec3(1.0); float _fixedBoundingSphere = 0.f; @@ -198,7 +198,7 @@ private: properties::DoubleProperty _distFromCamToNode; properties::DoubleProperty _screenSizeRadius; properties::FloatProperty _visibilityDistance; - + // This variable is used for the rate-limiting of the screenspace positions (if they // are calculated when _computeScreenSpaceValues is true) std::chrono::high_resolution_clock::time_point _lastScreenSpaceUpdateTime; diff --git a/include/openspace/util/syncbuffer.h b/include/openspace/util/syncbuffer.h index 4f2a7ed370..c73d05270c 100644 --- a/include/openspace/util/syncbuffer.h +++ b/include/openspace/util/syncbuffer.h @@ -57,14 +57,14 @@ public: //void write(); //void read(); - void setData(std::vector data); - std::vector data(); + void setData(std::vector data); + std::vector data(); private: size_t _n; size_t _encodeOffset = 0; size_t _decodeOffset = 0; - std::vector _dataStream; + std::vector _dataStream; }; } // namespace openspace diff --git a/include/openspace/util/touch.h b/include/openspace/util/touch.h index cb9a6e71da..2f5f1d6deb 100644 --- a/include/openspace/util/touch.h +++ b/include/openspace/util/touch.h @@ -32,6 +32,9 @@ namespace openspace { +// The TouchInput represents a single finger/device-input at a specific point in time. +// the fingerId and touchDeviceId coupled with the timestamp allows this to be compared +// with other TouchInputs in order to calculate gesture-like behaviour. struct TouchInput { TouchInput(size_t touchDeviceId, size_t fingerId, float x, float y, double timestamp); glm::vec2 screenCoordinates(glm::vec2 resolution) const; @@ -46,19 +49,25 @@ struct TouchInput { float y; float dx = 0.f; // movement in x direction since last touch input float dy = 0.f; // movement in y direction since last touch input - double timestamp; // timestamp in seconds from global touch initialization + double timestamp; // timestamp in seconds from global touch initialization }; +// The TouchInputHolder holds one or many TouchInputs, in order to track the history of +// the finger/input device class TouchInputHolder { public: TouchInputHolder(TouchInput input); - // tryAddInput: // Succeeds upon a different input than last. // Fails upon a too similar input as last. + // Updates time for the last input if same position. bool tryAddInput(TouchInput input); + void clearInputs(); + // Checks whether or not this Holder actually holds a specific input (based on IDs) + // Succeeds when `input` is held by this Holder + // Fails if `input` is not held by this Holder bool holdsInput(const TouchInput &input) const; size_t touchDeviceId() const; @@ -72,12 +81,14 @@ public: double gestureTime() const; size_t numInputs() const; + const TouchInput& firstInput() const; const TouchInput& latestInput() const; const std::deque& peekInputs() const; private: //A deque of recorded inputs. Adding newer points to the front of the queue std::deque _inputs; + TouchInput _firstInput; size_t _touchDeviceId; size_t _fingerId; diff --git a/include/openspace/util/updatestructures.h b/include/openspace/util/updatestructures.h index 0e5281554f..3baf2ac3cc 100644 --- a/include/openspace/util/updatestructures.h +++ b/include/openspace/util/updatestructures.h @@ -38,7 +38,7 @@ struct InitializeData {}; struct TransformData { glm::dvec3 translation = glm::dvec3(0.0); glm::dmat3 rotation = glm::dmat3(1.0); - double scale = 0.0; + glm::dvec3 scale = glm::dvec3(1.0); }; struct UpdateData { diff --git a/modules/base/CMakeLists.txt b/modules/base/CMakeLists.txt index 472ed85e74..bf54a33b9d 100644 --- a/modules/base/CMakeLists.txt +++ b/modules/base/CMakeLists.txt @@ -62,6 +62,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rotation/luarotation.h ${CMAKE_CURRENT_SOURCE_DIR}/rotation/staticrotation.h ${CMAKE_CURRENT_SOURCE_DIR}/scale/luascale.h + ${CMAKE_CURRENT_SOURCE_DIR}/scale/nonuniformstaticscale.h ${CMAKE_CURRENT_SOURCE_DIR}/scale/staticscale.h ${CMAKE_CURRENT_SOURCE_DIR}/scale/timedependentscale.h ${CMAKE_CURRENT_SOURCE_DIR}/timeframe/timeframeinterval.h @@ -111,6 +112,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rotation/luarotation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rotation/staticrotation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/scale/luascale.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/scale/nonuniformstaticscale.cpp ${CMAKE_CURRENT_SOURCE_DIR}/scale/staticscale.cpp ${CMAKE_CURRENT_SOURCE_DIR}/scale/timedependentscale.cpp ${CMAKE_CURRENT_SOURCE_DIR}/timeframe/timeframeinterval.cpp diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp index cf79f7b00c..4c2e465b80 100644 --- a/modules/base/basemodule.cpp +++ b/modules/base/basemodule.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -155,6 +156,7 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) { ghoul_assert(fScale, "Scale factory was not created"); fScale->registerClass("LuaScale"); + fScale->registerClass("NonUniformStaticScale"); fScale->registerClass("StaticScale"); fScale->registerClass("TimeDependentScale"); diff --git a/modules/base/rendering/renderablelabels.cpp b/modules/base/rendering/renderablelabels.cpp index 2fa6c17ba4..e44e49fb17 100644 --- a/modules/base/rendering/renderablelabels.cpp +++ b/modules/base/rendering/renderablelabels.cpp @@ -48,7 +48,7 @@ namespace { constexpr const char* _loggerCat = "base::RenderableLabels"; - + constexpr const char* MeterUnit = "m"; constexpr const char* KilometerUnit = "Km"; constexpr const char* MegameterUnit = "Mm"; @@ -203,7 +203,7 @@ documentation::Documentation RenderableLabels::Documentation() { LabelColorInfo.identifier, new DoubleVector4Verifier, Optional::Yes, - LabelColorInfo.description, + LabelColorInfo.description, }, { LabelColorInfo.identifier, @@ -392,7 +392,7 @@ RenderableLabels::RenderableLabels(const ghoul::Dictionary& dictionary) addProperty(_labelText); addProperty(_labelOrientationOption); - + _labelColor.setViewOption(properties::Property::ViewOptions::Color); if (dictionary.hasKey(LabelColorInfo.identifier)) { _labelColor = dictionary.value(LabelColorInfo.identifier); @@ -634,17 +634,15 @@ void RenderableLabels::render(const RenderData& data, RendererTasks&) { //} float fadeInVariable = 1.f; - + if (_enableFadingEffect) { - float distanceNodeToCamera = glm::distance( - data.camera.positionVec3(), - data.modelTransform.translation + float distanceNodeToCamera = static_cast( + glm::distance(data.camera.positionVec3(), data.modelTransform.translation) ); float sUnit = unit(_fadeStartUnitOption); float eUnit = unit(_fadeEndUnitOption); float startX = _fadeStartDistance * sUnit; float endX = _fadeEndDistance * eUnit; - //fadeInVariable = changedPerlinSmoothStepFunc(distanceNodeToCamera, startX, endX); fadeInVariable = linearSmoothStepFunc( distanceNodeToCamera, startX, @@ -676,7 +674,7 @@ void RenderableLabels::render(const RenderData& data, RendererTasks&) { glm::dvec3 orthoUp = glm::normalize(glm::cross(cameraViewDirectionWorld, orthoRight)); renderLabels(data, modelViewProjectionMatrix, orthoRight, orthoUp, fadeInVariable); - + //if (additiveBlending) { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthMask(true); @@ -688,18 +686,18 @@ void RenderableLabels::setLabelText(const std::string & newText) { _labelText = newText; } -void RenderableLabels::renderLabels(const RenderData& data, +void RenderableLabels::renderLabels(const RenderData& data, const glm::dmat4& modelViewProjectionMatrix, const glm::dvec3& orthoRight, const glm::dvec3& orthoUp, float fadeInVariable) { glm::vec4 textColor = _labelColor; - + textColor.a *= fadeInVariable; textColor.a *= _opacity; ghoul::fontrendering::FontRenderer::ProjectedLabelsInformation labelInfo; - + labelInfo.orthoRight = orthoRight; labelInfo.orthoUp = orthoUp; labelInfo.minSize = static_cast(_labelMinSize); @@ -716,7 +714,7 @@ void RenderableLabels::renderLabels(const RenderData& data, glm::vec3 transformedPos( _transformationMatrix * glm::dvec4(data.modelTransform.translation, 1.0) ); - + ghoul::fontrendering::FontRenderer::defaultProjectionRenderer().render( *_font, transformedPos, @@ -727,11 +725,11 @@ void RenderableLabels::renderLabels(const RenderData& data, } float RenderableLabels::changedPerlinSmoothStepFunc(float x, float startX, - float endX) const + float endX) const { - float f1 = 6.f * powf((x - startX), 5.f) - 15.f * powf((x - startX), 4.f) + + float f1 = 6.f * powf((x - startX), 5.f) - 15.f * powf((x - startX), 4.f) + 10.f * powf((x - startX), 3.f); - float f2 = -6.f * powf((x - endX), 5.f) + 15.f * powf((x - endX), 4.f) - + float f2 = -6.f * powf((x - endX), 5.f) + 15.f * powf((x - endX), 4.f) - 10.f * powf((x - endX), 3.f) + 1.f; float f3 = 1.f; @@ -743,7 +741,8 @@ float RenderableLabels::changedPerlinSmoothStepFunc(float x, float startX, } else if (x >= endX) { return std::clamp(f2, 0.f, 1.f); - } + } + return x; } float RenderableLabels::linearSmoothStepFunc(float x, float startX, float endX, @@ -754,7 +753,7 @@ float RenderableLabels::linearSmoothStepFunc(float x, float startX, float endX, float f1 = sdiv * (x - startX) + 1.f; float f2 = ediv * (x - endX) + 1.f; float f3 = 1.f; - + if (x <= startX) { return std::clamp(f1, 0.f, 1.f); } @@ -764,17 +763,18 @@ float RenderableLabels::linearSmoothStepFunc(float x, float startX, float endX, else if (x >= endX) { return std::clamp(f2, 0.f, 1.f); } + return x; } float RenderableLabels::unit(int unit) const { switch (static_cast(unit)) { case Meter: return 1.f; - case Kilometer: return 1e3; - case Megameter: return 1e6; - case Gigameter: return 1e9; + case Kilometer: return 1e3f; + case Megameter: return 1e6f; + case Gigameter: return 1e9f; case AU: return 149597870700.f; - case Terameter: return 1e12; - case Petameter: return 1e15; + case Terameter: return 1e12f; + case Petameter: return 1e15f; case Parsec: return static_cast(PARSEC); case Kiloparsec: return static_cast(1e3 * PARSEC); case Megaparsec: return static_cast(1e6 * PARSEC); diff --git a/modules/base/rendering/renderablelabels.h b/modules/base/rendering/renderablelabels.h index c35d52d451..7d0466b9d0 100644 --- a/modules/base/rendering/renderablelabels.h +++ b/modules/base/rendering/renderablelabels.h @@ -100,7 +100,7 @@ private: const glm::dvec3& orthoRight, const glm::dvec3& orthoUp, float fadeInVariable); float changedPerlinSmoothStepFunc(float x, float startX, float endX) const; - + float linearSmoothStepFunc(float x, float startX, float endX, float sUnit, float eUnit) const; diff --git a/modules/base/rendering/renderablenodeline.cpp b/modules/base/rendering/renderablenodeline.cpp index 4dc4291a55..7fc1f26068 100644 --- a/modules/base/rendering/renderablenodeline.cpp +++ b/modules/base/rendering/renderablenodeline.cpp @@ -146,7 +146,9 @@ RenderableNodeLine::RenderableNodeLine(const ghoul::Dictionary& dictionary) _lineColor = dictionary.value(LineColorInfo.identifier); } if (dictionary.hasKey(LineWidthInfo.identifier)) { - _lineWidth = static_cast(dictionary.value(LineWidthInfo.identifier)); + _lineWidth = static_cast( + dictionary.value(LineWidthInfo.identifier) + ); } _start.onChange([&]() { validateNodes(); }); @@ -238,13 +240,13 @@ void RenderableNodeLine::updateVertexData() { global::renderEngine.scene()->sceneGraphNode(_end)->worldPosition() ); - _vertexArray.push_back(_startPos.x); - _vertexArray.push_back(_startPos.y); - _vertexArray.push_back(_startPos.z); + _vertexArray.push_back(static_cast(_startPos.x)); + _vertexArray.push_back(static_cast(_startPos.y)); + _vertexArray.push_back(static_cast(_startPos.z)); - _vertexArray.push_back(_endPos.x); - _vertexArray.push_back(_endPos.y); - _vertexArray.push_back(_endPos.z); + _vertexArray.push_back(static_cast(_endPos.x)); + _vertexArray.push_back(static_cast(_endPos.y)); + _vertexArray.push_back(static_cast(_endPos.z)); _vertexArray; @@ -264,7 +266,7 @@ void RenderableNodeLine::updateVertexData() { void RenderableNodeLine::render(const RenderData& data, RendererTasks&) { updateVertexData(); - + _program->activate(); glm::dmat4 anchorTranslation(1.0); @@ -316,7 +318,7 @@ void RenderableNodeLine::render(const RenderData& data, RendererTasks&) { // Bind and draw bindGL(); glDrawArrays(GL_LINES, 0, 2); - + // Restore GL State unbindGL(); _program->deactivate(); diff --git a/modules/base/rendering/renderabletrail.cpp b/modules/base/rendering/renderabletrail.cpp index b6fa66ff23..8ad12a9d93 100644 --- a/modules/base/rendering/renderabletrail.cpp +++ b/modules/base/rendering/renderabletrail.cpp @@ -344,7 +344,7 @@ void RenderableTrail::render(const RenderData& data, RendererTasks&) { } auto render = [renderLines, renderPoints, p = _programObject, &data, - &modelTransform, pointSize = _appearance.pointSize.value(), + &modelTransform, pointSize = _appearance.pointSize.value(), c = _uniformCache, lw = _appearance.lineWidth] (RenderInformation& info, int nVertices, int offset) { @@ -366,14 +366,13 @@ void RenderableTrail::render(const RenderData& data, RendererTasks&) { p->setUniform(c.nVertices, nVertices); - #ifndef __APPLE__ glm::ivec2 resolution = global::renderEngine.renderingResolution(); p->setUniform(c.resolution, resolution); p->setUniform(c.lineWidth, ceil((2.f * 1.f + lw) * std::sqrt(2.f))); #endif - + if (renderPoints) { // The stride parameter determines the distance between larger points and // smaller ones @@ -444,7 +443,7 @@ void RenderableTrail::render(const RenderData& data, RendererTasks&) { ); glm::dvec3 trailPosWorld = glm::dvec3( - modelTransform * _primaryRenderInformation._localTransform * + modelTransform * _primaryRenderInformation._localTransform * glm::dvec4(0.0, 0.0, 0.0, 1.0) ); const double distance = glm::distance( diff --git a/modules/base/rendering/renderabletrailorbit.cpp b/modules/base/rendering/renderabletrailorbit.cpp index db57d56381..9d58c6dc72 100644 --- a/modules/base/rendering/renderabletrailorbit.cpp +++ b/modules/base/rendering/renderabletrailorbit.cpp @@ -373,7 +373,7 @@ void RenderableTrailOrbit::update(const UpdateData& data) { std::for_each(_vertexArray.begin(), _vertexArray.end(), setMax); - setBoundingSphere(glm::distance(maxVertex, minVertex) / 2.0); + setBoundingSphere(glm::distance(maxVertex, minVertex) / 2.f); } RenderableTrailOrbit::UpdateReport RenderableTrailOrbit::updateTrails( diff --git a/modules/base/rendering/renderabletrailtrajectory.cpp b/modules/base/rendering/renderabletrailtrajectory.cpp index e8dae4adc8..966ffd51af 100644 --- a/modules/base/rendering/renderabletrailtrajectory.cpp +++ b/modules/base/rendering/renderabletrailtrajectory.cpp @@ -350,7 +350,7 @@ void RenderableTrailTrajectory::update(const UpdateData& data) { std::for_each(_vertexArray.begin(), _vertexArray.end(), setMax); - setBoundingSphere(glm::distance(maxVertex, minVertex) / 2.0); + setBoundingSphere(glm::distance(maxVertex, minVertex) / 2.f); } diff --git a/modules/base/scale/luascale.cpp b/modules/base/scale/luascale.cpp index cfd19f9aca..f13b485c9a 100644 --- a/modules/base/scale/luascale.cpp +++ b/modules/base/scale/luascale.cpp @@ -43,7 +43,7 @@ namespace { "scaling factor for this transformation. The script needs to define a function " "'scale' that takes the current simulation time in seconds past the J2000 epoch " "as the first argument, the current wall time as milliseconds past the J2000 " - "epoch the second argument and computes the scaling factor." + "epoch the second argument and computes the three scaling factors." }; } // namespace @@ -86,7 +86,7 @@ LuaScale::LuaScale(const ghoul::Dictionary& dictionary) : LuaScale() { _luaScriptFile = absPath(dictionary.value(ScriptInfo.identifier)); } -double LuaScale::scaleValue(const UpdateData& data) const { +glm::dvec3 LuaScale::scaleValue(const UpdateData& data) const { ghoul::lua::runScriptFile(_state, _luaScriptFile); // Get the scaling function @@ -97,7 +97,7 @@ double LuaScale::scaleValue(const UpdateData& data) const { "LuaScale", fmt::format("Script '{}' does not have a function 'scale'", _luaScriptFile) ); - return 0.0; + return glm::dvec3(1.0); } // First argument is the number of seconds past the J2000 epoch in ingame time @@ -120,7 +120,11 @@ double LuaScale::scaleValue(const UpdateData& data) const { ); } - return luaL_checknumber(_state, -1); + const double x = luaL_checknumber(_state, -1); + const double y = luaL_checknumber(_state, -2); + const double z = luaL_checknumber(_state, -3); + lua_settop(_state, 0); + return glm::dvec3(x, y, z); } } // namespace openspace diff --git a/modules/base/scale/luascale.h b/modules/base/scale/luascale.h index ce8a1fa061..1306ec476b 100644 --- a/modules/base/scale/luascale.h +++ b/modules/base/scale/luascale.h @@ -41,7 +41,7 @@ public: LuaScale(); LuaScale(const ghoul::Dictionary& dictionary); - double scaleValue(const UpdateData& data) const override; + glm::dvec3 scaleValue(const UpdateData& data) const override; static documentation::Documentation Documentation(); diff --git a/modules/base/scale/nonuniformstaticscale.cpp b/modules/base/scale/nonuniformstaticscale.cpp new file mode 100644 index 0000000000..cc9a2d487d --- /dev/null +++ b/modules/base/scale/nonuniformstaticscale.cpp @@ -0,0 +1,79 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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 + +namespace { + constexpr openspace::properties::Property::PropertyInfo ScaleInfo = { + "Scale", + "Scale", + "These values are used as scaling factors for the scene graph node that this " + "transformation is attached to relative to its parent." + }; +} // namespace + +namespace openspace { + +documentation::Documentation NonUniformStaticScale::Documentation() { + using namespace openspace::documentation; + return { + "Static Scaling", + "base_scale_static", + { + { + ScaleInfo.identifier, + new DoubleVector3Verifier, + Optional::No, + ScaleInfo.description + } + } + }; +} + +glm::dvec3 NonUniformStaticScale::scaleValue(const UpdateData&) const { + return _scaleValue; +} + +NonUniformStaticScale::NonUniformStaticScale() + : _scaleValue(ScaleInfo, glm::dvec3(1.0), glm::dvec3(0.1), glm::dvec3(100.0)) +{ + addProperty(_scaleValue); + + _scaleValue.onChange([this]() { + requireUpdate(); + }); +} + +NonUniformStaticScale::NonUniformStaticScale(const ghoul::Dictionary& dictionary) + : NonUniformStaticScale() +{ + documentation::testSpecificationAndThrow(Documentation(), dictionary, "StaticScale"); + + _scaleValue = dictionary.value(ScaleInfo.identifier); +} + +} // namespace openspace diff --git a/modules/base/scale/nonuniformstaticscale.h b/modules/base/scale/nonuniformstaticscale.h new file mode 100644 index 0000000000..ded7951c11 --- /dev/null +++ b/modules/base/scale/nonuniformstaticscale.h @@ -0,0 +1,50 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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_BASE___NONUNIFORMSTATICSCALE___H__ +#define __OPENSPACE_MODULE_BASE___NONUNIFORMSTATICSCALE___H__ + +#include + +#include + +namespace openspace { + +namespace documentation { struct Documentation; } + +class NonUniformStaticScale : public Scale { +public: + NonUniformStaticScale(); + NonUniformStaticScale(const ghoul::Dictionary& dictionary); + glm::dvec3 scaleValue(const UpdateData& data) const override; + + static documentation::Documentation Documentation(); + +private: + properties::DVec3Property _scaleValue; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_BASE___NONUNIFORMSTATICSCALE___H__ diff --git a/modules/base/scale/staticscale.cpp b/modules/base/scale/staticscale.cpp index bb282dfb9e..4c15f70fae 100644 --- a/modules/base/scale/staticscale.cpp +++ b/modules/base/scale/staticscale.cpp @@ -54,8 +54,8 @@ documentation::Documentation StaticScale::Documentation() { }; } -double StaticScale::scaleValue(const UpdateData&) const { - return _scaleValue; +glm::dvec3 StaticScale::scaleValue(const UpdateData&) const { + return glm::dvec3(_scaleValue); } StaticScale::StaticScale() : _scaleValue(ScaleInfo, 1.f, 0.1f, 100.f) { diff --git a/modules/base/scale/staticscale.h b/modules/base/scale/staticscale.h index 21e5bb6cde..f11e95a4ed 100644 --- a/modules/base/scale/staticscale.h +++ b/modules/base/scale/staticscale.h @@ -37,7 +37,7 @@ class StaticScale : public Scale { public: StaticScale(); StaticScale(const ghoul::Dictionary& dictionary); - double scaleValue(const UpdateData& data) const override; + glm::dvec3 scaleValue(const UpdateData& data) const override; static documentation::Documentation Documentation(); diff --git a/modules/base/scale/timedependentscale.cpp b/modules/base/scale/timedependentscale.cpp index 0fba563a0c..e6e731d667 100644 --- a/modules/base/scale/timedependentscale.cpp +++ b/modules/base/scale/timedependentscale.cpp @@ -108,7 +108,7 @@ TimeDependentScale::TimeDependentScale(const ghoul::Dictionary& dictionary) addProperty(_clampToPositive); } -double TimeDependentScale::scaleValue(const UpdateData& data) const { +glm::dvec3 TimeDependentScale::scaleValue(const UpdateData& data) const { if (_cachedReferenceDirty) { _cachedReference = Time::convertTime(_referenceDate); _cachedReferenceDirty = false; @@ -118,10 +118,10 @@ double TimeDependentScale::scaleValue(const UpdateData& data) const { const double dt = now - _cachedReference; if (_clampToPositive) { - return std::max(0.0, dt) * _speed; + return glm::dvec3(std::max(0.0, dt) * _speed); } else { - return dt * _speed; + return glm::dvec3(dt * _speed); } } diff --git a/modules/base/scale/timedependentscale.h b/modules/base/scale/timedependentscale.h index e2d219bf6e..3fda4e19ed 100644 --- a/modules/base/scale/timedependentscale.h +++ b/modules/base/scale/timedependentscale.h @@ -38,7 +38,7 @@ namespace documentation { struct Documentation; } class TimeDependentScale : public Scale { public: TimeDependentScale(const ghoul::Dictionary& dictionary); - double scaleValue(const UpdateData& data) const override; + glm::dvec3 scaleValue(const UpdateData& data) const override; static documentation::Documentation Documentation(); diff --git a/modules/cefwebgui/cefwebguimodule.cpp b/modules/cefwebgui/cefwebguimodule.cpp index 2d5b7c520d..839e5182c5 100644 --- a/modules/cefwebgui/cefwebguimodule.cpp +++ b/modules/cefwebgui/cefwebguimodule.cpp @@ -225,9 +225,9 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) if (isGuiWindow && isMaster && _instance) { if (global::windowDelegate.windowHasResized() || _instance->_shouldReshape) { + glm::ivec2 csws = global::windowDelegate.currentSubwindowSize(); _instance->reshape(static_cast( - static_cast(global::windowDelegate.currentSubwindowSize()) * - global::windowDelegate.dpiScaling() + static_cast(csws) * global::windowDelegate.dpiScaling() )); _instance->_shouldReshape = false; } diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp index 688d518611..2e5612e913 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp @@ -424,7 +424,10 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di , _drawLabels(DrawLabelInfo, false) , _pixelSizeControl(PixelSizeControlInfo, false) , _colorOption(ColorOptionInfo, properties::OptionProperty::DisplayType::Dropdown) - , _datavarSizeOption(SizeOptionInfo, properties::OptionProperty::DisplayType::Dropdown) + , _datavarSizeOption( + SizeOptionInfo, + properties::OptionProperty::DisplayType::Dropdown + ) , _fadeInDistance( FadeInDistancesInfo, glm::vec2(0.f), @@ -548,7 +551,7 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di ); } } - + if (dictionary.hasKey(ExactColorMapInfo.identifier)) { _isColorMapExact = dictionary.value(ExactColorMapInfo.identifier); } @@ -583,12 +586,12 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di _datavarSizeOption.onChange([&]() { _dataIsDirty = true; - _datavarSizeOptionString = _optionConversionSizeMap[_datavarSizeOption.value()]; - }); + _datavarSizeOptionString = _optionConversionSizeMap[_datavarSizeOption]; + }); addProperty(_datavarSizeOption); _hasDatavarSize = true; - } + } if (dictionary.hasKey(PolygonSidesInfo.identifier)) { _polygonSides = static_cast( @@ -673,13 +676,11 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di addProperty(_correctionSizeFactor); } - if (dictionary.hasKey(PixelSizeControlInfo.identifier)) { _pixelSizeControl = dictionary.value(PixelSizeControlInfo.identifier); addProperty(_pixelSizeControl); } - } bool RenderableBillboardsCloud::isReady() const { @@ -1086,7 +1087,7 @@ void RenderableBillboardsCloud::update(const UpdateData&) { sizeof(float) * 9, reinterpret_cast(sizeof(float) * 8) ); - } + } else if (_hasColorMapFile) { glEnableVertexAttribArray(positionAttrib); glVertexAttribPointer( @@ -1607,10 +1608,11 @@ void RenderableBillboardsCloud::createDataSlice() { } // what datavar in use for the index color - int colorMapInUse = _hasColorMapFile ? _variableDataPositionMap[_colorOptionString] : 0; - + int colorMapInUse = + _hasColorMapFile ? _variableDataPositionMap[_colorOptionString] : 0; + // what datavar in use for the size scaling (if present) - int sizeScalingInUse = _hasDatavarSize ? + int sizeScalingInUse = _hasDatavarSize ? _variableDataPositionMap[_datavarSizeOptionString] : -1; auto addDatavarSizeScalling = [&](size_t i, int datavarInUse) { @@ -1625,7 +1627,7 @@ void RenderableBillboardsCloud::createDataSlice() { float minColorIdx = std::numeric_limits::max(); float maxColorIdx = std::numeric_limits::min(); - + for (size_t i = 0; i < _fullData.size(); i += _nValuesPerAstronomicalObject) { float colorIdx = _fullData[i + 3 + colorMapInUse]; maxColorIdx = colorIdx >= maxColorIdx ? colorIdx : maxColorIdx; @@ -1671,7 +1673,7 @@ void RenderableBillboardsCloud::createDataSlice() { } else { float ncmap = static_cast(_colorMapData.size()); - float normalization = ((cmax != cmin) && (ncmap > 2)) ? + float normalization = ((cmax != cmin) && (ncmap > 2)) ? (ncmap - 2) / (cmax - cmin) : 0; colorIndex = (variableColor - cmin) * normalization + 1; colorIndex = colorIndex < 0 ? 0 : colorIndex; diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.h b/modules/digitaluniverse/rendering/renderablebillboardscloud.h index 15d4d241e6..7953806824 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.h +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.h @@ -144,7 +144,7 @@ private: correctionSizeFactor, color, alphaValue, scaleFactor, up, right, fadeInValue, screenSize, spriteTexture, hasColormap, enabledRectSizeControl, hasDvarScaling ) _uniformCache; - + std::shared_ptr _font; std::string _speckFile; diff --git a/modules/digitaluniverse/rendering/renderabledumeshes.cpp b/modules/digitaluniverse/rendering/renderabledumeshes.cpp index bdc7b80436..a9ce646b08 100644 --- a/modules/digitaluniverse/rendering/renderabledumeshes.cpp +++ b/modules/digitaluniverse/rendering/renderabledumeshes.cpp @@ -110,6 +110,12 @@ namespace { "objects being rendered." }; + constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = { + "LineWidth", + "Line Width", + "If the DU mesh is of wire type, this value determines the width of the lines" + }; + constexpr openspace::properties::Property::PropertyInfo DrawElementsInfo = { "DrawElements", "Draw Elements", @@ -215,6 +221,12 @@ documentation::Documentation RenderableDUMeshes::Documentation() { Optional::Yes, LabelMaxSizeInfo.description }, + { + LineWidthInfo.identifier, + new DoubleVerifier, + Optional::Yes, + LineWidthInfo.description + }, { TransformationMatrixInfo.identifier, new Matrix4x4Verifier, @@ -242,6 +254,7 @@ RenderableDUMeshes::RenderableDUMeshes(const ghoul::Dictionary& dictionary) , _drawLabels(DrawLabelInfo, false) , _textMinSize(LabelMinSizeInfo, 8.f, 0.5f, 24.f) , _textMaxSize(LabelMaxSizeInfo, 500.f, 0.f, 1000.f) + , _lineWidth(LineWidthInfo, 2.f, 0.f, 16.f) , _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown) { documentation::testSpecificationAndThrow( @@ -315,6 +328,13 @@ RenderableDUMeshes::RenderableDUMeshes(const ghoul::Dictionary& dictionary) } addProperty(_scaleFactor);*/ + if (dictionary.hasKeyAndValue(LineWidthInfo.identifier)) { + _lineWidth = static_cast( + dictionary.value(LineWidthInfo.identifier) + ); + } + addProperty(_lineWidth); + if (dictionary.hasKey(DrawLabelInfo.identifier)) { _drawLabels = dictionary.value(DrawLabelInfo.identifier); } @@ -473,7 +493,7 @@ void RenderableDUMeshes::renderMeshes(const RenderData&, case Solid: break; case Wire: - glLineWidth(2.0); + glLineWidth(_lineWidth); glDrawArrays(GL_LINE_STRIP, 0, pair.second.numV); glLineWidth(lineWidth); break; diff --git a/modules/digitaluniverse/rendering/renderabledumeshes.h b/modules/digitaluniverse/rendering/renderabledumeshes.h index 418f45eafe..bb0b6dce20 100644 --- a/modules/digitaluniverse/rendering/renderabledumeshes.h +++ b/modules/digitaluniverse/rendering/renderabledumeshes.h @@ -128,6 +128,7 @@ private: //properties::OptionProperty _blendMode; properties::FloatProperty _textMinSize; properties::FloatProperty _textMaxSize; + properties::FloatProperty _lineWidth; // DEBUG: properties::OptionProperty _renderOption; diff --git a/modules/galaxy/rendering/renderablegalaxy.cpp b/modules/galaxy/rendering/renderablegalaxy.cpp index 9023fe154d..ba5a801649 100644 --- a/modules/galaxy/rendering/renderablegalaxy.cpp +++ b/modules/galaxy/rendering/renderablegalaxy.cpp @@ -149,7 +149,10 @@ namespace { return; } - fileStream.write(reinterpret_cast(&CurrentCacheVersion), sizeof(int8_t)); + fileStream.write( + reinterpret_cast(&CurrentCacheVersion), + sizeof(int8_t) + ); fileStream.write(reinterpret_cast(&nPoints), sizeof(int64_t)); fileStream.write(reinterpret_cast(&pointsRatio), sizeof(float)); uint64_t nPositions = static_cast(positions.size()); @@ -291,7 +294,7 @@ RenderableGalaxy::RenderableGalaxy(const ghoul::Dictionary& dictionary) _downScaleVolumeRendering.setVisibility(properties::Property::Visibility::Developer); if (volumeDictionary.hasKey(DownscaleVolumeRenderingInfo.identifier)) { - _downScaleVolumeRendering = + _downScaleVolumeRendering = volumeDictionary.value(DownscaleVolumeRenderingInfo.identifier); } @@ -331,7 +334,7 @@ void RenderableGalaxy::initializeGL() { _aspect = static_cast(_volumeDimensions); _aspect /= std::max(std::max(_aspect.x, _aspect.y), _aspect.z); - // The volume + // The volume volume::RawVolumeReader> reader( _volumeFilename, _volumeDimensions @@ -460,9 +463,9 @@ void RenderableGalaxy::initializeGL() { } else { FileSys.cacheManager()->removeCacheFile(_pointsFilename); - Result res = loadPointFile(_pointsFilename); - pointPositions = std::move(res.positions); - pointColors = std::move(res.color); + Result resPoint = loadPointFile(_pointsFilename); + pointPositions = std::move(resPoint.positions); + pointColors = std::move(resPoint.color); saveCachedFile( cachedPointsFile, pointPositions, @@ -558,7 +561,7 @@ void RenderableGalaxy::update(const UpdateData& data) { _pointTransform[3] += translation; _raycaster->setDownscaleRender(_downScaleVolumeRendering); - _raycaster->setMaxSteps(_numberOfRayCastingSteps); + _raycaster->setMaxSteps(static_cast(_numberOfRayCastingSteps)); _raycaster->setStepSize(_stepSize); _raycaster->setAspect(_aspect); _raycaster->setModelTransform(volumeTransform); @@ -657,7 +660,7 @@ void RenderableGalaxy::renderPoints(const RenderData& data) { glm::dmat4(1.0), glm::pi(), glm::dvec3(1.0, 0.0, 0.0)) * - glm::rotate(glm::dmat4(1.0), 3.1248, glm::dvec3(0.0, 1.0, 0.0)) * + glm::rotate(glm::dmat4(1.0), 3.1248, glm::dvec3(0.0, 1.0, 0.0)) * glm::rotate(glm::dmat4(1.0), 4.45741, glm::dvec3(0.0, 0.0, 1.0) ); @@ -737,7 +740,7 @@ void RenderableGalaxy::renderBillboards(const RenderData& data) { glm::dmat4(1.0), glm::pi(), glm::dvec3(1.0, 0.0, 0.0)) * - glm::rotate(glm::dmat4(1.0), 3.1248, glm::dvec3(0.0, 1.0, 0.0)) * + glm::rotate(glm::dmat4(1.0), 3.1248, glm::dvec3(0.0, 1.0, 0.0)) * glm::rotate(glm::dmat4(1.0), 4.45741, glm::dvec3(0.0, 0.0, 1.0) ); @@ -795,7 +798,7 @@ float RenderableGalaxy::safeLength(const glm::vec3& vector) const { return glm::length(vector / maxComponent) * maxComponent; } -RenderableGalaxy::Result RenderableGalaxy::loadPointFile(const std::string& file) { +RenderableGalaxy::Result RenderableGalaxy::loadPointFile(const std::string&) { std::vector pointPositions; std::vector pointColors; int64_t nPoints; diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 4eb99dd7da..b7cea3cb2d 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -626,8 +626,7 @@ void GlobeBrowsingModule::goToGeodetic2(const globebrowsing::RenderableGlobe& gl } void GlobeBrowsingModule::goToGeodetic3(const globebrowsing::RenderableGlobe& globe, - globebrowsing::Geodetic3 geo3, - bool doResetCameraDirection) + globebrowsing::Geodetic3 geo3, bool) { using namespace globebrowsing; const glm::dvec3 positionModelSpace = globe.ellipsoid().cartesianPosition(geo3); diff --git a/modules/globebrowsing/shaders/texturetilemapping.hglsl b/modules/globebrowsing/shaders/texturetilemapping.hglsl index ff4b09eb42..a866211b85 100644 --- a/modules/globebrowsing/shaders/texturetilemapping.hglsl +++ b/modules/globebrowsing/shaders/texturetilemapping.hglsl @@ -377,16 +377,16 @@ vec4 calculateShadedColor(vec4 currentColor, vec3 ellipsoidNormalCameraSpace, vec3 shadedColor = currentColor.rgb * 0.05; vec3 n = normalize(ellipsoidNormalCameraSpace); - vec3 l = lightDirectionCameraSpace; - + float power = orenNayarDiffuse( -lightDirectionCameraSpace, - viewDirectionCameraSpace, + viewDirectionCameraSpace, ellipsoidNormalCameraSpace, roughness); + vec3 l = lightDirectionCameraSpace; power = max(smoothstep(0.0f, 0.1f, max(dot(-l, n), 0.0f)) * power, 0.0f); - + vec4 color = vec4(shadedColor + currentColor.rgb * power, currentColor.a); return color; } diff --git a/modules/globebrowsing/src/rawtiledatareader.cpp b/modules/globebrowsing/src/rawtiledatareader.cpp index 6cc980e36d..a602008e1a 100644 --- a/modules/globebrowsing/src/rawtiledatareader.cpp +++ b/modules/globebrowsing/src/rawtiledatareader.cpp @@ -394,7 +394,8 @@ PixelRegion highestResPixelRegion(const GeodeticPatch& geodeticPatch, return region; } -RawTile::ReadError postProcessErrorCheck(const RawTile& rawTile, size_t nRasters, +RawTile::ReadError postProcessErrorCheck(const RawTile& rawTile, + [[ maybe_unused ]] size_t nRasters, float noDataValue) { // This check was implicit before and just made explicit here diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index d205fc4a5a..b883b6acfb 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -697,7 +697,7 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) _ringsComponent.initialize(); addPropertySubOwner(_ringsComponent); _hasRings = true; - + ghoul::Dictionary ringsDic; dictionary.getValue("Rings", ringsDic); } @@ -799,7 +799,7 @@ void RenderableGlobe::render(const RenderData& data, RendererTasks& rendererTask if (_hasRings && _ringsComponent.isEnabled()) { _ringsComponent.draw(lightRenderData, RingsComponent::GeometryOnly); } - + glEnable(GL_BLEND); _shadowComponent.setViewDepthMap(false); @@ -897,15 +897,13 @@ void RenderableGlobe::update(const UpdateData& data) { } setBoundingSphere(static_cast( - _ellipsoid.maximumRadius() * data.modelTransform.scale + _ellipsoid.maximumRadius() * glm::compMax(data.modelTransform.scale) )); glm::dmat4 translation = glm::translate(glm::dmat4(1.0), data.modelTransform.translation); glm::dmat4 rotation = glm::dmat4(data.modelTransform.rotation); - glm::dmat4 scaling = - glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale, - data.modelTransform.scale, data.modelTransform.scale)); + glm::dmat4 scaling = glm::scale(glm::dmat4(1.0), data.modelTransform.scale); _cachedModelTransform = translation * rotation * scaling; _cachedInverseModelTransform = glm::inverse(_cachedModelTransform); @@ -968,7 +966,7 @@ const glm::dmat4& RenderableGlobe::modelTransform() const { // Rendering code ////////////////////////////////////////////////////////////////////////////////////////// -void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, +void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, const ShadowComponent::ShadowMapData& shadowData, bool renderGeomOnly) { @@ -986,7 +984,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, const float dsf = static_cast( _generalProperties.currentLodScaleFactor * _ellipsoid.minimumRadius() ); - + // We are setting the setIgnoreUniformLocationError as it is not super trivial // and brittle to figure out apriori whether the uniform was optimized away // or not. It should be something long the lines of: @@ -1108,9 +1106,9 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, const bool hasWaterLayer = !_layerManager.layerGroup( layergroupid::GroupID::WaterMasks ).activeLayers().empty(); - + _globalRenderer.program->setUniform("modelViewTransform", modelViewTransform); - + const bool hasHeightLayer = !_layerManager.layerGroup( layergroupid::HeightLayers ).activeLayers().empty(); @@ -1118,7 +1116,9 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, // Apply an extra scaling to the height if the object is scaled _globalRenderer.program->setUniform( "heightScale", - static_cast(data.modelTransform.scale * data.camera.scaling()) + static_cast( + glm::compMax(data.modelTransform.scale) * data.camera.scaling() + ) ); } @@ -1135,13 +1135,22 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, const glm::vec3 directionToSunCameraSpace = glm::vec3(viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); - _globalRenderer.program->setUniform( + // @TODO (abock, 2020-04-14); This is just a bandaid for issue #1136. The better + // way is to figure out with the uniform is optimized away. I assume that it is + // because the shader doesn't get recompiled when the last layer of the night + // or water is disabled; so the shader thinks it has to do the calculation, but + // there are actually no layers left + using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; + _localRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes); + _localRenderer.program->setUniform( "lightDirectionCameraSpace", -glm::normalize(directionToSunCameraSpace) ); + _localRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes); } + // Local shader _localRenderer.program->setUniform( "projectionTransform", @@ -1156,10 +1165,18 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, const glm::vec3 directionToSunCameraSpace = glm::vec3(viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); - _localRenderer.program->setUniform( + // @TODO (abock, 2020-04-14); This is just a bandaid for issue #1136. The better + // way is to figure out with the uniform is optimized away. I assume that it is + // because the shader doesn't get recompiled when the last layer of the night + // or water is disabled; so the shader thinks it has to do the calculation, but + // there are actually no layers left + using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; + _globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes); + _globalRenderer.program->setUniform( "lightDirectionCameraSpace", -glm::normalize(directionToSunCameraSpace) ); + _globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes); } constexpr const int ChunkBufferSize = 2048; @@ -1329,9 +1346,9 @@ void RenderableGlobe::renderChunkGlobally(const Chunk& chunk, const RenderData& // Shadow Mapping ghoul::opengl::TextureUnit shadowMapUnit; if (_generalProperties.shadowMapping && shadowData.shadowDepthTexture != 0) { - // Adding the model transformation to the final shadow matrix so we have a - // complete transformation from the model coordinates to the clip space of - // the light position. + // Adding the model transformation to the final shadow matrix so we have a + // complete transformation from the model coordinates to the clip space of the + // light position. program.setUniform( "shadowMatrix", shadowData.shadowMatrix * modelTransform() @@ -1345,14 +1362,14 @@ void RenderableGlobe::renderChunkGlobally(const Chunk& chunk, const RenderData& } glEnable(GL_DEPTH_TEST); - + if (!renderGeomOnly) { glEnable(GL_CULL_FACE); glCullFace(GL_BACK); } _grid.drawUsingActiveProgram(); - + for (GPULayerGroup& l : _globalRenderer.gpuLayerGroups) { l.deactivate(); } @@ -1444,7 +1461,9 @@ void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& d // Apply an extra scaling to the height if the object is scaled program.setUniform( "heightScale", - static_cast(data.modelTransform.scale * data.camera.scaling()) + static_cast( + glm::compMax(data.modelTransform.scale) * data.camera.scaling() + ) ); } @@ -1459,9 +1478,9 @@ void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& d // Shadow Mapping ghoul::opengl::TextureUnit shadowMapUnit; if (_generalProperties.shadowMapping && shadowData.shadowDepthTexture != 0) { - // Adding the model transformation to the final shadow matrix so we have a - // complete transformation from the model coordinates to the clip space of - // the light position. + // Adding the model transformation to the final shadow matrix so we have a + // complete transformation from the model coordinates to the clip space of the + // light position. program.setUniform( "shadowMatrix", shadowData.shadowMatrix * modelTransform() @@ -1479,7 +1498,7 @@ void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& d glEnable(GL_CULL_FACE); glCullFace(GL_BACK); } - + _grid.drawUsingActiveProgram(); for (GPULayerGroup& l : _localRenderer.gpuLayerGroups) { @@ -1616,7 +1635,7 @@ void RenderableGlobe::recompileShaders() { //); layeredTextureInfo.lastLayerIdx = static_cast( layerGroup.activeLayers().size() - 1 - ); + ); layeredTextureInfo.layerBlendingEnabled = layerGroup.layerBlendingEnabled(); for (Layer* layer : layers) { diff --git a/modules/globebrowsing/src/renderableglobe.h b/modules/globebrowsing/src/renderableglobe.h index 48f77d3042..ab4045d893 100644 --- a/modules/globebrowsing/src/renderableglobe.h +++ b/modules/globebrowsing/src/renderableglobe.h @@ -188,7 +188,7 @@ private: */ float getHeight(const glm::dvec3& position) const; - void renderChunks(const RenderData& data, RendererTasks& rendererTask, + void renderChunks(const RenderData& data, RendererTasks& rendererTask, const ShadowComponent::ShadowMapData& shadowData = {}, bool renderGeomOnly = false ); diff --git a/modules/globebrowsing/src/ringscomponent.cpp b/modules/globebrowsing/src/ringscomponent.cpp index 45559754ab..4a45be2517 100644 --- a/modules/globebrowsing/src/ringscomponent.cpp +++ b/modules/globebrowsing/src/ringscomponent.cpp @@ -52,7 +52,7 @@ namespace { constexpr const char* _loggerCat = "RingsComponent"; constexpr const std::array UniformNames = { - "modelViewProjectionMatrix", "textureOffset", "transparency", "_nightFactor", + "modelViewProjectionMatrix", "textureOffset", "transparency", "_nightFactor", "sunPosition", "ringTexture", "shadowMatrix", "shadowMapTexture", "zFightingPercentage" }; @@ -180,7 +180,7 @@ RingsComponent::RingsComponent(const ghoul::Dictionary& dictionary) , _ringsDictionary(dictionary) { using ghoul::filesystem::File; - + if (dictionary.hasKey("Rings")) { // @TODO (abock, 2019-12-16) It would be better to not store the dictionary long // term and rather extract the values directly here. This would require a bit of @@ -188,7 +188,7 @@ RingsComponent::RingsComponent(const ghoul::Dictionary& dictionary) // class-initializer list though dictionary.getValue("Rings", _ringsDictionary); } - + documentation::testSpecificationAndThrow( Documentation(), _ringsDictionary, @@ -310,20 +310,20 @@ void RingsComponent::draw(const RenderData& data, else if (renderPass == GeometryOnly) { _geometryOnlyShader->activate(); } - + const glm::dmat4 modelTransform = glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * glm::dmat4(data.modelTransform.rotation) * glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); - const glm::dmat4 modelViewProjectionTransform = - glm::dmat4(data.camera.projectionMatrix()) * data.camera.combinedViewMatrix() + const glm::dmat4 modelViewProjectionTransform = + glm::dmat4(data.camera.projectionMatrix()) * data.camera.combinedViewMatrix() * modelTransform; ghoul::opengl::TextureUnit ringTextureUnit; if (renderPass == GeometryAndShading) { _shader->setUniform( - _uniformCache.modelViewProjectionMatrix, + _uniformCache.modelViewProjectionMatrix, modelViewProjectionTransform ); _shader->setUniform(_uniformCache.textureOffset, _offset); @@ -336,18 +336,18 @@ void RingsComponent::draw(const RenderData& data, _texture->bind(); _shader->setUniform(_uniformCache.ringTexture, ringTextureUnit); - // Adding the model transformation to the final shadow matrix so we have a - // complete transformation from the model coordinates to the clip space of + // Adding the model transformation to the final shadow matrix so we have a + // complete transformation from the model coordinates to the clip space of // the light position. _shader->setUniform( - _uniformCache.shadowMatrix, + _uniformCache.shadowMatrix, shadowData.shadowMatrix * modelTransform ); ghoul::opengl::TextureUnit shadowMapUnit; shadowMapUnit.activate(); glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture); - + _shader->setUniform(_uniformCache.shadowMapTexture, shadowMapUnit); } else if (renderPass == GeometryOnly) { @@ -386,8 +386,8 @@ void RingsComponent::update(const UpdateData& data) { if (_geometryOnlyShader->isDirty()) { _geometryOnlyShader->rebuildFromFile(); ghoul::opengl::updateUniformLocations( - *_geometryOnlyShader, - _geomUniformCache, + *_geometryOnlyShader, + _geomUniformCache, GeomUniformNames ); } diff --git a/modules/globebrowsing/src/ringscomponent.h b/modules/globebrowsing/src/ringscomponent.h index c501c4a9de..62980e1bf6 100644 --- a/modules/globebrowsing/src/ringscomponent.h +++ b/modules/globebrowsing/src/ringscomponent.h @@ -54,18 +54,16 @@ public: GeometryOnly, GeometryAndShading }; - + RingsComponent(const ghoul::Dictionary& dictionary); void initialize(); void initializeGL(); void deinitializeGL(); - + bool isReady() const; - void draw( - const RenderData& data, - const RingsComponent::RenderPass renderPass, + void draw(const RenderData& data, const RingsComponent::RenderPass renderPass, const ShadowComponent::ShadowMapData& shadowData = {} ); void update(const UpdateData& data); @@ -90,11 +88,11 @@ private: std::unique_ptr _shader; std::unique_ptr _geometryOnlyShader; - UniformCache(modelViewProjectionMatrix, textureOffset, transparency, nightFactor, + UniformCache(modelViewProjectionMatrix, textureOffset, transparency, nightFactor, sunPosition, ringTexture, shadowMatrix, shadowMapTexture, zFightingPercentage ) _uniformCache; - UniformCache(modelViewProjectionMatrix, textureOffset, ringTexture) - _geomUniformCache; + UniformCache(modelViewProjectionMatrix, textureOffset, ringTexture + ) _geomUniformCache; std::unique_ptr _texture; std::unique_ptr _textureFile; diff --git a/modules/globebrowsing/src/shadowcomponent.cpp b/modules/globebrowsing/src/shadowcomponent.cpp index 3d59598e7b..0662c50566 100644 --- a/modules/globebrowsing/src/shadowcomponent.cpp +++ b/modules/globebrowsing/src/shadowcomponent.cpp @@ -55,7 +55,7 @@ namespace { constexpr const char* _loggerCat = "ShadowComponent"; - + constexpr openspace::properties::Property::PropertyInfo SaveDepthTextureInfo = { "SaveDepthTextureInfo", "Save Depth Texture", @@ -197,10 +197,10 @@ ShadowComponent::ShadowComponent(const ghoul::Dictionary& dictionary) if (_shadowMapDictionary.hasKey(DepthMapSizeInfo.identifier)) { - glm::vec2 depthMapSize = + glm::vec2 depthMapSize = _shadowMapDictionary.value(DepthMapSizeInfo.identifier); - _shadowDepthTextureWidth = depthMapSize.x; - _shadowDepthTextureHeight = depthMapSize.y; + _shadowDepthTextureWidth = static_cast(depthMapSize.x); + _shadowDepthTextureHeight = static_cast(depthMapSize.y); _dynamicDepthTextureRes = false; } else { @@ -240,42 +240,42 @@ RenderData ShadowComponent::begin(const RenderData& data) { // =========================================== // Builds light's ModelViewProjectionMatrix: // =========================================== - + glm::dvec3 diffVector = glm::dvec3(_sunPosition) - data.modelTransform.translation; double originalLightDistance = glm::length(diffVector); glm::dvec3 lightDirection = glm::normalize(diffVector); - + // Percentage of the original light source distance (to avoid artifacts) - //double multiplier = originalLightDistance * + //double multiplier = originalLightDistance * // (static_cast(_distanceFraction)/1.0E5); double multiplier = originalLightDistance * (static_cast(_distanceFraction) / 1E17); - + // New light source position - //glm::dvec3 lightPosition = data.modelTransform.translation + + //glm::dvec3 lightPosition = data.modelTransform.translation + // (lightDirection * multiplier); glm::dvec3 lightPosition = data.modelTransform.translation + (diffVector * multiplier); //// Light Position //glm::dvec3 lightPosition = glm::dvec3(_sunPosition); - + //=============== Manually Created Camera Matrix =================== //================================================================== // camera Z glm::dvec3 cameraZ = lightDirection; - + // camera X glm::dvec3 upVector = glm::dvec3(0.0, 1.0, 0.0); - glm::dvec3 cameraX = glm::normalize(glm::cross(upVector, cameraZ)); - + glm::dvec3 cameraX = glm::normalize(glm::cross(upVector, cameraZ)); + // camera Y glm::dvec3 cameraY = glm::cross(cameraZ, cameraX); // init 4x4 matrix glm::dmat4 cameraRotationMatrix(1.0); - + double* matrix = glm::value_ptr(cameraRotationMatrix); matrix[0] = cameraX.x; matrix[4] = cameraX.y; @@ -288,31 +288,31 @@ RenderData ShadowComponent::begin(const RenderData& data) { matrix[10] = cameraZ.z; // set translation part - // We aren't setting the position here because it is set in + // We aren't setting the position here because it is set in // the camera->setPosition() //matrix[12] = -glm::dot(cameraX, lightPosition); //matrix[13] = -glm::dot(cameraY, lightPosition); //matrix[14] = -glm::dot(cameraZ, lightPosition); - + _lightCamera = std::move(std::unique_ptr(new Camera(data.camera))); _lightCamera->setPositionVec3(lightPosition); _lightCamera->setRotation(glm::dquat(glm::inverse(cameraRotationMatrix))); //======================================================================= //======================================================================= - + //============= Light Matrix by Camera Matrices Composition ============= //======================================================================= glm::dmat4 lightProjectionMatrix = glm::dmat4(_lightCamera->projectionMatrix()); - - // The model transformation missing in the final shadow matrix is add when rendering each - // object (using its transformations provided by the RenderData structure) - _shadowData.shadowMatrix = - _toTextureCoordsMatrix * lightProjectionMatrix * + + // The model transformation missing in the final shadow matrix is add when rendering + // each object (using its transformations provided by the RenderData structure) + _shadowData.shadowMatrix = + _toTextureCoordsMatrix * lightProjectionMatrix * _lightCamera->combinedViewMatrix(); - + // Saves current state glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); glGetIntegerv(GL_VIEWPORT, _mViewport); @@ -337,8 +337,7 @@ RenderData ShadowComponent::begin(const RenderData& data) { glEnable(GL_DEPTH_TEST); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - + //glEnable(GL_CULL_FACE); //checkGLError("begin() -- enabled cull face"); //glCullFace(GL_FRONT); @@ -372,7 +371,7 @@ void ShadowComponent::end() { }; glDrawBuffers(3, drawBuffers); glViewport(_mViewport[0], _mViewport[1], _mViewport[2], _mViewport[3]); - + if (_faceCulling) { glEnable(GL_CULL_FACE); glCullFace(_faceToCull); @@ -399,9 +398,9 @@ void ShadowComponent::end() { } glClearColor( - _colorClearValue[0], - _colorClearValue[1], - _colorClearValue[2], + _colorClearValue[0], + _colorClearValue[1], + _colorClearValue[2], _colorClearValue[3] ); glClearDepth(_depthClearValue); @@ -433,14 +432,14 @@ void ShadowComponent::end() { glBindVertexArray(_quadVAO); glDrawArrays(GL_TRIANGLES, 0, 6); - + _renderDMProgram->deactivate(); } } void ShadowComponent::update(const UpdateData&) { _sunPosition = global::renderEngine.scene()->sceneGraphNode("Sun")->worldPosition(); - + glm::ivec2 renderingResolution = global::renderEngine.renderingResolution(); if (_dynamicDepthTextureRes && ((_shadowDepthTextureWidth != renderingResolution.x) || (_shadowDepthTextureHeight != renderingResolution.y))) @@ -454,7 +453,7 @@ void ShadowComponent::update(const UpdateData&) { void ShadowComponent::createDepthTexture() { glGenTextures(1, &_shadowDepthTexture); updateDepthTexture(); - + _shadowData.shadowDepthTexture = _shadowDepthTexture; //_shadowData.positionInLightSpaceTexture = _positionInLightSpaceTexture; } @@ -462,13 +461,13 @@ void ShadowComponent::createDepthTexture() { void ShadowComponent::createShadowFBO() { // Saves current FBO first glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); - + glGenFramebuffers(1, &_shadowFBO); glBindFramebuffer(GL_FRAMEBUFFER, _shadowFBO); glFramebufferTexture( - GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - _shadowDepthTexture, + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + _shadowDepthTexture, 0 ); @@ -478,7 +477,7 @@ void ShadowComponent::createShadowFBO() { // _positionInLightSpaceTexture, // 0 //); - + //GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE }; GLenum drawBuffers[] = { GL_NONE, GL_NONE, GL_NONE }; glDrawBuffers(3, drawBuffers); @@ -561,7 +560,7 @@ void ShadowComponent::saveDepthBuffer() { if (ppmFile.is_open()) { ppmFile << "P3" << std::endl; - ppmFile << _shadowDepthTextureWidth << " " << _shadowDepthTextureHeight + ppmFile << _shadowDepthTextureWidth << " " << _shadowDepthTextureHeight << std::endl; ppmFile << "255" << std::endl; @@ -601,7 +600,7 @@ void ShadowComponent::saveDepthBuffer() { if (ppmFile.is_open()) { ppmFile << "P3" << std::endl; - ppmFile << _shadowDepthTextureWidth << " " << _shadowDepthTextureHeight + ppmFile << _shadowDepthTextureWidth << " " << _shadowDepthTextureHeight << std::endl; ppmFile << "255" << std::endl; diff --git a/modules/globebrowsing/src/shadowcomponent.h b/modules/globebrowsing/src/shadowcomponent.h index 180b9aeccd..3c39293697 100644 --- a/modules/globebrowsing/src/shadowcomponent.h +++ b/modules/globebrowsing/src/shadowcomponent.h @@ -70,7 +70,7 @@ public: RenderData begin(const RenderData& data); void end(); void update(const UpdateData& data); - + static documentation::Documentation Documentation(); bool isEnabled() const; @@ -101,13 +101,13 @@ private: properties::TriggerProperty _saveDepthTexture; properties::IntProperty _distanceFraction; properties::BoolProperty _enabled; - + ghoul::Dictionary _shadowMapDictionary; - + int _shadowDepthTextureHeight = 4096; int _shadowDepthTextureWidth = 4096; bool _dynamicDepthTextureRes = true; - + GLuint _shadowDepthTexture = 0; GLuint _positionInLightSpaceTexture = 0; GLuint _shadowFBO = 0; diff --git a/modules/globebrowsing/src/timequantizer.cpp b/modules/globebrowsing/src/timequantizer.cpp index 68de65ac1f..67f7288d62 100644 --- a/modules/globebrowsing/src/timequantizer.cpp +++ b/modules/globebrowsing/src/timequantizer.cpp @@ -540,7 +540,7 @@ void TimeQuantizer::doFirstApproximation(DateTime& quantized, DateTime& unQ, static_cast(_start.year()); minIncrementsAdjust = minYearsToAdjust / value; quantized.setYear( - _start.year() + static_cast(minIncrementsAdjust) * value + _start.year() + static_cast(minIncrementsAdjust * value) ); break; case 'M': diff --git a/modules/globebrowsing/src/timequantizer.h b/modules/globebrowsing/src/timequantizer.h index f8907e3359..19decc6fa9 100644 --- a/modules/globebrowsing/src/timequantizer.h +++ b/modules/globebrowsing/src/timequantizer.h @@ -65,7 +65,7 @@ public: * * \param checkTime An ISO8601 date/time string to clamp if falls outside of range * - * \returns clamped value of input parameter, will be equal to the start value if + * \returns clamped value of input parameter, will be equal to the start value if * less than start, equal to end if greater than end, or equal to input * parameter if falls in-between */ @@ -227,7 +227,7 @@ public: /* * Increment operation for the date/time - * + * * \param value integer value for number of units in an operation * \param unit single char that specifies the unit of increment. Allowable units are: * (y)ear, (M)onth, (d)ay, (h)our, (m)inute, (s)econd @@ -254,7 +254,7 @@ public: * \returns The number of decrements that were performed in order to get as close as * possible to the target, where each decrement is defined by the value & * unit (and approximated but not fixed by the resolution param) - */ + */ int decrement(int value, char unit, double error, double resolution); /* diff --git a/modules/imgui/imguimodule.cpp b/modules/imgui/imguimodule.cpp index 1b8d63ace9..a4a873c267 100644 --- a/modules/imgui/imguimodule.cpp +++ b/modules/imgui/imguimodule.cpp @@ -154,9 +154,6 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) { global::callback::draw2D.emplace_back([&]() { ZoneScopedN("ImGUI") - // TODO emiax: Make sure this is only called for one of the eyes, in the case - // of side-by-side / top-bottom stereo. - WindowDelegate& delegate = global::windowDelegate; const bool showGui = delegate.hasGuiWindow() ? delegate.isGuiWindow() : true; if (delegate.isMaster() && showGui) { @@ -167,22 +164,15 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) { return; } - glm::vec2 mousePosition = delegate.mousePosition(); - uint32_t mouseButtons = delegate.mouseButtons(2); - const double dt = std::max(delegate.averageDeltaTime(), 0.0); - if (touchInput.active && mouseButtons == 0) { - mouseButtons = touchInput.action; - mousePosition = touchInput.pos; - } // We don't do any collection of immediate mode user interface, so it // is fine to open and close a frame immediately gui.startFrame( static_cast(dt), glm::vec2(windowSize), resolution / windowSize, - mousePosition, - mouseButtons + _mousePosition, + _mouseButtons ); gui.endFrame(); @@ -221,10 +211,23 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) { } ); + global::callback::mousePosition.emplace_back( + [&](double x, double y) { + _mousePosition = glm::vec2(static_cast(x), static_cast(y)); + } + ); + global::callback::mouseButton.emplace_back( [&](MouseButton button, MouseAction action, KeyModifier) -> bool { ZoneScopedN("ImGUI") + if (action == MouseAction::Press) { + _mouseButtons |= (1 << static_cast(button)); + } + else if (action == MouseAction::Release) { + _mouseButtons &= ~(1 << static_cast(button)); + } + // A list of all the windows that can show up by themselves if (gui.isEnabled() || gui._performance.isEnabled() || gui._sceneProperty.isEnabled()) @@ -252,6 +255,24 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) { } } ); + + global::callback::touchDetected.emplace_back( + [&](TouchInput input) -> bool { + return gui.touchDetectedCallback(input); + } + ); + + global::callback::touchUpdated.emplace_back( + [&](TouchInput input) -> bool { + return gui.touchUpdatedCallback(input); + } + ); + + global::callback::touchExit.emplace_back( + [&](TouchInput input) { + gui.touchExitCallback(input); + } + ); } } // namespace openspace diff --git a/modules/imgui/imguimodule.h b/modules/imgui/imguimodule.h index 73f037b5f2..e08556ffa8 100644 --- a/modules/imgui/imguimodule.h +++ b/modules/imgui/imguimodule.h @@ -31,13 +31,6 @@ namespace openspace { -// This should be moved into the touch module ---abock -struct Touch { - bool active; - glm::vec2 pos = glm::vec2(0.f); - uint32_t action = 0; -}; - class ImGUIModule : public OpenSpaceModule { public: constexpr static const char* Name = "ImGUI"; @@ -45,7 +38,10 @@ public: ImGUIModule(); gui::GUI gui; - Touch touchInput = { false, glm::vec2(0), 0 }; + +private: + glm::vec2 _mousePosition = glm::vec2(0.f); + uint32_t _mouseButtons = 0; }; } // namespace openspace diff --git a/modules/imgui/include/gui.h b/modules/imgui/include/gui.h index 17378491d0..e428631d89 100644 --- a/modules/imgui/include/gui.h +++ b/modules/imgui/include/gui.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,10 @@ public: bool keyCallback(Key key, KeyModifier modifier, KeyAction action); bool charCallback(unsigned int character, KeyModifier modifier); + bool touchDetectedCallback(TouchInput input); + bool touchUpdatedCallback(TouchInput input); + void touchExitCallback(TouchInput input); + void startFrame(float deltaTime, const glm::vec2& windowSize, const glm::vec2& dpiScaling, const glm::vec2& mousePos, uint32_t mouseButtonsPressed); @@ -169,6 +174,8 @@ private: properties::Property::Visibility::Developer; std::vector _contexts; + + std::vector _validTouchStates; }; void CaptionText(const char* text); diff --git a/modules/imgui/src/gui.cpp b/modules/imgui/src/gui.cpp index f9389ce043..f1d2d3ffcd 100644 --- a/modules/imgui/src/gui.cpp +++ b/modules/imgui/src/gui.cpp @@ -637,6 +637,77 @@ bool GUI::charCallback(unsigned int character, KeyModifier) { return consumeEvent; } +bool GUI::touchDetectedCallback(TouchInput input) { + ImGuiIO& io = ImGui::GetIO(); + const glm::vec2 windowPos = input.currentWindowCoordinates(); + const bool consumeEvent = ImGui::IsPosHoveringAnyWindow({ windowPos.x, windowPos.y }); + + if (!consumeEvent) { + return false; + } + if (_validTouchStates.empty()) { + io.MousePos = {windowPos.x, windowPos.y}; + io.MouseClicked[0] = true; + } + _validTouchStates.push_back(input); + return true; +} + +bool GUI::touchUpdatedCallback(TouchInput input) { + if (_validTouchStates.empty()) { + return false; + } + ImGuiIO& io = ImGui::GetIO(); + + auto it = std::find_if( + _validTouchStates.cbegin(), + _validTouchStates.cend(), + [&](const TouchInput& state){ + return state.fingerId == input.fingerId && + state.touchDeviceId == input.touchDeviceId; + } + ); + + if (it == _validTouchStates.cbegin()) { + glm::vec2 windowPos = input.currentWindowCoordinates(); + io.MousePos = {windowPos.x, windowPos.y}; + io.MouseClicked[0] = true; + return true; + } + else if (it != _validTouchStates.cend()){ + return true; + } + return false; +} + +void GUI::touchExitCallback(TouchInput input) { + if (_validTouchStates.empty()) { + return; + } + + const auto found = std::find_if( + _validTouchStates.cbegin(), + _validTouchStates.cend(), + [&](const TouchInput& state){ + return state.fingerId == input.fingerId && + state.touchDeviceId == input.touchDeviceId; + } + ); + + if (found == _validTouchStates.cend()) { + return; + } + + ImGuiIO& io = ImGui::GetIO(); + _validTouchStates.erase(found); + if (_validTouchStates.empty()) { + glm::vec2 windowPos = input.currentWindowCoordinates(); + io.MousePos = {windowPos.x, windowPos.y}; + io.MouseClicked[0] = false; + } +} + + void GUI::render() { ImGui::SetNextWindowCollapsed(_isCollapsed); diff --git a/modules/server/servermodule.cpp b/modules/server/servermodule.cpp index 95abd7c4ab..47974dfe50 100644 --- a/modules/server/servermodule.cpp +++ b/modules/server/servermodule.cpp @@ -87,7 +87,7 @@ void ServerModule::internalInitialize(const ghoul::Dictionary& configuration) { for (const std::string& key : interfaces.keys()) { ghoul::Dictionary interfaceDictionary = interfaces.value(key); - // @TODO (abock, 2019-09-17); This is a hack to make the parsing of the + // @TODO (abock, 2019-09-17); This is a hack to make the parsing of the // openspace.cfg file not corrupt the heap and cause a potential crash at shutdown // (see ticket https://github.com/OpenSpace/OpenSpace/issues/982) // The AllowAddresses are specified externally and are injected here diff --git a/modules/server/src/topics/flightcontrollertopic.cpp b/modules/server/src/topics/flightcontrollertopic.cpp index aedb5f3367..6d8dc96573 100644 --- a/modules/server/src/topics/flightcontrollertopic.cpp +++ b/modules/server/src/topics/flightcontrollertopic.cpp @@ -89,7 +89,8 @@ namespace { // Friction JSON Keys constexpr const char* FrictionEngagedKey = "engaged"; - constexpr const char* FrictionPropertyUri = "NavigationHandler.OrbitalNavigator.Friction"; + constexpr const char* FrictionPropertyUri = + "NavigationHandler.OrbitalNavigator.Friction"; constexpr const char* FrictionRotationKey = "rotation"; constexpr const char* FrictionZoomKey = "zoom"; constexpr const char* FrictionRollKey = "roll"; @@ -179,7 +180,9 @@ bool FlightControllerTopic::isDone() const { void FlightControllerTopic::handleJson(const nlohmann::json& json) { auto it = CommandMap.find(json[TypeKey]); if (it == CommandMap.end()) { - LWARNING(fmt::format("Poorly formatted JSON command: no '{}' in payload", TypeKey)); + LWARNING( + fmt::format("Poorly formatted JSON command: no '{}' in payload", TypeKey) + ); return; } @@ -213,7 +216,7 @@ void FlightControllerTopic::handleJson(const nlohmann::json& json) { void FlightControllerTopic::connect() { _isDone = false; - std::fill(_inputState.axes.begin(), _inputState.axes.end(), 0); + std::fill(_inputState.axes.begin(), _inputState.axes.end(), 0.f); _payload[TypeKey] = Connect; setFocusNodes(); setInterestingTimes(); @@ -290,10 +293,12 @@ void FlightControllerTopic::updateView(const nlohmann::json& json) const { void FlightControllerTopic::changeFocus(const nlohmann::json& json) const { if (json[FocusKey].find(SceneNodeName) == json[FocusKey].end()) { const std::string j = json; - LWARNING(fmt::format("Could not find {} key in JSON. JSON was:\n{}", FocusKey, j)); + LWARNING( + fmt::format("Could not find {} key in JSON. JSON was:\n{}", FocusKey, j) + ); return; } - + const std::string focus = json[FocusKey][SceneNodeName]; const SceneGraphNode* node = global::renderEngine.scene()->sceneGraphNode(focus); if (node) { @@ -308,7 +313,9 @@ void FlightControllerTopic::changeFocus(const nlohmann::json& json) const { void FlightControllerTopic::setRenderableEnabled(const nlohmann::json& json) const { if (json[RenderableKey].find(SceneNodeName) == json[RenderableKey].end()) { const std::string j = json; - LWARNING(fmt::format("Could not find {} key in JSON. JSON was:\n{}", FocusKey, j)); + LWARNING( + fmt::format("Could not find {} key in JSON. JSON was:\n{}", FocusKey, j) + ); return; } @@ -369,7 +376,7 @@ void FlightControllerTopic::engageAutopilot(const nlohmann::json &json) { setFriction(false); auto input = json[AutopilotInputKey][ValuesKey]; - std::fill(_inputState.axes.begin(), _inputState.axes.end(), 0); + std::fill(_inputState.axes.begin(), _inputState.axes.end(), 0.f); _inputState.isConnected = true; for (auto it = input.begin(); it != input.end(); ++it) { @@ -406,7 +413,7 @@ void FlightControllerTopic::handleAutopilot(const nlohmann::json &json) { } void FlightControllerTopic::processInputState(const nlohmann::json& json) { - std::fill(_inputState.axes.begin(), _inputState.axes.end(), 0); + std::fill(_inputState.axes.begin(), _inputState.axes.end(), 0.f); _inputState.isConnected = true; // Get "inputState" object from "payload" @@ -426,7 +433,7 @@ void FlightControllerTopic::processInputState(const nlohmann::json& json) { _inputState.axes[std::distance(AxisIndexMap.begin(), mapIt)] = float(it.value()); } } - + void FlightControllerTopic::processLua(const nlohmann::json &json) { const std::string script = json[LuaScript]; global::scriptEngine.queueScript( @@ -434,5 +441,5 @@ void FlightControllerTopic::processLua(const nlohmann::json &json) { openspace::scripting::ScriptEngine::RemoteScripting::Yes ); } - + } // namespace openspace diff --git a/modules/space/CMakeLists.txt b/modules/space/CMakeLists.txt index 612c2686e4..e191a4eff1 100644 --- a/modules/space/CMakeLists.txt +++ b/modules/space/CMakeLists.txt @@ -28,6 +28,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/planetgeometry.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableconstellationbounds.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablerings.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableorbitalkepler.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesatellites.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesmallbody.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablestars.h @@ -44,6 +45,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/planetgeometry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableconstellationbounds.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablerings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableorbitalkepler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesatellites.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesmallbody.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablestars.cpp diff --git a/modules/space/rendering/renderableorbitalkepler.cpp b/modules/space/rendering/renderableorbitalkepler.cpp new file mode 100644 index 0000000000..f9612d567e --- /dev/null +++ b/modules/space/rendering/renderableorbitalkepler.cpp @@ -0,0 +1,568 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + constexpr const char* ProgramName = "OrbitalKepler"; + constexpr const char* _loggerCat = "OrbitalKepler"; + constexpr const char* KeyFile = "Path"; + constexpr const char* KeyLineNum = "LineNumber"; + + constexpr const std::array LeapYears = { + 1956, 1960, 1964, 1968, 1972, 1976, 1980, 1984, 1988, 1992, 1996, + 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036, 2040, + 2044, 2048, 2052, 2056 + }; + constexpr const std::array DaysOfMonths = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + + // Find the position of the current year in the vector; its position in + // the vector gives the number of leap seconds + struct LeapSecond { + int year; + int dayOfYear; + bool operator<(const LeapSecond& rhs) const { + return std::tie(year, dayOfYear) < std::tie(rhs.year, rhs.dayOfYear); + } + }; + + constexpr const LeapSecond LeapEpoch = { 2000, 1 }; + + // List taken from: https://www.ietf.org/timezones/data/leap-seconds.list + constexpr const std::array LeapSeconds = { + LeapSecond{ 1972, 1 }, + LeapSecond{ 1972, 183 }, + LeapSecond{ 1973, 1 }, + LeapSecond{ 1974, 1 }, + LeapSecond{ 1975, 1 }, + LeapSecond{ 1976, 1 }, + LeapSecond{ 1977, 1 }, + LeapSecond{ 1978, 1 }, + LeapSecond{ 1979, 1 }, + LeapSecond{ 1980, 1 }, + LeapSecond{ 1981, 182 }, + LeapSecond{ 1982, 182 }, + LeapSecond{ 1983, 182 }, + LeapSecond{ 1985, 182 }, + LeapSecond{ 1988, 1 }, + LeapSecond{ 1990, 1 }, + LeapSecond{ 1991, 1 }, + LeapSecond{ 1992, 183 }, + LeapSecond{ 1993, 182 }, + LeapSecond{ 1994, 182 }, + LeapSecond{ 1996, 1 }, + LeapSecond{ 1997, 182 }, + LeapSecond{ 1999, 1 }, + LeapSecond{ 2006, 1 }, + LeapSecond{ 2009, 1 }, + LeapSecond{ 2012, 183 }, + LeapSecond{ 2015, 182 }, + LeapSecond{ 2017, 1 } + }; + + static const openspace::properties::Property::PropertyInfo PathInfo = { + "Path", + "Path", + "The file path to the data file to read" + }; + static const openspace::properties::Property::PropertyInfo SegmentQualityInfo = { + "SegmentQuality", + "Segment Quality", + "A segment quality value for the orbital trail. A value from 1 (lowest) to " + "10 (highest) that controls the number of line segments in the rendering of the " + "orbital trail. This does not control the direct number of segments because " + "these automatically increase according to the eccentricity of the orbit." + }; + constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = { + "LineWidth", + "Line Width", + "This value specifies the line width of the trail if the selected rendering " + "method includes lines. If the rendering mode is set to Points, this value is " + "ignored." + }; + constexpr openspace::properties::Property::PropertyInfo LineColorInfo = { + "Color", + "Color", + "This value determines the RGB main color for the lines and points of the trail." + }; + constexpr openspace::properties::Property::PropertyInfo TrailFadeInfo = { + "TrailFade", + "Trail Fade", + "This value determines how fast the trail fades and is an appearance property. " + }; + static const openspace::properties::Property::PropertyInfo UpperLimitInfo = { + "UpperLimit", + "Upper Limit", + "Upper limit on the number of objects for this renderable, regardless of " + "how many objects are contained in the data file. Produces an evenly-distributed" + "sample from the data file." + }; + static const openspace::properties::Property::PropertyInfo StartRenderIdxInfo = { + "StartRenderIdx", + "Starting Index of Render", + "Index of object in renderable group to start rendering (all prior objects will " + "be ignored)." + }; + static const openspace::properties::Property::PropertyInfo RenderSizeInfo = { + "RenderSizeInfo", + "Size of Render Block", + "Number of objects to render sequentially from StartRenderIdx" + }; + + // Count the number of full days since the beginning of 2000 to the beginning of + // the parameter 'year' + int countDays(int year) { + // Find the position of the current year in the vector, the difference + // between its position and the position of 2000 (for J2000) gives the + // number of leap years + constexpr const int Epoch = 2000; + constexpr const int DaysRegularYear = 365; + constexpr const int DaysLeapYear = 366; + + if (year == Epoch) { + return 0; + } + + // Get the position of the most recent leap year + const auto lb = std::lower_bound(LeapYears.begin(), LeapYears.end(), year); + + // Get the position of the epoch + const auto y2000 = std::find(LeapYears.begin(), LeapYears.end(), Epoch); + + // The distance between the two iterators gives us the number of leap years + const int nLeapYears = static_cast(std::abs(std::distance(y2000, lb))); + + const int nYears = std::abs(year - Epoch); + const int nRegularYears = nYears - nLeapYears; + + // Get the total number of days as the sum of leap years + non leap years + const int result = nRegularYears * DaysRegularYear + nLeapYears * DaysLeapYear; + return result; + } + + // Returns the number of leap seconds that lie between the {year, dayOfYear} + // time point and { 2000, 1 } + int countLeapSeconds(int year, int dayOfYear) { + // Get the position of the last leap second before the desired date + LeapSecond date{ year, dayOfYear }; + const auto it = std::lower_bound(LeapSeconds.begin(), LeapSeconds.end(), date); + + // Get the position of the Epoch + const auto y2000 = std::lower_bound( + LeapSeconds.begin(), + LeapSeconds.end(), + LeapEpoch + ); + + // The distance between the two iterators gives us the number of leap years + const int nLeapSeconds = static_cast(std::abs(std::distance(y2000, it))); + return nLeapSeconds; + } + + int daysIntoGivenYear(int year, int month, int dayOfMonth) { + //month and dayCount are zero-based. + month -= 1; + int dayCount = dayOfMonth - 1; + const int February = 1; + const bool isInLeapYear = + std::find(LeapYears.begin(), LeapYears.end(), year) + != LeapYears.end(); + + for (int m = 0; m < month; ++m) { + dayCount += DaysOfMonths[m]; + if (m == February && isInLeapYear) { + dayCount += 1; + } + } + return dayCount; + } + +} // namespace + +namespace openspace { + +double RenderableOrbitalKepler::calculateSemiMajorAxis(double meanMotion) const { + constexpr const double GravitationalConstant = 6.6740831e-11; + constexpr const double MassEarth = 5.9721986e24; + constexpr const double muEarth = GravitationalConstant * MassEarth; + + // Use Kepler's 3rd law to calculate semimajor axis + // a^3 / P^2 = mu / (2pi)^2 + // <=> a = ((mu * P^2) / (2pi^2))^(1/3) + // with a = semimajor axis + // P = period in seconds + // mu = G*M_earth + const double period = + std::chrono::seconds(std::chrono::hours(24)).count() / meanMotion; + + constexpr const double pisq = glm::pi() * glm::pi(); + const double semiMajorAxis = pow((muEarth * period*period) / (4 * pisq), 1.0 / 3.0); + + // We need the semi major axis in km instead of m + return semiMajorAxis / 1000.0; +} + +double RenderableOrbitalKepler::epochFromSubstring(const std::string& epochString) const { + // The epochString is in the form: + // YYDDD.DDDDDDDD + // With YY being the last two years of the launch epoch, the first DDD the day + // of the year and the remaning a fractional part of the day + + // The main overview of this function: + // 1. Reconstruct the full year from the YY part + // 2. Calculate the number of days since the beginning of the year + // 3. Convert the number of days to a number of seconds + // 4. Get the number of leap seconds since January 1st, 2000 and remove them + // 5. Adjust for the fact the epoch starts on 1st Januaray at 12:00:00, not + // midnight + + // According to https://celestrak.com/columns/v04n03/ + // Apparently, US Space Command sees no need to change the two-line element + // set format yet since no artificial earth satellites existed prior to 1957. + // By their reasoning, two-digit years from 57-99 correspond to 1957-1999 and + // those from 00-56 correspond to 2000-2056. We'll see each other again in 057! + + // 1. Get the full year + std::string yearPrefix = + std::atoi(epochString.substr(0, 2).c_str()) > 57 ? "19" : "20"; + const int year = std::atoi((yearPrefix + epochString.substr(0, 2)).c_str()); + const int daysSince2000 = countDays(year); + + // 2. + double daysInYear = std::atof(epochString.substr(2).c_str()); + + // 3 + using namespace std::chrono; + const int SecondsPerDay = static_cast(seconds(hours(24)).count()); + //Need to subtract 1 from daysInYear since it is not a zero-based count + const double nSecondsSince2000 = (daysSince2000 + daysInYear - 1) * SecondsPerDay; + + // 4 + // We need to remove additional leap seconds past 2000 and add them prior to + // 2000 to sync up the time zones + const double nLeapSecondsOffset = -countLeapSeconds( + year, + static_cast(std::floor(daysInYear)) + ); + + // 5 + const double nSecondsEpochOffset = static_cast(seconds(hours(12)).count()); + + // Combine all of the values + const double epoch = nSecondsSince2000 + nLeapSecondsOffset - nSecondsEpochOffset; + return epoch; +} + +double RenderableOrbitalKepler::epochFromYMDdSubstring(const std::string& epochString) { + // The epochString is in the form: + // YYYYMMDD.ddddddd + // With YYYY as the year, MM the month (1 - 12), DD the day of month (1-31), + // and dddd the fraction of that day. + + // The main overview of this function: + // 1. Read the year value + // 2. Calculate the number of days since the beginning of the year + // 3. Convert the number of days to a number of seconds + // 4. Get the number of leap seconds since January 1st, 2000 and remove them + // 5. Adjust for the fact the epoch starts on 1st January at 12:00:00, not + // midnight + + // 1 + int year = std::atoi(epochString.substr(0, 4).c_str()); + const int daysSince2000 = countDays(year); + + // 2. + int monthNum = std::atoi(epochString.substr(4, 2).c_str()); + int dayOfMonthNum = std::atoi(epochString.substr(6, 2).c_str()); + int wholeDaysInto = daysIntoGivenYear(year, monthNum, dayOfMonthNum); + double fractionOfDay = std::atof(epochString.substr(9, 7).c_str()); + double daysInYear = static_cast(wholeDaysInto) + fractionOfDay; + + // 3 + using namespace std::chrono; + const int SecondsPerDay = static_cast(seconds(hours(24)).count()); + //Need to subtract 1 from daysInYear since it is not a zero-based count + const double nSecondsSince2000 = (daysSince2000 + daysInYear - 1) * SecondsPerDay; + + // 4 + // We need to remove additional leap seconds past 2000 and add them prior to + // 2000 to sync up the time zones + const double nLeapSecondsOffset = -countLeapSeconds( + year, + static_cast(std::floor(daysInYear)) + ); + + // 5 + const double nSecondsEpochOffset = static_cast(seconds(hours(12)).count()); + + // Combine all of the values + const double epoch = nSecondsSince2000 + nLeapSecondsOffset - nSecondsEpochOffset; + return epoch; +} + +RenderableOrbitalKepler::RenderableOrbitalKepler(const ghoul::Dictionary& dict) + : Renderable(dict) + , _path(PathInfo) + , _segmentQuality(SegmentQualityInfo, 2, 1, 10) + , _upperLimit(UpperLimitInfo, 1000, 1, 1000000) + , _startRenderIdx(StartRenderIdxInfo, 0, 0, 1) + , _sizeRender(RenderSizeInfo, 1, 1, 2) +{ + documentation::testSpecificationAndThrow( + Documentation(), + dict, + "RenderableOrbitalKepler" + ); + + _path = dict.value(PathInfo.identifier); + _segmentQuality = static_cast(dict.value(SegmentQualityInfo.identifier)); + + if (dict.hasKeyAndValue(LineColorInfo.identifier)) { + _appearance.lineColor = dict.value(LineColorInfo.identifier); + } + + _appearance.lineFade = dict.hasKeyAndValue(TrailFadeInfo.identifier) ? + static_cast(dict.value(TrailFadeInfo.identifier)) : + 20.f; + + _upperLimit = dict.hasKeyAndValue(UpperLimitInfo.identifier) ? + static_cast(dict.value(UpperLimitInfo.identifier)) : + 0u; + + _startRenderIdx = dict.hasKeyAndValue(StartRenderIdxInfo.identifier) ? + static_cast(dict.value(StartRenderIdxInfo.identifier)) : + 0u; + + _sizeRender = dict.hasKeyAndValue(RenderSizeInfo.identifier) ? + static_cast(dict.value(RenderSizeInfo.identifier)) : + 0u; + + _appearance.lineWidth = dict.hasKeyAndValue(LineWidthInfo.identifier) ? + static_cast(dict.value(LineWidthInfo.identifier)) : + 2.f; + + _reinitializeTrailBuffers = std::function([this] { initializeGL(); }); + _path.onChange(_reinitializeTrailBuffers); + _segmentQuality.onChange(_reinitializeTrailBuffers); + + addPropertySubOwner(_appearance); + addProperty(_path); + addProperty(_segmentQuality); + addProperty(_opacity); + addProperty(_startRenderIdx); + addProperty(_sizeRender); + + _updateStartRenderIdxSelect = std::function([this] { initializeGL(); }); + _updateRenderSizeSelect = std::function([this] { initializeGL(); }); + _startRenderIdxCallbackHandle = _startRenderIdx.onChange(_updateStartRenderIdxSelect); + _sizeRenderCallbackHandle = _sizeRender.onChange(_updateRenderSizeSelect); + + setRenderBin(Renderable::RenderBin::Overlay); +} + +void RenderableOrbitalKepler::initializeGL() { + glGenVertexArrays(1, &_vertexArray); + glGenBuffers(1, &_vertexBuffer); + + _programObject = SpaceModule::ProgramObjectManager.request( + ProgramName, + []() -> std::unique_ptr { + return global::renderEngine.buildRenderProgram( + ProgramName, + absPath("${MODULE_SPACE}/shaders/debrisViz_vs.glsl"), + absPath("${MODULE_SPACE}/shaders/debrisViz_fs.glsl") + ); + } + ); + + _uniformCache.modelView = _programObject->uniformLocation("modelViewTransform"); + _uniformCache.projection = _programObject->uniformLocation("projectionTransform"); + _uniformCache.lineFade = _programObject->uniformLocation("lineFade"); + _uniformCache.inGameTime = _programObject->uniformLocation("inGameTime"); + _uniformCache.color = _programObject->uniformLocation("color"); + _uniformCache.opacity = _programObject->uniformLocation("opacity"); + + updateBuffers(); +} + +void RenderableOrbitalKepler::deinitializeGL() { + glDeleteBuffers(1, &_vertexBuffer); + glDeleteVertexArrays(1, &_vertexArray); + + SpaceModule::ProgramObjectManager.release( + ProgramName, + [](ghoul::opengl::ProgramObject* p) { + global::renderEngine.removeRenderProgram(p); + } + ); + _programObject = nullptr; +} + +bool RenderableOrbitalKepler::isReady() const { + return _programObject != nullptr; +} + +void RenderableOrbitalKepler::render(const RenderData& data, RendererTasks&) { + if (_data.empty()) { + return; + } + + _programObject->activate(); + _programObject->setUniform(_uniformCache.opacity, _opacity); + _programObject->setUniform(_uniformCache.inGameTime, data.time.j2000Seconds()); + + glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * + glm::dmat4(data.modelTransform.rotation) * + glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); + + _programObject->setUniform( + _uniformCache.modelView, + data.camera.combinedViewMatrix() * modelTransform + ); + + // Because we want the property to work similar to the planet trails + const float fade = static_cast( + pow(_appearance.lineFade.maxValue() - _appearance.lineFade, 2.0) + ); + + _programObject->setUniform(_uniformCache.projection, data.camera.projectionMatrix()); + _programObject->setUniform(_uniformCache.color, _appearance.lineColor); + _programObject->setUniform(_uniformCache.lineFade, fade); + + glLineWidth(_appearance.lineWidth); + + const size_t nrOrbits = _data.size(); + gl::GLint vertices = 0; + + //glDepthMask(false); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE) + + glBindVertexArray(_vertexArray); + for (size_t i = 0; i < nrOrbits; ++i) { + glDrawArrays(GL_LINE_STRIP, vertices, static_cast(_segmentSize[i] + 1)); + vertices = vertices + static_cast(_segmentSize[i]) + 1; + } + glBindVertexArray(0); + + _programObject->deactivate(); +} + +void RenderableOrbitalKepler::updateBuffers() { + readDataFile(_path); + + size_t nVerticesTotal = 0; + + int numOrbits = static_cast(_data.size()); + for (size_t i = 0; i < numOrbits; ++i) { + nVerticesTotal += _segmentSize[i] + 1; + } + _vertexBufferData.resize(nVerticesTotal); + + size_t vertexBufIdx = 0; + for (size_t orbitIdx = 0; orbitIdx < numOrbits; ++orbitIdx) { + const KeplerParameters& orbit = _data[orbitIdx]; + + _keplerTranslator.setKeplerElements( + orbit.eccentricity, + orbit.semiMajorAxis, + orbit.inclination, + orbit.ascendingNode, + orbit.argumentOfPeriapsis, + orbit.meanAnomaly, + orbit.period, + orbit.epoch + ); + + for (size_t j = 0 ; j < (_segmentSize[orbitIdx] + 1); ++j) { + double timeOffset = orbit.period * + static_cast(j)/ static_cast(_segmentSize[orbitIdx]); + + glm::dvec3 position = _keplerTranslator.position({ + {}, + Time(timeOffset + orbit.epoch), + Time(0.0), + false + }); + + _vertexBufferData[vertexBufIdx].x = static_cast(position.x); + _vertexBufferData[vertexBufIdx].y = static_cast(position.y); + _vertexBufferData[vertexBufIdx].z = static_cast(position.z); + _vertexBufferData[vertexBufIdx].time = static_cast(timeOffset); + _vertexBufferData[vertexBufIdx].epoch = orbit.epoch; + _vertexBufferData[vertexBufIdx].period = orbit.period; + + vertexBufIdx++; + } + } + + glBindVertexArray(_vertexArray); + + glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); + glBufferData( + GL_ARRAY_BUFFER, + _vertexBufferData.size() * sizeof(TrailVBOLayout), + _vertexBufferData.data(), + GL_STATIC_DRAW + ); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(TrailVBOLayout), nullptr); + + glEnableVertexAttribArray(1); + glVertexAttribPointer( + 1, + 2, + GL_DOUBLE, + GL_FALSE, + sizeof(TrailVBOLayout), + reinterpret_cast(4 * sizeof(GL_FLOAT)) + ); + + glBindVertexArray(0); +} + +} // namespace opensapce diff --git a/modules/space/rendering/renderableorbitalkepler.h b/modules/space/rendering/renderableorbitalkepler.h new file mode 100644 index 0000000000..42c6a45848 --- /dev/null +++ b/modules/space/rendering/renderableorbitalkepler.h @@ -0,0 +1,139 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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_SPACE___RENDERABLEORBITALKEPLER___H__ +#define __OPENSPACE_MODULE_SPACE___RENDERABLEORBITALKEPLER___H__ + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace openspace { + +class RenderableOrbitalKepler : public Renderable { +public: + RenderableOrbitalKepler(const ghoul::Dictionary& dictionary); + + void initializeGL() override; + void deinitializeGL() override; + + bool isReady() const override; + void render(const RenderData& data, RendererTasks& rendererTask) override; + + /** + * Reads the provided data file and calls the KeplerTranslation::setKeplerElments + * method with the correct values. If \p filename is a valid data file but contains + * disallowed values (see KeplerTranslation::setKeplerElements), a + * KeplerTranslation::RangeError is thrown. + * + * \param filename The path to the file that contains the data file. + * + * \throw ghoul::RuntimeError if the data file does not exist or there is a + * problem with its format. + * \pre The \p filename must exist + */ + virtual void readDataFile(const std::string& filename) = 0; + +protected: + double calculateSemiMajorAxis(double meanMotion) const; + double epochFromSubstring(const std::string& epochString) const; + double epochFromYMDdSubstring(const std::string& epochString); + + std::function _reinitializeTrailBuffers; + std::function _updateStartRenderIdxSelect; + std::function _updateRenderSizeSelect; + + struct KeplerParameters { + double inclination = 0.0; + double semiMajorAxis = 0.0; + double ascendingNode = 0.0; + double eccentricity = 0.0; + double argumentOfPeriapsis = 0.0; + double meanAnomaly = 0.0; + double meanMotion = 0.0; + double epoch = 0.0; + double period = 0.0; + }; + std::streamoff _numObjects; + bool _isFileReadinitialized = false; + inline static constexpr double convertAuToKm = 1.496e8; + inline static constexpr double convertDaysToSecs = 86400.0; + std::vector _data; + std::vector _segmentSize; + properties::UIntProperty _upperLimit; + properties::UIntProperty _segmentQuality; + properties::Property::OnChangeHandle _upperLimitCallbackHandle; + properties::UIntProperty _startRenderIdx; + properties::UIntProperty _sizeRender; + properties::Property::OnChangeHandle _startRenderIdxCallbackHandle; + properties::Property::OnChangeHandle _sizeRenderCallbackHandle; + +private: + struct Vertex { + glm::vec3 position = glm::vec3(0.f); + glm::vec3 color = glm::vec3(0.f); + glm::vec2 texcoord = glm::vec2(0.f); + }; + + /// The layout of the VBOs + struct TrailVBOLayout { + float x = 0.f; + float y = 0.f; + float z = 0.f; + float time = 0.f; + double epoch = 0.0; + double period = 0.0; + }; + + KeplerTranslation _keplerTranslator; + + /// The backend storage for the vertex buffer object containing all points for this + /// trail. + std::vector _vertexBufferData; + + GLuint _vertexArray; + GLuint _vertexBuffer; + GLuint _indexBuffer; + + void updateBuffers(); + + ghoul::opengl::ProgramObject* _programObject; + properties::StringProperty _path; + RenderableTrail::Appearance _appearance; + glm::vec3 _position = glm::vec3(0.f); + + UniformCache(modelView, projection, lineFade, inGameTime, color, opacity, + numberOfSegments) _uniformCache; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_SPACE___RENDERABLEORBITALKEPLER___H__ + diff --git a/modules/space/rendering/renderablesatellites.cpp b/modules/space/rendering/renderablesatellites.cpp index a2e34ac2ba..f3c667a197 100644 --- a/modules/space/rendering/renderablesatellites.cpp +++ b/modules/space/rendering/renderablesatellites.cpp @@ -42,7 +42,7 @@ #include #include #include -#include +#include namespace { constexpr const char* ProgramName = "RenderableSatellites"; @@ -53,7 +53,6 @@ namespace { "Path", "The file path to the TLE file to read" }; - static const openspace::properties::Property::PropertyInfo SegmentsInfo = { "Segments", "Segments", @@ -76,197 +75,10 @@ namespace { "Trail Fade", "This value determines how fast the trail fades and is an appearance property. " }; - - constexpr const char* KeyFile = "Path"; - constexpr const char* KeyLineNum = "LineNumber"; } namespace openspace { - // Count the number of full days since the beginning of 2000 to the beginning of - // the parameter 'year' - int countDays(int year) { - // Find the position of the current year in the vector, the difference - // between its position and the position of 2000 (for J2000) gives the - // number of leap years - constexpr const int Epoch = 2000; - constexpr const int DaysRegularYear = 365; - constexpr const int DaysLeapYear = 366; - - if (year == Epoch) { - return 0; - } - - // Get the position of the most recent leap year - const auto lb = std::lower_bound(LeapYears.begin(), LeapYears.end(), year); - - // Get the position of the epoch - const auto y2000 = std::find(LeapYears.begin(), LeapYears.end(), Epoch); - - // The distance between the two iterators gives us the number of leap years - const int nLeapYears = static_cast(std::abs(std::distance(y2000, lb))); - - const int nYears = std::abs(year - Epoch); - const int nRegularYears = nYears - nLeapYears; - - // Get the total number of days as the sum of leap years + non leap years - const int result = nRegularYears * DaysRegularYear + nLeapYears * DaysLeapYear; - return result; - } - - // Returns the number of leap seconds that lie between the {year, dayOfYear} - // time point and { 2000, 1 } - int countLeapSeconds(int year, int dayOfYear) { - // Find the position of the current year in the vector; its position in - // the vector gives the number of leap seconds - struct LeapSecond { - int year; - int dayOfYear; - bool operator<(const LeapSecond& rhs) const { - return std::tie(year, dayOfYear) < std::tie(rhs.year, rhs.dayOfYear); - } - }; - - const LeapSecond Epoch = { 2000, 1 }; - - // List taken from: https://www.ietf.org/timezones/data/leap-seconds.list - static const std::vector LeapSeconds = { - { 1972, 1 }, - { 1972, 183 }, - { 1973, 1 }, - { 1974, 1 }, - { 1975, 1 }, - { 1976, 1 }, - { 1977, 1 }, - { 1978, 1 }, - { 1979, 1 }, - { 1980, 1 }, - { 1981, 182 }, - { 1982, 182 }, - { 1983, 182 }, - { 1985, 182 }, - { 1988, 1 }, - { 1990, 1 }, - { 1991, 1 }, - { 1992, 183 }, - { 1993, 182 }, - { 1994, 182 }, - { 1996, 1 }, - { 1997, 182 }, - { 1999, 1 }, - { 2006, 1 }, - { 2009, 1 }, - { 2012, 183 }, - { 2015, 182 }, - { 2017, 1 } - }; - - // Get the position of the last leap second before the desired date - LeapSecond date { year, dayOfYear }; - const auto it = std::lower_bound(LeapSeconds.begin(), LeapSeconds.end(), date); - - // Get the position of the Epoch - const auto y2000 = std::lower_bound( - LeapSeconds.begin(), - LeapSeconds.end(), - Epoch - ); - - // The distance between the two iterators gives us the number of leap years - const int nLeapSeconds = static_cast(std::abs(std::distance(y2000, it))); - return nLeapSeconds; - } - - double calculateSemiMajorAxis(double meanMotion) { - constexpr const double GravitationalConstant = 6.6740831e-11; - constexpr const double MassEarth = 5.9721986e24; - constexpr const double muEarth = GravitationalConstant * MassEarth; - - // Use Kepler's 3rd law to calculate semimajor axis - // a^3 / P^2 = mu / (2pi)^2 - // <=> a = ((mu * P^2) / (2pi^2))^(1/3) - // with a = semimajor axis - // P = period in seconds - // mu = G*M_earth - double period = std::chrono::seconds(std::chrono::hours(24)).count() / meanMotion; - - const double pisq = glm::pi() * glm::pi(); - double semiMajorAxis = pow((muEarth * period*period) / (4 * pisq), 1.0 / 3.0); - - // We need the semi major axis in km instead of m - return semiMajorAxis / 1000.0; - } - -double epochFromSubstring(const std::string& epochString) { - // The epochString is in the form: - // YYDDD.DDDDDDDD - // With YY being the last two years of the launch epoch, the first DDD the day - // of the year and the remaning a fractional part of the day - - // The main overview of this function: - // 1. Reconstruct the full year from the YY part - // 2. Calculate the number of seconds since the beginning of the year - // 2.a Get the number of full days since the beginning of the year - // 2.b If the year is a leap year, modify the number of days - // 3. Convert the number of days to a number of seconds - // 4. Get the number of leap seconds since January 1st, 2000 and remove them - // 5. Adjust for the fact the epoch starts on 1st Januaray at 12:00:00, not - // midnight - - // According to https://celestrak.com/columns/v04n03/ - // Apparently, US Space Command sees no need to change the two-line element - // set format yet since no artificial earth satellites existed prior to 1957. - // By their reasoning, two-digit years from 57-99 correspond to 1957-1999 and - // those from 00-56 correspond to 2000-2056. We'll see each other again in 2057! - - // 1. Get the full year - std::string yearPrefix = [y = epochString.substr(0, 2)](){ - int year = std::atoi(y.c_str()); - return year >= 57 ? "19" : "20"; - }(); - const int year = std::atoi((yearPrefix + epochString.substr(0, 2)).c_str()); - const int daysSince2000 = countDays(year); - - // 2. - // 2.a - double daysInYear = std::atof(epochString.substr(2).c_str()); - - // 2.b - const bool isInLeapYear = std::find( - LeapYears.begin(), - LeapYears.end(), - year - ) != LeapYears.end(); - if (isInLeapYear && daysInYear >= 60) { - // We are in a leap year, so we have an effective day more if we are - // beyond the end of february (= 31+29 days) - --daysInYear; - } - - // 3 - using namespace std::chrono; - const int SecondsPerDay = static_cast(seconds(hours(24)).count()); - //Need to subtract 1 from daysInYear since it is not a zero-based count - const double nSecondsSince2000 = (daysSince2000 + daysInYear - 1) * SecondsPerDay; - - // 4 - // We need to remove additional leap seconds past 2000 and add them prior to - // 2000 to sync up the time zones - const double nLeapSecondsOffset = -countLeapSeconds( - year, - static_cast(std::floor(daysInYear)) - ); - - // 5 - const double nSecondsEpochOffset = static_cast( - seconds(hours(12)).count() - ); - - // Combine all of the values - const double epoch = nSecondsSince2000 + nLeapSecondsOffset - nSecondsEpochOffset; - return epoch; - } - documentation::Documentation RenderableSatellites::Documentation() { using namespace documentation; return { @@ -296,84 +108,59 @@ documentation::Documentation RenderableSatellites::Documentation() { new DoubleVector3Verifier, Optional::No, LineColorInfo.description + }, + { + TrailFadeInfo.identifier, + new DoubleVerifier, + Optional::Yes, + TrailFadeInfo.description } } }; } - + RenderableSatellites::RenderableSatellites(const ghoul::Dictionary& dictionary) - : Renderable(dictionary) - , _path(PathInfo) - , _nSegments(SegmentsInfo, 120, 4, 1024) -{ - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableSatellites" - ); + : RenderableOrbitalKepler(dictionary) +{} - _path = dictionary.value(PathInfo.identifier); - _nSegments = static_cast(dictionary.value(SegmentsInfo.identifier)); - - if (dictionary.hasKeyAndValue(LineColorInfo.identifier)) { - _appearance.lineColor = dictionary.value(LineColorInfo.identifier); - } - if (dictionary.hasKeyAndValue(TrailFadeInfo.identifier)) { - _appearance.lineFade = static_cast( - dictionary.value(TrailFadeInfo.identifier) - ); - } - else { - _appearance.lineFade = 20; - } - - if (dictionary.hasKeyAndValue(LineWidthInfo.identifier)) { - _appearance.lineWidth = static_cast( - dictionary.value(LineWidthInfo.identifier) - ); - } - else { - _appearance.lineWidth = 2.0; - } - - auto reinitializeTrailBuffers = [this]() { - initializeGL(); - }; - - _path.onChange(reinitializeTrailBuffers); - _nSegments.onChange(reinitializeTrailBuffers); - - addPropertySubOwner(_appearance); - addProperty(_path); - addProperty(_nSegments); - addProperty(_opacity); - - setRenderBin(Renderable::RenderBin::Overlay); -} - - -void RenderableSatellites::readTLEFile(const std::string& filename) { +void RenderableSatellites::readDataFile(const std::string& filename) { if (!FileSys.fileExists(filename)) { throw ghoul::RuntimeError(fmt::format( "Satellite TLE file {} does not exist.", filename )); } + _data.clear(); + _segmentSize.clear(); std::ifstream file; file.exceptions(std::ifstream::failbit | std::ifstream::badbit); file.open(filename); - std::streamoff numberOfLines = std::count(std::istreambuf_iterator(file), - std::istreambuf_iterator(), '\n' ); + std::streamoff numberOfLines = std::count( + std::istreambuf_iterator(file), + std::istreambuf_iterator(), + '\n' + ); file.seekg(std::ios_base::beg); // reset iterator to beginning of file - // 3 because a TLE has 3 lines per element/ object. - std::streamoff numberOfObjects = numberOfLines / 3; + _numObjects = numberOfLines / nLineEntriesPerSatellite; + + if (!_isFileReadinitialized) { + _isFileReadinitialized = true; + initializeFileReading(); + } std::string line = "-"; - for (std::streamoff i = 0; i < numberOfObjects; i++) { - std::getline(file, line); // get rid of title - + std::string name; + long long endElement = _startRenderIdx + _sizeRender - 1; + endElement = (endElement >= _numObjects) ? _numObjects - 1 : endElement; + //Burn lines if not starting at first element + for (unsigned int k = 0; k < _startRenderIdx; ++k) { + skipSingleEntryInFile(file); + } + for (std::streamoff i = _startRenderIdx; i <= endElement; i++) { + //Read title line + std::getline(file, name); KeplerParameters keplerElements; std::getline(file, line); @@ -386,6 +173,13 @@ void RenderableSatellites::readTLEFile(const std::string& filename) { // 4 10-11 International Designator (Last two digits of launch year) // 5 12-14 International Designator (Launch number of the year) // 6 15-17 International Designator(piece of the launch) A + name += " " + line.substr(2, 15); + if (_startRenderIdx > 0 && _startRenderIdx == i) { + LINFO(fmt::format( + "Set render block to start at object {}", + name + )); + } // 7 19-20 Epoch Year(last two digits of year) // 8 21-32 Epoch(day of the year and fractional portion of the day) // 9 34-43 First Time Derivative of the Mean Motion divided by two @@ -462,165 +256,30 @@ void RenderableSatellites::readTLEFile(const std::string& filename) { double period = seconds(hours(24)).count() / keplerElements.meanMotion; keplerElements.period = period; - _TLEData.push_back(keplerElements); - + _data.push_back(keplerElements); + _segmentSize.push_back(_segmentQuality * 16); } file.close(); } -void RenderableSatellites::initializeGL() { - glGenVertexArrays(1, &_vertexArray); - glGenBuffers(1, &_vertexBuffer); - - _programObject = SpaceModule::ProgramObjectManager.request( - ProgramName, - []() -> std::unique_ptr { - return global::renderEngine.buildRenderProgram( - ProgramName, - absPath("${MODULE_SPACE}/shaders/debrisViz_vs.glsl"), - absPath("${MODULE_SPACE}/shaders/debrisViz_fs.glsl") - ); - } - ); - - _uniformCache.modelView = _programObject->uniformLocation("modelViewTransform"); - _uniformCache.projection = _programObject->uniformLocation("projectionTransform"); - _uniformCache.lineFade = _programObject->uniformLocation("lineFade"); - _uniformCache.inGameTime = _programObject->uniformLocation("inGameTime"); - _uniformCache.color = _programObject->uniformLocation("color"); - _uniformCache.opacity = _programObject->uniformLocation("opacity"); - - updateBuffers(); -} - -void RenderableSatellites::deinitializeGL() { - glDeleteBuffers(1, &_vertexBuffer); - glDeleteVertexArrays(1, &_vertexArray); - - SpaceModule::ProgramObjectManager.release( - ProgramName, - [](ghoul::opengl::ProgramObject* p) { - global::renderEngine.removeRenderProgram(p); - } - ); - _programObject = nullptr; +void RenderableSatellites::initializeFileReading() { + _startRenderIdx.removeOnChange(_startRenderIdxCallbackHandle); + _sizeRender.removeOnChange(_sizeRenderCallbackHandle); + _startRenderIdx.setMaxValue(static_cast(_numObjects - 1)); + _sizeRender.setMaxValue(static_cast(_numObjects)); + _startRenderIdx = static_cast(0); + _sizeRender = static_cast(_numObjects); + _startRenderIdxCallbackHandle = _startRenderIdx.onChange( + _updateStartRenderIdxSelect); + _sizeRenderCallbackHandle = _sizeRender.onChange( + _updateRenderSizeSelect); } -bool RenderableSatellites::isReady() const { - return _programObject != nullptr; -} - -void RenderableSatellites::render(const RenderData& data, RendererTasks&) { - if (_TLEData.empty()) - return; - - _programObject->activate(); - _programObject->setUniform(_uniformCache.opacity, _opacity); - _programObject->setUniform(_uniformCache.inGameTime, data.time.j2000Seconds()); - - - glm::dmat4 modelTransform = - glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * - glm::dmat4(data.modelTransform.rotation) * - glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); - - _programObject->setUniform( - _uniformCache.modelView, - data.camera.combinedViewMatrix() * modelTransform - ); - - // Because we want the property to work similar to the planet trails - float fade = static_cast(pow(_appearance.lineFade.maxValue() - _appearance.lineFade, 2.0)); - - _programObject->setUniform(_uniformCache.projection, data.camera.projectionMatrix()); - _programObject->setUniform(_uniformCache.color, _appearance.lineColor); - _programObject->setUniform(_uniformCache.lineFade, fade); - - glLineWidth(_appearance.lineWidth); - - const size_t nrOrbits = _TLEData.size(); - gl::GLint vertices = 0; - - //glDepthMask(false); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE) - - glBindVertexArray(_vertexArray); - for (size_t i = 0; i < nrOrbits; ++i) { - glDrawArrays(GL_LINE_STRIP, vertices, _nSegments + 1); - vertices = vertices + _nSegments + 1; +void RenderableSatellites::skipSingleEntryInFile(std::ifstream& file) { + std::string line; + for (unsigned int i = 0; i < nLineEntriesPerSatellite; i++) { + std::getline(file, line); } - glBindVertexArray(0); - - _programObject->deactivate(); - } -void RenderableSatellites::updateBuffers() { - readTLEFile(_path); - - const size_t nVerticesPerOrbit = _nSegments + 1; - _vertexBufferData.resize(_TLEData.size() * nVerticesPerOrbit); - size_t orbitindex = 0; - - for (const auto& orbit : _TLEData) { - _keplerTranslator.setKeplerElements( - orbit.eccentricity, - orbit.semiMajorAxis, - orbit.inclination, - orbit.ascendingNode, - orbit.argumentOfPeriapsis, - orbit.meanAnomaly, - orbit.period, - orbit.epoch - ); - - for (size_t i=0 ; i < nVerticesPerOrbit; ++i) { - size_t index = orbitindex * nVerticesPerOrbit + i; - - double timeOffset = orbit.period * - static_cast(i)/ static_cast(_nSegments); - - glm::dvec3 position = _keplerTranslator.position({ - {}, - Time(timeOffset + orbit.epoch), - Time(0.0), - false - }); - - double positionX = position.x; - double positionY = position.y; - double positionZ = position.z; - - _vertexBufferData[index].x = static_cast(positionX); - _vertexBufferData[index].y = static_cast(positionY); - _vertexBufferData[index].z = static_cast(positionZ); - _vertexBufferData[index].time = static_cast(timeOffset); - _vertexBufferData[index].epoch = orbit.epoch; - _vertexBufferData[index].period = orbit.period; - } - - ++orbitindex; - } - - glBindVertexArray(_vertexArray); - - glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); - glBufferData( - GL_ARRAY_BUFFER, - _vertexBufferData.size() * sizeof(TrailVBOLayout), - _vertexBufferData.data(), - GL_STATIC_DRAW - ); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(TrailVBOLayout), nullptr); - - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_DOUBLE, GL_FALSE, sizeof(TrailVBOLayout), (GLvoid*)(4 * sizeof(GL_FLOAT))); - - - glBindVertexArray(0); - -} - } diff --git a/modules/space/rendering/renderablesatellites.h b/modules/space/rendering/renderablesatellites.h index 9043c4ab46..d6e9112ecb 100644 --- a/modules/space/rendering/renderablesatellites.h +++ b/modules/space/rendering/renderablesatellites.h @@ -25,6 +25,7 @@ #ifndef __OPENSPACE_MODULE_SPACE___RENDERABLESATELLITES___H__ #define __OPENSPACE_MODULE_SPACE___RENDERABLESATELLITES___H__ +#include #include #include @@ -37,98 +38,16 @@ namespace openspace { -const std::vector LeapYears = { - 1956, 1960, 1964, 1968, 1972, 1976, 1980, 1984, 1988, 1992, 1996, - 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036, 2040, - 2044, 2048, 2052, 2056 -}; -int countDays(int year); -int countLeapSeconds(int year, int dayOfYear); -double calculateSemiMajorAxis(double meanMotion); -double epochFromSubstring(const std::string& epochString); - -class RenderableSatellites : public Renderable { +class RenderableSatellites : public RenderableOrbitalKepler { public: RenderableSatellites(const ghoul::Dictionary& dictionary); - - void initializeGL() override; - void deinitializeGL() override; - - bool isReady() const override; - void render(const RenderData& data, RendererTasks& rendererTask) override; - + void readDataFile(const std::string& filename); static documentation::Documentation Documentation(); - /** - * Reads the provided TLE file and calls the KeplerTranslation::setKeplerElments - * method with the correct values. If \p filename is a valid TLE file but contains - * disallowed values (see KeplerTranslation::setKeplerElements), a - * KeplerTranslation::RangeError is thrown. - * - * \param filename The path to the file that contains the TLE file. - * - * \throw ghoul::RuntimeError if the TLE file does not exist or there is a - * problem with its format. - * \pre The \p filename must exist - */ - void readTLEFile(const std::string& filename); + void initializeFileReading(); private: - struct Vertex { - glm::vec3 position = glm::vec3(0.f); - glm::vec3 color = glm::vec3(0.f); - glm::vec2 texcoord = glm::vec2(0.f); - }; - - struct KeplerParameters { - double inclination = 0.0; - double semiMajorAxis = 0.0; - double ascendingNode = 0.0; - double eccentricity = 0.0; - double argumentOfPeriapsis = 0.0; - double meanAnomaly = 0.0; - double meanMotion = 0.0; - double epoch = 0.0; - double period = 0.0; - }; - - /// The layout of the VBOs - struct TrailVBOLayout { - float x = 0.f; - float y = 0.f; - float z = 0.f; - float time = 0.f; - double epoch = 0.0; - double period = 0.0; - }; - - KeplerTranslation _keplerTranslator; - std::vector _TLEData; - - /// The backend storage for the vertex buffer object containing all points for this - /// trail. - std::vector _vertexBufferData; - - GLuint _vertexArray; - GLuint _vertexBuffer; - GLuint _indexBuffer; - - //GLuint _vaoTest; // vertexArrayObject - //GLuint _vboTest; // vertextBufferObject - //GLuint _eboTest; // elementBufferObject/ indexBufferObject - - void updateBuffers(); - - ghoul::opengl::ProgramObject* _programObject; - - properties::StringProperty _path; - properties::UIntProperty _nSegments; - - RenderableTrail::Appearance _appearance; - - glm::vec3 _position = glm::vec3(0.f); - - UniformCache(modelView, projection, lineFade, inGameTime, color, opacity, - numberOfSegments) _uniformCache; + void skipSingleEntryInFile(std::ifstream& file); + const unsigned int nLineEntriesPerSatellite = 3; }; } // namespace openspace diff --git a/modules/space/rendering/renderablesmallbody.cpp b/modules/space/rendering/renderablesmallbody.cpp index be5dbf2ba3..39dd624e98 100644 --- a/modules/space/rendering/renderablesmallbody.cpp +++ b/modules/space/rendering/renderablesmallbody.cpp @@ -41,9 +41,9 @@ #include #include #include -#include #include -#include +#include +#include namespace { constexpr const char* ProgramName = "RenderableSmallBody"; @@ -52,13 +52,15 @@ namespace { static const openspace::properties::Property::PropertyInfo PathInfo = { "Path", "Path", - "The file path to the SBDB file to read" + "The file path to the SBDB .csv file to read" }; - - static const openspace::properties::Property::PropertyInfo SegmentsInfo = { - "Segments", - "Segments", - "The number of segments to use for each orbit ellipse" + static const openspace::properties::Property::PropertyInfo SegmentQualityInfo = { + "SegmentQuality", + "Segment Quality", + "A segment quality value for the orbital trail. A value from 1 (lowest) to " + "100 (highest) that controls the number of line segments in the rendering of the " + "orbital trail. This does not control the direct number of segments because " + "these automatically increase according to the eccentricity of the orbit." }; constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = { "LineWidth", @@ -67,130 +69,43 @@ namespace { "method includes lines. If the rendering mode is set to Points, this value is " "ignored." }; - constexpr openspace::properties::Property::PropertyInfo FadeInfo = { - "Fade", - "Line fade", - "The fading factor that is applied to the trail if the 'EnableFade' value is " - "'true'. If it is 'false', this setting has no effect. The higher the number, " - "the less fading is applied." - }; constexpr openspace::properties::Property::PropertyInfo LineColorInfo = { "Color", "Color", "This value determines the RGB main color for the lines and points of the trail." }; - - constexpr const char* KeyFile = "Path"; - constexpr const char* KeyLineNum = "LineNumber"; -} + constexpr openspace::properties::Property::PropertyInfo TrailFadeInfo = { + "TrailFade", + "Trail Fade", + "This value determines how fast the trail fades and is an appearance property. " + }; + static const openspace::properties::Property::PropertyInfo UpperLimitInfo = { + "UpperLimit", + "Upper Limit", + "Upper limit on the number of objects for this renderable, regardless of " + "how many objects are contained in the data file" + }; +} // namespace namespace openspace { -const std::vector DaysOfMonths = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - -enum Months { - January = 0, - February, - March, - April, - May, - June, - July, - August, - September, - October, - November, - December -}; - -int daysIntoGivenYear(int month, int dayOfMonth) { - //month and dayCount are zero-based. Does NOT account for leap year. - month -= 1; - int dayCount = dayOfMonth - 1; - - for (int m = Months::January; m < month; ++m) { - dayCount += DaysOfMonths[m]; - } - return dayCount; -} - -double epochFromYMDdSubstring(const std::string& epochString) { - // The epochString is in the form: - // YYYYMMDD.ddddddd - // With YYYY as the year, MM the month (1 - 12), DD the day of month (1-31), - // and dddd the fraction of that day. - - // The main overview of this function: - // 1. Read the year value - // 2. Calculate the number of seconds since the beginning of the year - // 2.a Get the number of full days since the beginning of the year - // 2.b If the year is a leap year, modify the number of days - // 3. Convert the number of days to a number of seconds - // 4. Get the number of leap seconds since January 1st, 2000 and remove them - // 5. Adjust for the fact the epoch starts on 1st January at 12:00:00, not - // midnight - - // 1 - int year = std::atoi(epochString.substr(0, 4).c_str()); - const int daysSince2000 = countDays(year); - - // 2. - // 2.a - int monthNum = std::atoi(epochString.substr(4, 2).c_str()); - int dayOfMonthNum = std::atoi(epochString.substr(6, 2).c_str()); - int wholeDaysInto = daysIntoGivenYear(monthNum, dayOfMonthNum); - double fractionOfDay = std::atof(epochString.substr(9, 7).c_str()); - double daysInYear = static_cast(wholeDaysInto) + fractionOfDay; - - // 2.b - const bool isInLeapYear = std::find( - LeapYears.begin(), - LeapYears.end(), - year - ) != LeapYears.end(); - if (isInLeapYear && daysInYear >= 60) { - // We are in a leap year, so we have an effective day more if we are - // beyond the end of february (= 31+29 days) - --daysInYear; - } - - // 3 - using namespace std::chrono; - const int SecondsPerDay = static_cast(seconds(hours(24)).count()); - //Need to subtract 1 from daysInYear since it is not a zero-based count - const double nSecondsSince2000 = (daysSince2000 + daysInYear - 1) * SecondsPerDay; - - // 4 - // We need to remove additional leap seconds past 2000 and add them prior to - // 2000 to sync up the time zones - const double nLeapSecondsOffset = -countLeapSeconds( - year, - static_cast(std::floor(daysInYear)) - ); - - // 5 - const double nSecondsEpochOffset = static_cast( - seconds(hours(12)).count() - ); - - // Combine all of the values - const double epoch = nSecondsSince2000 + nLeapSecondsOffset - nSecondsEpochOffset; - return epoch; -} - documentation::Documentation RenderableSmallBody::Documentation() { using namespace documentation; return { "RenderableSmallBody", - "small solar system bodies", + "space_renderable_small_body", { { - SegmentsInfo.identifier, + SegmentQualityInfo.identifier, new DoubleVerifier, Optional::No, - SegmentsInfo.description + SegmentQualityInfo.description + }, + { + UpperLimitInfo.identifier, + new IntVerifier, + Optional::Yes, + UpperLimitInfo.description }, { PathInfo.identifier, @@ -204,75 +119,30 @@ documentation::Documentation RenderableSmallBody::Documentation() { Optional::Yes, LineWidthInfo.description }, - { - FadeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - FadeInfo.description - }, { LineColorInfo.identifier, new DoubleVector3Verifier, Optional::No, LineColorInfo.description + }, + { + TrailFadeInfo.identifier, + new DoubleVerifier, + Optional::Yes, + TrailFadeInfo.description } } }; } - + RenderableSmallBody::RenderableSmallBody(const ghoul::Dictionary& dictionary) - : Renderable(dictionary) - , _path(PathInfo) - , _nSegments(SegmentsInfo) - + : RenderableOrbitalKepler(dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableSmallBody" - ); - - _path = dictionary.value(PathInfo.identifier); - _nSegments = static_cast(dictionary.value(SegmentsInfo.identifier)); - - if (dictionary.hasKeyAndValue(LineColorInfo.identifier)) { - _appearance.lineColor = dictionary.value(LineColorInfo.identifier); - } - if (dictionary.hasKeyAndValue("FadeInfo")) { - _appearance.lineFade = static_cast( - dictionary.value("FadeInfo") - ); - } - else { - _appearance.lineFade = 20; - } - - if (dictionary.hasKeyAndValue(LineWidthInfo.identifier)) { - _appearance.lineWidth = static_cast( - dictionary.value(LineWidthInfo.identifier) - ); - } - else { - _appearance.lineWidth = 2.0; - } - - auto reinitializeTrailBuffers = [this]() { - initializeGL(); - }; - - _path.onChange(reinitializeTrailBuffers); - _nSegments.onChange(reinitializeTrailBuffers); - - addPropertySubOwner(_appearance); - addProperty(_path); - addProperty(_nSegments); - addProperty(_opacity); - - setRenderBin(Renderable::RenderBin::Overlay); + _upperLimitCallbackHandle = _upperLimit.onChange(_reinitializeTrailBuffers); + addProperty(_upperLimit); } - - -void RenderableSmallBody::readJplSbDb(const std::string& filename) { + +void RenderableSmallBody::readDataFile(const std::string& filename) { if (!FileSys.fileExists(filename)) { throw ghoul::RuntimeError(fmt::format( "JPL SBDB file {} does not exist.", filename @@ -283,133 +153,249 @@ void RenderableSmallBody::readJplSbDb(const std::string& filename) { file.exceptions(std::ifstream::failbit | std::ifstream::badbit); file.open(filename); - std::streamoff numberOfLines = std::count(std::istreambuf_iterator(file), - std::istreambuf_iterator(), '\n' ); + std::streamoff numberOfLines = std::count( + std::istreambuf_iterator(file), + std::istreambuf_iterator(), + '\n' + ); file.seekg(std::ios_base::beg); // reset iterator to beginning of file + _data.clear(); + _sbNames.clear(); + _segmentSize.clear(); std::string line; - std::string name; - std::string field; - std::streamoff csvLine = -1; + unsigned int csvLine = 0; int fieldCount = 0; - const std::string expectedHeaderLine = - "full_name,epoch_cal,e,a,i,om,w,ma,per"; + float lineSkipFraction = 1.0; + int lastLineCount = -1; + const std::string expectedHeaderLine = "full_name,epoch_cal,e,a,i,om,w,ma,per"; try { std::getline(file, line); // get rid of first line (header) numberOfLines -= 1; + if (_numObjects != numberOfLines) { + _isFileReadinitialized = false; + } + _numObjects = numberOfLines; + + if (!_isFileReadinitialized) { + _isFileReadinitialized = true; + initializeFileReading(); + } + else { + if (_sizeRender < _numObjects || _startRenderIdx > 0) { + lineSkipFraction = 1.0; + } + else { + lineSkipFraction = static_cast(_upperLimit) + / static_cast(_numObjects); + } + } + if (line.compare(expectedHeaderLine) != 0) { LERROR(fmt::format( - "File {} does not have the appropriate JPL SBDB header at line 1.", + "File {} does not have the appropriate JPL SBDB header at line 1", filename )); - file.close(); return; } - for (csvLine = 0; csvLine < numberOfLines; csvLine++) { - fieldCount = 0; - KeplerParameters keplerElements; - // Object designator string - std::getline(file, name, ','); - fieldCount++; + unsigned int sequentialLineErrors = 0; + unsigned int endElement = _startRenderIdx + _sizeRender - 1; + endElement = + (endElement >= _numObjects) ? + static_cast(_numObjects - 1) : + endElement; + // Burn lines if not starting at first element + for (unsigned int k = 0; k < _startRenderIdx; ++k) { + skipSingleLineInFile(file); + } + bool firstDataLine = true; + for (csvLine = _startRenderIdx + 1; + csvLine <= endElement + 1; + csvLine++, sequentialLineErrors++) + { + float currLineFraction = static_cast(csvLine - 1) * lineSkipFraction; + int currLineCount = static_cast(currLineFraction); + if (currLineCount > lastLineCount) { + try { + readOrbitalParamsFromThisLine(firstDataLine, fieldCount, csvLine, + file); + sequentialLineErrors = 0; + } + catch (std::invalid_argument&) { + const char* errMsg = "Unable to convert field {} to double value "\ + "(invalid_argument exception) at line {}/{} of {}"; + LERROR(fmt::format( + errMsg, + fieldCount, csvLine + 1, numberOfLines, filename + )); + } + catch (std::out_of_range&) { + const char* errMsg = "Unable to convert field {} to double value "\ + "(out_of_range exception) at line {}/{} of {}"; + LERROR(fmt::format( + errMsg, + fieldCount, csvLine + 1, numberOfLines, filename + )); + } + catch (std::ios_base::failure& f) { + throw f; + } - // Epoch - if (!std::getline(file, field, ',')) { - throw std::invalid_argument("Unable to read epoch from line" - + std::to_string(csvLine + 1)); + if (sequentialLineErrors == 4) { + _data.clear(); + _sbNames.clear(); + LERROR(fmt::format( + "Abandoning data file {} (too many sequential line errors).", + filename + )); + break; + } } - keplerElements.epoch = epochFromYMDdSubstring(field); - fieldCount++; - - // Eccentricity (unit-less) - if (!std::getline(file, field, ',')) { - throw std::invalid_argument("Unable to read eccentricity from line" - + std::to_string(csvLine + 1)); + else { + skipSingleLineInFile(file); } - keplerElements.eccentricity = std::stod(field); - fieldCount++; - - // Semi-major axis (astronomical units - au) - if (!std::getline(file, field, ',')) { - throw std::invalid_argument("Unable to read semi-major axis from line" - + std::to_string(csvLine + 1)); - } - keplerElements.semiMajorAxis = std::stod(field); - keplerElements.semiMajorAxis *= convertAuToKm; - fieldCount++; - - // Inclination (degrees) - if (!std::getline(file, field, ',')) { - throw std::invalid_argument("Unable to read inclination from line" - + std::to_string(csvLine + 1)); - } - keplerElements.inclination = importAngleValue(field); - fieldCount++; - - // Longitude of ascending node (degrees) - if (!std::getline(file, field, ',')) { - throw std::invalid_argument("Unable to read ascending node from line" - + std::to_string(csvLine + 1)); - } - keplerElements.ascendingNode = importAngleValue(field); - fieldCount++; - - // Argument of Periapsis (degrees) - if (!std::getline(file, field, ',')) { - throw std::invalid_argument("Unable to read arg of periapsis from line" - + std::to_string(csvLine + 1)); - } - keplerElements.argumentOfPeriapsis = importAngleValue(field); - fieldCount++; - - // Mean Anomaly (degrees) - if (!std::getline(file, field, ',')) { - throw std::invalid_argument("Unable to read mean anomaly from line" - + std::to_string(csvLine + 1)); - } - keplerElements.meanAnomaly = importAngleValue(field); - fieldCount++; - - // Period (days) - if (!std::getline(file, field)) { - throw std::invalid_argument("Unable to read period from line" - + std::to_string(csvLine + 1)); - } - keplerElements.period = std::stod(field); - keplerElements.period *= convertDaysToSecs; - fieldCount++; - - _sbData.push_back(keplerElements); - _sbNames.push_back(name); + lastLineCount = currLineCount; + firstDataLine = false; } } - catch (std::invalid_argument&) { - const char* errMsg = "Unable to convert field {} to double value "\ - "(invalid_argument exception) at line {}/{} of {}"; + catch (const std::ios_base::failure&) { LERROR(fmt::format( - errMsg, - fieldCount, csvLine + 1, numberOfLines, filename - )); - } - catch (std::out_of_range&) { - const char* errMsg = "Unable to convert field {} to double value "\ - "(out_of_range exception) at line {}/{} of {}"; - LERROR(fmt::format( - errMsg, - fieldCount, csvLine + 1, numberOfLines, filename - )); - } - catch (std::ios_base::failure&) { - const char* errMsg = "File read exception (ios_base::failure) while trying "\ - "to read field {} at line {}/{} of {}"; - LERROR(fmt::format( - errMsg, + "File read exception (ios_base::failure) while trying to read field {} at " + "line {}/{} of {}", fieldCount, csvLine + 1, numberOfLines, filename )); } +} - file.close(); +void RenderableSmallBody::initializeFileReading() { + _startRenderIdx.removeOnChange(_startRenderIdxCallbackHandle); + _sizeRender.removeOnChange(_sizeRenderCallbackHandle); + _startRenderIdx.setMaxValue(static_cast(_numObjects - 1)); + _sizeRender.setMaxValue(static_cast(_numObjects)); + _startRenderIdx = static_cast(0); + _sizeRender = static_cast(_numObjects); + _startRenderIdxCallbackHandle = _startRenderIdx.onChange(_updateStartRenderIdxSelect); + _sizeRenderCallbackHandle = _sizeRender.onChange(_updateRenderSizeSelect); + // If a limit wasn't specified in dictionary, set it to # lines in file + // minus the header line (but temporarily disable callback to avoid 2nd call) + _upperLimit.removeOnChange(_upperLimitCallbackHandle); + _upperLimit.setMaxValue(static_cast(_numObjects)); + _upperLimit = static_cast(_numObjects); + _upperLimitCallbackHandle = _upperLimit.onChange(_reinitializeTrailBuffers); +} + +void RenderableSmallBody::skipSingleLineInFile(std::ifstream& file) { + std::string line; + std::getline(file, line); +} + +void RenderableSmallBody::readOrbitalParamsFromThisLine(bool firstDataLine, + int& fieldCount, + unsigned int& csvLine, + std::ifstream& file) +{ + const int numDataFields = 8; + std::string name; + std::string field; + KeplerParameters keplerElements; + + //If there was a read/conversion error in the previous line, then read the remainder + // of that line and throw it out first before proceeding with the next line. + if (fieldCount != (numDataFields + 1) && !firstDataLine) { + std::getline(file, field); + } + fieldCount = 0; + + // Object designator string + std::getline(file, name, ','); + if (_startRenderIdx > 0 && _startRenderIdx == (csvLine - 1)) { + formatObjectName(name); + LINFO(fmt::format("Set render block to start at object {}", name)); + } + fieldCount++; + + // Epoch + if (!std::getline(file, field, ',')) { + throw std::invalid_argument( + "Unable to read epoch from line" + std::to_string(csvLine + 1) + ); + } + keplerElements.epoch = epochFromYMDdSubstring(field); + fieldCount++; + + // Eccentricity (unit-less) + if (!std::getline(file, field, ',')) { + throw std::invalid_argument( + "Unable to read eccentricity from line" + std::to_string(csvLine + 1) + ); + } + keplerElements.eccentricity = std::stod(field); + fieldCount++; + + // Semi-major axis (astronomical units - au) + if (!std::getline(file, field, ',')) { + throw std::invalid_argument( + "Unable to read semi-major axis from line" + std::to_string(csvLine + 1) + ); + } + keplerElements.semiMajorAxis = std::stod(field); + keplerElements.semiMajorAxis *= convertAuToKm; + fieldCount++; + + // Inclination (degrees) + if (!std::getline(file, field, ',')) { + throw std::invalid_argument( + "Unable to read inclination from line" + std::to_string(csvLine + 1) + ); + } + keplerElements.inclination = importAngleValue(field); + fieldCount++; + + // Longitude of ascending node (degrees) + if (!std::getline(file, field, ',')) { + throw std::invalid_argument( + "Unable to read ascending node from line" + std::to_string(csvLine + 1) + ); + } + keplerElements.ascendingNode = importAngleValue(field); + fieldCount++; + + // Argument of Periapsis (degrees) + if (!std::getline(file, field, ',')) { + throw std::invalid_argument( + "Unable to read arg of periapsis from line" + std::to_string(csvLine + 1) + ); + } + keplerElements.argumentOfPeriapsis = importAngleValue(field); + fieldCount++; + + // Mean Anomaly (degrees) + if (!std::getline(file, field, ',')) { + throw std::invalid_argument( + "Unable to read mean anomaly from line" + std::to_string(csvLine + 1) + ); + } + keplerElements.meanAnomaly = importAngleValue(field); + fieldCount++; + + // Period (days) + if (!std::getline(file, field)) { + throw std::invalid_argument( + "Unable to read period from line" + std::to_string(csvLine + 1) + ); + } + keplerElements.period = std::stod(field); + keplerElements.period *= convertDaysToSecs; + fieldCount++; + + _data.push_back(keplerElements); + _sbNames.push_back(name); + const double scale = static_cast(_segmentQuality) * 10.0; + _segmentSize.push_back( + static_cast(scale + (scale / pow(1 - keplerElements.eccentricity, 1.2))) + ); } static double importAngleValue(const std::string& angle) { @@ -421,157 +407,11 @@ static double importAngleValue(const std::string& angle) { return output; } -void RenderableSmallBody::initializeGL() { - glGenVertexArrays(1, &_vertexArray); - glGenBuffers(1, &_vertexBuffer); - - _programObject = SpaceModule::ProgramObjectManager.request( - ProgramName, - []() -> std::unique_ptr { - return global::renderEngine.buildRenderProgram( - ProgramName, - absPath("${MODULE_SPACE}/shaders/debrisViz_vs.glsl"), - absPath("${MODULE_SPACE}/shaders/debrisViz_fs.glsl") - ); - } - ); - - _uniformCache.modelView = _programObject->uniformLocation("modelViewTransform"); - _uniformCache.projection = _programObject->uniformLocation("projectionTransform"); - _uniformCache.lineFade = _programObject->uniformLocation("lineFade"); - _uniformCache.inGameTime = _programObject->uniformLocation("inGameTime"); - _uniformCache.color = _programObject->uniformLocation("color"); - _uniformCache.opacity = _programObject->uniformLocation("opacity"); - - updateBuffers(); - setRenderBin(Renderable::RenderBin::Overlay); -} - -void RenderableSmallBody::deinitializeGL() { - glDeleteBuffers(1, &_vertexBuffer); - glDeleteVertexArrays(1, &_vertexArray); - - SpaceModule::ProgramObjectManager.release( - ProgramName, - [](ghoul::opengl::ProgramObject* p) { - global::renderEngine.removeRenderProgram(p); - } - ); - _programObject = nullptr; +static std::string& formatObjectName(std::string& name) { + const std::string trimChars = "\t\n\v\f\r\" "; + name.erase(0, name.find_first_not_of(trimChars)); + name.erase(name.find_last_not_of(trimChars) + 1); + return name; } -bool RenderableSmallBody::isReady() const { - return _programObject != nullptr; -} - -void RenderableSmallBody::render(const RenderData& data, RendererTasks&) { - if (_sbData.empty()) - return; - - _programObject->activate(); - _programObject->setUniform(_uniformCache.opacity, _opacity); - _programObject->setUniform(_uniformCache.inGameTime, data.time.j2000Seconds()); - - - glm::dmat4 modelTransform = - glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * - glm::dmat4(data.modelTransform.rotation) * - glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); - - _programObject->setUniform( - _uniformCache.modelView, - data.camera.combinedViewMatrix() * modelTransform - ); - // Because we want the property to work similar to the planet trails - float fade = static_cast(pow(_appearance.lineFade.maxValue() - _appearance.lineFade, 2.0)); - - _programObject->setUniform(_uniformCache.projection, data.camera.projectionMatrix()); - _programObject->setUniform(_uniformCache.color, _appearance.lineColor); - _programObject->setUniform(_uniformCache.lineFade, fade); - - glLineWidth(_appearance.lineWidth); - - const size_t nrOrbits = _sbData.size(); - gl::GLint vertices = 0; - - //glDepthMask(false); - //glBlendFunc(GL_SRC_ALPHA, GL_ONE) - - glBindVertexArray(_vertexArray); - for (size_t i = 0; i < nrOrbits; ++i) { - glDrawArrays(GL_LINE_STRIP, vertices, _nSegments + 1); - vertices = vertices + _nSegments + 1; - } - glBindVertexArray(0); - - _programObject->deactivate(); - -} - -void RenderableSmallBody::updateBuffers() { - readJplSbDb(_path); - - const size_t nVerticesPerOrbit = _nSegments + 1; - _vertexBufferData.resize(_sbData.size() * nVerticesPerOrbit); - size_t orbitindex = 0; - - for (const auto& orbit : _sbData) { - _keplerTranslator.setKeplerElements( - orbit.eccentricity, - orbit.semiMajorAxis, - orbit.inclination, - orbit.ascendingNode, - orbit.argumentOfPeriapsis, - orbit.meanAnomaly, - orbit.period, - orbit.epoch - ); - - for (size_t i=0 ; i < nVerticesPerOrbit; ++i) { - size_t index = orbitindex * nVerticesPerOrbit + i; - - double timeOffset = orbit.period * - static_cast(i)/ static_cast(_nSegments); - - glm::dvec3 position = _keplerTranslator.position({ - {}, - Time(timeOffset + orbit.epoch), - Time(0.0), - false - }); - - double positionX = position.x; - double positionY = position.y; - double positionZ = position.z; - - _vertexBufferData[index].x = static_cast(positionX); - _vertexBufferData[index].y = static_cast(positionY); - _vertexBufferData[index].z = static_cast(positionZ); - _vertexBufferData[index].time = static_cast(timeOffset); - _vertexBufferData[index].epoch = orbit.epoch; - _vertexBufferData[index].period = orbit.period; - } - - ++orbitindex; - } - - glBindVertexArray(_vertexArray); - - glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); - glBufferData( - GL_ARRAY_BUFFER, - _vertexBufferData.size() * sizeof(TrailVBOLayout), - _vertexBufferData.data(), - GL_STATIC_DRAW - ); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(TrailVBOLayout), nullptr); - - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_DOUBLE, GL_FALSE, sizeof(TrailVBOLayout), (GLvoid*)(4*sizeof(GL_FLOAT)) ); - - glBindVertexArray(0); -} - -} +} // namespace openspace diff --git a/modules/space/rendering/renderablesmallbody.h b/modules/space/rendering/renderablesmallbody.h index 4e1b87219a..6a68bb7e3e 100644 --- a/modules/space/rendering/renderablesmallbody.h +++ b/modules/space/rendering/renderablesmallbody.h @@ -25,6 +25,7 @@ #ifndef __OPENSPACE_MODULE_SPACE___RENDERABLESMALLBODY___H__ #define __OPENSPACE_MODULE_SPACE___RENDERABLESMALLBODY___H__ +#include #include #include @@ -37,96 +38,29 @@ namespace openspace { -class RenderableSmallBody : public Renderable { +static double importAngleValue(const std::string& angle); + +class RenderableSmallBody : public RenderableOrbitalKepler { public: RenderableSmallBody(const ghoul::Dictionary& dictionary); - - void initializeGL() override; - void deinitializeGL() override; - - bool isReady() const override; - void render(const RenderData& data, RendererTasks& rendererTask) override; - static documentation::Documentation Documentation(); - /** - * Reads the provided file downloaded from the JPL Small Body Database and calls - * the KeplerTranslation::setKeplerElments method with the correct values. - * If \p filename is a valid JPL SBDB file but contains - * disallowed values (see KeplerTranslation::setKeplerElements), a - * KeplerTranslation::RangeError is thrown. - * - * \param filename The path to the file that contains the file. - * - * \throw ghoul::RuntimeError if the file does not exist or there is a - * problem with its format. - * \pre The \p filename must exist - */ - void readJplSbDb(const std::string& filename); private: - struct Vertex { - glm::vec3 position; - glm::vec3 color; - glm::vec2 texcoord; - }; + void readOrbitalParamsFromThisLine(bool firstDataLine, int& fieldCount, + unsigned int& csvLine, std::ifstream& file); + void readDataFile(const std::string& filename); + void initializeFileReading(); + void skipSingleLineInFile(std::ifstream& file); - struct KeplerParameters { - double inclination = 0.0; - double semiMajorAxis = 0.0; - double ascendingNode = 0.0; - double eccentricity = 0.0; - double argumentOfPeriapsis = 0.0; - double meanAnomaly = 0.0; - double meanMotion = 0.0; - double epoch = 0.0; - double period = 0.0; - }; - - /// The layout of the VBOs - struct TrailVBOLayout { - float x, y, z, time; - double epoch, period; - }; - - KeplerTranslation _keplerTranslator; - std::vector _sbData; std::vector _sbNames; - /// The backend storage for the vertex buffer object containing all points for this - /// trail. - std::vector _vertexBufferData; - /// The index array that is potentially used in the draw call. If this is empty, no /// element draw call is used. std::vector _indexBufferData; - - GLuint _vertexArray; - GLuint _vertexBuffer; - GLuint _indexBuffer; - - //GLuint _vaoTest; // vertexArrayObject - //GLuint _vboTest; // vertextBufferObject - //GLuint _eboTest; // elementBufferObject/ indexBufferObject - - void updateBuffers(); - - ghoul::opengl::ProgramObject* _programObject; - - properties::StringProperty _path; - properties::UIntProperty _nSegments; - - RenderableTrail::Appearance _appearance; - - glm::vec3 _position; - - UniformCache(modelView, projection, lineFade, inGameTime, color, opacity, - numberOfSegments) _uniformCache; - - const double convertAuToKm = 1.496e8; - const double convertDaysToSecs = 86400.; }; static double importAngleValue(const std::string& angle); +static std::string& formatObjectName(std::string& name); } // namespace openspace diff --git a/modules/space/rendering/renderablestars.cpp b/modules/space/rendering/renderablestars.cpp index 377f8c77bd..2778673233 100644 --- a/modules/space/rendering/renderablestars.cpp +++ b/modules/space/rendering/renderablestars.cpp @@ -1026,8 +1026,6 @@ void RenderableStars::render(const RenderData& data, RendererTasks&) { _program->setUniform(_uniformCache.alphaValue, _alphaValue); } - - ghoul::opengl::TextureUnit psfUnit; psfUnit.activate(); @@ -1479,7 +1477,7 @@ void RenderableStars::readSpeckFile() { for (int i = 0; i < _nValuesPerStar; ++i) { str >> values[i]; } - + bool nullArray = true; for (float v : values) { if (v != 0.0) { diff --git a/modules/space/tasks/generatedebrisvolumetask.cpp b/modules/space/tasks/generatedebrisvolumetask.cpp index d7bf763a45..3946f9ccc2 100644 --- a/modules/space/tasks/generatedebrisvolumetask.cpp +++ b/modules/space/tasks/generatedebrisvolumetask.cpp @@ -44,7 +44,6 @@ namespace { - constexpr const char* ProgramName = "RenderableSatellites"; constexpr const char* _loggerCat = "SpaceDebris"; @@ -62,13 +61,11 @@ namespace { // constexpr const char* KeyInputPath3 = "InputPath3"; // constexpr const char* KeyInputPath4 = "InputPath4"; - constexpr const char* KeyLowerDomainBound = "LowerDomainBound"; - constexpr const char* KeyUpperDomainBound = "UpperDomainBound"; + constexpr const char* KeyUpperDomainBound = "UpperDomainBound"; +} // namespace -} - -namespace openspace{ +namespace openspace { namespace volume { // The list of leap years only goes until 2056 as we need to touch this file then // again anyway ;) @@ -263,14 +260,14 @@ double epochFromSubstring(const std::string& epochString) { std::vector readTLEFile(const std::string& filename){ ghoul_assert(FileSys.fileExists(filename), "The filename must exist"); - + std::vector data; std::ifstream file; file.exceptions(std::ifstream::failbit | std::ifstream::badbit); file.open(filename); - int numberOfLines = std::count(std::istreambuf_iterator(file), + int numberOfLines = std::count(std::istreambuf_iterator(file), std::istreambuf_iterator(), '\n' ); file.seekg(std::ios_base::beg); // reset iterator to beginning of file @@ -281,7 +278,7 @@ std::vector readTLEFile(const std::string& filename){ for (int i = 0; i < numberOfObjects; i++) { std::getline(file, line); // get rid of title - + KeplerParameters keplerElements; std::getline(file, line); @@ -379,21 +376,19 @@ std::vector readTLEFile(const std::string& filename){ glm::dvec3 cartesianToSphericalCoord(glm::dvec3 position){ glm::dvec3 sphericalPosition; - //sphericalPosition.x = pow(pow(position.x,2)+pow(position.y,2)+pow(position.z,2) , 0.5); //abs(position.x + position.y + position.z); // r - //sphericalPosition.y = atan(position.y/position.x); // theta - //sphericalPosition.z = atan(pow(pow(position.x,2)+pow(position.y,2),0.5)/position.z); // abs(position.x + position.y) // p - - sphericalPosition.x = sqrt(pow(position.x,2)+pow(position.y,2)+pow(position.z,2)); // r [0, MaxApogee] - sphericalPosition.y = acos(position.z/sphericalPosition.x); // theta [0, pi] - sphericalPosition.z = atan2(position.y,position.x); // phi [-pi, pi] -> [0, 2*pi] - // if(sphericalPosition.y < 0) - sphericalPosition.z += 3.14159265358979323846264338327950288; + // r [0, MaxApogee] + sphericalPosition.x = sqrt(pow(position.x,2)+pow(position.y,2)+pow(position.z,2)); + // theta [0, pi] + sphericalPosition.y = acos(position.z/sphericalPosition.x); + // phi [-pi, pi] -> [0, 2*pi] + sphericalPosition.z = atan2(position.y,position.x); + sphericalPosition.z += glm::pi(); return sphericalPosition; } - -std::vector getPositionBuffer(std::vector tleData, double timeInSeconds, std::string gridType) { - +std::vector getPositionBuffer(std::vector tleData, + double timeInSeconds, std::string gridType) +{ float minTheta = 0.0; float minPhi = 0.0; float maxTheta = 0.0; @@ -437,14 +432,14 @@ std::vector getPositionBuffer(std::vector tleData, } // LINFO(fmt::format("pos: {} ", sphPos)); positionBuffer.push_back(sphPos); - + } else { positionBuffer.push_back(position); } - - + + } LINFO(fmt::format("max theta: {} ", maxTheta)); LINFO(fmt::format("max phi: {} ", maxPhi)); @@ -456,7 +451,7 @@ std::vector getPositionBuffer(std::vector tleData, // std::vector generatePositions(int numberOfPositions) { // std::vector positions; - + // float radius = 700000; // meter // float degreeStep = 360 / numberOfPositions; @@ -483,7 +478,7 @@ float getMaxApogee(std::vector inData){ double ah = dataElement.semiMajorAxis * (1 + dataElement.eccentricity); if (ah > maxApogee) maxApogee = ah; - } + } return static_cast(maxApogee*1000); // * 1000 for meters } @@ -501,7 +496,7 @@ int getIndexFromPosition(glm::dvec3 position, glm::uvec3 dim, float maxApogee, s ,static_cast(newPosition.y * dim.y / (2 * (maxApogee + epsilon))) ,static_cast(newPosition.z * dim.z / (2 * (maxApogee + epsilon)))); - + return coordinateIndex.z * (dim.x * dim.y) + coordinateIndex.y * dim.x + coordinateIndex.x; } else if(gridType == "Spherical"){ @@ -517,7 +512,7 @@ int getIndexFromPosition(glm::dvec3 position, glm::uvec3 dim, float maxApogee, s ,static_cast(position.y * dim.y / (3.14159265358979323846264338327950288)) ,static_cast(position.z * dim.z / (2*3.14159265358979323846264338327950288))); - + // LINFO(fmt::format("index coords: {} ", coordinateIndex)); // LINFO(fmt::format("index dim: {} ", dim)); // LINFO(fmt::format("index va: {} ", coordinateIndex.y * (dim.x * dim.y) + coordinateIndex.z * dim.x + coordinateIndex.x)); @@ -529,7 +524,7 @@ int getIndexFromPosition(glm::dvec3 position, glm::uvec3 dim, float maxApogee, s } double getVoxelVolume(int index, RawVolume& raw, glm::uvec3 dim, float maxApogee){ - // get coords from index + // get coords from index glm::uvec3 coords = raw.indexToCoords(index); double rMax = maxApogee / dim.x; @@ -585,10 +580,9 @@ GenerateDebrisVolumeTask::GenerateDebrisVolumeTask(const ghoul::Dictionary& dict _gridType = dictionary.value(KeyGridType); _lowerDomainBound = dictionary.value(KeyLowerDomainBound); _upperDomainBound = dictionary.value(KeyUpperDomainBound); - + _TLEDataVector = readTLEFile(_inputPath); _maxApogee = getMaxApogee(_TLEDataVector); - } std::string GenerateDebrisVolumeTask::description() { @@ -603,7 +597,7 @@ void GenerateDebrisVolumeTask::perform(const Task::ProgressCallback& progressCal SpiceManager::ref().unloadKernel(kernel); }; - ////////// + ////////// //1. read TLE-data and position of debris elements. // std::vectorTLEDataVector = readTLEFile(_inputPath); // std::vectorTLEDataVector1 = readTLEFile(_inputPath1); @@ -620,7 +614,7 @@ void GenerateDebrisVolumeTask::perform(const Task::ProgressCallback& progressCal // ----- or ----- if only one // _TLEDataVector = readTLEFile(_inputPath); - + ////////// VolumeGridType GridType = VolumeGridType::Cartesian; if(_gridType == "Spherical"){ @@ -637,7 +631,7 @@ void GenerateDebrisVolumeTask::perform(const Task::ProgressCallback& progressCal /** SEQUENCE * 1. handle timeStep * 1.1 either ignore last timeperiod from the latest whole timestep to _endTime - * 1.2 or extend endTime to be equal to next full timestep + * 1.2 or extend endTime to be equal to next full timestep * 2. loop to create a rawVolume for each timestep. */ @@ -659,7 +653,7 @@ void GenerateDebrisVolumeTask::perform(const Task::ProgressCallback& progressCal // 2. for(int i=0 ; i<=numberOfIterations ; ++i) { - std::vector startPositionBuffer = getPositionBuffer(_TLEDataVector, startTimeInSeconds+(i*timeStep), _gridType); //+(i*timeStep) + std::vector startPositionBuffer = getPositionBuffer(_TLEDataVector, startTimeInSeconds+(i*timeStep), _gridType); //+(i*timeStep) //LINFO(fmt::format("pos: {} ", startPositionBuffer[4])); double *densityArrayp = new double[size](); @@ -678,16 +672,16 @@ void GenerateDebrisVolumeTask::perform(const Task::ProgressCallback& progressCal densityArrayp = mapDensityToVoxels(densityArrayp, testBuffer, _dimensions, _maxApogee, _gridType); */ // create object rawVolume - + //glm::vec3 domainSize = _upperDomainBound - _lowerDomainBound; - + // TODO: Create a forEachSatallite and set(cell, value) to combine mapDensityToVoxel // and forEachVoxel for less time complexity. rawVolume.forEachVoxel([&](glm::uvec3 cell, float) { // glm::vec3 coord = _lowerDomainBound + // glm::vec3(cell) / glm::vec3(_dimensions) * domainSize; float value = getDensityAt(cell, densityArrayp, rawVolume); // (coord) - + rawVolume.set(cell, value); minVal = std::min(minVal, value); @@ -705,22 +699,22 @@ void GenerateDebrisVolumeTask::perform(const Task::ProgressCallback& progressCal size_t lastIndex = _rawVolumeOutputPath.find_last_of("."); std::string rawOutputName = _rawVolumeOutputPath.substr(0, lastIndex); - rawOutputName += std::to_string(i) + ".rawvolume"; + rawOutputName += std::to_string(i) + ".rawvolume"; lastIndex = _dictionaryOutputPath.find_last_of("."); std::string dictionaryOutputName = _dictionaryOutputPath.substr(0, lastIndex); - dictionaryOutputName += std::to_string(i) + ".dictionary"; + dictionaryOutputName += std::to_string(i) + ".dictionary"; ghoul::filesystem::File file(rawOutputName); const std::string directory = file.directoryName(); if (!FileSys.directoryExists(directory)) { FileSys.createDirectory(directory, ghoul::filesystem::FileSystem::Recursive::Yes); } - + volume::RawVolumeWriter writer(rawOutputName); writer.write(rawVolumeQueue.front()); rawVolumeQueue.pop(); - + RawVolumeMetadata metadata; // alternatively metadata.hasTime = false; metadata.time = Time::convertTime(_startTime)+(i*timeStep); @@ -745,7 +739,6 @@ void GenerateDebrisVolumeTask::perform(const Task::ProgressCallback& progressCal std::fstream f(dictionaryOutputName, std::ios::out); f << "return " << metadataString; f.close(); - } } diff --git a/modules/space/tasks/generatedebrisvolumetask.h b/modules/space/tasks/generatedebrisvolumetask.h index 887f75be60..1a0225b4f2 100644 --- a/modules/space/tasks/generatedebrisvolumetask.h +++ b/modules/space/tasks/generatedebrisvolumetask.h @@ -59,7 +59,7 @@ private: std::string _timeStep; std::string _endTime; std::string _inputPath; - + glm::uvec3 _dimensions; glm::vec3 _lowerDomainBound; glm::vec3 _upperDomainBound; diff --git a/modules/space/translation/keplertranslation.h b/modules/space/translation/keplertranslation.h index 83c8fd6233..0370822e9e 100644 --- a/modules/space/translation/keplertranslation.h +++ b/modules/space/translation/keplertranslation.h @@ -78,7 +78,7 @@ public: * be passed to the constructor */ static documentation::Documentation Documentation(); - + /** * Sets the internal values for the Keplerian elements and the epoch as a string of * the form YYYY MM DD HH:mm:ss. @@ -120,7 +120,7 @@ public: void setKeplerElements(double eccentricity, double semiMajorAxis, double inclination, double ascendingNode, double argumentOfPeriapsis, double meanAnomalyAtEpoch, double orbitalPeriod, double epoch); - + /// Default construct that initializes all the properties and member variables KeplerTranslation(); diff --git a/modules/space/translation/tletranslation.cpp b/modules/space/translation/tletranslation.cpp index ec5fb75137..add42596de 100644 --- a/modules/space/translation/tletranslation.cpp +++ b/modules/space/translation/tletranslation.cpp @@ -145,9 +145,7 @@ namespace { // The main overview of this function: // 1. Reconstruct the full year from the YY part - // 2. Calculate the number of seconds since the beginning of the year - // 2.a Get the number of full days since the beginning of the year - // 2.b If the year is a leap year, modify the number of days + // 2. Calculate the number of days since the beginning of the year // 3. Convert the number of days to a number of seconds // 4. Get the number of leap seconds since January 1st, 2000 and remove them // 5. Adjust for the fact the epoch starts on 1st Januaray at 12:00:00, not @@ -168,21 +166,8 @@ namespace { const int daysSince2000 = countDays(year); // 2. - // 2.a double daysInYear = std::atof(epochString.substr(2).c_str()); - // 2.b - const bool isInLeapYear = std::find( - LeapYears.begin(), - LeapYears.end(), - year - ) != LeapYears.end(); - if (isInLeapYear && daysInYear >= 60) { - // We are in a leap year, so we have an effective day more if we are - // beyond the end of february (= 31+29 days) - --daysInYear; - } - // 3 using namespace std::chrono; const int SecondsPerDay = static_cast(seconds(hours(24)).count()); diff --git a/modules/spacecraftinstruments/util/projectioncomponent.cpp b/modules/spacecraftinstruments/util/projectioncomponent.cpp index 704b361b6b..847a45523c 100644 --- a/modules/spacecraftinstruments/util/projectioncomponent.cpp +++ b/modules/spacecraftinstruments/util/projectioncomponent.cpp @@ -69,7 +69,8 @@ namespace { constexpr const char* sequenceTypePlaybook = "playbook"; constexpr const char* sequenceTypeHybrid = "hybrid"; constexpr const char* sequenceTypeInstrumentTimes = "instrument-times"; - constexpr const char* sequenceTypeImageAndInstrumentTimes = "image-and-instrument-times"; + constexpr const char* sequenceTypeImageAndInstrumentTimes = + "image-and-instrument-times"; constexpr const char* placeholderFile = "${DATA}/placeholder.png"; @@ -381,7 +382,9 @@ void ProjectionComponent::initialize(const std::string& identifier, ) ); - std::string timesSequenceSource = absPath(dictionary.value(keyTimesSequenceDir)); + std::string timesSequenceSource = absPath( + dictionary.value(keyTimesSequenceDir) + ); ghoul::Dictionary timesTranslationDictionary; dictionary.getValue(keyTimesTranslation, timesTranslationDictionary); diff --git a/modules/touch/include/touchinteraction.h b/modules/touch/include/touchinteraction.h index 8faed8bbfb..7ef8e2867d 100644 --- a/modules/touch/include/touchinteraction.h +++ b/modules/touch/include/touchinteraction.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -79,16 +80,14 @@ public: /* Main function call * 1 Checks if doubleTap occured - * 2 Goes through the guiMode() function - * 3 Continues if GUI isn't on - * 4 If the node in focus is large enough and all contact points have selected it, + * 2 If the node in focus is large enough and all contact points have selected it, * calls directControl() function for direct-manipulation - * 5 Updates std::vector _selected (only if LMA successfully + * 3 Updates std::vector _selected (only if LMA successfully * converged, avoids interaction to snap on LMA fails) - * 6 If directControl() wasn't called this frame, interpret the incoming + * 4 If directControl() wasn't called this frame, interpret the incoming * list and decide what type of interaction this frame should do - * 7 Compute the new total velocities after interaction - * 8 Evaluate if directControl should be called next frame- true if all contact points + * 5 Compute the new total velocities after interaction + * 6 Evaluate if directControl should be called next frame- true if all contact points * select the same node and said node is larger than _nodeRadiusThreshold */ @@ -96,7 +95,7 @@ public: std::vector& lastProcessed); // Calculates the new camera state with velocities and time since last frame - void step(double dt); + void step(double dt, bool directTouch = false); // Called each frame we have no new input, used to reset data void resetAfterInput(); @@ -114,11 +113,6 @@ public: void setCamera(Camera* camera); private: - /* Returns true if we have the GUI window open. If so, emulates the incoming touch - * input to a mouse such that we can interact with the GUI - */ - bool isGuiMode(glm::dvec2 screenPosition, size_t numFingers); - /* Function that calculates the new camera state such that it minimizes the L2 error * in screenspace * between contact points and surface coordinates projected to clip space using LMA @@ -166,6 +160,7 @@ private: properties::IntProperty _deceleratesPerSecond; properties::FloatProperty _touchScreenSize; properties::FloatProperty _tapZoomFactor; + properties::FloatProperty _pinchZoomFactor; properties::FloatProperty _nodeRadiusThreshold; properties::FloatProperty _rollAngleThreshold; properties::FloatProperty _orbitSpeedThreshold; @@ -181,10 +176,8 @@ private: properties::BoolProperty _panEnabled; properties::FloatProperty _interpretPan; properties::FloatProperty _slerpTime; - properties::IVec2Property _guiButton; properties::Vec4Property _friction; properties::FloatProperty _pickingRadiusMinimum; - properties::BoolProperty _ignoreGui; properties::FloatProperty _constTimeDecay_secs; #ifdef TOUCH_DEBUG_PROPERTIES @@ -202,7 +195,7 @@ private: double pinchConsecZoomFactor = 0; //int stepVelUpdate = 0; #endif - + std::array _pinchInputs; // Class variables VelocityStates _vel; VelocityStates _lastVel; @@ -220,7 +213,6 @@ private: bool _doubleTap = false; bool _zoomOutTap = false; bool _lmSuccess = true; - bool _guiON = false; std::vector _selected; SceneGraphNode* _pickingSelected = nullptr; DirectInputSolver _solver; @@ -242,4 +234,3 @@ private: } // openspace namespace #endif // __OPENSPACE_MODULE_TOUCH___TOUCH_INTERACTION___H__ - diff --git a/modules/touch/src/touchinteraction.cpp b/modules/touch/src/touchinteraction.cpp index b12795b9e6..c31ac046ea 100644 --- a/modules/touch/src/touchinteraction.cpp +++ b/modules/touch/src/touchinteraction.cpp @@ -29,7 +29,6 @@ #include #endif -#include #include #include #include @@ -117,6 +116,13 @@ namespace { "" // @TODO Missing documentation }; + constexpr openspace::properties::Property::PropertyInfo PinchZoomFactorInfo = { + "PinchZoomFactor", + "Scaling distance travelled on pinch", + "This value is used to reduce the amount of pinching needed. A linear kind of " + "sensitivity that will alter the pinch-zoom speed." + }; + constexpr openspace::properties::Property::PropertyInfo DirectManipulationInfo = { "DirectManipulationRadius", "Radius a planet has to have to activate direct-manipulation", @@ -205,12 +211,6 @@ namespace { "" // @TODO Missing documentation }; - constexpr openspace::properties::Property::PropertyInfo GuiButtonSizeInfo = { - "GuiButtonSize", - "GUI button size in pixels", - "" // @TODO Missing documentation - }; - constexpr openspace::properties::Property::PropertyInfo FrictionInfo = { "Friction", "Friction for different interactions (orbit, zoom, roll, pan)", @@ -264,6 +264,7 @@ TouchInteraction::TouchInteraction() , _deceleratesPerSecond(DecelatesPerSecondInfo, 240, 60, 300) , _touchScreenSize(TouchScreenSizeInfo, 55.0f, 5.5f, 150.0f) , _tapZoomFactor(TapZoomFactorInfo, 0.2f, 0.f, 0.5f) + , _pinchZoomFactor(PinchZoomFactorInfo, 0.01f, 0.f, 0.2f) , _nodeRadiusThreshold(DirectManipulationInfo, 0.2f, 0.0f, 1.0f) , _rollAngleThreshold(RollThresholdInfo, 0.025f, 0.f, 0.05f) , _orbitSpeedThreshold(OrbitSpinningThreshold, 0.005f, 0.f, 0.01f) @@ -277,7 +278,12 @@ TouchInteraction::TouchInteraction() 0.25f ) , _zoomBoundarySphereMultiplier(ZoomBoundarySphereMultiplierInfo, 1.001f, 1.f, 1.01f) - , _zoomOutLimit(ZoomOutLimitInfo, std::numeric_limits::max(), 1000.0, std::numeric_limits::max()) + , _zoomOutLimit( + ZoomOutLimitInfo, + std::numeric_limits::max(), + 1000.0, + std::numeric_limits::max() + ) , _zoomInLimit(ZoomInLimitInfo, -1.0, 0.0, std::numeric_limits::max()) , _inputStillThreshold(InputSensitivityInfo, 0.0005f, 0.f, 0.001f) // used to void wrongly interpreted roll interactions @@ -285,12 +291,6 @@ TouchInteraction::TouchInteraction() , _panEnabled(PanModeInfo, false) , _interpretPan(PanDeltaDistanceInfo, 0.015f, 0.f, 0.1f) , _slerpTime(SlerpTimeInfo, 3.f, 0.1f, 5.f) - , _guiButton( - GuiButtonSizeInfo, - glm::ivec2(32, 64), - glm::ivec2(8, 16), - glm::ivec2(128, 256) - ) , _friction( FrictionInfo, glm::vec4(0.025f, 0.025f, 0.02f, 0.02f), @@ -303,12 +303,9 @@ TouchInteraction::TouchInteraction() 0.f, 1.f ) - , _ignoreGui( // @TODO Missing documentation - { "Ignore GUI", "Disable GUI touch interaction", "" }, - false - ) + , _pinchInputs({ TouchInput(0, 0, 0.0, 0.0, 0.0), TouchInput(0, 0, 0.0, 0.0, 0.0) }) , _vel{ glm::dvec2(0.0), 0.0, 0.0, glm::dvec2(0.0) } - , _sensitivity{ glm::dvec2(0.08, 0.045), 12.0 /*4.0*/, 2.75, glm::dvec2(0.08, 0.045) } + , _sensitivity{ glm::dvec2(0.08, 0.045), 12.0, 2.75, glm::dvec2(0.08, 0.045) } , _constTimeDecay_secs(ConstantTimeDecaySecsInfo, 1.75f, 0.1f, 4.0f) // calculated with two vectors with known diff in length, then // projDiffLength/diffLength. @@ -320,6 +317,7 @@ TouchInteraction::TouchInteraction() addProperty(_deceleratesPerSecond); addProperty(_touchScreenSize); addProperty(_tapZoomFactor); + addProperty(_pinchZoomFactor); addProperty(_nodeRadiusThreshold); addProperty(_rollAngleThreshold); addProperty(_orbitSpeedThreshold); @@ -336,10 +334,8 @@ TouchInteraction::TouchInteraction() addProperty(_panEnabled); addProperty(_interpretPan); addProperty(_slerpTime); - addProperty(_guiButton); addProperty(_friction); addProperty(_pickingRadiusMinimum); - addProperty(_ignoreGui); #ifdef TOUCH_DEBUG_PROPERTIES addPropertySubOwner(_debugProperties); @@ -401,69 +397,36 @@ void TouchInteraction::updateStateFromInput(const std::vector& } size_t numFingers = list.size(); - if (!isGuiMode(pos, numFingers)) { - bool isTransitionBetweenModes = (_wasPrevModeDirectTouch != _directTouchMode); - if (isTransitionBetweenModes) { - _vel.orbit = glm::dvec2(0.0); - _vel.zoom = 0.0; - _vel.roll = 0.0; - _vel.pan = glm::dvec2(0.0); - resetAfterInput(); - } + bool isTransitionBetweenModes = (_wasPrevModeDirectTouch != _directTouchMode); + if (isTransitionBetweenModes) { + _vel.orbit = glm::dvec2(0.0); + _vel.zoom = 0.0; + _vel.roll = 0.0; + _vel.pan = glm::dvec2(0.0); + resetAfterInput(); + } - if (_directTouchMode && _selected.size() > 0 && numFingers == _selected.size()) { + if (_directTouchMode && _selected.size() > 0 && numFingers == _selected.size()) { #ifdef TOUCH_DEBUG_PROPERTIES - _debugProperties.interactionMode = "Direct"; + _debugProperties.interactionMode = "Direct"; #endif - directControl(list); - } - if (_lmSuccess) { - findSelectedNode(list); - } + directControl(list); + } + if (_lmSuccess) { + findSelectedNode(list); + } - if (!_directTouchMode) { + if (!_directTouchMode) { #ifdef TOUCH_DEBUG_PROPERTIES - _debugProperties.interactionMode = "Velocities"; + _debugProperties.interactionMode = "Velocities"; #endif - computeVelocities(list, lastProcessed); - } - - _wasPrevModeDirectTouch = _directTouchMode; - // evaluates if current frame is in directTouchMode (will be used next frame) - _directTouchMode = - (_currentRadius > _nodeRadiusThreshold && _selected.size() == numFingers); - } -} - -bool TouchInteraction::isGuiMode(glm::dvec2 screenPosition, size_t numFingers) { - if (_ignoreGui) { - return false; + computeVelocities(list, lastProcessed); } - ImGUIModule& module = *(global::moduleEngine.module()); - _guiON = module.gui.isEnabled(); - - if (_tap && numFingers == 1 && - std::abs(screenPosition.x) < _guiButton.value().x && - std::abs(screenPosition.y) < _guiButton.value().y) - { - // pressed invisible button - _guiON = !_guiON; - module.gui.setEnabled(_guiON); - - LINFO(fmt::format( - "GUI mode is {}. Inside box by: ({}%, {}%)", - _guiON ? "activated" : "deactivated", - static_cast(100 * (screenPosition.x / _guiButton.value().x)), - static_cast(100 * (screenPosition.y / _guiButton.value().y)) - )); - } - else if (_guiON) { - // emulate touch input as a mouse - module.touchInput = { _guiON, screenPosition, 1 }; - } - - return _guiON; + _wasPrevModeDirectTouch = _directTouchMode; + // evaluates if current frame is in directTouchMode (will be used next frame) + _directTouchMode = + (_currentRadius > _nodeRadiusThreshold && _selected.size() == numFingers); } void TouchInteraction::directControl(const std::vector& list) { @@ -494,7 +457,7 @@ void TouchInteraction::directControl(const std::vector& list) _vel.pan = glm::dvec2(par.at(4), par.at(5)); } } - step(1.0); + step(1.0, true); // Reset velocities after setting new camera state _lastVel = _vel; @@ -506,11 +469,6 @@ void TouchInteraction::directControl(const std::vector& list) else { // prevents touch to infinitely be active (due to windows bridge case where event // doesnt get consumed sometimes when LMA fails to converge) - Touch touch; - touch.active = true; - touch.pos = glm::dvec2(0.0); - touch.action = 1; - global::moduleEngine.module()->touchInput = touch; resetAfterInput(); } } @@ -722,7 +680,8 @@ int TouchInteraction::interpretInteraction(const std::vector& double res = 0.0; float lastAngle = lastPoint.angleToPos(_centroid.x, _centroid.y); - float currentAngle = inputHolder.latestInput().angleToPos(_centroid.x, _centroid.y); + float currentAngle = + inputHolder.latestInput().angleToPos(_centroid.x, _centroid.y); if (lastAngle > currentAngle + 1.5 * glm::pi()) { res = currentAngle + (2.0 * glm::pi() - lastAngle); } @@ -777,6 +736,15 @@ int TouchInteraction::interpretInteraction(const std::vector& return ROLL; } else { + const bool sameInput0 = _pinchInputs[0].holdsInput(list[0].latestInput()); + const bool sameInput1 = _pinchInputs[1].holdsInput(list[1].latestInput()); + if (sameInput0 && sameInput1) { + _pinchInputs[0].tryAddInput(list[0].latestInput()); + _pinchInputs[1].tryAddInput(list[1].latestInput()); + } else { + _pinchInputs[0] = TouchInputHolder(list[0].latestInput()); + _pinchInputs[1] = TouchInputHolder(list[1].latestInput()); + } return PINCH; } } @@ -816,6 +784,9 @@ void TouchInteraction::computeVelocities(const std::vector& li #endif const TouchInputHolder& inputHolder = list.at(0); + const glm::ivec2 windowSize = global::windowDelegate.currentWindowSize(); + const float aspectRatio = + static_cast(windowSize.x) / static_cast(windowSize.y); switch (action) { case ROT: { // add rotation velocity _vel.orbit += glm::dvec2(inputHolder.speedX() * @@ -829,54 +800,29 @@ void TouchInteraction::computeVelocities(const std::vector& li } case PINCH: { // add zooming velocity - dependant on distance difference between contact - // points this/last frame - double distance = std::accumulate( - list.begin(), - list.end(), - 0.0, - [&](double d, const TouchInputHolder& c) { - const glm::vec2 currPos = { c.latestInput().x, c.latestInput().y }; - return d + glm::distance(currPos, _centroid); - } - ) / list.size(); - double lastDistance = std::accumulate( - lastProcessed.begin(), - lastProcessed.end(), - 0.f, - [&](float d, const TouchInput& p) { - const glm::vec2 lastPos = { p.x, p.y }; - return d + glm::distance(lastPos, _centroid); - } - ) / lastProcessed.size(); + // points this/first frame + using namespace glm; + const TouchInput& startFinger0 = _pinchInputs[0].firstInput(); + const TouchInput& startFinger1 = _pinchInputs[1].firstInput(); + const dvec2 startVec0 = dvec2(startFinger0.x * aspectRatio, startFinger0.y); + const dvec2 startVec1 = dvec2(startFinger1.x * aspectRatio, startFinger1.y); + double distToCentroidStart = length(startVec0 - startVec1) / 2.0; - glm::dvec3 camPos = _camera->positionVec3(); - glm::dvec3 centerPos = anchor->worldPosition(); - glm::dvec3 currDistanceToFocusNode = camPos - centerPos; + const TouchInput& endFinger0 = _pinchInputs[0].latestInput(); + const TouchInput& endFinger1 = _pinchInputs[1].latestInput(); + const dvec2 endVec0 = dvec2(endFinger0.x * aspectRatio, endFinger0.y); + const dvec2 endVec1 = dvec2(endFinger1.x * aspectRatio, endFinger1.y); + double distToCentroidEnd = length(endVec0 - endVec1) / 2.0; - const double distanceFromFocusSurface = - length(currDistanceToFocusNode) - anchor->boundingSphere(); - double zoomFactor = (distance - lastDistance); + double zoomFactor = distToCentroidEnd - distToCentroidStart; #ifdef TOUCH_DEBUG_PROPERTIES pinchConsecCt++; pinchConsecZoomFactor += zoomFactor; #endif - _constTimeDecayCoeff.zoom = computeConstTimeDecayCoefficient(_vel.zoom); - if (distanceFromFocusSurface > 0.1) { - const double ratioOfDistanceToNodeVsSurface = - length(currDistanceToFocusNode) / distanceFromFocusSurface; - if (ratioOfDistanceToNodeVsSurface > _zoomSensitivityDistanceThreshold) { - zoomFactor *= pow( - std::abs(distanceFromFocusSurface), - static_cast(_zoomSensitivityExponential) - ); - } - } - else { - zoomFactor = 1.0; - } - _vel.zoom = zoomFactor * _zoomSensitivityProportionalDist * - std::max(_touchScreenSize.value() * 0.1, 1.0); + _constTimeDecayCoeff.zoom = 1.0; + _vel.zoom = zoomFactor * _pinchZoomFactor * _zoomSensitivityProportionalDist * + std::max(_touchScreenSize.value() * 0.1, 1.0); break; } case ROLL: { @@ -917,7 +863,7 @@ void TouchInteraction::computeVelocities(const std::vector& li break; } case PAN: { - // add local rotation velocity + // add local rotation velocity _vel.pan += glm::dvec2(inputHolder.speedX() * _sensitivity.pan.x, inputHolder.speedY() * _sensitivity.pan.y); double panVelocityAvg = glm::distance(_vel.pan.x, _vel.pan.y); @@ -925,7 +871,7 @@ void TouchInteraction::computeVelocities(const std::vector& li break; } case PICK: { - // pick something in the scene as focus node + // pick something in the scene as focus node if (_pickingSelected) { setFocusNode(_pickingSelected); @@ -992,7 +938,7 @@ double TouchInteraction::computeTapZoomDistance(double zoomGain) { // Main update call, calculates the new orientation and position for the camera depending // on _vel and dt. Called every frame -void TouchInteraction::step(double dt) { +void TouchInteraction::step(double dt, bool directTouch) { using namespace glm; const SceneGraphNode* anchor = @@ -1086,7 +1032,7 @@ void TouchInteraction::step(double dt) { centerToActualSurfaceModelSpace; const double nodeRadius = length(centerToActualSurface); - // Because of heightmaps we should make sure we do not go through the surface + // Because of heightmaps we need to ensure we don't go through the surface if (_zoomInLimit.value() < nodeRadius) { #ifdef TOUCH_DEBUG_PROPERTIES LINFO(fmt::format("{}: Zoom In limit should be larger than anchor " @@ -1103,23 +1049,46 @@ void TouchInteraction::step(double dt) { _loggerCat, _zoomOutLimit.value() )); } + const double currentPosDistance = length(centerToCamera); //Apply the velocity to update camera position - glm::dvec3 zoomDistanceIncrement = directionToCenter * _vel.zoom * dt; - const double newPosDistance = length(centerToCamera + zoomDistanceIncrement); - const double currentPosDistance = length(centerToCamera); + double zoomVelocity = _vel.zoom; + if (!directTouch) { + const double distanceFromSurface = + length(currentPosDistance) - anchor->boundingSphere(); + if (distanceFromSurface > 0.1) { + const double ratioOfDistanceToNodeVsSurf = + length(currentPosDistance) / distanceFromSurface; + if (ratioOfDistanceToNodeVsSurf > _zoomSensitivityDistanceThreshold) { + zoomVelocity *= pow( + std::abs(distanceFromSurface), + static_cast(_zoomSensitivityExponential) + ); + } + } + else { + zoomVelocity = 1.0; + } + } + + const glm::dvec3 zoomDistanceInc = directionToCenter * zoomVelocity * dt; + const double newPosDistance = length(centerToCamera + zoomDistanceInc); // Possible with other navigations performed outside touch interaction const bool currentPosViolatingZoomOutLimit = - (currentPosDistance >= _zoomOutLimit.value()); + (currentPosDistance >= _zoomOutLimit); const bool willNewPositionViolateZoomOutLimit = - (newPosDistance >= _zoomOutLimit.value()); + (newPosDistance >= _zoomOutLimit); bool willNewPositionViolateZoomInLimit = (newPosDistance < zoomInBounds); + bool willNewPositionViolateDirection = + (currentPosDistance <= length(zoomDistanceInc)); - if (!willNewPositionViolateZoomInLimit - && !willNewPositionViolateZoomOutLimit) { - camPos += zoomDistanceIncrement; + if (!willNewPositionViolateZoomInLimit && + !willNewPositionViolateDirection && + !willNewPositionViolateZoomOutLimit) + { + camPos += zoomDistanceInc; } else if (currentPosViolatingZoomOutLimit) { #ifdef TOUCH_DEBUG_PROPERTIES @@ -1129,7 +1098,7 @@ void TouchInteraction::step(double dt) { #endif // Only allow zooming in if you are outside the zoom out limit if (newPosDistance < currentPosDistance) { - camPos += zoomDistanceIncrement; + camPos += zoomDistanceInc; } } else { @@ -1204,30 +1173,19 @@ void TouchInteraction::resetAfterInput() { _vel.orbit = _lastVel.orbit * spinDelta; } } - // Reset emulated mouse values - ImGUIModule& module = *(global::moduleEngine.module()); - if (_guiON) { - bool activeLastFrame = module.touchInput.action; - module.touchInput.active = false; - if (activeLastFrame) { - module.touchInput.active = true; - module.touchInput.action = 0; - } - } - else { - module.touchInput.active = false; - module.touchInput.action = 0; - } _lmSuccess = true; - // Ensure that _guiON is consistent with properties in OnScreenGUI and - _guiON = module.gui.isEnabled(); // Reset variables _lastVel.orbit = glm::dvec2(0.0); _lastVel.zoom = 0.0; _lastVel.roll = 0.0; _lastVel.pan = glm::dvec2(0.0); + + _constTimeDecayCoeff.zoom = computeConstTimeDecayCoefficient(_vel.zoom); + _pinchInputs[0].clearInputs(); + _pinchInputs[1].clearInputs(); + _selected.clear(); _pickingSelected = nullptr; } @@ -1240,6 +1198,7 @@ void TouchInteraction::resetToDefault() { _deceleratesPerSecond.set(240); _touchScreenSize.set(55.0f); _tapZoomFactor.set(0.2f); + _pinchZoomFactor.set(0.01f); _nodeRadiusThreshold.set(0.2f); _rollAngleThreshold.set(0.025f); _orbitSpeedThreshold.set(0.005f); @@ -1249,7 +1208,6 @@ void TouchInteraction::resetToDefault() { _centroidStillThreshold.set(0.0018f); _interpretPan.set(0.015f); _slerpTime.set(3.0f); - _guiButton.set(glm::ivec2(32, 64)); _friction.set(glm::vec4(0.025, 0.025, 0.02, 0.02)); } diff --git a/modules/touch/src/win32_touch.cpp b/modules/touch/src/win32_touch.cpp index 9507b5ef8a..7ac553205b 100644 --- a/modules/touch/src/win32_touch.cpp +++ b/modules/touch/src/win32_touch.cpp @@ -42,7 +42,7 @@ namespace { constexpr const char* _loggerCat = "win32_touch"; HHOOK gTouchHook = nullptr; - std::thread* gMouseHookThread; + std::thread* gMouseHookThread = nullptr; HHOOK gMouseHook = nullptr; bool gStarted = false; std::chrono::microseconds gStartTime = std::chrono::microseconds(0); @@ -50,13 +50,22 @@ namespace { UINT32, std::unique_ptr > gTouchInputsMap; + #ifdef ENABLE_TUIOMESSAGES TUIO::TuioServer* gTuioServer = nullptr; std::unordered_map gCursorMap; #endif + + const long long gFrequency = []() -> long long { + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + return frequency.QuadPart; + }(); + } // namespace namespace openspace { + LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam); // This hook will only work for Win8+ Digitizers. @@ -79,10 +88,14 @@ LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam) { break; } - using namespace std::chrono; - const microseconds timestamp = duration_cast( - high_resolution_clock::now().time_since_epoch() - ) - gStartTime; + //Implementation from microsoft STL of high_resolution_clock(steady_clock): + const long long freq = gFrequency; + const long long whole = (info.PerformanceCount / freq) * std::micro::den; + const long long part = (info.PerformanceCount % freq) * + std::micro::den / freq; + const std::chrono::microseconds timestamp = + std::chrono::duration(whole + part) - gStartTime; + RECT rect; GetClientRect(pStruct->hwnd, reinterpret_cast(&rect)); @@ -90,17 +103,17 @@ LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam) { // native touch to screen conversion ScreenToClient(pStruct->hwnd, reinterpret_cast(&p)); - float xPos = static_cast(p.x) / - static_cast(rect.right - rect.left); - float yPos = static_cast(p.y) / - static_cast(rect.bottom - rect.top); + const float xPos = static_cast(p.x) / + static_cast(rect.right - rect.left); + const float yPos = static_cast(p.y) / + static_cast(rect.bottom - rect.top); TouchInput touchInput( reinterpret_cast(info.sourceDevice), static_cast(info.pointerId), xPos, yPos, - static_cast(timestamp.count())/1'000'000.0 + static_cast(timestamp.count()) / 1000000.0 ); if (info.pointerFlags & POINTER_FLAG_DOWN) { @@ -160,23 +173,13 @@ LRESULT CALLBACK HookCallback(int nCode, WPARAM wParam, LPARAM lParam) { return CallNextHookEx(0, nCode, wParam, lParam); } -Win32TouchHook::Win32TouchHook(void* nativeWindow) -{ +Win32TouchHook::Win32TouchHook(void* nativeWindow) { HWND hWnd = reinterpret_cast(nativeWindow); if (hWnd == nullptr) { LINFO("No windowhandle available for touch input."); return; } - // HACK: This hack is required as long as our GLFW version is based on the touch - // branch. There is no convenient way to set a GLFWBool (uint32_t) which sets the - // state of touch-to-mouseinput interpretation. It happens to be 116 bytes into an - // internal glfw struct... - uint32_t* HACKY_PTR = (uint32_t *)GetPropW(hWnd, L"GLFW"); - HACKY_PTR += 116/sizeof(uint32_t); - *HACKY_PTR = 1; - - // Test for touch: int value = GetSystemMetrics(SM_DIGITIZER); if ((value & NID_READY) == 0) { @@ -223,7 +226,7 @@ Win32TouchHook::Win32TouchHook(void* nativeWindow) gTouchHook = SetWindowsHookExW( WH_GETMESSAGE, HookCallback, - GetModuleHandleW(NULL), + GetModuleHandleW(nullptr), GetCurrentThreadId() ); @@ -285,7 +288,7 @@ LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) { } LPMSLLHOOKSTRUCT msg = reinterpret_cast(lParam); // block injected events (in most cases generated by touches) - bool isFromTouch = (msg->dwExtraInfo || SIGNATURE_MASK) == MOUSEEVENTF_FROMTOUCH; + bool isFromTouch = (msg->dwExtraInfo | SIGNATURE_MASK) == MOUSEEVENTF_FROMTOUCH; if (msg->flags & LLMHF_INJECTED || isFromTouch) { return 1; } diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 73a12cbbfc..1672b2cf42 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -221,7 +221,7 @@ void TouchModule::internalInitialize(const ghoul::Dictionary& /*dictionary*/){ global::callback::touchUpdated.push_back( [this](TouchInput i) { updateOrAddTouchInput(i); - return true; + return true; } ); diff --git a/modules/toyvolume/rendering/renderabletoyvolume.cpp b/modules/toyvolume/rendering/renderabletoyvolume.cpp index ab642b0a13..46dc7ffca8 100644 --- a/modules/toyvolume/rendering/renderabletoyvolume.cpp +++ b/modules/toyvolume/rendering/renderabletoyvolume.cpp @@ -69,7 +69,8 @@ namespace { "" // @TODO Missing documentation }; - constexpr openspace::properties::Property::PropertyInfo DownscaleVolumeRenderingInfo = { + constexpr openspace::properties::Property::PropertyInfo DownscaleVolumeRenderingInfo = + { "Downscale", "Downscale Factor Volume Rendering", "This value set the downscaling factor" diff --git a/modules/vislab/rendering/renderabledistancelabel.cpp b/modules/vislab/rendering/renderabledistancelabel.cpp index eac120946d..db6d3c0cef 100644 --- a/modules/vislab/rendering/renderabledistancelabel.cpp +++ b/modules/vislab/rendering/renderabledistancelabel.cpp @@ -53,8 +53,8 @@ namespace { constexpr openspace::properties::Property::PropertyInfo CustomUnitDescriptorInfo = { "CustomUnitDescriptor", "Custom Unit Descriptor", - "Property to define a custom unit descriptor to use to describe the distance value." - "Defaults to the units SI descriptor if not specified." + "Property to define a custom unit descriptor to use to describe the distance " + "value. Defaults to the units SI descriptor if not specified." }; } @@ -111,7 +111,8 @@ RenderableDistanceLabel::RenderableDistanceLabel(const ghoul::Dictionary& dictio addProperty(_distanceUnit); } if (dictionary.hasKey(CustomUnitDescriptorInfo.identifier)) { - _customUnitDescriptor = dictionary.value(CustomUnitDescriptorInfo.identifier); + _customUnitDescriptor = + dictionary.value(CustomUnitDescriptorInfo.identifier); addProperty(_customUnitDescriptor); } } @@ -144,7 +145,9 @@ void RenderableDistanceLabel::update(const UpdateData&) { } // Get distance as string and remove fractional part - std::string distanceText = std::to_string(std::round(nodeline->distance() / scale)); + std::string distanceText = std::to_string( + std::round(nodeline->distance() / scale) + ); int pos = static_cast(distanceText.find(".")); std::string subStr = distanceText.substr(pos); distanceText.erase(pos, subStr.size()); diff --git a/modules/webbrowser/include/browserinstance.h b/modules/webbrowser/include/browserinstance.h index b96e701da8..5e74c6806c 100644 --- a/modules/webbrowser/include/browserinstance.h +++ b/modules/webbrowser/include/browserinstance.h @@ -84,10 +84,9 @@ public: void draw(); void close(bool force = false); - void sendTouchPressEvent(const CefMouseEvent & event, - CefBrowserHost::MouseButtonType button, const int clickCount); - void sendResleasePressEvent(const CefMouseEvent & event, - CefBrowserHost::MouseButtonType button, const int clickCount); +#ifdef WIN32 + void sendTouchEvent(const CefTouchEvent& event) const; +#endif bool sendKeyEvent(const CefKeyEvent& event); bool sendMouseClickEvent(const CefMouseEvent& event, diff --git a/modules/webbrowser/include/eventhandler.h b/modules/webbrowser/include/eventhandler.h index 406b27813d..870eb49a47 100644 --- a/modules/webbrowser/include/eventhandler.h +++ b/modules/webbrowser/include/eventhandler.h @@ -84,6 +84,19 @@ private: */ CefMouseEvent mouseEvent(KeyModifier mods = KeyModifier::NoModifier); +#ifdef WIN32 + /** + * Build a CEF touch event based on our internal structure + * + * Note: as of 02/21/2020 we are using an older version of CEF on OSX + * than WIN32. + * This version does not handle the CefTouchEvent type and does + * not have any internal touch handling. + */ + CefTouchEvent touchEvent(const TouchInput& input, + const cef_touch_event_type_t eventType) const; +#endif + /** * Find the CEF key event to use for a given action. * diff --git a/modules/webbrowser/src/browserinstance.cpp b/modules/webbrowser/src/browserinstance.cpp index 52016fe15f..14eaaef9b0 100644 --- a/modules/webbrowser/src/browserinstance.cpp +++ b/modules/webbrowser/src/browserinstance.cpp @@ -149,19 +149,11 @@ bool BrowserInstance::sendMouseClickEvent(const CefMouseEvent& event, return hasContent(event.x, event.y); } -void BrowserInstance::sendTouchPressEvent(const CefMouseEvent& event, - CefBrowserHost::MouseButtonType button, - const int clickCount) -{ - _browser->GetHost()->SendMouseClickEvent(event, button, false, clickCount); -} - -void BrowserInstance::sendResleasePressEvent(const CefMouseEvent& event, - CefBrowserHost::MouseButtonType button, - const int clickCount) -{ - _browser->GetHost()->SendMouseClickEvent(event, button, true, clickCount); +#ifdef WIN32 +void BrowserInstance::sendTouchEvent(const CefTouchEvent& event) const{ + _browser->GetHost()->SendTouchEvent(event); } +#endif bool BrowserInstance::sendMouseMoveEvent(const CefMouseEvent& event) { constexpr const bool DidNotLeaveWindow = false; diff --git a/modules/webbrowser/src/eventhandler.cpp b/modules/webbrowser/src/eventhandler.cpp index 0ee3e8f7a3..9607457a30 100644 --- a/modules/webbrowser/src/eventhandler.cpp +++ b/modules/webbrowser/src/eventhandler.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -208,6 +210,13 @@ void EventHandler::initialize() { } if (_validTouchStates.empty()) { +#ifdef WIN32 + CefTouchEvent event = touchEvent( + input, + cef_touch_event_type_t::CEF_TET_PRESSED + ); + _browserInstance->sendTouchEvent(event); +#else _mousePosition.x = windowPos.x; _mousePosition.y = windowPos.y; _leftButton.down = true; @@ -217,6 +226,7 @@ void EventHandler::initialize() { false, BrowserInstance::SingleClick ); +#endif _validTouchStates.emplace_back(input); } else { @@ -245,11 +255,20 @@ void EventHandler::initialize() { ); if (it == _validTouchStates.cbegin()) { +#ifdef WIN32 + + CefTouchEvent event = touchEvent( + input, + cef_touch_event_type_t::CEF_TET_MOVED + ); + _browserInstance->sendTouchEvent(event); +#else glm::vec2 windowPos = input.currentWindowCoordinates(); _mousePosition.x = windowPos.x; _mousePosition.y = windowPos.y; _leftButton.down = true; _browserInstance->sendMouseMoveEvent(mouseEvent()); +#endif return true; } else if (it != _validTouchStates.cend()){ @@ -280,8 +299,15 @@ void EventHandler::initialize() { if (found == _validTouchStates.cend()) { return; } - +#ifdef WIN32 + CefTouchEvent event = touchEvent( + input, + cef_touch_event_type_t::CEF_TET_RELEASED + ); + _browserInstance->sendTouchEvent(event); +#endif _validTouchStates.erase(found); +#ifndef WIN32 if (_validTouchStates.empty()) { glm::vec2 windowPos = input.currentWindowCoordinates(); _mousePosition.x = windowPos.x; @@ -294,6 +320,7 @@ void EventHandler::initialize() { BrowserInstance::SingleClick ); } +#endif } ); } @@ -337,7 +364,7 @@ bool EventHandler::mouseButtonCallback(MouseButton button, MouseAction action, bool EventHandler::isDoubleClick(const MouseButtonState& button) const { // check time using namespace std::chrono; - + auto now = high_resolution_clock::now(); milliseconds maxTimeDifference(doubleClickTime()); auto requiredTime = button.lastClickTime + maxTimeDifference; @@ -438,6 +465,27 @@ CefMouseEvent EventHandler::mouseEvent(KeyModifier mods) { return event; } +#ifdef WIN32 +CefTouchEvent EventHandler::touchEvent(const TouchInput& input, + const cef_touch_event_type_t eventType) const +{ + const glm::vec2 windowPos = input.currentWindowCoordinates(); + CefTouchEvent event = {}; + event.id = static_cast(input.fingerId); + event.x = windowPos.x; + event.y = windowPos.y; + event.type = eventType; + const std::vector>& keyModVec = + global::navigationHandler.inputState().pressedKeys(); + for (const std::pair& keyModPair : keyModVec) { + const KeyModifier mods = keyModPair.second; + event.modifiers |= static_cast(mapToCefModifiers(mods)); + } + event.pointer_type = cef_pointer_type_t::CEF_POINTER_TYPE_TOUCH; + return event; +} +#endif + void EventHandler::setBrowserInstance(BrowserInstance* browserInstance) { LDEBUG("Setting browser instance."); _browserInstance = browserInstance; diff --git a/openspace.cfg b/openspace.cfg index c73d8154f3..a557e5468d 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -46,6 +46,7 @@ SGCTConfig = sgct.config.single{} -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace Asset = "default" +-- Asset = "asteroids" -- Asset = "default_full" -- Asset = "newhorizons" -- Asset = "rosetta" diff --git a/src/engine/downloadmanager.cpp b/src/engine/downloadmanager.cpp index 936b7c4672..6f75683ccb 100644 --- a/src/engine/downloadmanager.cpp +++ b/src/engine/downloadmanager.cpp @@ -188,8 +188,8 @@ std::shared_ptr DownloadManager::downloadFile( &progressCb }; #if LIBCURL_VERSION_NUM >= 0x072000 - // xferinfo was introduced in 7.32.0, if a lower curl version is used the progress - // will not be shown for downloads on the splash screen + // xferinfo was introduced in 7.32.0, if a lower curl version is used the + // progress will not be shown for downloads on the splash screen curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo); // NOLINT curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &p); // NOLINT #endif diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index a7baa68726..10c4b9d9c8 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -403,11 +403,6 @@ void OpenSpaceEngine::initializeGL() { rendering::helper::initialize(); - // clear the screen so the user doesn't have to see old buffer contents left on the - // graphics card - LDEBUG("Clearing all Windows"); - global::windowDelegate.clearAllWindows(glm::vec4(0.f, 0.f, 0.f, 1.f)); - LDEBUG("Adding system components"); // Detect and log OpenCL and OpenGL versions and available devices SysCap.addComponent( @@ -656,9 +651,9 @@ void OpenSpaceEngine::initializeGL() { global::moduleEngine.initializeGL(); + for (const std::function& func : global::callback::initializeGL) { ZoneScopedN("[Module] initializeGL") - func(); } @@ -1392,10 +1387,7 @@ void OpenSpaceEngine::mouseButtonCallback(MouseButton button, // Check if the user clicked on one of the 'buttons' the RenderEngine is drawing if (action == MouseAction::Press) { - bool isConsumed = global::renderEngine.mouseActivationCallback( - global::windowDelegate.mousePosition() - ); - + bool isConsumed = global::renderEngine.mouseActivationCallback(_mousePosition); if (isConsumed) { return; } @@ -1415,6 +1407,8 @@ void OpenSpaceEngine::mousePositionCallback(double x, double y) { global::navigationHandler.mousePositionCallback(x, y); global::interactionMonitor.markInteraction(); + + _mousePosition = glm::vec2(static_cast(x), static_cast(y)); } void OpenSpaceEngine::mouseScrollWheelCallback(double posX, double posY) { @@ -1466,14 +1460,14 @@ void OpenSpaceEngine::touchExitCallback(TouchInput input) { } -std::vector OpenSpaceEngine::encode() { +std::vector OpenSpaceEngine::encode() { ZoneScoped - std::vector buffer = global::syncEngine.encodeSyncables(); + std::vector buffer = global::syncEngine.encodeSyncables(); return buffer; } -void OpenSpaceEngine::decode(std::vector data) { +void OpenSpaceEngine::decode(std::vector data) { ZoneScoped global::syncEngine.decodeSyncables(std::move(data)); @@ -1561,15 +1555,6 @@ scripting::LuaLibrary OpenSpaceEngine::luaLibrary() { "Returns whether the current OpenSpace instance is the master node of a " "cluster configuration. If this instance is not part of a cluster, this " "function also returns 'true'." - }, - { - "clusterId", - &luascriptfunctions::clusterId, - {}, - "", - "Returns the zero-based identifier for this OpenSpace instance in a " - "cluster configuration. If this instance is not part of a cluster, this " - "identifier is always 0." } }, { diff --git a/src/engine/openspaceengine_lua.inl b/src/engine/openspaceengine_lua.inl index 8980499883..db0a9a70fa 100644 --- a/src/engine/openspaceengine_lua.inl +++ b/src/engine/openspaceengine_lua.inl @@ -272,10 +272,4 @@ int isMaster(lua_State* L) { return 1; } -int clusterId(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::clusterId"); - ghoul::lua::push(L, global::windowDelegate.clusterId()); - return 1; -} - } // namespace openspace::luascriptfunctions diff --git a/src/engine/syncengine.cpp b/src/engine/syncengine.cpp index f3f341ce74..c2dca81352 100644 --- a/src/engine/syncengine.cpp +++ b/src/engine/syncengine.cpp @@ -38,18 +38,18 @@ SyncEngine::SyncEngine(unsigned int syncBufferSize) } // Should be called on sgct master -std::vector SyncEngine::encodeSyncables() { +std::vector SyncEngine::encodeSyncables() { for (Syncable* syncable : _syncables) { syncable->encode(&_syncBuffer); } - std::vector data = _syncBuffer.data(); + std::vector data = _syncBuffer.data(); _syncBuffer.reset(); return data; } // Should be called on sgct slaves -void SyncEngine::decodeSyncables(std::vector data) { +void SyncEngine::decodeSyncables(std::vector data) { _syncBuffer.setData(std::move(data)); for (Syncable* syncable : _syncables) { syncable->decode(&_syncBuffer); diff --git a/src/interaction/mousecamerastates.cpp b/src/interaction/mousecamerastates.cpp index ba897bd1d3..36cc688170 100644 --- a/src/interaction/mousecamerastates.cpp +++ b/src/interaction/mousecamerastates.cpp @@ -40,10 +40,15 @@ MouseCameraStates::MouseCameraStates(double sensitivity, double velocityScaleFac void MouseCameraStates::updateStateFromInput(const InputState& inputState, double deltaTime) { + MouseButton primary = + _isMouseButtonInverted ? MouseButton::Button2 : MouseButton::Button1; + MouseButton secondary = + _isMouseButtonInverted ? MouseButton::Button1 : MouseButton::Button2; + glm::dvec2 mousePosition = inputState.mousePosition(); - bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1); - bool button2Pressed = inputState.isMouseButtonPressed(MouseButton::Button2); + bool primaryPressed = inputState.isMouseButtonPressed(primary); + bool secondaryPressed = inputState.isMouseButtonPressed(secondary); bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3); bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl) | inputState.isKeyPressed(Key::RightControl); @@ -53,7 +58,7 @@ void MouseCameraStates::updateStateFromInput(const InputState& inputState, inputState.isKeyPressed(Key::RightAlt); // Update the mouse states - if (button1Pressed && !keyShiftPressed && !keyAltPressed) { + if (primaryPressed && !keyShiftPressed && !keyAltPressed) { if (keyCtrlPressed) { glm::dvec2 mousePositionDelta = _localRotationState.previousPosition - mousePosition; @@ -84,7 +89,7 @@ void MouseCameraStates::updateStateFromInput(const InputState& inputState, _globalRotationState.previousPosition = mousePosition; _globalRotationState.velocity.decelerate(deltaTime); } - if (button2Pressed || (keyAltPressed && button1Pressed)) { + if (secondaryPressed || (keyAltPressed && primaryPressed)) { glm::dvec2 mousePositionDelta = _truckMovementState.previousPosition - mousePosition; @@ -105,7 +110,7 @@ void MouseCameraStates::updateStateFromInput(const InputState& inputState, _truckMovementState.previousPosition = mousePosition; _truckMovementState.velocity.decelerate(deltaTime); } - if (button3Pressed || (keyShiftPressed && button1Pressed)) { + if (button3Pressed || (keyShiftPressed && primaryPressed)) { if (keyCtrlPressed) { glm::dvec2 mousePositionDelta = _localRollState.previousPosition - mousePosition; @@ -138,4 +143,8 @@ void MouseCameraStates::updateStateFromInput(const InputState& inputState, } } +void MouseCameraStates::setInvertMouseButton(bool value) { + _isMouseButtonInverted = value; +} + } // namespace openspace::interaction diff --git a/src/interaction/orbitalnavigator.cpp b/src/interaction/orbitalnavigator.cpp index efcd4bace1..2a49c21a82 100644 --- a/src/interaction/orbitalnavigator.cpp +++ b/src/interaction/orbitalnavigator.cpp @@ -145,16 +145,18 @@ namespace { constexpr openspace::properties::Property::PropertyInfo ApplyLinearFlightInfo = { "ApplyLinearFlight", "Apply Linear Flight", - "This property makes the camera move to the specified distance 'FlightDestinationDistance' while facing the anchor" + "This property makes the camera move to the specified distance " + "'FlightDestinationDistance' while facing the anchor" }; - constexpr openspace::properties::Property::PropertyInfo FlightDestinationDistanceInfo = { + constexpr openspace::properties::Property::PropertyInfo FlightDestinationDistInfo = { "FlightDestinationDistance", "Flight Destination Distance", "The final distance we want to fly to, with regards to the anchor node." }; - constexpr openspace::properties::Property::PropertyInfo FlightDestinationFactorInfo = { + constexpr openspace::properties::Property::PropertyInfo FlightDestinationFactorInfo = + { "FlightDestinationFactor", "Flight Destination Factor", "The minimal distance factor that we need to reach to end linear flight." @@ -183,6 +185,14 @@ namespace { "The interpolation time when toggling following focus node rotation." }; + constexpr openspace::properties::Property::PropertyInfo InvertMouseButtons = { + "InvertMouseButtons", + "Invert left and right mouse buttons", + "If this value is 'false', the left mouse button causes the camera to rotate " + "around the object and the right mouse button causes the zooming motion. If this " + "value is 'true', these two functionalities are reversed." + }; + constexpr openspace::properties::Property::PropertyInfo UseAdaptiveStereoscopicDepthInfo = { "UseAdaptiveStereoscopicDepth", @@ -236,7 +246,7 @@ OrbitalNavigator::OrbitalNavigator() , _minimumAllowedDistance(MinimumDistanceInfo, 10.0f, 0.0f, 10000.f) , _velocitySensitivity(VelocityZoomControlInfo, 0.02f, 0.01f, 0.15f) , _applyLinearFlight(ApplyLinearFlightInfo, false) - , _flightDestinationDistance(FlightDestinationDistanceInfo, 2e8f, 0.0f, 1e10f) + , _flightDestinationDistance(FlightDestinationDistInfo, 2e8f, 0.0f, 1e10f) , _flightDestinationFactor(FlightDestinationFactorInfo, 1E-4, 1E-6, 0.5) , _mouseSensitivity(MouseSensitivityInfo, 15.0f, 1.0f, 50.f) , _joystickSensitivity(JoystickSensitivityInfo, 10.0f, 1.0f, 50.f) @@ -247,6 +257,7 @@ OrbitalNavigator::OrbitalNavigator() , _retargetInterpolationTime(RetargetInterpolationTimeInfo, 2.0, 0.0, 10.0) , _stereoInterpolationTime(StereoInterpolationTimeInfo, 8.0, 0.0, 10.0) , _followRotationInterpolationTime(FollowRotationInterpTimeInfo, 1.0, 0.0, 10.0) + , _invertMouseButtons(InvertMouseButtons, false) , _mouseStates(_mouseSensitivity * 0.0001, 1 / (_friction.friction + 0.0000001)) , _joystickStates(_joystickSensitivity * 0.1, 1 / (_friction.friction + 0.0000001)) , _websocketStates(_websocketSensitivity, 1 / (_friction.friction + 0.0000001)) @@ -378,6 +389,10 @@ OrbitalNavigator::OrbitalNavigator() addProperty(_retargetInterpolationTime); addProperty(_stereoInterpolationTime); addProperty(_followRotationInterpolationTime); + _invertMouseButtons.onChange( + [this]() { _mouseStates.setInvertMouseButton(_invertMouseButtons); } + ); + addProperty(_invertMouseButtons); addProperty(_mouseSensitivity); addProperty(_joystickSensitivity); @@ -442,16 +457,17 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { if (_applyLinearFlight) { // Calculate a position handle based on the camera position in world space glm::dvec3 camPosToAnchorPosDiff = prevCameraPosition - anchorPos; - // Use the boundingsphere to get an approximate distance to the surface of the node + // Use the boundingsphere to get an approximate distance to the node surface double nodeRadius = static_cast(_anchorNode->boundingSphere()); - double distFromCameraToFocus = glm::distance(prevCameraPosition, anchorPos) - nodeRadius; + double distFromCameraToFocus = + glm::distance(prevCameraPosition, anchorPos) - nodeRadius; // Make the approximation delta size depending on the flight distance - double arrivalThreshold = _flightDestinationDistance.value() * _flightDestinationFactor; - - // Fly towards the flight destination distance. When getting closer than arrivalThreshold terminate the flight - if (abs(distFromCameraToFocus - _flightDestinationDistance.value()) > arrivalThreshold) { + double arrivalThreshold = _flightDestinationDistance * _flightDestinationFactor; + // Fly towards the flight destination distance. When getting closer than + // arrivalThreshold terminate the flight + if (abs(distFromCameraToFocus - _flightDestinationDistance) > arrivalThreshold) { pose.position = moveCameraAlongVector( pose.position, distFromCameraToFocus, @@ -460,7 +476,7 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { ); } else { - _applyLinearFlight.setValue(false); + _applyLinearFlight = false; } } diff --git a/src/interaction/scriptcamerastates.cpp b/src/interaction/scriptcamerastates.cpp index c68212177e..e9e01b81dc 100644 --- a/src/interaction/scriptcamerastates.cpp +++ b/src/interaction/scriptcamerastates.cpp @@ -35,9 +35,7 @@ namespace openspace::interaction { ScriptCameraStates::ScriptCameraStates() : CameraInteractionStates(1.0, 1.0) {} -void ScriptCameraStates::updateStateFromInput(const InputState& inputState, - double deltaTime) -{ +void ScriptCameraStates::updateStateFromInput(const InputState&, double deltaTime) { if (_localRotation != glm::dvec2(0.0)) { _localRotationState.velocity.set( _localRotation * _sensitivity, @@ -114,5 +112,4 @@ void ScriptCameraStates::addGlobalRoll(const glm::dvec2& delta) { _globalRoll += delta; } - } // namespace openspace::interaction diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 110eca4b43..849dc8d9e9 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -1441,8 +1441,10 @@ scripting::LuaLibrary SessionRecording::luaLibrary() { "enableTakeScreenShotDuringPlayback", &luascriptfunctions::enableTakeScreenShotDuringPlayback, {}, - "int", - "Enables that rendered frames should be saved during playback." + "[int]", + "Enables that rendered frames should be saved during playback. The " + "parameter determines the number of frames that are exported per second " + "if this value is not provided, 60 frames per second will be exported." }, { "disableTakeScreenShotDuringPlayback", diff --git a/src/interaction/sessionrecording_lua.inl b/src/interaction/sessionrecording_lua.inl index 5d138b84d6..8a1c2409b4 100644 --- a/src/interaction/sessionrecording_lua.inl +++ b/src/interaction/sessionrecording_lua.inl @@ -143,9 +143,13 @@ int stopPlayback(lua_State* L) { } int enableTakeScreenShotDuringPlayback(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::enableTakeScreenShotDuringPlayback"); + const int nArguments = ghoul::lua::checkArgumentsAndThrow( + L, + { 0, 1 }, + "lua::enableTakeScreenShotDuringPlayback" + ); - const int fps = ghoul::lua::value(L, 1); + const int fps = nArguments == 0 ? 60 : ghoul::lua::value(L, 1); global::sessionRecording.enableTakeScreenShotDuringPlayback(fps); diff --git a/src/interaction/websocketcamerastates.cpp b/src/interaction/websocketcamerastates.cpp index d3769213bc..9fefc15d02 100644 --- a/src/interaction/websocketcamerastates.cpp +++ b/src/interaction/websocketcamerastates.cpp @@ -32,12 +32,13 @@ namespace openspace::interaction { -WebsocketCameraStates::WebsocketCameraStates(double sensitivity, double velocityScaleFactor) +WebsocketCameraStates::WebsocketCameraStates(double sensitivity, + double velocityScaleFactor) : CameraInteractionStates(sensitivity, velocityScaleFactor) {} void WebsocketCameraStates::updateStateFromInput(const InputState& inputState, - double deltaTime) + double deltaTime) { std::pair globalRotation = { false, glm::dvec2(0.0) }; std::pair zoom = { false, 0.0 }; @@ -115,7 +116,7 @@ void WebsocketCameraStates::updateStateFromInput(const InputState& inputState, } } } - + if (globalRotation.first) { _globalRotationState.velocity.set(globalRotation.second, deltaTime); } @@ -164,7 +165,8 @@ void WebsocketCameraStates::setAxisMapping(int axis, AxisType mapping, _axisMapping[axis].normalize = shouldNormalize; } -WebsocketCameraStates::AxisInformation WebsocketCameraStates::axisMapping(int axis) const { +WebsocketCameraStates::AxisInformation WebsocketCameraStates::axisMapping(int axis) const +{ return _axisMapping[axis]; } diff --git a/src/interaction/websocketinputstate.cpp b/src/interaction/websocketinputstate.cpp index 3f6851d33a..9ccccf12cb 100644 --- a/src/interaction/websocketinputstate.cpp +++ b/src/interaction/websocketinputstate.cpp @@ -39,7 +39,9 @@ float WebsocketInputStates::axis(int axis) const { begin(), end(), 0.f, - [axis](float value, const std::pair state) { + [axis](float value, + const std::pair state) + { if (state.second->isConnected) { value += state.second->axes[axis]; } @@ -58,9 +60,10 @@ bool WebsocketInputStates::button(int button, WebsocketAction action) const { bool res = std::any_of( begin(), end(), - [button, action](const std::pair state) { + [button, action](const std::pair state) + { return state.second->isConnected ? - ( state.second->buttons[button] == action ) + (state.second->buttons[button] == action) : false; } ); diff --git a/src/rendering/framebufferrenderer.cpp b/src/rendering/framebufferrenderer.cpp index 5a3ff016cd..cec4b87e92 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -61,7 +61,7 @@ namespace { glPushDebugGroup( GL_DEBUG_SOURCE_APPLICATION, 0, - name.length(), + static_cast(name.length()), name.data() ); } @@ -76,7 +76,7 @@ namespace { constexpr const std::array HDRUniformNames = { - "hdrFeedingTexture", "blackoutFactor", "hdrExposure", "gamma", + "hdrFeedingTexture", "blackoutFactor", "hdrExposure", "gamma", "Hue", "Saturation", "Value" }; @@ -456,8 +456,8 @@ void FramebufferRenderer::initialize() { glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); ghoul::opengl::updateUniformLocations( - *_hdrFilteringProgram, - _hdrUniformCache, + *_hdrFilteringProgram, + _hdrUniformCache, HDRUniformNames ); ghoul::opengl::updateUniformLocations( @@ -525,7 +525,7 @@ void FramebufferRenderer::deferredcastersChanged(Deferredcaster&, void FramebufferRenderer::applyTMO(float blackoutFactor) { const bool doPerformanceMeasurements = global::performanceManager.isEnabled(); std::unique_ptr perfInternal; - + if (doPerformanceMeasurements) { perfInternal = std::make_unique( "FramebufferRenderer::render::TMO" @@ -536,7 +536,7 @@ void FramebufferRenderer::applyTMO(float blackoutFactor) { ghoul::opengl::TextureUnit hdrFeedingTextureUnit; hdrFeedingTextureUnit.activate(); glBindTexture(GL_TEXTURE_2D, _pingPongBuffers.colorTexture[_pingPongIndex]); - + _hdrFilteringProgram->setUniform( _hdrUniformCache.hdrFeedingTexture, hdrFeedingTextureUnit @@ -608,8 +608,12 @@ void FramebufferRenderer::updateDownscaleTextures() { GL_TEXTURE_2D, 0, GL_RGBA32F, - _resolution.x * _downscaleVolumeRendering.currentDownscaleFactor, - _resolution.y * _downscaleVolumeRendering.currentDownscaleFactor, + static_cast( + _resolution.x * _downscaleVolumeRendering.currentDownscaleFactor + ), + static_cast( + _resolution.y * _downscaleVolumeRendering.currentDownscaleFactor + ), 0, GL_RGBA, GL_FLOAT, @@ -625,8 +629,12 @@ void FramebufferRenderer::updateDownscaleTextures() { GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, - _resolution.x * _downscaleVolumeRendering.currentDownscaleFactor, - _resolution.y * _downscaleVolumeRendering.currentDownscaleFactor, + static_cast( + _resolution.x * _downscaleVolumeRendering.currentDownscaleFactor + ), + static_cast( + _resolution.y * _downscaleVolumeRendering.currentDownscaleFactor + ), 0, GL_DEPTH_COMPONENT, GL_FLOAT, @@ -683,7 +691,7 @@ void FramebufferRenderer::writeDownscaledVolume() { _writeDownscaledVolumeUniformCache.downscaledRenderedVolume, downscaledTextureUnit ); - + ghoul::opengl::TextureUnit downscaledDepthUnit; downscaledDepthUnit.activate(); glBindTexture( @@ -928,8 +936,12 @@ void FramebufferRenderer::updateResolution() { GL_TEXTURE_2D, 0, GL_RGBA32F, - _resolution.x * _downscaleVolumeRendering.currentDownscaleFactor, - _resolution.y * _downscaleVolumeRendering.currentDownscaleFactor, + static_cast( + _resolution.x * _downscaleVolumeRendering.currentDownscaleFactor + ), + static_cast( + _resolution.y * _downscaleVolumeRendering.currentDownscaleFactor + ), 0, GL_RGBA, GL_FLOAT, @@ -945,8 +957,12 @@ void FramebufferRenderer::updateResolution() { GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, - _resolution.x * _downscaleVolumeRendering.currentDownscaleFactor, - _resolution.y * _downscaleVolumeRendering.currentDownscaleFactor, + static_cast( + _resolution.x * _downscaleVolumeRendering.currentDownscaleFactor + ), + static_cast( + _resolution.y * _downscaleVolumeRendering.currentDownscaleFactor + ), 0, GL_DEPTH_COMPONENT, GL_FLOAT, @@ -1160,7 +1176,7 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac glEnable(GL_DEPTH_TEST); } _pingPongIndex = 0; - + // Measurements cache variable const bool doPerformanceMeasurements = global::performanceManager.isEnabled(); @@ -1173,7 +1189,7 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac if (!scene || !camera) { return; - } + } { // deferred g-buffer @@ -1236,7 +1252,7 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac GLDebugGroup group("Deferred Caster Tasks"); // We use ping pong rendering in order to be able to - // render to the same final buffer, multiple + // render to the same final buffer, multiple // deferred tasks at same time (e.g. more than 1 ATM being seen at once) glBindFramebuffer(GL_FRAMEBUFFER, _pingPongBuffers.framebuffer); glDrawBuffers(1, &ColorAttachment01Array[_pingPongIndex]); @@ -1263,7 +1279,7 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac // Disabling depth test for filtering and hdr glDisable(GL_DEPTH_TEST); - + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); if (_enableFXAA) { @@ -1277,7 +1293,7 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac // by the Operating System. Also, the resolve procedure is executed in this step. glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); } - + { // Apply the selected TMO on the results and resolve the result to the default FBO GLDebugGroup group("Apply TMO"); @@ -1290,7 +1306,6 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); applyFXAA(); } - } void FramebufferRenderer::performRaycasterTasks(const std::vector& tasks) { @@ -1312,11 +1327,16 @@ void FramebufferRenderer::performRaycasterTasks(const std::vector } if (raycaster->downscaleRender() < 1.f) { - float scaleDown = raycaster->downscaleRender(); glBindFramebuffer(GL_FRAMEBUFFER, _downscaleVolumeRendering.framebuffer); - glViewport(viewport[0], viewport[1], viewport[2] * scaleDown, viewport[3] * scaleDown); - if (_downscaleVolumeRendering.currentDownscaleFactor != scaleDown) { - _downscaleVolumeRendering.currentDownscaleFactor = scaleDown; + const float s = raycaster->downscaleRender(); + glViewport( + viewport[0], + viewport[1], + static_cast(viewport[2] * s), + static_cast(viewport[3] * s) + ); + if (_downscaleVolumeRendering.currentDownscaleFactor != s) { + _downscaleVolumeRendering.currentDownscaleFactor = s; updateDownscaleTextures(); } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -1357,7 +1377,7 @@ void FramebufferRenderer::performRaycasterTasks(const std::vector if (raycastProgram) { raycastProgram->setUniform("rayCastSteps", raycaster->maxSteps()); - + raycaster->preRaycast(_raycastData[raycaster], *raycastProgram); ghoul::opengl::TextureUnit exitColorTextureUnit; @@ -1383,7 +1403,10 @@ void FramebufferRenderer::performRaycasterTasks(const std::vector ); } else { - raycastProgram->setUniform("windowSize", static_cast(_resolution)); + raycastProgram->setUniform( + "windowSize", + static_cast(_resolution) + ); } glDisable(GL_DEPTH_TEST); diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 99d6637790..50cf01876d 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -319,14 +319,13 @@ RenderEngine::RenderEngine() }); addProperty(_disableHDRPipeline); - _hdrExposure.onChange([this]() { if (_renderer) { _renderer->setHDRExposure(_hdrExposure); } }); addProperty(_hdrExposure); - + _gamma.onChange([this]() { if (_renderer) { _renderer->setGamma(_gamma); @@ -342,7 +341,7 @@ RenderEngine::RenderEngine() }); addProperty(_hue); - + _saturation.onChange([this]() { if (_renderer) { _renderer->setSaturation(_saturation); @@ -350,7 +349,7 @@ RenderEngine::RenderEngine() }); addProperty(_saturation); - + _value.onChange([this]() { if (_renderer) { _renderer->setValue(_value); @@ -518,7 +517,7 @@ void RenderEngine::updateScene() { const Time& integrateFromTime = global::timeManager.integrateFromTime(); _scene->update({ - { glm::dvec3(0.0), glm::dmat3(1.0), 1.0 }, + { glm::dvec3(0.0), glm::dmat3(1.0), glm::dvec3(1.0) }, currentTime, integrateFromTime, _doPerformanceMeasurements diff --git a/src/scene/scale.cpp b/src/scene/scale.cpp index dff7b83fe6..d1eb8e59fc 100644 --- a/src/scene/scale.cpp +++ b/src/scene/scale.cpp @@ -79,7 +79,7 @@ bool Scale::initialize() { return true; } -double Scale::scaleValue() const { +glm::dvec3 Scale::scaleValue() const { return _cachedScale; } diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 82a0672084..43732d9e3e 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -346,7 +346,7 @@ void Scene::render(const RenderData& data, RendererTasks& tasks) { if (global::callback::webBrowserPerformanceHotfix) { (*global::callback::webBrowserPerformanceHotfix)(); } - + { ZoneScopedN("Get Error Hack") diff --git a/src/scene/scene_lua.inl b/src/scene/scene_lua.inl index 1e00beee8c..37aa928996 100644 --- a/src/scene/scene_lua.inl +++ b/src/scene/scene_lua.inl @@ -643,7 +643,9 @@ int addInterestingTime(lua_State* L) { std::string time = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); lua_pop(L, 2); - global::renderEngine.scene()->addInterestingTime({ std::move(name), std::move(time) }); + global::renderEngine.scene()->addInterestingTime( + { std::move(name), std::move(time) } + ); ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 5177ea9c69..dc304556eb 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -469,14 +469,7 @@ void SceneGraphNode::update(const UpdateData& data) { newUpdateData.modelTransform.translation ); glm::dmat4 rotation = glm::dmat4(newUpdateData.modelTransform.rotation); - glm::dmat4 scaling = glm::scale( - glm::dmat4(1.0), - glm::dvec3( - newUpdateData.modelTransform.scale, - newUpdateData.modelTransform.scale, - newUpdateData.modelTransform.scale - ) - ); + glm::dmat4 scaling = glm::scale(glm::dmat4(1.0), newUpdateData.modelTransform.scale); _modelTransformCached = translation * rotation * scaling; _inverseModelTransformCached = glm::inverse(_modelTransformCached); @@ -707,7 +700,7 @@ void SceneGraphNode::computeScreenSpaceData(RenderData& newData) { } glm::ivec2 res = global::windowDelegate.currentSubwindowSize(); - + // Get the radius of node double nodeRadius = static_cast(this->boundingSphere()); @@ -788,7 +781,7 @@ const glm::dmat3& SceneGraphNode::rotationMatrix() const { return _transform.rotation->matrix(); } -double SceneGraphNode::scale() const { +glm::dvec3 SceneGraphNode::scale() const { return _transform.scale->scaleValue(); } @@ -808,7 +801,7 @@ glm::dmat4 SceneGraphNode::inverseModelTransform() const { return _inverseModelTransformCached; } -double SceneGraphNode::worldScale() const { +glm::dvec3 SceneGraphNode::worldScale() const { return _worldScaleCached; } @@ -825,7 +818,7 @@ glm::dvec3 SceneGraphNode::calculateWorldPosition() const { if (_parent) { const glm::dvec3 wp = _parent->worldPosition(); const glm::dmat3 wrot = _parent->worldRotationMatrix(); - const double ws = _parent->worldScale(); + const glm::dvec3 ws = _parent->worldScale(); const glm::dvec3 p = position(); return wp + wrot * ws * p; @@ -859,7 +852,7 @@ glm::dmat3 SceneGraphNode::calculateWorldRotation() const { } } -double SceneGraphNode::calculateWorldScale() const { +glm::dvec3 SceneGraphNode::calculateWorldScale() const { // recursive up the hierarchy if there are parents available if (_parent) { return _parent->worldScale() * scale(); diff --git a/src/scripting/scriptengine_lua.inl b/src/scripting/scriptengine_lua.inl index 4ffce5c454..562d8c9600 100644 --- a/src/scripting/scriptengine_lua.inl +++ b/src/scripting/scriptengine_lua.inl @@ -417,7 +417,10 @@ int saveLastChangeToProfile(lua_State* L) { printInternal(ghoul::logging::LogLevel::Error, L); } if (!fileout) { - ghoul::lua::push(L, fmt::format("Could not open tmp profile '{}'", tempAssetPath)); + ghoul::lua::push( + L, + fmt::format("Could not open tmp profile '{}'", tempAssetPath) + ); printInternal(ghoul::logging::LogLevel::Error, L); } diff --git a/src/util/syncbuffer.cpp b/src/util/syncbuffer.cpp index f52cfa42dc..edb19f7123 100644 --- a/src/util/syncbuffer.cpp +++ b/src/util/syncbuffer.cpp @@ -39,8 +39,9 @@ SyncBuffer::~SyncBuffer() {} // NOLINT void SyncBuffer::encode(const std::string& s) { ZoneScoped - int32_t anticpatedBufferSize = _encodeOffset + (sizeof(char) * s.size()) - + sizeof(int32_t); + int32_t anticpatedBufferSize = static_cast( + _encodeOffset + (sizeof(char) * s.size()) + sizeof(int32_t) + ); if (anticpatedBufferSize >= _n) { _dataStream.resize(anticpatedBufferSize); } @@ -78,11 +79,11 @@ void SyncBuffer::decode(std::string& s) { s = decode(); } -void SyncBuffer::setData(std::vector data) { +void SyncBuffer::setData(std::vector data) { _dataStream = std::move(data); } -std::vector SyncBuffer::data() { +std::vector SyncBuffer::data() { _dataStream.resize(_encodeOffset); return _dataStream; diff --git a/src/util/touch.cpp b/src/util/touch.cpp index aa0ef75ddd..f08c5cab03 100644 --- a/src/util/touch.cpp +++ b/src/util/touch.cpp @@ -73,32 +73,41 @@ float TouchInput::angleToPos(float otherX, float otherY) const { TouchInputHolder::TouchInputHolder(TouchInput input) : _inputs{ input } + , _firstInput(input) , _touchDeviceId(input.touchDeviceId) , _fingerId(input.fingerId) {} bool TouchInputHolder::tryAddInput(TouchInput input) { + if(_inputs.empty()) { + _inputs.emplace_front(input); + return true; + } constexpr const double ONE_MS = 0.001; const TouchInput& lastInput = latestInput(); input.dx = input.x - lastInput.x; input.dy = input.y - lastInput.y; - const bool sameTimeAsLastInput = (input.timestamp - lastInput.timestamp) > ONE_MS; - bool wasInserted = false; - if (isMoving()) { + const bool sameTimeAsLastInput = (input.timestamp - lastInput.timestamp) < ONE_MS; + bool successful = false; + if (!sameTimeAsLastInput && isMoving()) { _inputs.emplace_front(input); - wasInserted = true; + successful = true; } - else if (sameTimeAsLastInput && input.isMoving()) { + else if (!sameTimeAsLastInput && input.isMoving()) { _inputs.emplace_front(input); - wasInserted = true; + successful = true; + } + else if (!sameTimeAsLastInput){ + _inputs.front().timestamp = input.timestamp; + successful = true; } constexpr const int MaxInputs = 128; if (_inputs.size() > MaxInputs) { _inputs.pop_back(); } - return wasInserted; + return successful; } void TouchInputHolder::clearInputs() { @@ -142,8 +151,7 @@ bool TouchInputHolder::isMoving() const { if (_inputs.size() <= 1) { return false; } - const TouchInput& currentInput = _inputs[0]; - return currentInput.dx != 0.f || currentInput.dy != 0.f; + return latestInput().isMoving(); } float TouchInputHolder::gestureDistance() const { @@ -174,6 +182,10 @@ size_t TouchInputHolder::numInputs() const { return _inputs.size(); } +const TouchInput& TouchInputHolder::firstInput() const { + return _firstInput; +} + const TouchInput& TouchInputHolder::latestInput() const { return _inputs.front(); }