diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..b025b07993 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +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 diff --git a/CREDITS b/CREDITS.md similarity index 66% rename from CREDITS rename to CREDITS.md index 3bb64218eb..02aa209148 100644 --- a/CREDITS +++ b/CREDITS.md @@ -1,16 +1,26 @@ Alexander Bock Joakim Kilby Emil Axelsson +Eric Myers Jonathas Costa Matthew Territo +Gene Payne +Kalle Bladin +Erik Sundén Jonas Strandstedt Hans-Christian Helltegen Michal Marcinkowski Anton Arbring Tomas Forsyth Rosin -Kalle Bladin Erik Broberg Michael Nilsson Sebastian Piwell Niclas Hultberg +Rickard Lindtstedt +Michael Sjöström +Michael Novén +Oskar Carlbaum + +Anteige +noahdasanaike diff --git a/LICENSE b/LICENSE.md similarity index 97% rename from LICENSE rename to LICENSE.md index 0e48e547cb..9f67ee7043 100644 --- a/LICENSE +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2014-2016 +Copyright (c) 2014-2017 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 diff --git a/README.md b/README.md new file mode 100644 index 0000000000..d3c2d1e8de --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +OpenSpace is an open source, non-commercial, and freely available interactive data visualization software designed to visualize the entire known universe and portray our ongoing efforts to investigate the cosmos. Bringing the latest techniques from data visualization research to the general public, OpenSpace supports interactive presentation of dynamic data from observations, simulations, and space mission planning and operations. The software works on multiple operating systems (Windows, Linux, MacOS) with an extensible architecture powering high resolution tiled displays and planetarium domes, making use of the latest graphic card technologies for rapid data throughput. In addition, OpenSpace enables simultaneous connections across the globe creating opportunity for shared experiences among audiences worldwide. + +The project stems from the same academic collaboration between Sweden’s Linköping University (LiU) and the American Museum of Natural History (AMNH) that led to the creation of Uniview and its parent company SCISS. Development of the software began several years ago through a close collaboration with NASA Goddard’s Community Coordinated Modeling Center (CCMC) to model space weather forecasting and continued last year with visualization of NASA’s New Horizons mission to Pluto and ESA’s Rosetta mission. This promising set of preliminary work provided a foundation for recent NASA funding, which has extended the collaboration to include the University of Utah’s Scientific Computing and Imaging (SCI) Institute, New York University’s Tandon School of Engineering, multiple informal science institutions across the United States, and multiple, international vendors. Current areas of focus within OpenSpace include: + +- Visualization of dynamic simulations via interactive volumetric rendering, as a priority for communicating research in astrophysics. +- Utilization of NASA’s SPICE observational geometry system with its Planetary Data Service (PDS) to enable space mission visualization that reveal how missions are designed to gather science. +- Globe browsing techniques across spatial and temporal scales to examine scientific campaigns on multiple planets, including close up surface exploration. + +This repository contains the source code and example scenes for OpenSpace, but does not contain any data. To build and install the client, we refer to the [Wiki](https://github.com/OpenSpace/OpenSpace/wiki) pages here on GitHub, specifically [building](https://github.com/OpenSpace/OpenSpace/wiki/General-Getting-Started-Guide%3A-Compiling-OpenSpace) for [Windows](https://github.com/OpenSpace/OpenSpace/wiki/Guides-Compile-OpenSpace-on-Windows), [Linux](https://github.com/OpenSpace/OpenSpace/wiki/Guides-Compile-OpenSpace-on-Linux), and [MacOS](https://github.com/OpenSpace/OpenSpace/wiki/Guides-Compile-OpenSpace-on-OSX). Required preexisting dependencies are: [NASM](http://www.nasm.us/), [Boost](http://www.boost.org/), and [Qt](http://www.qt.io/download). Feel free to create issues for missing features, bug reports, or compile problems or contact us via [email](mailto:alexander.bock@me.com?subject=OpenSpace:). \ No newline at end of file diff --git a/apps/OpenSpace/CMakeLists.txt b/apps/OpenSpace/CMakeLists.txt index f4df34ab38..c5e93b08bb 100644 --- a/apps/OpenSpace/CMakeLists.txt +++ b/apps/OpenSpace/CMakeLists.txt @@ -1,26 +1,28 @@ -######################################################################################### -# # -# OpenSpace # -# # -# Copyright (c) 2014-2015 # -# # -# 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. # -######################################################################################### +########################################################################################## +# # +# OpenSpace # +# # +# Copyright (c) 2014-2017 # +# # +# 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(${GHOUL_BASE_DIR}/support/cmake/CopySharedLibraries.cmake) set(APPLICATION_NAME OpenSpace) set(APPLICATION_LINK_TO_OPENSPACE ON) @@ -29,50 +31,98 @@ if (WIN32) set(RESOURCE_FILE ${OPENSPACE_APPS_DIR}/OpenSpace/openspace.rc) endif () -##OpenVR section start#################### + +######################## +# OpenVR section start # +######################## option(OPENSPACE_OPENVR_SUPPORT "Build OpenSpace application with OpenVR support" OFF) -if(OPENSPACE_OPENVR_SUPPORT) - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${OPENSPACE_EXT_DIR}/sgct/cmake/modules/") - - find_package(OpenVR REQUIRED) - - set(SGCT_OPENVR_DEFINITIONS OPENVR_SUPPORT) +if (OPENSPACE_OPENVR_SUPPORT) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${OPENSPACE_EXT_DIR}/sgct/cmake/modules/") + + find_package(OpenVR REQUIRED) + + set(SGCT_OPENVR_DEFINITIONS OPENVR_SUPPORT) - if(NOT SGCT_OPENVR_INCLUDE_DIRECTORY) - if( WIN32 ) - find_path(SGCT_OPENVR_INCLUDE_DIRECTORY - NAMES SGCTOpenVR.h - PATHS $ENV{SGCT_ROOT_DIR}/additional_includes/openvr ${OPENSPACE_EXT_DIR}/sgct/additional_includes/openvr NO_DEFAULT_PATH - REQUIRED) - else() - find_path(SGCT_OPENVR_INCLUDE_DIRECTORY - NAMES SGCTOpenVR.h - PATH_SUFFIXES SGCTOpenVR - PATHS $ENV{SGCT_ROOT_DIR}/additional_includes/openvr ${OPENSPACE_EXT_DIR}/sgct/additional_includes/openvr - REQUIRED) - endif() - else() - set(SGCT_OPENVR_FILES ${SGCT_OPENVR_INCLUDE_DIRECTORY}/SGCTOpenVR.h ${SGCT_OPENVR_INCLUDE_DIRECTORY}/SGCTOpenVR.cpp) - endif() + if(NOT SGCT_OPENVR_INCLUDE_DIRECTORY) + if( WIN32 ) + find_path(SGCT_OPENVR_INCLUDE_DIRECTORY + NAMES SGCTOpenVR.h + PATHS $ENV{SGCT_ROOT_DIR}/additional_includes/openvr ${OPENSPACE_EXT_DIR}/sgct/additional_includes/openvr NO_DEFAULT_PATH + REQUIRED) + else() + find_path(SGCT_OPENVR_INCLUDE_DIRECTORY + NAMES SGCTOpenVR.h + PATH_SUFFIXES SGCTOpenVR + PATHS $ENV{SGCT_ROOT_DIR}/additional_includes/openvr ${OPENSPACE_EXT_DIR}/sgct/additional_includes/openvr + REQUIRED) + endif() + else() + set(SGCT_OPENVR_FILES ${SGCT_OPENVR_INCLUDE_DIRECTORY}/SGCTOpenVR.h ${SGCT_OPENVR_INCLUDE_DIRECTORY}/SGCTOpenVR.cpp) + endif() else() - set(OPENVR_INCLUDE_DIRS "") - set(SGCT_OPENVR_INCLUDE_DIRECTORY "") - set(OPENVR_LIBRARY "") - set(SGCT_OPENVR_DEFINITIONS "") + set(OPENVR_INCLUDE_DIRS "") + set(SGCT_OPENVR_INCLUDE_DIRECTORY "") + set(OPENVR_LIBRARY "") + set(SGCT_OPENVR_DEFINITIONS "") endif() -##OpenVR section end#################### +######################## +# OpenVR section end # +######################## + +######################## +# Spout section start # +######################## +if (WIN32) + option(OPENSPACE_SPOUT_SUPPORT "Build OpenSpace application with Spout support" OFF) +endif () + +set(SPOUT_INCLUDE_DIRS "") +set(SPOUT_LIBRARY "") +set(SPOUT_DEFINITIONS "") +if (OPENSPACE_SPOUT_SUPPORT) + set(SPOUT_INCLUDE_DIRS ${OPENSPACE_APPS_DIR}/OpenSpace/ext/spout) + set(SPOUT_LIBRARY ${OPENSPACE_APPS_DIR}/OpenSpace/ext/spout/SpoutLibrary.lib) + set(SPOUT_DEFINITIONS "OPENSPACE_HAS_SPOUT") +endif () + +######################## +# Spout section end # +######################## add_executable(${APPLICATION_NAME} - ${SGCT_OPENVR_FILES} + ${SGCT_OPENVR_FILES} ${OPENSPACE_APPS_DIR}/OpenSpace/main.cpp ${RESOURCE_FILE} ) -target_include_directories(${APPLICATION_NAME} PUBLIC ${OPENSPACE_BASE_DIR}/include ${OPENVR_INCLUDE_DIRS} ${SGCT_OPENVR_INCLUDE_DIRECTORY}) -target_link_libraries(${APPLICATION_NAME} libOpenSpace ${OPENVR_LIBRARY}) -target_compile_definitions(${APPLICATION_NAME} PUBLIC ${SGCT_OPENVR_DEFINITIONS}) +if (OPENSPACE_SPOUT_SUPPORT) + copy_files( + ${APPLICATION_NAME} + ${OPENSPACE_APPS_DIR}/OpenSpace/ext/spout/SpoutLibrary.dll + ) +endif () + +target_include_directories( + ${APPLICATION_NAME} PUBLIC + ${OPENSPACE_BASE_DIR}/include + ${OPENVR_INCLUDE_DIRS} + ${SGCT_OPENVR_INCLUDE_DIRECTORY} + ${SPOUT_INCLUDE_DIRS} +) + +target_link_libraries(${APPLICATION_NAME} + libOpenSpace + ${OPENVR_LIBRARY} + ${SPOUT_LIBRARY} +) + +target_compile_definitions(${APPLICATION_NAME} PUBLIC + ${SGCT_OPENVR_DEFINITIONS} + ${SPOUT_DEFINITIONS} +) if (MSVC) + target_link_libraries(${APPLICATION_NAME} Dbghelp.lib) set_target_properties(${APPLICATION_NAME} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib" ) diff --git a/apps/OpenSpace/ext/readme.md b/apps/OpenSpace/ext/readme.md new file mode 100644 index 0000000000..2b6c321821 --- /dev/null +++ b/apps/OpenSpace/ext/readme.md @@ -0,0 +1,8 @@ +The spout folder is a copy of the folder: +SpoutSDK/Source in the repository: +https://github.com/leadedge/Spout2.git/SpoutSDK/Source/SPOUT_LIBRARY/Binaries +and +https://github.com/leadedge/Spout2.git/SpoutSDK/Source/SPOUT_LIBRARY/Include + +Last update: +https://github.com/leadedge/Spout2/commit/28dbea6059cd7968c4d2b296d6739a5fdebe9104 diff --git a/apps/OpenSpace/ext/spout/SpoutLibrary.dll b/apps/OpenSpace/ext/spout/SpoutLibrary.dll new file mode 100644 index 0000000000..36aca87f87 Binary files /dev/null and b/apps/OpenSpace/ext/spout/SpoutLibrary.dll differ diff --git a/apps/OpenSpace/ext/spout/SpoutLibrary.h b/apps/OpenSpace/ext/spout/SpoutLibrary.h new file mode 100644 index 0000000000..d50c0a1106 --- /dev/null +++ b/apps/OpenSpace/ext/spout/SpoutLibrary.h @@ -0,0 +1,90 @@ +// +// SpoutLibrary.dll +// +// Spout SDK dll compatible with any C++ compiler +// + +#include +#include + +#define SPOUTLIBRARY_EXPORTS // defined for this DLL. The application imports rather than exports + +#ifdef SPOUTLIBRARY_EXPORTS +#define SPOUTAPI __declspec(dllexport) +#else +#define SPOUTAPI __declspec(dllimport) +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +// COM-Like abstract interface. +// This interface doesn't require __declspec(dllexport/dllimport) specifier. +// Method calls are dispatched via virtual table. +// Any C++ compiler can use it. +// Instances are obtained via factory function. +// +struct SPOUTLIBRARY +{ + // Sender + virtual bool CreateSender(const char *Sendername, unsigned int width, unsigned int height, DWORD dwFormat = 0) = 0; + virtual void ReleaseSender(DWORD dwMsec = 0) = 0; + virtual bool UpdateSender(const char* Sendername, unsigned int width, unsigned int height) = 0; + virtual bool SendTexture(GLuint TextureID, GLuint TextureTarget, unsigned int width, unsigned int height, bool bInvert = true, GLuint HostFBO = 0) = 0; + virtual bool SendImage(const unsigned char* pixels, unsigned int width, unsigned int height, GLenum glFormat = GL_RGBA, bool bInvert=false) = 0; + + // Receiver + virtual bool CreateReceiver(char* Sendername, unsigned int &width, unsigned int &height, bool bUseActive = false) = 0; + virtual void ReleaseReceiver() = 0; + virtual bool ReceiveTexture(char* Sendername, unsigned int &width, unsigned int &height, GLuint TextureID = 0, GLuint TextureTarget = 0, bool bInvert = false, GLuint HostFBO = 0) = 0; + virtual bool ReceiveImage(char* Sendername, unsigned int &width, unsigned int &height, unsigned char* pixels, GLenum glFormat = GL_RGBA, bool bInvert = false, GLuint HostFBO=0) = 0; + virtual bool CheckReceiver(char* Sendername, unsigned int &width, unsigned int &height, bool &bConnected) = 0; + virtual bool GetImageSize(char* sendername, unsigned int &width, unsigned int &height, bool &bMemoryMode) = 0; + + virtual bool BindSharedTexture() = 0; + virtual bool UnBindSharedTexture() = 0; + + virtual bool DrawSharedTexture(float max_x = 1.0, float max_y = 1.0, float aspect = 1.0, bool bInvert = true) = 0; + virtual bool DrawToSharedTexture(GLuint TextureID, GLuint TextureTarget, unsigned int width, unsigned int height, float max_x = 1.0, float max_y = 1.0, float aspect = 1.0, bool bInvert = false, GLuint HostFBO = 0) = 0; + + virtual int GetSenderCount() = 0; + virtual bool GetSenderName(int index, char* sendername, int MaxSize = 256) = 0; + virtual bool GetSenderInfo(const char* sendername, unsigned int &width, unsigned int &height, HANDLE &dxShareHandle, DWORD &dwFormat) = 0; + virtual bool GetActiveSender(char* Sendername) = 0; + virtual bool SetActiveSender(const char* Sendername) = 0; + + // Utilities + virtual bool SetDX9(bool bDX9 = true) = 0; // User request to use DirectX 9 (default is DirectX 11) + virtual bool GetDX9() = 0; // Return the flag that has been set + virtual bool SetMemoryShareMode(bool bMem = true) = 0; + virtual bool GetMemoryShareMode() = 0; + virtual int GetMaxSenders() = 0; // Get maximum senders allowed + virtual void SetMaxSenders(int maxSenders) = 0; // Set maximum senders allowed + virtual bool GetHostPath(const char *sendername, char *hostpath, int maxchars) = 0; // The path of the host that produced the sender + virtual int GetVerticalSync() = 0; + virtual bool SetVerticalSync(bool bSync = true) = 0; + virtual bool SelectSenderPanel(const char* message = NULL) = 0; + + // Access to globals + virtual bool GetSpoutSenderName(char * sendername, int maxchars) = 0; // get the global sender name + virtual bool IsSpoutInitialized() = 0; // has the class been initialized + + // Adapter functions + virtual int GetNumAdapters() = 0; // Get the number of graphics adapters in the system + virtual bool GetAdapterName(int index, char *adaptername, int maxchars) = 0; // Get an adapter name + virtual bool SetAdapter(int index = 0) = 0; // Set required graphics adapter for output + virtual int GetAdapter() = 0; // Get the SpoutDirectX global adapter index + + // Library release function + virtual void Release() = 0; + +}; + + +// Handle type. In C++ language the interface type is used. +typedef SPOUTLIBRARY* SPOUTHANDLE; + +// Factory function that creates instances of the SPOUT object. +extern "C" SPOUTAPI SPOUTHANDLE WINAPI GetSpout(VOID); + + +//////////////////////////////////////////////////////////////////////////////// diff --git a/apps/OpenSpace/ext/spout/SpoutLibrary.lib b/apps/OpenSpace/ext/spout/SpoutLibrary.lib new file mode 100644 index 0000000000..435552b195 Binary files /dev/null and b/apps/OpenSpace/ext/spout/SpoutLibrary.lib differ diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index e6beaef342..ec55894de0 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -32,22 +32,141 @@ #include +#ifdef WIN32 + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#endif // WIN32 + #ifdef OPENVR_SUPPORT #include #endif // OPENVR_SUPPORT +#ifdef OPENSPACE_HAS_SPOUT +#include "SpoutLibrary.h" +#endif // OPENSPACE_HAS_SPOUT + + #define DEVELOPER_MODE namespace { const char* _loggerCat = "main"; - sgct::Engine* SgctEngine; + +const char* OpenVRTag = "OpenVR"; +const char* SpoutTag = "Spout"; + +#ifdef WIN32 + +LONG WINAPI generateMiniDump(EXCEPTION_POINTERS* exceptionPointers) { + SYSTEMTIME stLocalTime; + GetLocalTime(&stLocalTime); + + + LFATAL("Printing Stack Trace that lead to the crash:"); + std::vector stackTrace = ghoul::stackTrace(); + for (const std::string& s : stackTrace) { + LINFO(s); + } + + std::string dumpFile = fmt::format( + "OpenSpace_{}_{}_{}-{}-{}-{}-{}-{}-{}--{}--{}.dmp", + openspace::OPENSPACE_VERSION_MAJOR, + openspace::OPENSPACE_VERSION_MINOR, + openspace::OPENSPACE_VERSION_PATCH, + stLocalTime.wYear, + stLocalTime.wMonth, + stLocalTime.wDay, + stLocalTime.wHour, + stLocalTime.wMinute, + stLocalTime.wSecond, + GetCurrentProcessId(), + GetCurrentThreadId() + ); + + LINFO("Creating dump file: " << dumpFile); + + HANDLE hDumpFile = CreateFile( + dumpFile.c_str(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + 0, + CREATE_ALWAYS, + 0, + 0 + ); + + MINIDUMP_EXCEPTION_INFORMATION exceptionParameter; + exceptionParameter.ThreadId = GetCurrentThreadId(); + exceptionParameter.ExceptionPointers = exceptionPointers; + exceptionParameter.ClientPointers = TRUE; + + BOOL success = MiniDumpWriteDump( + GetCurrentProcess(), + GetCurrentProcessId(), + hDumpFile, + MiniDumpWithDataSegs, + &exceptionParameter, + nullptr, + nullptr + ); + + if (success) { + LINFO("Created successfully"); + } + else { + LERROR("Dumpfile created unsuccessfully"); + } + + return EXCEPTION_EXECUTE_HANDLER; +} + +#endif // WIN32 #ifdef OPENVR_SUPPORT sgct::SGCTWindow* FirstOpenVRWindow = nullptr; #endif +#ifdef OPENSPACE_HAS_SPOUT +/** + * This struct stores all information about a single render window. Depending on the + * frame setup, each window can be mono or stereo, the information of which is stored in + * the \c leftOrMain and \c right members respectively. + */ +struct SpoutWindow { + struct SpoutData { + SPOUTHANDLE handle = nullptr; + bool initialized = false; + }; + + /// The left framebuffer (or main, if there is no stereo rendering) + SpoutData leftOrMain; + + /// The right framebuffer + SpoutData right; + + /// The window ID of this windows + size_t windowId = size_t(-1); +}; + +/// The list of all windows with spout senders +std::vector SpoutWindows; + +#endif // OPENSPACE_HAS_SPOUT + + + std::pair supportedOpenGLVersion() { // Just create a window in order to retrieve the available OpenGL version before we // create the real window @@ -96,7 +215,7 @@ void mainInitFunc() { // 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("OpenVR")) { + if (SgctEngine->getWindowPtr(i)->checkIfTagExists(OpenVRTag)) { #ifdef OPENVR_SUPPORT FirstOpenVRWindow = SgctEngine->getWindowPtr(i); @@ -117,18 +236,72 @@ void mainInitFunc() { // Set the clear color for all non-linear projection viewports // @CLEANUP: Why is this necessary? We can set the clear color in the configuration // files --- abock - size_t nWindows = SgctEngine->getNumberOfWindows(); + const size_t nWindows = SgctEngine->getNumberOfWindows(); for (size_t i = 0; i < nWindows; ++i) { sgct::SGCTWindow* w = SgctEngine->getWindowPtr(i); - size_t nViewports = w->getNumberOfViewports(); + const size_t nViewports = w->getNumberOfViewports(); for (size_t j = 0; j < nViewports; ++j) { sgct_core::Viewport* v = w->getViewport(j); ghoul_assert(v != nullptr, "Number of reported viewports was incorrect"); sgct_core::NonLinearProjection* p = v->getNonLinearProjectionPtr(); - if (p) + if (p) { p->setClearColor(glm::vec4(0.f, 0.f, 0.f, 1.f)); + } } } + + for (size_t i = 0; i < nWindows; ++i) { + const sgct::SGCTWindow* windowPtr = SgctEngine->getWindowPtr(i); + + if (!windowPtr->checkIfTagExists(SpoutTag)) { + continue; + } + +#ifdef OPENSPACE_HAS_SPOUT + SpoutWindow w; + + 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); + + if (hasStereo) { + SpoutWindow::SpoutData& left = w.leftOrMain; + left.handle = GetSpout(); + left.initialized = left.handle->CreateSender( + (windowPtr->getName() + "_left").c_str(), + windowPtr->getXFramebufferResolution(), + windowPtr->getYFramebufferResolution() + ); + + SpoutWindow::SpoutData& right = w.right; + right.handle = GetSpout(); + right.initialized = right.handle->CreateSender( + (windowPtr->getName() + "_right").c_str(), + windowPtr->getXFramebufferResolution(), + windowPtr->getYFramebufferResolution() + ); + } + else { + SpoutWindow::SpoutData& main = w.leftOrMain; + main.handle = GetSpout(); + main.initialized = main.handle->CreateSender( + windowPtr->getName().c_str(), + windowPtr->getXFramebufferResolution(), + windowPtr->getYFramebufferResolution() + ); + } + + SpoutWindows.push_back(std::move(w)); +#else + LWARNING( + "Spout was requested, but OpenSpace was compiled without Spout support." + ); + +#endif // OPENSPACE_HAS_SPOUT + } LTRACE("main::mainInitFunc(end)"); } @@ -148,7 +321,7 @@ void mainPostSyncPreDrawFunc() { // Update pose matrices for all tracked OpenVR devices once per frame sgct::SGCTOpenVR::updatePoses(); } -#endif +#endif // OPENVR_SUPPORT LTRACE("main::postSynchronizationPreDraw(end)"); } @@ -175,13 +348,11 @@ void mainRenderFunc() { } #endif - if (SgctEngine->isMaster()) { - OsEng.render(viewMatrix, projectionMatrix); - } - else { - glm::mat4 sceneMatrix = SgctEngine->getModelMatrix(); - OsEng.render(viewMatrix * sceneMatrix, projectionMatrix); - } + OsEng.render( + SgctEngine->getModelMatrix(), + viewMatrix, + projectionMatrix + ); LTRACE("main::mainRenderFunc(end)"); } @@ -193,9 +364,38 @@ void mainPostDrawFunc() { // Copy the first OpenVR window to the HMD sgct::SGCTOpenVR::copyWindowToHMD(FirstOpenVRWindow); } -#endif +#endif // OPENVR_SUPPORT OsEng.postDraw(); + +#ifdef OPENSPACE_HAS_SPOUT + for (const SpoutWindow& w : SpoutWindows) { + sgct::SGCTWindow* window = SgctEngine->getWindowPtr(w.windowId); + if (w.leftOrMain.initialized) { + GLuint texId = window->getFrameBufferTexture(sgct::Engine::LeftEye); + glBindTexture(GL_TEXTURE_2D, texId); + w.leftOrMain.handle->SendTexture( + texId, + GL_TEXTURE_2D, + window->getXFramebufferResolution(), + window->getYFramebufferResolution() + ); + } + + if (w.right.initialized) { + GLuint texId = window->getFrameBufferTexture(sgct::Engine::RightEye); + glBindTexture(GL_TEXTURE_2D, texId); + w.right.handle->SendTexture( + texId, + GL_TEXTURE_2D, + window->getXFramebufferResolution(), + window->getYFramebufferResolution() + ); + } + } + glBindTexture(GL_TEXTURE_2D, 0); +#endif // OPENSPACE_HAS_SPOUT + LTRACE("main::mainPostDrawFunc(end)"); } @@ -236,7 +436,7 @@ void mainMousePosCallback(double x, double y) { } } -void mainMouseScrollCallback(double posX, double posY) { +void mainMouseScrollCallback(double, double posY) { LTRACE("main::mainMouseScrollCallback(begin"); if (SgctEngine->isMaster()) { OsEng.mouseScrollWheelCallback(posY); @@ -368,6 +568,25 @@ int main_main(int argc, char** argv) { LDEBUG("Destroying SGCT Engine"); delete SgctEngine; + + +#ifdef OPENVR_SUPPORT + // 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(); + } + } +#endif // OPENSPACE_HAS_SPOUT }; bool initSuccess = SgctEngine->init(versionMapping[glVersion]); @@ -385,11 +604,6 @@ int main_main(int argc, char** argv) { cleanup(); -#ifdef OPENVR_SUPPORT - // Clean up OpenVR - sgct::SGCTOpenVR::shutdown(); -#endif - // Exit program exit(EXIT_SUCCESS); } @@ -397,6 +611,10 @@ int main_main(int argc, char** argv) { } // namespace int main(int argc, char** argv) { +#ifdef WIN32 + SetUnhandledExceptionFilter(generateMiniDump); +#endif // WIN32 + // If we are working as a developer, we don't want to catch the exceptions in order to // find the locations where the exceptions are raised. // If we are not in developer mode, we want to catch and at least log the error before diff --git a/config/sgct/two_nodes.xml b/config/sgct/two_nodes.xml index bbcd4a63e5..b4ae20f8c0 100644 --- a/config/sgct/two_nodes.xml +++ b/config/sgct/two_nodes.xml @@ -5,6 +5,7 @@ + diff --git a/data/scene/atmosphereearth.scene b/data/scene/atmosphereearth.scene index c537671beb..bbbb601879 100644 --- a/data/scene/atmosphereearth.scene +++ b/data/scene/atmosphereearth.scene @@ -43,7 +43,7 @@ function postInitialization() graphical settings for the renderables. ]]-- openspace.printInfo("Setting default values") - openspace.setPropertyValue("Sun.renderable.enabled", false) + openspace.setPropertyValue("Sun.renderable.enabled", true) openspace.setPropertyValue("SunMarker.renderable.enabled", false) openspace.setPropertyValue("EarthMarker.renderable.enabled", false) openspace.setPropertyValue("Constellation Bounds.renderable.enabled", false) @@ -69,8 +69,10 @@ return { --Focus = "Mars", --Position = {526781518487.171326, 257168309890.072144, -1381125204152.817383}, --Rotation = {-0.106166, 0.981574, -0.084545, 0.134513}, - Position = {-21230341452.764542, -75199905816.520981, 126295587136.952240}, - Rotation = {0.243724, 0.002268, 0.964416, 0.102449}, + --Position = {-21230341452.764542, -75199905816.520981, 126295587136.952240}, + --Rotation = {0.243724, 0.002268, 0.964416, 0.102449}, + Position = {-21235464763.652920, -75191278487.585068, 126294839057.346405}, + Rotation = {0.224913, -0.096227, 0.939918, 0.238136}, }, Modules = { "sun", diff --git a/data/scene/atmosphereearth/atmosphereearth.mod b/data/scene/atmosphereearth/atmosphereearth.mod index 9eff9a9650..dd90d2b531 100644 --- a/data/scene/atmosphereearth/atmosphereearth.mod +++ b/data/scene/atmosphereearth/atmosphereearth.mod @@ -23,23 +23,23 @@ return { Body = "EARTH", Geometry = { Type = "SimpleSphere", - Radius = { 6.3781366, 6 }, - --Radius = { 6.420, 6 }, + Radius = 6.3781366E6, + --Radius = 6.420E6, Segments = 100 }, Shadow_Group = { Source1 = { Name = "Sun", -- All radius in meters - Radius = {696.0, 6} + Radius = 696.3E6 }, - --Source2 = { Name = "Monolith", Radius = {0.01, 6} }, + --Source2 = { Name = "Monolith", Radius = 0.01E6 }, Caster1 = { Name = "Moon", -- All radius in meters - Radius = {1.737, 6} + Radius = 1.737E6 }, - --Caster2 = { Name = "Independency Day Ship", Radius = {0.0, 0.0} } + --Caster2 = { Name = "Independency Day Ship", Radius = 0 } }, Textures = { Type = "simple", @@ -148,7 +148,7 @@ return { Parent = "Earth", Renderable = { Type = "RenderablePlane", - Size = {3.0, 11.0}, + Size = 3.0E11.0, Origin = "Center", Billboard = true, Texture = "textures/marker.png", @@ -167,7 +167,7 @@ return { -- Renderable = { -- Type = "RenderablePlane", -- Billboard = true, - -- Size = { 6.371, 6 }, + -- Size = 6.371E6, -- Texture = "textures/graph.jpg", -- Atmosphere = { -- Type = "Nishita", -- for example, values missing etc etc diff --git a/data/scene/default.scene b/data/scene/default.scene index b28458aa52..3714385858 100644 --- a/data/scene/default.scene +++ b/data/scene/default.scene @@ -11,7 +11,6 @@ function preInitialization() openspace.time.setTime(openspace.time.currentWallTime()) dofile(openspace.absPath('${SCRIPTS}/bind_common_keys.lua')) - end function postInitialization() @@ -28,6 +27,8 @@ function postInitialization() openspace.setPropertyValue("MilkyWay.renderable.transparency", 0.55) openspace.setPropertyValue("MilkyWay.renderable.segments", 50) + openspace.addVirtualProperty("BoolProperty", "Show Trails", "*Trail.renderable.enabled", true, nil, nil) + openspace.resetCameraDirection() openspace.printInfo("Done setting default values") diff --git a/data/scene/earth/earth.mod b/data/scene/earth/earth.mod index 78b3a3bb90..3e293f6f3d 100644 --- a/data/scene/earth/earth.mod +++ b/data/scene/earth/earth.mod @@ -34,7 +34,7 @@ return { Body = "EARTH", Geometry = { Type = "SimpleSphere", - Radius = { 6.371, 6 }, + Radius = 6.371E6, Segments = 100 }, Textures = { @@ -49,6 +49,7 @@ return { MieColor = {1.0, 1.0, 1.0} } }, + Tag = {"planet_solarSystem", "planet_terrestrial"}, Transform = { Rotation = { Type = "SpiceRotation", @@ -78,9 +79,10 @@ return { -- EndTime = "2017 JAN 01 12:00:00.000", -- SampleInterval = 3600 Period = 365.242, - Resolution = 1000 + Resolution = 1000, + Tag = {"planetTrail_solarSystem", "planetTrail_terrestrial"} }, - GuiName = "/Solar/EarthTrail" + GuiName = "/Solar/EarthTrail", }, --[[ { @@ -88,7 +90,7 @@ return { Parent = "Earth", Renderable = { Type = "RenderablePlane", - Size = {3.0, 11.0}, + Size = 3.0E11, Origin = "Center", Billboard = true, Texture = "textures/marker.png", diff --git a/data/scene/jupiter/callisto/callisto.mod b/data/scene/jupiter/callisto/callisto.mod index 74c3360adf..aa6122bd47 100644 --- a/data/scene/jupiter/callisto/callisto.mod +++ b/data/scene/jupiter/callisto/callisto.mod @@ -9,7 +9,7 @@ return { Body = "CALLISTO", Geometry = { Type = "SimpleSphere", - Radius = { 2.631, 6}, + Radius = 2.631E6, Segments = 100 }, Textures = { diff --git a/data/scene/jupiter/europa/europa.mod b/data/scene/jupiter/europa/europa.mod index 54df372720..fea16b4627 100644 --- a/data/scene/jupiter/europa/europa.mod +++ b/data/scene/jupiter/europa/europa.mod @@ -9,7 +9,7 @@ return { Body = "EUROPA", Geometry = { Type = "SimpleSphere", - Radius = { 1.561, 6}, + Radius = 1.561E6, Segments = 100 }, Textures = { diff --git a/data/scene/jupiter/ganymede/ganymede.mod b/data/scene/jupiter/ganymede/ganymede.mod index c2c9fdca08..16aa1c175a 100644 --- a/data/scene/jupiter/ganymede/ganymede.mod +++ b/data/scene/jupiter/ganymede/ganymede.mod @@ -9,7 +9,7 @@ return { Body = "JUPITER BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = { 2.631, 6}, + Radius = 2.631E6, Segments = 100 }, Textures = { diff --git a/data/scene/jupiter/io/io.mod b/data/scene/jupiter/io/io.mod index 03d28e60d1..98e5e88e7f 100644 --- a/data/scene/jupiter/io/io.mod +++ b/data/scene/jupiter/io/io.mod @@ -9,7 +9,7 @@ return { Body = "IO", Geometry = { Type = "SimpleSphere", - Radius = { 1.8213, 6 }, + Radius = 1.8213E6, Segments = 100 }, Textures = { diff --git a/data/scene/jupiter/jupiter/jupiter.mod b/data/scene/jupiter/jupiter/jupiter.mod index 6302b66739..f9030b25f1 100644 --- a/data/scene/jupiter/jupiter/jupiter.mod +++ b/data/scene/jupiter/jupiter/jupiter.mod @@ -22,7 +22,7 @@ return { Body = "JUPITER BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = { 0.71492, 8 }, + Radius = 0.71492E8, Segments = 200 }, Textures = { @@ -35,6 +35,7 @@ return { MieColor = {1.0, 1.0, 1.0} } }, + Tag = "planet_solarSystem", Transform = { Translation = { Type = "StaticTranslation", @@ -64,7 +65,8 @@ return { }, Color = { 0.8, 0.7, 0.7 }, Period = 4330.595, - Resolution = 1000 - } + Resolution = 1000, + }, + Tag = "planetTrail_solarSystem" } } diff --git a/data/scene/lodglobes/earth/earth.mod b/data/scene/lodglobes/earth/earth.mod index 1df4498c85..5660cff113 100644 --- a/data/scene/lodglobes/earth/earth.mod +++ b/data/scene/lodglobes/earth/earth.mod @@ -56,13 +56,14 @@ return { SegmentsPerPatch = 64, Layers = { ColorLayers = { + { Name = "ESRI VIIRS Combo", Type = "ByLevel", LevelTileProviders = { { - MaxLevel = 7, - TileProvider = { FilePath = "map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml", }, + MaxLevel = 3, + TileProvider = { Type = "Temporal", FilePath = "map_service_configs/GIBS/Temporal_VIIRS_SNPP_CorrectedReflectance_TrueColor.xml", }, }, { MaxLevel = 22, @@ -71,6 +72,10 @@ return { }, Enabled = true, }, + { + Name = "ESRI Imagery World", + FilePath = "map_service_configs/ESRI/ESRI_Imagery_World_2D.wms" + }, { Type = "Temporal", Name = "Temporal VIIRS SNPP", @@ -81,6 +86,11 @@ return { Name = "Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature", FilePath = "map_service_configs/GIBS/Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature.xml", }, + { + Type = "Temporal", + Name = "Temporal_AMSR2_GCOM_W1_Sea_Ice_Concentration", + FilePath = "map_service_configs/GIBS/Temporal_AMSR2_GCOM_W1_Sea_Ice_Concentration.xml", + }, -- { -- Type = "SingleImage", -- Name = "Debug Tiles", @@ -104,6 +114,11 @@ return { FilePath = "map_service_configs/GIBS/VIIRS_CityLights_2012.xml", Enabled = true, }, + { + Type = "Temporal", + Name = "Temporal Earth at Night", + FilePath = "map_service_configs/GIBS/Temporal_VIIRS_SNPP_DayNightBand_ENCC.xml" + } }, WaterMasks = { { @@ -159,7 +174,7 @@ return { Name = "Terrain tileset", FilePath = "map_service_configs/ESRI/TERRAIN.wms", Enabled = true, - MinimumPixelSize = 64, + TilePixelSize = 64, DoPreProcessing = true, }, }, diff --git a/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms b/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms index dfaa82712b..d7d7263f5c 100644 --- a/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms +++ b/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms @@ -14,8 +14,8 @@ 3 5 - ./GDAL_Cache_ESRI_Imagery_World_2d - 10 + ./GDAL_Cache/ESRI_Imagery_World_2d + 4 .jpg false diff --git a/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms b/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms index 86f039232e..3937681945 100644 --- a/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms +++ b/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms @@ -1,14 +1,21 @@ - - http://198.102.45.23/arcgis/rest/services/worldelevation3d/terrain3d? - GCS_Elevation - - - -180.0 - 90.0 - 180.0 - -90.0 - bottom - - 2 + + http://198.102.45.23/arcgis/rest/services/worldelevation3d/terrain3d? + GCS_Elevation + + + -180.0 + 90.0 + 180.0 + -90.0 + bottom + + 2 + 5 + + ./GDAL_Cache/TERRAIN + 4 + .jpg + + false diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml index c9578ad205..830e32da8a 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml @@ -1,6 +1,6 @@ - http://map1.vis.earthdata.nasa.gov/wmts-geo/Coastlines/default/2013-08-21/EPSG4326_250m/${z}/${y}/${x}.png + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/Coastlines/default/2013-08-21/250m/${z}/${y}/${x}.png -180.0 @@ -16,4 +16,14 @@ 512 512 4 - \ No newline at end of file + true + 400 + true + 5 + + ./GDAL_Cache/Coastlines + 4 + .png + + false + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml index 8d3196deff..19bbcdb9c5 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml @@ -1,6 +1,6 @@ - http://map1.vis.earthdata.nasa.gov/wmts-geo/MODIS_Aqua_CorrectedReflectance_TrueColor/default/2013-08-21/EPSG4326_250m/${z}/${y}/${x}.jpg + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/MODIS_Aqua_CorrectedReflectance_TrueColor/default/2013-08-21/250m/${z}/${y}/${x}.jpg -180.0 @@ -16,4 +16,14 @@ 512 512 3 - \ No newline at end of file + 5 + + ./GDAL_Cache/GIBS_Aqua_MODIS_true + 4 + .jpg + + false + true + 400 + true + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml index c63f815618..46a1189c43 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml @@ -1,6 +1,6 @@ - http://map1.vis.earthdata.nasa.gov/wmts-geo/MODIS_Terra_Brightness_Temp_Band31_Day/default/2013-08-21/EPSG4326_1km/${z}/${y}/${x}.png + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/MODIS_Terra_Brightness_Temp_Band31_Day/default/2013-08-21/1km/${z}/${y}/${x}.png -180.0 @@ -16,4 +16,14 @@ 512 512 4 - \ No newline at end of file + 5 + + ./GDAL_Cache/MODIS_Terra_Brightness_Temp_Band31_Day + 4 + .png + + false + true + 400 + true + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml index faf07ccced..a0d82a02b0 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml @@ -1,6 +1,6 @@ - http://map1.vis.earthdata.nasa.gov/wmts-geo/MODIS_Terra_CorrectedReflectance_TrueColor/default/2016-05-16/EPSG4326_250m/${z}/${y}/${x}.jpg + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/MODIS_Terra_CorrectedReflectance_TrueColor/default/2013-08-21/250m/${z}/${y}/${x}.jpg -180.0 @@ -16,4 +16,14 @@ 512 512 3 - \ No newline at end of file + 5 + + ./GDAL_Cache/MODIS_Terra_CorrectedReflectance_TrueColor + 4 + .jpg + + false + true + 400 + true + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor_temporal.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor_temporal.xml deleted file mode 100644 index 36013e4a3a..0000000000 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor_temporal.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - http://map1.vis.earthdata.nasa.gov/wmts-geo/MODIS_Terra_CorrectedReflectance_TrueColor/default/${t}/EPSG4326_250m/${z}/${y}/${x}.jpg - - - -180.0 - 90 - 396.0 - -198 - 8 - 2 - 1 - top - - EPSG:4326 - 512 - 512 - 3 - \ No newline at end of file diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml index 0f9c24b540..b3b90a2f48 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml @@ -1,6 +1,6 @@ - http://map1.vis.earthdata.nasa.gov/wmts-geo/MODIS_Water_Mask/default/2013-08-21/EPSG4326_250m/${z}/${y}/${x}.png + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/MODIS_Water_Mask/default/2013-08-21/250m/${z}/${y}/${x}.png -180.0 @@ -16,4 +16,14 @@ 512 512 4 - \ No newline at end of file + 5 + + ./GDAL_Cache/MODIS_Water_Mask + 4 + .png + + false + true + 400 + true + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml index 6cc0348f36..7cb0e23db1 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml @@ -1,6 +1,6 @@ - http://map1.vis.earthdata.nasa.gov/wmts-geo/Reference_Features/default/2013-08-21/EPSG4326_250m/${z}/${y}/${x}.png + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/Reference_Features/default/2013-08-21/250m/${z}/${y}/${x}.png -180.0 @@ -16,4 +16,14 @@ 512 512 4 - \ No newline at end of file + 5 + + ./GDAL_Cache/Reference_Features + 4 + .png + + false + true + 400 + true + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml index 0a13e11f23..2731893a09 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml @@ -1,6 +1,6 @@ - http://map1.vis.earthdata.nasa.gov/wmts-geo/Reference_Labels/default/2013-08-21/EPSG4326_250m/${z}/${y}/${x}.png + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/Reference_Labels/default/2013-08-21/250m/${z}/${y}/${x}.png -180.0 @@ -16,4 +16,14 @@ 512 512 4 - \ No newline at end of file + 5 + + ./GDAL_Cache/Reference_Labels + 4 + .png + + false + true + 400 + true + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/TERRA_CR_B143_2016-04-12.wms b/data/scene/lodglobes/earth/map_service_configs/GIBS/TERRA_CR_B143_2016-04-12.wms index 974c7da85f..ea8427a9a4 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/TERRA_CR_B143_2016-04-12.wms +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/TERRA_CR_B143_2016-04-12.wms @@ -1,6 +1,6 @@ - http://map1.vis.earthdata.nasa.gov/twms-geo/twms.cgi? + https://gibs.earthdata.nasa.gov/twms/twms.cgi? MODIS TERRA tileset 2016-04-12 diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_AMSR2_GCOM_W1_Sea_Ice_Concentration.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_AMSR2_GCOM_W1_Sea_Ice_Concentration.xml new file mode 100644 index 0000000000..c838cf1667 --- /dev/null +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_AMSR2_GCOM_W1_Sea_Ice_Concentration.xml @@ -0,0 +1,28 @@ + + 2012-05-08 + + 1d + YYYY-MM-DD + + + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/AMSR2_Sea_Ice_Concentration_12km/default/${OpenSpaceTimeId}/2km/${z}/${y}/${x}.png + + + -180.0 + 90 + 396.0 + -198 + 8 + 2 + 1 + top + + EPSG:4326 + 512 + 512 + 3 + true + 400 + true + + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_Aqua_Orbit_Asc.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_Aqua_Orbit_Asc.xml index e2253fabc9..a0c7ed6f8f 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_Aqua_Orbit_Asc.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_Aqua_Orbit_Asc.xml @@ -6,7 +6,7 @@ 1.1.1 - http://map2.vis.earthdata.nasa.gov/wms/wms.php?TIME=${OpenSpaceTimeId} + https://gibs.earthdata.nasa.gov/wms/wms.php?TIME=${OpenSpaceTimeId} EPSG:4326 image/png TRUE @@ -26,11 +26,8 @@ 512 512 3 + true + 400 + true - diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature.xml index 2a4f525511..d28ad2d84f 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature.xml @@ -5,7 +5,7 @@ YYYY-MM-DD - http://map1.vis.earthdata.nasa.gov/wmts-geo/GHRSST_L4_MUR_Sea_Surface_Temperature/default/${OpenSpaceTimeId}/EPSG4326_1km/${z}/${y}/${x}.png + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/GHRSST_L4_MUR_Sea_Surface_Temperature/default/${OpenSpaceTimeId}/250m/${z}/${y}/${x}.png -180.0 @@ -21,5 +21,8 @@ 512 512 4 + true + 400 + true - \ No newline at end of file + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_MODIS_Aqua_CorrectedReflectance_TrueColor.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_MODIS_Aqua_CorrectedReflectance_TrueColor.xml index d09c0e9615..1637409c25 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_MODIS_Aqua_CorrectedReflectance_TrueColor.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_MODIS_Aqua_CorrectedReflectance_TrueColor.xml @@ -5,7 +5,7 @@ YYYY-MM-DD - http://map1.vis.earthdata.nasa.gov/wmts-geo/MODIS_Aqua_CorrectedReflectance_TrueColor/default/${OpenSpaceTimeId}/EPSG4326_250m/${z}/${y}/${x}.jpg + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/MODIS_Aqua_CorrectedReflectance_TrueColor/default/${OpenSpaceTimeId}/250m/${z}/${y}/${x}.jpg -180.0 @@ -21,5 +21,8 @@ 512 512 3 + true + 400 + true - \ No newline at end of file + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_MODIS_Terra_CorrectedReflectance_TrueColor.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_MODIS_Terra_CorrectedReflectance_TrueColor.xml new file mode 100644 index 0000000000..fb8ffbf297 --- /dev/null +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_MODIS_Terra_CorrectedReflectance_TrueColor.xml @@ -0,0 +1,28 @@ + + 2012-05-08 + + 1d + YYYY-MM-DD + + + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/MODIS_Terra_CorrectedReflectance_TrueColor/default/${OpenSpaceTimeId}/250m/${z}/${y}/${x}.jpg + + + -180.0 + 90 + 396.0 + -198 + 8 + 2 + 1 + top + + EPSG:4326 + 512 + 512 + 3 + true + 400 + true + + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_VIIRS_SNPP_CorrectedReflectance_TrueColor.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_VIIRS_SNPP_CorrectedReflectance_TrueColor.xml index 311f2ec097..c656c8866e 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_VIIRS_SNPP_CorrectedReflectance_TrueColor.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_VIIRS_SNPP_CorrectedReflectance_TrueColor.xml @@ -5,7 +5,7 @@ YYYY-MM-DD - http://map1.vis.earthdata.nasa.gov/wmts-geo/VIIRS_SNPP_CorrectedReflectance_TrueColor/default/${OpenSpaceTimeId}/EPSG4326_250m/${z}/${y}/${x}.jpg + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/VIIRS_SNPP_CorrectedReflectance_TrueColor/default/${OpenSpaceTimeId}/250m/${z}/${y}/${x}.jpg -180.0 @@ -21,5 +21,8 @@ 512 512 3 + true + 400 + true - \ No newline at end of file + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_VIIRS_SNPP_DayNightBand_ENCC.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_VIIRS_SNPP_DayNightBand_ENCC.xml new file mode 100644 index 0000000000..d2e093a97c --- /dev/null +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Temporal_VIIRS_SNPP_DayNightBand_ENCC.xml @@ -0,0 +1,28 @@ + + 2012-05-08 + + 1d + YYYY-MM-DD + + + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/VIIRS_SNPP_DayNightBand_ENCC/default/${OpenSpaceTimeId}/500m/${z}/${y}/${x}.png + + + -180.0 + 90 + 396.0 + -198 + 8 + 2 + 1 + top + + EPSG:4326 + 512 + 512 + 3 + true + 400 + true + + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml index cf0c6a1866..91645c3d59 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml @@ -1,6 +1,6 @@ - http://map1.vis.earthdata.nasa.gov/wmts-geo/VIIRS_CityLights_2012/default/2012-01-01/EPSG4326_500m/${z}/${y}/${x}.jpg + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/VIIRS_CityLights_2012/default/2013-08-21/500m/${z}/${y}/${x}.jpg -180.0 @@ -16,4 +16,14 @@ 512 512 4 - \ No newline at end of file + 5 + + ./GDAL_Cache/VIIRS_CityLights_2012 + 4 + .jpg + + false + true + 400 + true + diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml index 28499cabbd..b6ffc234fa 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml @@ -1,6 +1,6 @@ - http://map1.vis.earthdata.nasa.gov/wmts-geo/VIIRS_SNPP_CorrectedReflectance_TrueColor/default/2016-10-01/EPSG4326_250m/${z}/${y}/${x}.jpg + https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/VIIRS_SNPP_CorrectedReflectance_TrueColor/default/2016-08-21/250m/${z}/${y}/${x}.jpg -180.0 @@ -16,4 +16,14 @@ 512 512 3 + 5 + + ./GDAL_Cache/VIIRS_SNPP_CorrectedReflectance_TrueColor + 4 + .jpg + + false + true + 400 + true \ No newline at end of file diff --git a/data/scene/lodglobes/jupiter/callisto/callisto.mod b/data/scene/lodglobes/jupiter/callisto/callisto.mod index 8aa1bda8f0..c86a629158 100644 --- a/data/scene/lodglobes/jupiter/callisto/callisto.mod +++ b/data/scene/lodglobes/jupiter/callisto/callisto.mod @@ -32,7 +32,7 @@ return { Name = "Callisto Texture", FilePath = "textures/callisto.jpg", Enabled = true, - MinimumPixelSize = 112, + TilePixelSize = 112, }, }, GrayScaleLayers = { }, diff --git a/data/scene/lodglobes/jupiter/europa/europa.mod b/data/scene/lodglobes/jupiter/europa/europa.mod index cd32cdd332..b3f4c1a8df 100644 --- a/data/scene/lodglobes/jupiter/europa/europa.mod +++ b/data/scene/lodglobes/jupiter/europa/europa.mod @@ -32,7 +32,7 @@ return { Name = "Europa Texture", FilePath = "textures/europa.jpg", Enabled = true, - MinimumPixelSize = 256, + TilePixelSize = 256, }, }, GrayScaleLayers = { }, diff --git a/data/scene/lodglobes/jupiter/ganymede/ganymede.mod b/data/scene/lodglobes/jupiter/ganymede/ganymede.mod index be1bb1274c..0099a57786 100644 --- a/data/scene/lodglobes/jupiter/ganymede/ganymede.mod +++ b/data/scene/lodglobes/jupiter/ganymede/ganymede.mod @@ -32,7 +32,7 @@ return { Name = "Ganymede Texture", FilePath = "textures/ganymede.jpg", Enabled = true, - MinimumPixelSize = 112, + TilePixelSize = 112, }, }, GrayScaleLayers = { }, diff --git a/data/scene/lodglobes/mars/map_service_configs/Utah/Mola_Elevation.xml b/data/scene/lodglobes/mars/map_service_configs/Utah/Mola_Elevation.xml index a0294879cf..79332d59c9 100644 --- a/data/scene/lodglobes/mars/map_service_configs/Utah/Mola_Elevation.xml +++ b/data/scene/lodglobes/mars/map_service_configs/Utah/Mola_Elevation.xml @@ -12,6 +12,7 @@ 6 top + Int16 GEOGCS["GCS_Mars_2000_Sphere",DATUM["D_Mars_2000_Sphere",SPHEROID["Mars_2000_Sphere_IAU_IAG",3396190.0,0.0]],PRIMEM["Reference_Meridian",0.0],UNIT["Degree",0.0174532925199433]] 360 360 diff --git a/data/scene/lodglobes/mars/mars.mod b/data/scene/lodglobes/mars/mars.mod index 040fc570e8..375954c010 100644 --- a/data/scene/lodglobes/mars/mars.mod +++ b/data/scene/lodglobes/mars/mars.mod @@ -32,20 +32,36 @@ return { Type = "RenderableGlobe", Radii = marsEllipsoid, CameraMinHeight = 10, + SegmentsPerPatch = 90, + -- Allows camera to go down 10000 meters below the reference ellipsoid InteractionDepthBelowEllipsoid = 10000, -- Useful when having negative height map values - SegmentsPerPatch = 64, Layers = { ColorLayers = { + { + Name = "Viking combo", + Type = "ByLevel", + LevelTileProviders = { + { + MaxLevel = 3, + TileProvider = { FilePath = "textures/mars.jpg", }, + }, + { + MaxLevel = 22, + TileProvider = { FilePath = "map_service_configs/MARS_Viking_MDIM21.xml" }, + }, + }, + Enabled = true, + }, -- { -- Type = "SingleImage", -- Name = "Debug Tiles", -- FilePath = "../../debugglobe/textures/test_tile.png", -- }, - { - Name = "MARS_Viking", - FilePath = "map_service_configs/MARS_Viking_MDIM21.xml", - Enabled = true, - }, + --{ + -- Name = "MARS_Viking", + -- FilePath = "map_service_configs/MARS_Viking_MDIM21.xml", + -- Enabled = true, + --}, { Name = "MOLA Pseudo Color", FilePath = "map_service_configs/Utah/MolaPseudoColor.xml", @@ -66,16 +82,22 @@ return { { Name = "CTX Mosaic [Europe]", FilePath = "map_service_configs/CTX_Mosaic.xml", - Enabled = true, - }, { + --Enabled = true, + }, + { Name = "CTX Mosaic [Utah]", FilePath = "map_service_configs/Utah/CTX_Mosaic.xml", }, + { + Name = "West Candor Chasma", + FilePath = "map_datasets/CTX/West_Candor_Chasma_longlat_global.vrt", + --Enabled = true, + }, { Name = "Layered Rock Outcrops in Southwest Candor Chasma", FilePath = "map_datasets/HiRISE/Layered_Rock_Outcrops_in_Southwest_Candor_Chasma_Texture.vrt", }, - { + --[[{ Name = "Themis IR Day", FilePath = "map_service_configs/Utah/ThemisIRDay.xml", }, @@ -83,12 +105,7 @@ return { Name = "Themis IR Night", FilePath = "map_service_configs/Utah/ThemisIRNight.xml", }, - --[[ - { - Name = "West Candor Chasma", - FilePath = "map_datasets/CTX/West_Candor_Chasma_longlat_global.vrt", - --Enabled = true, - }, + { Name = "MER_Meridianni_Endeavor_Basemap_25cm", FilePath = "map_datasets/Basemap/MER_Meridianni_Endeavor_Basemap_25cm.vrt", @@ -115,41 +132,49 @@ return { }, HeightLayers = { { - Name = "Mola Elevation", - FilePath = "map_service_configs/Utah/Mola_Elevation.xml", + Name = "Mola Elevation [Europe]", + FilePath = "map_service_configs/Mola_Elevation.xml", Enabled = true, - MinimumPixelSize = 90, + TilePixelSize = 90, + DoPreProcessing = true, + }, + --[[ + { + Name = "Mola Elevation [Utah]", + FilePath = "map_service_configs/Utah/Mola_Elevation.xml", + Enabled = false, + TilePixelSize = 90, DoPreProcessing = true, }, { Name = "Mola Elevation CTX", FilePath = "map_service_configs/Utah/MolaCTX_Elevation.xml", -- Enabled = true, - MinimumPixelSize = 90, + TilePixelSize = 90, DoPreProcessing = true, - }, + },]] { - Name = "Layered Rock Outcrops in Southwest Candor Chasma", - FilePath = "map_datasets/HiRISE/Layered_Rock_Outcrops_in_Southwest_Candor_Chasma_Heightmap.vrt", - MinimumPixelSize = 90, - DoPreProcessing = true, - }, - --[[ - { - Name = "Mola Elevation", - FilePath = "map_service_configs/Mars_MGS_MOLA_DEM.xml", - Enabled = true, - MinimumPixelSize = 64, - DoPreProcessing = true, - }, ---]] ---[[ { Name = "West Candor Chasma", FilePath = "map_datasets/CTX/West_Candor_Chasma_DEM_longlat_global.vrt", --Enabled = true, MinimumPixelSize = 90, DoPreProcessing = true, }, + { + Name = "Layered Rock Outcrops in Southwest Candor Chasma", + FilePath = "map_datasets/HiRISE/Layered_Rock_Outcrops_in_Southwest_Candor_Chasma_Heightmap.vrt", + TilePixelSize = 90, + DoPreProcessing = true, + }, + --[[ + { + Name = "West Candor Chasma", + FilePath = "map_datasets/CTX/West_Candor_Chasma_DEM_longlat_global.vrt", + --Enabled = true, + TilePixelSize = 90, + DoPreProcessing = true, + },]] + --[[ { Name = "Part of Area Traversed by the Mars Exploration Rover", FilePath = "map_datasets/HiRISE/Part_of_Area_Traversed_by_the_Mars_Exploration_Rover_Heightmap.vrt", diff --git a/data/scene/lodglobes/mercury/lodmercury.mod b/data/scene/lodglobes/mercury/lodmercury.mod index 8e211d3c5e..17f7383c80 100644 --- a/data/scene/lodglobes/mercury/lodmercury.mod +++ b/data/scene/lodglobes/mercury/lodmercury.mod @@ -42,7 +42,7 @@ return { Name = "Simple Texture", FilePath = "textures/mercury.jpg", Enabled = true, - MinimumPixelSize = 256, + TilePixelSize = 256, }, { Name = "Messenger_Mosaic", diff --git a/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml b/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml index 5ba619a141..6eae17b3cf 100644 --- a/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml +++ b/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml @@ -62,4 +62,10 @@ 512 512 + + + ./GDAL_Cache/OnMoonColor + 4 + .png + \ No newline at end of file diff --git a/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml b/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml index 9fe0516d15..cdfd4114e1 100644 --- a/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml +++ b/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml @@ -16,4 +16,9 @@ 1 top + + ./GDAL_Cache/OnMoonHeight + 4 + .png + \ No newline at end of file diff --git a/data/scene/lodglobes/moon/map_service_configs/Utah/LolaDem.wms b/data/scene/lodglobes/moon/map_service_configs/Utah/LolaDem.wms index 1ef0f4be0e..9465278db8 100644 --- a/data/scene/lodglobes/moon/map_service_configs/Utah/LolaDem.wms +++ b/data/scene/lodglobes/moon/map_service_configs/Utah/LolaDem.wms @@ -12,6 +12,7 @@ 7 top + Int16 GEOGCS["GCS_Moon_2000",DATUM["D_Moon_2000",SPHEROID["Moon_2000_IAU_IAG",1737400.0,0.0]],PRIMEM["Reference_Meridian",0.0],UNIT["Degree",0.0174532925199433]] 360 360 diff --git a/data/scene/lodglobes/moon/moon.mod b/data/scene/lodglobes/moon/moon.mod index 54c525ea6d..1247ae7187 100644 --- a/data/scene/lodglobes/moon/moon.mod +++ b/data/scene/lodglobes/moon/moon.mod @@ -20,8 +20,9 @@ return { Type = "RenderableGlobe", Radii = {1738140, 1738140, 1735970}, -- Moons's radius CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 5000, -- Useful when having negative height map values SegmentsPerPatch = 64, + -- Allows camera to go down 10000 meters below the reference ellipsoid + InteractionDepthBelowEllipsoid = 10000, -- Useful when having negative height map values Layers = { ColorLayers = { @@ -63,10 +64,13 @@ return { FilePath = "map_service_configs/OnMoonHeight.xml", Enabled = true, DoPreProcessing = true, + TileSize = 64, }, { Name = "LolaDem", - FilePath = "map_service_configs/Utah/LolaDem.wms" + FilePath = "map_service_configs/Utah/LolaDem.wms", + DoPreProcessing = true, + TileSize = 64, } }, }, diff --git a/data/scene/lodglobes/neptune/neptune.mod b/data/scene/lodglobes/neptune/neptune.mod index 9f3c9f854f..cfb74029b9 100644 --- a/data/scene/lodglobes/neptune/neptune.mod +++ b/data/scene/lodglobes/neptune/neptune.mod @@ -40,7 +40,7 @@ return { Name = "Texture", FilePath = "textures/neptune.jpg", Enabled = true, - MinimumPixelSize = 256, + TilePixelSize = 256, }, }, GrayScaleLayers = { }, diff --git a/data/scene/lodglobes/saturn/saturn.mod b/data/scene/lodglobes/saturn/saturn.mod index 6ce3287d0e..da471b0979 100644 --- a/data/scene/lodglobes/saturn/saturn.mod +++ b/data/scene/lodglobes/saturn/saturn.mod @@ -40,7 +40,7 @@ return { Name = "Saturn Texture", FilePath = "textures/saturn.jpg", Enabled = true, - MinimumPixelSize = 256, + TilePixelSize = 256, }, }, GrayScaleLayers = { }, diff --git a/data/scene/lodglobes/uranus/uranus.mod b/data/scene/lodglobes/uranus/uranus.mod index 9825a16459..06b2160647 100644 --- a/data/scene/lodglobes/uranus/uranus.mod +++ b/data/scene/lodglobes/uranus/uranus.mod @@ -40,7 +40,7 @@ return { Name = "Texture", FilePath = "textures/uranus.jpg", Enabled = true, - MinimumPixelSize = 256, + TilePixelSize = 256, }, }, GrayScaleLayers = { }, diff --git a/data/scene/lodglobes/venus/venus.mod b/data/scene/lodglobes/venus/venus.mod index ba6e050a33..2ac91197ed 100644 --- a/data/scene/lodglobes/venus/venus.mod +++ b/data/scene/lodglobes/venus/venus.mod @@ -45,7 +45,7 @@ return { Name = "Venus Texture", FilePath = "textures/venus.jpg", Enabled = true, - MinimumPixelSize = 256, + TilePixelSize = 256, }, }, GrayScaleLayers = { }, diff --git a/data/scene/mars/mars.mod b/data/scene/mars/mars.mod index 54e33cbd6c..301f510e5f 100644 --- a/data/scene/mars/mars.mod +++ b/data/scene/mars/mars.mod @@ -22,7 +22,7 @@ return { Body = "MARS BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = { 6.390, 6 }, + Radius = 6.390E6, Segments = 100 }, Textures = { @@ -35,12 +35,17 @@ return { MieColor = {1.0, 1.0, 1.0} } }, + Tag = {"planet_solarSystem", "planet_terrestrial"}, Transform = { Rotation = { Type = "SpiceRotation", SourceFrame = "IAU_MARS", DestinationFrame = "GALACTIC", }, + Scale = { + Type = "StaticScale", + Scale = 1, + }, } }, -- MarsTrail module @@ -56,7 +61,8 @@ return { }, Color = { 0.814, 0.305, 0.220 }, Period = 686.973, - Resolution = 1000 + Resolution = 1000, + Tag = {"planetTrail_solarSystem", "planetTrail_terrestrial"} } } } diff --git a/data/scene/mercury/mercury.mod b/data/scene/mercury/mercury.mod index aa4be9675d..61d5c6ff8b 100644 --- a/data/scene/mercury/mercury.mod +++ b/data/scene/mercury/mercury.mod @@ -1,5 +1,3 @@ -MercuryRadius = 2.4397E6; - return { -- Mercury barycenter module { @@ -24,7 +22,7 @@ return { Body = "MERCURY", Geometry = { Type = "SimpleSphere", - Radius = {MercuryRadius, 1.0}, + Radius = 2.4397E6, Segments = 100 }, Textures = { @@ -37,6 +35,7 @@ return { MieColor = {1.0, 1.0, 1.0} } }, + Tag = {"planet_solarSystem", "planet_terrestrial"}, Transform = { Rotation = { Type = "SpiceRotation", @@ -62,7 +61,8 @@ return { }, Color = {0.6, 0.5, 0.5 }, Period = 87.968, - Resolution = 100 + Resolution = 100, + Tag = {"planetTrail_solarSystem", "planetTrail_terrestrial"} } } } diff --git a/data/scene/missions/dawn/ceres/ceres.mod b/data/scene/missions/dawn/ceres/ceres.mod index ff9c413a2a..0c29ae852b 100644 --- a/data/scene/missions/dawn/ceres/ceres.mod +++ b/data/scene/missions/dawn/ceres/ceres.mod @@ -10,7 +10,7 @@ return { Body = "CERES", Geometry = { Type = "SimpleSphere", - Radius = { 6.390, 5 }, + Radius = 6.390E5, Segments = 100 }, Textures = { diff --git a/data/scene/missions/newhorizons/jupiter/callisto/callisto.mod b/data/scene/missions/newhorizons/jupiter/callisto/callisto.mod index acf03fd873..c99c354d59 100644 --- a/data/scene/missions/newhorizons/jupiter/callisto/callisto.mod +++ b/data/scene/missions/newhorizons/jupiter/callisto/callisto.mod @@ -9,7 +9,7 @@ return { Body = "CALLISTO", Geometry = { Type = "SimpleSphere", - Radius = { 1.8213, 6 }, + Radius = 1.8213E6, Segments = 100 }, Textures = { @@ -58,7 +58,7 @@ return { Parent = "Callisto", Renderable = { Type = "RenderablePlane", - Size = {1.0, 7.4}, + Size = 10^7.4, Origin = "Center", Billboard = true, Texture = "textures/Callisto-Text.png", diff --git a/data/scene/missions/newhorizons/jupiter/europa/europa.mod b/data/scene/missions/newhorizons/jupiter/europa/europa.mod index 1bec7e5c9b..21e07a2703 100644 --- a/data/scene/missions/newhorizons/jupiter/europa/europa.mod +++ b/data/scene/missions/newhorizons/jupiter/europa/europa.mod @@ -9,7 +9,7 @@ return { Body = "EUROPA", Geometry = { Type = "SimpleSphere", - Radius = { 1.8213, 6 }, + Radius = 1.8213E6, Segments = 100 }, Textures = { @@ -58,7 +58,7 @@ return { Parent = "Europa", Renderable = { Type = "RenderablePlane", - Size = {1.0, 7.4}, + Size = 10^7.4, Origin = "Center", Billboard = true, Texture = "textures/Europa-Text.png", diff --git a/data/scene/missions/newhorizons/jupiter/ganymede/ganymede.mod b/data/scene/missions/newhorizons/jupiter/ganymede/ganymede.mod index 401babcca6..5fa473d332 100644 --- a/data/scene/missions/newhorizons/jupiter/ganymede/ganymede.mod +++ b/data/scene/missions/newhorizons/jupiter/ganymede/ganymede.mod @@ -9,7 +9,7 @@ return { Body = "GANYMEDE", Geometry = { Type = "SimpleSphere", - Radius = { 1.8213, 6 }, + Radius = 1.8213E6, Segments = 100 }, Textures = { @@ -58,7 +58,7 @@ return { Parent = "Ganymede", Renderable = { Type = "RenderablePlane", - Size = {1.0, 7.4}, + Size = 10^7.4, Origin = "Center", Billboard = true, Texture = "textures/Ganymede-Text.png", diff --git a/data/scene/missions/newhorizons/jupiter/io/io.mod b/data/scene/missions/newhorizons/jupiter/io/io.mod index c41b45f29b..d4e5260cbd 100644 --- a/data/scene/missions/newhorizons/jupiter/io/io.mod +++ b/data/scene/missions/newhorizons/jupiter/io/io.mod @@ -9,7 +9,7 @@ return { Body = "IO", Geometry = { Type = "SimpleSphere", - Radius = { 1.8213, 6 }, + Radius = 1.8213E6, Segments = 100 }, Textures = { diff --git a/data/scene/missions/newhorizons/jupiter/jupiter/jupiter.mod b/data/scene/missions/newhorizons/jupiter/jupiter/jupiter.mod index 079357b2ad..17f3a6afea 100644 --- a/data/scene/missions/newhorizons/jupiter/jupiter/jupiter.mod +++ b/data/scene/missions/newhorizons/jupiter/jupiter/jupiter.mod @@ -22,7 +22,7 @@ return { Body = "JUPITER", Geometry = { Type = "SimpleSphere", - Radius = { 0.71492, 8 }, + Radius = 0.71492E8, Segments = 200, }, Textures = { @@ -101,7 +101,7 @@ return { Parent = "JupiterProjection", Renderable = { Type = "RenderablePlane", - Size = {1.0, 7.5}, + Size = 10^7.5, Origin = "Center", Billboard = true, Texture = "textures/Jupiter-text.png", diff --git a/data/scene/missions/newhorizons/newhorizonsfov/newhorizonsfov.mod b/data/scene/missions/newhorizons/newhorizonsfov/newhorizonsfov.mod index 7fdccdf6cc..7ece77d4e9 100644 --- a/data/scene/missions/newhorizons/newhorizonsfov/newhorizonsfov.mod +++ b/data/scene/missions/newhorizons/newhorizonsfov/newhorizonsfov.mod @@ -295,9 +295,9 @@ return { Type = "RenderableCrawlingLine", Source = "NH_REX", Target = "EARTH", - -- Body = "NEW HORIZONS", + -- Body = "NEW HORIZONS", Frame = "GALACTIC", - RGB = { 1.0, 0.7, 0.0 }, + Color = { 1.0, 0.7, 0.0 }, Instrument = "NH_REX" }, } diff --git a/data/scene/missions/newhorizons/pluto/charon/charon.mod b/data/scene/missions/newhorizons/pluto/charon/charon.mod index 4cfff1d131..7cc7544f84 100644 --- a/data/scene/missions/newhorizons/pluto/charon/charon.mod +++ b/data/scene/missions/newhorizons/pluto/charon/charon.mod @@ -24,7 +24,7 @@ return { Type = "RenderablePlanetProjection", Geometry = { Type = "SimpleSphere", - Radius = { 6.035 , 5 }, + Radius = 6.035E5, Segments = 100 }, Textures = { @@ -72,7 +72,7 @@ return { Parent = "Charon", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 10^6.3, Origin = "Center", Billboard = true, Texture = "textures/Charon-Text.png", diff --git a/data/scene/missions/newhorizons/pluto/hydra/hydra.mod b/data/scene/missions/newhorizons/pluto/hydra/hydra.mod index 8dcf6d2d0f..dbffd9a8a2 100644 --- a/data/scene/missions/newhorizons/pluto/hydra/hydra.mod +++ b/data/scene/missions/newhorizons/pluto/hydra/hydra.mod @@ -46,7 +46,7 @@ return { Parent = "Hydra", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 10.0^6.3, Origin = "Center", Billboard = true, Texture = "textures/Hydra-Text.png" diff --git a/data/scene/missions/newhorizons/pluto/kerberos/kerberos.mod b/data/scene/missions/newhorizons/pluto/kerberos/kerberos.mod index 595baf13e8..5710783747 100644 --- a/data/scene/missions/newhorizons/pluto/kerberos/kerberos.mod +++ b/data/scene/missions/newhorizons/pluto/kerberos/kerberos.mod @@ -46,7 +46,7 @@ return { Parent = "Kerberos", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 10^6.3, Origin = "Center", Billboard = true, Texture = "textures/Kerberos-Text.png" diff --git a/data/scene/missions/newhorizons/pluto/nix/nix.mod b/data/scene/missions/newhorizons/pluto/nix/nix.mod index da05401b4e..8a4373431c 100644 --- a/data/scene/missions/newhorizons/pluto/nix/nix.mod +++ b/data/scene/missions/newhorizons/pluto/nix/nix.mod @@ -19,7 +19,7 @@ return { Body = "NIX", Geometry = { Type = "SimpleSphere", - Radius = { 0.45 , 5 }, + Radius = 0.45E5, Segments = 100 }, Textures = { @@ -46,7 +46,7 @@ return { Parent = "Nix", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 10^6.3, Origin = "Center", Billboard = true, Texture = "textures/Nix-Text.png" diff --git a/data/scene/missions/newhorizons/pluto/pluto/pluto.mod b/data/scene/missions/newhorizons/pluto/pluto/pluto.mod index 53118f9e84..6709f03fdb 100644 --- a/data/scene/missions/newhorizons/pluto/pluto/pluto.mod +++ b/data/scene/missions/newhorizons/pluto/pluto/pluto.mod @@ -38,7 +38,7 @@ return { Type = "RenderablePlanetProjection", Geometry = { Type = "SimpleSphere", - Radius = { 1.173 , 6 }, + Radius = 1.173E6, Segments = 100 }, Textures = { @@ -173,7 +173,7 @@ return { Renderable = { Type = "RenderablePlane", Billboard = true, - Size = { 5, 4 }, + Size = 5E4, Texture = "textures/barycenter.png", Atmosphere = { Type = "Nishita", -- for example, values missing etc etc @@ -187,7 +187,7 @@ return { Parent = "Pluto", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 10^6.3, Origin = "Center", Billboard = true, Texture = "textures/Pluto-Text.png", diff --git a/data/scene/missions/newhorizons/pluto/styx/styx.mod b/data/scene/missions/newhorizons/pluto/styx/styx.mod index 559062be97..8637601452 100644 --- a/data/scene/missions/newhorizons/pluto/styx/styx.mod +++ b/data/scene/missions/newhorizons/pluto/styx/styx.mod @@ -19,7 +19,7 @@ return { Body = "STYX", Geometry = { Type = "SimpleSphere", - Radius = { 0.75 , 4 }, + Radius = 0.75E4, Segments = 100 }, Textures = { @@ -46,7 +46,7 @@ return { Parent = "Styx", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 10^6.3, Origin = "Center", Billboard = true, Texture = "textures/Styx-Text.png", diff --git a/data/scene/moon/moon.mod b/data/scene/moon/moon.mod index b58b056dcb..534adf617c 100644 --- a/data/scene/moon/moon.mod +++ b/data/scene/moon/moon.mod @@ -9,17 +9,17 @@ return { Body = "MOON", Geometry = { Type = "SimpleSphere", - Radius = { 1.737, 6}, + Radius = 1.737E6, Segments = 100 }, Shadow_Group = { Source1 = { Name = "Sun", - Radius = {696.3, 6} + Radius = 696.3E6 }, Caster1 = { Name = "Earth", - Radius = {6.371, 6} + Radius = 6.371E6 }, }, Textures = { diff --git a/data/scene/neptune/neptune.mod b/data/scene/neptune/neptune.mod index 5967f0a8fe..38e698c9ea 100644 --- a/data/scene/neptune/neptune.mod +++ b/data/scene/neptune/neptune.mod @@ -23,20 +23,25 @@ return { Body = "NEPTUNE BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = { 2.4622 , 7 }, + Radius = 2.4622E7, Segments = 100 }, Textures = { Type = "simple", Color = "textures/neptune.jpg", - }, + } }, - Translation = { + Tag = "planet_solarSystem", + Transform = { Rotation = { Type = "SpiceRotation", SourceFrame = "IAU_NEPTUNE", DestinationFrame = "GALACTIC" }, + Scale = { + Type = "StaticScale", + Scale = 1, + }, } }, -- NeptuneTrail module @@ -52,7 +57,8 @@ return { }, Color = {0.2, 0.5, 1.0 }, Period = 60200, - Resolution = 1000 - }, + Resolution = 1000, + Tag = "planetTrail_solarSystem" + } } } diff --git a/data/scene/pluto/pluto.mod b/data/scene/pluto/pluto.mod index 88346771ef..27f540d731 100644 --- a/data/scene/pluto/pluto.mod +++ b/data/scene/pluto/pluto.mod @@ -25,7 +25,7 @@ return { Body = "PLUTO", Geometry = { Type = "SimpleSphere", - Radius = { 1.173 , 6 }, + Radius = 1.173E6, Segments = 100 }, Textures = { @@ -61,7 +61,7 @@ return { Body = "CHARON", Geometry = { Type = "SimpleSphere", - Radius = { 6.035 , 5 }, + Radius = 6.035E5, Segments = 100 }, Textures = { diff --git a/data/scene/saturn/dione/dione.mod b/data/scene/saturn/dione/dione.mod index d132bea897..477705ea2b 100644 --- a/data/scene/saturn/dione/dione.mod +++ b/data/scene/saturn/dione/dione.mod @@ -8,7 +8,7 @@ return { Body = "DIONE", Geometry = { Type = "SimpleSphere", - Radius = { 0.563, 3 }, + Radius = 0.563E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/enceladus/enceladus.mod b/data/scene/saturn/enceladus/enceladus.mod index 1d3011e4c8..f49104d3ca 100644 --- a/data/scene/saturn/enceladus/enceladus.mod +++ b/data/scene/saturn/enceladus/enceladus.mod @@ -8,7 +8,7 @@ return { Body = "ENCELADUS", Geometry = { Type = "SimpleSphere", - Radius = { 0.257, 3 }, + Radius = 0.257E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/iapetus/iapetus.mod b/data/scene/saturn/iapetus/iapetus.mod index a390af3ec4..0bcc6b8c38 100644 --- a/data/scene/saturn/iapetus/iapetus.mod +++ b/data/scene/saturn/iapetus/iapetus.mod @@ -8,7 +8,7 @@ return { Body = "IAPETUS", Geometry = { Type = "SimpleSphere", - Radius = { 0.746, 3 }, + Radius = 0.746E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/mimas/mimas.mod b/data/scene/saturn/mimas/mimas.mod index bf7b451d83..9f8e5242e6 100644 --- a/data/scene/saturn/mimas/mimas.mod +++ b/data/scene/saturn/mimas/mimas.mod @@ -8,7 +8,7 @@ return { Body = "MIMAS", Geometry = { Type = "SimpleSphere", - Radius = { 0.28, 3 }, + Radius = 0.28E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/rhea/rhea.mod b/data/scene/saturn/rhea/rhea.mod index 623dd479a6..8bb6c61393 100644 --- a/data/scene/saturn/rhea/rhea.mod +++ b/data/scene/saturn/rhea/rhea.mod @@ -8,7 +8,7 @@ return { Body = "RHEA", Geometry = { Type = "SimpleSphere", - Radius = { 0.765, 3 }, + Radius = 0.765E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/saturn/saturn.mod b/data/scene/saturn/saturn/saturn.mod index 4dc0a215c6..675910faab 100644 --- a/data/scene/saturn/saturn/saturn.mod +++ b/data/scene/saturn/saturn/saturn.mod @@ -1,6 +1,3 @@ -SaturnRadius = 5.8232E7; - - return { -- Saturn barycenter module { @@ -26,7 +23,7 @@ return { Body = "SATURN BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = {SaturnRadius, 0}, + Radius = 5.8232E7, Segments = 100 }, Textures = { @@ -39,6 +36,7 @@ return { MieColor = {1.0, 1.0, 1.0} } }, + Tag = "planet_solarSystem", Transform = { Rotation = { Type = "SpiceRotation", @@ -76,7 +74,8 @@ return { }, Color = {0.85,0.75,0.51 }, Period = 10746.94, - Resolution = 1000 + Resolution = 1000, + Tag = "planetTrail_solarSystem" }, } } diff --git a/data/scene/saturn/tethys/tethys.mod b/data/scene/saturn/tethys/tethys.mod index eb2a84b3f9..8fe16fa3cd 100644 --- a/data/scene/saturn/tethys/tethys.mod +++ b/data/scene/saturn/tethys/tethys.mod @@ -8,7 +8,7 @@ return { Body = "TETHYS", Geometry = { Type = "SimpleSphere", - Radius = { 0.538, 3 }, + Radius = 0.538E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/titan/titan.mod b/data/scene/saturn/titan/titan.mod index 83e366c7ba..12cc0d6034 100644 --- a/data/scene/saturn/titan/titan.mod +++ b/data/scene/saturn/titan/titan.mod @@ -8,7 +8,7 @@ return { Body = "TITAN", Geometry = { Type = "SimpleSphere", - Radius = { 0.2575, 4 }, + Radius = 0.2575E4, Segments = 50 }, Textures = { diff --git a/data/scene/sun/sun.mod b/data/scene/sun/sun.mod index 3bd4e2218e..6905d9de89 100644 --- a/data/scene/sun/sun.mod +++ b/data/scene/sun/sun.mod @@ -1,4 +1,9 @@ return { + -- Solar system module + { + Name = "SolarSystem", + Parent = "Root" + }, -- Sun barycenter module { Name = "SolarSystemBarycenter", @@ -15,7 +20,8 @@ return { Body = "SUN", Geometry = { Type = "SimpleSphere", - Radius = { 2.783200, 9 }, + --Radius = 2.783200E9, + Radius = 6.957E8, Segments = 100 }, Textures = { @@ -44,7 +50,7 @@ return { Parent = "SolarSystemBarycenter", Renderable = { Type = "RenderablePlane", - Size = {1.3, 10.5}, + Size = 1.3*10^10.5, Origin = "Center", Billboard = true, Texture = "textures/sun-glare.png", @@ -65,7 +71,7 @@ return { Parent = "Sun", Renderable = { Type = "RenderablePlane", - Size = {3.0, 11.0}, + Size = 3.0E11, Origin = "Center", Billboard = true, Texture = "textures/marker.png", diff --git a/data/scene/uranus/uranus.mod b/data/scene/uranus/uranus.mod index 7d0a559780..28e4568118 100644 --- a/data/scene/uranus/uranus.mod +++ b/data/scene/uranus/uranus.mod @@ -23,7 +23,7 @@ return { Body = "URANUS BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = { 2.5362 , 7 }, + Radius = 2.5362E7, Segments = 100 }, Textures = { @@ -36,12 +36,17 @@ return { MieColor = {1.0, 1.0, 1.0} } }, + Tag = "planet_solarSystem", Transform = { Rotation = { Type = "SpiceRotation", SourceFrame = "IAU_URANUS", DestinationFrame = "ECLIPJ2000", - } + }, + Scale = { + Type = "StaticScale", + Scale = 1, + }, }, }, @@ -58,7 +63,8 @@ return { }, Color = {0.60, 0.95, 1.00 }, Period = 30588.740, - Resolution = 1000 - }, + Resolution = 1000, + Tag = "planetTrail_solarSystem" + } } } diff --git a/data/scene/venus/venus.mod b/data/scene/venus/venus.mod index c7943047d3..7badb32f9c 100644 --- a/data/scene/venus/venus.mod +++ b/data/scene/venus/venus.mod @@ -23,7 +23,7 @@ return { Body = "VENUS", Geometry = { Type = "SimpleSphere", - Radius = { 3.760, 6 }, + Radius = 3.760E6, Segments = 100 }, Textures = { @@ -36,10 +36,17 @@ return { MieColor = {1.0, 1.0, 1.0} } }, - Rotation = { - Type = "SpiceRotation", - Frame = "IAU_VENUS", - Reference = "GALACTIC" + Tag = {"planet_solarSystem", "planet_terrestrial"}, + Transform = { + Rotation = { + Type = "SpiceRotation", + SourceFrame = "IAU_VENUS", + DestinationFrame = "GALACTIC" + }, + Scale = { + Type = "StaticScale", + Scale = 1, + }, }, }, @@ -56,7 +63,8 @@ return { }, Color = { 1.0, 0.5, 0.2 }, Period = 224.695, - Resolution = 1000 + Resolution = 1000, + Tag = {"planetTrail_solarSystem", "planetTrail_terrestrial"} } } } diff --git a/ext/curl/lib/libcurl.dll b/ext/curl/lib/libcurl.dll index 1c912ca6ad..3bb272359f 100644 Binary files a/ext/curl/lib/libcurl.dll and b/ext/curl/lib/libcurl.dll differ diff --git a/ext/curl/lib/libcurl_imp.lib b/ext/curl/lib/libcurl_imp.lib index 917274da36..1b3d959654 100644 Binary files a/ext/curl/lib/libcurl_imp.lib and b/ext/curl/lib/libcurl_imp.lib differ diff --git a/ext/curl/lib/libeay32.dll b/ext/curl/lib/libeay32.dll new file mode 100644 index 0000000000..84ea405801 Binary files /dev/null and b/ext/curl/lib/libeay32.dll differ diff --git a/ext/curl/lib/ssleay32.dll b/ext/curl/lib/ssleay32.dll new file mode 100644 index 0000000000..b5d2864366 Binary files /dev/null and b/ext/curl/lib/ssleay32.dll differ diff --git a/ext/ghoul b/ext/ghoul index 143d50aa65..8afa0763b1 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 143d50aa657adc075c311d5e8c3d829710bc2ec3 +Subproject commit 8afa0763b1dc52b02384333abffa7e126146403c diff --git a/ext/sgct b/ext/sgct index 0bea7bdb11..1eb6bcfa78 160000 --- a/ext/sgct +++ b/ext/sgct @@ -1 +1 @@ -Subproject commit 0bea7bdb11fe060b39194801646fb1b8a7ff597d +Subproject commit 1eb6bcfa78a08abf0caa4c7a03097316e76d701b diff --git a/ext/spice b/ext/spice index 1c9bb9e4dd..63e382ac76 160000 --- a/ext/spice +++ b/ext/spice @@ -1 +1 @@ -Subproject commit 1c9bb9e4dd562e3085c8a519c8a90668439a34ac +Subproject commit 63e382ac76e0ef37d46a8a0ec3d1980e480f3f88 diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h index f431add35f..ddf39e6c9a 100644 --- a/include/openspace/documentation/verifier.h +++ b/include/openspace/documentation/verifier.h @@ -216,6 +216,19 @@ struct StringListVerifier : public TableVerifier { std::string type() const override; }; +/** +* A Verifier that checks whether all values contained in a Table are of type \c int. +*/ +struct IntListVerifier : public TableVerifier { + /** + * Constructor for a IntListVerifier. + * \param elementDocumentation The documentation for each string in the list + */ + IntListVerifier(std::string elementDocumentation = ""); + + std::string type() const override; +}; + //---------------------------------------------------------------------------------------- // Vector verifiers //---------------------------------------------------------------------------------------- diff --git a/include/openspace/engine/configurationmanager.h b/include/openspace/engine/configurationmanager.h index f67b55bc6e..92909e6789 100644 --- a/include/openspace/engine/configurationmanager.h +++ b/include/openspace/engine/configurationmanager.h @@ -104,6 +104,8 @@ public: /// The key that stores whether the master node should perform rendering just function /// as a pure manager static const std::string KeyDisableMasterRendering; + /// The key that stores whether the master node should apply the scene transformation + static const std::string KeyDisableSceneOnMaster; /// The key that sets the request URL that is used to request additional data to be /// downloaded static const std::string KeyDownloadRequestURL; @@ -124,7 +126,22 @@ public: static const std::string PartHttpProxyUser; /// The key that stores the password to use for authentication to access the http proxy static const std::string PartHttpProxyPassword; - + /// The key that stores the dictionary containing information about debug contexts + static const std::string KeyOpenGLDebugContext; + /// The part of the key storing whether an OpenGL Debug context should be created + static const std::string PartActivate; + /// The part of the key storing whether the debug callbacks are performed synchronous + static const std::string PartSynchronous; + /// The part of the key storing a list of identifiers that should be filtered out + static const std::string PartFilterIdentifier; + /// The part of the key that stores the source of the ignored identifier + static const std::string PartFilterIdentifierSource; + /// The part of the key that stores the type of the ignored identifier + static const std::string PartFilterIdentifierType; + /// The part of the key that stores the identifier of the ignored identifier + static const std::string PartFilterIdentifierIdentifier; + /// The part of the key storing a list of severities that should be filtered out + static const std::string PartFilterSeverity; /** * Iteratively walks the directory structure starting with \p filename to find the diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 7a12cc6e2a..dfc04f409b 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -55,6 +55,9 @@ class NetworkEngine; class ParallelConnection; class RenderEngine; class SettingsEngine; +class SceneManager; +class VirtualPropertyManager; + class SyncEngine; class TimeManager; class WindowWrapper; @@ -85,7 +88,8 @@ public: void deinitialize(); void preSynchronization(); void postSynchronizationPreDraw(); - void render(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix); + void render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix, + const glm::mat4& projectionMatrix); void postDraw(); void keyboardCallback(Key key, KeyModifier mod, KeyAction action); void charCallback(unsigned int codepoint, KeyModifier mod); @@ -95,7 +99,9 @@ public: void externalControlCallback(const char* receivedChars, int size, int clientId); void encode(); void decode(); - + + void scheduleLoadScene(std::string scenePath); + void enableBarrier(); void disableBarrier(); @@ -120,6 +126,7 @@ public: properties::PropertyOwner& globalPropertyOwner(); scripting::ScriptEngine& scriptEngine(); scripting::ScriptScheduler& scriptScheduler(); + VirtualPropertyManager& virtualPropertyManager(); // This method is only to be called from Modules @@ -165,8 +172,8 @@ public: private: OpenSpaceEngine(std::string programName, std::unique_ptr windowWrapper); - ~OpenSpaceEngine() = default; + void loadScene(const std::string& scenePath); void gatherCommandlineArguments(); void loadFonts(); void runPreInitializationScripts(const std::string& sceneDescription); @@ -174,6 +181,7 @@ private: // Components std::unique_ptr _configurationManager; + std::unique_ptr _sceneManager; std::unique_ptr _downloadManager; std::unique_ptr _console; std::unique_ptr _moduleEngine; @@ -189,10 +197,14 @@ private: std::unique_ptr _interactionHandler; std::unique_ptr _scriptEngine; std::unique_ptr _scriptScheduler; + std::unique_ptr _virtualPropertyManager; // Others std::unique_ptr _globalPropertyNamespace; + bool _scheduledSceneSwitch; + std::string _scenePath; + struct { std::vector> initialize; std::vector> deinitialize; diff --git a/include/openspace/engine/syncengine.h b/include/openspace/engine/syncengine.h index 80d6d6d937..8d2c92711e 100644 --- a/include/openspace/engine/syncengine.h +++ b/include/openspace/engine/syncengine.h @@ -89,6 +89,11 @@ public: */ void removeSyncable(Syncable* syncable); + /** + * Remove multiple Syncables from being synchronized over the SGCT cluster + */ + void removeSyncables(const std::vector& syncables); + private: /** * Vector of Syncables. The vectors ensures consistent encode/decode order diff --git a/include/openspace/scene/scenegraph.h b/include/openspace/engine/virtualpropertymanager.h similarity index 63% rename from include/openspace/scene/scenegraph.h rename to include/openspace/engine/virtualpropertymanager.h index 01126bcc60..5c1192ede0 100644 --- a/include/openspace/scene/scenegraph.h +++ b/include/openspace/engine/virtualpropertymanager.h @@ -21,55 +21,30 @@ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ - -#ifndef __OPENSPACE_CORE___SCENEGRAPH___H__ -#define __OPENSPACE_CORE___SCENEGRAPH___H__ +#ifndef __OPENSPACE_CORE___VIRTUALPROPERTYMANAGER___H__ +#define __OPENSPACE_CORE___VIRTUALPROPERTYMANAGER___H__ + +#include + +#include + +#include #include -#include namespace openspace { -class SceneGraphNode; - -class SceneGraph { +class VirtualPropertyManager : public properties::PropertyOwner { public: - SceneGraph(); - ~SceneGraph(); + VirtualPropertyManager(); - void clear(); - bool loadFromFile(const std::string& sceneDescription); - - // Returns if addition was successful - bool addSceneGraphNode(SceneGraphNode* node); - bool removeSceneGraphNode(SceneGraphNode* node); - - const std::vector& nodes() const; - - SceneGraphNode* rootNode() const; - SceneGraphNode* sceneGraphNode(const std::string& name) const; + void addProperty(std::unique_ptr prop); + void removeProperty(properties::Property* prop); private: - struct SceneGraphNodeInternal { - ~SceneGraphNodeInternal(); - - SceneGraphNode* node = nullptr; - // From nodes that are dependent on this one - std::vector incomingEdges; - // To nodes that this node depends on - std::vector outgoingEdges; - }; - - bool nodeIsDependentOnRoot(SceneGraphNodeInternal* node); - bool sortTopologically(); - - SceneGraphNodeInternal* nodeByName(const std::string& name); - - SceneGraphNode* _rootNode; - std::vector _nodes; - std::vector _topologicalSortedNodes; + std::vector> _properties; }; } // namespace openspace -#endif // __OPENSPACE_CORE___SCENEGRAPH___H__ +#endif // __OPENSPACE_CORE___VIRTUALPROPERTYMANAGER___H__ diff --git a/include/openspace/interaction/interactionhandler.h b/include/openspace/interaction/interactionhandler.h index 34c398186c..76ab9b5610 100644 --- a/include/openspace/interaction/interactionhandler.h +++ b/include/openspace/interaction/interactionhandler.h @@ -65,6 +65,7 @@ public: // Interaction mode setters void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict); void setInteractionMode(const std::string& interactionModeKey); + InteractionMode* interactionMode(); void goToChunk(int x, int y, int level); void goToGeo(double latitude, double longitude); @@ -72,7 +73,9 @@ public: void resetKeyBindings(); void addKeyframe(const datamessagestructures::CameraKeyframe &kf); + void removeKeyframesAfter(double timestamp); void clearKeyframes(); + const std::vector& keyframes() const; void bindKeyLocal( Key key, @@ -95,8 +98,10 @@ public: // Accessors ghoul::Dictionary getCameraStateDictionary(); - SceneGraphNode* const focusNode() const; - Camera* const camera() const; + SceneGraphNode* focusNode() const; + glm::dvec3 focusNodeToCameraVector() const; + glm::quat focusNodeToCameraRotation() const; + Camera* camera() const; const InputState& inputState() const; /** diff --git a/include/openspace/interaction/interactionmode.h b/include/openspace/interaction/interactionmode.h index ae9efa3be2..0698e2992e 100644 --- a/include/openspace/interaction/interactionmode.h +++ b/include/openspace/interaction/interactionmode.h @@ -82,9 +82,12 @@ namespace interaction { // Mutators void addKeyframe(const datamessagestructures::CameraKeyframe &kf); + void removeKeyframesAfter(double timestamp); void clearKeyframes(); void clearOldKeyframes(); + static bool compareKeyframeTimes(const datamessagestructures::CameraKeyframe& a, const datamessagestructures::CameraKeyframe& b); + // Accessors const std::list >& getPressedKeys() const; const std::list& getPressedMouseButtons() const; @@ -119,6 +122,7 @@ public: // Accessors SceneGraphNode* focusNode(); Interpolator& rotateToFocusNodeInterpolator(); + virtual bool followingNodeRotation() const = 0; virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime) = 0; virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime) = 0; @@ -195,6 +199,7 @@ public: virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); + bool followingNodeRotation() const override; private: std::vector _keyframes; @@ -245,6 +250,7 @@ public: virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); + bool followingNodeRotation() const override; protected: //void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); @@ -260,6 +266,7 @@ public: virtual void setFocusNode(SceneGraphNode* focusNode); //virtual void update(Camera& camera, const InputState& inputState, double deltaTime); virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); + bool followingNodeRotation() const override; #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED void goToChunk(Camera& camera, globebrowsing::TileIndex ti, glm::vec2 uv, bool resetCameraDirection); diff --git a/include/openspace/interaction/luaconsole.h b/include/openspace/interaction/luaconsole.h index 119134e7e3..77beaf3109 100644 --- a/include/openspace/interaction/luaconsole.h +++ b/include/openspace/interaction/luaconsole.h @@ -53,7 +53,7 @@ private: void addToCommand(std::string c); properties::BoolProperty _isVisible; - bool _remoteScripting; + properties::BoolProperty _remoteScripting; size_t _inputPosition; std::vector _commandsHistory; diff --git a/include/openspace/network/messagestructures.h b/include/openspace/network/messagestructures.h index 5f85c57bcb..ee2ffc71a9 100644 --- a/include/openspace/network/messagestructures.h +++ b/include/openspace/network/messagestructures.h @@ -51,16 +51,28 @@ struct CameraKeyframe { glm::dvec3 _position; glm::dquat _rotation; + bool _followNodeRotation; + std::string _focusNode; + double _timestamp; void serialize(std::vector &buffer){ - //add position + // Add position buffer.insert(buffer.end(), reinterpret_cast(&_position), reinterpret_cast(&_position) + sizeof(_position)); - //add orientation + // Add orientation buffer.insert(buffer.end(), reinterpret_cast(&_rotation), reinterpret_cast(&_rotation) + sizeof(_rotation)); - - //add timestamp + + // Follow focus node rotation? + buffer.insert(buffer.end(), reinterpret_cast(&_followNodeRotation), reinterpret_cast(&_followNodeRotation) + sizeof(_followNodeRotation)); + + int nodeNameLength = _focusNode.size(); + + // Add focus node + buffer.insert(buffer.end(), reinterpret_cast(&nodeNameLength), reinterpret_cast(&nodeNameLength) + sizeof(nodeNameLength)); + buffer.insert(buffer.end(), _focusNode.data(), _focusNode.data() + nodeNameLength); + + // Add timestamp buffer.insert(buffer.end(), reinterpret_cast(&_timestamp), reinterpret_cast(&_timestamp) + sizeof(_timestamp)); }; @@ -68,17 +80,31 @@ struct CameraKeyframe { int offset = 0; int size = 0; - //position + // Position size = sizeof(_position); memcpy(&_position, buffer.data() + offset, size); offset += size; - - //orientation + + // Orientation size = sizeof(_rotation); memcpy(&_rotation, buffer.data() + offset, size); offset += size; + + // Follow focus node rotation? + size = sizeof(_followNodeRotation); + memcpy(&_followNodeRotation, buffer.data() + offset, size); + offset += size; + + // Focus node + int nodeNameLength; + size = sizeof(int); + memcpy(&nodeNameLength, buffer.data() + offset, size); + offset += size; + size = nodeNameLength; + _focusNode = std::string(buffer.data() + offset, buffer.data() + offset + size); + offset += size; - //timestamp + // Timestamp size = sizeof(_timestamp); memcpy(&_timestamp, buffer.data() + offset, size); }; @@ -97,19 +123,19 @@ struct TimeKeyframe { double _timestamp; void serialize(std::vector &buffer){ - //add current time + // Add current time buffer.insert(buffer.end(), reinterpret_cast(&_time), reinterpret_cast(&_time) + sizeof(_time)); - //add delta time + // Add delta time buffer.insert(buffer.end(), reinterpret_cast(&_dt), reinterpret_cast(&_dt) + sizeof(_dt)); - //add wether time is paused or not + // Add whether time is paused or not buffer.insert(buffer.end(), reinterpret_cast(&_paused), reinterpret_cast(&_paused) + sizeof(_paused)); - //add wether a time jump is necessary (recompute paths etc) + // Add whether a time jump is necessary (recompute paths etc) buffer.insert(buffer.end(), reinterpret_cast(&_requiresTimeJump), reinterpret_cast(&_requiresTimeJump) + sizeof(_requiresTimeJump)); - //add timestamp + // Add timestamp buffer.insert(buffer.end(), reinterpret_cast(&_timestamp), reinterpret_cast(&_timestamp) + sizeof(_timestamp)); }; @@ -117,27 +143,27 @@ struct TimeKeyframe { int offset = 0; int size = 0; - //current time + // Current time size = sizeof(_time); memcpy(&_time, buffer.data() + offset, size); offset += size; - //delta time + // Delta time size = sizeof(_dt); memcpy(&_dt, buffer.data() + offset, size); offset += size; - //is time paused? + // Is time paused? size = sizeof(_paused); memcpy(&_paused, buffer.data() + offset, size); offset += sizeof(_paused); - //is a time jump required? + // Is a time jump required? size = sizeof(_requiresTimeJump); memcpy(&_requiresTimeJump, buffer.data() + offset, size); offset += size; - // timestamp + // Timestamp size = sizeof(_timestamp); memcpy(&_timestamp, buffer.data() + offset, size); offset += size; diff --git a/include/openspace/network/parallelconnection.h b/include/openspace/network/parallelconnection.h index 8b43662206..db3d000413 100644 --- a/include/openspace/network/parallelconnection.h +++ b/include/openspace/network/parallelconnection.h @@ -27,6 +27,9 @@ //openspace includes #include +#include +#include +#include //glm includes #include @@ -57,7 +60,7 @@ struct addrinfo; namespace openspace { -class ParallelConnection { +class ParallelConnection : public properties::PropertyOwner { public: enum class Status : uint32_t { Disconnected = 0, @@ -99,17 +102,21 @@ class ParallelConnection { ParallelConnection(); ~ParallelConnection(); void clientConnect(); - void setPort(const std::string &port); - void setAddress(const std::string &address); - void setName(const std::string& name); + void setPort(std::string port); + void setAddress(std::string address); + void setName(std::string name); bool isHost(); const std::string& hostName(); - void requestHostship(const std::string &password); + void requestHostship(); void resignHostship(); - void setPassword(const std::string &password); + void setPassword(std::string password); + void setHostPassword(std::string hostPassword); void signalDisconnect(); void preSynchronization(); - void sendScript(const std::string& script); + void sendScript(std::string script); + void resetTimeOffset(); + double latencyStandardDeviation() const; + double timeTolerance() const; /** * Returns the Lua library that contains all Lua functions available to affect the @@ -145,7 +152,6 @@ private: void connectionStatusMessageReceived(const std::vector& messageContent); void nConnectionsMessageReceived(const std::vector& messageContent); - void broadcast(); void sendCameraKeyframe(); void sendTimeKeyframe(); @@ -158,10 +164,18 @@ private: double calculateBufferedKeyframeTime(double originalTime); - uint32_t _passCode; - std::string _port; - std::string _address; - std::string _name; + properties::StringProperty _password; + properties::StringProperty _hostPassword; + properties::StringProperty _port; + properties::StringProperty _address; + properties::StringProperty _name; + properties::FloatProperty _bufferTime; + properties::FloatProperty _timeKeyframeInterval; + properties::FloatProperty _cameraKeyframeInterval; + properties::FloatProperty _timeTolerance; + + double _lastTimeKeyframeTimestamp; + double _lastCameraKeyframeTimestamp; _SOCKET _clientSocket; @@ -191,7 +205,6 @@ private: double _initialTimeDiff; std::unique_ptr _connectionThread; - std::unique_ptr _broadcastThread; std::unique_ptr _sendThread; std::unique_ptr _listenThread; std::unique_ptr _handlerThread; diff --git a/include/openspace/openspace.h b/include/openspace/openspace.h index 199359475a..58ba149440 100644 --- a/include/openspace/openspace.h +++ b/include/openspace/openspace.h @@ -32,10 +32,10 @@ namespace openspace { std::string licenseText(); const int OPENSPACE_VERSION_MAJOR = 0; -const int OPENSPACE_VERSION_MINOR = 7; +const int OPENSPACE_VERSION_MINOR = 8; const int OPENSPACE_VERSION_PATCH = 0; -const std::string OPENSPACE_VERSION_STRING = "prerelease-12 (NAOJ)"; +const std::string OPENSPACE_VERSION_STRING = "prerelease-13 (Earth Day)"; } // namespace openspace diff --git a/include/openspace/properties/propertyowner.h b/include/openspace/properties/propertyowner.h index e26af2db6f..4fdec7bb12 100644 --- a/include/openspace/properties/propertyowner.h +++ b/include/openspace/properties/propertyowner.h @@ -207,6 +207,20 @@ public: /// \see PropertyOwner::removePropertySubOwner(PropertyOwner*) void removePropertySubOwner(PropertyOwner& owner); + /** + * Returns a list of all tags that have been assigned to the Property. Useful for + * trying to find a match for a desired batch operation on Properties. + * \return Pointer to vector of string tags that were assigned to the Property + */ + std::vector tags() const; + + /** + * Adds a tag to the Property's list of assigned tags. Tags are useful for creating + * groups of Properties that can be used in batch operations. + * \param tag The string that is to be assigned to the Property + */ + void addTag(std::string tag); + private: /// The name of this PropertyOwner std::string _name; @@ -218,6 +232,8 @@ private: std::vector _subOwners; /// The associations between group identifiers of Property's and human-readable names std::map _groupNames; + /// Collection of string tag(s) assigned to this property + std::vector _tags; }; } // namespace properties diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index c4b1e731c2..b2abbb7710 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -28,7 +28,6 @@ #include #include -#include #include #include @@ -72,8 +71,8 @@ public: virtual bool isReady() const = 0; bool isEnabled() const; - void setBoundingSphere(PowerScaledScalar boundingSphere); - PowerScaledScalar getBoundingSphere(); + void setBoundingSphere(float boundingSphere); + float boundingSphere() const; virtual void render(const RenderData& data); virtual void render(const RenderData& data, RendererTasks& rendererTask); @@ -99,7 +98,7 @@ protected: private: RenderBin _renderBin; - PowerScaledScalar boundingSphere_; + float _boundingSphere; std::string _startTime; std::string _endTime; bool _hasTimeInterval; diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index 373a7a4b58..e690b94c85 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -25,13 +25,19 @@ #ifndef __OPENSPACE_CORE___RENDERENGINE___H__ #define __OPENSPACE_CORE___RENDERENGINE___H__ -#include - +#include #include #include -#include #include #include +#include + +#include +#include +#include +#include + +#include #include @@ -48,18 +54,11 @@ class SharedMemory; namespace openspace { -namespace performance { -class PerformanceManager; -} - // Forward declare to minimize dependencies class Camera; class SyncBuffer; - class Scene; -class Renderer; -class DeferredcasterManager; -class RaycasterManager; +class SceneManager; class ScreenLog; class ScreenSpaceRenderable; @@ -78,14 +77,15 @@ public: }; RenderEngine(); - ~RenderEngine(); + ~RenderEngine() = default; void initialize(); void initializeGL(); void deinitialize(); - void setSceneGraph(Scene* sceneGraph); + void setScene(Scene* scene); Scene* scene(); + void updateScene(); Camera* camera() const; Renderer* renderer() const; @@ -95,12 +95,13 @@ public: // sgct wrapped functions - void updateSceneGraph(); + void updateShaderPrograms(); void updateFade(); void updateRenderer(); void updateScreenSpaceRenderables(); - void render(const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix); + void render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix, + const glm::mat4& projectionMatrix); void renderScreenLog(); void renderShutdownInformation(float timer, float fullTime); @@ -146,6 +147,11 @@ public: */ void postRaycast(ghoul::opengl::ProgramObject& programObject); + /** + * Set the camera to use for rendering + */ + void setCamera(Camera* camera); + void setRendererFromString(const std::string& method); @@ -183,10 +189,10 @@ private: void renderInformation(); - Camera* _mainCamera; - Scene* _sceneGraph; - RaycasterManager* _raycasterManager; - DeferredcasterManager* _deferredcasterManager; + Camera* _camera; + Scene* _scene; + std::unique_ptr _raycasterManager; + std::unique_ptr _deferredcasterManager; properties::BoolProperty _performanceMeasurements; std::unique_ptr _performanceManager; @@ -209,6 +215,7 @@ private: properties::BoolProperty _applyWarping; properties::BoolProperty _showFrameNumber; properties::BoolProperty _disableMasterRendering; + properties::BoolProperty _disableSceneOnMaster; float _globalBlackOutFactor; float _fadeDuration; diff --git a/include/openspace/scene/rotation.h b/include/openspace/scene/rotation.h index 140f95d9df..18d1f0a7c1 100644 --- a/include/openspace/scene/rotation.h +++ b/include/openspace/scene/rotation.h @@ -27,7 +27,7 @@ #include -#include +#include #include @@ -35,6 +35,8 @@ namespace ghoul { class Dictionary; } namespace openspace { +struct UpdateData; + namespace documentation { struct Documentation; } class Rotation : public properties::PropertyOwner { @@ -42,7 +44,7 @@ public: static std::unique_ptr createFromDictionary(const ghoul::Dictionary& dictionary); Rotation(const ghoul::Dictionary& dictionary); - virtual ~Rotation(); + virtual ~Rotation() = default; virtual bool initialize(); const glm::dmat3& matrix() const; virtual void update(const UpdateData& data); diff --git a/include/openspace/scene/scale.h b/include/openspace/scene/scale.h index b6c0f27a1a..147fed31f1 100644 --- a/include/openspace/scene/scale.h +++ b/include/openspace/scene/scale.h @@ -27,11 +27,16 @@ #include -#include +#include + +#include namespace ghoul { class Dictionary; } + namespace openspace { +struct UpdateData; + namespace documentation { struct Documentation; }; class Scale : public properties::PropertyOwner { @@ -39,7 +44,7 @@ public: static std::unique_ptr createFromDictionary(const ghoul::Dictionary& dictionary); Scale(); - virtual ~Scale(); + virtual ~Scale() = default; virtual bool initialize(); virtual double scaleValue() const = 0; virtual void update(const UpdateData& data); diff --git a/include/openspace/scene/scene.h b/include/openspace/scene/scene.h index 2e441092f9..76f87a3e41 100644 --- a/include/openspace/scene/scene.h +++ b/include/openspace/scene/scene.h @@ -33,8 +33,6 @@ #include #include #include -#include - #include namespace ghoul { class Dictionary; } @@ -49,61 +47,99 @@ class SceneGraphNode; // SceneGraphFinishedLoading class Scene { public: + + using UpdateDependencies = ghoul::Boolean; + + struct InvalidSceneError : ghoul::RuntimeError { + /** + * \param message The reason that caused this exception to be thrown + * \param component The optional compoment that caused this exception to be thrown + * \pre message may not be empty + */ + explicit InvalidSceneError(const std::string& message, const std::string& component = ""); + }; + // constructors & destructor Scene(); ~Scene(); /** - * Initalizes the SceneGraph by loading modules from the ${SCENEPATH} directory + * Initalizes the SceneGraph */ - bool initialize(); + void initialize(); - /* - * Clean up everything + /** + * Clear the scene graph, + * i.e. set the root node to nullptr and deallocate all scene graph nodes. */ - bool deinitialize(); + void clear(); - /* - * Load the scenegraph from the provided folder + /** + * Set the root node of the scene */ - void scheduleLoadSceneFile(const std::string& sceneDescriptionFilePath); - void clearSceneGraph(); + void setRoot(std::unique_ptr root); - void loadModule(const std::string& modulePath); + /** + * Set the camera of the scene + */ + void setCamera(std::unique_ptr camera); - /* + /** + * Return the camera + */ + Camera* camera() const; + + /** * Updates all SceneGraphNodes relative positions */ void update(const UpdateData& data); - /* - * Evaluates if the SceneGraphNodes are visible to the provided camera - */ - void evaluate(Camera* camera); - - /* - * Render visible SceneGraphNodes using the provided camera + /** + * Render visible SceneGraphNodes using the provided camera. */ void render(const RenderData& data, RendererTasks& tasks); - /* - * Returns the root SceneGraphNode + /** + * Return the root SceneGraphNode. */ SceneGraphNode* root() const; /** * Return the scenegraph node with the specified name or nullptr if that - * name does not exist + * name does not exist. */ SceneGraphNode* sceneGraphNode(const std::string& name) const; - std::vector allSceneGraphNodes() const; + /** + * Add a node and all its children to the scene. + */ + void addNode(SceneGraphNode* node, UpdateDependencies updateDeps = UpdateDependencies::Yes); - SceneGraph& sceneGraph(); + /** + * Remove a node and all its children from the scene. + */ + void removeNode(SceneGraphNode* node, UpdateDependencies updateDeps = UpdateDependencies::Yes); + + /** + * Update dependencies. + */ + void updateDependencies(); + + /** + * Return a vector of all scene graph nodes in the scene. + */ + const std::vector& allSceneGraphNodes() const; + + /** + * Return a a map from name to scene graph node. + */ + const std::map& nodesByName() const; + + /** + * Output property documentation to a file. + */ + void writePropertyDocumentation(const std::string& filename, const std::string& type, const std::string& sceneFilename); - void addSceneGraphNode(SceneGraphNode* node){ - _graph.addSceneGraphNode(node); - } /** * Returns the Lua library that contains all Lua functions available to change the * scene graph. The functions contained are @@ -116,39 +152,18 @@ public: static documentation::Documentation Documentation(); -private: - bool loadSceneInternal(const std::string& sceneDescriptionFilePath); +private: + void sortTopologically(); - void writePropertyDocumentation(const std::string& filename, const std::string& type, const std::string& sceneFilename); - - std::string _focus; - - // actual scenegraph - SceneGraph _graph; - //SceneGraphNode* _root; - //std::vector _nodes; - //std::map _allNodes; - - std::string _sceneGraphToLoad; + std::unique_ptr _root; + std::unique_ptr _camera; + std::vector _topologicallySortedNodes; + std::vector _circularNodes; + std::map _nodesByName; std::mutex _programUpdateLock; std::set _programsToUpdate; std::vector> _programs; - - typedef std::map NodeMap; - typedef std::multimap DependencyMap; - typedef std::vector LoadedList; - - struct LoadMaps { - NodeMap nodes; - DependencyMap dependencies; - LoadedList loadedNodes; - }; - - void loadModules(const std::string& directory, const ghoul::Dictionary& dictionary); - void loadModule(LoadMaps& m,const std::string& modulePath, lua_State* state); - void loadNodes(const std::string& parentName, LoadMaps& m); - void loadNode(const ghoul::Dictionary& dictionary); }; } // namespace openspace diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index 1acce2442e..9298e670ae 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -47,6 +47,8 @@ namespace documentation { struct Documentation; } class SceneGraphNode : public properties::PropertyOwner { public: + using UpdateScene = ghoul::Boolean; + struct PerformanceRecord { long long renderTime; // time in ns long long updateTimeRenderable; // time in ns @@ -59,25 +61,36 @@ public: static const std::string KeyName; static const std::string KeyParentName; static const std::string KeyDependencies; + static const std::string KeyTag; SceneGraphNode(); ~SceneGraphNode(); - static SceneGraphNode* createFromDictionary(const ghoul::Dictionary& dictionary); + static std::unique_ptr createFromDictionary(const ghoul::Dictionary& dictionary); bool initialize(); bool deinitialize(); + void traversePreOrder(std::function fn); + void traversePostOrder(std::function fn); void update(const UpdateData& data); - void evaluate(const Camera* camera, const psc& parentPosition = psc()); void render(const RenderData& data, RendererTasks& tasks); void updateCamera(Camera* camera) const; - //void addNode(SceneGraphNode* child); + void attachChild(std::unique_ptr child, UpdateScene updateScene = UpdateScene::Yes); + std::unique_ptr detachChild(SceneGraphNode& child, UpdateScene updateScene = UpdateScene::Yes); + void setParent(SceneGraphNode& parent, UpdateScene updateScene = UpdateScene::Yes); - void addChild(SceneGraphNode* child); - void setParent(SceneGraphNode* parent); - //bool abandonChild(SceneGraphNode* child); + void addDependency(SceneGraphNode& dependency, UpdateScene updateScene = UpdateScene::Yes); + void removeDependency(SceneGraphNode& dependency, UpdateScene updateScene = UpdateScene::Yes); + void clearDependencies(UpdateScene updateScene = UpdateScene::Yes); + void setDependencies(const std::vector& dependencies, UpdateScene updateScene = UpdateScene::Yes); + + const std::vector& dependencies() const; + const std::vector& dependentNodes() const; + + Scene* scene(); + void setScene(Scene* scene); glm::dvec3 position() const; const glm::dmat3& rotationMatrix() const; @@ -85,13 +98,14 @@ public: glm::dvec3 worldPosition() const; const glm::dmat3& worldRotationMatrix() const; + glm::dmat4 modelTransform() const; + glm::dmat4 inverseModelTransform() const; double worldScale() const; SceneGraphNode* parent() const; - const std::vector& children() const; + std::vector children() const; - PowerScaledScalar calculateBoundingSphere(); - PowerScaledScalar boundingSphere() const; + float boundingSphere() const; SceneGraphNode* childNode(const std::string& name); @@ -104,22 +118,19 @@ public: static documentation::Documentation Documentation(); private: - bool sphereInsideFrustum(const psc& s_pos, const PowerScaledScalar& s_rad, const Camera* camera); - glm::dvec3 calculateWorldPosition() const; glm::dmat3 calculateWorldRotation() const; double calculateWorldScale() const; - std::vector _children; + std::vector> _children; SceneGraphNode* _parent; + std::vector _dependencies; + std::vector _dependentNodes; + Scene* _scene; PerformanceRecord _performanceRecord; std::unique_ptr _renderable; - bool _renderableVisible; - - bool _boundingSphereVisible; - PowerScaledScalar _boundingSphere; // Transformation defined by ephemeris, rotation and scale struct { @@ -132,6 +143,9 @@ private: glm::dvec3 _worldPositionCached; glm::dmat3 _worldRotationCached; double _worldScaleCached; + + glm::dmat4 _modelTransformCached; + glm::dmat4 _inverseModelTransformCached; }; } // namespace openspace diff --git a/include/openspace/scene/sceneloader.h b/include/openspace/scene/sceneloader.h new file mode 100644 index 0000000000..ee828985a4 --- /dev/null +++ b/include/openspace/scene/sceneloader.h @@ -0,0 +1,119 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___SCENELOADER___H__ +#define __OPENSPACE_CORE___SCENELOADER___H__ + +#include +#include + +#include +#include + +#include +#include + +namespace openspace { + +class Scene; + +class SceneLoader { +public: + SceneLoader() = default; + ~SceneLoader() = default; + + /** + * Load a scene file. + */ + std::unique_ptr loadScene(const std::string& path); + + /** + * Import a directory of scene contents into an existing scene. + */ + std::vector importDirectory(Scene& scene, const std::string& directory); + + /** + * Import a scene graph node from a dictionary into an existing scene. + */ + SceneGraphNode* importNodeDictionary(Scene& scene, const ghoul::Dictionary& dictionary); + +private: + struct LoadedNode { + LoadedNode( + const std::string& nodeName, + const std::string& parentName, + const std::vector& deps, + std::unique_ptr n + ) + : name(nodeName) + , parent(parentName) + , dependencies(deps) + , node(std::move(n)) {} + + std::string name; + std::string parent; + std::vector dependencies; + std::unique_ptr node; + }; + + struct LoadedCamera { + LoadedCamera( + const std::string& parentName, + std::unique_ptr c + ) + : parent(parentName) + , camera(std::move(c)) {} + std::string parent; + std::unique_ptr camera; + }; + + /** + * Load a scene graph node from a dictionary + */ + SceneLoader::LoadedNode loadNode(const ghoul::Dictionary& dictionary); + + /** + * Load a mod file. + */ + std::vector loadModule(const std::string& path, lua_State* luaState); + + /** + * Load a directory. + */ + std::vector loadDirectory(const std::string& path, lua_State* luaState); + + /** + * Load a camera from a dictionary + */ + SceneLoader::LoadedCamera loadCamera(const ghoul::Dictionary& dictionary); + + /** + * Add loaded nodes to an existing scene + */ + std::vector addLoadedNodes(Scene& scene, std::vector&& nodes); +}; + +} // namespace openspace + +#endif // __OPENSPACE_CORE___SCENELOADER___H__ diff --git a/include/openspace/scene/scenemanager.h b/include/openspace/scene/scenemanager.h new file mode 100644 index 0000000000..26e73d9857 --- /dev/null +++ b/include/openspace/scene/scenemanager.h @@ -0,0 +1,48 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___SCENEMANAGER___H__ +#define __OPENSPACE_CORE___SCENEMANAGER___H__ + +#include +#include + +namespace openspace { + +class Scene; + +class SceneManager { +public: + SceneManager() = default; + ~SceneManager() = default; + Scene* loadScene(const std::string& path); + void unloadScene(Scene& scene); + void unloadAll(); +private: + std::vector> _scenes; +}; + +} // namespace + +#endif // __OPENSPACE_CORE___SCENEMANAGER___H__ diff --git a/include/openspace/scene/translation.h b/include/openspace/scene/translation.h index 3cc355be03..21ce0515b4 100644 --- a/include/openspace/scene/translation.h +++ b/include/openspace/scene/translation.h @@ -27,14 +27,17 @@ #include -#include +#include +#include #include namespace ghoul { class Dictionary; } namespace openspace { +struct UpdateData; + namespace documentation { struct Documentation; } class Translation : public properties::PropertyOwner { @@ -42,7 +45,7 @@ public: static std::unique_ptr createFromDictionary(const ghoul::Dictionary& dictionary); Translation(); - virtual ~Translation(); + virtual ~Translation() = default; virtual bool initialize(); virtual glm::dvec3 position() const = 0; diff --git a/include/openspace/util/camera.h b/include/openspace/util/camera.h index b67d82feab..d2436ab93d 100644 --- a/include/openspace/util/camera.h +++ b/include/openspace/util/camera.h @@ -39,6 +39,7 @@ namespace openspace { class SyncBuffer; +class SceneGraphNode; /** * This class still needs some more love. Suggested improvements: @@ -92,6 +93,7 @@ public: void setRotation(Quat rotation); void setScaling(glm::vec2 scaling); void setMaxFov(float fov); + void setParent(SceneGraphNode* parent); // Relative mutators void rotate(Quat rotation); @@ -109,6 +111,7 @@ public: const Quat& rotationQuaternion() const; float maxFov() const; float sinMaxFov() const; + SceneGraphNode* parent() const; // @TODO this should simply be called viewMatrix! // Or it needs to be changed so that it actually is combined. Right now it is @@ -181,6 +184,7 @@ private: SyncData _position; SyncData _rotation; SyncData _scaling; + SceneGraphNode* _parent; // _focusPosition to be removed diff --git a/include/openspace/util/distanceconstants.h b/include/openspace/util/distanceconstants.h index a7a368f7ba..daa2a1bba1 100644 --- a/include/openspace/util/distanceconstants.h +++ b/include/openspace/util/distanceconstants.h @@ -28,10 +28,10 @@ namespace openspace { namespace distanceconstants { - const float EarthRadius = 6371; - const float LightYear = 9.4607304725808E15; - const float AstronomicalUnit = 1.495978707E11; - const float Parsec = 3.0856776E16; + const float EarthRadius = 6371; + const float LightYear = 9.4607304725808E15; + const float AstronomicalUnit = 1.495978707E11; + const float Parsec = 3.0856776E16; } } diff --git a/include/openspace/util/histogram.h b/include/openspace/util/histogram.h index f26cd80beb..408cc2222c 100644 --- a/include/openspace/util/histogram.h +++ b/include/openspace/util/histogram.h @@ -34,7 +34,7 @@ class Histogram { public: Histogram(); Histogram(float minValue, float maxValue, int numBins); - Histogram(float minValue, float maxValue, int numBins, float *data); + Histogram(float minValue, float maxValue, int numBins, float* data); Histogram(Histogram&& other); ~Histogram(); diff --git a/include/openspace/util/powerscaledsphere.h b/include/openspace/util/powerscaledsphere.h index 0e51bb4364..7c18782b8c 100644 --- a/include/openspace/util/powerscaledsphere.h +++ b/include/openspace/util/powerscaledsphere.h @@ -38,8 +38,8 @@ public: // initializers PowerScaledSphere(const PowerScaledScalar& radius, int segments = 8); - PowerScaledSphere(properties::Vec4Property &radius, - int segments, std::string planetName); + + PowerScaledSphere(glm::vec3 radius, int segments); ~PowerScaledSphere(); PowerScaledSphere(const PowerScaledSphere& cpy); diff --git a/include/openspace/util/timemanager.h b/include/openspace/util/timemanager.h index 376e8d35e5..018765fbf6 100644 --- a/include/openspace/util/timemanager.h +++ b/include/openspace/util/timemanager.h @@ -25,6 +25,7 @@ #ifndef __OPENSPACE_CORE___TIMEMANAGER___H__ #define __OPENSPACE_CORE___TIMEMANAGER___H__ +#include #include #include @@ -35,7 +36,9 @@ public: void preSynchronization(double dt); void addKeyframe(const datamessagestructures::TimeKeyframe& kf); void removeKeyframesBefore(double timestamp); + void removeKeyframesAfter(double timestamp); void clearKeyframes(); + const std::deque& keyframes() const; private: void consumeKeyframes(double dt); std::deque _keyframes; diff --git a/modules/atmosphere/rendering/renderableplanetatmosphere.cpp b/modules/atmosphere/rendering/renderableplanetatmosphere.cpp index 765c428417..bf9f7f70c5 100644 --- a/modules/atmosphere/rendering/renderableplanetatmosphere.cpp +++ b/modules/atmosphere/rendering/renderableplanetatmosphere.cpp @@ -58,23 +58,23 @@ namespace { const std::string _loggerCat = "RenderablePlanetAtmosphere"; - const std::string keyFrame = "Frame"; - const std::string keyGeometry = "Geometry"; - const std::string keyRadius = "Radius"; - const std::string keyShading = "PerformShading"; - const std::string keyShadowGroup = "Shadow_Group"; - const std::string keyShadowSource = "Source"; - const std::string keyShadowCaster = "Caster"; - const std::string keyAtmosphere = "Atmosphere"; - const std::string keyAtmosphereRadius = "AtmoshereRadius"; - const std::string keyPlanetRadius = "PlanetRadius"; + const std::string keyFrame = "Frame"; + const std::string keyGeometry = "Geometry"; + const std::string keyRadius = "Radius"; + const std::string keyShading = "PerformShading"; + const std::string keyShadowGroup = "Shadow_Group"; + const std::string keyShadowSource = "Source"; + const std::string keyShadowCaster = "Caster"; + const std::string keyAtmosphere = "Atmosphere"; + const std::string keyAtmosphereRadius = "AtmoshereRadius"; + const std::string keyPlanetRadius = "PlanetRadius"; const std::string keyAverageGroundReflectance = "PlanetAverageGroundReflectance"; - const std::string keyRayleigh = "Rayleigh"; - const std::string keyRayleighHeightScale = "H_R"; - const std::string keyMie = "Mie"; - const std::string keyMieHeightScale = "H_M"; - const std::string keyMiePhaseConstant = "G"; - const std::string keyBody = "Body"; + const std::string keyRayleigh = "Rayleigh"; + const std::string keyRayleighHeightScale = "H_R"; + const std::string keyMie = "Mie"; + const std::string keyMieHeightScale = "H_M"; + const std::string keyMiePhaseConstant = "G"; + const std::string keyBody = "Body"; } namespace openspace { @@ -125,25 +125,46 @@ namespace openspace { { std::string name; bool success = dictionary.getValue(SceneGraphNode::KeyName, name); - ghoul_assert(success, - "RenderablePlanetAtmosphere need the '" + SceneGraphNode::KeyName + "' be specified"); + ghoul_assert( + success, + std::string("RenderablePlanetAtmosphere need the '") + SceneGraphNode::KeyName + + "' be specified" + ); //======================================================= //======== Reads Geometry Entries in mod file ============= //======================================================= ghoul::Dictionary geometryDictionary; success = dictionary.getValue(keyGeometry, geometryDictionary); + glm::dvec3 radius; + bool accutareRadius = false; + try { + SpiceManager::ref().getValue(name, "RADII", radius); + accutareRadius = true; + } + catch (const SpiceManager::SpiceException& e) { + accutareRadius = false; + } + + if (accutareRadius) { + radius *= 1000.0; // Spice gives radii in KM. + std::swap(radius[1], radius[2]); // z is equivalent to y in our coordinate system + geometryDictionary.setValue(keyRadius, radius); + } + if (success) { - geometryDictionary.setValue(SceneGraphNode::KeyName, name); - //geometryDictionary.setValue(constants::scenegraph::keyPathModule, path); _geometry = planetgeometry::PlanetGeometry::createFromDictionary(geometryDictionary); - glm::vec2 planetRadiusVec; - success = geometryDictionary.getValue(keyRadius, planetRadiusVec); - if (success) - _planetRadius = planetRadiusVec[0] * glm::pow(10, planetRadiusVec[1]); - else - LWARNING("No Radius value expecified for " << name << " planet."); + float planetRadius; + if (accutareRadius) { + _planetRadius = (radius[0] + radius[1] + radius[2]) / 3.0; + } + else if (geometryDictionary.getValue(keyRadius, planetRadius)) { + _planetRadius = planetRadius; + } + else { + LWARNING("No Radius value specified for " << name << " planet."); + } } //=============================================================== @@ -223,13 +244,13 @@ namespace openspace { ss << keyShadowSource << sourceCounter << ".Name"; success = shadowDictionary.getValue(ss.str(), sourceName); if (success) { - glm::vec2 sourceRadius; + float sourceRadius; ss.str(std::string()); ss << keyShadowSource << sourceCounter << ".Radius"; success = shadowDictionary.getValue(ss.str(), sourceRadius); if (success) { sourceArray.push_back(std::pair< std::string, float>( - sourceName, sourceRadius[0] * pow(10.f, sourceRadius[1]))); + sourceName, sourceRadius)); } else { LWARNING("No Radius value expecified for Shadow Source Name " @@ -252,13 +273,13 @@ namespace openspace { ss << keyShadowCaster << casterCounter << ".Name"; success = shadowDictionary.getValue(ss.str(), casterName); if (success) { - glm::vec2 casterRadius; + float casterRadius; ss.str(std::string()); ss << keyShadowCaster << casterCounter << ".Radius"; success = shadowDictionary.getValue(ss.str(), casterRadius); if (success) { casterArray.push_back(std::pair< std::string, float>( - casterName, casterRadius[0] * pow(10.f, casterRadius[1]))); + casterName, casterRadius)); } else { LWARNING("No Radius value expecified for Shadow Caster Name " @@ -448,7 +469,6 @@ namespace openspace { "shadowNightProgram", "${MODULE_ATMOSPHERE}/shaders/shadow_nighttexture_vs.glsl", "${MODULE_ATMOSPHERE}/shaders/shadow_nighttexture_fs.glsl"); - std::cout << "Building shadow night..." << std::endl; if (!_programObject) return false; } @@ -458,7 +478,6 @@ namespace openspace { "shadowProgram", "${MODULE_ATMOSPHERE}/shaders/shadow_vs.glsl", "${MODULE_ATMOSPHERE}/shaders/shadow_fs.glsl"); - std::cout << "Building shadow..." << std::endl; if (!_programObject) return false; } @@ -468,7 +487,6 @@ namespace openspace { "nightTextureProgram", "${MODULE_ATMOSPHERE}/shaders/nighttexture_vs.glsl", "${MODULE_ATMOSPHERE}/shaders/nighttexture_fs.glsl"); - std::cout << "Building night..." << std::endl; if (!_programObject) return false; } @@ -478,7 +496,6 @@ namespace openspace { "pscstandard", "${MODULE_ATMOSPHERE}/shaders/renderableplanet_vs.glsl", "${MODULE_ATMOSPHERE}/shaders/renderableplanet_fs.glsl"); - std::cout << "Building renderableplanet..." << std::endl; if (!_programObject) return false; } @@ -491,6 +508,15 @@ namespace openspace { LERROR("Error after loading shading programs. OpenGL error: " << errString); } + + //======================================================================== + //======== Initialize the current geometry (SimpleSphereGeometry) ======== + //======================================================================== + _geometry->initialize(this); + + // Deactivate any previously activated shader program. + _programObject->deactivate(); + //=================================================================== //=========== Load textures defined in mod file to GPU ============== //=================================================================== @@ -501,14 +527,6 @@ namespace openspace { LERROR("Error loading textures. OpenGL error: " << errString); } - //======================================================================== - //======== Initialize the current geometry (SimpleSphereGeometry) ======== - //======================================================================== - _geometry->initialize(this); - - // Deactivate any previously activated shader program. - _programObject->deactivate(); - // Testing Deferredcaster _deferredcaster = std::make_unique(); if (_deferredcaster) { @@ -615,10 +633,6 @@ namespace openspace { } void RenderablePlanetAtmosphere::render(const RenderData& data, RendererTasks& tasks) { - - GLint defaultFBO; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); - // activate shader _programObject->activate(); @@ -629,20 +643,20 @@ namespace openspace { computeModelTransformMatrix(&transform); // setup the data to the shader - double lt; - glm::dvec3 sunPosFromPlanet = - SpiceManager::ref().targetPosition("SUN", _target, "GALACTIC", {}, _time, lt); - sunPosFromPlanet *= 1000.0; // from Km to m - psc sunPosFromPlanetPSC = PowerScaledCoordinate::CreatePowerScaledCoordinate( - sunPosFromPlanet.x, sunPosFromPlanet.y, sunPosFromPlanet.z); + // double lt; + // glm::dvec3 sunPosFromPlanet = + // SpiceManager::ref().targetPosition("SUN", _target, "GALACTIC", {}, _time, lt); + // sunPosFromPlanet *= 1000.0; // from Km to m + // psc sunPosFromPlanetPSC = PowerScaledCoordinate::CreatePowerScaledCoordinate( + // sunPosFromPlanet.x, sunPosFromPlanet.y, sunPosFromPlanet.z); - glm::dvec3 planetPosFromSun = - SpiceManager::ref().targetPosition(_target, "SUN", "GALACTIC", {}, _time, lt); - psc planetPosFronSunPSC = PowerScaledCoordinate::CreatePowerScaledCoordinate( - planetPosFromSun.x, planetPosFromSun.y, planetPosFromSun.z); + // glm::dvec3 planetPosFromSun = + // SpiceManager::ref().targetPosition(_target, "SUN", "GALACTIC", {}, _time, lt); + // psc planetPosFronSunPSC = PowerScaledCoordinate::CreatePowerScaledCoordinate( + // planetPosFromSun.x, planetPosFromSun.y, planetPosFromSun.z); - // Camera direction (vector) - glm::vec3 cam_dir = glm::normalize(data.camera.position().vec3() - planetPosFronSunPSC.vec3()); + // // Camera direction (vector) + // glm::vec3 cam_dir = glm::normalize(data.camera.position().vec3() - planetPosFronSunPSC.vec3()); _programObject->setUniform("transparency", _alpha); _programObject->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); @@ -698,6 +712,7 @@ namespace openspace { //============= Eclipse Shadow Calculations and Uniforms Loading ============== //============================================================================= // TODO: Move Calculations to VIEW SPACE (let's avoid precision problems...) + double lt; if (!_shadowConfArray.empty()) { std::vector shadowDataArray; shadowDataArray.reserve(_shadowConfArray.size()); @@ -768,7 +783,7 @@ namespace openspace { } counter++; } - } + } // render _geometry->render(); @@ -784,7 +799,8 @@ namespace openspace { void RenderablePlanetAtmosphere::update(const UpdateData& data) { // set spice-orientation in accordance to timestamp - _stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, "GALACTIC", data.time); + //_stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, "GALACTIC", data.time); + _stateMatrix = data.modelTransform.rotation; _time = data.time; if (_programObject && _programObject->isDirty()) @@ -795,7 +811,7 @@ namespace openspace { glm::dmat4 modelTransform; computeModelTransformMatrix(&modelTransform); _deferredcaster->setModelTransform(modelTransform); - } + } } void RenderablePlanetAtmosphere::loadTexture() { @@ -857,17 +873,17 @@ namespace openspace { } void RenderablePlanetAtmosphere::updateAtmosphereParameters() { - _atmosphereRadius = _atmospherePlanetRadius + _atmosphereHeightP; + _atmosphereRadius = _atmospherePlanetRadius + _atmosphereHeightP; _planetAverageGroundReflectance = _groundAverageReflectanceP; - _rayleighHeightScale = _rayleighHeightScaleP; - _rayleighScatteringCoeff = glm::vec3(_rayleighScatteringCoeffXP * 0.001f, _rayleighScatteringCoeffYP * 0.001f, - _rayleighScatteringCoeffZP * 0.001f); - _mieHeightScale = _mieHeightScaleP; - _mieScatteringCoeff = glm::vec3(_mieScatteringCoefficientP * 0.001f); - _mieExtinctionCoeff = _mieScatteringCoeff * (1.0f / static_cast(_mieScatteringExtinctionPropCoefficientP)); - _miePhaseConstant = _mieAsymmetricFactorGP; - _sunRadianceIntensity = _sunIntensityP; - _hdrConstant = _hdrExpositionP; + _rayleighHeightScale = _rayleighHeightScaleP; + _rayleighScatteringCoeff = glm::vec3(_rayleighScatteringCoeffXP * 0.001f, _rayleighScatteringCoeffYP * 0.001f, + _rayleighScatteringCoeffZP * 0.001f); + _mieHeightScale = _mieHeightScaleP; + _mieScatteringCoeff = glm::vec3(_mieScatteringCoefficientP * 0.001f); + _mieExtinctionCoeff = _mieScatteringCoeff * (1.0f / static_cast(_mieScatteringExtinctionPropCoefficientP)); + _miePhaseConstant = _mieAsymmetricFactorGP; + _sunRadianceIntensity = _sunIntensityP; + _hdrConstant = _hdrExpositionP; if (_deferredcaster) { _deferredcaster->setAtmosphereRadius(_atmosphereRadius); diff --git a/modules/base/rendering/modelgeometry.cpp b/modules/base/rendering/modelgeometry.cpp index 82e3ee0074..b74f44bd59 100644 --- a/modules/base/rendering/modelgeometry.cpp +++ b/modules/base/rendering/modelgeometry.cpp @@ -144,7 +144,7 @@ bool ModelGeometry::initialize(Renderable* parent) { glm::pow(v.location[1], 2.f) + glm::pow(v.location[2], 2.f), maximumDistanceSquared); } - _parent->setBoundingSphere(PowerScaledScalar(glm::sqrt(maximumDistanceSquared), 0.0)); + _parent->setBoundingSphere(glm::sqrt(maximumDistanceSquared)); if (_vertices.empty()) return false; @@ -287,8 +287,7 @@ bool ModelGeometry::getIndices(std::vector* indexList) { return !(indexList->empty()); } -void ModelGeometry::setUniforms(ghoul::opengl::ProgramObject& program) { -} +void ModelGeometry::setUniforms(ghoul::opengl::ProgramObject&) {} } // namespace modelgeometry } // namespace openspace diff --git a/modules/base/rendering/multimodelgeometry.cpp b/modules/base/rendering/multimodelgeometry.cpp index 49e5b77e43..5428bd5724 100644 --- a/modules/base/rendering/multimodelgeometry.cpp +++ b/modules/base/rendering/multimodelgeometry.cpp @@ -62,12 +62,6 @@ bool MultiModelGeometry::loadModel(const std::string& filename) { _vertices.reserve(vertices.size()); for (const auto & v : vertices) { - psc p = PowerScaledCoordinate::CreatePowerScaledCoordinate( - v.location[0], - v.location[1], - v.location[2] - ); - Vertex vv; memcpy(vv.location, v.location, sizeof(GLfloat) * 3); vv.location[3] = 1.0; diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index 8fce14dc90..2f92b51d79 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -221,8 +221,9 @@ void RenderableModel::render(const RenderData& data) { } void RenderableModel::update(const UpdateData& data) { - if (_programObject->isDirty()) + if (_programObject->isDirty()) { _programObject->rebuildFromFile(); + } // double _time = data.time; //if (_isGhost){ @@ -247,7 +248,7 @@ void RenderableModel::update(const UpdateData& data) { void RenderableModel::loadTexture() { _texture = nullptr; if (_colorTexturePath.value() != "") { - _texture = std::move(ghoul::io::TextureReader::ref().loadTexture(absPath(_colorTexturePath))); + _texture = ghoul::io::TextureReader::ref().loadTexture(absPath(_colorTexturePath)); if (_texture) { LDEBUG("Loaded texture from '" << absPath(_colorTexturePath) << "'"); _texture->uploadTexture(); diff --git a/modules/base/rendering/renderableplane.cpp b/modules/base/rendering/renderableplane.cpp index 965ffd0307..25e80ffd59 100644 --- a/modules/base/rendering/renderableplane.cpp +++ b/modules/base/rendering/renderableplane.cpp @@ -55,7 +55,7 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) , _texturePath("texture", "Texture") , _billboard("billboard", "Billboard", false) , _projectionListener("projectionListener", "DisplayProjections", false) - , _size("size", "Size", glm::vec2(1,1), glm::vec2(0.f), glm::vec2(1.f, 25.f)) + , _size("size", "Size", 10, 0, std::pow(10, 25)) , _origin(Origin::Center) , _shader(nullptr) , _textureIsDirty(false) @@ -64,9 +64,7 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) , _quad(0) , _vertexPositionBuffer(0) { - glm::vec2 size; - dictionary.getValue("Size", size); - _size = size; + dictionary.getValue("Size", _size); if (dictionary.hasKey("Name")) { dictionary.getValue("Name", _nodeName); @@ -127,7 +125,7 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) //_size.onChange(std::bind(&RenderablePlane::createPlane, this)); _size.onChange([this](){ _planeIsDirty = true; }); - setBoundingSphere(_size.value()); + setBoundingSphere(_size); } RenderablePlane::~RenderablePlane() { @@ -263,7 +261,7 @@ void RenderablePlane::render(const RenderData& data) { _shader->deactivate(); } -void RenderablePlane::update(const UpdateData& data) { +void RenderablePlane::update(const UpdateData&) { if (_shader->isDirty()) _shader->rebuildFromFile(); @@ -299,16 +297,15 @@ void RenderablePlane::createPlane() { // ============================ // GEOMETRY (quad) // ============================ - const GLfloat size = _size.value()[0]; - const GLfloat w = _size.value()[1]; + const GLfloat size = _size; const GLfloat vertex_data[] = { // x y z w s t - -size, -size, 0.f, w, 0.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, - -size, size, 0.f, w, 0.f, 1.f, - -size, -size, 0.f, w, 0.f, 0.f, - size, -size, 0.f, w, 1.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, + -size, -size, 0.f, 0.f, 0.f, 0.f, + size, size, 0.f, 0.f, 1.f, 1.f, + -size, size, 0.f, 0.f, 0.f, 1.f, + -size, -size, 0.f, 0.f, 0.f, 0.f, + size, -size, 0.f, 0.f, 1.f, 0.f, + size, size, 0.f, 0.f, 1.f, 1.f, }; glBindVertexArray(_quad); // bind array diff --git a/modules/base/rendering/renderableplane.h b/modules/base/rendering/renderableplane.h index 3c26807882..a14e340f9e 100644 --- a/modules/base/rendering/renderableplane.h +++ b/modules/base/rendering/renderableplane.h @@ -29,7 +29,6 @@ #include #include -#include #include namespace ghoul { @@ -75,7 +74,7 @@ private: properties::StringProperty _texturePath; properties::BoolProperty _billboard; properties::BoolProperty _projectionListener; - properties::Vec2Property _size; + properties::FloatProperty _size; Origin _origin; std::string _nodeName; diff --git a/modules/base/rendering/renderablesphere.cpp b/modules/base/rendering/renderablesphere.cpp index 5453db84c6..3383aa594b 100644 --- a/modules/base/rendering/renderablesphere.cpp +++ b/modules/base/rendering/renderablesphere.cpp @@ -178,7 +178,7 @@ void RenderableSphere::render(const RenderData& data) { _shader->deactivate(); } -void RenderableSphere::update(const UpdateData& data) { +void RenderableSphere::update(const UpdateData&) { if (_shader->isDirty()) _shader->rebuildFromFile(); diff --git a/modules/base/rendering/renderablesphericalgrid.cpp b/modules/base/rendering/renderablesphericalgrid.cpp index da602a2c5f..7a3ad7d2e6 100644 --- a/modules/base/rendering/renderablesphericalgrid.cpp +++ b/modules/base/rendering/renderablesphericalgrid.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #define _USE_MATH_DEFINES #include @@ -39,12 +40,10 @@ namespace { const char* KeyGridSegments = "GridSegments"; const char* KeyGridRadius = "GridRadius"; const char* KeyGridParentsRotation = "ParentsRotation"; + const glm::vec2 GridRadius = { 1.f, 20.f }; } namespace openspace { -// needs to be set from dictionary - REMEMBER -const PowerScaledScalar radius = PowerScaledScalar(1.f, 20.f); - RenderableSphericalGrid::RenderableSphericalGrid(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _gridProgram(nullptr) @@ -78,7 +77,7 @@ RenderableSphericalGrid::RenderableSphericalGrid(const ghoul::Dictionary& dictio int nr = 0; const float fsegments = static_cast(_segments); - const float r = static_cast(radius[0]); + const float r = static_cast(GridRadius[0]); //int nr2 = 0; @@ -117,7 +116,7 @@ RenderableSphericalGrid::RenderableSphericalGrid(const ghoul::Dictionary& dictio _varray[nr].location[i] = tmp[i]; _varray[nr].normal[i] = normal[i]; } - _varray[nr].location[3] = static_cast(radius[1]); + _varray[nr].location[3] = static_cast(GridRadius[1]); ++nr; } } diff --git a/modules/base/rendering/renderablesphericalgrid.h b/modules/base/rendering/renderablesphericalgrid.h index 1980018c48..f5290bc1d5 100644 --- a/modules/base/rendering/renderablesphericalgrid.h +++ b/modules/base/rendering/renderablesphericalgrid.h @@ -62,7 +62,6 @@ protected: bool staticGrid; std::string _parentsRotation; glm::dmat3 _parentMatrix; - PowerScaledScalar _radius; GLuint _vaoID = 3; GLuint _vBufferID = 4; diff --git a/modules/base/rendering/renderabletrailorbit.cpp b/modules/base/rendering/renderabletrailorbit.cpp index 90f5551b14..2f21fd320a 100644 --- a/modules/base/rendering/renderabletrailorbit.cpp +++ b/modules/base/rendering/renderabletrailorbit.cpp @@ -337,14 +337,14 @@ RenderableTrailOrbit::UpdateReport RenderableTrailOrbit::updateTrails( // This might become a bigger issue if we are starting to look at very short time // intervals const double Epsilon = 1e-7; - if (abs(delta) < Epsilon) { + if (std::abs(delta) < Epsilon) { return { false, 0 }; } if (delta > 0.0) { // Check whether we need to drop a new permanent point. This is only the case if // enough (> secondsPerPoint) time has passed since the last permanent point - if (abs(delta) < secondsPerPoint) { + if (std::abs(delta) < secondsPerPoint) { return { false, 0 }; } diff --git a/modules/base/rendering/screenspaceimage.cpp b/modules/base/rendering/screenspaceimage.cpp index 3839cbe352..6b2e4e44bb 100644 --- a/modules/base/rendering/screenspaceimage.cpp +++ b/modules/base/rendering/screenspaceimage.cpp @@ -33,8 +33,6 @@ #include namespace { - const std::string _loggerCat = "ScreenSpaceImage"; - const char* KeyName = "Name"; const char* KeyTexturePath = "TexturePath"; const char* KeyUrl = "URL"; @@ -44,8 +42,9 @@ namespace openspace { ScreenSpaceImage::ScreenSpaceImage(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) - , _texturePath("texturePath", "Texture path", "") , _downloadImage(false) + , _textureIsDirty(false) + , _texturePath("texturePath", "Texture path", "") { std::string name; if (dictionary.getValue(KeyName, name)) { @@ -61,7 +60,7 @@ ScreenSpaceImage::ScreenSpaceImage(const ghoul::Dictionary& dictionary) std::string texturePath; if (dictionary.getValue(KeyTexturePath, texturePath)) { _texturePath = texturePath; - _texturePath.onChange([this](){ loadTexture(); }); + _texturePath.onChange([this]() { _textureIsDirty = true; }); } if (dictionary.getValue(KeyUrl, _url)) { @@ -82,7 +81,6 @@ bool ScreenSpaceImage::initialize() { } bool ScreenSpaceImage::deinitialize() { - glDeleteVertexArrays(1, &_quad); _quad = 0; @@ -106,7 +104,7 @@ void ScreenSpaceImage::render() { void ScreenSpaceImage::update() { bool download = _downloadImage ? (_futureImage.valid() && DownloadManager::futureReady(_futureImage)) : true; - if (download) { + if (download && _textureIsDirty) { loadTexture(); } } @@ -118,9 +116,9 @@ bool ScreenSpaceImage::isReady() const { void ScreenSpaceImage::loadTexture() { std::unique_ptr texture = nullptr; if (!_downloadImage) - texture = std::move(loadFromDisk()); + texture = loadFromDisk(); else - texture = std::move(loadFromMemory()); + texture = loadFromMemory(); if (texture) { // LDEBUG("Loaded texture from '" << absPath(_texturePath) << "'"); @@ -130,6 +128,7 @@ void ScreenSpaceImage::loadTexture() { texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); _texture = std::move(texture); + _textureIsDirty = false; } } @@ -175,15 +174,21 @@ void ScreenSpaceImage::updateTexture() { std::future ScreenSpaceImage::downloadImageToMemory( std::string url) { - return std::move(OsEng.downloadManager().fetchFile( + return OsEng.downloadManager().fetchFile( url, - [url](const DownloadManager::MemoryFile& file) { - LDEBUG("Download to memory finished for screen space image"); + [url](const DownloadManager::MemoryFile&) { + LDEBUGC( + "ScreenSpaceImage", + "Download to memory finished for screen space image" + ); }, [url](const std::string& err) { - LDEBUG("Download to memory failer for screen space image: " +err); + LDEBUGC( + "ScreenSpaceImage", + "Download to memory failer for screen space image: " + err + ); } - )); + ); } } // namespace openspace diff --git a/modules/base/rendering/screenspaceimage.h b/modules/base/rendering/screenspaceimage.h index 7316722608..4788e6df72 100644 --- a/modules/base/rendering/screenspaceimage.h +++ b/modules/base/rendering/screenspaceimage.h @@ -51,6 +51,7 @@ protected: std::string _url; bool _downloadImage; + bool _textureIsDirty; std::future _futureImage; private: @@ -59,6 +60,8 @@ private: std::unique_ptr loadFromMemory(); properties::StringProperty _texturePath; + + }; } // namespace openspace diff --git a/modules/base/scale/staticscale.cpp b/modules/base/scale/staticscale.cpp index dd7f16167d..5e53730ea8 100644 --- a/modules/base/scale/staticscale.cpp +++ b/modules/base/scale/staticscale.cpp @@ -28,7 +28,6 @@ #include namespace { - const char* _loggerCat = "StaticScale"; const char* KeyValue = "Scale"; } diff --git a/modules/base/shaders/screenspace_fs.glsl b/modules/base/shaders/screenspace_fs.glsl index 11aae2042f..22b09a4987 100644 --- a/modules/base/shaders/screenspace_fs.glsl +++ b/modules/base/shaders/screenspace_fs.glsl @@ -22,8 +22,6 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#version __CONTEXT__ - uniform sampler2D texture1; uniform float OcclusionDepth; uniform float Alpha; diff --git a/modules/base/translation/statictranslation.cpp b/modules/base/translation/statictranslation.cpp index ead533d1c8..069c64e10e 100644 --- a/modules/base/translation/statictranslation.cpp +++ b/modules/base/translation/statictranslation.cpp @@ -82,8 +82,6 @@ StaticTranslation::StaticTranslation(const ghoul::Dictionary& dictionary) _position = dictionary.value(KeyPosition); } -StaticTranslation::~StaticTranslation() {} - glm::dvec3 StaticTranslation::position() const { return _position; } diff --git a/modules/base/translation/statictranslation.h b/modules/base/translation/statictranslation.h index 665e89f123..fd92a76645 100644 --- a/modules/base/translation/statictranslation.h +++ b/modules/base/translation/statictranslation.h @@ -37,7 +37,6 @@ class StaticTranslation : public Translation { public: StaticTranslation(); StaticTranslation(const ghoul::Dictionary& dictionary); - virtual ~StaticTranslation(); virtual glm::dvec3 position() const; virtual void update(const UpdateData& data) override; diff --git a/modules/debugging/rendering/debugrenderer.cpp b/modules/debugging/rendering/debugrenderer.cpp index 3f028ecb6a..a84a0ff170 100644 --- a/modules/debugging/rendering/debugrenderer.cpp +++ b/modules/debugging/rendering/debugrenderer.cpp @@ -111,7 +111,7 @@ void DebugRenderer::renderVertices(const Vertices& clippingSpacePoints, GLenum m glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(clippingSpacePoints[0]), 0); // Draw the vertices - glDrawArrays(mode, 0, clippingSpacePoints.size()); + glDrawArrays(mode, 0, static_cast(clippingSpacePoints.size())); // Check for errors GLenum error = glGetError(); @@ -200,7 +200,7 @@ void DebugRenderer::renderCameraFrustum(const RenderData& data, const Camera& ot RGBA rgba) const { using namespace glm; - dmat4 modelTransform = translate(dmat4(1), data.position.dvec3()); +// dmat4 modelTransform = translate(dmat4(1), data.position.dvec3()); dmat4 viewTransform = dmat4(data.camera.combinedViewMatrix()); dmat4 vp = dmat4(data.camera.projectionMatrix()) * viewTransform; @@ -266,7 +266,7 @@ const DebugRenderer::Vertices DebugRenderer::verticesFor( vertices[i] = glm::vec4(x, y, z, 1); } - return std::move(vertices); + return vertices; } #endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED diff --git a/modules/debugging/rendering/renderabledebugplane.cpp b/modules/debugging/rendering/renderabledebugplane.cpp index e40dd68cd5..53278c1c42 100644 --- a/modules/debugging/rendering/renderabledebugplane.cpp +++ b/modules/debugging/rendering/renderabledebugplane.cpp @@ -49,15 +49,13 @@ RenderableDebugPlane::RenderableDebugPlane(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _texture("texture", "Texture", -1, -1, 255) , _billboard("billboard", "Billboard", false) - , _size("size", "Size", glm::vec2(1,1), glm::vec2(0.f), glm::vec2(1.f, 25.f)) + , _size("size", "Size", 10, 0, std::pow(10, 25)) , _origin(Origin::Center) , _shader(nullptr) , _quad(0) , _vertexPositionBuffer(0) { - glm::vec2 size; - dictionary.getValue("Size", size); - _size = size; + dictionary.getValue("Size", _size); if (dictionary.hasKey("Name")){ dictionary.getValue("Name", _nodeName); @@ -104,7 +102,7 @@ RenderableDebugPlane::RenderableDebugPlane(const ghoul::Dictionary& dictionary) addProperty(_size); _size.onChange([this](){ _planeIsDirty = true; }); - setBoundingSphere(_size.value()); + setBoundingSphere(_size); } RenderableDebugPlane::~RenderableDebugPlane() { @@ -189,16 +187,16 @@ void RenderableDebugPlane::createPlane() { // ============================ // GEOMETRY (quad) // ============================ - const GLfloat size = _size.value()[0]; - const GLfloat w = _size.value()[1]; + const GLfloat size = _size; + const GLfloat vertex_data[] = { // x y z w s t - -size, -size, 0.f, w, 0.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, - -size, size, 0.f, w, 0.f, 1.f, - -size, -size, 0.f, w, 0.f, 0.f, - size, -size, 0.f, w, 1.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, + -size, -size, 0.f, 0.f, 0.f, 0.f, + size, size, 0.f, 0.f, 1.f, 1.f, + -size, size, 0.f, 0.f, 0.f, 1.f, + -size, -size, 0.f, 0.f, 0.f, 0.f, + size, -size, 0.f, 0.f, 1.f, 0.f, + size, size, 0.f, 0.f, 1.f, 1.f, }; glBindVertexArray(_quad); // bind array diff --git a/modules/debugging/rendering/renderabledebugplane.h b/modules/debugging/rendering/renderabledebugplane.h index 96df652354..b007cef5dd 100644 --- a/modules/debugging/rendering/renderabledebugplane.h +++ b/modules/debugging/rendering/renderabledebugplane.h @@ -28,7 +28,6 @@ #include #include -#include #include namespace ghoul { @@ -67,7 +66,7 @@ private: properties::IntProperty _texture; properties::BoolProperty _billboard; - properties::Vec2Property _size; + properties::FloatProperty _size; Origin _origin; std::string _nodeName; diff --git a/modules/fieldlines/rendering/renderablefieldlines.cpp b/modules/fieldlines/rendering/renderablefieldlines.cpp index 1d855b278a..060701141a 100644 --- a/modules/fieldlines/rendering/renderablefieldlines.cpp +++ b/modules/fieldlines/rendering/renderablefieldlines.cpp @@ -121,7 +121,7 @@ RenderableFieldlines::RenderableFieldlines(const ghoul::Dictionary& dictionary) } // @TODO a non-magic number perhaps ---abock - setBoundingSphere(PowerScaledScalar::CreatePSS(250.f*6371000.f)); + setBoundingSphere(250.f*6371000.f); _seedPointSource.addOption(SeedPointSourceFile, "File"); _seedPointSource.addOption(SeedPointSourceTable, "Lua Table"); diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index 08ab6695c5..beb70af6ec 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -25,6 +25,13 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/cache/lrucache.h + ${CMAKE_CURRENT_SOURCE_DIR}/cache/lrucache.inl + ${CMAKE_CURRENT_SOURCE_DIR}/cache/memoryawarecacheable.h + ${CMAKE_CURRENT_SOURCE_DIR}/cache/memoryawarelrucache.h + ${CMAKE_CURRENT_SOURCE_DIR}/cache/memoryawarelrucache.inl + ${CMAKE_CURRENT_SOURCE_DIR}/cache/memoryawaretilecache.h + ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunk.h ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunknode.h ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunklevelevaluator/chunklevelevaluator.h @@ -57,8 +64,6 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/other/concurrentqueue.h ${CMAKE_CURRENT_SOURCE_DIR}/other/concurrentqueue.inl ${CMAKE_CURRENT_SOURCE_DIR}/other/distanceswitch.h - ${CMAKE_CURRENT_SOURCE_DIR}/other/lrucache.h - ${CMAKE_CURRENT_SOURCE_DIR}/other/lrucache.inl ${CMAKE_CURRENT_SOURCE_DIR}/other/statscollector.h ${CMAKE_CURRENT_SOURCE_DIR}/other/statscollector.inl ${CMAKE_CURRENT_SOURCE_DIR}/other/threadpool.h @@ -79,15 +84,13 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layermanager.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layerrendersettings.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/asynctilereader.h + ${CMAKE_CURRENT_SOURCE_DIR}/tile/asynctiledataprovider.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/chunktile.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/pixelregion.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtile.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/textureformat.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tile.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tiledatalayout.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tiledataset.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tiledatatype.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tiledepthtransform.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tilediskcache.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileindex.h @@ -98,6 +101,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tile/loadjob/loadjob.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/loadjob/tileloadjob.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/cachingtileprovider.h + ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/presentationslideprovider.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/singleimageprovider.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/sizereferencetileprovider.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/temporaltileprovider.h @@ -106,19 +110,26 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileprovider.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbyindex.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbylevel.h + + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/rawtiledatareader.h + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/gdalrawtiledatareader.h + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/simplerawtiledatareader.h + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/gdalwrapper.h + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/iodescription.h + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/tiledatatype.h ) set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/cache/memoryawaretilecache.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunk.cpp ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunknode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunklevelevaluator/availabletiledataevaluator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunklevelevaluator/distanceevaluator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunklevelevaluator/projectedareaevaluator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/chunk/culling/frustumculler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/chunk/culling/horizonculler.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/aabb.cpp ${CMAKE_CURRENT_SOURCE_DIR}/geometry/ellipsoid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/geometry/geodetic2.cpp @@ -153,13 +164,11 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layermanager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layerrendersettings.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/asynctilereader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tile/asynctiledataprovider.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/pixelregion.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tile/tile.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tiledatalayout.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tiledataset.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tiledatatype.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tilediskcache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileindex.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tilemetadata.cpp @@ -167,6 +176,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tile/loadjob/diskcachedtileloadjob.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/loadjob/tileloadjob.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/cachingtileprovider.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/presentationslideprovider.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/singleimageprovider.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/sizereferencetileprovider.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/temporaltileprovider.cpp @@ -175,6 +185,13 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileprovider.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbyindex.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileproviderbylevel.cpp + + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/rawtiledatareader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/gdalrawtiledatareader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/simplerawtiledatareader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/gdalwrapper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/iodescription.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tile/rawtiledatareader/tiledatatype.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) @@ -201,31 +218,34 @@ create_new_module( ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} ) -if (WIN32) - target_include_directories( - openspace-module-globebrowsing - SYSTEM PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/include - ) +option(OPENSPACE_MODULE_GLOBEBROWSING_USE_GDAL "Use GDAL" ON) - target_link_libraries( - openspace-module-globebrowsing - ${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/lib/gdal_i.lib - ) +if (OPENSPACE_MODULE_GLOBEBROWSING_USE_GDAL) + if (WIN32) + target_include_directories( + openspace-module-globebrowsing + SYSTEM PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/include + ) - set(EXTERNAL_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/lib/gdal201.dll" PARENT_SCOPE) + target_link_libraries( + openspace-module-globebrowsing + ${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/lib/gdal_i.lib + ) + set(EXTERNAL_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/lib/gdal201.dll" PARENT_SCOPE) + else (WIN32) + find_package(GDAL REQUIRED) -else (WIN32) - find_package(GDAL REQUIRED) + target_include_directories( + openspace-module-globebrowsing + SYSTEM PUBLIC + ${GDAL_INCLUDE_DIR} + ) - target_include_directories( - openspace-module-globebrowsing - SYSTEM PUBLIC - ${GDAL_INCLUDE_DIR} - ) - - target_link_libraries( - openspace-module-globebrowsing - ${GDAL_LIBRARY} - ) -endif () + target_link_libraries( + openspace-module-globebrowsing + ${GDAL_LIBRARY} + ) + endif () # WIN32 + target_compile_definitions(openspace-module-globebrowsing PRIVATE GLOBEBROWSING_USE_GDAL) +endif () # OPENSPACE_MODULE_GLOBEBROWSING_USE_GDAL diff --git a/modules/globebrowsing/other/lrucache.h b/modules/globebrowsing/cache/lrucache.h similarity index 90% rename from modules/globebrowsing/other/lrucache.h rename to modules/globebrowsing/cache/lrucache.h index d410ab4985..4857761995 100644 --- a/modules/globebrowsing/other/lrucache.h +++ b/modules/globebrowsing/cache/lrucache.h @@ -30,11 +30,18 @@ namespace openspace { namespace globebrowsing { +namespace cache { -// Templated class implementing a Least-Recently-Used Cache +/** + * Templated class implementing a Least-Recently-Used Cache. + * KeyType needs to be an enumerable type. + */ template class LRUCache { public: + /** + * \param size is the maximum size of the cache given in number of cached items. + */ LRUCache(size_t size); void put(const KeyType& key, const ValueType& value); @@ -51,9 +58,10 @@ private: size_t _cacheSize; }; +} // namespace cache } // namespace globebrowsing } // namespace openspace -#include +#include #endif // __OPENSPACE_MODULE_GLOBEBROWSING___LRU_CACHE___H__ diff --git a/modules/globebrowsing/other/lrucache.inl b/modules/globebrowsing/cache/lrucache.inl similarity index 99% rename from modules/globebrowsing/other/lrucache.inl rename to modules/globebrowsing/cache/lrucache.inl index 4aacc3132e..4bc88bca4f 100644 --- a/modules/globebrowsing/other/lrucache.inl +++ b/modules/globebrowsing/cache/lrucache.inl @@ -26,6 +26,7 @@ namespace openspace { namespace globebrowsing { +namespace cache { template LRUCache::LRUCache(size_t size) @@ -78,5 +79,6 @@ void LRUCache::clean() { } } +} // namespace cache } // namespace globebrowsing } // namespace openspace diff --git a/modules/globebrowsing/cache/memoryawarecacheable.h b/modules/globebrowsing/cache/memoryawarecacheable.h new file mode 100644 index 0000000000..ccd2c253c7 --- /dev/null +++ b/modules/globebrowsing/cache/memoryawarecacheable.h @@ -0,0 +1,58 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_GLOBEBROWSING___MEMORY_AWARE_CACHEABLE___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___MEMORY_AWARE_CACHEABLE___H__ + +namespace openspace { +namespace globebrowsing { +namespace cache { + +/** + * Base class to be extended by classes that need to be cached and make use of the + * memoryImpact interface. A class extending MemoryAwareCacheable needs to + * know its memory impact at initialization and hence provide the memory impact in its + * constructors. The memory impact can not change during the lifetime of an object that is + * a MemoryAwareCacheable. + */ +class MemoryAwareCacheable { +public: + /** + * \param memoryImpact is the memory impact of the object. Can for example be given + * in kilobytes. + */ + MemoryAwareCacheable(size_t memoryImpact) : _memoryImpact(memoryImpact) {}; + ~MemoryAwareCacheable() {}; + + size_t memoryImpact() { return _memoryImpact; }; + +protected: + size_t _memoryImpact; +}; + +} // namespace cache +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___MEMORY_AWARE_CACHEABLE___H__ diff --git a/modules/globebrowsing/cache/memoryawarelrucache.h b/modules/globebrowsing/cache/memoryawarelrucache.h new file mode 100644 index 0000000000..c4aaef71a7 --- /dev/null +++ b/modules/globebrowsing/cache/memoryawarelrucache.h @@ -0,0 +1,83 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_GLOBEBROWSING___MEMORY_AWARE_LRU_CACHE___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___MEMORY_AWARE_LRU_CACHE___H__ + +#include +#include + +namespace openspace { +namespace globebrowsing { +namespace cache { + +/** + * Least recently used cache that knows about its memory impact. This class is templated + * and the second template argument ValueType needs to have a function + * void memoryImpact() that returns the size of the object given in whatever + * unit is used for size in the creation of the MemoryAwareLRUCache. + * It can for example be given in kilobytes. + * KeyType needs to be a size comparable type. + */ + +template +class MemoryAwareLRUCache { +public: + /** + * \param maximumSize is the maximum size of the MemoryAwareLRUCache + * Once the maximum size is reached, the cache will start removing objects that were + * least recently used. The maximum size can for example be given in kilobytes. It + * must be the same size unit as used by the cached object class + * ValueType. + */ + MemoryAwareLRUCache(size_t maximumSize); + + void put(const KeyType& key, const ValueType& value); + void clear(); + bool exist(const KeyType& key) const; + ValueType get(const KeyType& key); + size_t size() const; + size_t maximumSize() const; + + void setMaximumSize(size_t maximumSize); + +private: + void clean(); + + using Item = std::pair; + using Items = std::list; + Items _itemList; + std::unordered_map _itemMap; + + size_t _cacheSize; + size_t _maximumCacheSize; +}; + +} // namespace cache +} // namespace globebrowsing +} // namespace openspace + +#include + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___MEMORY_AWARE_LRU_CACHE___H__ diff --git a/modules/globebrowsing/cache/memoryawarelrucache.inl b/modules/globebrowsing/cache/memoryawarelrucache.inl new file mode 100644 index 0000000000..28e0a1ec6e --- /dev/null +++ b/modules/globebrowsing/cache/memoryawarelrucache.inl @@ -0,0 +1,100 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { +namespace globebrowsing { +namespace cache { + +template +MemoryAwareLRUCache::MemoryAwareLRUCache(size_t maximumSize) + : _maximumCacheSize(maximumSize) + , _cacheSize(0) +{} + +template +void MemoryAwareLRUCache::clear() { + _itemList.clear(); + _itemMap.clear(); + _cacheSize = 0; +} + +template +void MemoryAwareLRUCache::put(const KeyType& key, const ValueType& value) { + auto it = _itemMap.find(key); + if (it != _itemMap.end()) { + _cacheSize -= it->second->second.memoryImpact(); + _itemList.erase(it->second); + _itemMap.erase(it); + } + _itemList.emplace_front(key, value); + _itemMap.emplace(key, _itemList.begin()); + _cacheSize += _itemList.begin()->second.memoryImpact(); + clean(); +} + +template +bool MemoryAwareLRUCache::exist(const KeyType& key) const { + return _itemMap.count(key) > 0; +} + +template +ValueType MemoryAwareLRUCache::get(const KeyType& key) { + //ghoul_assert(exist(key), "Key " << key << " must exist"); + auto it = _itemMap.at(key); + // Move list iterator pointing to value + _itemList.splice(_itemList.begin(), _itemList, it); + return it->second; +} + +template +size_t MemoryAwareLRUCache::size() const { + return _cacheSize; +} + +template +size_t MemoryAwareLRUCache::maximumSize() const { + return _maximumCacheSize; +} + +template +void MemoryAwareLRUCache::setMaximumSize(size_t maximumSize) { + _maximumCacheSize = maximumSize; +} + +template +void MemoryAwareLRUCache::clean() { + while (_cacheSize > _maximumCacheSize) { + auto last_it = _itemList.end(); + last_it--; + _itemMap.erase(last_it->first); + _cacheSize -= last_it->second.memoryImpact(); + _itemList.pop_back(); + } +} + +} // namespace cache +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/cache/memoryawaretilecache.cpp b/modules/globebrowsing/cache/memoryawaretilecache.cpp new file mode 100644 index 0000000000..e45daf6452 --- /dev/null +++ b/modules/globebrowsing/cache/memoryawaretilecache.cpp @@ -0,0 +1,84 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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 openspace { +namespace globebrowsing { +namespace cache { + +MemoryAwareTileCache* MemoryAwareTileCache::_singleton = nullptr; +std::mutex MemoryAwareTileCache::_mutexLock; + +void MemoryAwareTileCache::create(size_t cacheSize) { + std::lock_guard guard(_mutexLock); + _singleton = new MemoryAwareTileCache(cacheSize); +} + +void MemoryAwareTileCache::destroy() { + std::lock_guard guard(_mutexLock); + delete _singleton; +} + +MemoryAwareTileCache& MemoryAwareTileCache::ref() { + std::lock_guard guard(_mutexLock); + ghoul_assert(_singleton, "MemoryAwareTileCache not created"); + return *_singleton; +} + +void MemoryAwareTileCache::clear() { + std::lock_guard guard(_mutexLock); + _tileCache.clear(); +} + +bool MemoryAwareTileCache::exist(ProviderTileKey key) const { + std::lock_guard guard(_mutexLock); + return _tileCache.exist(key); +} + +Tile MemoryAwareTileCache::get(ProviderTileKey key) { + std::lock_guard guard(_mutexLock); + return _tileCache.get(key); +} + +void MemoryAwareTileCache::put(ProviderTileKey key, Tile tile) { + std::lock_guard guard(_mutexLock); + _tileCache.put(key, tile); +} + +void MemoryAwareTileCache::setMaximumSize(size_t maximumSize) { + std::lock_guard guard(_mutexLock); + _tileCache.setMaximumSize(maximumSize); +} + +MemoryAwareTileCache::MemoryAwareTileCache(size_t cacheSize) + : _tileCache(cacheSize) {} + +} // namespace cache +} // namespace globebrowsing +} // namespace openspace + diff --git a/modules/globebrowsing/cache/memoryawaretilecache.h b/modules/globebrowsing/cache/memoryawaretilecache.h new file mode 100644 index 0000000000..114be6f69b --- /dev/null +++ b/modules/globebrowsing/cache/memoryawaretilecache.h @@ -0,0 +1,113 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_GLOBEBROWSING___MEMORY_AWARE_TILE_CACHE___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___MEMORY_AWARE_TILE_CACHE___H__ + +#include +#include +#include + +#include +#include + +namespace openspace { +namespace globebrowsing { +namespace cache { + +struct ProviderTileKey { + TileIndex tileIndex; + unsigned int providerID; + + bool operator==(const ProviderTileKey& r) const { + return (providerID == r.providerID) && + (tileIndex == r.tileIndex); + } +}; + +struct ProviderTileHasher { + /** + Creates a hash which can be used as key in hash maps. + First set the bits to be unique for all tiles. + +-------+------------+-------+------------+ + | USAGE | BIT RANGE | #BITS | MAX VALUE | + +-------+------------+-------+------------+ + | level | 0 - 5 | 5 | 31 | + | x | 5 - 35 | 30 | 1073741824 | + | y | 35 - 64 | 29 | 536870912 | + +-------+------------+-------+------------+ + + Bits are then shifted depending on the tile provider used. + */ + unsigned long long operator()(const ProviderTileKey& t) const { + unsigned long long key = 0; + key |= static_cast(t.tileIndex.level); + key |= static_cast(t.tileIndex.x << 5); + key |= static_cast(t.tileIndex.y << 35); + // Now the key is unique for all tiles, however not for all tile providers. + // Add to the key depending on the tile provider to avoid some hash collisions. + // (All hash collisions can not be avoided due to the limit in 64 bit for the + // hash key) + // Idea: make some offset in the place of the bits for the x value. Lesser chance + // of having different x-value than having different tile provider ids. + key += static_cast(t.providerID << 25); + return key; + } +}; + + +/** + * Singleton class used to cache tiles for all CachingTileProviders. + */ +class MemoryAwareTileCache { +public: + static void create(size_t cacheSize); + static void destroy(); + + void clear(); + bool exist(ProviderTileKey key) const; + Tile get(ProviderTileKey key); + void put(ProviderTileKey key, Tile tile); + + void setMaximumSize(size_t maximumSize); + + static MemoryAwareTileCache& ref(); + +private: + /** + * \param cacheSize is the cache size given in bytes. + */ + MemoryAwareTileCache(size_t cacheSize); + ~MemoryAwareTileCache() = default; + + static MemoryAwareTileCache* _singleton; + MemoryAwareLRUCache _tileCache; + static std::mutex _mutexLock; +}; + +} // namespace cache +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___MEMORY_AWARE_TILE_CACHE___H__ diff --git a/modules/globebrowsing/chunk/chunk.cpp b/modules/globebrowsing/chunk/chunk.cpp index 54284da290..5e140bfc3b 100644 --- a/modules/globebrowsing/chunk/chunk.cpp +++ b/modules/globebrowsing/chunk/chunk.cpp @@ -29,6 +29,8 @@ #include #include #include +#include + namespace openspace { namespace globebrowsing { @@ -83,6 +85,8 @@ Chunk::Status Chunk::update(const RenderData& data) { } Chunk::BoundingHeights Chunk::getBoundingHeights() const { + using ChunkTileSettingsPair = std::pair; + BoundingHeights boundingHeights { 0.f, 0.f, false @@ -90,50 +94,58 @@ Chunk::BoundingHeights Chunk::getBoundingHeights() const { // In the future, this should be abstracted away and more easily queryable. // One must also handle how to sample pick one out of multiplte heightmaps - auto layerManager = owner().chunkedLodGlobe()->layerManager(); - + std::shared_ptr layerManager = + owner().chunkedLodGlobe()->layerManager(); + // The raster of a height map is the first one. We assume that the height map is // a single raster image. If it is not we will just use the first raster // (that is channel 0). const size_t HeightChannel = 0; const LayerGroup& heightmaps = layerManager->layerGroup(LayerManager::HeightLayers); - std::vector chunkTiles = tileselector::getTilesSortedByHighestResolution( - heightmaps, _tileIndex - ); + std::vector chunkTileSettingPairs = + tileselector::getTilesAndSettingsSortedByHighestResolution( + heightmaps, _tileIndex); bool lastHadMissingData = true; - for (const auto& chunkTile : chunkTiles) { - bool goodTile = (chunkTile.tile.status == Tile::Status::OK); - bool hasTileMetaData = (chunkTile.tile.metaData != nullptr); + for (const ChunkTileSettingsPair& chunkTileSettingsPair : chunkTileSettingPairs) { + ChunkTile chunkTile = chunkTileSettingsPair.first; + const LayerRenderSettings* settings = chunkTileSettingsPair.second; + bool goodTile = (chunkTile.tile.status() == Tile::Status::OK); + bool hasTileMetaData = (chunkTile.tile.metaData() != nullptr); if (goodTile && hasTileMetaData) { - auto tileMetaData = chunkTile.tile.metaData; + std::shared_ptr tileMetaData = chunkTile.tile.metaData(); + + float minValue = + settings->performLayerSettings(tileMetaData->minValues[HeightChannel]); + float maxValue = + settings->performLayerSettings(tileMetaData->maxValues[HeightChannel]); if (!boundingHeights.available) { if (tileMetaData->hasMissingData[HeightChannel]) { boundingHeights.min = std::min( DEFAULT_HEIGHT, - tileMetaData->minValues[HeightChannel] + minValue ); boundingHeights.max = std::max( DEFAULT_HEIGHT, - tileMetaData->maxValues[HeightChannel] + maxValue ); } else { - boundingHeights.min = tileMetaData->minValues[HeightChannel]; - boundingHeights.max = tileMetaData->maxValues[HeightChannel]; + boundingHeights.min = minValue; + boundingHeights.max = maxValue; } boundingHeights.available = true; } else { boundingHeights.min = std::min( boundingHeights.min, - tileMetaData->minValues[HeightChannel] + minValue ); boundingHeights.max = std::max( boundingHeights.max, - tileMetaData->maxValues[HeightChannel] + maxValue ); } lastHadMissingData = tileMetaData->hasMissingData[HeightChannel]; diff --git a/modules/globebrowsing/chunk/chunklevelevaluator/distanceevaluator.cpp b/modules/globebrowsing/chunk/chunklevelevaluator/distanceevaluator.cpp index d1cc671b49..e7ce4379d7 100644 --- a/modules/globebrowsing/chunk/chunklevelevaluator/distanceevaluator.cpp +++ b/modules/globebrowsing/chunk/chunklevelevaluator/distanceevaluator.cpp @@ -66,7 +66,7 @@ int Distance::getDesiredLevel(const Chunk& chunk, const RenderData& data) const double scaleFactor = globe.generalProperties().lodScaleFactor * ellipsoid.minimumRadius(); double projectedScaleFactor = scaleFactor / distance; - int desiredLevel = ceil(log2(projectedScaleFactor)); + int desiredLevel = static_cast(ceil(log2(projectedScaleFactor))); return desiredLevel; } diff --git a/modules/globebrowsing/chunk/chunknode.cpp b/modules/globebrowsing/chunk/chunknode.cpp index 408fd613a9..6b64a7e02c 100644 --- a/modules/globebrowsing/chunk/chunknode.cpp +++ b/modules/globebrowsing/chunk/chunknode.cpp @@ -33,9 +33,9 @@ namespace openspace { namespace globebrowsing { ChunkNode::ChunkNode(const Chunk& chunk, ChunkNode* parent) - : _chunk(chunk) - , _parent(parent) + : _parent(parent) , _children({ nullptr, nullptr, nullptr, nullptr }) + , _chunk(chunk) {} bool ChunkNode::isRoot() const { @@ -159,20 +159,20 @@ const ChunkNode& ChunkNode::getChild(Quad quad) const { void ChunkNode::split(int depth) { if (depth > 0 && isLeaf()) { for (size_t i = 0; i < _children.size(); ++i) { - Chunk chunk(_chunk.owner(), _chunk.tileIndex().child((Quad)i)); + Chunk chunk(_chunk.owner(), _chunk.tileIndex().child(static_cast(i))); _children[i] = std::make_unique(chunk, this); } } if (depth - 1 > 0) { - for (int i = 0; i < _children.size(); ++i) { + for (size_t i = 0; i < _children.size(); ++i) { _children[i]->split(depth - 1); } } } void ChunkNode::merge() { - for (int i = 0; i < _children.size(); ++i) { + for (size_t i = 0; i < _children.size(); ++i) { if (_children[i] != nullptr) { _children[i]->merge(); } diff --git a/modules/globebrowsing/ext/gdal/gdal.h b/modules/globebrowsing/ext/gdal/gdal.h new file mode 100644 index 0000000000..7153331b6a --- /dev/null +++ b/modules/globebrowsing/ext/gdal/gdal.h @@ -0,0 +1,36 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_GLOBEBROWSING___GDAL___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___GDAL___H__ + +#ifdef WIN32 +#pragma warning(push, 0) +#endif // WIN32 + +#include + +#ifdef WIN32 +#pragma warning(pop) +#endif // WIN32 diff --git a/modules/globebrowsing/geometry/ellipsoid.cpp b/modules/globebrowsing/geometry/ellipsoid.cpp index 4f756f575b..9d51d762d2 100644 --- a/modules/globebrowsing/geometry/ellipsoid.cpp +++ b/modules/globebrowsing/geometry/ellipsoid.cpp @@ -78,7 +78,7 @@ glm::dvec3 Ellipsoid::geodeticSurfaceProjection(const glm::dvec3& p) const { dSdA = -2.0 * glm::dot(p2 / (_cached._radiiToTheFourth * d3), glm::dvec3(1.0)); } - while (abs(s) > epsilon); + while (std::abs(s) > epsilon); return p / d; } diff --git a/modules/globebrowsing/geometry/geodeticpatch.cpp b/modules/globebrowsing/geometry/geodeticpatch.cpp index 8aca1219fb..b302e30b1d 100644 --- a/modules/globebrowsing/geometry/geodeticpatch.cpp +++ b/modules/globebrowsing/geometry/geodeticpatch.cpp @@ -27,6 +27,8 @@ #include #include +#include + namespace openspace { namespace globebrowsing { @@ -90,6 +92,7 @@ Geodetic2 GeodeticPatch::getCorner(Quad q) const { case NORTH_EAST: return Geodetic2(maxLat(), maxLon());// northEastCorner(); case SOUTH_WEST: return Geodetic2(minLat(), minLon());// southWestCorner(); case SOUTH_EAST: return Geodetic2(minLat(), maxLon());// southEastCorner(); + default: ghoul_assert(false, "Missing case label"); } } diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 808e5ce072..71dc2c07c6 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -24,8 +24,10 @@ #include +#include #include #include +#include #include #include #include @@ -35,20 +37,69 @@ #include #include #include +#include +#include #include #include #include #include +#include + namespace openspace { -GlobeBrowsingModule::GlobeBrowsingModule() : OpenSpaceModule("GlobeBrowsing") {} +GlobeBrowsingModule::GlobeBrowsingModule() + : OpenSpaceModule("GlobeBrowsing") + , _openSpaceMaximumTileCacheSize( + "maximumTileCacheSize", "Maximum tile cache size", + 512, // Default: 512 MB + 0, // Minimum: No caching + 1024, // Maximum: 1024 MB + 1) // Step: One MB + , _clearTileCache("clearTileCache", "Clear tile cache") {} void GlobeBrowsingModule::internalInitialize() { using namespace globebrowsing; + OsEng.registerModuleCallback(OpenSpaceEngine::CallbackOption::Initialize, [&] { + // Set maximum cache size to 25% of total RAM + _openSpaceMaximumTileCacheSize.setMaxValue(CpuCap.installedMainMemory() * 0.25); + + // Convert from MB to KB + cache::MemoryAwareTileCache::create(_openSpaceMaximumTileCacheSize * 1024); + _openSpaceMaximumTileCacheSize.onChange( + [&]{ + // Convert from MB to KB + cache::MemoryAwareTileCache::ref().setMaximumSize( + _openSpaceMaximumTileCacheSize * 1024); + }); + _clearTileCache.onChange( + [&]{ + cache::MemoryAwareTileCache::ref().clear(); + }); + + addProperty(_openSpaceMaximumTileCacheSize); + addProperty(_clearTileCache); + +#ifdef GLOBEBROWSING_USE_GDAL + // Convert from MB to Bytes + GdalWrapper::create( + 16ULL * 1024ULL * 1024ULL, // 16 MB + CpuCap.installedMainMemory() * 0.25 * 1024 * 1024); // 25% of total RAM + addPropertySubOwner(GdalWrapper::ref()); +#endif // GLOBEBROWSING_USE_GDAL + }); + + OsEng.registerModuleCallback(OpenSpaceEngine::CallbackOption::Deinitialize, [&]{ + cache::MemoryAwareTileCache::ref().clear(); + cache::MemoryAwareTileCache::ref().destroy(); +#ifdef GLOBEBROWSING_USE_GDAL + GdalWrapper::ref().destroy(); +#endif // GLOBEBROWSING_USE_GDAL + }); + auto fRenderable = FactoryManager::ref().factory(); ghoul_assert(fRenderable, "Renderable factory was not created"); fRenderable->registerClass("RenderableGlobe"); @@ -58,14 +109,17 @@ void GlobeBrowsingModule::internalInitialize() { fTileProvider->registerClass("LRUCaching"); fTileProvider->registerClass("SingleImage"); +#ifdef GLOBEBROWSING_USE_GDAL fTileProvider->registerClass("Temporal"); +#endif // GLOBEBROWSING_USE_GDAL + fTileProvider->registerClass("TileIndex"); fTileProvider->registerClass("SizeReference"); // Combining Tile Providers fTileProvider->registerClass("ByLevel"); fTileProvider->registerClass("ByIndex"); - + fTileProvider->registerClass("PresentationSlides"); FactoryManager::ref().addFactory(std::move(fTileProvider)); } diff --git a/modules/globebrowsing/globebrowsingmodule.h b/modules/globebrowsing/globebrowsingmodule.h index 942aea1819..9996c8876e 100644 --- a/modules/globebrowsing/globebrowsingmodule.h +++ b/modules/globebrowsing/globebrowsingmodule.h @@ -26,6 +26,10 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___GLOBEBROWSING_MODULE___H__ #include +#include +#include + +#include namespace openspace { @@ -35,6 +39,9 @@ public: protected: void internalInitialize() override; +private: + properties::IntProperty _openSpaceMaximumTileCacheSize; + properties::TriggerProperty _clearTileCache; }; } // namespace openspace diff --git a/modules/globebrowsing/globes/chunkedlodglobe.cpp b/modules/globebrowsing/globes/chunkedlodglobe.cpp index a4a6c6e823..24430afaa5 100644 --- a/modules/globebrowsing/globes/chunkedlodglobe.cpp +++ b/modules/globebrowsing/globes/chunkedlodglobe.cpp @@ -143,7 +143,8 @@ int ChunkedLodGlobe::getDesiredLevel( int desiredLevelByAvailableData = _chunkEvaluatorByAvailableTiles->getDesiredLevel( chunk, renderData ); - if (desiredLevelByAvailableData != chunklevelevaluator::Evaluator::UnknownDesiredLevel) { + if (desiredLevelByAvailableData != chunklevelevaluator::Evaluator::UnknownDesiredLevel && + _owner.debugProperties().limitLevelByAvailableData) { desiredLevel = glm::min(desiredLevel, desiredLevelByAvailableData); } @@ -180,14 +181,14 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const { const auto& tile = chunkTile.tile; const auto& uvTransform = chunkTile.uvTransform; const auto& depthTransform = tileProvider->depthTransform(); - if (tile.status != Tile::Status::OK) { + if (tile.status() != Tile::Status::OK) { return 0; } glm::vec2 transformedUv = Tile::TileUvToTextureSamplePosition( uvTransform, patchUV, - glm::uvec2(tile.texture->dimensions()) + glm::uvec2(tile.texture()->dimensions()) ); // Sample and do linear interpolation @@ -195,7 +196,7 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const { // Suggestion: a function in ghoul::opengl::Texture that takes uv coordinates // in range [0,1] and uses the set interpolation method and clamping. - glm::uvec3 dimensions = tile.texture->dimensions(); + glm::uvec3 dimensions = tile.texture()->dimensions(); glm::vec2 samplePos = transformedUv * glm::vec2(dimensions); glm::uvec2 samplePos00 = samplePos; @@ -219,10 +220,10 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const { glm::uvec2(dimensions) - glm::uvec2(1) ); - float sample00 = tile.texture->texelAsFloat(samplePos00).x; - float sample10 = tile.texture->texelAsFloat(samplePos10).x; - float sample01 = tile.texture->texelAsFloat(samplePos01).x; - float sample11 = tile.texture->texelAsFloat(samplePos11).x; + float sample00 = tile.texture()->texelAsFloat(samplePos00).x; + float sample10 = tile.texture()->texelAsFloat(samplePos10).x; + float sample01 = tile.texture()->texelAsFloat(samplePos01).x; + float sample11 = tile.texture()->texelAsFloat(samplePos11).x; // In case the texture has NaN or no data values don't use this height map. bool anySampleIsNaN = @@ -248,6 +249,10 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const { // Perform depth transform to get the value in meters height = depthTransform.depthOffset + depthTransform.depthScale * sample; + // Make sure that the height value follows the layer settings. + // For example if the multiplier is set to a value bigger than one, + // the sampled height should be modified as well. + height = layer->renderSettings().performLayerSettings(height); } // Return the result return height; @@ -276,7 +281,6 @@ void ChunkedLodGlobe::render(const RenderData& data) { stats.i["leafs chunk nodes"]++; if (chunk.isVisible()) { stats.i["rendered chunks"]++; - double t0 = Time::now().j2000Seconds(); _renderer->renderChunk(chunkNode.getChunk(), data); debugRenderChunk(chunk, mvp); } diff --git a/modules/globebrowsing/globes/pointglobe.cpp b/modules/globebrowsing/globes/pointglobe.cpp index d4d796c18f..7e1887a3e2 100644 --- a/modules/globebrowsing/globes/pointglobe.cpp +++ b/modules/globebrowsing/globes/pointglobe.cpp @@ -117,7 +117,5 @@ void PointGlobe::render(const RenderData& data) { _programObject->deactivate(); } -void PointGlobe::update(const UpdateData& data) {} - } // namespace globebrowsing } // namespace openspace diff --git a/modules/globebrowsing/globes/pointglobe.h b/modules/globebrowsing/globes/pointglobe.h index 2c41a38e8a..b52c151821 100644 --- a/modules/globebrowsing/globes/pointglobe.h +++ b/modules/globebrowsing/globes/pointglobe.h @@ -46,7 +46,6 @@ public: bool isReady() const override; void render(const RenderData& data) override; - void update(const UpdateData& data) override; private: const RenderableGlobe& _owner; diff --git a/modules/globebrowsing/globes/renderableglobe.cpp b/modules/globebrowsing/globes/renderableglobe.cpp index 40de2649eb..6b43aca744 100644 --- a/modules/globebrowsing/globes/renderableglobe.cpp +++ b/modules/globebrowsing/globes/renderableglobe.cpp @@ -44,15 +44,7 @@ using namespace properties; namespace globebrowsing { RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) - : _generalProperties({ - BoolProperty("enabled", "Enabled", true), - BoolProperty("performShading", "perform shading", true), - BoolProperty("atmosphere", "atmosphere", false), - FloatProperty("lodScaleFactor", "lodScaleFactor",10.0f, 1.0f, 50.0f), - FloatProperty("cameraMinHeight", "cameraMinHeight", 100.0f, 0.0f, 1000.0f) - }) - , _debugPropertyOwner("Debug") - , _debugProperties({ + : _debugProperties({ BoolProperty("saveOrThrowCamera", "save or throw camera", false), BoolProperty("showChunkEdges", "show chunk edges", false), BoolProperty("showChunkBounds", "show chunk bounds", false), @@ -61,12 +53,21 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) BoolProperty("showHeightIntensities", "show height intensities", false), BoolProperty("performFrustumCulling", "perform frustum culling", true), BoolProperty("performHorizonCulling", "perform horizon culling", true), - BoolProperty("levelByProjectedAreaElseDistance", "level by projected area (else distance)",false), + BoolProperty("levelByProjectedAreaElseDistance", "level by projected area (else distance)", true), BoolProperty("resetTileProviders", "reset tile providers", false), BoolProperty("toggleEnabledEveryFrame", "toggle enabled every frame", false), BoolProperty("collectStats", "collect stats", false), - BoolProperty("onlyModelSpaceRendering", "Only Model Space Rendering", false) + BoolProperty("limitLevelByAvailableData", "Limit level by available data", true), + IntProperty("modelSpaceRenderingCutoffLevel", "Model Space Rendering Cutoff Level", 10, 1, 22) }) + , _generalProperties({ + BoolProperty("enabled", "Enabled", true), + BoolProperty("performShading", "perform shading", true), + BoolProperty("atmosphere", "atmosphere", false), + FloatProperty("lodScaleFactor", "lodScaleFactor",10.0f, 1.0f, 50.0f), + FloatProperty("cameraMinHeight", "cameraMinHeight", 100.0f, 0.0f, 1000.0f) + }) + , _debugPropertyOwner("Debug") , _texturePropertyOwner("Textures") { setName("RenderableGlobe"); @@ -77,23 +78,28 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) glm::dvec3 radii; dictionary.getValue(keyRadii, radii); _ellipsoid = Ellipsoid(radii); - setBoundingSphere(pss(_ellipsoid.averageRadius(), 0.0)); + setBoundingSphere(_ellipsoid.averageRadius()); // Ghoul can't read ints from lua dictionaries... double patchSegmentsd; dictionary.getValue(keySegmentsPerPatch, patchSegmentsd); int patchSegments = patchSegmentsd; - dictionary.getValue(keyInteractionDepthBelowEllipsoid, - _interactionDepthBelowEllipsoid); + if (!dictionary.getValue(keyInteractionDepthBelowEllipsoid, + _interactionDepthBelowEllipsoid)) { + _interactionDepthBelowEllipsoid = 0; + } + float cameraMinHeight; dictionary.getValue(keyCameraMinHeight, cameraMinHeight); _generalProperties.cameraMinHeight.set(cameraMinHeight); // Init layer manager ghoul::Dictionary layersDictionary; - if (!dictionary.getValue(keyLayers, layersDictionary)) - throw ghoul::RuntimeError(std::string(keyLayers) + " must be specified specified!"); + if (!dictionary.getValue(keyLayers, layersDictionary)) { + throw ghoul::RuntimeError( + std::string(keyLayers) + " must be specified specified!"); + } _layerManager = std::make_shared(layersDictionary); @@ -127,8 +133,9 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) _debugPropertyOwner.addProperty(_debugProperties.resetTileProviders); _debugPropertyOwner.addProperty(_debugProperties.toggleEnabledEveryFrame); _debugPropertyOwner.addProperty(_debugProperties.collectStats); - _debugPropertyOwner.addProperty(_debugProperties.onlyModelSpaceRendering); - + _debugPropertyOwner.addProperty(_debugProperties.limitLevelByAvailableData); + _debugPropertyOwner.addProperty(_debugProperties.modelSpaceRenderingCutoffLevel); + addPropertySubOwner(_debugPropertyOwner); addPropertySubOwner(_layerManager.get()); } diff --git a/modules/globebrowsing/globes/renderableglobe.h b/modules/globebrowsing/globes/renderableglobe.h index bd5c5b4ea3..b90e01eec2 100644 --- a/modules/globebrowsing/globes/renderableglobe.h +++ b/modules/globebrowsing/globes/renderableglobe.h @@ -31,6 +31,7 @@ #include #include +#include namespace openspace { namespace globebrowsing { @@ -64,7 +65,8 @@ public: properties::BoolProperty resetTileProviders; properties::BoolProperty toggleEnabledEveryFrame; properties::BoolProperty collectStats; - properties::BoolProperty onlyModelSpaceRendering; + properties::BoolProperty limitLevelByAvailableData; + properties::IntProperty modelSpaceRenderingCutoffLevel; }; struct GeneralProperties { diff --git a/modules/globebrowsing/meshes/skirtedgrid.cpp b/modules/globebrowsing/meshes/skirtedgrid.cpp index ee632af4b6..822c3dd63e 100644 --- a/modules/globebrowsing/meshes/skirtedgrid.cpp +++ b/modules/globebrowsing/meshes/skirtedgrid.cpp @@ -26,10 +26,6 @@ #include -namespace { - const char*_loggerCat = "SkirtedGrid"; -} - namespace openspace { namespace globebrowsing { diff --git a/modules/globebrowsing/other/distanceswitch.cpp b/modules/globebrowsing/other/distanceswitch.cpp index 971f2e32d0..18f4644643 100644 --- a/modules/globebrowsing/other/distanceswitch.cpp +++ b/modules/globebrowsing/other/distanceswitch.cpp @@ -23,7 +23,6 @@ ****************************************************************************************/ #include - #include namespace openspace { @@ -32,6 +31,7 @@ namespace globebrowsing { DistanceSwitch::~DistanceSwitch() {} bool DistanceSwitch::initialize() { + _objectScale = 1.0; for (int i = 0; i < _renderables.size(); ++i) { _renderables[i]->initialize(); } @@ -51,16 +51,15 @@ void DistanceSwitch::render(const RenderData& data) { return; } - pss pssDistanceToCamera = (data.camera.position() - data.position).length(); - double distanceToCamera = pssDistanceToCamera.lengthd(); + double distanceToCamera = (data.camera.positionVec3() - data.position.dvec3()).length(); - if (distanceToCamera > _maxDistances.back()) { + if (distanceToCamera > _maxDistances.back() * _objectScale) { return; } // linear search through nodes to find which Renderable to render for (int i = 0; i < _renderables.size(); ++i) { - if (distanceToCamera < _maxDistances[i]) { + if (distanceToCamera < _maxDistances[i] * _objectScale) { _renderables[i]->render(data); return; } @@ -68,6 +67,7 @@ void DistanceSwitch::render(const RenderData& data) { } void DistanceSwitch::update(const UpdateData& data) { + _objectScale = data.modelTransform.scale; for (int i = 0; i < _renderables.size(); ++i) { _renderables[i]->update(data); } diff --git a/modules/globebrowsing/other/distanceswitch.h b/modules/globebrowsing/other/distanceswitch.h index 59a87d41c8..9f26e35f43 100644 --- a/modules/globebrowsing/other/distanceswitch.h +++ b/modules/globebrowsing/other/distanceswitch.h @@ -63,6 +63,7 @@ public: private: std::vector> _renderables; std::vector _maxDistances; + double _objectScale; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/rendering/chunkrenderer.cpp b/modules/globebrowsing/rendering/chunkrenderer.cpp index d7296db626..717c0c4038 100644 --- a/modules/globebrowsing/rendering/chunkrenderer.cpp +++ b/modules/globebrowsing/rendering/chunkrenderer.cpp @@ -30,6 +30,7 @@ #include #include #include +#include namespace { const char* keyFrame = "Frame"; @@ -64,7 +65,8 @@ ChunkRenderer::ChunkRenderer(std::shared_ptr grid, void ChunkRenderer::renderChunk(const Chunk& chunk, const RenderData& data) { // A little arbitrary with 10 but it works - if (chunk.owner().debugProperties().onlyModelSpaceRendering || chunk.tileIndex().level < 10) { + if (chunk.tileIndex().level < + chunk.owner().debugProperties().modelSpaceRenderingCutoffLevel) { renderChunkGlobally(chunk, data); } else { @@ -98,18 +100,25 @@ ghoul::opengl::ProgramObject* ChunkRenderer::getActivatedProgramWithTileData( const auto& debugProps = chunk.owner().debugProperties(); auto& pairs = layeredTexturePreprocessingData.keyValuePairs; - pairs.push_back(std::make_pair("useAtmosphere", - std::to_string(generalProps.atmosphereEnabled))); - pairs.push_back(std::make_pair("performShading", - std::to_string(generalProps.performShading))); - pairs.push_back(std::make_pair("showChunkEdges", - std::to_string(debugProps.showChunkEdges))); - pairs.push_back(std::make_pair("showHeightResolution", - std::to_string(debugProps.showHeightResolution))); - pairs.push_back(std::make_pair("showHeightIntensities", - std::to_string(debugProps.showHeightIntensities))); - pairs.push_back(std::make_pair("defaultHeight", - std::to_string(Chunk::DEFAULT_HEIGHT))); + pairs.emplace_back("useAtmosphere", std::to_string(generalProps.atmosphereEnabled)); + pairs.emplace_back("performShading", std::to_string(generalProps.performShading)); + pairs.emplace_back("showChunkEdges", std::to_string(debugProps.showChunkEdges)); + pairs.emplace_back("showHeightResolution", + std::to_string(debugProps.showHeightResolution)); + pairs.emplace_back("showHeightIntensities", + std::to_string(debugProps.showHeightIntensities)); + pairs.emplace_back("defaultHeight", std::to_string(Chunk::DEFAULT_HEIGHT)); + + pairs.emplace_back("tilePaddingStart", + "ivec2(" + + std::to_string(RawTileDataReader::padding.start.x) + "," + + std::to_string(RawTileDataReader::padding.start.y) + ")" + ); + pairs.emplace_back("tilePaddingSizeDiff", + "ivec2(" + + std::to_string(RawTileDataReader::padding.numPixels.x) + "," + + std::to_string(RawTileDataReader::padding.numPixels.y) + ")" + ); // Now the shader program can be accessed ghoul::opengl::ProgramObject* programObject = @@ -194,7 +203,6 @@ void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& da glm::normalize(-data.modelTransform.translation); glm::vec3 directionToSunCameraSpace = (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); - data.modelTransform.translation; programObject->setUniform("modelViewTransform", modelViewTransform); programObject->setUniform( "lightDirectionCameraSpace", -directionToSunCameraSpace); @@ -276,7 +284,6 @@ void ChunkRenderer::renderChunkLocally(const Chunk& chunk, const RenderData& dat glm::normalize(-data.modelTransform.translation); glm::vec3 directionToSunCameraSpace = (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); - data.modelTransform.translation; programObject->setUniform( "lightDirectionCameraSpace", -directionToSunCameraSpace); } diff --git a/modules/globebrowsing/rendering/gpu/gpuchunktile.cpp b/modules/globebrowsing/rendering/gpu/gpuchunktile.cpp index b5a92339b7..9efcdd9f74 100644 --- a/modules/globebrowsing/rendering/gpu/gpuchunktile.cpp +++ b/modules/globebrowsing/rendering/gpu/gpuchunktile.cpp @@ -33,7 +33,7 @@ namespace globebrowsing { void GPUChunkTile::setValue(ghoul::opengl::ProgramObject* programObject, const ChunkTile& chunkTile) { - gpuTexture.setValue(programObject, chunkTile.tile.texture); + gpuTexture.setValue(programObject, chunkTile.tile.texture()); gpuTileUvTransform.setValue(programObject, chunkTile.uvTransform); } diff --git a/modules/globebrowsing/rendering/layer/layer.cpp b/modules/globebrowsing/rendering/layer/layer.cpp index ba8eb7a39f..b6b6b1c9fc 100644 --- a/modules/globebrowsing/rendering/layer/layer.cpp +++ b/modules/globebrowsing/rendering/layer/layer.cpp @@ -47,10 +47,11 @@ Layer::Layer(const ghoul::Dictionary& layerDict) addProperty(_enabled); addPropertySubOwner(_renderSettings); + addPropertySubOwner(*_tileProvider); } ChunkTilePile Layer::getChunkTilePile(const TileIndex& tileIndex, int pileSize) const { - return std::move(_tileProvider->getChunkTilePile(tileIndex, pileSize)); + return _tileProvider->getChunkTilePile(tileIndex, pileSize); } } // namespace globebrowsing diff --git a/modules/globebrowsing/rendering/layer/layergroup.cpp b/modules/globebrowsing/rendering/layer/layergroup.cpp index a5ff471a98..171b3a6b38 100644 --- a/modules/globebrowsing/rendering/layer/layergroup.cpp +++ b/modules/globebrowsing/rendering/layer/layergroup.cpp @@ -31,7 +31,7 @@ namespace globebrowsing { LayerGroup::LayerGroup(std::string name) : properties::PropertyOwner(std::move(name)) - , _levelBlendingEnabled("blendTileLevels", "blend tile levels", true) + , _levelBlendingEnabled("blendTileLevels", "blend tile levels", false) { addProperty(_levelBlendingEnabled); } diff --git a/modules/globebrowsing/rendering/layer/layerrendersettings.cpp b/modules/globebrowsing/rendering/layer/layerrendersettings.cpp index 17c0784d6f..19c7c9d62f 100644 --- a/modules/globebrowsing/rendering/layer/layerrendersettings.cpp +++ b/modules/globebrowsing/rendering/layer/layerrendersettings.cpp @@ -38,5 +38,25 @@ LayerRenderSettings::LayerRenderSettings() addProperty(multiplier); } +float LayerRenderSettings::performLayerSettings(float currentValue) const { + float newValue = currentValue; + + newValue = glm::sign(newValue) * glm::pow(glm::abs(newValue), gamma); + newValue = newValue * multiplier; + newValue = newValue * opacity; + + return newValue; +} + +glm::vec4 LayerRenderSettings::performLayerSettings(glm::vec4 currentValue) const { + glm::vec4 newValue = glm::vec4( + performLayerSettings(currentValue.r), + performLayerSettings(currentValue.g), + performLayerSettings(currentValue.b), + performLayerSettings(currentValue.a)); + + return newValue; +} + } // namespace globebrowsing } // namespace openspace diff --git a/modules/globebrowsing/rendering/layer/layerrendersettings.h b/modules/globebrowsing/rendering/layer/layerrendersettings.h index 7b794d8b3b..a737f19b90 100644 --- a/modules/globebrowsing/rendering/layer/layerrendersettings.h +++ b/modules/globebrowsing/rendering/layer/layerrendersettings.h @@ -37,6 +37,13 @@ struct LayerRenderSettings : public properties::PropertyOwner { properties::FloatProperty opacity; properties::FloatProperty gamma; properties::FloatProperty multiplier; + + /// This function matches the function with the same name in the + /// shader code + float performLayerSettings(float currentValue) const; + /// This function matches the function with the same name in the + /// shader code + glm::vec4 performLayerSettings(glm::vec4 currentValue) const; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/shaders/tile.hglsl b/modules/globebrowsing/shaders/tile.hglsl index b48e79486b..7f0f4e3958 100644 --- a/modules/globebrowsing/shaders/tile.hglsl +++ b/modules/globebrowsing/shaders/tile.hglsl @@ -28,8 +28,8 @@ // Must match the values in tiledataset.cpp // (could be set as shader preprocessing data so that multiple definitions // are not needed) -#define TILE_PIXEL_START_OFFSET ivec2(-2) -#define TILE_PIXEL_SIZE_DIFFERENCE ivec2(4) +#define TILE_PIXEL_START_OFFSET #{tilePaddingStart} +#define TILE_PIXEL_SIZE_DIFFERENCE #{tilePaddingSizeDiff} vec4 patchBorderOverlay(vec2 uv, vec3 borderColor, float borderSize) { vec2 uvOffset = uv - vec2(0.5); @@ -87,7 +87,7 @@ vec2 compensateSourceTextureSampling(vec2 startOffset, vec2 sizeDiff, const Chun vec2 TileUVToTextureSamplePosition(const ChunkTile chunkTile, vec2 tileUV){ vec2 uv = chunkTile.uvTransform.uvOffset + chunkTile.uvTransform.uvScale * tileUV; - uv = compensateSourceTextureSampling(vec2(-2), vec2(4), chunkTile, uv); + uv = compensateSourceTextureSampling(TILE_PIXEL_START_OFFSET, TILE_PIXEL_SIZE_DIFFERENCE, chunkTile, uv); return uv; } diff --git a/modules/globebrowsing/tile/asynctilereader.cpp b/modules/globebrowsing/tile/asynctiledataprovider.cpp similarity index 81% rename from modules/globebrowsing/tile/asynctilereader.cpp rename to modules/globebrowsing/tile/asynctiledataprovider.cpp index 893bf70b58..537178d498 100644 --- a/modules/globebrowsing/tile/asynctilereader.cpp +++ b/modules/globebrowsing/tile/asynctiledataprovider.cpp @@ -22,28 +22,29 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include #include -#include +#include #include namespace openspace { namespace globebrowsing { -AsyncTileDataProvider::AsyncTileDataProvider(std::shared_ptr tileDataset, - std::shared_ptr pool) - : _tileDataset(tileDataset) +AsyncTileDataProvider::AsyncTileDataProvider( + const std::shared_ptr rawTileDataReader, + std::shared_ptr pool) + : _rawTileDataReader(rawTileDataReader) , _concurrentJobManager(pool) {} -std::shared_ptr AsyncTileDataProvider::getTextureDataProvider() const { - return _tileDataset; +std::shared_ptr AsyncTileDataProvider::getRawTileDataReader() const { + return _rawTileDataReader; } bool AsyncTileDataProvider::enqueueTileIO(const TileIndex& tileIndex) { if (satisfiesEnqueueCriteria(tileIndex)) { - auto job = std::make_shared(_tileDataset, tileIndex); + auto job = std::make_shared(_rawTileDataReader, tileIndex); //auto job = std::make_shared(_tileDataset, tileIndex, tileDiskCache, "ReadAndWrite"); _concurrentJobManager.enqueueJob(job); _enqueuedTileRequests[tileIndex.hashKey()] = tileIndex; @@ -61,6 +62,13 @@ std::vector> AsyncTileDataProvider::getRawTiles() { return readyResults; } +std::shared_ptr AsyncTileDataProvider::popFinishedRawTile() { + if (_concurrentJobManager.numFinishedJobs() > 0) + return _concurrentJobManager.popFinishedJob()->product(); + else + return nullptr; +} + bool AsyncTileDataProvider::satisfiesEnqueueCriteria(const TileIndex& tileIndex) const { // only allow tile to be enqueued if it's not already enqueued //return _futureTileIOResults.find(tileIndex.hashKey()) == _futureTileIOResults.end(); @@ -77,7 +85,7 @@ void AsyncTileDataProvider::reset() { while (_concurrentJobManager.numFinishedJobs() > 0) { _concurrentJobManager.popFinishedJob(); } - getTextureDataProvider()->reset(); + _rawTileDataReader->reset(); } void AsyncTileDataProvider::clearRequestQueue() { @@ -87,8 +95,8 @@ void AsyncTileDataProvider::clearRequestQueue() { _enqueuedTileRequests.clear(); } -float AsyncTileDataProvider::noDataValueAsFloat() { - return _tileDataset->noDataValueAsFloat(); +float AsyncTileDataProvider::noDataValueAsFloat() const { + return _rawTileDataReader->noDataValueAsFloat(); } } // namespace globebrowsing diff --git a/modules/globebrowsing/tile/asynctilereader.h b/modules/globebrowsing/tile/asynctiledataprovider.h similarity index 83% rename from modules/globebrowsing/tile/asynctilereader.h rename to modules/globebrowsing/tile/asynctiledataprovider.h index 445cd0c6f0..2863454f9c 100644 --- a/modules/globebrowsing/tile/asynctilereader.h +++ b/modules/globebrowsing/tile/asynctiledataprovider.h @@ -22,11 +22,10 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___ASYNC_TILE_READER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___ASYNC_TILE_READER___H__ +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___ASYNC_TILE_DATAPROVIDER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___ASYNC_TILE_DATAPROVIDER___H__ #include - #include #include @@ -34,28 +33,29 @@ namespace openspace { namespace globebrowsing { -class RawTile; -class TileDataset; +struct RawTile; +class RawTileDataReader; class AsyncTileDataProvider { public: - AsyncTileDataProvider(std::shared_ptr textureDataProvider, + AsyncTileDataProvider(std::shared_ptr textureDataProvider, std::shared_ptr pool); bool enqueueTileIO(const TileIndex& tileIndex); std::vector> getRawTiles(); - + std::shared_ptr popFinishedRawTile(); + void reset(); void clearRequestQueue(); - std::shared_ptr getTextureDataProvider() const; - float noDataValueAsFloat(); + std::shared_ptr getRawTileDataReader() const; + float noDataValueAsFloat() const; protected: virtual bool satisfiesEnqueueCriteria(const TileIndex&) const; private: - std::shared_ptr _tileDataset; + std::shared_ptr _rawTileDataReader; ConcurrentJobManager _concurrentJobManager; std::unordered_map _enqueuedTileRequests; }; @@ -63,4 +63,4 @@ private: } // namespace globebrowsing } // namespace openspace -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___ASYNC_TILE_READER___H__ +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___ASYNC_TILE_DATAPROVIDER___H__ diff --git a/modules/globebrowsing/tile/chunktile.h b/modules/globebrowsing/tile/chunktile.h index 5679123b9a..3fa3bcde07 100644 --- a/modules/globebrowsing/tile/chunktile.h +++ b/modules/globebrowsing/tile/chunktile.h @@ -34,6 +34,12 @@ namespace openspace { namespace globebrowsing { struct ChunkTile { + ChunkTile() : tile(Tile::TileUnavailable) {}; + ChunkTile(Tile tile, TileUvTransform uvTransform, TileDepthTransform depthTransform) : + tile(tile), + uvTransform(uvTransform), + depthTransform(depthTransform) {}; + Tile tile; TileUvTransform uvTransform; TileDepthTransform depthTransform; diff --git a/modules/globebrowsing/tile/loadjob/diskcachedtileloadjob.cpp b/modules/globebrowsing/tile/loadjob/diskcachedtileloadjob.cpp index 41a16afb6b..5e1911da69 100644 --- a/modules/globebrowsing/tile/loadjob/diskcachedtileloadjob.cpp +++ b/modules/globebrowsing/tile/loadjob/diskcachedtileloadjob.cpp @@ -25,17 +25,16 @@ #include #include -#include +#include #include namespace openspace { namespace globebrowsing { DiskCachedTileLoadJob::DiskCachedTileLoadJob( - std::shared_ptr textureDataProvider, - const TileIndex& tileIndex, - std::shared_ptr tdc, - CacheMode m) + std::shared_ptr textureDataProvider, + const TileIndex& tileIndex, std::shared_ptr tdc, + CacheMode m) : TileLoadJob(textureDataProvider, tileIndex) , _tileDiskCache(tdc) , _mode(m) @@ -46,26 +45,26 @@ void DiskCachedTileLoadJob::execute() { switch (_mode) { case CacheMode::Disabled: - _rawTile = _tileDataset->readTileData(_chunkIndex); + _rawTile = _rawTileDataReader->readTileData(_chunkIndex); break; case CacheMode::ReadOnly: _rawTile = _tileDiskCache->get(_chunkIndex); if (_rawTile == nullptr) { - _rawTile = _tileDataset->readTileData(_chunkIndex); + _rawTile = _rawTileDataReader->readTileData(_chunkIndex); } break; case CacheMode::ReadAndWrite: _rawTile = _tileDiskCache->get(_chunkIndex); if (_rawTile == nullptr) { - _rawTile = _tileDataset->readTileData(_chunkIndex); + _rawTile = _rawTileDataReader->readTileData(_chunkIndex); _tileDiskCache->put(_chunkIndex, _rawTile); } break; case CacheMode::WriteOnly: - _rawTile = _tileDataset->readTileData(_chunkIndex); + _rawTile = _rawTileDataReader->readTileData(_chunkIndex); _tileDiskCache->put(_chunkIndex, _rawTile); break; diff --git a/modules/globebrowsing/tile/loadjob/diskcachedtileloadjob.h b/modules/globebrowsing/tile/loadjob/diskcachedtileloadjob.h index 98c25e8598..4f20d98d65 100644 --- a/modules/globebrowsing/tile/loadjob/diskcachedtileloadjob.h +++ b/modules/globebrowsing/tile/loadjob/diskcachedtileloadjob.h @@ -41,7 +41,7 @@ struct DiskCachedTileLoadJob : public TileLoadJob { CacheHitsOnly, }; - DiskCachedTileLoadJob(std::shared_ptr textureDataProvider, + DiskCachedTileLoadJob(std::shared_ptr rawTileDataReader, const TileIndex& tileIndex, std::shared_ptr tdc, CacheMode cacheMode = CacheMode::ReadOnly); diff --git a/modules/globebrowsing/tile/loadjob/loadjob.h b/modules/globebrowsing/tile/loadjob/loadjob.h index 28aec76b70..ef1a5291dc 100644 --- a/modules/globebrowsing/tile/loadjob/loadjob.h +++ b/modules/globebrowsing/tile/loadjob/loadjob.h @@ -32,7 +32,7 @@ namespace openspace { namespace globebrowsing { -class RawTile; +struct RawTile; struct LoadJob : public Job { virtual void execute() = 0; diff --git a/modules/globebrowsing/tile/loadjob/tileloadjob.cpp b/modules/globebrowsing/tile/loadjob/tileloadjob.cpp index 20be5d229b..47c2e6030b 100644 --- a/modules/globebrowsing/tile/loadjob/tileloadjob.cpp +++ b/modules/globebrowsing/tile/loadjob/tileloadjob.cpp @@ -24,13 +24,18 @@ #include -#include +#include namespace openspace { namespace globebrowsing { +TileLoadJob::TileLoadJob(std::shared_ptr rawTileDataReader, + const TileIndex& tileIndex) + : _rawTileDataReader(rawTileDataReader) + , _chunkIndex(tileIndex) {} + void TileLoadJob::execute() { - _rawTile = _tileDataset->readTileData(_chunkIndex); + _rawTile = _rawTileDataReader->readTileData(_chunkIndex); } std::shared_ptr TileLoadJob::product() const { diff --git a/modules/globebrowsing/tile/loadjob/tileloadjob.h b/modules/globebrowsing/tile/loadjob/tileloadjob.h index a02538d1b7..68d59dce38 100644 --- a/modules/globebrowsing/tile/loadjob/tileloadjob.h +++ b/modules/globebrowsing/tile/loadjob/tileloadjob.h @@ -33,15 +33,12 @@ namespace openspace { namespace globebrowsing { -class TileDataset; -class RawTile; +class RawTileDataReader; +struct RawTile; struct TileLoadJob : LoadJob { - TileLoadJob(std::shared_ptr textureDataProvider, - const TileIndex& tileIndex) - : _tileDataset(textureDataProvider) - , _chunkIndex(tileIndex) - {} + TileLoadJob(std::shared_ptr rawTileDataReader, + const TileIndex& tileIndex); virtual ~TileLoadJob() = default; @@ -51,7 +48,7 @@ struct TileLoadJob : LoadJob { protected: TileIndex _chunkIndex; - std::shared_ptr _tileDataset; + std::shared_ptr _rawTileDataReader; std::shared_ptr _rawTile; }; diff --git a/modules/globebrowsing/tile/pixelregion.cpp b/modules/globebrowsing/tile/pixelregion.cpp index 63b62f5312..b24d7b263d 100644 --- a/modules/globebrowsing/tile/pixelregion.cpp +++ b/modules/globebrowsing/tile/pixelregion.cpp @@ -119,10 +119,12 @@ void PixelRegion::scale(double s) { void PixelRegion::downscalePow2(int exponent, PixelCoordinate wrt) { start += wrt; - start.x >>= exponent; - start.y >>= exponent; - numPixels.x >>= exponent; - numPixels.y >>= exponent; + start.x = ceil(start.x / static_cast(pow(2, exponent)));// >>= exponent; + start.y = ceil(start.y / static_cast(pow(2, exponent)));// >>= exponent; + numPixels.x = + ceil(numPixels.x / static_cast(pow(2, exponent)));// >>= exponent; + numPixels.y = + ceil(numPixels.y / static_cast(pow(2, exponent)));// >>= exponent; start -= wrt; } @@ -170,15 +172,20 @@ void PixelRegion::forceNumPixelToDifferByNearestMultipleOf(unsigned int multiple numPixels.y += sizeDiff % multiple; } else { - numPixels.x += static_cast(std::abs(static_cast(sizeDiff))) % multiple; + numPixels.x += static_cast( + std::abs(static_cast(sizeDiff))) % multiple; } } } void PixelRegion::roundUpNumPixelToNearestMultipleOf(unsigned int multiple) { ghoul_assert(multiple > 0, "multiple must be 1 or larger"); - numPixels.x += numPixels.x % multiple; - numPixels.y += numPixels.y % multiple; + numPixels.x += (numPixels.x % multiple == 0) ? 0 : + (multiple - (numPixels.x % multiple)); + numPixels.y += (numPixels.y % multiple == 0) ? 0 : + (multiple - (numPixels.y % multiple)); + ghoul_assert((numPixels.x % multiple) == 0, "Round to nearest multiple failed"); + ghoul_assert((numPixels.y % multiple) == 0, "Round to nearest multiple failed"); } void PixelRegion::roundDownToQuadratic() { @@ -241,6 +248,8 @@ int PixelRegion::edge(Side side) const { return start.x + numPixels.x; case Side::BOTTOM: return start.y + numPixels.y; + default: + ghoul_assert(false, "Missing case label"); } } diff --git a/modules/globebrowsing/tile/pixelregion.h b/modules/globebrowsing/tile/pixelregion.h index 9a86a82270..e85f2a84b1 100644 --- a/modules/globebrowsing/tile/pixelregion.h +++ b/modules/globebrowsing/tile/pixelregion.h @@ -73,8 +73,8 @@ struct PixelRegion { void scale(const glm::dvec2& s); void scale(double s); - void downscalePow2(int exponent, PixelCoordinate wrt = {0,0}); - void upscalePow2(int exponent, PixelCoordinate wrt = { 0,0 }); + void downscalePow2(int exponent, PixelCoordinate wrt = { 0, 0 }); + void upscalePow2(int exponent, PixelCoordinate wrt = { 0, 0 }); void move(Side side, int amount); void pad(const PixelRegion& padding); diff --git a/modules/globebrowsing/tile/rawtile.cpp b/modules/globebrowsing/tile/rawtile.cpp index 80471264db..009019bc44 100644 --- a/modules/globebrowsing/tile/rawtile.cpp +++ b/modules/globebrowsing/tile/rawtile.cpp @@ -26,12 +26,6 @@ #include -#include - -namespace { - const std::string _loggerCat = "Tile"; -} - namespace openspace { namespace globebrowsing { @@ -40,7 +34,7 @@ RawTile::RawTile() , dimensions(0, 0, 0) , tileMetaData(nullptr) , tileIndex(0, 0, 0) - , error(CE_None) + , error(ReadError::None) , nBytesImageData(0) {} @@ -52,13 +46,13 @@ RawTile RawTile::createDefaultRes() { defaultRes.nBytesImageData = w * h * 1 * 3 * 4; // assume max 3 channels, max 4 bytes per pixel defaultRes.imageData = new char[defaultRes.nBytesImageData]; std::fill_n((char*)defaultRes.imageData, defaultRes.nBytesImageData, 0); - return std::move(defaultRes); + return defaultRes; } void RawTile::serializeMetaData(std::ostream& os) { os << dimensions.x << " " << dimensions.y << " " << dimensions.z << std::endl; os << tileIndex.x << " " << tileIndex.y << " " << tileIndex.level << std::endl; - os << error << std::endl; + os << static_cast(error) << std::endl; // preprocess data os << (tileMetaData != nullptr) << std::endl; @@ -73,7 +67,7 @@ RawTile RawTile::deserializeMetaData(std::istream& is) { RawTile res; is >> res.dimensions.x >> res.dimensions.y >> res.dimensions.z; is >> res.tileIndex.x >> res.tileIndex.y >> res.tileIndex.level; - int err; is >> err; res.error = (CPLErr) err; + int err; is >> err; res.error = static_cast(err); res.tileMetaData = nullptr; bool hastileMetaData; @@ -89,7 +83,7 @@ RawTile RawTile::deserializeMetaData(std::istream& is) { is >> binaryDataSeparator; // not used // char* buffer = new char[res.nBytesImageData](); - return std::move(res); + return res; } } // namespace globebrowsing diff --git a/modules/globebrowsing/tile/rawtile.h b/modules/globebrowsing/tile/rawtile.h index fa436957f1..eb1d401ef0 100644 --- a/modules/globebrowsing/tile/rawtile.h +++ b/modules/globebrowsing/tile/rawtile.h @@ -26,28 +26,38 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___RAWTILE___H__ #include +#include #include #include #include -#include - namespace openspace { namespace globebrowsing { struct TileMetaData; struct RawTile { + + enum class ReadError { + None = 0, + Debug = 1, + Warning = 2, + Failure = 3, + Fatal = 4 + }; + RawTile(); char* imageData; glm::uvec3 dimensions; std::shared_ptr tileMetaData; TileIndex tileIndex; - CPLErr error; + ReadError error; size_t nBytesImageData; + GLuint glType; + TextureFormat textureFormat; void serializeMetaData(std::ostream& s); static RawTile deserializeMetaData(std::istream& s); diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp b/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp new file mode 100644 index 0000000000..9a2b454eb9 --- /dev/null +++ b/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp @@ -0,0 +1,412 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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. * + ****************************************************************************************/ +#ifdef GLOBEBROWSING_USE_GDAL + +#include + +#include +#include +#include +#include + +#include +#include // abspath +#include +#include +#include + +#include +#include +#include + +#include + +namespace { + const std::string _loggerCat = "GdalRawTileDataReader"; +} + +namespace openspace { +namespace globebrowsing { + +std::ostream& operator<<(std::ostream& os, const PixelRegion& pr) { + return os << pr.start.x << ", " << pr.start.y << " with size " << pr.numPixels.x << + ", " << pr.numPixels.y; +} + +GdalRawTileDataReader::GdalRawTileDataReader(const std::string& filePath, + const Configuration& config, + const std::string& baseDirectory) + : RawTileDataReader(config) + , _dataset(nullptr) +{ + + std::string initDir = baseDirectory.empty() ? CPLGetCurrentDir() : baseDirectory; + + _initData = { initDir, filePath, config.tilePixelSize, config.dataType }; + ensureInitialized(); +} + +GdalRawTileDataReader::~GdalRawTileDataReader() { + if (_dataset != nullptr) { + GDALClose(_dataset); + _dataset = nullptr; + } +} + +void GdalRawTileDataReader::reset() { + _cached._maxLevel = -1; + if (_dataset != nullptr) { + GDALClose(_dataset); + _dataset = nullptr; + } + initialize(); +} + +int GdalRawTileDataReader::maxChunkLevel() { + ensureInitialized(); + if (_cached._maxLevel < 0) { + int numOverviews = _dataset->GetRasterBand(1)->GetOverviewCount(); + _cached._maxLevel = -_cached._tileLevelDifference; + if (numOverviews > 0) { + _cached._maxLevel += numOverviews - 1; + } + } + return _cached._maxLevel; +} + +float GdalRawTileDataReader::noDataValueAsFloat() const { + float noDataValue; + if (_dataset && _dataset->GetRasterBand(1)) { + noDataValue = _dataset->GetRasterBand(1)->GetNoDataValue();; + } + else { + noDataValue = std::numeric_limits::min(); + } + return noDataValue; +} + +int GdalRawTileDataReader::rasterXSize() const { + return _dataset->GetRasterXSize(); +} + +int GdalRawTileDataReader::rasterYSize() const { + return _dataset->GetRasterYSize(); +} + +float GdalRawTileDataReader::depthOffset() const { + return _dataset->GetRasterBand(1)->GetOffset(); +} + +float GdalRawTileDataReader::depthScale() const { + return _dataset->GetRasterBand(1)->GetScale(); +} + +std::array GdalRawTileDataReader::getGeoTransform() const { + std::array padfTransform; + CPLErr err = _dataset->GetGeoTransform(&padfTransform[0]); + if (err == CE_Failure) { + return RawTileDataReader::getGeoTransform(); + } + return padfTransform; +} + +IODescription GdalRawTileDataReader::getIODescription(const TileIndex& tileIndex) const { + IODescription io; + io.read.region = highestResPixelRegion(tileIndex); + + // write region starts in origin + io.write.region.start = PixelRegion::PixelCoordinate(0, 0); + io.write.region.numPixels = PixelRegion::PixelCoordinate(_initData.tilePixelSize, _initData.tilePixelSize); + + io.read.overview = 0; + io.read.fullRegion = gdalPixelRegion( + _dataset->GetRasterBand(1)); + // For correct sampling in dataset, we need to pad the texture tile + + PixelRegion scaledPadding = padding; + double scale = io.read.region.numPixels.x / static_cast(io.write.region.numPixels.x); + scaledPadding.numPixels *= scale; + scaledPadding.start *= scale; + + io.read.region.pad(scaledPadding); + io.write.region.pad(padding); + io.write.region.start = PixelRegion::PixelCoordinate(0, 0); + + + + io.write.bytesPerLine = _dataLayout.bytesPerPixel * io.write.region.numPixels.x; + io.write.totalNumBytes = io.write.bytesPerLine * io.write.region.numPixels.y; + + // OpenGL does not like if the number of bytes per line is not 4 + if (io.write.bytesPerLine % 4 != 0) { + io.write.region.roundUpNumPixelToNearestMultipleOf(4); + io.write.bytesPerLine = _dataLayout.bytesPerPixel * io.write.region.numPixels.x; + io.write.totalNumBytes = io.write.bytesPerLine * io.write.region.numPixels.y; + } + + return io; +} + +void GdalRawTileDataReader::initialize() { + _dataset = openGdalDataset(_initData.datasetFilePath); + + //Do any other initialization needed for the GdalRawTileDataReader + _dataLayout = getTileDataLayout(_initData.dataType); + _depthTransform = calculateTileDepthTransform(); + _cached._tileLevelDifference = + calculateTileLevelDifference(_initData.tilePixelSize); +} + +char* GdalRawTileDataReader::readImageData( + IODescription& io, RawTile::ReadError& worstError) const { + // allocate memory for the image + char* imageData = new char[io.write.totalNumBytes]; + + // In case there are extra channels not existing in the GDAL dataset + // we set the bytes to 255 (for example an extra alpha channel that) + // needs to be 1. + if (_dataLayout.numRasters > _dataLayout.numRastersAvailable) { + memset(imageData, 255, io.write.totalNumBytes); + } + + if (_dataLayout.numRastersAvailable == 3) // RGB -> BGR + { + for (size_t i = 0; i < _dataLayout.numRastersAvailable; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageData + (i * _dataLayout.bytesPerDatum); + + RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + } + else if (_dataLayout.numRastersAvailable == 4) // RGBA -> BGRA + { + for (size_t i = 0; i < 3; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageData + (i * _dataLayout.bytesPerDatum); + + RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageData + (3 * _dataLayout.bytesPerDatum); + + RawTile::ReadError err = repeatedRasterRead(4, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + else + { + // Read the data (each rasterband is a separate channel) + for (size_t i = 0; i < _dataLayout.numRastersAvailable; i++) { + GDALRasterBand* rasterBand = _dataset->GetRasterBand(i + 1); + + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageData + (i * _dataLayout.bytesPerDatum); + + RawTile::ReadError err = repeatedRasterRead(i + 1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + } + + // GDAL reads pixel lines top to bottom, we want the opposite + return imageData; +} + +RawTile::ReadError GdalRawTileDataReader::rasterRead( + int rasterBand, const IODescription& io, char* dataDestination) const +{ + ghoul_assert(io.read.region.isInside(io.read.fullRegion), "write region of bounds!"); + ghoul_assert( + io.write.region.start.x >= 0 && io.write.region.start.y >= 0, + "Invalid write region" + ); + + PixelRegion::PixelCoordinate end = io.write.region.end(); + size_t largestIndex = + (end.y - 1) * io.write.bytesPerLine + (end.x - 1) * _dataLayout.bytesPerPixel; + ghoul_assert(largestIndex <= io.write.totalNumBytes, "Invalid write region"); + + char* dataDest = dataDestination; + + // GDAL reads pixels top to bottom, but we want our pixels bottom to top. + // Therefore, we increment the destination pointer to the last line on in the + // buffer, and the we specify in the rasterIO call that we want negative line + // spacing. Doing this compensates the flipped Y axis + dataDest += (io.write.totalNumBytes - io.write.bytesPerLine); + + // handle requested write region. Note -= since flipped y axis + dataDest -= io.write.region.start.y * io.write.bytesPerLine; + dataDest += io.write.region.start.x * _dataLayout.bytesPerPixel; + + CPLErr readError = _dataset->GetRasterBand(rasterBand)->RasterIO( + GF_Read, + io.read.region.start.x, // Begin read x + io.read.region.start.y, // Begin read y + io.read.region.numPixels.x, // width to read x + io.read.region.numPixels.y, // width to read y + dataDest, // Where to put data + io.write.region.numPixels.x, // width to write x in destination + io.write.region.numPixels.y, // width to write y in destination + _gdalType, // Type + _dataLayout.bytesPerPixel, // Pixel spacing + -io.write.bytesPerLine // Line spacing + ); + + // Convert error to RawTile::ReadError + RawTile::ReadError error; + switch (readError) { + case CE_None: error = RawTile::ReadError::None; break; + case CE_Debug: error = RawTile::ReadError::Debug; break; + case CE_Warning: error = RawTile::ReadError::Warning; break; + case CE_Failure: error = RawTile::ReadError::Failure; break; + case CE_Fatal: error = RawTile::ReadError::Fatal; break; + default: error = RawTile::ReadError::Failure; break; + } + return error; +} + +GDALDataset* GdalRawTileDataReader::openGdalDataset(const std::string& filePath) { + GDALDataset* dataset = static_cast(GDALOpen(filePath.c_str(), GA_ReadOnly)); + if (!dataset) { + using namespace ghoul::filesystem; + std::string correctedPath = FileSystem::ref().pathByAppendingComponent( + _initData.initDirectory, filePath + ); + + dataset = (GDALDataset *)GDALOpen(correctedPath.c_str(), GA_ReadOnly); + if (!dataset) { + throw ghoul::RuntimeError("Failed to load dataset:\n" + filePath); + } + } + return dataset; +} + +int GdalRawTileDataReader::calculateTileLevelDifference(int minimumPixelSize) { + GDALRasterBand* firstBand = _dataset->GetRasterBand(1); + GDALRasterBand* maxOverview; + int numOverviews = firstBand->GetOverviewCount(); + int sizeLevel0; + if (numOverviews <= 0) { // No overviews. Use first band. + maxOverview = firstBand; + } + else { // Pick the highest overview. + maxOverview = firstBand->GetOverview(numOverviews - 1); + } + sizeLevel0 = maxOverview->GetXSize(); + double diff = log2(minimumPixelSize) - log2(sizeLevel0); + return diff; +} + +bool GdalRawTileDataReader::gdalHasOverviews() const { + return _dataset->GetRasterBand(1)->GetOverviewCount() > 0; +} + +int GdalRawTileDataReader::gdalOverview( + const PixelRegion::PixelRange& regionSizeOverviewZero) const { + GDALRasterBand* firstBand = _dataset->GetRasterBand(1); + + int minNumPixels0 = glm::min(regionSizeOverviewZero.x, regionSizeOverviewZero.y); + + int overviews = firstBand->GetOverviewCount(); + GDALRasterBand* maxOverview = + overviews ? firstBand->GetOverview(overviews - 1) : firstBand; + + int sizeLevel0 = maxOverview->GetXSize(); + // The dataset itself may not have overviews but even if it does not, an overview + // for the data region can be calculated and possibly be used to sample greater + // Regions of the original dataset. + int ov = std::log2(minNumPixels0) - std::log2(sizeLevel0 + 1) - + _cached._tileLevelDifference; + ov = glm::clamp(ov, 0, overviews - 1); + + return ov; +} + +int GdalRawTileDataReader::gdalOverview(const TileIndex& tileIndex) const { + int overviews = _dataset->GetRasterBand(1)->GetOverviewCount(); + int ov = overviews - (tileIndex.level + _cached._tileLevelDifference + 1); + return glm::clamp(ov, 0, overviews - 1); +} + +int GdalRawTileDataReader::gdalVirtualOverview(const TileIndex& tileIndex) const { + int overviews = _dataset->GetRasterBand(1)->GetOverviewCount(); + int ov = overviews - (tileIndex.level + _cached._tileLevelDifference + 1); + return ov; +} + +PixelRegion GdalRawTileDataReader::gdalPixelRegion(GDALRasterBand* rasterBand) const { + PixelRegion gdalRegion; + gdalRegion.start.x = 0; + gdalRegion.start.y = 0; + gdalRegion.numPixels.x = rasterBand->GetXSize(); + gdalRegion.numPixels.y = rasterBand->GetYSize(); + return gdalRegion; +} + +TileDataLayout GdalRawTileDataReader::getTileDataLayout(GLuint preferredGlType) { + TileDataLayout layout; + + // Assume all raster bands have the same data type + _gdalType = preferredGlType != 0 ? + tiledatatype::getGdalDataType(preferredGlType) : + _dataset->GetRasterBand(1)->GetRasterDataType(); + + layout.glType = tiledatatype::getOpenGLDataType(_gdalType); + layout.numRastersAvailable = _dataset->GetRasterCount(); + layout.numRasters = layout.numRastersAvailable; + + // This is to avoid corrupted textures that can appear when the number of + // bytes per row is not a multiplie of 4. + // Info here: https://www.khronos.org/opengl/wiki/Pixel_Transfer#Pixel_layout + // This also mean that we need to make sure not to read from non existing + // rasters from the GDAL dataset + if (layout.numRasters == 3) { + layout.numRasters = 4; + } + + layout.bytesPerDatum = tiledatatype::numberOfBytes(_gdalType); + layout.bytesPerPixel = layout.bytesPerDatum * layout.numRasters; + layout.textureFormat = tiledatatype::getTextureFormatOptimized(layout.numRasters, _gdalType); + + return layout; +} + + +} // namespace globebrowsing +} // namespace openspace + +#endif // GLOBEBROWSING_USE_GDAL diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.h b/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.h new file mode 100644 index 0000000000..338f3f5a90 --- /dev/null +++ b/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.h @@ -0,0 +1,125 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_GLOBEBROWSING___GDAL_RAW_TILE_DATA_READER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___GDAL_RAW_TILE_DATA_READER___H__ + +#ifdef GLOBEBROWSING_USE_GDAL + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +class GDALDataset; +class GDALRasterBand; + +namespace openspace { +namespace globebrowsing { + +class GeodeticPatch; + +class GdalRawTileDataReader : public RawTileDataReader { +public: + + /** + * Opens a GDALDataset in readonly mode and calculates meta data required for + * reading tile using a TileIndex. + * + * \param filePath, a path to a specific file GDAL can read + * \param config, Configuration used for initialization + * \param baseDirectory, the base directory to use in future loading operations + */ + GdalRawTileDataReader(const std::string& filePath, const Configuration& config, + const std::string& baseDirectory = ""); + + virtual ~GdalRawTileDataReader() override; + + // Public virtual function overloading + virtual void reset() override; + virtual int maxChunkLevel() override; + virtual float noDataValueAsFloat() const override; + virtual int rasterXSize() const override; + virtual int rasterYSize() const override; + virtual float depthOffset() const override; + virtual float depthScale() const override; + +protected: + + /** + * Returns the geo transform from raster space to projection coordinates as defined + * by GDAL. + * If the transform is not available, the function returns a transform to map + * the pixel coordinates to cover the whole geodetic lat long space. + */ + virtual std::array getGeoTransform() const override; + virtual IODescription getIODescription(const TileIndex& tileIndex) const override; + +private: + // Private virtual function overloading + virtual void initialize() override; + virtual char* readImageData( + IODescription& io, RawTile::ReadError& worstError) const override; + virtual RawTile::ReadError rasterRead( + int rasterBand, const IODescription& io, char* dst) const override; + + // GDAL Helper methods + GDALDataset* openGdalDataset(const std::string& filePath); + int calculateTileLevelDifference(int minimumPixelSize); + bool gdalHasOverviews() const; + int gdalOverview(const PixelRegion::PixelRange& baseRegionSize) const; + int gdalOverview(const TileIndex& tileIndex) const; + int gdalVirtualOverview(const TileIndex& tileIndex) const; + PixelRegion gdalPixelRegion(GDALRasterBand* rasterBand) const; + TileDataLayout getTileDataLayout(GLuint prefferedGLType); + + // Member variables + struct InitData { + std::string initDirectory; + std::string datasetFilePath; + int tilePixelSize; + GLuint dataType; + } _initData; + + GDALDataset* _dataset; + GDALDataType _gdalType; // The type to reinterpret to when reading +}; + +} // namespace globebrowsing +} // namespace openspace + +#endif // GLOBEBROWSING_USE_GDAL + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GDAL_RAW_TILE_DATA_READER___H__ diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.cpp b/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.cpp new file mode 100644 index 0000000000..952dbb93f8 --- /dev/null +++ b/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.cpp @@ -0,0 +1,190 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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. * + ****************************************************************************************/ + +#ifdef GLOBEBROWSING_USE_GDAL + +#include + +#include +#include + +#include // abspath +#include +#include + +#include + +namespace { + const char* _loggerCat = "GdalWrapper"; +} + +namespace openspace { +namespace globebrowsing { + +void gdalErrorHandler(CPLErr eErrClass, int errNo, const char *msg) { + if (GdalWrapper::ref().logGdalErrors()) { + switch (eErrClass) { + case CE_None: break; + case CE_Debug: LDEBUG ("GDAL " << msg); break; + case CE_Warning: LWARNING("GDAL " << msg); break; + case CE_Failure: LERROR ("GDAL " << msg); break; + case CE_Fatal: LFATAL ("GDAL " << msg); break; + } + } +} + +GdalWrapper* GdalWrapper::_singleton = nullptr; +std::mutex GdalWrapper::_mutexLock; + +void GdalWrapper::create(size_t maximumCacheSize, + size_t maximumMaximumCacheSize) { + std::lock_guard guard(_mutexLock); + _singleton = new GdalWrapper(maximumCacheSize, maximumMaximumCacheSize); +} + +void GdalWrapper::destroy() { + std::lock_guard guard(_mutexLock); + ghoul_assert(_singleton, "Cannot delete null"); + delete _singleton; +} + +GdalWrapper& GdalWrapper::ref() { + ghoul_assert(_singleton, "GdalWrapper not created"); + return *_singleton; +} + +size_t GDALCacheUsed() { + return GDALGetCacheUsed64(); +} + +size_t GDALMaximumCacheSize() { + return GDALGetCacheMax64(); +} + +bool GdalWrapper::logGdalErrors() const { + return _logGdalErrors; +} + +GdalWrapper::GdalWrapper(size_t maximumCacheSize, + size_t maximumMaximumCacheSize) + : PropertyOwner("GdalWrapper") + , _logGdalErrors("logGdalErrors", "Log GDAL errors", true) + , _gdalMaximumCacheSize ( + "gdalMaximumCacheSize", "GDAL maximum cache size", + maximumCacheSize / (1024 * 1024), // Default + 0, // Minimum: No caching + maximumMaximumCacheSize / (1024 * 1024), // Maximum + 1 // Step: One MB + ) { + addProperty(_logGdalErrors); + addProperty(_gdalMaximumCacheSize); + + GDALAllRegister(); + CPLSetConfigOption( + "GDAL_DATA", + absPath("${MODULE_GLOBEBROWSING}/gdal_data").c_str() + ); + CPLSetConfigOption( + "CPL_TMPDIR", + absPath("${BASE_PATH}").c_str() + ); + setGdalProxyConfiguration(); + CPLSetErrorHandler(gdalErrorHandler); + + _gdalMaximumCacheSize.onChange([&] { + // MB to Bytes + GDALSetCacheMax64( + static_cast(_gdalMaximumCacheSize) * + 1024ULL * 1024ULL + ); + }); +} + +void GdalWrapper::setGdalProxyConfiguration() { + ghoul::Dictionary proxySettings; + bool proxyEnabled = OsEng.configurationManager().getValue( + ConfigurationManager::KeyHttpProxy, proxySettings + ); + if (proxyEnabled) { + std::string proxyAddress, proxyPort, proxyUser, proxyPassword, + proxyAuth; + + bool success = proxySettings.getValue( + ConfigurationManager::PartHttpProxyAddress, + proxyAddress + ); + success &= proxySettings.getValue( + ConfigurationManager::PartHttpProxyPort, + proxyPort + ); + proxySettings.getValue( + ConfigurationManager::PartHttpProxyAuthentication, + proxyAuth + ); + + std::string proxyAuthString = "BASIC"; + if (proxyAuth == "basic" || proxyAuth == "") { + proxyAuthString = "BASIC"; + } else if (proxyAuth == "ntlm") { + proxyAuthString = "NTLM"; + } else if (proxyAuth == "digest") { + proxyAuthString = "DIGEST"; + } else if (proxyAuth == "any") { + proxyAuthString = "ANY"; + } else { + success = false; + } + + bool userAndPassword = proxySettings.getValue( + ConfigurationManager::PartHttpProxyUser, + proxyUser + ); + userAndPassword &= proxySettings.getValue( + ConfigurationManager::PartHttpProxyPassword, + proxyPassword + ); + + if (success) { + std::string proxy = proxyAddress + ":" + proxyPort; + CPLSetConfigOption("GDAL_HTTP_PROXY", proxy.c_str()); + LDEBUG("Using proxy server " << proxy); + if (userAndPassword) { + std::string proxyUserPwd = proxyUser + ":" + proxyPassword; + CPLSetConfigOption("GDAL_HTTP_PROXYUSERPWD", proxyUserPwd.c_str()); + CPLSetConfigOption("GDAL_HTTP_PROXYAUTH", proxyAuthString.c_str()); + LDEBUG("Using authentication method: " << proxyAuthString); + } + } else { + LERROR("Invalid proxy settings for GDAL"); + } + } else { + LDEBUG("Setting up GDAL without proxy server"); + } +} + + +} // namespace globebrowsing +} // namespace openspace + +#endif // GLOBEBROWSING_USE_GDAL diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.h b/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.h new file mode 100644 index 0000000000..c47818cd29 --- /dev/null +++ b/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.h @@ -0,0 +1,96 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_GLOBEBROWSING___GDAL_WRAPPER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___GDAL_WRAPPER___H__ + +#ifdef GLOBEBROWSING_USE_GDAL + +#include +#include +#include + +#include + +#include +#include + +namespace openspace { +namespace globebrowsing { + +/** + * Function for passing GDAL error messages to the GHOUL logging system. + */ +static void gdalErrorHandler(CPLErr eErrClass, int errNo, const char* msg); + +/** + * Singleton class interfacing with global GDAL functions. + */ +class GdalWrapper : public properties::PropertyOwner { +public: + /** + * Create the singleton. Must be called before the class can be used. + * \param maximumCacheSize is the current maximum cache size GDAL can use + * for caching blocks in memory given in bytes. + * \param maximumMaximumCacheSize is the maximum cache size GDAL can use + * for caching blocks in memory given in bytes. + */ + static void create(size_t maximumCacheSize, size_t maximumMaximumCacheSize); + static void destroy(); + + static GdalWrapper& ref(); + + /** + * Get the current size of the GDAL in memory cache. + * \returns the number of bytes currently in the GDAL memory cache. + */ + static size_t GDALCacheUsed(); + + /** + * Get the maximum GDAL in memory cache size. + * \returns the maximum number of bytes allowed for the GDAL cache. + */ + static size_t GDALMaximumCacheSize(); + + bool logGdalErrors() const; + +private: + GdalWrapper(size_t maximumCacheSize, size_t maximumMaximumCacheSize); + ~GdalWrapper() = default; + + void setGdalProxyConfiguration(); + + properties::IntProperty _gdalMaximumCacheSize; + properties::BoolProperty _logGdalErrors; + + static GdalWrapper* _singleton; + static std::mutex _mutexLock; +}; + +} // namespace globebrowsing +} // namespace openspace + +#endif // GLOBEBROWSING_USE_GDAL + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GDAL_WRAPPER___H__ diff --git a/modules/globebrowsing/tile/rawtiledatareader/iodescription.cpp b/modules/globebrowsing/tile/rawtiledatareader/iodescription.cpp new file mode 100644 index 0000000000..66b0fd1fcd --- /dev/null +++ b/modules/globebrowsing/tile/rawtiledatareader/iodescription.cpp @@ -0,0 +1,70 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +namespace { + const char* _loggerCat = "IODescription"; +} + +namespace openspace { +namespace globebrowsing { + +IODescription IODescription::cut(PixelRegion::Side side, int pos) { + PixelRegion readPreCut = read.region; + PixelRegion writePreCut = write.region; + + glm::dvec2 ratio; + ratio.x = write.region.numPixels.x / static_cast(read.region.numPixels.x); + ratio.y = write.region.numPixels.y / static_cast(read.region.numPixels.y); + + IODescription whatCameOff = *this; + whatCameOff.read.region = read.region.globalCut(side, pos); + + PixelRegion::PixelRange cutSize = whatCameOff.read.region.numPixels; + PixelRegion::PixelRange localWriteCutSize = ratio * glm::dvec2(cutSize); + + if (cutSize.x == 0 || cutSize.y == 0) { + ghoul_assert( + read.region.equals(readPreCut), + "Read region should not have been modified" + ); + ghoul_assert( + write.region.equals(writePreCut), + "Write region should not have been modified" + ); + } + + int localWriteCutPos = + (side == PixelRegion::Side::LEFT || side == PixelRegion::Side::RIGHT) + ? localWriteCutSize.x : localWriteCutSize.y; + whatCameOff.write.region = write.region.localCut(side, localWriteCutPos); + + return whatCameOff; +} + +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/rawtiledatareader/iodescription.h b/modules/globebrowsing/tile/rawtiledatareader/iodescription.h new file mode 100644 index 0000000000..5905a8a57c --- /dev/null +++ b/modules/globebrowsing/tile/rawtiledatareader/iodescription.h @@ -0,0 +1,63 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_GLOBEBROWSING___IO_DESCRIPTION___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___IO_DESCRIPTION___H__ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace openspace { +namespace globebrowsing { + +struct IODescription { + struct ReadData { + int overview; + PixelRegion region; + PixelRegion fullRegion; + } read; + + struct WriteData { + PixelRegion region; + size_t bytesPerLine; + size_t totalNumBytes; + } write; + + IODescription cut(PixelRegion::Side side, int pos); +}; + +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___IO_DESCRIPTION___H__ diff --git a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp new file mode 100644 index 0000000000..18b8a381e5 --- /dev/null +++ b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp @@ -0,0 +1,395 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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 +#include +#include + +#define _USE_MATH_DEFINES +#include + +namespace openspace { +namespace globebrowsing { + +const glm::ivec2 RawTileDataReader::tilePixelStartOffset = glm::ivec2(-2); +const glm::ivec2 RawTileDataReader::tilePixelSizeDifference = glm::ivec2(4); + +const PixelRegion RawTileDataReader::padding = PixelRegion( + tilePixelStartOffset, + tilePixelSizeDifference +); + +RawTileDataReader::RawTileDataReader(const Configuration& config) + : _config(config) + , _hasBeenInitialized(false) +{} + +void RawTileDataReader::ensureInitialized() { + if (!_hasBeenInitialized) { + initialize(); + _hasBeenInitialized = true; + } +} + +std::shared_ptr RawTileDataReader::defaultTileData() { + PixelRegion pixelRegion = { + PixelRegion::PixelCoordinate(0, 0), + PixelRegion::PixelRange(16, 16) + }; + int bytesPerPixel = 1; // GL_R -> 1 bpp + std::shared_ptr rawTile = std::make_shared(); + rawTile->tileIndex = { 0, 0, 0 }; + rawTile->dimensions = glm::uvec3(pixelRegion.numPixels, 1); + rawTile->nBytesImageData = + rawTile->dimensions.x * rawTile->dimensions.y * bytesPerPixel; + rawTile->imageData = new char[rawTile->nBytesImageData]; + rawTile->glType = GL_UNSIGNED_BYTE; + rawTile->textureFormat = { ghoul::opengl::Texture::Format::Red, GL_R }; + + for (size_t i = 0; i < rawTile->nBytesImageData; ++i) { + rawTile->imageData[i] = 0; + } + rawTile->error = RawTile::ReadError::None; + + return rawTile; +} + +std::shared_ptr RawTileDataReader::readTileData(TileIndex tileIndex) { + ensureInitialized(); + IODescription io = getIODescription(tileIndex); + RawTile::ReadError worstError = RawTile::ReadError::None; + + // Build the RawTile from the data we querred + std::shared_ptr rawTile = std::make_shared(); + rawTile->imageData = readImageData(io, worstError); + rawTile->error = worstError; + rawTile->tileIndex = tileIndex; + rawTile->dimensions = glm::uvec3(io.write.region.numPixels, 1); + rawTile->nBytesImageData = io.write.totalNumBytes; + rawTile->glType = _dataLayout.glType; + rawTile->textureFormat = _dataLayout.textureFormat; + + if (_config.doPreProcessing) { + rawTile->tileMetaData = getTileMetaData(rawTile, io.write.region); + rawTile->error = std::max(rawTile->error, postProcessErrorCheck(rawTile, io)); + } + + return rawTile; +} + +TileDepthTransform RawTileDataReader::getDepthTransform() const { + return _depthTransform; +} + +std::array RawTileDataReader::getGeoTransform() const { + std::array padfTransform; + + GeodeticPatch globalCoverage(Geodetic2(0,0), Geodetic2(M_PI / 2.0, M_PI)); + padfTransform[1] = Angle::fromRadians( + globalCoverage.size().lon).asDegrees() / rasterXSize(); + padfTransform[5] = -Angle::fromRadians( + globalCoverage.size().lat).asDegrees() / rasterYSize(); + padfTransform[0] = Angle::fromRadians( + globalCoverage.getCorner(Quad::NORTH_WEST).lon).asDegrees(); + padfTransform[3] = Angle::fromRadians( + globalCoverage.getCorner(Quad::NORTH_WEST).lat).asDegrees(); + padfTransform[2] = 0; + padfTransform[4] = 0; + return padfTransform; +} + +PixelRegion::PixelCoordinate RawTileDataReader::geodeticToPixel( + const Geodetic2& geo) const { + std::array padfTransform = getGeoTransform(); + + double Y = Angle::fromRadians(geo.lat).asDegrees(); + double X = Angle::fromRadians(geo.lon).asDegrees(); + + // convert from pixel and line to geodetic coordinates + // Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2]; + // Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5]; + + // <=> + double* a = &(padfTransform[0]); + double* b = &(padfTransform[3]); + + // Xp = a[0] + P*a[1] + L*a[2]; + // Yp = b[0] + P*b[1] + L*b[2]; + + // <=> + double divisor = (a[2] * b[1] - a[1] * b[2]); + ghoul_assert(divisor != 0.0, "Division by zero!"); + //ghoul_assert(a[2] != 0.0, "a2 must not be zero!"); + double P = (a[0] * b[2] - a[2] * b[0] + a[2] * Y - b[2] * X) / divisor; + double L = (-a[0] * b[1] + a[1] * b[0] - a[1] * Y + b[1] * X) / divisor; + // ref: https://www.wolframalpha.com/input/?i=X+%3D+a0+%2B+a1P+%2B+a2L,+Y+%3D+b0+%2B+b1P+%2B+b2L,+solve+for+P+and+L + + double Xp = a[0] + P*a[1] + L*a[2]; + double Yp = b[0] + P*b[1] + L*b[2]; + + ghoul_assert(std::abs(X - Xp) < 1e-10, "inverse should yield X as before"); + ghoul_assert(std::abs(Y - Yp) < 1e-10, "inverse should yield Y as before"); + + return PixelRegion::PixelCoordinate(glm::round(P), glm::round(L)); +} + +Geodetic2 RawTileDataReader::pixelToGeodetic( + const PixelRegion::PixelCoordinate& p) const { + std::array padfTransform = getGeoTransform(); + Geodetic2 geodetic; + // Should be using radians and not degrees? + geodetic.lon = padfTransform[0] + p.x * padfTransform[1] + p.y * padfTransform[2]; + geodetic.lat = padfTransform[3] + p.x * padfTransform[4] + p.y * padfTransform[5]; + return geodetic; +} + +PixelRegion RawTileDataReader::highestResPixelRegion(const GeodeticPatch& geodeticPatch) const { + Geodetic2 nwCorner = geodeticPatch.getCorner(Quad::NORTH_WEST); + Geodetic2 swCorner = geodeticPatch.getCorner(Quad::SOUTH_EAST); + PixelRegion::PixelCoordinate pixelStart = geodeticToPixel(nwCorner); + PixelRegion::PixelCoordinate pixelEnd = geodeticToPixel(swCorner); + PixelRegion region(pixelStart, pixelEnd - pixelStart); + return region; +} + +RawTile::ReadError RawTileDataReader::repeatedRasterRead( + int rasterBand, const IODescription& fullIO, char* dataDestination, + int depth) const +{ + RawTile::ReadError worstError = RawTile::ReadError::None; + + // NOTE: + // Ascii graphics illustrates the implementation details of this method, for one + // specific case. Even though the illustrated case is specific, readers can + // hopefully find it useful to get the general idea. + + // Make a copy of the full IO desription as we will have to modify it + IODescription io = fullIO; + + // Example: + // We have an io description that defines a WRITE and a READ region. + // In this case the READ region extends outside of the defined io.read.fullRegion, + // meaning we will have to perform wrapping + + // io.write.region io.read.region + // | | + // V V + // +-------+ +-------+ + // | | | |--------+ + // | | | | | + // | | | | | + // +-------+ +-------+ | + // | | <-- io.read.fullRegion + // | | + // +--------------+ + + if (!io.read.region.isInside(io.read.fullRegion)) { + // Loop through each side: left, top, right, bottom + for (int i = 0; i < 4; ++i) { + + // Example: + // We are currently considering the left side of the pixel region + PixelRegion::Side side = static_cast(i); + IODescription cutoff = io.cut(side, io.read.fullRegion.edge(side)); + + // Example: + // We cut off the left part that was outside the io.read.fullRegion, and we + // now have an additional io description for the cut off region. + // Note that the cut-method used above takes care of the corresponding + // WRITE region for us. + + // cutoff.write.region cutoff.read.region + // | io.write.region | io.read.region + // | | | | + // V V V V + // +-+-----+ +-+-----+ + // | | | | | |--------+ + // | | | | | | | + // | | | | | | | + // +-+-----+ +-+-----+ | + // | | <-- io.read.fullRegion + // | | + // +--------------+ + + if (cutoff.read.region.area() > 0) { + // Wrap by repeating + PixelRegion::Side oppositeSide = static_cast((i + 2) % 4); + + cutoff.read.region.align( + oppositeSide, io.read.fullRegion.edge(oppositeSide)); + + // Example: + // The cut off region is wrapped to the opposite side of the region, + // i.e. "repeated". Note that we don't want WRITE region to change, + // we're only wrapping the READ region. + + // cutoff.write.region io.read.region cutoff.read.region + // | io.write.region | | + // | | V V + // V V +-----+ +-+ + // +-+-----+ | |------| | + // | | | | | | | + // | | | | | | | + // | | | +-----+ +-+ + // +-+-----+ | | <-- io.read.fullRegion + // | | + // +--------------+ + + // Example: + // The cutoff region has been repeated along one of its sides, but + // as we can see in this example, it still has a top part outside the + // defined gdal region. This is handled through recursion. + RawTile::ReadError err = repeatedRasterRead( + rasterBand, cutoff, dataDestination, depth + 1); + + worstError = std::max(worstError, err); + } + } + } + + RawTile::ReadError err = rasterRead(rasterBand, io, dataDestination); + + // The return error from a repeated rasterRead is ONLY based on the main region, + // which in the usual case will cover the main area of the patch anyway + return err; +} + +std::shared_ptr RawTileDataReader::getTileMetaData( + std::shared_ptr rawTile, const PixelRegion& region) +{ + ensureInitialized(); + size_t bytesPerLine = _dataLayout.bytesPerPixel * region.numPixels.x; + + TileMetaData* preprocessData = new TileMetaData(); + preprocessData->maxValues.resize(_dataLayout.numRasters); + preprocessData->minValues.resize(_dataLayout.numRasters); + preprocessData->hasMissingData.resize(_dataLayout.numRasters); + + std::vector noDataValues; + noDataValues.resize(_dataLayout.numRasters); + + for (size_t raster = 0; raster < _dataLayout.numRasters; ++raster) { + preprocessData->maxValues[raster] = -FLT_MAX; + preprocessData->minValues[raster] = FLT_MAX; + preprocessData->hasMissingData[raster] = false; + noDataValues[raster] = noDataValueAsFloat(); + } + + for (size_t y = 0; y < region.numPixels.y; ++y) { + size_t yi = (region.numPixels.y - 1 - y) * bytesPerLine; + size_t i = 0; + for (size_t x = 0; x < region.numPixels.x; ++x) { + for (size_t raster = 0; raster < _dataLayout.numRasters; ++raster) { + float noDataValue = noDataValueAsFloat(); + float val = tiledatatype::interpretFloat( + _dataLayout.glType, + &(rawTile->imageData[yi + i]) + ); + if (val != noDataValue) { + preprocessData->maxValues[raster] = std::max( + val, + preprocessData->maxValues[raster] + ); + preprocessData->minValues[raster] = std::min( + val, + preprocessData->minValues[raster] + ); + } + else { + preprocessData->hasMissingData[raster] = true; + } + i += _dataLayout.bytesPerDatum; + } + } + } + + return std::shared_ptr(preprocessData); +} + +float RawTileDataReader::depthOffset() const { + return 0.0f; +} + +float RawTileDataReader::depthScale() const { + return 1.0f; +} + +TileDepthTransform RawTileDataReader::calculateTileDepthTransform() { + bool isFloat = + (_dataLayout.glType == GL_FLOAT || _dataLayout.glType == GL_DOUBLE); + double maximumValue = + isFloat ? 1.0 : tiledatatype::getMaximumValue(_dataLayout.glType); + + TileDepthTransform transform; + transform.depthOffset = depthOffset(); + transform.depthScale = depthScale() * maximumValue; + return transform; +} + +RawTile::ReadError RawTileDataReader::postProcessErrorCheck( + std::shared_ptr rawTile, const IODescription& io) +{ + ensureInitialized(); + + double missingDataValue = noDataValueAsFloat(); + + bool hasMissingData = false; + + for (size_t c = 0; c < _dataLayout.numRasters; c++) { + hasMissingData |= rawTile->tileMetaData->maxValues[c] == missingDataValue; + } + + bool onHighLevel = rawTile->tileIndex.level > 6; + if (hasMissingData && onHighLevel) { + return RawTile::ReadError::Fatal; + } + return RawTile::ReadError::None; +} + +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.h b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.h new file mode 100644 index 0000000000..5a6d2ea3ae --- /dev/null +++ b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.h @@ -0,0 +1,180 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_GLOBEBROWSING___RAW_TILE_DATA_READER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___RAW_TILE_DATA_READER___H__ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace openspace { +namespace globebrowsing { + +class GeodeticPatch; + +class RawTileDataReader { +public: + struct Configuration { + bool doPreProcessing; + int tilePixelSize; + GLuint dataType = 0; // default = no datatype reinterpretation + }; + + RawTileDataReader(const Configuration& config); + virtual ~RawTileDataReader() = default; + + /** + * Reads data from the current dataset and initializes a RawTile + * which gets returned. + */ + std::shared_ptr readTileData(TileIndex tileIndex); + TileDepthTransform getDepthTransform() const; + + /** + * \returns the maximum chunk level available in the dataset. Should be a value + * between 2 and 31. + */ + virtual int maxChunkLevel() = 0; + + /** + * Reset the dataset to its initial state. This is the place to clear any cache used. + */ + virtual void reset() = 0; + virtual float noDataValueAsFloat() const = 0; + virtual int rasterXSize() const = 0; + virtual int rasterYSize() const = 0; + virtual float depthOffset() const; + virtual float depthScale() const; + + /** + * Returns a single channeled empty RawTile of size 16 * 16 pixels. + */ + std::shared_ptr defaultTileData(); + + const static glm::ivec2 tilePixelStartOffset; + const static glm::ivec2 tilePixelSizeDifference; + + /// Padding around all tiles to read to make sure edge blending works. + const static PixelRegion padding; // same as the two above + +protected: + + /** + * This function should set the variables _cached, + * _dataLayout and _depthTransform. + */ + virtual void initialize() = 0; + + /** + * Call this in the constructor of the class extending RawTileDataReader + */ + void ensureInitialized(); + + /** + * The function returns a transform to map + * the pixel coordinates to cover the whole geodetic lat long space. + */ + virtual std::array getGeoTransform() const; + + /** + * Read image data as described by the given IODescription. + * \param io describes how to read the data. + * \param worstError should be set to the error code returned when + * reading the data. + */ + virtual char* readImageData( + IODescription& io, RawTile::ReadError& worstError) const = 0; + + virtual RawTile::ReadError rasterRead( + int rasterBand, const IODescription& io, char* dst) const = 0; + + virtual IODescription getIODescription(const TileIndex& tileIndex) const = 0; + + /** + * Get the pixel corresponding to a specific position on the globe defined by the + * Geodetic2 coordinate geo. If the dataset has overviews + * the function returns the pixel at the lowest overview (highest resolution). + * \param geo is the position on the globe to convert to pixel space. + * \returns a pixel coordinate in the dataset. + */ + PixelRegion::PixelCoordinate geodeticToPixel(const Geodetic2& geo) const; + + /** + * Get the geodetic coordinate corresponding to the given pixel in the dataset. If + * The dataset has overviews it is the lowest overview that is used. That is the + * one with highest resolution. + */ + Geodetic2 pixelToGeodetic(const PixelRegion::PixelCoordinate& p) const; + + /** + * Get a pixel region corresponding to the given GeodeticPatch. If the + * dataset has overviews the function returns the pixel region at the lowest overview + * (highest resolution). + * \param geodeticPatch is a patch covering an area in geodetic + * coordinates + * \returns a PixelRegion covering the given geodetic patch at highest + * resolution. + */ + PixelRegion highestResPixelRegion(const GeodeticPatch& geodeticPatch) const; + + /** + * A recursive function that is able to perform wrapping in case the read region of + * the given IODescription is outside of the given write region. + */ + RawTile::ReadError repeatedRasterRead( + int rasterBand, const IODescription& io, char* dst, int depth = 0) const; + + std::shared_ptr getTileMetaData( + std::shared_ptr result, const PixelRegion& region); + TileDepthTransform calculateTileDepthTransform(); + RawTile::ReadError postProcessErrorCheck( + std::shared_ptr ioResult, const IODescription& io); + + struct Cached { + int _maxLevel = -1; + double _tileLevelDifference; + } _cached; + const Configuration _config; + TileDataLayout _dataLayout; + TileDepthTransform _depthTransform; + +private: + bool _hasBeenInitialized; +}; + +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___RAW_TILE_DATA_READER___H__ diff --git a/modules/globebrowsing/tile/rawtiledatareader/simplerawtiledatareader.cpp b/modules/globebrowsing/tile/rawtiledatareader/simplerawtiledatareader.cpp new file mode 100644 index 0000000000..096624fc25 --- /dev/null +++ b/modules/globebrowsing/tile/rawtiledatareader/simplerawtiledatareader.cpp @@ -0,0 +1,184 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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 // abspath +#include +#include +#include + +#include + +namespace { + const std::string _loggerCat = "SimpleRawTileDataReader"; +} + +namespace openspace { +namespace globebrowsing { + +SimpleRawTileDataReader::SimpleRawTileDataReader( + const std::string& filePath, const Configuration& config) + : RawTileDataReader(config) +{ + _datasetFilePath = filePath; + ensureInitialized(); +} + +void SimpleRawTileDataReader::reset() { + initialize(); +} + +int SimpleRawTileDataReader::maxChunkLevel() { + return _cached._maxLevel; +} + +float SimpleRawTileDataReader::noDataValueAsFloat() const { + return 0.0f; +} + +int SimpleRawTileDataReader::rasterXSize() const { + return _dataTexture->dimensions().x; +} + +int SimpleRawTileDataReader::rasterYSize() const { + return _dataTexture->dimensions().y; +} + +float SimpleRawTileDataReader::depthOffset() const { + return 0.0f; +} + +float SimpleRawTileDataReader::depthScale() const { + return 1.0f; +} + +IODescription SimpleRawTileDataReader::getIODescription(const TileIndex& tileIndex) const { + IODescription io; + io.read.overview = 0; + io.read.region = highestResPixelRegion(tileIndex); + io.read.fullRegion = PixelRegion({0, 0}, {rasterXSize(), rasterYSize()}); + io.write.region = PixelRegion({0, 0}, io.read.region.numPixels); + io.write.bytesPerLine = _dataTexture->bytesPerPixel() * io.write.region.numPixels.x; + io.write.totalNumBytes = io.write.bytesPerLine * io.write.region.numPixels.y; + + return io; +} + +void SimpleRawTileDataReader::initialize() { + _dataTexture = ghoul::io::TextureReader::ref().loadTexture(_datasetFilePath); + if (_dataTexture == nullptr) { + throw ghoul::RuntimeError( + "Unable to read dataset: " + _datasetFilePath + + ".\nCompiling OpenSpace with GDAL will allow for better support for different" + "formats." + ); + } + float exponentX = log2(_dataTexture->dimensions().x); + float exponentY = log2(_dataTexture->dimensions().y); + if ( (exponentX - static_cast(exponentX)) > 0.0001 || + (exponentY - static_cast(exponentY)) > 0.0001 ) { + throw ghoul::RuntimeError( + "Unable to read dataset: " + _datasetFilePath + + ".\nCurrently only supporting power of 2 textures." + ); + } + + _cached._maxLevel = 2; + _cached._tileLevelDifference = 0; + + _dataLayout.glType = _dataTexture->dataType(); + _dataLayout.bytesPerDatum = tiledatatype::numberOfBytes(_dataLayout.glType); + _dataLayout.numRasters = tiledatatype::numberOfRasters(_dataTexture->format()); + _dataLayout.numRastersAvailable = _dataLayout.numRasters; + _dataLayout.bytesPerPixel = _dataLayout.bytesPerDatum * _dataLayout.numRasters; + _dataLayout.textureFormat = {_dataTexture->format(), _dataTexture->internalFormat()}; + + _depthTransform = {depthScale(), depthOffset()}; +} + +char* SimpleRawTileDataReader::readImageData( + IODescription& io, RawTile::ReadError& worstError) const { + // allocate memory for the image + char* imageData = new char[io.write.totalNumBytes]; + + // In case there are extra channels not existing in the dataset + // we set the bytes to 255 (for example an extra alpha channel that) + // needs to be 1. + if (_dataLayout.numRasters > _dataLayout.numRastersAvailable) { + memset(imageData, 255, io.write.totalNumBytes); + } + + // Modify to match OpenGL texture layout: + IODescription modifiedIO = io; + modifiedIO.read.region.start.y = modifiedIO.read.fullRegion.numPixels.y - modifiedIO.read.region.numPixels.y - modifiedIO.read.region.start.y; + + RawTile::ReadError err = repeatedRasterRead(0, modifiedIO, imageData); + + // None = 0, Debug = 1, Warning = 2, Failure = 3, Fatal = 4 + worstError = std::max(worstError, err); + + return imageData; +} + +RawTile::ReadError SimpleRawTileDataReader::rasterRead( + int rasterBand, const IODescription& io, char* dataDestination) const +{ + ghoul_assert(io.read.fullRegion.numPixels.x == _dataTexture->dimensions().x, + "IODescription does not match data texture."); + ghoul_assert(io.read.fullRegion.numPixels.y == _dataTexture->dimensions().y, + "IODescription does not match data texture."); + ghoul_assert(io.read.region.numPixels.x == io.write.region.numPixels.x, + "IODescription does not match data texture."); + ghoul_assert(io.read.region.numPixels.y == io.write.region.numPixels.y, + "IODescription does not match data texture."); + + char* pixelWriteRow = dataDestination; + try { + // For each row + for (int y = 0; y < io.read.region.numPixels.y; y++) { + int bytesPerLineDataTexture = + _dataTexture->bytesPerPixel() * _dataTexture->dimensions().x; + const char* textureRow = (static_cast(_dataTexture->pixelData()) + + io.read.region.start.x * _dataTexture->bytesPerPixel()) + + io.read.region.start.y * bytesPerLineDataTexture + + y * bytesPerLineDataTexture; + memcpy(pixelWriteRow, textureRow, io.write.bytesPerLine); + pixelWriteRow += io.write.bytesPerLine; + } + } catch (const std::exception&) { + return RawTile::ReadError::Failure; + } + return RawTile::ReadError::None; +} + + +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/tiledatalayout.cpp b/modules/globebrowsing/tile/rawtiledatareader/simplerawtiledatareader.h similarity index 61% rename from modules/globebrowsing/tile/tiledatalayout.cpp rename to modules/globebrowsing/tile/rawtiledatareader/simplerawtiledatareader.h index f20a626f3e..cd3a86831e 100644 --- a/modules/globebrowsing/tile/tiledatalayout.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/simplerawtiledatareader.h @@ -22,71 +22,61 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include - -#include - -#include -#include - -#include -#include // abspath -#include +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___SIMPLE_RAW_TILE_DATA_READER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___SIMPLE_RAW_TILE_DATA_READER___H__ +#include #include -#include - - -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include #include +#include #include #include -#include -#include -#include -namespace { - const std::string _loggerCat = "TileDataset"; -} +#include + +#include +#include +#include + +#include namespace openspace { namespace globebrowsing { -TileDataLayout::TileDataLayout() {} +class GeodeticPatch; -TileDataLayout::TileDataLayout(GDALDataset* dataSet, GLuint preferredGlType) { - // Assume all raster bands have the same data type - gdalType =preferredGlType != 0 ? - tiledatatype::getGdalDataType(preferredGlType) : - dataSet->GetRasterBand(1)->GetRasterDataType(); +class SimpleRawTileDataReader : public RawTileDataReader { +public: + + SimpleRawTileDataReader(const std::string& filePath, const Configuration& config); + + // Public virtual function overloading + virtual void reset() override; + virtual int maxChunkLevel() override; + virtual float noDataValueAsFloat() const override; + virtual int rasterXSize() const override; + virtual int rasterYSize() const override; + virtual float depthOffset() const override; + virtual float depthScale() const override; + +protected: + + virtual IODescription getIODescription(const TileIndex& tileIndex) const override; + +private: + // Private virtual function overloading + virtual void initialize() override; + virtual char* readImageData( + IODescription& io, RawTile::ReadError& worstError) const override; + virtual RawTile::ReadError rasterRead( + int rasterBand, const IODescription& io, char* dst) const override; + + // Member variables + std::string _datasetFilePath; + std::unique_ptr _dataTexture; +}; - glType = tiledatatype::getOpenGLDataType(gdalType); - numRasters = dataSet->GetRasterCount(); - bytesPerDatum = tiledatatype::numberOfBytes(gdalType); - bytesPerPixel = bytesPerDatum * numRasters; - textureFormat = tiledatatype::getTextureFormat(numRasters, gdalType); -} - } // namespace globebrowsing } // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___SIMPLE_RAW_TILE_DATA_READER___H__ diff --git a/modules/globebrowsing/tile/tiledatatype.cpp b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp similarity index 59% rename from modules/globebrowsing/tile/tiledatatype.cpp rename to modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp index 8cebef5b31..9530ebe676 100644 --- a/modules/globebrowsing/tile/tiledatatype.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp @@ -22,10 +22,12 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include +#ifdef GLOBEBROWSING_USE_GDAL #include #include +#endif // GLOBEBROWSING_USE_GDAL #include #include // abspath @@ -39,13 +41,15 @@ #include namespace { - const std::string _loggerCat = "RawTile"; + const char* _loggerCat = "TileDataType"; } namespace openspace { namespace globebrowsing { namespace tiledatatype { +#ifdef GLOBEBROWSING_USE_GDAL + float interpretFloat(GDALDataType gdalType, const char* src) { switch (gdalType) { case GDT_Byte: @@ -85,7 +89,6 @@ size_t numberOfBytes(GDALDataType gdalType) { return sizeof(GLdouble); default: ghoul_assert(false, "Unknown data type"); - } } @@ -103,7 +106,6 @@ size_t getMaximumValue(GDALDataType gdalType) { return 1 << 31; default: ghoul_assert(false, "Unknown data type"); - } } @@ -233,6 +235,132 @@ TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType) { return format; } +TextureFormat getTextureFormatOptimized(int rasterCount, GDALDataType gdalType) { + TextureFormat format; + + switch (rasterCount) { + case 1: // Red + format.ghoulFormat = ghoul::opengl::Texture::Format::Red; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_R8; + break; + case GDT_UInt16: + format.glFormat = GL_R16UI; + break; + case GDT_Int16: + format.glFormat = GL_R16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_R32UI; + break; + case GDT_Int32: + format.glFormat = GL_R32I; + break; + case GDT_Float32: + format.glFormat = GL_R32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 2: + format.ghoulFormat = ghoul::opengl::Texture::Format::RG; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RG8; + break; + case GDT_UInt16: + format.glFormat = GL_RG16UI; + break; + case GDT_Int16: + format.glFormat = GL_RG16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RG32UI; + break; + case GDT_Int32: + format.glFormat = GL_RG32I; + break; + case GDT_Float32: + format.glFormat = GL_RG32F; + break; + case GDT_Float64: + format.glFormat = GL_RED; + break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 3: + format.ghoulFormat = ghoul::opengl::Texture::Format::BGR; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RGB8; + break; + case GDT_UInt16: + format.glFormat = GL_RGB16UI; + break; + case GDT_Int16: + format.glFormat = GL_RGB16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RGB32UI; + break; + case GDT_Int32: + format.glFormat = GL_RGB32I; + break; + case GDT_Float32: + format.glFormat = GL_RGB32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 4: + format.ghoulFormat = ghoul::opengl::Texture::Format::BGRA; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RGBA8; + break; + case GDT_UInt16: + format.glFormat = GL_RGBA16UI; + break; + case GDT_Int16: + format.glFormat = GL_RGB16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RGBA32UI; + break; + case GDT_Int32: + format.glFormat = GL_RGBA32I; + break; + case GDT_Float32: + format.glFormat = GL_RGBA32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + default: + LERROR("Unknown number of channels for OpenGL texture: " << rasterCount); + break; + } + return format; +} + GLuint getOpenGLDataType(GDALDataType gdalType) { switch (gdalType) { case GDT_Byte: @@ -277,6 +405,70 @@ GDALDataType getGdalDataType(GLuint glType) { } } +#endif // GLOBEBROWSING_USE_GDAL + +size_t numberOfRasters(ghoul::opengl::Texture::Format format) { + switch (format) { + case ghoul::opengl::Texture::Format::Red: return 1; + case ghoul::opengl::Texture::Format::RG: return 2; + case ghoul::opengl::Texture::Format::RGB: return 3; + case ghoul::opengl::Texture::Format::RGBA: return 4; + default: ghoul_assert(false, "Unknown format"); + } +} + +size_t numberOfBytes(GLuint glType) { + switch (glType) { + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + case GL_UNSIGNED_SHORT: return sizeof(GLushort); + case GL_SHORT: return sizeof(GLshort); + case GL_UNSIGNED_INT: return sizeof(GLuint); + case GL_INT: return sizeof(GLint); + case GL_FLOAT: return sizeof(GLfloat); + case GL_DOUBLE: return sizeof(GLdouble); + default: + ghoul_assert(false, "Unknown data type"); + } +} + +size_t getMaximumValue(GLuint glType) { + switch (glType) { + case GL_UNSIGNED_BYTE: + return 1 << 8; + case GL_UNSIGNED_SHORT: + return 1 << 16; + case GL_SHORT: + return 1 << 15; + case GL_UNSIGNED_INT: + return size_t(1) << 32; + case GL_INT: + return 1 << 31; + default: + ghoul_assert(false, "Unknown data type"); + } +} + +float interpretFloat(GLuint glType, const char* src) { + switch (glType) { + case GL_UNSIGNED_BYTE: + return static_cast(*reinterpret_cast(src)); + case GL_UNSIGNED_SHORT: + return static_cast(*reinterpret_cast(src)); + case GL_SHORT: + return static_cast(*reinterpret_cast(src)); + case GL_UNSIGNED_INT: + return static_cast(*reinterpret_cast(src)); + case GL_INT: + return static_cast(*reinterpret_cast(src)); + case GL_FLOAT: + return static_cast(*reinterpret_cast(src)); + case GL_DOUBLE: + return static_cast(*reinterpret_cast(src)); + default: + ghoul_assert(false, "Unknown data type"); + } +} + } // namespace tiledatatype } // namespace globebrowsing } // namespace openspace diff --git a/modules/globebrowsing/tile/tiledatatype.h b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h similarity index 87% rename from modules/globebrowsing/tile/tiledatatype.h rename to modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h index fd92aa07e0..26bee1a670 100644 --- a/modules/globebrowsing/tile/tiledatatype.h +++ b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h @@ -26,28 +26,32 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ #include - #include #include +#ifdef GLOBEBROWSING_USE_GDAL #include +#endif // GLOBEBROWSING_USE_GDAL namespace openspace { namespace globebrowsing { namespace tiledatatype { +#ifdef GLOBEBROWSING_USE_GDAL GLuint getOpenGLDataType(GDALDataType gdalType); - GDALDataType getGdalDataType(GLuint glType); - TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType); - +TextureFormat getTextureFormatOptimized(int rasterCount, GDALDataType gdalType); size_t getMaximumValue(GDALDataType gdalType); - size_t numberOfBytes(GDALDataType gdalType); - float interpretFloat(GDALDataType gdalType, const char* src); +#endif // GLOBEBROWSING_USE_GDAL + +size_t numberOfRasters(ghoul::opengl::Texture::Format format); +size_t numberOfBytes(GLuint glType); +size_t getMaximumValue(GLuint glType); +float interpretFloat(GLuint glType, const char* src); } // namespace tiledatatype } // namespace globebrowsing diff --git a/modules/globebrowsing/tile/textureformat.h b/modules/globebrowsing/tile/textureformat.h index 4149b14a33..f90867213d 100644 --- a/modules/globebrowsing/tile/textureformat.h +++ b/modules/globebrowsing/tile/textureformat.h @@ -33,7 +33,7 @@ namespace globebrowsing { struct TextureFormat { ghoul::opengl::Texture::Format ghoulFormat; - GLuint glFormat; + GLint glFormat; }; diff --git a/modules/globebrowsing/tile/tile.cpp b/modules/globebrowsing/tile/tile.cpp index fb9307557e..6b0cd1ad53 100644 --- a/modules/globebrowsing/tile/tile.cpp +++ b/modules/globebrowsing/tile/tile.cpp @@ -22,9 +22,10 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include -#include +#include +#include namespace { const std::string _loggerCat = "Tile"; @@ -33,8 +34,22 @@ namespace { namespace openspace { namespace globebrowsing { -const Tile Tile::TileUnavailable = {nullptr, nullptr, Tile::Status::Unavailable }; - +const Tile Tile::TileUnavailable = Tile(nullptr, nullptr, Tile::Status::Unavailable); + +Tile::Tile(std::shared_ptr texture, + std::shared_ptr metaData, Status status) + : MemoryAwareCacheable( + (sizeof(Tile) + + (metaData ? sizeof(TileMetaData) : 0) + + (texture ? sizeof(ghoul::opengl::Texture) + texture->expectedPixelDataSize() * 2 : 0)) + // Multiply by two since double memory is used when creating mip maps. + / 1000 // Convert from bytes to kilobytes + ) + , _texture(texture) + , _metaData(metaData) + , _status(status) +{} + Tile Tile::createPlainTile(const glm::uvec2& size, const glm::uvec4& color) { using namespace ghoul::opengl; @@ -58,13 +73,9 @@ Tile Tile::createPlainTile(const glm::uvec2& size, const glm::uvec4& color) { texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); // Create tile - Tile tile; - tile.status = Tile::Status::OK; - tile.metaData = nullptr; - tile.texture = texture; - + Tile tile(texture, nullptr, Tile::Status::OK); return tile; -} +} glm::vec2 Tile::compensateSourceTextureSampling(glm::vec2 startOffset, glm::vec2 sizeDiff, glm::uvec2 resolution, glm::vec2 tileUV) @@ -81,8 +92,8 @@ glm::vec2 Tile::TileUvToTextureSamplePosition(const TileUvTransform& uvTransform { glm::vec2 uv = uvTransform.uvOffset + uvTransform.uvScale * tileUV; uv = compensateSourceTextureSampling( - TileDataset::tilePixelStartOffset, - TileDataset::tilePixelSizeDifference, + RawTileDataReader::tilePixelStartOffset, + RawTileDataReader::tilePixelSizeDifference, resolution, uv); return uv; diff --git a/modules/globebrowsing/tile/tile.h b/modules/globebrowsing/tile/tile.h index 5db9f53385..211c11d9c1 100644 --- a/modules/globebrowsing/tile/tile.h +++ b/modules/globebrowsing/tile/tile.h @@ -26,9 +26,10 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___TILE___H__ #include - #include +#include + #include namespace ghoul { namespace opengl { @@ -44,42 +45,49 @@ struct TileUvTransform; /** * Defines a status and may have a Texture and TileMetaData */ -struct Tile { - std::shared_ptr texture; - std::shared_ptr metaData; - - /** +class Tile : public cache::MemoryAwareCacheable { +public: + /** * Describe if this Tile is good for usage (OK) or otherwise * the reason why it is not. */ - enum class Status { - /** - * E.g when texture data is not currently in memory. + enum class Status { + /** + * E.g when texture data is not currently in memory. * texture and tileMetaData are both null */ - Unavailable, + Unavailable, /** - * Can be set by TileProviders if the requested - * TileIndex is undefined for that particular - * provider. + * Can be set by TileProviders if the requested + * TileIndex is undefined for that particular + * provider. * texture and metaData are both null */ - OutOfRange, + OutOfRange, /** * An IO Error happend * texture and metaData are both null */ - IOError, + IOError, /** * The Texture is uploaded to the GPU and good for usage. * texture is defined. metaData may be defined. */ - OK - } status; - + OK + }; + + Tile(std::shared_ptr texture, + std::shared_ptr metaData, + Status status); + ~Tile() = default; + + std::shared_ptr metaData() const { return _metaData; }; + Status status() const { return _status; }; + std::shared_ptr texture() const { return _texture; }; + /** * Instantiates a new tile with a single color. * @@ -90,18 +98,20 @@ struct Tile { * with the requested size and color */ static Tile createPlainTile(const glm::uvec2& size, const glm::uvec4& color); - static glm::vec2 compensateSourceTextureSampling(glm::vec2 startOffset, glm::vec2 sizeDiff, glm::uvec2 resolution, glm::vec2 tileUV); - static glm::vec2 TileUvToTextureSamplePosition(const TileUvTransform& uvTransform, glm::vec2 tileUV, glm::uvec2 resolution); - /** - * A tile with status unavailable that any user can return to - * indicate that a tile was unavailable. - */ + * A tile with status unavailable that any user can return to + * indicate that a tile was unavailable. + */ static const Tile TileUnavailable; + +private: + std::shared_ptr _texture; + std::shared_ptr _metaData; + Status _status; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/tile/tiledatalayout.h b/modules/globebrowsing/tile/tiledatalayout.h index a030b13c13..06108e8f46 100644 --- a/modules/globebrowsing/tile/tiledatalayout.h +++ b/modules/globebrowsing/tile/tiledatalayout.h @@ -30,22 +30,21 @@ #include #include -#include - class GDALDataset; namespace openspace { namespace globebrowsing { struct TileDataLayout { - TileDataLayout(); - TileDataLayout(GDALDataset* dataSet, GLuint preferredGlType); - - GDALDataType gdalType; GLuint glType; size_t bytesPerDatum; size_t numRasters; + /// Number of rasters available in the GDAL dataset. + /// Does not necessarily have to be equal to numRasters. + /// In case an extra alpha channel needs to be added that + /// does not exist in the GDAL dataset for example + size_t numRastersAvailable; size_t bytesPerPixel; TextureFormat textureFormat; diff --git a/modules/globebrowsing/tile/tiledatareader/tiledatareader.cpp b/modules/globebrowsing/tile/tiledatareader/tiledatareader.cpp new file mode 100644 index 0000000000..b6f3a14033 --- /dev/null +++ b/modules/globebrowsing/tile/tiledatareader/tiledatareader.cpp @@ -0,0 +1,150 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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 + +namespace { + const char* _loggerCat = "TileDataReader"; +} + +namespace openspace { +namespace globebrowsing { + +std::ostream& operator<<(std::ostream& os, const PixelRegion& pr) { + return os << pr.start.x << ", " << pr.start.y << + " with size " << pr.numPixels.x << ", " << pr.numPixels.y; +} + +TileDataReader::TileDataReader(const Configuration& config) + : _config(config) +{} + +std::shared_ptr TileDataReader::defaultTileData() { + ensureInitialized(); + PixelRegion pixelRegion = { + PixelRegion::PixelCoordinate(0, 0), + PixelRegion::PixelRange(16, 16) + }; + std::shared_ptr rawTile = std::make_shared(); + rawTile->tileIndex = { 0, 0, 0 }; + rawTile->dimensions = glm::uvec3(pixelRegion.numPixels, 1); + rawTile->nBytesImageData = + rawTile->dimensions.x * rawTile->dimensions.y * _dataLayout.bytesPerPixel; + rawTile->imageData = new char[rawTile->nBytesImageData]; + for (size_t i = 0; i < rawTile->nBytesImageData; ++i) { + rawTile->imageData[i] = 0; + } + rawTile->error = RawTile::ReadError::None; + + if (_config.doPreProcessing) { + rawTile->tileMetaData = getTileMetaData(rawTile, pixelRegion); + } + + return rawTile; +} + +std::array TileDataset::getGeoTransform() const { + std::array padfTransform; + + // Global coverage of the whole latlon space + GeodeticPatch globalCoverage(Geodetic2(0,0), Geodetic2(M_PI / 2, M_PI)); + padfTransform[1] = Angle::fromRadians( + globalCoverage.size().lon).asDegrees() / rasterXSize(); + padfTransform[5] = -Angle::fromRadians( + globalCoverage.size().lat).asDegrees() / rasterYSize(); + padfTransform[0] = Angle::fromRadians( + globalCoverage.getCorner(Quad::NORTH_WEST).lon).asDegrees(); + padfTransform[3] = Angle::fromRadians( + globalCoverage.getCorner(Quad::NORTH_WEST).lat).asDegrees(); + padfTransform[2] = 0; + padfTransform[4] = 0; + + return padfTransform; +} + +PixelRegion::PixelCoordinate TileDataReader::geodeticToPixel(const Geodetic2& geo) const { + std::array padfTransform = getGeoTransform(); + + double Y = Angle::fromRadians(geo.lat).asDegrees(); + double X = Angle::fromRadians(geo.lon).asDegrees(); + + // convert from pixel and line to geodetic coordinates + // Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2]; + // Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5]; + + // <=> + double* a = &(padfTransform[0]); + double* b = &(padfTransform[3]); + + // Xp = a[0] + P*a[1] + L*a[2]; + // Yp = b[0] + P*b[1] + L*b[2]; + + // <=> + double divisor = (a[2] * b[1] - a[1] * b[2]); + ghoul_assert(divisor != 0.0, "Division by zero!"); + //ghoul_assert(a[2] != 0.0, "a2 must not be zero!"); + double P = (a[0] * b[2] - a[2] * b[0] + a[2] * Y - b[2] * X) / divisor; + double L = (-a[0] * b[1] + a[1] * b[0] - a[1] * Y + b[1] * X) / divisor; + // ref: https://www.wolframalpha.com/input/?i=X+%3D+a0+%2B+a1P+%2B+a2L,+Y+%3D+b0+%2B+b1P+%2B+b2L,+solve+for+P+and+L + + double Xp = a[0] + P*a[1] + L*a[2]; + double Yp = b[0] + P*b[1] + L*b[2]; + + ghoul_assert(abs(X - Xp) < 1e-10, "inverse should yield X as before"); + ghoul_assert(abs(Y - Yp) < 1e-10, "inverse should yield Y as before"); + + return PixelRegion::PixelCoordinate(glm::round(P), glm::round(L)); +} + +Geodetic2 TileDataReader::pixelToGeodetic(const PixelRegion::PixelCoordinate& p) const { + std::array padfTransform = getGeoTransform(); + Geodetic2 geodetic; + // Should be using radians and not degrees? + geodetic.lon = padfTransform[0] + p.x * padfTransform[1] + p.y * padfTransform[2]; + geodetic.lat = padfTransform[3] + p.x * padfTransform[4] + p.y * padfTransform[5]; + return geodetic; +} + +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/tiledatareader/tiledatareader.h b/modules/globebrowsing/tile/tiledatareader/tiledatareader.h new file mode 100644 index 0000000000..316db41839 --- /dev/null +++ b/modules/globebrowsing/tile/tiledatareader/tiledatareader.h @@ -0,0 +1,92 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_GLOBEBROWSING___TILE_DATAREADER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATAREADER___H__ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace openspace { +namespace globebrowsing { + +struct RawTile; +class GeodeticPatch; + +/** + * Interface for reading RawTiles given a TileIndex + */ +class TileDataReader { +public: + struct Configuration { + bool doPreProcessing; + int minimumTilePixelSize; + GLuint dataType = 0; // default = no datatype reinterpretation + }; + + virtual TileDataReader(const Configuration& config); + + std::shared_ptr defaultTileData(); + + virtual std::shared_ptr readTileData(TileIndex tileIndex) = 0; + virtual int maxChunkLevel() = 0; + virtual TileDepthTransform getDepthTransform() = 0; + virtual const TileDataLayout& getDataLayout() = 0; + virtual void reset() = 0; + virtual float noDataValueAsFloat() = 0; + virtual size_t rasterXSize() = 0; + virtual size_t rasterYSize() = 0; + + const static glm::ivec2 tilePixelStartOffset; + const static glm::ivec2 tilePixelSizeDifference; + const static PixelRegion padding; // same as the two above + + const static glm::ivec2 tilePixelStartOffset; + const static glm::ivec2 tilePixelSizeDifference; + const static PixelRegion padding; // same as the two above + + static bool logReadErrors; + +protected: + Configuration _config; + + virtual std::array padfTransform getGeoTransform(); + PixelRegion::PixelCoordinate geodeticToPixel(const Geodetic2& geo) const; + Geodetic2 pixelToGeodetic(const PixelRegion::PixelCoordinate& p) const; +}; + +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATAREADER___H__ diff --git a/modules/globebrowsing/tile/tiledataset.cpp b/modules/globebrowsing/tile/tiledataset.cpp deleted file mode 100644 index 9934234346..0000000000 --- a/modules/globebrowsing/tile/tiledataset.cpp +++ /dev/null @@ -1,823 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * 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 // abspath -#include - -#include -#include - - -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - const std::string _loggerCat = "TileDataset"; -} - -namespace openspace { -namespace globebrowsing { - -std::ostream& operator<<(std::ostream& os, const PixelRegion& pr) { - return os << pr.start.x << ", " << pr.start.y << " with size " << pr.numPixels.x << ", " << pr.numPixels.y; -} - -TileDataset::IODescription TileDataset::IODescription::cut(PixelRegion::Side side, int pos) { - PixelRegion readPreCut = read.region; - PixelRegion writePreCut = write.region; - - glm::dvec2 ratio; - ratio.x = write.region.numPixels.x / (double) read.region.numPixels.x; - ratio.y = write.region.numPixels.y / (double) read.region.numPixels.y; - -// double ratioRatio = ratio.x / ratio.y; - - //ghoul_assert(glm::abs(ratioRatio - 1.0) < 0.01, "Different read/write aspect ratio!"); - - IODescription whatCameOff = *this; - whatCameOff.read.region = read.region.globalCut(side, pos); - - PixelRegion::PixelRange cutSize = whatCameOff.read.region.numPixels; - PixelRegion::PixelRange localWriteCutSize = ratio * glm::dvec2(cutSize); - - if (cutSize.x == 0 || cutSize.y == 0) { - ghoul_assert( - read.region.equals(readPreCut), - "Read region should not have been modified" - ); - ghoul_assert( - write.region.equals(writePreCut), - "Write region should not have been modified" - ); - } - - int localWriteCutPos = (side == PixelRegion::Side::LEFT || side == PixelRegion::Side::RIGHT) - ? localWriteCutSize.x : localWriteCutSize.y; - whatCameOff.write.region = write.region.localCut(side, localWriteCutPos); - - return whatCameOff; -} - -const glm::ivec2 TileDataset::tilePixelStartOffset = glm::ivec2(-2); -const glm::ivec2 TileDataset::tilePixelSizeDifference = glm::ivec2(4); - -const PixelRegion TileDataset::padding = PixelRegion( - tilePixelStartOffset, - tilePixelSizeDifference -); - -bool TileDataset::GdalHasBeenInitialized = false; - -TileDataset::TileDataset(const std::string& gdalDatasetDesc, const Configuration& config) - : _config(config) - , hasBeenInitialized(false) -{ - _initData = { "", gdalDatasetDesc, config.minimumTilePixelSize, config.dataType }; - ensureInitialized(); - _initData.initDirectory = CPLGetCurrentDir(); -} - -void TileDataset::reset() { - _cached._maxLevel = -1; - if (_dataset != nullptr) { - GDALClose((GDALDatasetH)_dataset); - } - - initialize(); -} - -float TileDataset::noDataValueAsFloat() { - float noDataValue; - if (_dataset && _dataset->GetRasterBand(1)) { - noDataValue = _dataset->GetRasterBand(1)->GetNoDataValue();; - } - else { - noDataValue = std::numeric_limits::min(); - } - return noDataValue; -} - -void TileDataset::ensureInitialized() { - if (!hasBeenInitialized) { - initialize(); - hasBeenInitialized = true; - } - -} - -void TileDataset::initialize() { - gdalEnsureInitialized(); - - _dataset = gdalDataset(_initData.gdalDatasetDesc); - - //Do any other initialization needed for the TileDataset - _dataLayout = TileDataLayout(_dataset, _initData.dataType); - _depthTransform = calculateTileDepthTransform(); - _cached._tileLevelDifference = calculateTileLevelDifference(_initData.minimumPixelSize); -} - -void TileDataset::gdalEnsureInitialized() { - if (!GdalHasBeenInitialized) { - GDALAllRegister(); - CPLSetConfigOption( - "GDAL_DATA", - absPath("${MODULE_GLOBEBROWSING}/gdal_data").c_str() - ); - setGdalProxyConfiguration(); - GdalHasBeenInitialized = true; - } -} - -void TileDataset::setGdalProxyConfiguration() { - ghoul::Dictionary proxySettings; - bool proxyEnabled = OsEng.configurationManager().getValue( - ConfigurationManager::KeyHttpProxy, proxySettings - ); - if (proxyEnabled) { - std::string proxyAddress, proxyPort, proxyUser, proxyPassword, proxyAuth; - - bool success = proxySettings.getValue( - ConfigurationManager::PartHttpProxyAddress, - proxyAddress - ); - success &= proxySettings.getValue( - ConfigurationManager::PartHttpProxyPort, - proxyPort - ); - proxySettings.getValue( - ConfigurationManager::PartHttpProxyAuthentication, - proxyAuth - ); - - std::string proxyAuthString = "BASIC"; - if (proxyAuth == "basic" || proxyAuth == "") { - proxyAuthString = "BASIC"; - } else if (proxyAuth == "ntlm") { - proxyAuthString = "NTLM"; - } else if (proxyAuth == "digest") { - proxyAuthString = "DIGEST"; - } else if (proxyAuth == "any") { - proxyAuthString = "ANY"; - } else { - success = false; - } - - bool userAndPassword = proxySettings.getValue( - ConfigurationManager::PartHttpProxyUser, - proxyUser - ); - userAndPassword &= proxySettings.getValue( - ConfigurationManager::PartHttpProxyPassword, - proxyPassword - ); - - if (success) { - std::string proxy = proxyAddress + ":" + proxyPort; - CPLSetConfigOption("GDAL_HTTP_PROXY", proxy.c_str()); - LDEBUG("Using proxy server " << proxy); - if (userAndPassword) { - std::string proxyUserPwd = proxyUser + ":" + proxyPassword; - CPLSetConfigOption("GDAL_HTTP_PROXYUSERPWD", proxyUserPwd.c_str()); - CPLSetConfigOption("GDAL_HTTP_PROXYAUTH", proxyAuthString.c_str()); - LDEBUG("Using authentication method: " << proxyAuthString); - } - } else { - LERROR("Invalid proxy settings for GDAL"); - } - } else { - LDEBUG("Setting up GDAL without proxy server"); - } -} - -GDALDataset* TileDataset::gdalDataset(const std::string& gdalDatasetDesc) { - GDALDataset* dataset = (GDALDataset *)GDALOpen(gdalDatasetDesc.c_str(), GA_ReadOnly); - if (!dataset) { - using namespace ghoul::filesystem; - std::string correctedPath = FileSystem::ref().pathByAppendingComponent( - _initData.initDirectory, gdalDatasetDesc - ); - dataset = (GDALDataset *)GDALOpen(correctedPath.c_str(), GA_ReadOnly); - if (!dataset) { - throw ghoul::RuntimeError("Failed to load dataset:\n" + gdalDatasetDesc); - } - } - - // Commenting away the following for now since it is not supported for older - // versions of GDAL. Only used for debug info. - /* - const std::string originalDriverName = dataset->GetDriverName(); - - if (originalDriverName != "WMS") { - LDEBUG(" " << originalDriverName); - LDEBUG(" " << dataset->GetGCPProjection()); - LDEBUG(" " << dataset->GetProjectionRef()); - - GDALDriver* driver = dataset->GetDriver(); - char** metadata = driver->GetMetadata(); - for (int i = 0; metadata[i] != nullptr; i++) { - LDEBUG(" " << metadata[i]); - } - - const char* in_memory = ""; - //GDALDataset* vrtDataset = driver->CreateCopy(in_memory, dataset, false, nullptr, nullptr, nullptr); - } - */ - - return dataset; -} - -TileDataset::~TileDataset() { - delete _dataset; -} - -std::shared_ptr TileDataset::readTileData(TileIndex tileIndex) { - ensureInitialized(); - IODescription io = getIODescription(tileIndex); - CPLErr worstError = CPLErr::CE_None; - - // Build the RawTile from the data we querred - std::shared_ptr rawTile = std::make_shared(); - rawTile->imageData = readImageData(io, worstError); - rawTile->error = worstError; - rawTile->tileIndex = tileIndex; - rawTile->dimensions = glm::uvec3(io.write.region.numPixels, 1); - rawTile->nBytesImageData = io.write.totalNumBytes; - - if (_config.doPreProcessing) { - rawTile->tileMetaData = getTileMetaData(rawTile, io.write.region); - rawTile->error = std::max(rawTile->error, postProcessErrorCheck(rawTile, io)); - } - - return rawTile; -} - -std::shared_ptr TileDataset::defaultTileData() { - ensureInitialized(); - PixelRegion pixelRegion = { - PixelRegion::PixelCoordinate(0, 0), - PixelRegion::PixelRange(16, 16) - }; - std::shared_ptr rawTile = std::make_shared(); - rawTile->tileIndex = { 0, 0, 0 }; - rawTile->dimensions = glm::uvec3(pixelRegion.numPixels, 1); - rawTile->nBytesImageData = - rawTile->dimensions.x * rawTile->dimensions.y * _dataLayout.bytesPerPixel; - rawTile->imageData = new char[rawTile->nBytesImageData]; - for (size_t i = 0; i < rawTile->nBytesImageData; ++i) { - rawTile->imageData[i] = 0; - } - rawTile->error = CPLErr::CE_None; - - if (_config.doPreProcessing) { - rawTile->tileMetaData = getTileMetaData(rawTile, pixelRegion); - //rawTile->error = std::max(rawTile->error, postProcessErrorCheck(rawTile, io)); - } - - return rawTile; -} - -int TileDataset::maxChunkLevel() { - ensureInitialized(); - if (_cached._maxLevel < 0) { - int numOverviews = _dataset->GetRasterBand(1)->GetOverviewCount(); - _cached._maxLevel = -_cached._tileLevelDifference; - if (numOverviews > 0) { - _cached._maxLevel += numOverviews - 1; - } - } - return _cached._maxLevel; -} - -TileDepthTransform TileDataset::getDepthTransform() { - ensureInitialized(); - return _depthTransform; -} - -const TileDataLayout& TileDataset::getDataLayout() { - ensureInitialized(); - return _dataLayout; -} - -int TileDataset::calculateTileLevelDifference(int minimumPixelSize) { - GDALRasterBand* firstBand = _dataset->GetRasterBand(1); - GDALRasterBand* maxOverview; - int numOverviews = firstBand->GetOverviewCount(); - int sizeLevel0; - if (numOverviews <= 0) { // No overviews. Use first band. - maxOverview = firstBand; - } - else { // Pick the highest overview. - maxOverview = firstBand->GetOverview(numOverviews - 1); - } - sizeLevel0 = maxOverview->GetXSize(); - double diff = log2(minimumPixelSize) - log2(sizeLevel0); - return diff; -} - -TileDepthTransform TileDataset::calculateTileDepthTransform() { - GDALRasterBand* firstBand = _dataset->GetRasterBand(1); - - bool isFloat = - (_dataLayout.gdalType == GDT_Float32 || _dataLayout.gdalType == GDT_Float64); - double maximumValue = - isFloat ? 1.0 : tiledatatype::getMaximumValue(_dataLayout.gdalType); - - TileDepthTransform transform; - transform.depthOffset = firstBand->GetOffset(); - transform.depthScale = firstBand->GetScale() * maximumValue; - return transform; -} - -bool TileDataset::gdalHasOverviews() const { - return _dataset->GetRasterBand(1)->GetOverviewCount() > 0; -} - -int TileDataset::gdalOverview(const PixelRegion::PixelRange& regionSizeOverviewZero) const { - GDALRasterBand* firstBand = _dataset->GetRasterBand(1); - - int minNumPixels0 = glm::min(regionSizeOverviewZero.x, regionSizeOverviewZero.y); - - int overviews = firstBand->GetOverviewCount(); - GDALRasterBand* maxOverview = - overviews ? firstBand->GetOverview(overviews - 1) : firstBand; - - int sizeLevel0 = maxOverview->GetXSize(); - // The dataset itself may not have overviews but even if it does not, an overview - // for the data region can be calculated and possibly be used to sample greater - // Regions of the original dataset. - int ov = std::log2(minNumPixels0) - std::log2(sizeLevel0 + 1) - - _cached._tileLevelDifference; - ov = glm::clamp(ov, 0, overviews - 1); - - return ov; -} - -int TileDataset::gdalOverview(const TileIndex& tileIndex) const { - int overviews = _dataset->GetRasterBand(1)->GetOverviewCount(); - int ov = overviews - (tileIndex.level + _cached._tileLevelDifference + 1); - return glm::clamp(ov, 0, overviews - 1); -} - -int TileDataset::gdalVirtualOverview(const TileIndex& tileIndex) const { - int overviews = _dataset->GetRasterBand(1)->GetOverviewCount(); - int ov = overviews - (tileIndex.level + _cached._tileLevelDifference + 1); - return ov; -} - -PixelRegion TileDataset::gdalPixelRegion(GDALRasterBand* rasterBand) const { - PixelRegion gdalRegion; - gdalRegion.start.x = 0; - gdalRegion.start.y = 0; - gdalRegion.numPixels.x = rasterBand->GetXSize(); - gdalRegion.numPixels.y = rasterBand->GetYSize(); - return gdalRegion; -} - -PixelRegion TileDataset::gdalPixelRegion(const GeodeticPatch& geodeticPatch) const { - Geodetic2 nwCorner = geodeticPatch.getCorner(Quad::NORTH_WEST); - Geodetic2 swCorner = geodeticPatch.getCorner(Quad::SOUTH_EAST); - PixelRegion::PixelCoordinate pixelStart = geodeticToPixel(nwCorner); - PixelRegion::PixelCoordinate pixelEnd = geodeticToPixel(swCorner); - PixelRegion gdalRegion(pixelStart, pixelEnd - pixelStart); - return gdalRegion; -} - -GDALRasterBand* TileDataset::gdalRasterBand(int overview, int raster) const { - GDALRasterBand* rasterBand = _dataset->GetRasterBand(raster); -// int numberOfOverviews = rasterBand->GetOverviewCount(); - rasterBand = gdalHasOverviews() ? rasterBand->GetOverview(overview) : rasterBand; - ghoul_assert(rasterBand != nullptr, "Rasterband is null"); - return rasterBand; -} - -std::array TileDataset::getGeoTransform() const { - std::array padfTransform; - CPLErr err = _dataset->GetGeoTransform(&padfTransform[0]); - if (err == CE_Failure) { - GeodeticPatch globalCoverage(Geodetic2(0,0), Geodetic2(M_PI / 2, M_PI)); - padfTransform[1] = Angle::fromRadians( - globalCoverage.size().lon).asDegrees() / _dataset->GetRasterXSize(); - padfTransform[5] = -Angle::fromRadians( - globalCoverage.size().lat).asDegrees() / _dataset->GetRasterYSize(); - padfTransform[0] = Angle::fromRadians( - globalCoverage.getCorner(Quad::NORTH_WEST).lon).asDegrees(); - padfTransform[3] = Angle::fromRadians( - globalCoverage.getCorner(Quad::NORTH_WEST).lat).asDegrees(); - padfTransform[2] = 0; - padfTransform[4] = 0; - } - return padfTransform; -} - -PixelRegion::PixelCoordinate TileDataset::geodeticToPixel(const Geodetic2& geo) const { - std::array padfTransform = getGeoTransform(); - - double Y = Angle::fromRadians(geo.lat).asDegrees(); - double X = Angle::fromRadians(geo.lon).asDegrees(); - - // convert from pixel and line to geodetic coordinates - // Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2]; - // Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5]; - - // <=> - double* a = &(padfTransform[0]); - double* b = &(padfTransform[3]); - - // Xp = a[0] + P*a[1] + L*a[2]; - // Yp = b[0] + P*b[1] + L*b[2]; - - // <=> - double divisor = (a[2] * b[1] - a[1] * b[2]); - ghoul_assert(divisor != 0.0, "Division by zero!"); - //ghoul_assert(a[2] != 0.0, "a2 must not be zero!"); - double P = (a[0] * b[2] - a[2] * b[0] + a[2] * Y - b[2] * X) / divisor; - double L = (-a[0] * b[1] + a[1] * b[0] - a[1] * Y + b[1] * X) / divisor; - // ref: https://www.wolframalpha.com/input/?i=X+%3D+a0+%2B+a1P+%2B+a2L,+Y+%3D+b0+%2B+b1P+%2B+b2L,+solve+for+P+and+L - - double Xp = a[0] + P*a[1] + L*a[2]; - double Yp = b[0] + P*b[1] + L*b[2]; - - ghoul_assert(abs(X - Xp) < 1e-10, "inverse should yield X as before"); - ghoul_assert(abs(Y - Yp) < 1e-10, "inverse should yield Y as before"); - - return PixelRegion::PixelCoordinate(glm::round(P), glm::round(L)); -} - -Geodetic2 TileDataset::pixelToGeodetic(const PixelRegion::PixelCoordinate& p) const { - std::array padfTransform = getGeoTransform(); - Geodetic2 geodetic; - // Should be using radians and not degrees? - geodetic.lon = padfTransform[0] + p.x * padfTransform[1] + p.y * padfTransform[2]; - geodetic.lat = padfTransform[3] + p.x * padfTransform[4] + p.y * padfTransform[5]; - return geodetic; -} - -TileDataset::IODescription TileDataset::getIODescription(const TileIndex& tileIndex) const { - IODescription io; - io.read.region = gdalPixelRegion(tileIndex); - - if (gdalHasOverviews()) { - int overview = gdalOverview(tileIndex); - io.read.overview = overview; - io.read.region.downscalePow2(overview + 1); - io.write.region = io.read.region; - io.read.region.pad(padding); - } - else { - io.read.overview = 0; - io.write.region = io.read.region; - int virtualOverview = gdalVirtualOverview(tileIndex); - io.write.region.downscalePow2(virtualOverview + 1); - PixelRegion scaledPadding = padding; - - scaledPadding.upscalePow2(std::max(virtualOverview + 1, 0)); - io.read.region.pad(scaledPadding); - } - - // For correct sampling in height dataset, we need to pad the texture tile - io.write.region.pad(padding); - PixelRegion::PixelRange preRound = io.write.region.numPixels; - io.write.region.roundDownToQuadratic(); - io.write.region.roundUpNumPixelToNearestMultipleOf(2); - if (preRound != io.write.region.numPixels) { - LDEBUG(tileIndex << " | " << preRound.x << ", " << preRound.y << " --> " << io.write.region.numPixels.x << ", " << io.write.region.numPixels.y); - } - - io.write.region.start = PixelRegion::PixelCoordinate(0, 0); // write region starts in origin - io.write.bytesPerLine = _dataLayout.bytesPerPixel * io.write.region.numPixels.x; - io.write.totalNumBytes = io.write.bytesPerLine * io.write.region.numPixels.y; - - return io; -} - -char* TileDataset::readImageData(IODescription& io, CPLErr& worstError) const { - // allocate memory for the image - char* imageData = new char[io.write.totalNumBytes]; - - // Read the data (each rasterband is a separate channel) - for (size_t i = 0; i < _dataLayout.numRasters; i++) { - GDALRasterBand* rasterBand = gdalRasterBand(io.read.overview, i + 1); - - // The final destination pointer is offsetted by one datum byte size - // for every raster (or data channel, i.e. R in RGB) - char* dataDestination = imageData + (i * _dataLayout.bytesPerDatum); - - CPLErr err = repeatedRasterIO(rasterBand, io, dataDestination); - - // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 - worstError = std::max(worstError, err); - } - - // GDAL reads pixel lines top to bottom, we want the opposit - return imageData; -} - -CPLErr TileDataset::repeatedRasterIO(GDALRasterBand* rasterBand, const IODescription& fullIO, char* dataDestination, int depth) const { - std::string spaces = " "; - std::string indentation = spaces.substr(0, 2 * depth); - - CPLErr worstError = CPLErr::CE_None; - - // NOTE: - // Ascii graphics illustrates the implementation details of this method, for one - // specific case. Even though the illustrated case is specific, readers can - // hopefully find it useful to get the general idea. - - // Make a copy of the full IO desription as we will have to modify it - IODescription io = fullIO; - PixelRegion gdalRegion = gdalPixelRegion(rasterBand); - - - // Example: - // We have an io description that defines a WRITE and a READ region. - // In this case the READ region extends outside of the defined gdal region, - // meaning we will have to do wrapping - - - // io.write.region io.read.region - // | | - // V V - // +-------+ +-------+ - // | | | |--------+ - // | | | | | - // | | | | | - // +-------+ +-------+ | - // | | <-- gdalRegion - // | | - // +--------------+ - - - //LDEBUG(indentation << "-"); - //LDEBUG(indentation << "repeated read: " << io.read.region); - //LDEBUG(indentation << "repeated write: " << io.write.region); - - bool didCutOff = false; - - if (!io.read.region.isInside(gdalRegion)) { - // Loop through each side: left, top, right, bottom - for (int i = 0; i < 4; ++i) { - - // Example: - // We are currently considering the left side of the pixel region - PixelRegion::Side side = (PixelRegion::Side) i; - IODescription cutoff = io.cut(side, gdalRegion.edge(side)); - - // Example: - // We cut off the left part that was outside the gdal region, and we now - // have an additional io description for the cut off region. - // Note that the cut-method used above takes care of the corresponding - // WRITE region for us. - - // cutoff.write.region cutoff.read.region - // | io.write.region | io.read.region - // | | | | - // V V V V - // +-+-----+ +-+-----+ - // | | | | | |--------+ - // | | | | | | | - // | | | | | | | - // +-+-----+ +-+-----+ | - // | | <-- gdalRegion - // | | - // +--------------+ - - if (cutoff.read.region.area() > 0) { -// didCutOff = true; - - // Wrap by repeating - PixelRegion::Side oppositeSide = (PixelRegion::Side) ((i + 2) % 4); - - cutoff.read.region.align(oppositeSide, gdalRegion.edge(oppositeSide)); - - // Example: - // The cut off region is wrapped to the opposite side of the region, - // i.e. "repeated". Note that we don't want WRITE region to change, - // we're only wrapping the READ region. - - // cutoff.write.region io.read.region cutoff.read.region - // | io.write.region | | - // | | V V - // V V +-----+ +-+ - // +-+-----+ | |------| | - // | | | | | | | - // | | | | | | | - // | | | +-----+ +-+ - // +-+-----+ | | <-- gdalRegion - // | | - // +--------------+ - - // Example: - // The cutoff region has been repeated along one of its sides, but - // as we can see in this example, it still has a top part outside the - // defined gdal region. This is handled through recursion. - CPLErr err = repeatedRasterIO(rasterBand, cutoff, dataDestination, depth + 1); - - worstError = std::max(worstError, err); - } - } - } - else if (worstError > CPLErr::CE_None) { - LDEBUG(indentation << "Error reading padding: " << worstError); - } - - CPLErr err = rasterIO(rasterBand, io, dataDestination); -// worstError = std::max(worstError, err); - - // The return error from a repeated rasterIO is ONLY based on the main region, - // which in the usual case will cover the main area of the patch anyway - - return err; -} - -CPLErr TileDataset::rasterIO(GDALRasterBand* rasterBand, const IODescription& io, - char* dataDestination) const -{ - PixelRegion gdalRegion = gdalPixelRegion(rasterBand); - - ghoul_assert(io.read.region.isInside(gdalRegion), "write region of bounds!"); - ghoul_assert( - io.write.region.start.x >= 0 && io.write.region.start.y >= 0, - "Invalid write region" - ); - - PixelRegion::PixelCoordinate end = io.write.region.end(); - size_t largestIndex = - (end.y - 1) * io.write.bytesPerLine + (end.x - 1) * _dataLayout.bytesPerPixel; - ghoul_assert(largestIndex <= io.write.totalNumBytes, "Invalid write region"); - - char* dataDest = dataDestination; - - // OBS! GDAL reads pixels top to bottom, but we want our pixels bottom to top. - // Therefore, we increment the destination pointer to the last line on in the - // buffer, and the we specify in the rasterIO call that we want negative line - // spacing. Doing this compensates the flipped Y axis - dataDest += (io.write.totalNumBytes - io.write.bytesPerLine); - - // handle requested write region - dataDest -= io.write.region.start.y * io.write.bytesPerLine; // note -= since flipped y axis - dataDest += io.write.region.start.x * _dataLayout.bytesPerPixel; - - return rasterBand->RasterIO( - GF_Read, - io.read.region.start.x, // Begin read x - io.read.region.start.y, // Begin read y - io.read.region.numPixels.x, // width to read x - io.read.region.numPixels.y, // width to read y - dataDest, // Where to put data - io.write.region.numPixels.x, // width to write x in destination - io.write.region.numPixels.y, // width to write y in destination - _dataLayout.gdalType, // Type - _dataLayout.bytesPerPixel, // Pixel spacing - -io.write.bytesPerLine // Line spacing - ); -} - -std::shared_ptr TileDataset::getTileMetaData( - std::shared_ptr rawTile, - const PixelRegion& region) const -{ - size_t bytesPerLine = _dataLayout.bytesPerPixel * region.numPixels.x; -// size_t totalNumBytes = bytesPerLine * region.numPixels.y; - - TileMetaData* preprocessData = new TileMetaData(); - preprocessData->maxValues.resize(_dataLayout.numRasters); - preprocessData->minValues.resize(_dataLayout.numRasters); - preprocessData->hasMissingData.resize(_dataLayout.numRasters); - - std::vector noDataValues; - noDataValues.resize(_dataLayout.numRasters); - - for (size_t c = 0; c < _dataLayout.numRasters; c++) { - preprocessData->maxValues[c] = -FLT_MAX; - preprocessData->minValues[c] = FLT_MAX; - preprocessData->hasMissingData[c] = false; - noDataValues[c] = _dataset->GetRasterBand(1)->GetNoDataValue(); - } - - for (size_t y = 0; y < region.numPixels.y; y++) { - size_t yi = (region.numPixels.y - 1 - y) * bytesPerLine; - size_t i = 0; - for (size_t x = 0; x < region.numPixels.x; x++) { - for (size_t c = 0; c < _dataLayout.numRasters; c++) { - float noDataValue = _dataset->GetRasterBand(c + 1)->GetNoDataValue(); - float val = tiledatatype::interpretFloat( - _dataLayout.gdalType, - &(rawTile->imageData[yi + i]) - ); - if (val != noDataValue) { - preprocessData->maxValues[c] = std::max( - val, - preprocessData->maxValues[c] - ); - preprocessData->minValues[c] = std::min( - val, - preprocessData->minValues[c] - ); - } - else { - preprocessData->hasMissingData[c] = true; - } - i += _dataLayout.bytesPerDatum; - } - } - } - - for (size_t c = 0; c < _dataLayout.numRasters; c++) { - if (preprocessData->maxValues[c] > 8800.0f) { - //LDEBUG("Bad preprocess data: " << preprocessData->maxValues[c] << " at " << region.tileIndex); - } - } - - return std::shared_ptr(preprocessData); -} - -CPLErr TileDataset::postProcessErrorCheck(std::shared_ptr rawTile, - const IODescription& io) const -{ - int success; - - double missingDataValue = gdalRasterBand(io.read.overview)->GetNoDataValue(&success); - if (!success) { - // missing data value for TERRAIN.wms. Should be specified in XML - missingDataValue = 32767; - } - - bool hasMissingData = false; - - for (size_t c = 0; c < _dataLayout.numRasters; c++) { - hasMissingData |= rawTile->tileMetaData->maxValues[c] == missingDataValue; - } - - bool onHighLevel = rawTile->tileIndex.level > 6; - if (hasMissingData && onHighLevel) { - return CE_Fatal; - } - // ugly test for heightmap overlay - if (_dataLayout.textureFormat.ghoulFormat == ghoul::opengl::Texture::Format::RG) { - // check the alpha - if (rawTile->tileMetaData->maxValues[1] == 0.0 - && rawTile->tileMetaData->minValues[1] == 0.0) - { - //return CE_Warning; - } - } - return CE_None; -} - -} // namespace globebrowsing -} // namespace openspace diff --git a/modules/globebrowsing/tile/tiledataset.h b/modules/globebrowsing/tile/tiledataset.h deleted file mode 100644 index 6bc692884d..0000000000 --- a/modules/globebrowsing/tile/tiledataset.h +++ /dev/null @@ -1,188 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * 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_GLOBEBROWSING___TILE_DATASET___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATASET___H__ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -class GDALDataset; -class GDALRasterBand; - -namespace openspace { -namespace globebrowsing { - -class RawTile; -class GeodeticPatch; - -class TileDataset { -public: - struct Configuration { - bool doPreProcessing; - int minimumTilePixelSize; - GLuint dataType = 0; // default = no datatype reinterpretation - }; - - - /** - * Opens a GDALDataset in readonly mode and calculates meta data required for - * reading tile using a TileIndex. - * - * \param gdalDatasetDesc - A path to a specific file or raw XML describing the dataset - * \param minimumPixelSize - minimum number of pixels per side per tile requested - * \param datatype - datatype for storing pixel data in requested tile - */ - TileDataset(const std::string& gdalDatasetDesc, const Configuration& config); - - ~TileDataset(); - - - ////////////////////////////////////////////////////////////////////////////////// - // Public interface // - ////////////////////////////////////////////////////////////////////////////////// - std::shared_ptr readTileData(TileIndex tileIndex); - std::shared_ptr defaultTileData(); - int maxChunkLevel(); - TileDepthTransform getDepthTransform(); - const TileDataLayout& getDataLayout(); - void reset(); - float noDataValueAsFloat(); - - - const static glm::ivec2 tilePixelStartOffset; - const static glm::ivec2 tilePixelSizeDifference; - const static PixelRegion padding; // same as the two above - - -private: - struct IODescription { - struct ReadData { - int overview; - PixelRegion region; - } read; - - struct WriteData { - PixelRegion region; - size_t bytesPerLine; - size_t totalNumBytes; - } write; - - IODescription cut(PixelRegion::Side side, int pos); - }; - - - ////////////////////////////////////////////////////////////////////////////////// - // Initialization // - ////////////////////////////////////////////////////////////////////////////////// - - void initialize(); - void ensureInitialized(); - TileDepthTransform calculateTileDepthTransform(); - int calculateTileLevelDifference(int minimumPixelSize); - - - ////////////////////////////////////////////////////////////////////////////////// - // GDAL helper methods // - ////////////////////////////////////////////////////////////////////////////////// - - void gdalEnsureInitialized(); - void setGdalProxyConfiguration(); - GDALDataset* gdalDataset(const std::string& gdalDatasetDesc); - bool gdalHasOverviews() const; - int gdalOverview(const PixelRegion::PixelRange& baseRegionSize) const; - int gdalOverview(const TileIndex& tileIndex) const; - int gdalVirtualOverview(const TileIndex& tileIndex) const; - PixelRegion gdalPixelRegion(const GeodeticPatch& geodeticPatch) const; - PixelRegion gdalPixelRegion(GDALRasterBand* rasterBand) const; - GDALRasterBand* gdalRasterBand(int overview, int raster = 1) const; - - - ////////////////////////////////////////////////////////////////////////////////// - // ReadTileData helper functions // - ////////////////////////////////////////////////////////////////////////////////// - - /** - Returns the geo transform from raster space to projection coordinates as defined - by GDAL. - - If the transform is not available, the function returns a transform to map - the pixel coordinates to cover the whole geodetic lat long space. - */ - std::array getGeoTransform() const; - - PixelRegion::PixelCoordinate geodeticToPixel(const Geodetic2& geo) const; - Geodetic2 pixelToGeodetic(const PixelRegion::PixelCoordinate& p) const; - IODescription getIODescription(const TileIndex& tileIndex) const; - char* readImageData(IODescription& io, CPLErr& worstError) const; - CPLErr rasterIO(GDALRasterBand* rasterBand, const IODescription& io, char* dst) const; - CPLErr repeatedRasterIO(GDALRasterBand* rasterBand, const IODescription& io, char* dst, int depth = 0) const; - std::shared_ptr getTileMetaData(std::shared_ptr result, const PixelRegion& region) const; - CPLErr postProcessErrorCheck(std::shared_ptr ioResult, const IODescription& io) const; - - - - ////////////////////////////////////////////////////////////////////////////////// - // Member variables // - ////////////////////////////////////////////////////////////////////////////////// - - // init data - struct InitData { - std::string initDirectory; - std::string gdalDatasetDesc; - int minimumPixelSize; - GLuint dataType; - } _initData; - - struct Cached { - int _maxLevel = -1; - double _tileLevelDifference; - } _cached; - - const Configuration _config; - - - GDALDataset* _dataset; - TileDepthTransform _depthTransform; - TileDataLayout _dataLayout; - - static bool GdalHasBeenInitialized; - bool hasBeenInitialized; -}; - -} // namespace globebrowsing -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATASET___H__ diff --git a/modules/globebrowsing/tile/tilemetadata.cpp b/modules/globebrowsing/tile/tilemetadata.cpp index 6c6c2b344e..2b7e20d9eb 100644 --- a/modules/globebrowsing/tile/tilemetadata.cpp +++ b/modules/globebrowsing/tile/tilemetadata.cpp @@ -24,8 +24,6 @@ #include -#include - namespace openspace { namespace globebrowsing { @@ -53,7 +51,7 @@ TileMetaData TileMetaData::deserialize(std::istream& is) { is >> res.minValues[i]; } - return std::move(res); + return res; } } // namespace globebrowsing diff --git a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.cpp b/modules/globebrowsing/tile/tileprovider/cachingtileprovider.cpp index 407843dabd..509bd60bf1 100644 --- a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/cachingtileprovider.cpp @@ -24,21 +24,23 @@ #include -#include -#include +#include +#include +#include +#include #include +#include #include #include namespace { - const char* _loggerCat = "CachingTileProvider"; - const char* KeyDoPreProcessing = "DoPreProcessing"; - const char* KeyMinimumPixelSize = "MinimumPixelSize"; + const char* KeyTilePixelSize = "TilePixelSize"; const char* KeyFilePath = "FilePath"; - const char* KeyCacheSize = "CacheSize"; + const char* KeyBasePath = "BasePath"; const char* KeyFlushInterval = "FlushInterval"; + const char* KeyPreCacheLevel = "PreCacheLevel"; } namespace openspace { @@ -46,7 +48,9 @@ namespace globebrowsing { namespace tileprovider { CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary) - : _framesSinceLastRequestFlush(0) + : TileProvider(dictionary) + , _framesSinceLastRequestFlush(0) + , _defaultTile(Tile::TileUnavailable) { std::string name = "Name unspecified"; dictionary.getValue("Name", name); @@ -59,33 +63,36 @@ CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary) } // 2. Initialize default values for any optional Keys - TileDataset::Configuration config; + RawTileDataReader::Configuration config; config.doPreProcessing = false; - config.minimumTilePixelSize = 512; + config.tilePixelSize = 512; // getValue does not work for integers - double minimumPixelSize; - double cacheSize = 512; + double minimumPixelSize; double framesUntilRequestFlush = 60; // 3. Check for used spcified optional keys if (dictionary.getValue(KeyDoPreProcessing, config.doPreProcessing)) { LDEBUG("Default doPreProcessing overridden: " << config.doPreProcessing); } - if (dictionary.getValue(KeyMinimumPixelSize, minimumPixelSize)) { + if (dictionary.getValue(KeyTilePixelSize, minimumPixelSize)) { LDEBUG("Default minimumPixelSize overridden: " << minimumPixelSize); - config.minimumTilePixelSize = static_cast(minimumPixelSize); - } - if (dictionary.getValue(KeyCacheSize, cacheSize)) { - LDEBUG("Default cacheSize overridden: " << cacheSize); + config.tilePixelSize = static_cast(minimumPixelSize); } if (dictionary.getValue(KeyFlushInterval, framesUntilRequestFlush)) { LDEBUG("Default framesUntilRequestFlush overridden: " << framesUntilRequestFlush); } + std::string basePath; + dictionary.getValue(KeyBasePath, basePath); + // Initialize instance variables - auto tileDataset = std::make_shared(filePath, config); +#ifdef GLOBEBROWSING_USE_GDAL + auto tileDataset = std::make_shared(filePath, config, basePath); +#else // GLOBEBROWSING_USE_GDAL + auto tileDataset = std::make_shared(filePath, config); +#endif // GLOBEBROWSING_USE_GDAL // only one thread per provider supported atm // (GDAL does not handle multiple threads for a single dataset very well @@ -94,18 +101,28 @@ CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary) _asyncTextureDataProvider = std::make_shared( tileDataset, threadPool); - _tileCache = std::make_shared(static_cast(cacheSize)); _framesUntilRequestFlush = framesUntilRequestFlush; + + if (dictionary.hasKeyAndValue(KeyPreCacheLevel)) { + int preCacheLevel = static_cast(dictionary.value(KeyPreCacheLevel)); + LDEBUG("Precaching '" << filePath << "' with level '" << preCacheLevel << "'"); + for (int level = 0; level <= preCacheLevel; ++level) { + for (int x = 0; x <= level * 2; ++x) { + for (int y = 0; y <= level; ++y) { + _asyncTextureDataProvider->enqueueTileIO({ x, y, level }); + } + } + } + } } CachingTileProvider::CachingTileProvider( std::shared_ptr tileReader, - std::shared_ptr tileCache, int framesUntilFlushRequestQueue) : _asyncTextureDataProvider(tileReader) - , _tileCache(tileCache) , _framesUntilRequestFlush(framesUntilFlushRequestQueue) , _framesSinceLastRequestFlush(0) + , _defaultTile(Tile::TileUnavailable) {} CachingTileProvider::~CachingTileProvider(){ @@ -120,32 +137,29 @@ void CachingTileProvider::update() { } void CachingTileProvider::reset() { - _tileCache->clear(); - _asyncTextureDataProvider->reset(); + cache::MemoryAwareTileCache::ref().clear(); + //_asyncTextureDataProvider->reset(); } int CachingTileProvider::maxLevel() { - return _asyncTextureDataProvider->getTextureDataProvider()->maxChunkLevel(); + return _asyncTextureDataProvider->getRawTileDataReader()->maxChunkLevel(); } Tile CachingTileProvider::getTile(const TileIndex& tileIndex) { - Tile tile = Tile::TileUnavailable; - if (tileIndex.level > maxLevel()) { - tile.status = Tile::Status::OutOfRange; - return tile; + return Tile(nullptr, nullptr, Tile::Status::OutOfRange); } - TileIndex::TileHashKey key = tileIndex.hashKey(); + cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; - if (_tileCache->exist(key)) { - return _tileCache->get(key); + if (cache::MemoryAwareTileCache::ref().exist(key)) { + return cache::MemoryAwareTileCache::ref().get(key); } else { _asyncTextureDataProvider->enqueueTileIO(tileIndex); } - return tile; + return Tile::TileUnavailable; } float CachingTileProvider::noDataValueAsFloat() { @@ -153,20 +167,20 @@ float CachingTileProvider::noDataValueAsFloat() { } Tile CachingTileProvider::getDefaultTile() { - if (_defaultTile.texture == nullptr) { + if (_defaultTile.texture() == nullptr) { _defaultTile = createTile( - _asyncTextureDataProvider->getTextureDataProvider()->defaultTileData() + _asyncTextureDataProvider->getRawTileDataReader()->defaultTileData() ); } return _defaultTile; } void CachingTileProvider::initTexturesFromLoadedData() { - auto rawTiles = _asyncTextureDataProvider->getRawTiles(); - for (auto rawTile : rawTiles){ - TileIndex::TileHashKey key = rawTile->tileIndex.hashKey(); + std::shared_ptr rawTile = _asyncTextureDataProvider->popFinishedRawTile(); + if (rawTile) { + cache::ProviderTileKey key = { rawTile->tileIndex, uniqueIdentifier() }; Tile tile = createTile(rawTile); - _tileCache->put(key, tile); + cache::MemoryAwareTileCache::ref().put(key, tile); } } @@ -176,56 +190,49 @@ void CachingTileProvider::clearRequestQueue() { } Tile::Status CachingTileProvider::getTileStatus(const TileIndex& tileIndex) { - auto tileDataset = _asyncTextureDataProvider->getTextureDataProvider(); - if (tileIndex.level > tileDataset->maxChunkLevel()) { + auto rawTileDataReader = _asyncTextureDataProvider->getRawTileDataReader(); + if (tileIndex.level > rawTileDataReader->maxChunkLevel()) { return Tile::Status::OutOfRange; } - TileIndex::TileHashKey key = tileIndex.hashKey(); + cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; - if (_tileCache->exist(key)) { - return _tileCache->get(key).status; + if (cache::MemoryAwareTileCache::ref().exist(key)) { + return cache::MemoryAwareTileCache::ref().get(key).status(); } return Tile::Status::Unavailable; } TileDepthTransform CachingTileProvider::depthTransform() { - return _asyncTextureDataProvider->getTextureDataProvider()->getDepthTransform(); + return _asyncTextureDataProvider->getRawTileDataReader()->getDepthTransform(); } Tile CachingTileProvider::createTile(std::shared_ptr rawTile) { - if (rawTile->error != CE_None) { - return{ nullptr, nullptr, Tile::Status::IOError }; + if (rawTile->error != RawTile::ReadError::None) { + return Tile(nullptr, nullptr, Tile::Status::IOError); } -// TileIndex::TileHashKey key = rawTile->tileIndex.hashKey(); - TileDataLayout dataLayout = - _asyncTextureDataProvider->getTextureDataProvider()->getDataLayout(); + //TileDataLayout dataLayout = + // _asyncTextureDataProvider->getTextureDataProvider()->getDataLayout(); // The texture should take ownership of the data using ghoul::opengl::Texture; std::shared_ptr texture = std::make_shared( rawTile->imageData, rawTile->dimensions, - dataLayout.textureFormat.ghoulFormat, - dataLayout.textureFormat.glFormat, - dataLayout.glType, + rawTile->textureFormat.ghoulFormat, + rawTile->textureFormat.glFormat, + rawTile->glType, Texture::FilterMode::Linear, Texture::WrappingMode::ClampToEdge); texture->uploadTexture(); - // AnisotropicMipMap must be set after texture is uploaded. Why?! + // AnisotropicMipMap must be set after texture is uploaded texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - Tile tile = { - texture, - rawTile->tileMetaData, - Tile::Status::OK - }; - - return tile; + return Tile(texture, rawTile->tileMetaData, Tile::Status::OK); } } // namespace tileprovider diff --git a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.h b/modules/globebrowsing/tile/tileprovider/cachingtileprovider.h index 8a1669cf96..b8f836f03e 100644 --- a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.h +++ b/modules/globebrowsing/tile/tileprovider/cachingtileprovider.h @@ -26,12 +26,13 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___CACHING_TILE_PROVIDER___H__ #include +#include namespace openspace { namespace globebrowsing { class AsyncTileDataProvider; -class RawTile; +struct RawTile; namespace tileprovider { @@ -44,8 +45,7 @@ public: CachingTileProvider(const ghoul::Dictionary& dictionary); CachingTileProvider( - std::shared_ptr tileReader, - std::shared_ptr tileCache, + std::shared_ptr tileReader, int framesUntilFlushRequestQueue); virtual ~CachingTileProvider(); @@ -87,7 +87,7 @@ private: void clearRequestQueue(); std::shared_ptr _asyncTextureDataProvider; - std::shared_ptr _tileCache; + //std::shared_ptr _tileCache; int _framesSinceLastRequestFlush; int _framesUntilRequestFlush; diff --git a/modules/globebrowsing/tile/tileprovider/presentationslideprovider.cpp b/modules/globebrowsing/tile/tileprovider/presentationslideprovider.cpp new file mode 100644 index 0000000000..40c2708ea3 --- /dev/null +++ b/modules/globebrowsing/tile/tileprovider/presentationslideprovider.cpp @@ -0,0 +1,118 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include + +namespace { + const std::string _loggerCat = "PresentationSlideProvider"; + + const std::string KeyDefaultProvider = "DefaultProvider"; + const std::string KeySlideProviders = "SlideProviders"; + const std::string KeyTileIndex = "TileIndex"; + const std::string KeyTileProvider = "TileProvider"; +} + +namespace openspace { +namespace globebrowsing { +namespace tileprovider { + +PresentationSlideProvider::PresentationSlideProvider(const ghoul::Dictionary& dictionary) + : _slideIndex("slideIndex", "slideIndex", 0, 0, _slideProviders.size() - 1) +{ + setName("SlideProvider"); + ghoul::Dictionary defaultProviderDict = dictionary.value(KeyDefaultProvider); + _defaultProvider = TileProvider::createFromDictionary(defaultProviderDict); + + ghoul::Dictionary tileIndexDict = dictionary.value(KeyTileIndex); + _tileIndex = TileIndex(tileIndexDict); + + ghoul::Dictionary slideProvidersDict = dictionary.value(KeySlideProviders); + _slideProviders.resize(slideProvidersDict.size()); + for (size_t i = 0; i < slideProvidersDict.size(); i++) { + std::string dictKey = std::to_string(i + 1); + ghoul::Dictionary providerDict = slideProvidersDict.value(dictKey); + _slideProviders[i] = TileProvider::createFromDictionary(providerDict); + } + + _slideIndex.setMaxValue(_slideProviders.size() - 1); + addProperty(_slideIndex); +} + +Tile PresentationSlideProvider::getTile(const TileIndex& tileIndex) { + if(tileIndex == _tileIndex){ + return slideProvider()->getTile(tileIndex); + } + return Tile::TileUnavailable; + +} + +Tile PresentationSlideProvider::getDefaultTile() { + return _defaultProvider->getDefaultTile(); +} + +Tile::Status PresentationSlideProvider::getTileStatus(const TileIndex& tileIndex) { + if(tileIndex == _tileIndex){ + return slideProvider()->getTileStatus(tileIndex); + } + return Tile::Status::Unavailable; +} + +TileDepthTransform PresentationSlideProvider::depthTransform() { + return slideProvider()->depthTransform(); +} + +void PresentationSlideProvider::update() { + slideProvider()->update(); + _defaultProvider->update(); +} + +void PresentationSlideProvider::reset() { + for(auto& tp : _slideProviders){ + tp->reset(); + } + _defaultProvider->reset(); +} + +int PresentationSlideProvider::maxLevel() { + return _defaultProvider->maxLevel(); +} + +TileProvider* PresentationSlideProvider::slideProvider() { + int maxIndex = (int)_slideProviders.size() - 1; + int clampedIndex = std::max(0, std::min(_slideIndex.value(), maxIndex)); + _slideIndex.setValue(clampedIndex); + return _slideProviders[clampedIndex].get(); +} + +} // namespace tileprovider +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/tileprovider/presentationslideprovider.h b/modules/globebrowsing/tile/tileprovider/presentationslideprovider.h new file mode 100644 index 0000000000..facfba7966 --- /dev/null +++ b/modules/globebrowsing/tile/tileprovider/presentationslideprovider.h @@ -0,0 +1,70 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_GLOBEBROWSING___PRESENTATION_SLIDE_PROVIDER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___PRESENTATION_SLIDE_PROVIDER___H__ + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace openspace { +namespace globebrowsing { +namespace tileprovider { + +class PresentationSlideProvider : public TileProvider { +public: + PresentationSlideProvider(const ghoul::Dictionary& dictionary); + PresentationSlideProvider(const std::string& imagePath); + virtual ~PresentationSlideProvider() { } + + virtual Tile getTile(const TileIndex& tileIndex); + virtual Tile getDefaultTile(); + virtual Tile::Status getTileStatus(const TileIndex& index); + virtual TileDepthTransform depthTransform(); + virtual void update(); + virtual void reset(); + virtual int maxLevel(); + +private: + TileProvider* slideProvider(); + + TileIndex _tileIndex; + properties::IntProperty _slideIndex; + std::vector> _slideProviders; + std::unique_ptr _defaultProvider; +}; + +} // namespace tileprovider +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PRESENTATION_SLIDE_PROVIDER___H__ diff --git a/modules/globebrowsing/tile/tileprovider/projectiontileprovider.cpp b/modules/globebrowsing/tile/tileprovider/projectiontileprovider.cpp new file mode 100644 index 0000000000..944c4594ed --- /dev/null +++ b/modules/globebrowsing/tile/tileprovider/projectiontileprovider.cpp @@ -0,0 +1,385 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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 + +namespace { + const char* _loggerCat = "ProjectionTileProvider"; + + const char* keyGeometry = "Geometry"; + const char* keyProjection = "Projection"; + const char* keyMeridianShift = "Textures.MeridianShift"; + const char* keyColorTexture = "Textures.Color"; + const char* keyHeightTexture = "Textures.Height"; + + const char* keyRadius = "Geometry.Radius"; + const char* keyShading = "PerformShading"; + const char* _mainFrame = "GALACTIC"; +} + +namespace openspace { +namespace globebrowsing { +namespace tileprovider { + +/* +documentation::Documentation ProjectionTileProvider::Documentation() { + using namespace openspace::documentation; + return { + "Renderable Planet Projection", + "newhorizons_renderable_planetprojection", + { + { + "Type", + new StringEqualVerifier("RenderablePlanetProjection"), + "", + Optional::No + }, + { + keyGeometry, + new ReferencingVerifier("space_geometry_planet"), + "The geometry that is used for rendering this planet.", + Optional::No + }, + { + keyProjection, + new ReferencingVerifier("newhorizons_projectioncomponent"), + "Contains information about projecting onto this planet.", + Optional::No + }, + { + keyMeridianShift, + new BoolVerifier, + "Determines whether the meridian of the planet should be shifted by 180 " + "degrees. The default value is 'false'", + Optional::Yes + }, + { + keyColorTexture, + new StringVerifier, + "The path to the base color texture that is used on the planet prior to " + "any image projection. The path can use tokens of the form '${...}' or " + "be specified relative to the directory of the mod file.", + Optional::No + }, + { + keyHeightTexture, + new StringVerifier, + "The path to the height map texture that is used on the planet. The path " + "can use tokens of the form '${...}' or be specified relative to the " + "directory of the mod file. If no height map is specified the planet " + "does not use a height field.", + Optional::Yes + } + } + }; +} +*/ + +ProjectionTileProvider::ProjectionTileProvider(const ghoul::Dictionary& dictionary) + : _fboProgramObject(nullptr) + , _capture(false) + , _defaultTile(Tile::TileUnavailable) +{ + + ghoul::Dictionary geometryDictionary; + bool success = dictionary.getValue( + keyGeometry, geometryDictionary); + if (success) { + geometryDictionary.setValue(SceneGraphNode::KeyName, "TestGeometry"); + using planetgeometry::PlanetGeometry; + _geometry = std::unique_ptr( + PlanetGeometry::createFromDictionary(geometryDictionary) + ); + } + + _projectionComponent.initialize(dictionary.value(keyProjection)); + + + addPropertySubOwner(_geometry.get()); + addPropertySubOwner(_projectionComponent); +} + +ProjectionTileProvider::~ProjectionTileProvider(){ + +} + +bool ProjectionTileProvider::initialize() { + bool completeSuccess = true; + completeSuccess &= TileProvider::initialize(); + + _fboProgramObject = ghoul::opengl::ProgramObject::Build("fboPassProgram", + "${MODULE_NEWHORIZONS}/shaders/renderablePlanetProjection_vs.glsl", + "${MODULE_NEWHORIZONS}/shaders/renderablePlanetProjection_fs.glsl" + ); + + completeSuccess &= _projectionComponent.initializeGL(); + completeSuccess &= _geometry->initialize(nullptr); + + if (completeSuccess) { + //completeSuccess &= auxiliaryRendertarget(); + // SCREEN-QUAD + const GLfloat size = 1.f; + const GLfloat w = 1.f; + const GLfloat vertex_data[] = { + -size, -size, 0.f, w, 0.f, 0.f, + size, size, 0.f, w, 1.f, 1.f, + -size, size, 0.f, w, 0.f, 1.f, + -size, -size, 0.f, w, 0.f, 0.f, + size, -size, 0.f, w, 1.f, 0.f, + size, size, 0.f, w, 1.f, 1.f, + }; + + glGenVertexArrays(1, &_quad); + glBindVertexArray(_quad); + glGenBuffers(1, &_vertexPositionBuffer); + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(0)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(sizeof(GLfloat) * 4)); + + glBindVertexArray(0); + } + + return completeSuccess; +} + +bool ProjectionTileProvider::deinitialize() { + _projectionComponent.deinitialize(); + _geometry = nullptr; + + glDeleteVertexArrays(1, &_quad); + glDeleteBuffers(1, &_vertexPositionBuffer); + + _fboProgramObject = nullptr; + + return true; +} + +void ProjectionTileProvider::update() { + // Update + if (_fboProgramObject->isDirty()) { + _fboProgramObject->rebuildFromFile(); + } + + _projectionComponent.update(); + + _time = Time::ref().j2000Seconds(); + _capture = false; + + if (openspace::ImageSequencer::ref().isReady()){ + openspace::ImageSequencer::ref().updateSequencer(_time); + if (_projectionComponent.doesPerformProjection()) { + _capture = openspace::ImageSequencer::ref().getImagePaths( + _imageTimes, + _projectionComponent.projecteeId(), + _projectionComponent.instrumentId() + ); + } + } + + _stateMatrix = glm::dmat3(1.0); + + + + + + + + + + + + + + + // Projection + + if (_projectionComponent.needsClearProjection()) + _projectionComponent.clearAllProjections(); + + _camScaling = glm::vec2(1.0);// data.camera.scaling(); + _up = glm::vec3(0,1,0);// data.camera.lookUpVectorCameraSpace(); + + if (_capture && _projectionComponent.doesPerformProjection()) { + for (const Image& img : _imageTimes) { + attitudeParameters(img.timeRange.start); + imageProjectGPU(_projectionComponent.loadProjectionTexture(img.path)); + } + _capture = false; + } + attitudeParameters(_time); + _imageTimes.clear(); + +} + +void ProjectionTileProvider::reset() { +} + +int ProjectionTileProvider::maxLevel() { + return 3; +} + +Tile ProjectionTileProvider::getTile(const TileIndex& tileIndex) { + _projectionComponent.projectionTexture(); +} + +float ProjectionTileProvider::noDataValueAsFloat() { + +} + +Tile ProjectionTileProvider::getDefaultTile() { + +} + +Tile::Status ProjectionTileProvider::getTileStatus(const TileIndex& tileIndex) { + return Tile::Status::OK; +} + +TileDepthTransform ProjectionTileProvider::depthTransform() { + +} + +void ProjectionTileProvider::attitudeParameters(double time) { + // precomputations for shader + _instrumentMatrix = SpiceManager::ref().positionTransformMatrix( + _projectionComponent.instrumentId(), _mainFrame, time + ); + + _transform = glm::mat4(1); + //90 deg rotation w.r.t spice req. + glm::mat4 rot = glm::rotate( + _transform, + static_cast(M_PI_2), + glm::vec3(1, 0, 0) + ); + glm::mat4 roty = glm::rotate( + _transform, + static_cast(M_PI_2), + glm::vec3(0, -1, 0) + ); + + _transform = glm::mat4(_stateMatrix); + + glm::dvec3 bs; + try { + SpiceManager::FieldOfViewResult res = SpiceManager::ref().fieldOfView(_projectionComponent.instrumentId()); + bs = std::move(res.boresightVector); + } + catch (const SpiceManager::SpiceException& e) { + LERRORC(e.component, e.what()); + return; + } + + double lightTime; + glm::dvec3 p = SpiceManager::ref().targetPosition( + _projectionComponent.projectorId(), + _projectionComponent.projecteeId(), + _mainFrame, + _projectionComponent.aberration(), + time, + lightTime + ); + psc position = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); + + //change to KM and add psc camera scaling. + position[3] += (3 + _camScaling[1]); + //position[3] += 3; + glm::vec3 cpos = position.vec3(); + + float distance = glm::length(cpos); + float radius = 1185000.0f; + + _projectorMatrix = _projectionComponent.computeProjectorMatrix( + cpos, + bs, + _up, + _instrumentMatrix, + _projectionComponent.fieldOfViewY(), + _projectionComponent.aspectRatio(), + distance - radius, + distance + radius, + _boresight + ); +} + +void ProjectionTileProvider::imageProjectGPU( + std::shared_ptr projectionTexture) +{ + _projectionComponent.imageProjectBegin(); + + _fboProgramObject->activate(); + + ghoul::opengl::TextureUnit unitFbo; + unitFbo.activate(); + projectionTexture->bind(); + _fboProgramObject->setUniform("projectionTexture", unitFbo); + + _fboProgramObject->setUniform("ProjectorMatrix", _projectorMatrix); + _fboProgramObject->setUniform("ModelTransform" , _transform); + _fboProgramObject->setUniform("_scaling" , _camScaling); + _fboProgramObject->setUniform("boresight" , _boresight); + + if (_geometry->hasProperty("radius")){ + ghoul::any r = _geometry->property("radius")->get(); + if (glm::vec4* radius = ghoul::any_cast(&r)){ + _fboProgramObject->setUniform("_radius", radius); + } + }else{ + LERROR("Geometry object needs to provide radius"); + } + if (_geometry->hasProperty("segments")){ + ghoul::any s = _geometry->property("segments")->get(); + if (int* segments = ghoul::any_cast(&s)){ + _fboProgramObject->setUniform("_segments", segments[0]); + } + }else{ + LERROR("Geometry object needs to provide segment count"); + } + + glBindVertexArray(_quad); + glDrawArrays(GL_TRIANGLES, 0, 6); + _fboProgramObject->deactivate(); + + _projectionComponent.imageProjectEnd(); +} + + +} // namespace tileprovider +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/tileprovider/projectiontileprovider.h b/modules/globebrowsing/tile/tileprovider/projectiontileprovider.h new file mode 100644 index 0000000000..4b555c4f95 --- /dev/null +++ b/modules/globebrowsing/tile/tileprovider/projectiontileprovider.h @@ -0,0 +1,121 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * 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_GLOBEBROWSING___PROJECTION_TILE_PROVIDER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___PROJECTION_TILE_PROVIDER___H__ + +#include +#include + +#include +#include +#include + +namespace openspace { +namespace globebrowsing { + +class AsyncTileDataProvider; +class RawTile; + +namespace tileprovider { + +class ProjectionTileProvider : public TileProvider { +public: + ProjectionTileProvider(const ghoul::Dictionary& dictionary); + + virtual ~ProjectionTileProvider() override; + + virtual Tile getTile(const TileIndex& tileIndex) override; + + virtual Tile getDefaultTile() override; + virtual Tile::Status getTileStatus(const TileIndex& tileIndex) override; + virtual TileDepthTransform depthTransform() override; + virtual void update() override; + virtual void reset() override; + virtual int maxLevel() override; + virtual float noDataValueAsFloat() override; + + bool initialize() override; + bool deinitialize() override; + + //static documentation::Documentation Documentation(); + +protected: + bool loadTextures(); + void attitudeParameters(double time); + +private: + void imageProjectGPU(std::shared_ptr projectionTexture); + + ProjectionComponent _projectionComponent; + + //properties::StringProperty _colorTexturePath; + //properties::StringProperty _heightMapTexturePath; + + //properties::IntProperty _rotation; + + std::unique_ptr _fboProgramObject; + + //std::unique_ptr _baseTexture; + //std::unique_ptr _heightMapTexture; + + //properties::BoolProperty _shiftMeridianBy180; + + //properties::FloatProperty _heightExaggeration; + //properties::FloatProperty _debugProjectionTextureRotation; + + std::unique_ptr _geometry; + + glm::vec2 _camScaling; + glm::vec3 _up; + glm::mat4 _transform; + glm::mat4 _projectorMatrix; + + glm::dmat3 _stateMatrix; + glm::dmat3 _instrumentMatrix; + glm::vec3 _boresight; + + double _time; + + std::vector _imageTimes; + + std::string _frame; + + bool _capture; + + GLuint _quad; + GLuint _vertexPositionBuffer; + + + + +private: + Tile _defaultTile; +}; + +} // namespace tileprovider +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PROJECTION_TILE_PROVIDER___H__ diff --git a/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp b/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp index a2beeb5fe9..4c996337f6 100644 --- a/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp @@ -36,7 +36,9 @@ namespace openspace { namespace globebrowsing { namespace tileprovider { -SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) { +SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) + : _tile(nullptr, nullptr, Tile::Status::Unavailable) +{ // Required input if (!dictionary.getValue(KeyFilePath, _imagePath)) { throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'"); @@ -47,6 +49,7 @@ SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) { SingleImageProvider::SingleImageProvider(const std::string& imagePath) : _imagePath(imagePath) + , _tile(nullptr, nullptr, Tile::Status::Unavailable) { reset(); } @@ -60,7 +63,7 @@ Tile SingleImageProvider::getDefaultTile() { } Tile::Status SingleImageProvider::getTileStatus(const TileIndex& index) { - return _tile.status; + return _tile.status(); } TileDepthTransform SingleImageProvider::depthTransform() { @@ -75,15 +78,16 @@ void SingleImageProvider::update() { } void SingleImageProvider::reset() { - _tile = Tile(); - _tile.texture = std::shared_ptr( - std::move(ghoul::io::TextureReader::ref().loadTexture(_imagePath)) + auto tileTexture = std::shared_ptr( + ghoul::io::TextureReader::ref().loadTexture(_imagePath) ); - _tile.status = _tile.texture != nullptr ? Tile::Status::OK : Tile::Status::IOError; - _tile.metaData = nullptr; + auto tileStatus = tileTexture != nullptr ? Tile::Status::OK : Tile::Status::IOError; + auto tileMetaData = nullptr; - _tile.texture->uploadTexture(); - _tile.texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); + tileTexture->uploadTexture(); + tileTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); + + _tile = Tile(tileTexture, tileMetaData, tileStatus); } int SingleImageProvider::maxLevel() { diff --git a/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp b/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp index 80a944405e..552b9c9a11 100644 --- a/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp @@ -46,6 +46,7 @@ namespace { } SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary) + : _backgroundTile(Tile::TileUnavailable) { _fontSize = 50; _font = OsEng.fontManager().font("Mono", _fontSize); @@ -56,16 +57,19 @@ SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& di } _ellipsoid = Ellipsoid(radii); - _backgroundTile.status = Tile::Status::Unavailable; + auto backgroundTileStatus = Tile::Status::Unavailable; + std::shared_ptr backgroundTileTexture; + std::string backgroundImagePath; if (dictionary.getValue(KeyBackgroundImagePath, backgroundImagePath)) { using namespace ghoul::io; std::string imgAbsPath = absPath(backgroundImagePath); - _backgroundTile.texture = TextureReader::ref().loadTexture(imgAbsPath); - _backgroundTile.texture->uploadTexture(); - _backgroundTile.texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - _backgroundTile.status = Tile::Status::OK; + backgroundTileTexture = TextureReader::ref().loadTexture(imgAbsPath); + backgroundTileTexture->uploadTexture(); + backgroundTileTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); + backgroundTileStatus = Tile::Status::OK; } + _backgroundTile = Tile(backgroundTileTexture, nullptr, backgroundTileStatus); } void SizeReferenceTileProvider::renderText(const ghoul::fontrendering::FontRenderer& @@ -124,12 +128,11 @@ TileIndex::TileHashKey SizeReferenceTileProvider::toHash(const TileIndex& tileIn } Tile SizeReferenceTileProvider::backgroundTile(const TileIndex& tileIndex) const { - if (_backgroundTile.status == Tile::Status::OK) { - Tile tile; - auto t = _backgroundTile.texture; + if (_backgroundTile.status() == Tile::Status::OK) { + auto t = _backgroundTile.texture(); void* pixelData = new char[t->expectedPixelDataSize()]; memcpy(pixelData, t->pixelData(), t->expectedPixelDataSize()); - tile.texture = std::make_shared( + auto tileTexture = std::make_shared( pixelData, t->dimensions(), t->format(), @@ -138,10 +141,10 @@ Tile SizeReferenceTileProvider::backgroundTile(const TileIndex& tileIndex) const t->filter(), t->wrapping() ); - tile.texture->uploadTexture(); - tile.texture->setDataOwnership(ghoul::opengl::Texture::TakeOwnership::Yes); - tile.status = Tile::Status::OK; - return tile; + tileTexture->uploadTexture(); + tileTexture->setDataOwnership(ghoul::opengl::Texture::TakeOwnership::Yes); + auto tileStatus = Tile::Status::OK; + return Tile(tileTexture, nullptr, tileStatus); } else { // use default background diff --git a/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp b/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp index 8e8024872d..4e8fbb2d28 100644 --- a/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp @@ -22,13 +22,17 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#ifdef GLOBEBROWSING_USE_GDAL + #include #include +#include #include #include "cpl_minixml.h" +#include #include namespace { @@ -37,8 +41,11 @@ namespace { const char* KeyDoPreProcessing = "DoPreProcessing"; const char* KeyMinimumPixelSize = "MinimumPixelSize"; const char* KeyFilePath = "FilePath"; + const char* KeyBasePath = "BasePath"; const char* KeyCacheSize = "CacheSize"; const char* KeyFlushInterval = "FlushInterval"; + const char* KeyPreCacheStartTime = "PreCacheStartTime"; + const char* KeyPreCacheEndTime = "PreCacheEndTime"; } namespace openspace { @@ -56,11 +63,12 @@ const char* TemporalTileProvider::TemporalXMLTags::TIME_FORMAT = "OpenSpaceTimeI TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary) : _initDict(dictionary) { - if (!dictionary.getValue(KeyFilePath, _datasetFile)) { throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'"); } + _datasetFile = absPath(_datasetFile); + std::ifstream in(_datasetFile.c_str()); if (!in.is_open()) { throw ghoul::FileNotFoundError(_datasetFile); @@ -71,8 +79,29 @@ TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary) std::istreambuf_iterator(in), (std::istreambuf_iterator()) ); + + _initDict.setValue( + KeyBasePath, + ghoul::filesystem::File(_datasetFile).directoryName() + ); + _gdalXmlTemplate = consumeTemporalMetaData(xml); - _defaultTile = getTileProvider()->getDefaultTile(); + + const bool hasStart = dictionary.hasKeyAndValue(KeyPreCacheStartTime); + const bool hasEnd = dictionary.hasKeyAndValue(KeyPreCacheEndTime); + if (hasStart && hasEnd) { + const std::string start = dictionary.value(KeyPreCacheStartTime); + const std::string end = dictionary.value(KeyPreCacheEndTime); + std::vector