diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index c944074f64..8ffd865d61 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -137,7 +137,7 @@ public: void setRenderable(std::unique_ptr renderable); const Renderable* renderable() const; - //Renderable* renderable(); + Renderable* renderable(); const std::string& guiPath() const; bool hasGuiHintHidden() const; diff --git a/include/openspace/util/gpudata.h b/include/openspace/util/gpudata.h deleted file mode 100644 index ca80f8c12e..0000000000 --- a/include/openspace/util/gpudata.h +++ /dev/null @@ -1,107 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_CORE___GPUDATA___H__ -#define __OPENSPACE_CORE___GPUDATA___H__ - -#include -#include -#include -#include -#include - -// @TODO: This class should disappear as it doesn't server much of a purpose and only -// complicates local reasoning - -namespace openspace { - -/** - * Manages a GPU representation of the templated data type T. - * This class provides a simple interface setting the value of - * the binded GLSL variable. - */ -template -class GPUData { -public: - /** - * Updates the uniform location of the uniform variable named - * in the provided shader program. - */ - void bind(ghoul::opengl::ProgramObject* program, const std::string& name) { - _uniformLocation = program->uniformLocation(name); - } - - /** - * Sets the value of T to its corresponding GPU value. - * OBS! Users must ensure bind has been called before using this method - */ - void setValue(ghoul::opengl::ProgramObject* program, T val) { - program->setUniform(_uniformLocation, val); - } - -protected: - GLint _uniformLocation = -1; -}; - -/** - * Manages a Texture on the GPU. - * This class provides a simple interface binding texture to the - * named uniform. - */ -class GPUTexture { -public: - /** - * Updates the uniform location of the uniform variable named - * in the provided shader program. - */ - void bind(ghoul::opengl::ProgramObject* program, const std::string& name) { - _uniformLocation = program->uniformLocation(name); - } - - /** - * Sets and assignes a texture unit within the provided shader - * program. - * OBS! Users must ensure bind has been called before using this method. - */ - void setValue(ghoul::opengl::ProgramObject* program, ghoul::opengl::Texture* texture){ - _texUnit = std::make_unique(); - _texUnit->activate(); - if (texture) { - texture->bind(); - } - program->setUniform(_uniformLocation, *_texUnit); - } - - void deactivate() { - _texUnit = nullptr; - } - -private: - std::unique_ptr _texUnit; - GLint _uniformLocation = -1; -}; - -} // namespace openspace - -#endif // __OPENSPACE_CORE___GPUDATA___H__ diff --git a/include/openspace/util/job.h b/include/openspace/util/job.h index 6ac6bfae68..bdbcf8377b 100644 --- a/include/openspace/util/job.h +++ b/include/openspace/util/job.h @@ -37,7 +37,7 @@ struct Job { virtual ~Job() = default; virtual void execute() = 0; - virtual std::shared_ptr

product() = 0; + virtual P product() = 0; }; } // namespace openspace diff --git a/modules/atmosphere/rendering/renderableatmosphere.cpp b/modules/atmosphere/rendering/renderableatmosphere.cpp index 4bd196bdea..6bae40f3aa 100644 --- a/modules/atmosphere/rendering/renderableatmosphere.cpp +++ b/modules/atmosphere/rendering/renderableatmosphere.cpp @@ -55,9 +55,9 @@ namespace { static const char* _loggerCat = "RenderableAtmosphere"; - const char* keyShadowGroup = "ShadowGroup"; - const char* keyShadowSource = "Source"; - const char* keyShadowCaster = "Caster"; + const char* KeyShadowGroup = "ShadowGroup"; + const char* KeyShadowSource = "Source"; + const char* KeyShadowCaster = "Caster"; const char* keyAtmosphere = "Atmosphere"; const char* keyAtmosphereRadius = "AtmosphereRadius"; @@ -293,18 +293,18 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary) //======== Reads Shadow (Eclipses) Entries in mod file =========== //================================================================ ghoul::Dictionary shadowDictionary; - bool success = dictionary.getValue(keyShadowGroup, shadowDictionary); + bool success = dictionary.getValue(KeyShadowGroup, shadowDictionary); bool disableShadows = false; if (success) { std::vector> sourceArray; unsigned int sourceCounter = 1; while (success) { std::string sourceName; - success = shadowDictionary.getValue(keyShadowSource + + success = shadowDictionary.getValue(KeyShadowSource + std::to_string(sourceCounter) + ".Name", sourceName); if (success) { double sourceRadius; - success = shadowDictionary.getValue(keyShadowSource + + success = shadowDictionary.getValue(KeyShadowSource + std::to_string(sourceCounter) + ".Radius", sourceRadius); if (success) { sourceArray.emplace_back(sourceName, sourceRadius); @@ -329,11 +329,11 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary) unsigned int casterCounter = 1; while (success) { std::string casterName; - success = shadowDictionary.getValue(keyShadowCaster + + success = shadowDictionary.getValue(KeyShadowCaster + std::to_string(casterCounter) + ".Name", casterName); if (success) { double casterRadius; - success = shadowDictionary.getValue(keyShadowCaster + + success = shadowDictionary.getValue(KeyShadowCaster + std::to_string(casterCounter) + ".Radius", casterRadius); if (success) { casterArray.emplace_back(casterName, casterRadius); diff --git a/modules/debugging/rendering/debugrenderer.cpp b/modules/debugging/rendering/debugrenderer.cpp index 2f6842aa09..a5847d6e68 100644 --- a/modules/debugging/rendering/debugrenderer.cpp +++ b/modules/debugging/rendering/debugrenderer.cpp @@ -227,21 +227,6 @@ void DebugRenderer::renderCameraFrustum(const RenderData& data, const Camera& ot glEnable(GL_CULL_FACE); } -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED -void DebugRenderer::renderAABB2(const globebrowsing::AABB2& screenSpaceAABB, - const glm::vec4& rgba) const -{ - Vertices vertices = { - glm::vec4(screenSpaceAABB.min.x, screenSpaceAABB.min.y, 1, 1), - glm::vec4(screenSpaceAABB.min.x, screenSpaceAABB.max.y, 1, 1), - glm::vec4(screenSpaceAABB.max.x, screenSpaceAABB.min.y, 1, 1), - glm::vec4(screenSpaceAABB.max.x, screenSpaceAABB.max.y, 1, 1) - }; - - renderVertices(vertices, GL_LINES, rgba); -} -#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED const DebugRenderer::Vertices DebugRenderer::verticesFor( const globebrowsing::AABB3& screenSpaceAABB) const diff --git a/modules/debugging/rendering/debugrenderer.h b/modules/debugging/rendering/debugrenderer.h index 4da3e5d011..4b6274c746 100644 --- a/modules/debugging/rendering/debugrenderer.h +++ b/modules/debugging/rendering/debugrenderer.h @@ -28,7 +28,7 @@ #include #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED -#include +#include #endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED #include @@ -132,15 +132,6 @@ public: void renderCameraFrustum(const RenderData& data, const Camera& otherCamera, const glm::vec4& rgba = { 1.f, 1.f, 1.f, 0.3f }) const; -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - /** - * Renders a screen space AABB2 to the screen with the provided color - */ - void renderAABB2(const globebrowsing::AABB2& screenSpaceAABB, - const glm::vec4& rgba = { 1.f, 1.f, 1.f, 0.3f }) const; -#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - - #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED /** * Takes a AABB3 in screen space and returns vertices representing the corner points diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index 10ad550317..b2732e1e1d 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -26,201 +26,76 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/globebrowsingmodule.h - - ${CMAKE_CURRENT_SOURCE_DIR}/cache/lrucache.h - ${CMAKE_CURRENT_SOURCE_DIR}/cache/lrucache.inl - ${CMAKE_CURRENT_SOURCE_DIR}/cache/memoryawaretilecache.h - ${CMAKE_CURRENT_SOURCE_DIR}/cache/texturecontainer.h - ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunk.h - ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunknode.h - ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunklevelevaluator/chunklevelevaluator.h - ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunklevelevaluator/availabletiledataevaluator.h - ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunklevelevaluator/distanceevaluator.h - ${CMAKE_CURRENT_SOURCE_DIR}/chunk/chunklevelevaluator/projectedareaevaluator.h - ${CMAKE_CURRENT_SOURCE_DIR}/chunk/culling/chunkculler.h - ${CMAKE_CURRENT_SOURCE_DIR}/chunk/culling/frustumculler.h - ${CMAKE_CURRENT_SOURCE_DIR}/chunk/culling/horizonculler.h - - ${CMAKE_CURRENT_SOURCE_DIR}/dashboard/dashboarditemglobelocation.h - - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/aabb.h - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/angle.h - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/angle.inl - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/ellipsoid.h - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/geodetic2.h - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/geodetic3.h - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/geodeticpatch.h - - ${CMAKE_CURRENT_SOURCE_DIR}/globes/chunkedlodglobe.h - ${CMAKE_CURRENT_SOURCE_DIR}/globes/pointglobe.h - ${CMAKE_CURRENT_SOURCE_DIR}/globes/renderableglobe.h - - ${CMAKE_CURRENT_SOURCE_DIR}/meshes/basicgrid.h - ${CMAKE_CURRENT_SOURCE_DIR}/meshes/grid.h - ${CMAKE_CURRENT_SOURCE_DIR}/meshes/skirtedgrid.h - ${CMAKE_CURRENT_SOURCE_DIR}/meshes/trianglesoup.h - - ${CMAKE_CURRENT_SOURCE_DIR}/other/prioritizingconcurrentjobmanager.h - ${CMAKE_CURRENT_SOURCE_DIR}/other/prioritizingconcurrentjobmanager.inl - ${CMAKE_CURRENT_SOURCE_DIR}/other/pixelbuffer.h - ${CMAKE_CURRENT_SOURCE_DIR}/other/pixelbuffercontainer.h - ${CMAKE_CURRENT_SOURCE_DIR}/other/pixelbuffercontainer.inl - ${CMAKE_CURRENT_SOURCE_DIR}/other/statscollector.h - ${CMAKE_CURRENT_SOURCE_DIR}/other/templatedstatscollector.h - ${CMAKE_CURRENT_SOURCE_DIR}/other/templatedstatscollector.inl - ${CMAKE_CURRENT_SOURCE_DIR}/other/timequantizer.h - ${CMAKE_CURRENT_SOURCE_DIR}/other/lruthreadpool.h - ${CMAKE_CURRENT_SOURCE_DIR}/other/lruthreadpool.inl - - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/chunkrenderer.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layershadermanager.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpuchunktile.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpuchunktilepile.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpuheightlayer.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayer.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayeradjustment.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayergroup.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayermanager.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayerrendersettings.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gputiledepthtransform.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gputileuvtransform.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layer.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layeradjustment.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layergroup.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layergroupid.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layermanager.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layerrendersettings.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/tiledepthtransform.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileindex.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tilemetadata.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileselector.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileuvtransform.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileloadjob.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/defaulttileprovider.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 - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/texttileprovider.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileindextileprovider.h - ${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/tiletextureinitdata.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 + ${CMAKE_CURRENT_SOURCE_DIR}/src/asynctiledataprovider.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/basictypes.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/dashboarditemglobelocation.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/ellipsoid.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/gdalwrapper.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/geodeticpatch.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/gpulayergroup.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/layer.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/layeradjustment.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/layergroup.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/layergroupid.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/layermanager.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/layerrendersettings.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/lrucache.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/lrucache.inl + ${CMAKE_CURRENT_SOURCE_DIR}/src/lruthreadpool.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/lruthreadpool.inl + ${CMAKE_CURRENT_SOURCE_DIR}/src/memoryawaretilecache.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/prioritizingconcurrentjobmanager.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/prioritizingconcurrentjobmanager.inl + ${CMAKE_CURRENT_SOURCE_DIR}/src/rawtile.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/rawtiledatareader.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/renderableglobe.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/skirtedgrid.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/tileindex.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/tileloadjob.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/tileprovider.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/tiletextureinitdata.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/timequantizer.h ) set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/globebrowsingmodule.cpp ${CMAKE_CURRENT_SOURCE_DIR}/globebrowsingmodule_lua.inl - ${CMAKE_CURRENT_SOURCE_DIR}/cache/memoryawaretilecache.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/cache/texturecontainer.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}/dashboard/dashboarditemglobelocation.cpp - - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/aabb.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/ellipsoid.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/geodetic2.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/geometry/geodeticpatch.cpp - - ${CMAKE_CURRENT_SOURCE_DIR}/globes/chunkedlodglobe.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/globes/pointglobe.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/globes/renderableglobe.cpp - - ${CMAKE_CURRENT_SOURCE_DIR}/meshes/basicgrid.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/meshes/grid.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/meshes/skirtedgrid.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/meshes/trianglesoup.cpp - - ${CMAKE_CURRENT_SOURCE_DIR}/other/pixelbuffer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/other/statscollector.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/other/timequantizer.cpp - - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/chunkrenderer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layershadermanager.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpuchunktile.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpuchunktilepile.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpuheightlayer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayeradjustment.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayergroup.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayermanager.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayerrendersettings.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gputiledepthtransform.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gputileuvtransform.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layeradjustment.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layergroup.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layergroupid.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layermanager.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layerrendersettings.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/tileindex.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tilemetadata.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileselector.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileloadjob.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/defaulttileprovider.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 - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/texttileprovider.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/tileindextileprovider.cpp - ${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/tiletextureinitdata.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 + ${CMAKE_CURRENT_SOURCE_DIR}/src/asynctiledataprovider.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/dashboarditemglobelocation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/ellipsoid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/gdalwrapper.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/geodeticpatch.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/gpulayergroup.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/layer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/layeradjustment.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/layergroup.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/layergroupid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/layermanager.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/layerrendersettings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/memoryawaretilecache.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/rawtile.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/rawtiledatareader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/renderableglobe.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/skirtedgrid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tileindex.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tileloadjob.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tileprovider.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tiletextureinitdata.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/timequantizer.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) set(SHADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/shaders/blending.hglsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/ellipsoid.hglsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/globalchunkedlodpatch_vs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/globalchunkedlodpatch_fs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/localchunkedlodpatch_vs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/localchunkedlodpatch_fs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/pointglobe_vs.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/pointglobe_fs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/globalrenderer_vs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/localrenderer_vs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/renderer_fs.glsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/texturetilemapping.hglsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tile.hglsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tilefragment.hglsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tileheight.hglsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tilevertexskirt.hglsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/globeshading.hglsl ) source_group("Shader Files" FILES ${SHADER_FILES}) @@ -232,36 +107,31 @@ create_new_module( ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} ) -option(OPENSPACE_MODULE_GLOBEBROWSING_USE_GDAL "Use GDAL" ON) - install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/gdal_data DESTINATION modules/globebrowsing) -if (OPENSPACE_MODULE_GLOBEBROWSING_USE_GDAL) - if (WIN32) - target_include_directories( - openspace-module-globebrowsing - SYSTEM PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/include - ) +if (WIN32) + target_include_directories( + openspace-module-globebrowsing + SYSTEM PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/include + ) - target_link_libraries( - openspace-module-globebrowsing - ${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/lib/gdal_i.lib - ) - register_external_libraries("${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/lib/gdal202.dll") - else (WIN32) - find_package(GDAL REQUIRED) + target_link_libraries( + openspace-module-globebrowsing + ${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/lib/gdal_i.lib + ) + register_external_libraries("${CMAKE_CURRENT_SOURCE_DIR}/ext/gdal/lib/gdal202.dll") +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}) + target_link_libraries(openspace-module-globebrowsing ${GDAL_LIBRARY}) - mark_as_advanced(GDAL_CONFIG GDAL_INCLUDE_DIR GDAL_LIBRARY) + mark_as_advanced(GDAL_CONFIG GDAL_INCLUDE_DIR GDAL_LIBRARY) - endif () # WIN32 - target_compile_definitions(openspace-module-globebrowsing PUBLIC GLOBEBROWSING_USE_GDAL) -endif () # OPENSPACE_MODULE_GLOBEBROWSING_USE_GDAL +endif () # WIN32 diff --git a/modules/globebrowsing/cache/texturecontainer.cpp b/modules/globebrowsing/cache/texturecontainer.cpp deleted file mode 100644 index b61def4cc9..0000000000 --- a/modules/globebrowsing/cache/texturecontainer.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -namespace openspace::globebrowsing::cache { - -TextureContainer::TextureContainer(TileTextureInitData initData, size_t numTextures) - : _initData(std::move(initData)) - , _numTextures(numTextures) -{ - reset(); -} - -void TextureContainer::reset() { - _textures.clear(); - _freeTexture = 0; - for (size_t i = 0; i < _numTextures; ++i) { - using namespace ghoul::opengl; - std::unique_ptr tex = std::make_unique( - _initData.dimensions(), - _initData.ghoulTextureFormat(), - _initData.glTextureFormat(), - _initData.glType(), - Texture::FilterMode::Linear, - Texture::WrappingMode::ClampToEdge, - Texture::AllocateData(_initData.shouldAllocateDataOnCPU()) - ); - - tex->setDataOwnership(Texture::TakeOwnership::Yes); - tex->uploadTexture(); - tex->setFilter(Texture::FilterMode::AnisotropicMipMap); - - _textures.push_back(std::move(tex)); - } -} - -void TextureContainer::reset(size_t numTextures) { - _numTextures = numTextures; - reset(); -} - -ghoul::opengl::Texture* TextureContainer::getTextureIfFree() { - if (_freeTexture < _textures.size()) { - ghoul::opengl::Texture* texture = _textures[_freeTexture].get(); - _freeTexture++; - return texture; - } - else { - return nullptr; - } -} - -const TileTextureInitData& TextureContainer::tileTextureInitData() const { - return _initData; -} - -size_t TextureContainer::size() const { - return _textures.size(); -} - -} // namespace openspace::globebrowsing::cache diff --git a/modules/globebrowsing/cache/texturecontainer.h b/modules/globebrowsing/cache/texturecontainer.h deleted file mode 100644 index d739ed2019..0000000000 --- a/modules/globebrowsing/cache/texturecontainer.h +++ /dev/null @@ -1,76 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TEXTURE_CONTAINER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TEXTURE_CONTAINER___H__ - -#include - -#include -#include - -namespace openspace::globebrowsing::cache { - -/** - * Owner of texture data used for tiles. Instead of dynamically allocating textures one - * by one, they are created once and reused. - */ -class TextureContainer { -public: - /** - * \param initData is the description of the texture type. - * \param numTextures is the number of textures to allocate. - */ - TextureContainer(TileTextureInitData initData, size_t numTextures); - - ~TextureContainer() = default; - - void reset(); - void reset(size_t numTextures); - - /** - * \return A pointer to a texture if there is one texture never used before. If there - * are no textures left, nullptr is returned. TextureContainer still owns the - * texture so no delete should be called on the raw pointer. - */ - ghoul::opengl::Texture* getTextureIfFree(); - - const TileTextureInitData& tileTextureInitData() const; - - /** - * \returns the number of textures in this TextureContainer - */ - size_t size() const; - -private: - std::vector> _textures; - - const TileTextureInitData _initData; - size_t _freeTexture = 0; - size_t _numTextures; -}; - -} // namespace openspace::globebrowsing::cache - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TEXTURE_CONTAINER___H__ diff --git a/modules/globebrowsing/chunk/chunk.cpp b/modules/globebrowsing/chunk/chunk.cpp deleted file mode 100644 index dd44947f79..0000000000 --- a/modules/globebrowsing/chunk/chunk.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace openspace::globebrowsing { - -Chunk::Chunk(const RenderableGlobe& owner, const TileIndex& tileIndex, bool initVisible) - : _owner(owner) - , _tileIndex(tileIndex) - , _isVisible(initVisible) - , _surfacePatch(tileIndex) -{} - -const GeodeticPatch& Chunk::surfacePatch() const { - return _surfacePatch; -} - -const RenderableGlobe& Chunk::owner() const { - return _owner; -} - -const TileIndex Chunk::tileIndex() const { - return _tileIndex; -} - -bool Chunk::isVisible() const { - return _isVisible; -} - -Chunk::Status Chunk::update(const RenderData& data) { - const std::shared_ptr& savedCamera = _owner.savedCamera(); - const Camera& camRef = savedCamera ? *savedCamera : data.camera; - - RenderData myRenderData = { - camRef, - data.position, - data.time, - data.doPerformanceMeasurement, - data.renderBinMask, - data.modelTransform - }; - - _isVisible = true; - if (_owner.chunkedLodGlobe()->testIfCullable(*this, myRenderData)) { - _isVisible = false; - return Status::WantMerge; - } - - const int desiredLevel = _owner.chunkedLodGlobe()->desiredLevel( - *this, - myRenderData - ); - - if (desiredLevel < _tileIndex.level) { - return Status::WantMerge; - } - else if (_tileIndex.level < desiredLevel) { - return Status::WantSplit; - } - else { - return Status::DoNothing; - } -} - -Chunk::BoundingHeights Chunk::boundingHeights() const { - using ChunkTileSettingsPair = std::pair; - - BoundingHeights boundingHeights { 0.f, 0.f, false }; - - // 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 - std::shared_ptr lm = 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 = lm->layerGroup(layergroupid::GroupID::HeightLayers); - std::vector chunkTileSettingPairs = - tileselector::getTilesAndSettingsUnsorted(heightmaps, _tileIndex); - - bool lastHadMissingData = true; - for (const ChunkTileSettingsPair& chunkTileSettingsPair : chunkTileSettingPairs) { - const ChunkTile& chunkTile = chunkTileSettingsPair.first; - const LayerRenderSettings* settings = chunkTileSettingsPair.second; - const bool goodTile = (chunkTile.tile.status() == Tile::Status::OK); - const bool hasTileMetaData = (chunkTile.tile.metaData() != nullptr); - - if (goodTile && hasTileMetaData) { - TileMetaData* tileMetaData = chunkTile.tile.metaData(); - - const float minValue = settings->performLayerSettings( - tileMetaData->minValues[HeightChannel] - ); - const float maxValue = settings->performLayerSettings( - tileMetaData->maxValues[HeightChannel] - ); - - if (!boundingHeights.available) { - if (tileMetaData->hasMissingData[HeightChannel]) { - boundingHeights.min = std::min(DefaultHeight, minValue); - boundingHeights.max = std::max(DefaultHeight, maxValue); - } - else { - boundingHeights.min = minValue; - boundingHeights.max = maxValue; - } - boundingHeights.available = true; - } - else { - boundingHeights.min = std::min(boundingHeights.min, minValue); - boundingHeights.max = std::max(boundingHeights.max, maxValue); - } - lastHadMissingData = tileMetaData->hasMissingData[HeightChannel]; - } - - // Allow for early termination - if (!lastHadMissingData) { - break; - } - } - - return boundingHeights; -} - -std::vector Chunk::boundingPolyhedronCorners() const { - const Ellipsoid& ellipsoid = owner().ellipsoid(); - const GeodeticPatch& patch = surfacePatch(); - - const BoundingHeights& boundingHeight = boundingHeights(); - - // assume worst case - const double patchCenterRadius = ellipsoid.maximumRadius(); - - const double maxCenterRadius = patchCenterRadius + boundingHeight.max; - Geodetic2 halfSize = patch.halfSize(); - - // As the patch is curved, the maximum height offsets at the corners must be long - // enough to cover large enough to cover a boundingHeight.max at the center of the - // patch. - // Approximating scaleToCoverCenter by assuming the latitude and longitude angles - // of "halfSize" are equal to the angles they create from the center of the - // globe to the patch corners. This is true for the longitude direction when - // the ellipsoid can be approximated as a sphere and for the latitude for patches - // close to the equator. Close to the pole this will lead to a bigger than needed - // value for scaleToCoverCenter. However, this is a simple calculation and a good - // Approximation. - const double y1 = tan(halfSize.lat); - const double y2 = tan(halfSize.lon); - const double scaleToCoverCenter = sqrt(1 + pow(y1, 2) + pow(y2, 2)); - - const double maxCornerHeight = maxCenterRadius * scaleToCoverCenter - - patchCenterRadius; - - const bool chunkIsNorthOfEquator = patch.isNorthern(); - - // The minimum height offset, however, we can simply - const double minCornerHeight = boundingHeight.min; - std::vector corners(8); - - const double latCloseToEquator = patch.edgeLatitudeNearestEquator(); - const Geodetic3 p1Geodetic = { - { latCloseToEquator, patch.minLon() }, - maxCornerHeight - }; - const Geodetic3 p2Geodetic = { - { latCloseToEquator, patch.maxLon() }, - maxCornerHeight - }; - - const glm::vec3 p1 = ellipsoid.cartesianPosition(p1Geodetic); - const glm::vec3 p2 = ellipsoid.cartesianPosition(p2Geodetic); - const glm::vec3 p = 0.5f * (p1 + p2); - const Geodetic2 pGeodetic = ellipsoid.cartesianToGeodetic2(p); - const double latDiff = latCloseToEquator - pGeodetic.lat; - - for (size_t i = 0; i < 8; ++i) { - const Quad q = static_cast(i % 4); - const double cornerHeight = i < 4 ? minCornerHeight : maxCornerHeight; - Geodetic3 cornerGeodetic = { patch.corner(q), cornerHeight }; - - const bool cornerIsNorthern = !((i / 2) % 2); - const bool cornerCloseToEquator = chunkIsNorthOfEquator ^ cornerIsNorthern; - if (cornerCloseToEquator) { - cornerGeodetic.geodetic2.lat += latDiff; - } - - corners[i] = glm::dvec4(ellipsoid.cartesianPosition(cornerGeodetic), 1); - } - - return corners; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/chunk/chunk.h b/modules/globebrowsing/chunk/chunk.h deleted file mode 100644 index c6a2bfb7f5..0000000000 --- a/modules/globebrowsing/chunk/chunk.h +++ /dev/null @@ -1,103 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___CHUNK___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___CHUNK___H__ - -#include -#include -#include -#include - -namespace openspace { struct RenderData; } - -namespace openspace::globebrowsing { - -class RenderableGlobe; -struct TileIndex; - -class Chunk { -public: - constexpr static float DefaultHeight = 0.f; - - struct BoundingHeights { - float min; - float max; - bool available; - }; - - enum class Status { - DoNothing, - WantMerge, - WantSplit - }; - - Chunk(const RenderableGlobe& owner, const TileIndex& tileIndex, - bool initVisible = true); - - /** - * Updates the Chunk internally and returns the Status of the Chunk. - * - * Tests if the Chunk is cullable and gets the desired level of the Chunk. If the - * Chunk is cullable it will be set to invisible and return Status::WANT_MERGE. - * If the desired level is smaller than the current level of the chunk it will - * return Status::WANT_MERGE, if it is larger it will return Status::WANT_SPLIT, - * otherwise Status::DO_NOTHING. - * - * \return The Status of the chunk. - */ - Status update(const RenderData& data); - - /** - * Returns a convex polyhedron of eight vertices tightly bounding the volume of - * the Chunk. - */ - std::vector boundingPolyhedronCorners() const; - - const GeodeticPatch& surfacePatch() const; - const RenderableGlobe& owner() const; - const TileIndex tileIndex() const; - bool isVisible() const; - - /** - * Returns BoundingHeights that fits the Chunk as tightly as possible. - * - * If the Chunk uses more than one HightLayer, the BoundingHeights will be set - * to cover all HeightLayers. If the Chunk has a higher level than its highest - * resolution HightLayer Tile, it will base its BoundingHeights on that Tile. - * This means that high level Chunks can have BoundingHeights that are not - * tightly fitting. - */ - BoundingHeights boundingHeights() const; - -private: - const RenderableGlobe& _owner; - const TileIndex _tileIndex; - bool _isVisible; - const GeodeticPatch _surfacePatch; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___CHUNK___H__ diff --git a/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.cpp b/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.cpp deleted file mode 100644 index e0e0c37f65..0000000000 --- a/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace openspace::globebrowsing::chunklevelevaluator { - -int AvailableTileData::desiredLevel(const Chunk& chunk, const RenderData&) const { - std::shared_ptr layerManager = - chunk.owner().chunkedLodGlobe()->layerManager(); - - const int currLevel = chunk.tileIndex().level; - - for (size_t i = 0; i < layergroupid::NUM_LAYER_GROUPS; ++i) { - for (const std::shared_ptr& layer : - layerManager->layerGroup(i).activeLayers()) - { - Tile::Status status = layer->tileStatus(chunk.tileIndex()); - if (status == Tile::Status::OK) { - return UnknownDesiredLevel; - } - } - } - - return currLevel - 1; -} - -} // namespace openspace::globebrowsing::chunklevelevaluator diff --git a/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.h b/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.h deleted file mode 100644 index 9402431ef4..0000000000 --- a/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.h +++ /dev/null @@ -1,45 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___AVAILABLETILEDATAEVALUATOR___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___AVAILABLETILEDATAEVALUATOR___H__ - -#include - -namespace openspace::globebrowsing::chunklevelevaluator { - -/** - * If this chunk has available tile data for any LayerGroup on any of its active - * Layers it will return an UNKNOWN_DESIRED_LEVEL. If no data is available it will - * evaluate to a level that is current level -1. -*/ -class AvailableTileData : public Evaluator { -public: - virtual ~AvailableTileData() override = default; - int desiredLevel(const Chunk& chunk, const RenderData& data) const override; -}; - -} // namespace openspace::globebrowsing::chunklevelevaluator - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___AVAILABLETILEDATAEVALUATOR___H__ diff --git a/modules/globebrowsing/chunk/chunklevelevaluator/chunklevelevaluator.h b/modules/globebrowsing/chunk/chunklevelevaluator/chunklevelevaluator.h deleted file mode 100644 index 529a86b1de..0000000000 --- a/modules/globebrowsing/chunk/chunklevelevaluator/chunklevelevaluator.h +++ /dev/null @@ -1,49 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKLEVELEVALUATOR___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKLEVELEVALUATOR___H__ - -namespace openspace { struct RenderData; } - -namespace openspace::globebrowsing { class Chunk; } - -namespace openspace::globebrowsing::chunklevelevaluator { - -/** - * Abstract class defining an interface for accessing a desired level of a Chunk. - * The desired level can be used in the process of determining whether a Chunk should - * want to split, merge or do nothing. -*/ -class Evaluator { -public: - virtual ~Evaluator() = default; - constexpr static const int UnknownDesiredLevel = -1; - - virtual int desiredLevel(const Chunk& chunk, const RenderData& data) const = 0; -}; - -} // namespace openspace::globebrowsing::chunklevelevaluator - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKLEVELEVALUATOR___H__ diff --git a/modules/globebrowsing/chunk/chunklevelevaluator/distanceevaluator.cpp b/modules/globebrowsing/chunk/chunklevelevaluator/distanceevaluator.cpp deleted file mode 100644 index ed688deb92..0000000000 --- a/modules/globebrowsing/chunk/chunklevelevaluator/distanceevaluator.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include - -namespace openspace::globebrowsing::chunklevelevaluator { - -int Distance::desiredLevel(const Chunk& chunk, const RenderData& data) const { - // Calculations are done in the reference frame of the globe - // (model space). Hence, the camera position needs to be transformed - // with the inverse model matrix - const glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform(); - const RenderableGlobe& globe = chunk.owner(); - const Ellipsoid& ellipsoid = globe.ellipsoid(); - - const glm::dvec3 cameraPosition = glm::dvec3(inverseModelTransform * - glm::dvec4(data.camera.positionVec3(), 1.0)); - - const Geodetic2 pointOnPatch = chunk.surfacePatch().closestPoint( - ellipsoid.cartesianToGeodetic2(cameraPosition) - ); - const glm::dvec3 patchNormal = ellipsoid.geodeticSurfaceNormal(pointOnPatch); - glm::dvec3 patchPosition = ellipsoid.cartesianSurfacePosition(pointOnPatch); - - const Chunk::BoundingHeights heights = chunk.boundingHeights(); - const double heightToChunk = heights.min; - - // Offset position according to height - patchPosition += patchNormal * heightToChunk; - - const glm::dvec3 cameraToChunk = patchPosition - cameraPosition; - - // Calculate desired level based on distance - const double distanceToPatch = glm::length(cameraToChunk); - const double distance = distanceToPatch; - - const double scaleFactor = globe.generalProperties().lodScaleFactor * - ellipsoid.minimumRadius(); - const double projectedScaleFactor = scaleFactor / distance; - const int desiredLevel = static_cast(ceil(log2(projectedScaleFactor))); - return desiredLevel; -} - -} // namespace openspace::globebrowsing::chunklevelevaluator diff --git a/modules/globebrowsing/chunk/chunklevelevaluator/distanceevaluator.h b/modules/globebrowsing/chunk/chunklevelevaluator/distanceevaluator.h deleted file mode 100644 index 7aee93b489..0000000000 --- a/modules/globebrowsing/chunk/chunklevelevaluator/distanceevaluator.h +++ /dev/null @@ -1,44 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___DISTANCEEVALUATOR___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___DISTANCEEVALUATOR___H__ - -#include - -namespace openspace::globebrowsing::chunklevelevaluator { - -/** - * Evaluate the Chunk level depending on the distance from the Camera to the Chunk. - * This evaluation method aims to keep the screen size (horizontal length and not - * area) of all chunks constant. -*/ -class Distance : public Evaluator { -public: - int desiredLevel(const Chunk& chunk, const RenderData& data) const override; -}; - -} // namespace openspace::globebrowsing::chunklevelevaluator - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___DISTANCEEVALUATOR___H__ diff --git a/modules/globebrowsing/chunk/chunklevelevaluator/projectedareaevaluator.cpp b/modules/globebrowsing/chunk/chunklevelevaluator/projectedareaevaluator.cpp deleted file mode 100644 index dfa561f587..0000000000 --- a/modules/globebrowsing/chunk/chunklevelevaluator/projectedareaevaluator.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace openspace::globebrowsing::chunklevelevaluator { - -int ProjectedArea::desiredLevel(const Chunk& chunk, const RenderData& data) const { - // Calculations are done in the reference frame of the globe - // (model space). Hence, the camera position needs to be transformed - // with the inverse model matrix - const glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform(); - - const RenderableGlobe& globe = chunk.owner(); - const Ellipsoid& ellipsoid = globe.ellipsoid(); - const glm::dvec4 cameraPositionModelSpace = glm::dvec4(data.camera.positionVec3(), 1); - const glm::dvec3 cameraPosition = glm::dvec3( - inverseModelTransform * cameraPositionModelSpace - ); - const glm::dvec3 cameraToEllipsoidCenter = -cameraPosition; - - const Geodetic2 cameraGeodeticPos = ellipsoid.cartesianToGeodetic2(cameraPosition); - - // Approach: - // The projected area of the chunk will be calculated based on a small area that - // is close to the camera, and the scaled up to represent the full area. - // The advantage of doing this is that it will better handle the cases where the - // full patch is very curved (e.g. stretches from latitude 0 to 90 deg). - - const Geodetic2 center = chunk.surfacePatch().center(); - const Geodetic2 closestCorner = chunk.surfacePatch().closestCorner(cameraGeodeticPos); - - // Camera - // | - // V - // - // oo - // [ ]< - // *geodetic space* - // - // closestCorner - // +-----------------+ <-- north east corner - // | | - // | center | - // | | - // +-----------------+ <-- south east corner - - const Chunk::BoundingHeights heights = chunk.boundingHeights(); - const Geodetic3 c = { center, heights.min }; - const Geodetic3 c1 = { Geodetic2(center.lat, closestCorner.lon), heights.min }; - const Geodetic3 c2 = { Geodetic2(closestCorner.lat, center.lon), heights.min }; - - // Camera - // | - // V - // - // oo - // [ ]< - // *geodetic space* - // - // +--------c2-------+ <-- north east corner - // | | - // c1 c | - // | | - // +-----------------+ <-- south east corner - - - // Go from geodetic to cartesian space and project onto unit sphere - const glm::dvec3 A = glm::normalize( - cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c) - ); - const glm::dvec3 B = glm::normalize( - cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c1) - ); - const glm::dvec3 C = glm::normalize( - cameraToEllipsoidCenter + ellipsoid.cartesianPosition(c2) - ); - - // Camera *cartesian space* - // | +--------+---+ - // V __--'' __--'' / - // C-------A--------- + - // oo / / / - //[ ]< +-------B----------+ - // - - // If the geodetic patch is small (i.e. has small width), that means the patch in - // cartesian space will be almost flat, and in turn, the triangle ABC will roughly - // correspond to 1/8 of the full area - const glm::dvec3 AB = B - A; - const glm::dvec3 AC = C - A; - const double areaABC = 0.5 * glm::length(glm::cross(AC, AB)); - const double projectedChunkAreaApprox = 8 * areaABC; - - const double scaledArea = globe.generalProperties().lodScaleFactor * - projectedChunkAreaApprox; - return chunk.tileIndex().level + static_cast(round(scaledArea - 1)); -} - -} // namespace openspace::globebrowsing::chunklevelevaluator diff --git a/modules/globebrowsing/chunk/chunklevelevaluator/projectedareaevaluator.h b/modules/globebrowsing/chunk/chunklevelevaluator/projectedareaevaluator.h deleted file mode 100644 index b34e84a96e..0000000000 --- a/modules/globebrowsing/chunk/chunklevelevaluator/projectedareaevaluator.h +++ /dev/null @@ -1,46 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PROJECTEDAREAEVALUATOR___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___PROJECTEDAREAEVALUATOR___H__ - -#include - -namespace openspace::globebrowsing::chunklevelevaluator { - -/** - * Evaluate the chunk level using the area of the non-heightmapped Chunk projected - * on a sphere with the center in the position of the camera. A Chunk near the - * horizon will have a small projected area and hence a lower desired level. This - * evaluation is more forgiving than EvaluateChunkLevelByDistance, meaning it results - * in lower desired levels. -*/ -class ProjectedArea : public Evaluator { -public: - virtual int desiredLevel(const Chunk& chunk, const RenderData& data) const override; -}; - -} // namespace openspace::globebrowsing::chunklevelevaluator - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PROJECTEDAREAEVALUATOR___H__ diff --git a/modules/globebrowsing/chunk/chunknode.cpp b/modules/globebrowsing/chunk/chunknode.cpp deleted file mode 100644 index a08933edd6..0000000000 --- a/modules/globebrowsing/chunk/chunknode.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include - -namespace openspace::globebrowsing { - -ChunkNode::ChunkNode(Chunk chunk, ChunkNode* parent) - : _parent(parent) - , _children({ {nullptr, nullptr, nullptr, nullptr} }) - , _chunk(std::move(chunk)) -{} - -bool ChunkNode::isRoot() const { - return _parent == nullptr; -} - -bool ChunkNode::isLeaf() const { - return _children[0] == nullptr; -} - -bool ChunkNode::updateChunkTree(const RenderData& data) { - if (isLeaf()) { - Chunk::Status status = _chunk.update(data); - if (status == Chunk::Status::WantSplit) { - split(); - } - return status == Chunk::Status::WantMerge; - } - else { - char requestedMergeMask = 0; - for (int i = 0; i < 4; ++i) { - if (_children[i]->updateChunkTree(data)) { - requestedMergeMask |= (1 << i); - } - } - - const bool allChildrenWantsMerge = requestedMergeMask == 0xf; - const bool thisChunkWantsSplit = _chunk.update(data) == Chunk::Status::WantSplit; - - if (allChildrenWantsMerge && !thisChunkWantsSplit) { - merge(); - } - - return false; - } -} - -void ChunkNode::depthFirst(const std::function& f) const { - f(*this); - if (!isLeaf()) { - for (int i = 0; i < 4; ++i) { - _children[i]->depthFirst(f); - } - } -} - -void ChunkNode::breadthFirst(const std::function& f) const { - std::queue Q; - - // Loop through nodes in breadths first order - Q.push(this); - while (!Q.empty()) { - const ChunkNode* node = Q.front(); - Q.pop(); - - f(*node); - - // Add children to queue, if any - if (!node->isLeaf()) { - for (int i = 0; i < 4; ++i) { - Q.push(node->_children[i].get()); - } - } - } -} - -void ChunkNode::reverseBreadthFirst(const std::function& f) const -{ - std::stack S; - std::queue Q; - - // Loop through nodes in breadths first order - Q.push(this); - while (!Q.empty()) { - const ChunkNode* node = Q.front(); - Q.pop(); - - // Add node to future stack - S.push(node); - - // Add children to queue, if any - if (!node->isLeaf()) { - for (const auto& c : node->_children) { - Q.push(c.get()); - } - //for (int i = 0; i < 4; ++i) { - // Q.push(node->_children[i].get()); - //} - } - } - - // Loop through all nodes in stack, this will be reversed breadth first - while (!S.empty()) { - f(*S.top()); - S.pop(); - } -} - -const ChunkNode& ChunkNode::find(const Geodetic2& location) const { - const ChunkNode* node = this; - - while (!node->isLeaf()) { - const Geodetic2 center = node->_chunk.surfacePatch().center(); - int index = 0; - if (center.lon < location.lon) { - ++index; - } - if (location.lat < center.lat) { - ++index; - ++index; - } - node = &(node->child(static_cast(index))); - } - return *node; -} - -const ChunkNode& ChunkNode::child(const Quad& quad) const { - return *_children[quad]; -} - -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(static_cast(i))); - _children[i] = std::make_unique(chunk, this); - } - } - - if (depth - 1 > 0) { - for (const std::unique_ptr& child : _children) { - child->split(depth - 1); - } - } -} - -void ChunkNode::merge() { - for (std::unique_ptr& child : _children) { - if (child) { - child->merge(); - } - child = nullptr; - } - - ghoul_assert(isLeaf(), "ChunkNode must be leaf after merge"); -} - -const Chunk& ChunkNode::chunk() const { - return _chunk; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/chunk/chunknode.h b/modules/globebrowsing/chunk/chunknode.h deleted file mode 100644 index f871c69b71..0000000000 --- a/modules/globebrowsing/chunk/chunknode.h +++ /dev/null @@ -1,84 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKNODE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKNODE___H__ - -#include - -#include -#include -#include - -namespace openspace::globebrowsing { - -class ChunkedLodGlobe; - -class ChunkNode { -public: - ChunkNode(Chunk chunk, ChunkNode* parent = nullptr); - - /** - * Recursively split the ChunkNode. - * - * \param depth defines how deep the recursion should go. If depth == 1 (default), - * the ChunkNode will only split once. - */ - void split(int depth = 1); - - /** - * Deletes all children of the ChunkNode recursively. - */ - void merge(); - - bool isRoot() const; - bool isLeaf() const; - - void depthFirst(const std::function& f) const; - void breadthFirst(const std::function& f) const; - void reverseBreadthFirst(const std::function& f) const; - - const ChunkNode& find(const Geodetic2& location) const; - const ChunkNode& child(const Quad& quad) const; - const Chunk& chunk() const; - - /** - * Updates all children recursively. If this ChunkNode wants to split it will, - * otherwise check if the children wants to merge. If all children wants to merge - * and the Status of this Chunk is not Status::WANT_SPLIT it will merge. - * - * \returns true if the ChunkNode can merge and false if it can not merge. - */ - bool updateChunkTree(const RenderData& data); - -private: - ChunkNode* _parent; - std::array, 4> _children; - - Chunk _chunk; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKNODE___H__ diff --git a/modules/globebrowsing/chunk/culling/chunkculler.h b/modules/globebrowsing/chunk/culling/chunkculler.h deleted file mode 100644 index f8a336f3c8..0000000000 --- a/modules/globebrowsing/chunk/culling/chunkculler.h +++ /dev/null @@ -1,47 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKCULLER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKCULLER___H__ - -namespace openspace { struct RenderData; } - -namespace openspace::globebrowsing { class Chunk; } - -namespace openspace::globebrowsing::culling { - -class ChunkCuller { -public: - virtual ~ChunkCuller() = default; - /** - * Determine if the Chunk is cullable. That is return true if removing the - * Chunk 'culling it' will not have any result on the final rendering. Culling - * it will make the rendering faster. - */ - virtual bool isCullable(const Chunk& chunk, const RenderData& renderData) = 0; -}; - -} // namespace openspace::globebrowsing::culling - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKCULLER___H__ diff --git a/modules/globebrowsing/chunk/culling/frustumculler.cpp b/modules/globebrowsing/chunk/culling/frustumculler.cpp deleted file mode 100644 index fc0d11e067..0000000000 --- a/modules/globebrowsing/chunk/culling/frustumculler.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include - -#include - -namespace openspace::globebrowsing::culling { - -FrustumCuller::FrustumCuller(AABB3 viewFrustum) - : _viewFrustum(std::move(viewFrustum)) -{} - -bool FrustumCuller::isCullable(const Chunk& chunk, const RenderData& renderData) { - // Calculate the MVP matrix - const glm::dmat4 modelTransform = chunk.owner().modelTransform(); - const glm::dmat4 viewTransform = glm::dmat4(renderData.camera.combinedViewMatrix()); - const glm::dmat4 modelViewProjectionTransform = glm::dmat4( - renderData.camera.sgctInternal.projectionMatrix() - ) * viewTransform * modelTransform; - - const std::vector& corners = chunk.boundingPolyhedronCorners(); - - // Create a bounding box that fits the patch corners - AABB3 bounds; // in screen space - for (size_t i = 0; i < 8; ++i) { - const glm::dvec4 cornerClippingSpace = modelViewProjectionTransform * corners[i]; - const glm::dvec3 ndc = glm::dvec3( - (1.f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace - ); - bounds.expand(ndc); - } - - return !(_viewFrustum.intersects(bounds)); -} - -} // namespace openspace::globebrowsing::culling diff --git a/modules/globebrowsing/chunk/culling/frustumculler.h b/modules/globebrowsing/chunk/culling/frustumculler.h deleted file mode 100644 index 68551241f7..0000000000 --- a/modules/globebrowsing/chunk/culling/frustumculler.h +++ /dev/null @@ -1,59 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___FRUSTUMCULLER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___FRUSTUMCULLER___H__ - -#include - -#include - -namespace openspace::globebrowsing::culling { - -/** - * Culls all chunks that are completely outside the view frustum. - * - * The frustum culling uses a 2D axis aligned bounding box for the Chunk in - * screen space. This is calculated from a bounding polyhedron bounding the - * Chunk. Hence the culling will not be 'perfect' but fast and good enough for - * culling chunks outside the frustum with some margin. - */ -class FrustumCuller : public ChunkCuller { -public: - virtual ~FrustumCuller() override = default; - /** - * \param viewFrustum is the view space in normalized device coordinates space. - * Hence it is an axis aligned bounding box and not a real frustum. - */ - FrustumCuller(AABB3 viewFrustum); - - bool isCullable(const Chunk& chunk, const RenderData& renderData) override; - -private: - const AABB3 _viewFrustum; -}; - -} // namespace openspace::globebrowsing::culling - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___FRUSTUMCULLER___H__ diff --git a/modules/globebrowsing/chunk/culling/horizonculler.cpp b/modules/globebrowsing/chunk/culling/horizonculler.cpp deleted file mode 100644 index 002a73040b..0000000000 --- a/modules/globebrowsing/chunk/culling/horizonculler.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include - -namespace openspace::globebrowsing::culling { - -bool HorizonCuller::isCullable(const Chunk& chunk, const RenderData& renderData) { - // Calculations are done in the reference frame of the globe. Hence, the camera - // position needs to be transformed with the inverse model matrix - const glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform(); - - const Ellipsoid& ellipsoid = chunk.owner().ellipsoid(); - const GeodeticPatch& patch = chunk.surfacePatch(); - const float maxHeight = chunk.boundingHeights().max; - const glm::dvec3 globePos = glm::dvec3(0,0,0); // In model space it is 0 - const double minimumGlobeRadius = ellipsoid.minimumRadius(); - - const glm::dvec3 cameraPos = glm::dvec3( - inverseModelTransform * glm::dvec4(renderData.camera.positionVec3(), 1) - ); - - const glm::dvec3 globeToCamera = cameraPos; - - const Geodetic2 cameraPositionOnGlobe = ellipsoid.cartesianToGeodetic2(globeToCamera); - const Geodetic2 closestPatchPoint = patch.closestPoint(cameraPositionOnGlobe); - glm::dvec3 objectPos = ellipsoid.cartesianSurfacePosition(closestPatchPoint); - - // objectPosition is closest in latlon space but not guaranteed to be closest in - // castesian coordinates. Therefore we compare it to the corners and pick the - // real closest point, - std::array corners = { - ellipsoid.cartesianSurfacePosition(chunk.surfacePatch().corner(NORTH_WEST)), - ellipsoid.cartesianSurfacePosition(chunk.surfacePatch().corner(NORTH_EAST)), - ellipsoid.cartesianSurfacePosition(chunk.surfacePatch().corner(SOUTH_WEST)), - ellipsoid.cartesianSurfacePosition(chunk.surfacePatch().corner(SOUTH_EAST)) - }; - - for (int i = 0; i < 4; ++i) { - const double distance = glm::length(cameraPos - corners[i]); - if (distance < glm::length(cameraPos - objectPos)) { - objectPos = corners[i]; - } - } - - return isCullable(cameraPos, globePos, objectPos, maxHeight, minimumGlobeRadius); -} - -bool HorizonCuller::isCullable(const glm::dvec3& cameraPosition, - const glm::dvec3& globePosition, - const glm::dvec3& objectPosition, - double objectBoundingSphereRadius, - double minimumGlobeRadius) -{ - const double objectP = pow(length(objectPosition - globePosition), 2); - const double horizonP = pow(minimumGlobeRadius - objectBoundingSphereRadius, 2); - if (objectP < horizonP) { - return false; - } - - const double cameraP = pow(length(cameraPosition - globePosition), 2); - const double minR = pow(minimumGlobeRadius, 2); - if (cameraP < minR) { - return false; - } - - const double minimumAllowedDistanceToObjectFromHorizon = sqrt(objectP - horizonP); - const double distanceToHorizon = sqrt(cameraP - minR); - - // Minimum allowed for the object to be occluded - const double minimumAllowedDistanceToObjectSquared = - pow(distanceToHorizon + minimumAllowedDistanceToObjectFromHorizon, 2) + - pow(objectBoundingSphereRadius, 2); - - const double distanceToObjectSquared = pow( - length(objectPosition - cameraPosition), - 2 - ); - return distanceToObjectSquared > minimumAllowedDistanceToObjectSquared; -} - -} // namespace openspace::globebrowsing::culling diff --git a/modules/globebrowsing/chunk/culling/horizonculler.h b/modules/globebrowsing/chunk/culling/horizonculler.h deleted file mode 100644 index f31246007e..0000000000 --- a/modules/globebrowsing/chunk/culling/horizonculler.h +++ /dev/null @@ -1,53 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___HORIZONCULLER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___HORIZONCULLER___H__ - -#include - -#include - -namespace openspace::globebrowsing::culling { - -/** - * In this implementation of the horizon culling, the closer the ellipsoid is to a - * sphere, the better this will make the culling. Using the minimum radius to - * be safe. This means that if the ellipsoid has high difference between radii, - * splitting might accur even though it may not be needed. - */ -class HorizonCuller : public ChunkCuller { -public: - virtual ~HorizonCuller() override = default; - bool isCullable(const Chunk& chunk, const RenderData& renderData) override; - -private: - bool isCullable(const glm::dvec3& cameraPosition, const glm::dvec3& globePosition, - const glm::dvec3& objectPosition, double objectBoundingSphereRadius, - double minimumGlobeRadius); -}; - -} // namespace openspace::globebrowsing::culling - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___HORIZONCULLER___H__ diff --git a/modules/globebrowsing/geometry/aabb.cpp b/modules/globebrowsing/geometry/aabb.cpp deleted file mode 100644 index 930822d44a..0000000000 --- a/modules/globebrowsing/geometry/aabb.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace openspace::globebrowsing { - -AABB1::AABB1(float minValue, float maxValue) - : min(minValue) - , max(maxValue) -{} - -void AABB1::expand(float p) { - min = glm::min(min, p); - max = glm::max(max, p); -} - -float AABB1::center() const { - return 0.5f * (min + max); -} - -float AABB1::size() const { - return max - min; -} - -bool AABB1::contains(float p) const { - return (min <= p) && (p <= max); -} - -bool AABB1::contains(const AABB1& o) const { - return (min <= o.min) && (o.max <= max); -} - -bool AABB1::intersects(const AABB1& o) const { - return (min <= o.max) && (o.min <= max); -} - -AABB1::AABBSpatialRelation AABB1::relationTo(const AABB1& o) const { - if (intersects(o)) { - if (contains(o)) { - return AABB1::AABBSpatialRelation::Containing; - } - if (o.contains(*this)) { - return AABB1::AABBSpatialRelation::Contained; - } - return AABB1::AABBSpatialRelation::Intersecting; - } - return AABB1::AABBSpatialRelation::None; -} - -AABB2::AABB2(glm::vec2 minValue, glm::vec2 maxValue) - : min(std::move(minValue)) - , max(std::move(maxValue)) -{} - -void AABB2::expand(const glm::vec2& p) { - min = glm::min(min, p); - max = glm::max(max, p); -} - -glm::vec2 AABB2::center() const { - return 0.5f * (min + max); -} - -glm::vec2 AABB2::size() const { - return max - min; -} - -bool AABB2::contains(const glm::vec2& p) const { - return (min.x <= p.x) && (p.x <= max.x) - && (min.y <= p.y) && (p.y <= max.y); -} - -bool AABB2::contains(const AABB2& o) const { - return (min.x <= o.min.x) && (o.max.x <= max.x) - && (min.y <= o.min.y) && (o.max.y <= max.y); -} - -bool AABB2::intersects(const AABB2& o) const { - return (min.x <= o.max.x) && (o.min.x <= max.x) - && (min.y <= o.max.y) && (o.min.y <= max.y); -} - -AABB2::AABBSpatialRelation AABB2::relationTo(const AABB2& o) const { - if (intersects(o)) { - if (contains(o)) { - return AABB2::AABBSpatialRelation::Containing; - } - if (o.contains(*this)) { - return AABB2::AABBSpatialRelation::Contained; - } - return AABB2::AABBSpatialRelation::Intersecting; - } - return AABB2::AABBSpatialRelation::None; -} - -AABB3::AABB3(glm::vec3 minValue, glm::vec3 maxValue) - : min(std::move(minValue)) - , max(std::move(maxValue)) -{} - -void AABB3::expand(glm::vec3 p) { - min = glm::min(min, p); - max = glm::max(max, p); -} - -glm::vec3 AABB3::center() const { - return 0.5f * (min + max); -} - -glm::vec3 AABB3::size() const { - return max - min; -} - -bool AABB3::contains(const glm::vec3& p) const { - return (min.x <= p.x) && (p.x <= max.x) - && (min.y <= p.y) && (p.y <= max.y) - && (min.z <= p.z) && (p.z <= max.z); -} - -bool AABB3::contains(const AABB3& o) const { - return (min.x <= o.min.x) && (o.max.x <= max.x) - && (min.y <= o.min.y) && (o.max.y <= max.y) - && (min.z <= o.min.z) && (o.max.z <= max.z); -} - -bool AABB3::intersects(const AABB3& o) const { - return (min.x <= o.max.x) && (o.min.x <= max.x) - && (min.y <= o.max.y) && (o.min.y <= max.y) - && (min.z <= o.max.z) && (o.min.z <= max.z); -} - -AABB3::AABBSpatialRelation AABB3::relationTo(const AABB3& o) const { - if (intersects(o)) { - if (contains(o)) { - return AABB3::AABBSpatialRelation::Containing; - } - if (o.contains(*this)) { - return AABB3::AABBSpatialRelation::Contained; - } - return AABB3::AABBSpatialRelation::Intersecting; - } - return AABB3::AABBSpatialRelation::None; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/geometry/aabb.h b/modules/globebrowsing/geometry/aabb.h deleted file mode 100644 index 62b2e3f8d8..0000000000 --- a/modules/globebrowsing/geometry/aabb.h +++ /dev/null @@ -1,103 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___AABB___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___AABB___H__ - -#include - -namespace openspace::globebrowsing { - -struct AABB1 { - enum class AABBSpatialRelation { - None, - Intersecting, - Contained, - Containing - }; - - AABB1(float minValue = std::numeric_limits::max(), - float maxValue = -std::numeric_limits::max()); - - void expand(float p); - float center() const; - float size() const; - bool contains(float p) const; - bool contains(const AABB1& o) const; - bool intersects(const AABB1& o) const; - AABBSpatialRelation relationTo(const AABB1& o) const; - - float min; - float max; -}; - -struct AABB2 { - enum class AABBSpatialRelation { - None, - Intersecting, - Contained, - Containing - }; - - AABB2(glm::vec2 minValue = glm::vec2(std::numeric_limits::max()), - glm::vec2 maxValue = glm::vec2(-std::numeric_limits::max())); - - void expand(const glm::vec2& p); - glm::vec2 center() const; - glm::vec2 size() const; - bool contains(const glm::vec2& p) const; - bool contains(const AABB2& o) const; - bool intersects(const AABB2& o) const; - AABBSpatialRelation relationTo(const AABB2& o) const; - - glm::vec2 min; - glm::vec2 max; -}; - -struct AABB3 { - enum class AABBSpatialRelation { - None, - Intersecting, - Contained, - Containing - }; - - AABB3(glm::vec3 minValue = glm::vec3(std::numeric_limits::max()), - glm::vec3 maxValue = glm::vec3(-std::numeric_limits::max())); - - void expand(const glm::vec3 p); - glm::vec3 center() const; - glm::vec3 size() const; - bool contains(const glm::vec3& p) const; - bool contains(const AABB3& o) const; - bool intersects(const AABB3& o) const; - AABBSpatialRelation relationTo(const AABB3& o) const; - - glm::vec3 min; - glm::vec3 max; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___AABB___H__ diff --git a/modules/globebrowsing/geometry/angle.h b/modules/globebrowsing/geometry/angle.h deleted file mode 100644 index 8826f2977e..0000000000 --- a/modules/globebrowsing/geometry/angle.h +++ /dev/null @@ -1,110 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___ANGLE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___ANGLE___H__ - -#include -#include -//#include - -namespace openspace::globebrowsing { - -template -class Angle { -public: - /** = 0 radians = 0 degrees = no revolution */ - static const Angle ZERO; - - /** = PI/2 radians = 90 degrees = quarter of a revolution */ - static const Angle QUARTER; - - /** = PI radians = 180 degrees = half a revolution */ - static const Angle HALF; - - /** = 2PI radians = 360 degrees = a full revolution */ - static const Angle FULL; - - static Angle fromRadians(T radians); - static Angle fromDegrees(T degrees); - - /** Copy constructor */ - Angle(const Angle& other); - -public: - inline T asRadians() const; - inline T asDegrees() const; - - Angle operator+(const Angle& rhs) const; - Angle operator-(const Angle& rhs) const; - Angle operator*(T rhs) const; - Angle operator/(T rhs) const; - - Angle operator-() const; - - void operator+=(const Angle& rhs); - void operator-=(const Angle& rhs); - void operator*=(T rhs); - void operator/=(T rhs); - - bool operator<(const Angle& rhs) const; - bool operator<=(const Angle& rhs) const; - bool operator>(const Angle& rhs) const; - bool operator>=(const Angle& rhs) const; - bool operator==(const Angle& rhs) const; - bool operator!=(const Angle& rhs) const; - - /** - * Normalizes the angle to the interval [0, 2pi[ - */ - Angle& normalize(); - - /** - * Normalizes the angle to the interval [center - pi, center + pi[ - */ - Angle& normalizeAround(const Angle& center); - - /** - * Clamps the angle to the interval [min, max]. - * Default arguments are [0, 2pi]. - */ - Angle& clamp(const Angle& min = ZERO, const Angle& max = FULL); - - Angle abs() const; - -private: - /** Private constructor. Use factory methods to avoid unit confusion */ - Angle(T rad); - - T _radians; -}; - -using dAngle = Angle; -using fAngle = Angle; - -} // namespace openspace::globebrowsing - -#include "angle.inl" - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___ANGLE___H__ diff --git a/modules/globebrowsing/geometry/angle.inl b/modules/globebrowsing/geometry/angle.inl deleted file mode 100644 index 65772f9bdb..0000000000 --- a/modules/globebrowsing/geometry/angle.inl +++ /dev/null @@ -1,205 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -namespace openspace::globebrowsing { - -////////////////////////////////////////////////////////////////////////////////////////// -// STATIC CONSTANTS // -////////////////////////////////////////////////////////////////////////////////////////// - -template -const Angle Angle::ZERO = Angle(T(0)); - -template -const Angle Angle::QUARTER = Angle(glm::half_pi()); - -template -const Angle Angle::HALF = Angle(glm::pi()); - -template -const Angle Angle::FULL = Angle(glm::two_pi()); - -////////////////////////////////////////////////////////////////////////////////////////// -// Constructors // -////////////////////////////////////////////////////////////////////////////////////////// - -template -Angle::Angle(const Angle& other) - : _radians(other._radians) -{} - -template -Angle::Angle(T radians) - : _radians(radians) -{} - -////////////////////////////////////////////////////////////////////////////////////////// -// Factory Methods // -////////////////////////////////////////////////////////////////////////////////////////// - -template -Angle Angle::fromRadians(T rads) { - return Angle(rads); -} - -template -Angle Angle::fromDegrees(T degrees) { - return Angle(glm::radians(degrees)); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// Conversions // -////////////////////////////////////////////////////////////////////////////////////////// - -template -T Angle::asRadians() const { - return _radians; -} - -template -T Angle::asDegrees() const { - return glm::degrees(_radians); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// Operators // -////////////////////////////////////////////////////////////////////////////////////////// - -template -Angle Angle::operator+(const Angle& rhs) const{ - return Angle(_radians + rhs._radians); -} - -template -Angle Angle::operator-(const Angle& rhs) const{ - return Angle(_radians - rhs._radians); -} - -template -Angle Angle::operator*(T multiplier) const{ - return Angle(_radians * multiplier); -} - -template -Angle Angle::operator/(T divisor) const{ - return Angle(_radians / divisor); -} - -template -Angle Angle::operator-() const { - return Angle(-_radians); -} - -template -void Angle::operator+=(const Angle& rhs){ - _radians += rhs._radians; -} - -template -void Angle::operator-=(const Angle& rhs){ - _radians -= rhs._radians; -} - -template -void Angle::operator*=(T multiplier){ - _radians *= multiplier; -} - -template -void Angle::operator/=(T divisor){ - _radians /= divisor; -} - -template -bool Angle::operator<(const Angle& rhs) const{ - return _radians < rhs._radians; -} - -template -bool Angle::operator<=(const Angle& rhs) const{ - return _radians <= rhs._radians; -} - -template -bool Angle::operator>(const Angle& rhs) const{ - return _radians > rhs._radians; -} - -template -bool Angle::operator>=(const Angle& rhs) const{ - return _radians >= rhs._radians; -} - -template -bool Angle::operator==(const Angle& rhs) const{ - return _radians == rhs._radians; -} - -template -bool Angle::operator!=(const Angle& rhs) const{ - return _radians != rhs._radians; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// Chainable Relative Mutators // -////////////////////////////////////////////////////////////////////////////////////////// - -template -Angle& Angle::normalize() { - // this will cause _radians to be in value range ]-2pi, 2pi[ - _radians = fmod(_radians, glm::two_pi()); - - // ensure _radians are positive, ie in value range [0, 2pi[ - if (_radians < T(0)) { - _radians += glm::two_pi(); - } - - return *this; -} - -template -Angle& Angle::normalizeAround(const Angle& center) { - _radians -= center._radians + glm::pi(); - normalize(); - _radians += center._radians - glm::pi(); - return *this; -} - -template -Angle& Angle::clamp(const Angle& min, const Angle& max) { - const T& minRad = min._radians; - const T& maxRad = max._radians; - - _radians = glm::clamp(_radians, minRad, maxRad); - return *this; -} - -template -Angle Angle::abs() const { - return Angle::fromRadians(glm::abs(_radians)); -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/geometry/geodetic2.h b/modules/globebrowsing/geometry/geodetic2.h deleted file mode 100644 index 94fcf413ba..0000000000 --- a/modules/globebrowsing/geometry/geodetic2.h +++ /dev/null @@ -1,55 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GEODETIC2___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GEODETIC2___H__ - -#include - -namespace openspace::globebrowsing { - -struct Geodetic2 { - Geodetic2(double latitude = 0.0, double longitude = 0.0); - Geodetic2(const Geodetic2& src) = default; - - //static Geodetic2 fromCartesian(const Vec3& v); - //Vec3 asUnitCartesian() const; - - glm::dvec2 toLonLatVec2() const; - - bool operator==(const Geodetic2& other) const; - bool operator!=(const Geodetic2& other) const { return !(*this == (other)); } - - Geodetic2 operator+(const Geodetic2& other) const; - Geodetic2 operator-(const Geodetic2& other) const; - Geodetic2 operator*(double scalar) const; - Geodetic2 operator/(double scalar) const; - - double lat; - double lon; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GEODETIC2___H__ diff --git a/modules/globebrowsing/geometry/geodetic3.h b/modules/globebrowsing/geometry/geodetic3.h deleted file mode 100644 index 3f5f41880b..0000000000 --- a/modules/globebrowsing/geometry/geodetic3.h +++ /dev/null @@ -1,39 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GEODETIC3___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GEODETIC3___H__ - -#include - -namespace openspace::globebrowsing { - -struct Geodetic3 { - Geodetic2 geodetic2; - double height; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GEODETIC3___H__ diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index abd78cc7e3..060b4fdc86 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -24,20 +24,12 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -48,7 +40,6 @@ #include #include -#ifdef GLOBEBROWSING_USE_GDAL #include #ifdef _MSC_VER @@ -63,14 +54,11 @@ #pragma warning (pop) #endif // _MSC_VER -#endif // GLOBEBROWSING_USE_GDAL - #include "globebrowsingmodule_lua.inl" namespace { constexpr const char* _loggerCat = "GlobeBrowsingModule"; -#ifdef GLOBEBROWSING_USE_GDAL openspace::GlobeBrowsingModule::Capabilities parseSubDatasets(char** subDatasets, int nSubdatasets) { @@ -121,9 +109,6 @@ namespace { return result; } - -#endif // GLOBEBROWSING_USE_GDAL - } // namespace namespace openspace { @@ -138,14 +123,18 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary&) { _tileCache = std::make_unique(); addPropertySubOwner(*_tileCache); -#ifdef GLOBEBROWSING_USE_GDAL + tileprovider::initializeDefaultTile(); + // Convert from MB to Bytes GdalWrapper::create( 16ULL * 1024ULL * 1024ULL, // 16 MB static_cast(CpuCap.installedMainMemory() * 0.25 * 1024 * 1024) ); addPropertySubOwner(GdalWrapper::ref()); -#endif // GLOBEBROWSING_USE_GDAL + }); + + global::callback::deinitializeGL.push_back([]() { + tileprovider::deinitializeDefaultTile(); }); @@ -153,9 +142,7 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary&) { global::callback::render.push_back([&]() { _tileCache->update(); }); // Deinitialize -#ifdef GLOBEBROWSING_USE_GDAL global::callback::deinitialize.push_back([&]() { GdalWrapper::ref().destroy(); }); -#endif // GLOBEBROWSING_USE_GDAL // Get factories auto fRenderable = FactoryManager::ref().factory(); @@ -177,12 +164,10 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary&) { layergroupid::LAYER_TYPE_NAMES[static_cast( layergroupid::TypeID::SingleImageTileLayer )]); -#ifdef GLOBEBROWSING_USE_GDAL fTileProvider->registerClass( layergroupid::LAYER_TYPE_NAMES[static_cast( layergroupid::TypeID::TemporalTileLayer )]); -#endif // GLOBEBROWSING_USE_GDAL fTileProvider->registerClass( layergroupid::LAYER_TYPE_NAMES[static_cast( layergroupid::TypeID::TileIndexTileLayer @@ -273,7 +258,6 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { "Get geographic coordinates of the camera poosition in latitude, " "longitude, and altitude" }, -#ifdef GLOBEBROWSING_USE_GDAL { "loadWMSCapabilities", &globebrowsing::luascriptfunctions::loadWMSCapabilities, @@ -304,7 +288,6 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { "component of the returned table can be used in the 'FilePath' argument " "for a call to the 'addLayer' function to add the value to a globe." } -#endif // GLOBEBROWSING_USE_GDAL }; res.scripts = { absPath("${MODULE_GLOBEBROWSING}/scripts/layer_support.lua") @@ -321,9 +304,11 @@ void GlobeBrowsingModule::goToChunk(int x, int y, int level) { void GlobeBrowsingModule::goToGeo(double latitude, double longitude) { using namespace globebrowsing; Camera* cam = global::navigationHandler.camera(); - goToGeodetic2(*cam, Geodetic2( - Angle::fromDegrees(latitude).asRadians(), - Angle::fromDegrees(longitude).asRadians()), true); + goToGeodetic2( + *cam, + Geodetic2{ glm::radians(latitude), glm::radians(longitude) }, + true + ); } void GlobeBrowsingModule::goToGeo(double latitude, double longitude, @@ -335,9 +320,7 @@ void GlobeBrowsingModule::goToGeo(double latitude, double longitude, goToGeodetic3( *cam, { - Geodetic2( - Angle::fromDegrees(latitude).asRadians(), - Angle::fromDegrees(longitude).asRadians()), + Geodetic2{ glm::radians(latitude), glm::radians(longitude) }, altitude }, true @@ -351,10 +334,7 @@ glm::vec3 GlobeBrowsingModule::cartesianCoordinatesFromGeo( using namespace globebrowsing; const Geodetic3 pos = { - { - Angle::fromDegrees(latitude).asRadians(), - Angle::fromDegrees(longitude).asRadians() - }, + { glm::radians(latitude), glm::radians(longitude) }, altitude }; @@ -379,7 +359,7 @@ void GlobeBrowsingModule::goToChunk(Camera& camera, const globebrowsing::TileInd // Camera position in model space const glm::dvec3 camPos = camera.positionVec3(); - const glm::dmat4 inverseModelTransform = globe->inverseModelTransform(); + const glm::dmat4 inverseModelTransform = glm::inverse(globe->modelTransform()); const glm::dvec3 cameraPositionModelSpace = glm::dvec3( inverseModelTransform * glm::dvec4(camPos, 1) ); @@ -389,7 +369,10 @@ void GlobeBrowsingModule::goToChunk(Camera& camera, const globebrowsing::TileInd Geodetic2 positionOnPatch = patch.size(); positionOnPatch.lat *= uv.y; positionOnPatch.lon *= uv.x; - const Geodetic2 pointPosition = corner + positionOnPatch; + const Geodetic2 pointPosition = { + corner.lat + positionOnPatch.lat, + corner.lon + positionOnPatch.lon + }; const glm::dvec3 positionOnEllipsoid = globe->ellipsoid().geodeticSurfaceProjection( cameraPositionModelSpace @@ -467,7 +450,7 @@ void GlobeBrowsingModule::resetCameraDirection(Camera& camera, geo2 ); const glm::dvec3 slightlyNorth = globe->ellipsoid().cartesianSurfacePosition( - Geodetic2(geo2.lat + 0.001, geo2.lon) + Geodetic2{ geo2.lat + 0.001, geo2.lon } ); const glm::dvec3 lookUpModelSpace = glm::normalize( slightlyNorth - positionModelSpace @@ -534,8 +517,6 @@ std::string GlobeBrowsingModule::layerTypeNamesList() { return listLayerTypes; } -#ifdef GLOBEBROWSING_USE_GDAL - void GlobeBrowsingModule::loadWMSCapabilities(std::string name, std::string globe, std::string url) { @@ -624,6 +605,4 @@ bool GlobeBrowsingModule::hasUrlInfo(const std::string& globe) const { return _urlList.find(globe) != _urlList.end(); } -#endif // GLOBEBROWSING_USE_GDAL - } // namespace openspace diff --git a/modules/globebrowsing/globebrowsingmodule.h b/modules/globebrowsing/globebrowsingmodule.h index 7f26d9b479..e7d62e7c12 100644 --- a/modules/globebrowsing/globebrowsingmodule.h +++ b/modules/globebrowsing/globebrowsingmodule.h @@ -61,7 +61,6 @@ public: scripting::LuaLibrary luaLibrary() const override; const globebrowsing::RenderableGlobe* castFocusNodeRenderableToGlobe(); -#ifdef GLOBEBROWSING_USE_GDAL struct Layer { std::string name; std::string url; @@ -82,7 +81,6 @@ public: bool hasUrlInfo(const std::string& globe) const; void removeWMSServer(const std::string& name); -#endif // GLOBEBROWSING_USE_GDAL protected: void internalInitialize(const ghoul::Dictionary&) override; @@ -108,14 +106,12 @@ private: std::unique_ptr _tileCache; -#ifdef GLOBEBROWSING_USE_GDAL // name -> capabilities std::map> _inFlightCapabilitiesMap; // name -> capabilities std::map _capabilitiesMap; std::multimap _urlList; -#endif // GLOBEBROWSING_USE_GDAL }; } // namespace openspace diff --git a/modules/globebrowsing/globebrowsingmodule_lua.inl b/modules/globebrowsing/globebrowsingmodule_lua.inl index 746fdb0017..5fb59b3bad 100644 --- a/modules/globebrowsing/globebrowsingmodule_lua.inl +++ b/modules/globebrowsing/globebrowsingmodule_lua.inl @@ -22,17 +22,15 @@ * 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 @@ -58,13 +56,15 @@ int addLayer(lua_State* L) { } // Get the renderable globe - const RenderableGlobe* globe = dynamic_cast(n->renderable()); + RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { return ghoul::lua::luaError(L, "Renderable is not a globe: " + globeName); } // Get the layer group - layergroupid::GroupID groupID = layergroupid::getGroupIDFromName(layerGroupName); + layergroupid::GroupID groupID = ghoul::from_string( + layerGroupName + ); if (groupID == layergroupid::GroupID::Unknown) { return ghoul::lua::luaError(L, "Unknown layer group: " + layerGroupName); } @@ -81,7 +81,7 @@ int addLayer(lua_State* L) { } lua_settop(L, 0); - std::shared_ptr layer = globe->layerManager()->addLayer(groupID, d); + Layer* layer = globe->layerManager().addLayer(groupID, d); if (layer) { layer->initialize(); } @@ -108,18 +108,20 @@ int deleteLayer(lua_State* L) { } // Get the renderable globe - const RenderableGlobe* globe = dynamic_cast(n->renderable()); + RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { return ghoul::lua::luaError(L, "Renderable is not a globe: " + globeName); } // Get the layer group - layergroupid::GroupID groupID = layergroupid::getGroupIDFromName(layerGroupName); + layergroupid::GroupID groupID = ghoul::from_string( + layerGroupName + ); if (groupID == layergroupid::GroupID::Unknown) { return ghoul::lua::luaError(L, "Unknown layer group: " + layerGroupName); } - globe->layerManager()->deleteLayer(groupID, layerName); + globe->layerManager().deleteLayer(groupID, layerName); ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; @@ -219,18 +221,12 @@ int getGeoPositionForCamera(lua_State* L) { const double altitude = glm::length(cameraPositionModelSpace - posHandle.centerToReferenceSurface); - ghoul::lua::push( - L, - Angle::fromRadians(geo2.lat).asDegrees(), - Angle::fromRadians(geo2.lon).asDegrees(), - altitude - ); + ghoul::lua::push(L, glm::degrees(geo2.lat), glm::degrees(geo2.lon), altitude); ghoul_assert(lua_gettop(L) == 3, "Incorrect number of items left on stack"); return 3; } -#ifdef GLOBEBROWSING_USE_GDAL int loadWMSCapabilities(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::loadWMSCapabilities"); @@ -294,6 +290,5 @@ int capabilities(lua_State* L) { ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } -#endif // GLOBEBROWSING_USE_GDAL } // namespace openspace::globebrowsing::luascriptfunctions diff --git a/modules/globebrowsing/globes/chunkedlodglobe.cpp b/modules/globebrowsing/globes/chunkedlodglobe.cpp deleted file mode 100644 index 63cae9832c..0000000000 --- a/modules/globebrowsing/globes/chunkedlodglobe.cpp +++ /dev/null @@ -1,397 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include - -namespace { - const openspace::globebrowsing::GeodeticPatch Coverage = - openspace::globebrowsing::GeodeticPatch(0, 0, 90, 180); - - const openspace::globebrowsing::TileIndex LeftHemisphereIndex = - openspace::globebrowsing::TileIndex(0, 0, 1); - - const openspace::globebrowsing::TileIndex RightHemisphereIndex = - openspace::globebrowsing::TileIndex(1, 0, 1); -} // namespace - -namespace openspace::globebrowsing { - -ChunkedLodGlobe::ChunkedLodGlobe(const RenderableGlobe& owner, size_t segmentsPerPatch, - std::shared_ptr layerManager, - Ellipsoid& ellipsoid) - : Renderable({ { "Identifier", owner.identifier() }, { "Name", owner.guiName() } }) -#ifdef DEBUG_GLOBEBROWSING_STATSRECORD - , stats(StatsCollector(absPath("test_stats"), 1, StatsCollector::Enabled::No)) -#endif // DEBUG_GLOBEBROWSING_STATSRECORD - , _owner(owner) - , _leftRoot(std::make_unique(Chunk(owner, LeftHemisphereIndex))) - , _rightRoot(std::make_unique(Chunk(owner, RightHemisphereIndex))) - , _layerManager(layerManager) -{ - std::shared_ptr geometry = std::make_shared( - static_cast(segmentsPerPatch), - static_cast(segmentsPerPatch), - TriangleSoup::Positions::No, - TriangleSoup::TextureCoordinates::Yes, - TriangleSoup::Normals::No - ); - - _chunkCullers.push_back(std::make_unique()); - _chunkCullers.push_back(std::make_unique( - AABB3( - glm::vec3(-1, -1, 0), - glm::vec3(1, 1, 1e35) - ) - )); - - _chunkEvaluatorByAvailableTiles = - std::make_unique(); - _chunkEvaluatorByProjectedArea = - std::make_unique(); - _chunkEvaluatorByDistance = std::make_unique(); - - _renderer = std::make_unique(geometry, layerManager, ellipsoid); -} - -ChunkedLodGlobe::~ChunkedLodGlobe() {} // NOLINT - -bool ChunkedLodGlobe::isReady() const { - return true; -} - -std::shared_ptr ChunkedLodGlobe::layerManager() const { - return _layerManager; -} - -bool ChunkedLodGlobe::testIfCullable(const Chunk& chunk, - const RenderData& renderData) const -{ - if (_owner.debugProperties().performHorizonCulling && - _chunkCullers[0]->isCullable(chunk, renderData)) { - return true; - } - if (_owner.debugProperties().performFrustumCulling && - _chunkCullers[1]->isCullable(chunk, renderData)) { - return true; - } - return false; -} - -const ChunkNode& ChunkedLodGlobe::findChunkNode(const Geodetic2& location) const { - ghoul_assert( - Coverage.contains(location), - "Point must be in lat [-90, 90] and lon [-180, 180]" - ); - - return location.lon < Coverage.center().lon ? - _leftRoot->find(location) : - _rightRoot->find(location); -} - -int ChunkedLodGlobe::desiredLevel(const Chunk& chunk, - const RenderData& renderData) const -{ - int desiredLevel = 0; - if (_owner.debugProperties().levelByProjectedAreaElseDistance) { - desiredLevel = _chunkEvaluatorByProjectedArea->desiredLevel(chunk, renderData); - } - else { - desiredLevel = _chunkEvaluatorByDistance->desiredLevel(chunk, renderData); - } - - int levelByAvailableData = _chunkEvaluatorByAvailableTiles->desiredLevel( - chunk, - renderData - ); - if (levelByAvailableData != chunklevelevaluator::Evaluator::UnknownDesiredLevel && - _owner.debugProperties().limitLevelByAvailableData) - { - desiredLevel = glm::min(desiredLevel, levelByAvailableData); - } - - desiredLevel = glm::clamp(desiredLevel, MinSplitDepth, MaxSplitDepth); - return desiredLevel; -} - -float ChunkedLodGlobe::getHeight(const glm::dvec3& position) const { - float height = 0; - - // Get the uv coordinates to sample from - const Geodetic2 geodeticPosition = _owner.ellipsoid().cartesianToGeodetic2(position); - const int chunkLevel = findChunkNode(geodeticPosition).chunk().tileIndex().level; - - const TileIndex tileIndex = TileIndex(geodeticPosition, chunkLevel); - const GeodeticPatch patch = GeodeticPatch(tileIndex); - - const Geodetic2 geoDiffPatch = patch.corner(Quad::NORTH_EAST) - - patch.corner(Quad::SOUTH_WEST); - - const Geodetic2 geoDiffPoint = geodeticPosition - patch.corner(Quad::SOUTH_WEST); - const glm::vec2 patchUV = glm::vec2( - geoDiffPoint.lon / geoDiffPatch.lon, - geoDiffPoint.lat / geoDiffPatch.lat - ); - - // Get the tile providers for the height maps - const std::vector>& heightMapLayers = - _layerManager->layerGroup(layergroupid::GroupID::HeightLayers).activeLayers(); - - for (const std::shared_ptr& layer : heightMapLayers) { - tileprovider::TileProvider* tileProvider = layer->tileProvider(); - if (!tileProvider) { - continue; - } - // Transform the uv coordinates to the current tile texture - const ChunkTile chunkTile = tileProvider->chunkTile(tileIndex); - const Tile& tile = chunkTile.tile; - const TileUvTransform& uvTransform = chunkTile.uvTransform; - const TileDepthTransform& depthTransform = tileProvider->depthTransform(); - if (tile.status() != Tile::Status::OK) { - return 0; - } - - ghoul::opengl::Texture* tileTexture = tile.texture(); - if (!tileTexture) { - return 0; - } - - glm::vec2 transformedUv = layer->TileUvToTextureSamplePosition( - uvTransform, - patchUV, - glm::uvec2(tileTexture->dimensions()) - ); - - // Sample and do linear interpolation - // (could possibly be moved as a function in ghoul texture) - // Suggestion: a function in ghoul::opengl::Texture that takes uv coordinates - // in range [0,1] and uses the set interpolation method and clamping. - - const glm::uvec3 dimensions = tileTexture->dimensions(); - - const glm::vec2 samplePos = transformedUv * glm::vec2(dimensions); - glm::uvec2 samplePos00 = samplePos; - samplePos00 = glm::clamp( - samplePos00, - glm::uvec2(0, 0), - glm::uvec2(dimensions) - glm::uvec2(1) - ); - const glm::vec2 samplePosFract = samplePos - glm::vec2(samplePos00); - - const glm::uvec2 samplePos10 = glm::min( - samplePos00 + glm::uvec2(1, 0), - glm::uvec2(dimensions) - glm::uvec2(1) - ); - const glm::uvec2 samplePos01 = glm::min( - samplePos00 + glm::uvec2(0, 1), - glm::uvec2(dimensions) - glm::uvec2(1) - ); - const glm::uvec2 samplePos11 = glm::min( - samplePos00 + glm::uvec2(1, 1), - glm::uvec2(dimensions) - glm::uvec2(1) - ); - - const float sample00 = tileTexture->texelAsFloat(samplePos00).x; - const float sample10 = tileTexture->texelAsFloat(samplePos10).x; - const float sample01 = tileTexture->texelAsFloat(samplePos01).x; - const float sample11 = tileTexture->texelAsFloat(samplePos11).x; - - // In case the texture has NaN or no data values don't use this height map. - const bool anySampleIsNaN = - std::isnan(sample00) || - std::isnan(sample01) || - std::isnan(sample10) || - std::isnan(sample11); - - const bool anySampleIsNoData = - sample00 == tileProvider->noDataValueAsFloat() || - sample01 == tileProvider->noDataValueAsFloat() || - sample10 == tileProvider->noDataValueAsFloat() || - sample11 == tileProvider->noDataValueAsFloat(); - - if (anySampleIsNaN || anySampleIsNoData) { - continue; - } - - const float sample0 = sample00 * (1.f - samplePosFract.x) + - sample10 * samplePosFract.x; - const float sample1 = sample01 * (1.f - samplePosFract.x) + - sample11 * samplePosFract.x; - - const float sample = sample0 * (1.f - samplePosFract.y) + - sample1 * samplePosFract.y; - - // Same as is used in the shader. This is not a perfect solution but - // if the sample is actually a no-data-value (min_float) the interpolated - // value might not be. Therefore we have a cut-off. Assuming no data value - // is smaller than -100000 - if (sample > -100000) { - // 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; -} - -void ChunkedLodGlobe::notifyShaderRecompilation() { - _shadersNeedRecompilation = true; -} - -void ChunkedLodGlobe::recompileShaders() { - _renderer->recompileShaders(_owner); - _shadersNeedRecompilation = false; -} - -void ChunkedLodGlobe::render(const RenderData& data, RendererTasks&) { -#ifdef DEBUG_GLOBEBROWSING_STATSRECORD - stats.startNewRecord(); -#endif // DEBUG_GLOBEBROWSING_STATSRECORD - if (_shadersNeedRecompilation) { - _renderer->recompileShaders(_owner); - _shadersNeedRecompilation = false; - } - -#ifdef DEBUG_GLOBEBROWSING_STATSRECORD - auto duration = std::chrono::system_clock::now().time_since_epoch(); - auto millis = std::chrono::duration_cast(duration).count(); - stats.i["time"] = millis; -#endif // DEBUG_GLOBEBROWSING_STATSRECORD - - _leftRoot->updateChunkTree(data); - _rightRoot->updateChunkTree(data); - - // Calculate the MVP matrix - const glm::dmat4 viewTransform = glm::dmat4(data.camera.combinedViewMatrix()); - const glm::dmat4 vp = glm::dmat4(data.camera.sgctInternal.projectionMatrix()) * - viewTransform; - const glm::dmat4 mvp = vp * _owner.modelTransform(); - - // Render function - auto renderJob = [this, &data, &mvp](const ChunkNode& chunkNode) { -#ifdef DEBUG_GLOBEBROWSING_STATSRECORD - stats.i["chunks nodes"]++; -#endif // DEBUG_GLOBEBROWSING_STATSRECORD - const Chunk& chunk = chunkNode.chunk(); - if (chunkNode.isLeaf()) { -#ifdef DEBUG_GLOBEBROWSING_STATSRECORD - stats.i["leafs chunk nodes"]++; -#endif // DEBUG_GLOBEBROWSING_STATSRECORD - - if (chunk.isVisible()) { -#ifdef DEBUG_GLOBEBROWSING_STATSRECORD - stats.i["rendered chunks"]++; -#endif // DEBUG_GLOBEBROWSING_STATSRECORD - _renderer->renderChunk(chunkNode.chunk(), data); - debugRenderChunk(chunk, mvp); - } - } - }; - - _leftRoot->breadthFirst(renderJob); - _rightRoot->breadthFirst(renderJob); - - //_leftRoot->reverseBreadthFirst(renderJob); - //_rightRoot->reverseBreadthFirst(renderJob); - -#ifdef DEBUG_GLOBEBROWSING_STATSRECORD - auto duration2 = std::chrono::system_clock::now().time_since_epoch(); - auto ms2 = std::chrono::duration_cast(duration2).count(); - stats.i["chunk globe render time"] = ms2 - millis; -#endif // DEBUG_GLOBEBROWSING_STATSRECORD -} - -void ChunkedLodGlobe::debugRenderChunk(const Chunk& chunk, const glm::dmat4& mvp) const { - if (_owner.debugProperties().showChunkBounds || - _owner.debugProperties().showChunkAABB) - { - const std::vector& modelSpaceCorners = - chunk.boundingPolyhedronCorners(); - - std::vector clippingSpaceCorners(8); - AABB3 screenSpaceBounds; - - for (size_t i = 0; i < 8; ++i) { - const glm::vec4& clippingSpaceCorner = mvp * modelSpaceCorners[i]; - clippingSpaceCorners[i] = clippingSpaceCorner; - - glm::vec3 screenSpaceCorner = - glm::vec3((1.f / clippingSpaceCorner.w) * clippingSpaceCorner); - screenSpaceBounds.expand(std::move(screenSpaceCorner)); - } - - const unsigned int colorBits = 1 + chunk.tileIndex().level % 6; - const glm::vec4 color = glm::vec4( - colorBits & 1, - colorBits & 2, - colorBits & 4, - 0.3f - ); - - if (_owner.debugProperties().showChunkBounds) { - DebugRenderer::ref().renderNiceBox(clippingSpaceCorners, color); - } - - if (_owner.debugProperties().showChunkAABB) { - const std::vector& screenSpacePoints = - DebugRenderer::ref().verticesFor(screenSpaceBounds); - DebugRenderer::ref().renderNiceBox(screenSpacePoints, color); - } - } -} - -void ChunkedLodGlobe::update(const UpdateData& data) { - setBoundingSphere(static_cast( - _owner.ellipsoid().maximumRadius() * data.modelTransform.scale - )); - _renderer->update(); -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/globes/chunkedlodglobe.h b/modules/globebrowsing/globes/chunkedlodglobe.h deleted file mode 100644 index 4dbd80c42d..0000000000 --- a/modules/globebrowsing/globes/chunkedlodglobe.h +++ /dev/null @@ -1,154 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKED_LOD_GLOBE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKED_LOD_GLOBE___H__ - -#include - -#include - -//#define DEBUG_GLOBEBROWSING_STATSRECORD - -#ifdef DEBUG_GLOBEBROWSING_STATSRECORD -#include -#endif // DEBUG_GLOBEBROWSING_STATSRECORD - -namespace openspace::globebrowsing { - -namespace chunklevelevaluator { class Evaluator; } - -namespace culling { class ChunkCuller; } - -class Chunk; -class ChunkNode; -class ChunkRenderer; -class Ellipsoid; -struct Geodetic2; -class LayerManager; -class RenderableGlobe; - -class ChunkedLodGlobe : public Renderable { -public: - ChunkedLodGlobe(const RenderableGlobe& owner, size_t segmentsPerPatch, - std::shared_ptr layerManager, Ellipsoid& ellipsoid); - ~ChunkedLodGlobe(); - - bool isReady() const override; - - void render(const RenderData& data, RendererTasks& rendererTask) override; - void update(const UpdateData& data) override; - - /** - * Traverse the chunk tree and find the highest level chunk node. - * - * \param location is given in geodetic coordinates and must be in the range - * latitude [-90, 90] and longitude [-180, 180]. In other words, it must be a - * position defined on the globe in georeferenced coordinates. - */ - const ChunkNode& findChunkNode(const Geodetic2& location) const; - - /** - * Test if a specific chunk can saf;ely be culled without affecting the rendered - * image. - * - * Goes through all available ChunkCullers and check if any of them - * allows culling of the Chunks in question. - */ - bool testIfCullable(const Chunk& chunk, const RenderData& renderData) const; - - /** - * Gets the desired level which can be used to determine if a chunk should split - * or merge. - * - * Using ChunkLevelEvaluators, the desired level can be higher or - * lower than the current level of the Chunkss - * TileIndex. If the desired level is higher than that of the - * Chunk, it wants to split. If it is lower, it wants to merge with - * its siblings. - */ - int desiredLevel(const Chunk& chunk, const RenderData& renderData) const; - - /** - * Calculates the height from the surface of the reference ellipsoid to the - * heigh mapped surface. - * - * The height can be negative if the height map contains negative values. - * - * \param position is the position of a point that gets geodetically - * projected on the reference ellipsoid. position must be in - * cartesian model space. - * \returns the height from the reference ellipsoid to the globe surface. - */ - float getHeight(const glm::dvec3& position) const; - - /** - * Notifies the renderer to recompile its shaders the next time the render function is - * called. The actual shader recompilation takes place in the render function because - * properties that the shader depends on need to be properly synced. - */ - void notifyShaderRecompilation(); - - /** - * Directly recompile the shaders of the renderer. - */ - void recompileShaders(); - - constexpr static const int MinSplitDepth = 2; - constexpr static const int MaxSplitDepth = 22; - - std::shared_ptr layerManager() const; - -#ifdef DEBUG_GLOBEBROWSING_STATSRECORD - StatsCollector stats; -#endif // DEBUG_GLOBEBROWSING_STATSRECORD - -private: - void debugRenderChunk(const Chunk& chunk, const glm::dmat4& mvp) const; - - const RenderableGlobe& _owner; - - // Covers all negative longitudes - std::unique_ptr _leftRoot; - - // Covers all positive longitudes - std::unique_ptr _rightRoot; - - // the patch used for actual rendering - std::unique_ptr _renderer; - - std::vector> _chunkCullers; - - std::unique_ptr _chunkEvaluatorByAvailableTiles; - std::unique_ptr _chunkEvaluatorByProjectedArea; - std::unique_ptr _chunkEvaluatorByDistance; - - std::shared_ptr _layerManager; - - bool _shadersNeedRecompilation = true; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKED_LOD_GLOBE___H__ diff --git a/modules/globebrowsing/globes/pointglobe.cpp b/modules/globebrowsing/globes/pointglobe.cpp deleted file mode 100644 index a408c7ff93..0000000000 --- a/modules/globebrowsing/globes/pointglobe.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include - -namespace { - constexpr const std::array UniformNames = { - "lightIntensityClamped", "modelViewTransform", "projectionTransform" - }; - - constexpr openspace::properties::Property::PropertyInfo IntensityClampInfo = { - "IntensityClamp", - "Intensity clamp", - "" - }; - - constexpr openspace::properties::Property::PropertyInfo LightIntensityInfo = { - "LightIntensity", - "Light intensity", - "" // @TODO Missing documentation - }; -} // namespace - -namespace openspace::globebrowsing { - -PointGlobe::PointGlobe(const RenderableGlobe& owner) - : Renderable({ { "Identifier", owner.identifier() }, { "Name", owner.guiName() } }) - , _owner(owner) - , _intensityClamp(IntensityClampInfo, 1.f, 0.f, 1.f) - , _lightIntensity(LightIntensityInfo, 1.f, 0.f, 50.f) -{ - addProperty(_intensityClamp); - addProperty(_lightIntensity); -} - -PointGlobe::~PointGlobe() { - glDeleteBuffers(1, &_vertexBufferID); - glDeleteVertexArrays(1, &_vaoID); -} - -void PointGlobe::initialize() { - _programObject = global::renderEngine.buildRenderProgram( - "PointGlobe", - absPath("${MODULE_GLOBEBROWSING}/shaders/pointglobe_vs.glsl"), - absPath("${MODULE_GLOBEBROWSING}/shaders/pointglobe_fs.glsl") - ); - - ghoul::opengl::updateUniformLocations(*_programObject, _uniformCache, UniformNames); - - glGenVertexArrays(1, &_vaoID); - glGenBuffers(1, &_vertexBufferID); - - glBindVertexArray(_vaoID); - - std::array quadVertexData = { - -1.f, -1.f, - 1.f, -1.f, - -1.f, 1.f, - -1.f, 1.f, - 1.f, -1.f, - 1.f, 1.f - }; - - // Vertex buffer - glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID); - glBufferData( - GL_ARRAY_BUFFER, - sizeof(float) * quadVertexData.size(), - quadVertexData.data(), - GL_STATIC_DRAW - ); - - // Position at location 0 - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr); - - glBindVertexArray(0); -} - -void PointGlobe::deinitialize() { - glDeleteVertexArrays(1, &_vaoID); - glDeleteBuffers(1, &_vertexBufferID); -} - -bool PointGlobe::isReady() const { - return (_vaoID != 0) && (_vertexBufferID != 0); -} - -void PointGlobe::render(const RenderData& data, RendererTasks&) { - _programObject->activate(); - - // Calculate variables to be used as uniform variables in shader - const glm::dvec3 bodyPosition = data.modelTransform.translation; - - const glm::dmat4 rotationTransform = glm::lookAt( - glm::dvec3(0.0f), - data.camera.positionVec3() - bodyPosition, - glm::normalize(glm::dvec3(1000000.0f) - bodyPosition) - ); - - const glm::dvec3 camToBody = bodyPosition - data.camera.positionVec3(); - const float distanceToBody = static_cast(glm::length(camToBody)); - - const float avgRadius = static_cast(_owner.ellipsoid().averageRadius()); - const float lightIntensity = static_cast( - _lightIntensity.value() * data.modelTransform.scale * avgRadius / distanceToBody - ); - const float lightIntensityClamped = glm::min(lightIntensity, _intensityClamp.value()); - //float lightOverflow = glm::max(lightIntensity - lightIntensityClamped, 0.0f); - - const float billboardRadius = lightIntensityClamped * distanceToBody; - const glm::dmat4 scaleTransform = glm::scale( - glm::dmat4(1.0), glm::dvec3(billboardRadius) - ); - - setBoundingSphere(billboardRadius); - - // Model transform and view transform needs to be in double precision - const glm::dmat4 modelTransform = glm::translate(glm::dmat4(1.0), bodyPosition) * - glm::inverse(rotationTransform) * - scaleTransform; // Scale - const glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * - modelTransform; - - - _programObject->setUniform( - _uniformCache.lightIntensityClamped, - lightIntensityClamped - ); - //_program->setUniform("lightOverflow", lightOverflow); - //_program->setUniform("directionToSunViewSpace", directionToSunViewSpace); - _programObject->setUniform( - _uniformCache.modelView, - glm::mat4(modelViewTransform) - ); - _programObject->setUniform( - _uniformCache.projection, - data.camera.sgctInternal.projectionMatrix() - ); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - - glBindVertexArray(_vaoID); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vertexBufferID); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - _programObject->deactivate(); -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/globes/pointglobe.h b/modules/globebrowsing/globes/pointglobe.h deleted file mode 100644 index c986993862..0000000000 --- a/modules/globebrowsing/globes/pointglobe.h +++ /dev/null @@ -1,65 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___POINTGLOBE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___POINTGLOBE___H__ - -#include - -#include -#include -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace::globebrowsing { - -class RenderableGlobe; - -class PointGlobe : public Renderable { -public: - PointGlobe(const RenderableGlobe& owner); - virtual ~PointGlobe(); - - void initialize() override; - void deinitialize() override; - bool isReady() const override; - - void render(const RenderData& data, RendererTasks& rendererTask) override; - -private: - const RenderableGlobe& _owner; - std::unique_ptr _programObject; - UniformCache(lightIntensityClamped, modelView, projection) _uniformCache; - - GLuint _vertexBufferID = 0; - GLuint _vaoID = 0; - - properties::FloatProperty _intensityClamp; - properties::FloatProperty _lightIntensity; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___POINTGLOBE___H__ diff --git a/modules/globebrowsing/globes/renderableglobe.cpp b/modules/globebrowsing/globes/renderableglobe.cpp deleted file mode 100644 index bc98c4f556..0000000000 --- a/modules/globebrowsing/globes/renderableglobe.cpp +++ /dev/null @@ -1,534 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -namespace { - constexpr const char* keyFrame = "Frame"; - constexpr const char* keyRadii = "Radii"; - constexpr const char* keySegmentsPerPatch = "SegmentsPerPatch"; - constexpr const char* keyLayers = "Layers"; - constexpr const char* keyShadowGroup = "ShadowGroup"; - constexpr const char* keyShadowSource = "Source"; - constexpr const char* keyShadowCaster = "Caster"; - - constexpr openspace::properties::Property::PropertyInfo SaveOrThrowInfo = { - "SaveOrThrowCamera", - "Save or throw camera", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo ShowChunkEdgeInfo = { - "ShowChunkEdges", - "Show chunk edges", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo ShowChunkBoundsInfo = { - "ShowChunkBounds", - "Show chunk bounds", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo ShowChunkAABBInfo = { - "ShowChunkAABB", - "Show chunk AABB", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo HeightResolutionInfo = { - "ShowHeightResolution", - "Show height resolution", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo HeightIntensityInfo = { - "ShowHeightIntensities", - "Show height intensities", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo FrustumCullingInfo = { - "PerformFrustumCulling", - "Perform frustum culling", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo HorizonCullingInfo = { - "PerformHorizonCulling", - "Perform horizon culling", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo LevelProjectedAreaInfo = { - "LevelByProjectedAreaElseDistance", - "Level by projected area (else distance)", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo ResetTileProviderInfo = { - "ResetTileProviders", - "Reset tile providers", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo CollectStatsInfo = { - "CollectStats", - "Collect stats", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo LimitLevelInfo = { - "LimitLevelByAvailableData", - "Limit level by available data", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo ModelSpaceRenderingInfo = { - "ModelSpaceRenderingCutoffLevel", - "Model Space Rendering Cutoff Level", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo PerformShadingInfo = { - "PerformShading", - "Perform shading", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo AtmosphereInfo = { - "Atmosphere", - "Atmosphere", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo AccurateNormalsInfo = { - "UseAccurateNormals", - "Use Accurate Normals", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo EclipseInfo = { - "Eclipse", - "Eclipse", - "Enables/Disable Eclipse shadows" - }; - - constexpr openspace::properties::Property::PropertyInfo EclipseHardShadowsInfo = { - "EclipseHardShadows", - "Eclipse Hard Shadows", - "Enables the rendering of eclipse shadows using hard shadows" - }; - - constexpr openspace::properties::Property::PropertyInfo LodScaleFactorInfo = { - "LodScaleFactor", - "Level of Detail Scale Factor", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo CameraMinHeightInfo = { - "CameraMinHeight", - "Camera Minimum Height", - "" // @TODO Missing documentation - }; - - constexpr openspace::properties::Property::PropertyInfo OrenNayarRoughnessInfo = { - "OrenNayarRoughness", - "orenNayarRoughness", - "" // @TODO Missing documentation - }; -} // namespace - -using namespace openspace::properties; - -namespace openspace::globebrowsing { - -RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) - : Renderable(dictionary) - , _debugProperties({ - BoolProperty(SaveOrThrowInfo, false), - BoolProperty(ShowChunkEdgeInfo, false), - BoolProperty(ShowChunkBoundsInfo, false), - BoolProperty(ShowChunkAABBInfo, false), - BoolProperty(HeightResolutionInfo, false), - BoolProperty(HeightIntensityInfo, false), - BoolProperty(FrustumCullingInfo, true), - BoolProperty(HorizonCullingInfo, true), - BoolProperty(LevelProjectedAreaInfo, false), - BoolProperty(ResetTileProviderInfo, false), - BoolProperty(CollectStatsInfo, false), - BoolProperty(LimitLevelInfo, true), - IntProperty(ModelSpaceRenderingInfo, 10, 1, 22) - }) - , _generalProperties({ - BoolProperty(PerformShadingInfo, true), - BoolProperty(AtmosphereInfo, false), - BoolProperty(AccurateNormalsInfo, false), - BoolProperty(EclipseInfo, false), - BoolProperty(EclipseHardShadowsInfo, false), - FloatProperty(LodScaleFactorInfo, 10.f, 1.f, 50.f), - FloatProperty(CameraMinHeightInfo, 100.f, 0.f, 1000.f), - FloatProperty(OrenNayarRoughnessInfo, 0.f, 0.f, 1.f) - }) - , _debugPropertyOwner({ "Debug" }) -{ - setIdentifier("RenderableGlobe"); - - dictionary.getValue(keyFrame, _frame); - - // Read the radii in to its own dictionary - if (dictionary.hasKeyAndValue(keyRadii)) { - const glm::dvec3 radii = dictionary.value(keyRadii); - _ellipsoid = Ellipsoid(radii); - setBoundingSphere(static_cast(_ellipsoid.maximumRadius())); - } - else if (dictionary.hasKeyAndValue(keyRadii)) { - const double radius = dictionary.value(keyRadii); - _ellipsoid = Ellipsoid({ radius, radius, radius }); - setBoundingSphere(static_cast(_ellipsoid.maximumRadius())); - } - - // Ghoul can't read ints from lua dictionaries... - double patchSegmentsd; - dictionary.getValue(keySegmentsPerPatch, patchSegmentsd); - int patchSegments = static_cast(patchSegmentsd); - - if (dictionary.hasValue("PerformShading")) { - _generalProperties.performShading = dictionary.value("PerformShading"); - } - - // Init layer manager - ghoul::Dictionary layersDictionary; - if (!dictionary.getValue(keyLayers, layersDictionary)) { - throw ghoul::RuntimeError(std::string(keyLayers) + " must be specified"); - } - - _layerManager = std::make_shared(layersDictionary); - - _chunkedLodGlobe = std::make_unique( - *this, - patchSegments, - _layerManager, - _ellipsoid - ); - //_pointGlobe = std::make_shared(*this); - - //_distanceSwitch.addSwitchValue(_chunkedLodGlobe); - //_distanceSwitch.addSwitchValue(_pointGlobe); - - addProperty(_generalProperties.atmosphereEnabled); - addProperty(_generalProperties.performShading); - addProperty(_generalProperties.useAccurateNormals); - addProperty(_generalProperties.eclipseShadowsEnabled); - addProperty(_generalProperties.eclipseHardShadows); - addProperty(_generalProperties.lodScaleFactor); - addProperty(_generalProperties.cameraMinHeight); - addProperty(_generalProperties.orenNayarRoughness); - - _debugPropertyOwner.addProperty(_debugProperties.saveOrThrowCamera); - _debugPropertyOwner.addProperty(_debugProperties.showChunkEdges); - _debugPropertyOwner.addProperty(_debugProperties.showChunkBounds); - _debugPropertyOwner.addProperty(_debugProperties.showChunkAABB); - _debugPropertyOwner.addProperty(_debugProperties.showHeightResolution); - _debugPropertyOwner.addProperty(_debugProperties.showHeightIntensities); - _debugPropertyOwner.addProperty(_debugProperties.performFrustumCulling); - _debugPropertyOwner.addProperty(_debugProperties.performHorizonCulling); - _debugPropertyOwner.addProperty( - _debugProperties.levelByProjectedAreaElseDistance - ); - _debugPropertyOwner.addProperty(_debugProperties.resetTileProviders); - _debugPropertyOwner.addProperty(_debugProperties.collectStats); - _debugPropertyOwner.addProperty(_debugProperties.limitLevelByAvailableData); - _debugPropertyOwner.addProperty(_debugProperties.modelSpaceRenderingCutoffLevel); - - auto notifyShaderRecompilation = [&](){ - _chunkedLodGlobe->notifyShaderRecompilation(); - }; - _generalProperties.atmosphereEnabled.onChange(notifyShaderRecompilation); - _generalProperties.useAccurateNormals.onChange(notifyShaderRecompilation); - _generalProperties.eclipseShadowsEnabled.onChange(notifyShaderRecompilation); - _generalProperties.eclipseHardShadows.onChange(notifyShaderRecompilation); - _generalProperties.performShading.onChange(notifyShaderRecompilation); - _debugProperties.showChunkEdges.onChange(notifyShaderRecompilation); - _debugProperties.showHeightResolution.onChange(notifyShaderRecompilation); - _debugProperties.showHeightIntensities.onChange(notifyShaderRecompilation); - - _layerManager->onChange(notifyShaderRecompilation); - - addPropertySubOwner(_debugPropertyOwner); - addPropertySubOwner(_layerManager.get()); - //addPropertySubOwner(_pointGlobe.get()); - - //================================================================ - //======== Reads Shadow (Eclipses) Entries in mod file =========== - //================================================================ - ghoul::Dictionary shadowDictionary; - bool success = dictionary.getValue(keyShadowGroup, shadowDictionary); - bool disableShadows = false; - if (success) { - std::vector> sourceArray; - unsigned int sourceCounter = 1; - while (success) { - std::string sourceName; - success = shadowDictionary.getValue(keyShadowSource + - std::to_string(sourceCounter) + ".Name", sourceName); - if (success) { - double sourceRadius; - success = shadowDictionary.getValue(keyShadowSource + - std::to_string(sourceCounter) + ".Radius", sourceRadius); - if (success) { - sourceArray.emplace_back(sourceName, sourceRadius); - } - else { - //LWARNING("No Radius value expecified for Shadow Source Name " - // << sourceName << " from " << name - // << " planet.\nDisabling shadows for this planet."); - disableShadows = true; - break; - } - } - sourceCounter++; - } - - if (!disableShadows && !sourceArray.empty()) { - success = true; - std::vector> casterArray; - unsigned int casterCounter = 1; - while (success) { - std::string casterName; - success = shadowDictionary.getValue(keyShadowCaster + - std::to_string(casterCounter) + ".Name", casterName); - if (success) { - double casterRadius; - success = shadowDictionary.getValue(keyShadowCaster + - std::to_string(casterCounter) + ".Radius", casterRadius); - if (success) { - casterArray.emplace_back(casterName, casterRadius); - } - else { - //LWARNING("No Radius value expecified for Shadow Caster Name " - // << casterName << " from " << name - // << " planet.\nDisabling shadows for this planet."); - disableShadows = true; - break; - } - } - - casterCounter++; - } - - std::vector shadowConfArray; - if (!disableShadows && (!sourceArray.empty() && !casterArray.empty())) { - for (const auto & source : sourceArray) { - for (const auto & caster : casterArray) { - Ellipsoid::ShadowConfiguration sc; - sc.source = source; - sc.caster = caster; - shadowConfArray.push_back(sc); - } - } - _ellipsoid.setShadowConfigurationArray(shadowConfArray); - } - } - } -} - -void RenderableGlobe::initializeGL() { - _layerManager->initialize(); - - _layerManager->update(); - - _chunkedLodGlobe->initializeGL(); - - // Recompile the shaders directly so that it is not done the first time the render - // function is called. - _chunkedLodGlobe->recompileShaders(); -} - -void RenderableGlobe::deinitializeGL() { - _chunkedLodGlobe->deinitializeGL(); - - _layerManager->deinitialize(); -} - -bool RenderableGlobe::isReady() const { - return true; -} - -void RenderableGlobe::render(const RenderData& data, RendererTasks& rendererTask) { - bool statsEnabled = _debugProperties.collectStats; -#ifdef DEBUG_GLOBEBROWSING_STATSRECORD - _chunkedLodGlobe->stats.setEnabled(statsEnabled); -#else // DEBUG_GLOBEBROWSING_STATSRECORD - if (statsEnabled) { - LWARNINGC( - "RenderableGlobe", - "Stats collection was enabled, but ChunkedLodGlobe compiled without support" - ); - _debugProperties.collectStats = false; - } -#endif // DEBUG_GLOBEBROWSING_STATSRECORD - - if (_enabled) { - if (_debugProperties.saveOrThrowCamera.value()) { - _debugProperties.saveOrThrowCamera.setValue(false); - - if (savedCamera() == nullptr) { // save camera - setSaveCamera(std::make_shared(data.camera)); - } - else { // throw camera - setSaveCamera(nullptr); - } - } - - const double distanceToCamera = distance( - data.camera.positionVec3(), - data.modelTransform.translation - ); - - // This distance will be enough to render the globe as one pixel if the field of - // view is 'fov' radians and the screen resolution is 'res' pixels. - const double fov = 2 * glm::pi() / 6; // 60 degrees - const int res = 2880; - - const double distance = res * _chunkedLodGlobe->boundingSphere() / tan(fov / 2); - - if (distanceToCamera < distance) { - _chunkedLodGlobe->render(data, rendererTask); - } - } - if (_savedCamera != nullptr) { - DebugRenderer::ref().renderCameraFrustum(data, *_savedCamera); - } -} - -void RenderableGlobe::update(const UpdateData& data) { - _time = data.time.j2000Seconds(); - _chunkedLodGlobe->update(data); - - glm::dmat4 translation = - glm::translate(glm::dmat4(1.0), data.modelTransform.translation); - glm::dmat4 rotation = glm::dmat4(data.modelTransform.rotation); - glm::dmat4 scaling = - glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale, - data.modelTransform.scale, data.modelTransform.scale)); - - _cachedModelTransform = translation * rotation * scaling; - _cachedInverseModelTransform = glm::inverse(_cachedModelTransform); - - if (_debugProperties.resetTileProviders) { - _layerManager->reset(); - _debugProperties.resetTileProviders = false; - } - _layerManager->update(); - _chunkedLodGlobe->update(data); -} - -glm::dvec3 RenderableGlobe::projectOnEllipsoid(glm::dvec3 position) { - return _ellipsoid.geodeticSurfaceProjection(position); -} - -float RenderableGlobe::getHeight(glm::dvec3 position) const { - if (_chunkedLodGlobe) { - return _chunkedLodGlobe->getHeight(position); - } - else { - return 0; - } -} - -ChunkedLodGlobe* RenderableGlobe::chunkedLodGlobe() const{ - return _chunkedLodGlobe.get(); -} - -LayerManager* RenderableGlobe::layerManager() const { - return _layerManager.get(); -} - -const Ellipsoid& RenderableGlobe::ellipsoid() const{ - return _ellipsoid; -} - -const glm::dmat4& RenderableGlobe::modelTransform() const{ - return _cachedModelTransform; -} - -const glm::dmat4& RenderableGlobe::inverseModelTransform() const{ - return _cachedInverseModelTransform; -} - -const RenderableGlobe::DebugProperties& - RenderableGlobe::debugProperties() const{ - return _debugProperties; -} - -const RenderableGlobe::GeneralProperties& - RenderableGlobe::generalProperties() const{ - return _generalProperties; -} - -const std::shared_ptr RenderableGlobe::savedCamera() const { - return _savedCamera; -} - -SurfacePositionHandle RenderableGlobe::calculateSurfacePositionHandle( - const glm::dvec3& targetModelSpace) const -{ - glm::dvec3 centerToEllipsoidSurface = - _ellipsoid.geodeticSurfaceProjection(targetModelSpace); - glm::dvec3 ellipsoidSurfaceToTarget = targetModelSpace - centerToEllipsoidSurface; - // ellipsoidSurfaceOutDirection will point towards the target, we want the outward - // direction. Therefore it must be flipped in case the target is under the reference - // ellipsoid so that it always points outwards - glm::dvec3 ellipsoidSurfaceOutDirection = glm::normalize(ellipsoidSurfaceToTarget); - if (glm::dot(ellipsoidSurfaceOutDirection, centerToEllipsoidSurface) < 0) { - ellipsoidSurfaceOutDirection *= -1.0; - } - - double heightToSurface = getHeight(targetModelSpace); - heightToSurface = glm::isnan(heightToSurface) ? 0.0 : heightToSurface; - centerToEllipsoidSurface = glm::isnan(glm::length(centerToEllipsoidSurface)) ? - (glm::dvec3(0.0, 1.0, 0.0) * static_cast(boundingSphere())) : - centerToEllipsoidSurface; - ellipsoidSurfaceOutDirection = glm::isnan(glm::length(ellipsoidSurfaceOutDirection)) ? - glm::dvec3(0.0, 1.0, 0.0) : ellipsoidSurfaceOutDirection; - - return { - centerToEllipsoidSurface, - ellipsoidSurfaceOutDirection, - heightToSurface - }; -} - -void RenderableGlobe::setSaveCamera(std::shared_ptr camera) { - _savedCamera = std::move(camera); -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/globes/renderableglobe.h b/modules/globebrowsing/globes/renderableglobe.h deleted file mode 100644 index 2f7c64a6b2..0000000000 --- a/modules/globebrowsing/globes/renderableglobe.h +++ /dev/null @@ -1,149 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___RENDERABLEGLOBE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___RENDERABLEGLOBE___H__ - -#include - -#include -//#include - -#include -#include -#include - -#ifdef OPENSPACE_MODULE_ATMOSPHERE_ENABLED -namespace openspace { - class AtmosphereDeferredcaster; -} -#endif - -namespace openspace::globebrowsing { - -class ChunkedLodGlobe; -class PointGlobe; -class LayerManager; - -/** - * A RenderableGlobe is a globe modeled as an ellipsoid using a chunked LOD algorithm for - * rendering. - */ -class RenderableGlobe : public Renderable { -public: - /** - * These properties are specific for ChunkedLodGlobe and separated from - * the general properties of RenderableGlobe. - */ - struct DebugProperties { - properties::BoolProperty saveOrThrowCamera; - properties::BoolProperty showChunkEdges; - properties::BoolProperty showChunkBounds; - properties::BoolProperty showChunkAABB; - properties::BoolProperty showHeightResolution; - properties::BoolProperty showHeightIntensities; - properties::BoolProperty performFrustumCulling; - properties::BoolProperty performHorizonCulling; - properties::BoolProperty levelByProjectedAreaElseDistance; - properties::BoolProperty resetTileProviders; - properties::BoolProperty collectStats; - properties::BoolProperty limitLevelByAvailableData; - properties::IntProperty modelSpaceRenderingCutoffLevel; - }; - - struct GeneralProperties { - properties::BoolProperty performShading; - properties::BoolProperty atmosphereEnabled; - properties::BoolProperty useAccurateNormals; - properties::BoolProperty eclipseShadowsEnabled; - properties::BoolProperty eclipseHardShadows; - properties::FloatProperty lodScaleFactor; - properties::FloatProperty cameraMinHeight; - properties::FloatProperty orenNayarRoughness; - }; - - // Shadow structure - struct ShadowRenderingStruct { - double xu; - double xp; - double rs; - double rc; - glm::dvec3 sourceCasterVec; - glm::dvec3 casterPositionVec; - bool isShadowing; - }; - - RenderableGlobe(const ghoul::Dictionary& dictionary); - ~RenderableGlobe() = default; - - void initializeGL() override; - void deinitializeGL() override; - bool isReady() const override; - - void render(const RenderData& data, RendererTasks& rendererTask) override; - void update(const UpdateData& data) override; - - // Getters that perform calculations - glm::dvec3 projectOnEllipsoid(glm::dvec3 position); - float getHeight(glm::dvec3 position) const; - - // Getters - ChunkedLodGlobe* chunkedLodGlobe() const; - LayerManager* layerManager() const; - const Ellipsoid& ellipsoid() const; - const glm::dmat4& modelTransform() const; - const glm::dmat4& inverseModelTransform() const; - const DebugProperties& debugProperties() const; - const GeneralProperties& generalProperties() const; - const std::shared_ptr savedCamera() const; - double interactionDepthBelowEllipsoid(); - - // Setters - void setSaveCamera(std::shared_ptr camera); - - virtual SurfacePositionHandle calculateSurfacePositionHandle( - const glm::dvec3& targetModelSpace) const override; - -private: - std::unique_ptr _chunkedLodGlobe; - - Ellipsoid _ellipsoid; - std::shared_ptr _layerManager; - std::shared_ptr _savedCamera; - - std::string _frame; - double _time = 0.0; - - glm::dmat4 _cachedModelTransform; - glm::dmat4 _cachedInverseModelTransform; - - // Properties - DebugProperties _debugProperties; - GeneralProperties _generalProperties; - properties::PropertyOwner _debugPropertyOwner; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___RENDERABLEGLOBE___H__ diff --git a/modules/globebrowsing/meshes/basicgrid.cpp b/modules/globebrowsing/meshes/basicgrid.cpp deleted file mode 100644 index 237a1fb389..0000000000 --- a/modules/globebrowsing/meshes/basicgrid.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include - -namespace openspace::globebrowsing { - -BasicGrid::BasicGrid(unsigned int xSegments, unsigned int ySegments, - TriangleSoup::Positions usePositions, - TriangleSoup::TextureCoordinates useTextureCoordinates, - TriangleSoup::Normals useNormals) - : Grid(xSegments, ySegments) -{ - _geometry = std::make_unique( - createElements(xSegments, ySegments), - usePositions, - useTextureCoordinates, - useNormals - ); - - if (usePositions) { - _geometry->setVertexPositions(createPositions(_xSegments, _ySegments)); - } - - if (useTextureCoordinates) { - _geometry->setVertexTextureCoordinates( - createTextureCoordinates(_xSegments, _ySegments) - ); - } - if (useNormals) { - _geometry->setVertexNormals(createNormals(_xSegments, _ySegments)); - } -} - -int BasicGrid::xSegments() const { - return _xSegments; -} - -int BasicGrid::ySegments() const { - return _ySegments; -} - -void BasicGrid::validate([[maybe_unused]] int xSegments, [[maybe_unused]] int ySegments) { - ghoul_assert( - xSegments > 0 && ySegments > 0, - std::string("Resolution must be at least 1x1. (") + - std::to_string(xSegments) + ", " + std::to_string(ySegments) + ")" - ); -} - -inline size_t BasicGrid::numElements(int xSegments, int ySegments) { - return 3 * 2 * xSegments * ySegments; -} - -inline size_t BasicGrid::numVertices(int xSegments, int ySegments) { - return (xSegments + 1) * (ySegments + 1); -} - -std::vector BasicGrid::createElements(int xSegments, int ySegments) { - validate(xSegments, ySegments); - - std::vector elements; - elements.reserve(numElements(xSegments, ySegments)); - for (int y = 0; y < ySegments; y++) { - for (int x = 0; x < xSegments; x++) { - - // x v01---v11 x .. - // | / | - // x v00---v10 x .. - // - // x x x x .. - // : : : : - - const GLuint v00 = (y + 0) * (xSegments + 1) + x + 0; - const GLuint v10 = (y + 0) * (xSegments + 1) + x + 1; - const GLuint v01 = (y + 1) * (xSegments + 1) + x + 0; - const GLuint v11 = (y + 1) * (xSegments + 1) + x + 1; - - // add upper triangle - elements.push_back(v00); - elements.push_back(v10); - elements.push_back(v11); - - // add lower triangle - elements.push_back(v00); - elements.push_back(v11); - elements.push_back(v01); - } - } - - return elements; -} - -std::vector BasicGrid::createPositions(int xSegments, int ySegments) { - validate(xSegments, ySegments); - std::vector positions; - positions.reserve(numVertices(xSegments, ySegments)); - - // Copy from 2d texture coordinates and use as template to create positions - std::vector templateTextureCoords = createTextureCoordinates( - xSegments, - ySegments - ); - for (const glm::vec2& coords : templateTextureCoords) { - positions.emplace_back(coords, 0.f, 1.f); - } - //for (unsigned int i = 0; i < templateTextureCoords.size(); i++) { - // positions.push_back(glm::vec4( - // templateTextureCoords[i], - // 0.0f, - // 1.0f - // )); - //} - return positions; -} - -std::vector BasicGrid::createTextureCoordinates(int xSegments, int ySegments) { - validate(xSegments, ySegments); - std::vector textureCoordinates; - textureCoordinates.reserve(numVertices(xSegments, ySegments)); - - for (int y = 0; y < ySegments + 1; y++) { - for (int x = 0; x < xSegments + 1; x++) { - textureCoordinates.emplace_back( - static_cast(x) / static_cast(xSegments), - static_cast(y) / static_cast(ySegments) - ); - } - } - return textureCoordinates; -} - -std::vector BasicGrid::createNormals(int xSegments, int ySegments) { - validate(xSegments, ySegments); - std::vector normals; - normals.reserve(numVertices(xSegments, ySegments)); - - for (int y = 0; y < ySegments + 1; y++) { - for (int x = 0; x < xSegments + 1; x++) { - normals.emplace_back(0.f, 0.f, 1.f); - } - } - - return normals; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/meshes/basicgrid.h b/modules/globebrowsing/meshes/basicgrid.h deleted file mode 100644 index 00ddd55408..0000000000 --- a/modules/globebrowsing/meshes/basicgrid.h +++ /dev/null @@ -1,70 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___BASICGRIDGEOMETRY___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___BASICGRIDGEOMETRY___H__ - -#include - -#include -#include - -namespace openspace::globebrowsing { - -class BasicGrid : public Grid { -public: - /** - * \param xSegments is the number of grid cells in the x direction. - * \param ySegments is the number of grid cells in the y direction. - * \param usePositions determines whether or not to upload any vertex position data - * to the GPU. - * \param useTextureCoordinates determines whether or not to upload any vertex texture - * coordinate data to the GPU. - * \param useNormals determines whether or not to upload any vertex normal data - * to the GPU. - */ - BasicGrid(unsigned int xSegments, unsigned int ySegments, - TriangleSoup::Positions usePositions, - TriangleSoup::TextureCoordinates useTextureCoordinates, - TriangleSoup::Normals useNormals); - - virtual int xSegments() const override; - virtual int ySegments() const override; - -private: - std::vector createElements(int xSegments, int ySegments) override; - std::vector createPositions(int xSegments, int ySegments) override; - std::vector createTextureCoordinates(int xSegments, - int ySegments) override; - std::vector createNormals(int xSegments, int ySegments) override; - - void validate(int xSegments, int ySegments); - - inline size_t numElements(int xSegments, int ySegments); - inline size_t numVertices(int xSegments, int ySegments); -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___BASICGRIDGEOMETRY___H__ diff --git a/modules/globebrowsing/meshes/grid.h b/modules/globebrowsing/meshes/grid.h deleted file mode 100644 index d315f6e7b5..0000000000 --- a/modules/globebrowsing/meshes/grid.h +++ /dev/null @@ -1,101 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GRIDGEOMETRY___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GRIDGEOMETRY___H__ - -#include -#include -#include -#include - -namespace openspace::globebrowsing { - -class TriangleSoup; - -/** - * Abstract class defining an interface used for geometries with grid structures. - * The class Grid should be extended for use of geometries with a 2D structure where the - * number of segments in x and y direction represents the number of vertices + 1 in each - * direction. - */ -class Grid { -public: - Grid(int xSegments, int ySegments); - - virtual ~Grid(); - - TriangleSoup& geometry(); - - /** - * Returns the number of grid cells in the x direction. Hence the number of vertices - * in the x direction is xResolution + 1. - */ - virtual int xSegments() const = 0; - - /** - * Returns the number of grid cells in the y direction. Hence the number of vertices - * in the y direction is xResolution + 1. - */ - virtual int ySegments() const = 0; - -protected: - /** - * Should return the indices of vertices for a grid with size \c xSegments * - * \c ySegments. Where the number of vertices in each direction is the number of - * segments + 1. - */ - virtual std::vector createElements(int xSegments, int ySegments) = 0; - - /** - * Should return the positions of vertices for a grid with size \c xSegments * - * \c ySegments. Where the number of vertices in each direction is the number of - * segments + 1. - */ - virtual std::vector createPositions(int xSegments, int ySegments) = 0; - - /** - * Should return the texture coordinates of vertices for a grid with size - * \c xSegments * \c ySegments. Where the number of vertices in each direction is the - * number of segments + 1. - */ - virtual std::vector createTextureCoordinates(int xSegments, - int ySegments) = 0; - - /** - * Should return the normals of vertices for a grid with size \c xSegments * - * \c ySegments. Where the number of vertices in each direction is the number of - * segments + 1. - */ - virtual std::vector createNormals(int xSegments, int ySegments) = 0; - - std::unique_ptr _geometry; - - const int _xSegments; - const int _ySegments; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GRIDGEOMETRY___H__ diff --git a/modules/globebrowsing/meshes/skirtedgrid.cpp b/modules/globebrowsing/meshes/skirtedgrid.cpp deleted file mode 100644 index a6469747a6..0000000000 --- a/modules/globebrowsing/meshes/skirtedgrid.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace { - size_t numElements(int xSegments, int ySegments) { - return 3 * 2 * xSegments * ySegments; - } - - size_t numVertices(int xSegments, int ySegments) { - return (xSegments + 1) * (ySegments + 1); - } - - void validate([[maybe_unused]] int xSegments, [[maybe_unused]] int ySegments) { - ghoul_assert( - xSegments > 0 && ySegments > 0, - "Resolution must be at least 1x1. (" + std::to_string(xSegments) + ", " + - std::to_string(ySegments) + ")" - ); - } -} // namespace - -namespace openspace::globebrowsing { - -SkirtedGrid::SkirtedGrid(unsigned int xSegments, unsigned int ySegments, - TriangleSoup::Positions usePositions, - TriangleSoup::TextureCoordinates useTextureCoordinates, - TriangleSoup::Normals useNormals) - : Grid(xSegments, ySegments) -{ - _geometry = std::make_unique( - createElements(xSegments, ySegments), - usePositions, - useTextureCoordinates, - useNormals - ); - - if (usePositions) { - _geometry->setVertexPositions(createPositions(_xSegments, _ySegments)); - } - if (useTextureCoordinates) { - _geometry->setVertexTextureCoordinates( - createTextureCoordinates(_xSegments, _ySegments) - ); - } - if (useNormals) { - _geometry->setVertexNormals(createNormals(_xSegments, _ySegments)); - } -} - -int SkirtedGrid::xSegments() const { - return _xSegments; -} - -int SkirtedGrid::ySegments() const { - return _ySegments; -} - -std::vector SkirtedGrid::createElements(int xSegments, int ySegments) { - validate(xSegments, ySegments); - - std::vector elements; - elements.reserve(numElements(xSegments + 2, ySegments + 2)); - for (int y = 0; y < ySegments + 2; y++) { - for (int x = 0; x < xSegments + 2; x++) { - - // x v01---v11 x .. - // | / | - // x v00---v10 x .. - // - // x x x x .. - // : : : : - - const GLuint v00 = (y + 0) * (xSegments + 2 + 1) + x + 0; - const GLuint v10 = (y + 0) * (xSegments + 2 + 1) + x + 1; - const GLuint v01 = (y + 1) * (xSegments + 2 + 1) + x + 0; - const GLuint v11 = (y + 1) * (xSegments + 2 + 1) + x + 1; - - // add upper triangle - elements.push_back(v00); - elements.push_back(v10); - elements.push_back(v11); - - // add lower triangle - elements.push_back(v00); - elements.push_back(v11); - elements.push_back(v01); - } - } - - return elements; -} - -std::vector SkirtedGrid::createPositions(int xSegments, int ySegments) { - validate(xSegments, ySegments); - - // Copy from 2d texture coordinates and use as template to create positions - const std::vector& templateTextureCoords = createTextureCoordinates( - xSegments, - ySegments - ); - - std::vector positions; - positions.reserve(numVertices(xSegments, ySegments)); - for (const glm::vec2& c : templateTextureCoords) { - positions.emplace_back(c, 0.f, 1.f); - } - return positions; -} - -std::vector SkirtedGrid::createTextureCoordinates(int xSegments, int ySegments) -{ - validate(xSegments, ySegments); - - std::vector textureCoordinates; - textureCoordinates.reserve(numVertices(xSegments + 2, ySegments + 2)); - for (int y = -1; y < ySegments + 2; y++) { - for (int x = -1; x < xSegments + 2; x++) { - textureCoordinates.emplace_back( - glm::clamp( - static_cast(x) / static_cast(xSegments), - 0 - 1.f / (2 * xSegments), - 1 + 1.f / (2 * xSegments) - ), - glm::clamp( - static_cast(y) / static_cast(ySegments), - 0 - 1.f / (2 * ySegments), - 1 + 1.f / (2 * ySegments) - ) - ); - } - } - return textureCoordinates; -} - -std::vector SkirtedGrid::createNormals(int xSegments, int ySegments) { - validate(xSegments, ySegments); - - std::vector normals; - normals.reserve(numVertices(xSegments + 2, ySegments + 2)); - for (int y = -1; y < ySegments + 2; y++) { - for (int x = -1; x < xSegments + 2; x++) { - normals.emplace_back(0.f, 0.f, 1.f); - } - } - - return normals; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/meshes/trianglesoup.cpp b/modules/globebrowsing/meshes/trianglesoup.cpp deleted file mode 100644 index 55cef65a83..0000000000 --- a/modules/globebrowsing/meshes/trianglesoup.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace { - constexpr const char* _loggerCat = "TriangleSoup"; -} // namespace - -namespace openspace::globebrowsing { - -TriangleSoup::TriangleSoup(std::vector elements, Positions usePositions, - TextureCoordinates useTextures, Normals useNormals) - : _useVertexPositions(usePositions) - , _useTextureCoordinates(useTextures) - , _useVertexNormals(useNormals) -{ - setElements(std::move(elements)); -} - -TriangleSoup::~TriangleSoup() { - glDeleteBuffers(1, &_vertexBufferID); - glDeleteBuffers(1, &_elementBufferID); - glDeleteVertexArrays(1, &_vaoID); -} - -void TriangleSoup::setVertexPositions(std::vector positions) { - _useVertexPositions = true; - _gpuDataNeedUpdate = true; - _vertexData.resize(positions.size()); - for (size_t i = 0; i < positions.size(); ++i) { - _vertexData[i].position[0] = positions[i][0]; - _vertexData[i].position[1] = positions[i][1]; - _vertexData[i].position[2] = positions[i][2]; - //_vertexData[i].position[3] = positions[i][3]; - } -} - -void TriangleSoup::setVertexTextureCoordinates(std::vector textures) { - _useTextureCoordinates = true; - _gpuDataNeedUpdate = true; - _vertexData.resize(textures.size()); - for (size_t i = 0; i < textures.size(); ++i) { - _vertexData[i].texture[0] = textures[i][0]; - _vertexData[i].texture[1] = textures[i][1]; - } -} - -void TriangleSoup::setVertexNormals(std::vector normals) { - _useVertexNormals = true; - _gpuDataNeedUpdate = true; - _vertexData.resize(normals.size()); - for (size_t i = 0; i < normals.size(); ++i) { - _vertexData[i].normal[0] = normals[i][0]; - _vertexData[i].normal[1] = normals[i][1]; - _vertexData[i].normal[2] = normals[i][2]; - } -} - -void TriangleSoup::setElements(std::vector elements) { - _gpuDataNeedUpdate = true; - _elementData = std::move(elements); -} - -bool TriangleSoup::updateDataOnGPU() { - // Create VAO - if (_vaoID == 0) { - glGenVertexArrays(1, &_vaoID); - } - - // Create VBOs - if (_vertexBufferID == 0 && !_vertexData.empty()) { - glGenBuffers(1, &_vertexBufferID); - if (_vertexBufferID == 0) { - LERROR("Could not create vertex buffer"); - return false; - } - } - if (_elementBufferID == 0 && !_elementData.empty()) { - glGenBuffers(1, &_elementBufferID); - if (_elementBufferID == 0) { - LERROR("Could not create vertex element buffer"); - return false; - } - } - - // First VAO setup - glBindVertexArray(_vaoID); - - // Vertex buffer - glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID); - glBufferData( - GL_ARRAY_BUFFER, - _vertexData.size() * sizeof(Vertex), - &_vertexData[0], - GL_STATIC_DRAW - ); - - // Positions at location 0 - if (_useVertexPositions) { - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr); - } - // Textures at location 1 - if (_useTextureCoordinates) { - glEnableVertexAttribArray(1); - glVertexAttribPointer( - 1, - 2, - GL_FLOAT, - GL_FALSE, - sizeof(Vertex), - reinterpret_cast(offsetof(Vertex, texture)) // NOLINT - ); - } - // Normals at location 2 - if (_useVertexNormals) { - glEnableVertexAttribArray(2); - glVertexAttribPointer( - 2, - 3, - GL_FLOAT, - GL_FALSE, - sizeof(Vertex), - reinterpret_cast(offsetof(Vertex, normal)) // NOLINT - ); - } - - // Element buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _elementBufferID); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, - _elementData.size() * sizeof(GLint), - &_elementData[0], - GL_STATIC_DRAW); - - glBindVertexArray(0); - - _gpuDataNeedUpdate = false; - - return true; -} - -void TriangleSoup::drawUsingActiveProgram() { - if (_gpuDataNeedUpdate) { - updateDataOnGPU(); - } - glBindVertexArray(_vaoID); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _elementBufferID); - glDrawElements( - GL_TRIANGLES, - static_cast(_elementData.size()), - GL_UNSIGNED_INT, - nullptr - ); - glBindVertexArray(0); -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/meshes/trianglesoup.h b/modules/globebrowsing/meshes/trianglesoup.h deleted file mode 100644 index 9f12101478..0000000000 --- a/modules/globebrowsing/meshes/trianglesoup.h +++ /dev/null @@ -1,103 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TRIANGLESOUP___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TRIANGLESOUP___H__ - -#include -#include -#include - -#include - -namespace openspace::globebrowsing { - -/** - * Class to hold vertex data and handling OpenGL interfacing and rendering. - * A TriangleSoup has all data needed such as position buffer and normal - * buffer but all data is not necessarily needed for all purpouses so some vertex buffers - * such as normals can be disabled if not needed. - */ - -// TODO : Possibly render triangle strips in this class instead of triangles since -// that is faster -class TriangleSoup { -public: - BooleanType(Positions); - BooleanType(TextureCoordinates); - BooleanType(Normals); - - TriangleSoup(std::vector elements, // At least elements are required - Positions usePositions = Positions::No, - TextureCoordinates useTextures = TextureCoordinates::No, - Normals useNormals = Normals::No); - - ~TriangleSoup(); - - // Setters - void setVertexPositions(std::vector positions); - void setVertexTextureCoordinates(std::vector textures); - void setVertexNormals(std::vector normals); - void setElements(std::vector elements); - - /** - * Calls OpenGL's draw function to draw the triangles defined in the vertex buffers - * using the current bound program object. - * The vertex buffer attribute input locations to the shader program comes in the - * order of positions (0), texture coordinates (1) and normals (2). - * The input locations in the shader program should be specified to match these - * locations. - */ - void drawUsingActiveProgram(); - -protected: - // Determines what attribute data is in use - bool _useVertexPositions; - bool _useTextureCoordinates; - bool _useVertexNormals; - - struct Vertex { - GLfloat position[3]; - GLfloat texture[2]; - GLfloat normal[3]; - }; - - // Vertex data - std::vector _vertexData; - std::vector _elementData; - -private: - bool updateDataOnGPU(); - - // GL handles - GLuint _vaoID = 0; - GLuint _vertexBufferID = 0; - GLuint _elementBufferID = 0; - - bool _gpuDataNeedUpdate = false; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TRIANGLESOUP___H__ diff --git a/modules/globebrowsing/other/pixelbuffer.cpp b/modules/globebrowsing/other/pixelbuffer.cpp deleted file mode 100644 index c26b9e596c..0000000000 --- a/modules/globebrowsing/other/pixelbuffer.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include -#include - -namespace { - constexpr const char* _loggerCat = "PixelBuffer"; -} // namespace - -namespace openspace::globebrowsing { - -PixelBuffer::PixelBuffer(size_t numBytes, Usage usage) - : _numBytes(numBytes) - , _usage(usage) -{ - glGenBuffers(1, &_id); - bind(); - glBufferData(GL_PIXEL_UNPACK_BUFFER, _numBytes, nullptr, static_cast(_usage)); - unbind(); -} - -PixelBuffer::~PixelBuffer() { - glDeleteBuffers(1, &_id); -} - -void* PixelBuffer::mapBuffer(Access access) { - void* dataPtr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, static_cast(access)); - _isMapped = dataPtr != nullptr; - return dataPtr; -} - -void* PixelBuffer::mapBufferRange(GLintptr offset, GLsizeiptr length, - BufferAccessMask access) -{ - void* dataPtr = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, offset, length, access); - _isMapped = dataPtr; - return dataPtr; -} - -bool PixelBuffer::unMapBuffer() { - GLboolean success = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - if (!success) { - LERROR("Unable to unmap pixel buffer, data may be corrupt!"); - } - _isMapped = false; - return success == GL_TRUE; -} - -void PixelBuffer::bind() { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _id); -} - -void PixelBuffer::unbind() { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); -} - -bool PixelBuffer::isMapped() const { - return _isMapped; -} - -PixelBuffer::operator GLuint() const { - return _id; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/other/pixelbuffer.h b/modules/globebrowsing/other/pixelbuffer.h deleted file mode 100644 index 2c763acadd..0000000000 --- a/modules/globebrowsing/other/pixelbuffer.h +++ /dev/null @@ -1,140 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ - -#include - -namespace openspace::globebrowsing { - -/** - * Handles an OpenGL pixel buffer which contains data allocated on the GPU. A simple - * class that wraps the standard functionality of OpenGL pixel buffer objects. Once - * the PixelBuffer is created, data is allocated on the GPU. When mapping data to a - * address pointer, the user needs to ensure the data is unmapped before the data can - * be used on the GPU / CPU depending on Usage. - */ -class PixelBuffer { -public: - /** - * All kinds of usage for pixel buffer objects as defined by the OpenGL standard. - * See: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferData.xhtml - */ - enum class Usage : std::underlying_type_t { - StreamDraw = static_cast>(GL_STREAM_DRAW), - StreamRead = static_cast>(GL_STREAM_READ), - StreamCopy = static_cast>(GL_STREAM_COPY), - StaticDraw = static_cast>(GL_STATIC_DRAW), - StaticRead = static_cast>(GL_STATIC_READ), - StaticCopy = static_cast>(GL_STATIC_COPY), - DynamicDraw = static_cast>(GL_DYNAMIC_DRAW), - DynamicRead = static_cast>(GL_DYNAMIC_READ), - DynamicCopy = static_cast>(GL_DYNAMIC_COPY) - }; - - /** - * Access hints for OpenGL buffer mapping - * See: https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glMapBuffer.xml - */ - enum class Access : std::underlying_type_t { - ReadOnly = static_cast>(GL_READ_ONLY), - WriteOnly = static_cast>(GL_WRITE_ONLY), - ReadWrite = static_cast>(GL_READ_WRITE) - }; - - /** - * Allocates numBytes bytes on the GPU and creates an ID for the pixel - * buffer object. - * - * \param numBytes is the number of bytes to be allocated on GPU memory - * \param usage is the Usage for the pixel buffer - */ - PixelBuffer(size_t numBytes, Usage usage); - - /** - * calls glDeleteBuffers(). - */ - ~PixelBuffer(); - - /** - * Maps an address pointer to GPU direct memory access. The user must make sure the - * buffer is bound before calling this function. - * - * \param access is the access to which can be any of GL_READ_ONLY, - * GL_WRITE_ONLY, or GL_READ_WRITE - * \return The DMA address to the mapped buffer. Returns nullptr if the mapping - * failed - */ - void* mapBuffer(Access access); - - /** - * Maps an address pointer to GPU direct memory access. Gives access to a range of - * the buffer. The user must make sure the buffer is bound before calling this - * function. - * - * \param offet is the number of bytes to the first address to get in the buffer - * \param length is the number of bytes to access in the buffer - * \param access is a bitfield describing the access as described in: - * https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glMapBufferRange.xhtml - * \return The DMA address to the mapped buffer. Returns nullptr if the mapping - * failed - */ - void* mapBufferRange(GLintptr offset, GLsizeiptr length, BufferAccessMask access); - - /** - * Maps the default buffer and makes the data available on the GPU - */ - bool unMapBuffer(); - - /** - * Calls glBindBuffer() - */ - void bind(); - - /** - * Calls glBindBuffer() with argument 0 to unmap any pixel buffer - */ - void unbind(); - - /** - * \returns true of the buffer is mapped, otherwise false - */ - bool isMapped() const; - - /** - * \returns the OpenGL id of the pixel buffer object - */ - operator GLuint() const; - -private: - GLuint _id = 0; - const size_t _numBytes; - const Usage _usage; - bool _isMapped = false; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ diff --git a/modules/globebrowsing/other/pixelbuffercontainer.h b/modules/globebrowsing/other/pixelbuffercontainer.h deleted file mode 100644 index d129727a36..0000000000 --- a/modules/globebrowsing/other/pixelbuffercontainer.h +++ /dev/null @@ -1,116 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ - -#include -#include - -namespace openspace::globebrowsing { - -/** - * Templated class which owns one or many PixelBuffer%s. The KeyType is used to map a - * pixel buffer but only if it is not already mapped. - */ -template -class PixelBufferContainer { -public: - /** - * Creates numPixelBuffers pixel buffer objects, each with numBytesPerBuffer bytes - * allocated on the GPU. - * - * \param numBytesPerBuffer is the number of bytes per pixel buffer. All pixel - * buffers within a PixelBufferContainer have the same number of - * bytes - * \param usage is the Usage as described by PixelBuffer - * \param numPixelBuffers is the number of pixel buffers to create for this container. - * If numPixelBuffers is omitted, no pixel buffers are created. - */ - PixelBufferContainer(size_t numBytesPerBuffer, - globebrowsing::PixelBuffer::Usage usage, size_t numPixelBuffers = 0); - ~PixelBufferContainer() = default; - - /** - * Finds a Pixel buffer and maps it if it is available. - * - * \param key is the identifier for the pixel buffer which can be used later when - * unmapping the mapped pixel buffer. - * \param access is the access as described by PixelBuffer - * \return An address pointer to DMA if the mapping succeeded. Otherwise a \c nullptr - * is returned. The mapping can fail if the buffer identified with \p key is - * already mapped or if something else failed. - */ - void* mapBuffer(KeyType key, PixelBuffer::Access access); - - /** - * Finds a Pixel buffer and maps a range of it if it is available. - * - * \param key is the identifier for the pixel buffer which can be used later when - * unmapping the mapped pixel buffer. - * \param offet is the number of bytes to the first address to get in the buffer - * \param length is the number of bytes to access in the buffer - * \param access is the access as described by PixelBuffer - * \return An address pointer to DMA if the mapping succeeded. Otherwise a nullptr - * is returned. The mapping can fail if the buffer identified with \p key is - * already mapped or if something else failed. - */ - void* mapBufferRange(KeyType key, GLintptr offset, GLsizeiptr length, - BufferAccessMask access); - - /** - * Unmaps all buffers in the PixelBufferContainer. - * - * \return \c true if the unmapping succeeded, otherwise \c false - */ - bool resetMappedBuffers(); - - /** - * Unmaps a buffer that has previously been mapped. This buffer is identified using - * \p key. - * - * \param key is the identifier of the mapped buffer. - * \return \c true if the unmapping succeeded, otherwise \c false - */ - bool unMapBuffer(KeyType key); - - /** - * \return The \c GLuint id of a pixel buffer identified by \p key if it currently is - * mapped. - */ - GLuint idOfMappedBuffer(KeyType key); -private: - const globebrowsing::PixelBuffer::Usage _usage; - - std::vector> _pixelBuffers; - - // Maps from KeyType to index of mapped buffers - std::map _indexMap; -}; - -} // namespace openspace::globebrowsing - -#include "pixelbuffercontainer.inl" - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ diff --git a/modules/globebrowsing/other/pixelbuffercontainer.inl b/modules/globebrowsing/other/pixelbuffercontainer.inl deleted file mode 100644 index 374cf49566..0000000000 --- a/modules/globebrowsing/other/pixelbuffercontainer.inl +++ /dev/null @@ -1,129 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -namespace openspace::globebrowsing { - -template -PixelBufferContainer::PixelBufferContainer(size_t numBytesPerBuffer, - PixelBuffer::Usage usage, size_t numPixelBuffers) - : _usage(usage) -{ - for (size_t i = 0; i < numPixelBuffers; ++i) { - _pixelBuffers.push_back(std::make_unique(numBytesPerBuffer, _usage)); - } -} - -template -void* PixelBufferContainer::mapBuffer(KeyType key, PixelBuffer::Access access) { - const typename std::map::const_iterator iter = _indexMap.find(key); - const bool notFoundAmongMappedBuffers = (iter == _indexMap.end()); - - if (!notFoundAmongMappedBuffers) { // This PBO is already mapped - ghoul_assert(_pixelBuffers[iter->second], "Incorrect index map"); - return nullptr; - } - - // Find a pixel buffer that is unmapped - for (size_t i = 0; i < _pixelBuffers.size(); ++i) { - if (!_pixelBuffers[i]->isMapped()) { - _pixelBuffers[i]->bind(); - void* dataPtr = _pixelBuffers[i]->mapBuffer(access); - _pixelBuffers[i]->unbind(); - if (dataPtr) { // Success in mapping - // Add this index to the map of mapped pixel buffers - _indexMap.emplace(std::move(key), static_cast(i)); - return dataPtr; - } - } - } - return nullptr; -} - -template -void* PixelBufferContainer::mapBufferRange(KeyType key, GLintptr offset, - GLsizeiptr length, - BufferAccessMask access) -{ - const typename std::map::const_iterator iter = _indexMap.find(key); - const bool notFoundAmongMappedBuffers = (iter == _indexMap.end()); - - if (!notFoundAmongMappedBuffers) { // This PBO is already mapped - ghoul_assert(_pixelBuffers[iter->second], "Incorrect index map"); - return nullptr; - } - - // Find a pixel buffer that is unmapped - for (int i = 0; i < _pixelBuffers.size(); ++i) { - const bool bufferIsMapped = _pixelBuffers[i]->isMapped(); - if (!bufferIsMapped) { - _pixelBuffers[i]->bind(); - void* dataPtr = _pixelBuffers[i]->mapBufferRange(offset, length, access); - _pixelBuffers[i]->unbind(); - if (dataPtr) { // Success in mapping - _indexMap.emplace(std::move(key), i); - return dataPtr; - } - } - } - return nullptr; -} - -template -bool PixelBufferContainer::resetMappedBuffers() { - bool success = true; - for (auto iter = _indexMap.begin(); iter != _indexMap.end(); iter++) { - const int index = iter->second; // Index where the mapped buffer is stored - _pixelBuffers[index]->bind(); - success &= _pixelBuffers[index]->unMapBuffer(); - _pixelBuffers[index]->unbind(); - _indexMap.erase(iter); // This key should no longer be among the mapped buffers - } - return success; -} - -template -bool PixelBufferContainer::unMapBuffer(KeyType key) { - bool success = false; - const typename std::map::const_iterator iter = _indexMap.find(key); - if (iter != _indexMap.end()) { // Found a mapped pixel buffer - const int index = iter->second; // Index where the mapped buffer is stored - _pixelBuffers[index]->bind(); - success = _pixelBuffers[index]->unMapBuffer(); - _pixelBuffers[index]->unbind(); - _indexMap.erase(iter); // This key should no longer be among the mapped buffers - } - return success; -} - -template -GLuint PixelBufferContainer::idOfMappedBuffer(KeyType key) { - const typename std::map::const_iterator iter = _indexMap.find(key); - if (iter != _indexMap.end()) { // Found a mapped pixel buffer - int index = iter->second; // Index where the mapped buffer is stored - return *_pixelBuffers[index]; - } - return 0; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/other/statscollector.cpp b/modules/globebrowsing/other/statscollector.cpp deleted file mode 100644 index dd460db90b..0000000000 --- a/modules/globebrowsing/other/statscollector.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include - -namespace openspace::globebrowsing { - -StatsCollector::StatsCollector(std::string filename, int dumpEveryXRecord, - Enabled enabled, std::string delimiter) - : i(TemplatedStatsCollector( - TemplatedStatsCollector::Enabled(enabled), - delimiter - )) - , d(TemplatedStatsCollector( - TemplatedStatsCollector::Enabled(enabled), - delimiter - )) - , _filename(std::move(filename)) - , _delimiter(std::move(delimiter)) - , _dumpEveryXRecord(dumpEveryXRecord) -{ -} - -StatsCollector::~StatsCollector() { - dumpToDisk(); -} - -void StatsCollector::startNewRecord() { - ghoul_assert(i.enabled() == d.enabled(), "Both Statscollector have to be synced"); - - if (i.enabled()) { - if (_dumpEveryXRecord && (++_recordsSinceLastDump >= _dumpEveryXRecord)) { - dumpToDisk(); - _recordsSinceLastDump = 0; - } - - i.startNewRecord(); - d.startNewRecord(); - } -} - -void StatsCollector::setEnabled(bool enabled) { - i.setEnabled(enabled); - d.setEnabled(enabled); -} - -int StatsCollector::hasHeaders() { - return i.hasHeaders() || d.hasHeaders(); -} - -void StatsCollector::dumpToDisk() { - ghoul_assert(i.enabled() == d.enabled(), "Both Statscollector have to be synced"); - - if (i.enabled() && hasHeaders()) { - if (!_hasWrittenHeader) { - writeHeader(); - } - writeData(); - } -} - -void StatsCollector::writeHeader() { - std::ofstream ofs(_filename); - if (i.hasHeaders()) { - i.writeHeader(ofs); - if (d.hasHeaders()) { - ofs << _delimiter; - d.writeHeader(ofs); - } - } - else { - d.writeHeader(ofs); - } - _hasWrittenHeader = true; - ofs << std::endl; - ofs.close(); -} - -void StatsCollector::writeData() { - std::ofstream ofs(_filename, std::ofstream::out | std::ofstream::app); - ofs << std::setprecision(32); - while (i.hasRecordsToWrite() || d.hasRecordsToWrite()) { - if (i.hasHeaders() && d.hasHeaders()) { - i.writeNextRecord(ofs); ofs << _delimiter; d.writeNextRecord(ofs); - } - else { - i.writeNextRecord(ofs); d.writeNextRecord(ofs); - } - ofs << std::endl; - } - i.reset(); - d.reset(); - ofs.close(); -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/other/statscollector.h b/modules/globebrowsing/other/statscollector.h deleted file mode 100644 index be84cfb3f1..0000000000 --- a/modules/globebrowsing/other/statscollector.h +++ /dev/null @@ -1,73 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___STATS_COLLECTOR___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___STATS_COLLECTOR___H__ - -#include - -#include -#include - -namespace openspace::globebrowsing { - -class StatsCollector { -public: - BooleanType(Enabled); - - StatsCollector() = delete; - - StatsCollector(std::string filename, int dumpEveryXRecord, - Enabled enabled = Enabled::Yes, std::string delimiter = ","); - - ~StatsCollector(); - - void startNewRecord(); - - void setEnabled(bool enabled); - - int hasHeaders(); - - void dumpToDisk(); - - TemplatedStatsCollector i; - TemplatedStatsCollector d; - -private: - void writeHeader(); - - void writeData(); - - std::string _filename; - std::string _delimiter; - - int _dumpEveryXRecord; - int _recordsSinceLastDump = 0; - - bool _hasWrittenHeader = false; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___STATS_COLLECTOR___H__ diff --git a/modules/globebrowsing/other/templatedstatscollector.h b/modules/globebrowsing/other/templatedstatscollector.h deleted file mode 100644 index e935c0d7f5..0000000000 --- a/modules/globebrowsing/other/templatedstatscollector.h +++ /dev/null @@ -1,81 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TEMPLATED_STATS_COLLECTOR___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TEMPLATED_STATS_COLLECTOR___H__ - -#include -#include -#include -#include -#include - -namespace openspace::globebrowsing { - -template -class TemplatedStatsCollector { -public: - BooleanType(Enabled); - - TemplatedStatsCollector(Enabled enabled, std::string delimiter); - ~TemplatedStatsCollector() = default; - - void startNewRecord(); - - T& operator[](const std::string& name); - T previous(const std::string& name) const; - - void setEnabled(bool enabled); - bool enabled() const; - - bool hasHeaders() const; - bool hasRecordsToWrite() const; - - void reset(); - - void writeHeader(std::ostream& os); - void writeNextRecord(std::ostream& os); - -private: - template - using StatsRecord = std::unordered_map; - - template - struct StatsCollection : public std::vector> { - std::set keys; - }; - - StatsCollection _data; - T _dummy; // used when disabled - bool _enabled; - - size_t _writePos = 0; - std::string _delimiter; -}; - -} // namespace openspace::globebrowsing - -#include "templatedstatscollector.inl" - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TEMPLATED_STATS_COLLECTOR___H__ diff --git a/modules/globebrowsing/other/templatedstatscollector.inl b/modules/globebrowsing/other/templatedstatscollector.inl deleted file mode 100644 index c74686727d..0000000000 --- a/modules/globebrowsing/other/templatedstatscollector.inl +++ /dev/null @@ -1,118 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -namespace openspace::globebrowsing { - -template -TemplatedStatsCollector::TemplatedStatsCollector(Enabled enabled, - std::string delimiter) - : _enabled(enabled) - , _delimiter(std::move(delimiter)) -{} - -template -void TemplatedStatsCollector::startNewRecord() { - if (_enabled) { - _data.push_back(StatsRecord()); - } -} - -template -T& TemplatedStatsCollector::operator[](const std::string& name) { - if (_enabled) { - _data.keys.insert(name); - return _data.back()[name]; - } - else { - return _dummy; - } -} - -template -T TemplatedStatsCollector::previous(const std::string& name) const { - if (_data.size() > 1) { - return _data[_data.size() - 2][name]; - } - return T(); -} - -template -void TemplatedStatsCollector::setEnabled(bool enabled) { - _enabled = enabled; -} - -template -bool TemplatedStatsCollector::enabled() const { - return _enabled; -} - -template -bool TemplatedStatsCollector::hasHeaders() const { - return !_data.keys.empty(); -} - -template -bool TemplatedStatsCollector::hasRecordsToWrite() const { - return _writePos < (_data.size() - 1); -} - -template -void TemplatedStatsCollector::reset() { - // copy last, i.e. current record - StatsRecord lastRecord = _data.back(); - _data.clear(); - // add it again after cleared the vector - _data.push_back(std::move(lastRecord)); - _writePos = 0; -} - -template -void TemplatedStatsCollector::writeHeader(std::ostream& os) { - auto keyIt = _data.keys.begin(); - os << *keyIt; - while (++keyIt != _data.keys.end()) { - os << _delimiter << *keyIt; - } -} - -template -void TemplatedStatsCollector::writeNextRecord(std::ostream& os) { - if (hasRecordsToWrite()) { - // output line by line - StatsRecord& record = _data[_writePos]; - - // Access every key. Records with no entry will get a default value - auto keyIt = _data.keys.begin(); - if (keyIt != _data.keys.end()) { - os << record[(*keyIt)]; - while (++keyIt != _data.keys.end()) { - os << _delimiter << record[(*keyIt)]; - } - } - - _writePos++; - } -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/chunkrenderer.cpp b/modules/globebrowsing/rendering/chunkrenderer.cpp deleted file mode 100644 index e8477f48cc..0000000000 --- a/modules/globebrowsing/rendering/chunkrenderer.cpp +++ /dev/null @@ -1,547 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - constexpr const double KM_TO_M = 1000.0; -} // namespace - -namespace openspace::globebrowsing { - -ChunkRenderer::ChunkRenderer(std::shared_ptr grid, - std::shared_ptr layerManager, - Ellipsoid& ellipsoid) - : _grid(std::move(grid)) - , _layerManager(std::move(layerManager)) - , _ellipsoid(ellipsoid) -{ - _globalLayerShaderManager = std::make_shared( - "GlobalChunkedLodPatch", - "${MODULE_GLOBEBROWSING}/shaders/globalchunkedlodpatch_vs.glsl", - "${MODULE_GLOBEBROWSING}/shaders/globalchunkedlodpatch_fs.glsl" - ); - - _localLayerShaderManager = std::make_shared( - "LocalChunkedLodPatch", - "${MODULE_GLOBEBROWSING}/shaders/localchunkedlodpatch_vs.glsl", - "${MODULE_GLOBEBROWSING}/shaders/localchunkedlodpatch_fs.glsl" - ); - - _globalGpuLayerManager = std::make_shared(); - _localGpuLayerManager = std::make_shared(); -} - -ChunkRenderer::~ChunkRenderer() {} // NOLINT - -void ChunkRenderer::renderChunk(const Chunk& chunk, const RenderData& data) { - // A little arbitrary with 10 but it works - if (chunk.tileIndex().level < - chunk.owner().debugProperties().modelSpaceRenderingCutoffLevel) - { - renderChunkGlobally(chunk, data); - } - else { - renderChunkLocally(chunk, data); - } -} - -void ChunkRenderer::update() { - // unused atm. Could be used for caching or precalculating -} - -void ChunkRenderer::recompileShaders(const RenderableGlobe& globe) { - LayerShaderManager::LayerShaderPreprocessingData preprocessingData = - LayerShaderManager::LayerShaderPreprocessingData::get(globe); - _globalLayerShaderManager->recompileShaderProgram(preprocessingData); - _localLayerShaderManager->recompileShaderProgram(preprocessingData); -} - -ghoul::opengl::ProgramObject* ChunkRenderer::getActivatedProgramWithTileData( - LayerShaderManager& layeredShaderManager, - GPULayerManager& gpuLayerManager, - const Chunk& chunk) -{ - const TileIndex& tileIndex = chunk.tileIndex(); - - // Now the shader program can be accessed - ghoul::opengl::ProgramObject* programObject = layeredShaderManager.programObject(); - - if (layeredShaderManager.updatedSinceLastCall()) { - gpuLayerManager.bind(programObject, *_layerManager); - } - - // Activate the shader program - programObject->activate(); - - gpuLayerManager.setValue(programObject, *_layerManager, tileIndex); - - // The length of the skirts is proportional to its size - programObject->setUniform( - "skirtLength", - static_cast( - glm::min( - chunk.surfacePatch().halfSize().lat * 1000000, - _ellipsoid.minimumRadius() - ) - ) - ); - - //programObject->setUniform("skirtLength", - // glm::min(static_cast(chunk.surfacePatch().halfSize().lat * 1000000), - // 8700.0f)); - - programObject->setUniform("xSegments", _grid->xSegments()); - - if (chunk.owner().debugProperties().showHeightResolution) { - programObject->setUniform( - "vertexResolution", - glm::vec2(_grid->xSegments(), _grid->ySegments()) - ); - } - - return programObject; -} - -void ChunkRenderer::calculateEclipseShadows(const Chunk& chunk, - ghoul::opengl::ProgramObject* programObject, - const RenderData& data) -{ - // Shadow calculations.. - if (chunk.owner().ellipsoid().hasEclipseShadows()) { - std::vector shadowDataArray; - std::vector shadowConfArray = - chunk.owner().ellipsoid().shadowConfigurationArray(); - shadowDataArray.reserve(shadowConfArray.size()); - double lt; - for (const auto & shadowConf : shadowConfArray) { - // TO REMEMBER: all distances and lengths in world coordinates are in - // meters!!! We need to move this to view space... - // Getting source and caster: - glm::dvec3 sourcePos = SpiceManager::ref().targetPosition( - shadowConf.source.first, - "SUN", - "GALACTIC", - {}, - data.time.j2000Seconds(), - lt - ); - sourcePos *= KM_TO_M; // converting to meters - glm::dvec3 casterPos = SpiceManager::ref().targetPosition( - shadowConf.caster.first, - "SUN", - "GALACTIC", - {}, - data.time.j2000Seconds(), - lt - ); - casterPos *= KM_TO_M; // converting to meters - // psc caster_pos = PowerScaledCoordinate::CreatePowerScaledCoordinate( - // casterPos.x, - // casterPos.y, - // casterPos.z - // ); - - - // First we determine if the caster is shadowing the current planet (all - // calculations in World Coordinates): - const glm::dvec3 planetCasterVec = casterPos - data.position.dvec3(); - const glm::dvec3 sourceCasterVec = casterPos - sourcePos; - const double sc_length = glm::length(sourceCasterVec); - const glm::dvec3 planetCaster_proj = - (glm::dot(planetCasterVec, sourceCasterVec) / (sc_length*sc_length)) * - sourceCasterVec; - const double d_test = glm::length(planetCasterVec - planetCaster_proj); - const double xp_test = shadowConf.caster.second * sc_length / - (shadowConf.source.second + shadowConf.caster.second); - const double rp_test = shadowConf.caster.second * - (glm::length(planetCaster_proj) + xp_test) / xp_test; - - const glm::dvec3 sunPos = SpiceManager::ref().targetPosition( - "SUN", - "SUN", - "GALACTIC", - {}, - data.time.j2000Seconds(), - lt - ); - const double casterDistSun = glm::length(casterPos - sunPos); - const double planetDistSun = glm::length(data.position.dvec3() - sunPos); - - RenderableGlobe::ShadowRenderingStruct shadowData; - shadowData.isShadowing = false; - - // Eclipse shadows considers planets and moons as spheres - if (((d_test - rp_test) < (chunk.owner().ellipsoid().radii().x * KM_TO_M)) && - (casterDistSun < planetDistSun)) - { - // The current caster is shadowing the current planet - shadowData.isShadowing = true; - shadowData.rs = shadowConf.source.second; - shadowData.rc = shadowConf.caster.second; - shadowData.sourceCasterVec = glm::normalize(sourceCasterVec); - shadowData.xp = xp_test; - shadowData.xu = shadowData.rc * sc_length / - (shadowData.rs - shadowData.rc); - shadowData.casterPositionVec = casterPos; - } - shadowDataArray.push_back(shadowData); - } - - const std::string uniformVarName("shadowDataArray["); - unsigned int counter = 0; - for (const RenderableGlobe::ShadowRenderingStruct& sd : shadowDataArray) { - constexpr const char* NameIsShadowing = "shadowDataArray[{}].isShadowing"; - constexpr const char* NameXp = "shadowDataArray[{}].xp"; - constexpr const char* NameXu = "shadowDataArray[{}].xu"; - constexpr const char* NameRc = "shadowDataArray[{}].rc"; - constexpr const char* NameSource = "shadowDataArray[{}].sourceCasterVec"; - constexpr const char* NamePos= "shadowDataArray[{}].casterPositionVec"; - - programObject->setUniform( - fmt::format(NameIsShadowing, counter), sd.isShadowing - ); - if (sd.isShadowing) { - programObject->setUniform(fmt::format(NameXp, counter), sd.xp); - programObject->setUniform(fmt::format(NameXu, counter), sd.xu); - programObject->setUniform(fmt::format(NameRc, counter), sd.rc); - programObject->setUniform( - fmt::format(NameSource, counter), sd.sourceCasterVec - ); - programObject->setUniform( - fmt::format(NamePos, counter), sd.casterPositionVec - ); - } - counter++; - } - - programObject->setUniform( - "inverseViewTransform", - glm::inverse(data.camera.combinedViewMatrix()) - ); - programObject->setUniform("modelTransform", chunk.owner().modelTransform()); - programObject->setUniform( - "hardShadows", - chunk.owner().generalProperties().eclipseHardShadows - ); - programObject->setUniform("calculateEclipseShadows", true); - } -} - -void ChunkRenderer::setCommonUniforms(ghoul::opengl::ProgramObject& programObject, - const Chunk& chunk, const RenderData& data) -{ - const glm::dmat4 modelTransform = chunk.owner().modelTransform(); - const glm::dmat4 viewTransform = data.camera.combinedViewMatrix(); - const glm::dmat4 modelViewTransform = viewTransform * modelTransform; - - const bool nightLayersActive = - !_layerManager->layerGroup(layergroupid::NightLayers).activeLayers().empty(); - const bool waterLayersActive = - !_layerManager->layerGroup(layergroupid::WaterMasks).activeLayers().empty(); - - if (nightLayersActive || waterLayersActive || - chunk.owner().generalProperties().atmosphereEnabled || - chunk.owner().generalProperties().performShading) - { - const glm::dvec3 directionToSunWorldSpace = - length(data.modelTransform.translation) > 0.0 ? - glm::normalize(-data.modelTransform.translation) : - glm::dvec3(0.0); - - const glm::vec3 directionToSunCameraSpace = glm::vec3(viewTransform * - glm::dvec4(directionToSunWorldSpace, 0)); - programObject.setUniform( - "lightDirectionCameraSpace", - -glm::normalize(directionToSunCameraSpace) - ); - } - - if (chunk.owner().generalProperties().performShading) { - programObject.setUniform( - "orenNayarRoughness", - chunk.owner().generalProperties().orenNayarRoughness); - } - - if (chunk.owner().generalProperties().useAccurateNormals && - !_layerManager->layerGroup(layergroupid::HeightLayers).activeLayers().empty()) - { - const glm::dvec3 corner00 = chunk.owner().ellipsoid().cartesianSurfacePosition( - chunk.surfacePatch().corner(Quad::SOUTH_WEST) - ); - const glm::dvec3 corner10 = chunk.owner().ellipsoid().cartesianSurfacePosition( - chunk.surfacePatch().corner(Quad::SOUTH_EAST) - ); - const glm::dvec3 corner01 = chunk.owner().ellipsoid().cartesianSurfacePosition( - chunk.surfacePatch().corner(Quad::NORTH_WEST) - ); - const glm::dvec3 corner11 = chunk.owner().ellipsoid().cartesianSurfacePosition( - chunk.surfacePatch().corner(Quad::NORTH_EAST) - ); - - // This is an assumption that the height tile has a resolution of 64 * 64 - // If it does not it will still produce "correct" normals. If the resolution is - // higher the shadows will be softer, if it is lower, pixels will be visible. - // Since default is 64 this will most likely work fine. - - const glm::mat3& modelViewTransformMat3 = glm::mat3(modelViewTransform); - - constexpr const float TileDelta = 1.f / 64.f; - const glm::vec3 deltaTheta0 = modelViewTransformMat3 * - (glm::vec3(corner10 - corner00) * TileDelta); - const glm::vec3 deltaTheta1 = modelViewTransformMat3 * - (glm::vec3(corner11 - corner01) * TileDelta); - const glm::vec3 deltaPhi0 = modelViewTransformMat3 * - (glm::vec3(corner01 - corner00) * TileDelta); - const glm::vec3 deltaPhi1 = modelViewTransformMat3 * - (glm::vec3(corner11 - corner10) * TileDelta); - - // Upload uniforms - programObject.setUniform("deltaTheta0", glm::length(deltaTheta0)); - programObject.setUniform("deltaTheta1", glm::length(deltaTheta1)); - programObject.setUniform("deltaPhi0", glm::length(deltaPhi0)); - programObject.setUniform("deltaPhi1", glm::length(deltaPhi1)); - programObject.setUniform("tileDelta", TileDelta); - // This should not be needed once the light calculations for the atmosphere - // is performed in view space.. - programObject.setUniform( - "invViewModelTransform", - glm::inverse( - glm::mat4(data.camera.combinedViewMatrix()) * - glm::mat4(chunk.owner().modelTransform()) - ) - ); - } -} - -void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& data) { - ghoul::opengl::ProgramObject* programObject = getActivatedProgramWithTileData( - *_globalLayerShaderManager, - *_globalGpuLayerManager, - chunk - ); - if (!programObject) { - return; - } - - const Ellipsoid& ellipsoid = chunk.owner().ellipsoid(); - - if (_layerManager->hasAnyBlendingLayersEnabled()) { - // Calculations are done in the reference frame of the globe. Hence, the - // camera position needs to be transformed with the inverse model matrix - const glm::dmat4 inverseModelTransform = chunk.owner().inverseModelTransform(); - const glm::dvec3 cameraPosition = glm::dvec3( - inverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1.0) - ); - const float distanceScaleFactor = static_cast( - chunk.owner().generalProperties().lodScaleFactor * ellipsoid.minimumRadius() - ); - programObject->setUniform("cameraPosition", glm::vec3(cameraPosition)); - programObject->setUniform("distanceScaleFactor", distanceScaleFactor); - programObject->setUniform("chunkLevel", chunk.tileIndex().level); - } - - // Calculate other uniform variables needed for rendering - const Geodetic2 swCorner = chunk.surfacePatch().corner(Quad::SOUTH_WEST); - const Geodetic2& patchSize = chunk.surfacePatch().size(); - - const glm::dmat4 modelTransform = chunk.owner().modelTransform(); - const glm::dmat4 viewTransform = data.camera.combinedViewMatrix(); - const glm::mat4 modelViewTransform = glm::mat4(viewTransform * modelTransform); - const glm::mat4 modelViewProjectionTransform = - data.camera.sgctInternal.projectionMatrix() * modelViewTransform; - - // Upload the uniform variables - programObject->setUniform( - "modelViewProjectionTransform", - modelViewProjectionTransform - ); - programObject->setUniform("minLatLon", glm::vec2(swCorner.toLonLatVec2())); - programObject->setUniform("lonLatScalingFactor", glm::vec2(patchSize.toLonLatVec2())); - // Ellipsoid Radius (Model Space) - programObject->setUniform("radiiSquared", glm::vec3(ellipsoid.radiiSquared())); - - const bool hasNightLayers = !_layerManager->layerGroup( - layergroupid::GroupID::NightLayers - ).activeLayers().empty(); - - const bool hasWaterLayer = !_layerManager->layerGroup( - layergroupid::GroupID::WaterMasks - ).activeLayers().empty(); - - const bool hasHeightLayer = !_layerManager->layerGroup( - layergroupid::HeightLayers - ).activeLayers().empty(); - - if (hasNightLayers || hasWaterLayer || - chunk.owner().generalProperties().atmosphereEnabled || - chunk.owner().generalProperties().performShading) - { - programObject->setUniform("modelViewTransform", modelViewTransform); - } - - if (chunk.owner().generalProperties().useAccurateNormals && hasHeightLayer) { - // Apply an extra scaling to the height if the object is scaled - programObject->setUniform( - "heightScale", - static_cast(data.modelTransform.scale * data.camera.scaling()) - ); - } - - setCommonUniforms(*programObject, chunk, data); - - if (chunk.owner().ellipsoid().hasEclipseShadows()) { - calculateEclipseShadows(chunk, programObject, data); - } - - // OpenGL rendering settings - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - // render - _grid->geometry().drawUsingActiveProgram(); - - _globalGpuLayerManager->deactivate(); - - // disable shader - programObject->deactivate(); -} - -void ChunkRenderer::renderChunkLocally(const Chunk& chunk, const RenderData& data) { - ghoul::opengl::ProgramObject* programObject = getActivatedProgramWithTileData( - *_localLayerShaderManager, - *_localGpuLayerManager, - chunk - ); - if (!programObject) { - return; - } - - const Ellipsoid& ellipsoid = chunk.owner().ellipsoid(); - - if (_layerManager->hasAnyBlendingLayersEnabled()) { - float distanceScaleFactor = static_cast( - chunk.owner().generalProperties().lodScaleFactor * - chunk.owner().ellipsoid().minimumRadius() - ); - - programObject->setUniform("distanceScaleFactor", distanceScaleFactor); - programObject->setUniform("chunkLevel", chunk.tileIndex().level); - } - - // Calculate other uniform variables needed for rendering - // Send the matrix inverse to the fragment for the global and local shader (JCC) - const glm::dmat4 modelTransform = chunk.owner().modelTransform(); - const glm::dmat4 viewTransform = data.camera.combinedViewMatrix(); - const glm::dmat4 modelViewTransform = viewTransform * modelTransform; - - - std::array cornersCameraSpace; - std::array cornersModelSpace; - for (int i = 0; i < 4; ++i) { - constexpr const std::array CornerNames = { - "p01", "p11", "p00", "p10" - }; - - const Quad q = static_cast(i); - const Geodetic2 corner = chunk.surfacePatch().corner(q); - const glm::dvec3 cornerModelSpace = ellipsoid.cartesianSurfacePosition(corner); - cornersModelSpace[i] = cornerModelSpace; - const glm::dvec3 cornerCameraSpace = glm::dvec3( - modelViewTransform * glm::dvec4(cornerModelSpace, 1) - ); - cornersCameraSpace[i] = cornerCameraSpace; - programObject->setUniform(CornerNames[i], glm::vec3(cornerCameraSpace)); - - } - - // TODO: Patch normal can be calculated for all corners and then linearly - // interpolated on the GPU to avoid cracks for high altitudes. - const glm::vec3 patchNormalCameraSpace = normalize( - cross( - cornersCameraSpace[Quad::SOUTH_EAST] - cornersCameraSpace[Quad::SOUTH_WEST], - cornersCameraSpace[Quad::NORTH_EAST] - cornersCameraSpace[Quad::SOUTH_WEST] - ) - ); - - // In order to improve performance, lets use the normal in object space (model space) - // for deferred rendering. - const glm::vec3 patchNormalModelSpace = normalize( - cross( - cornersModelSpace[Quad::SOUTH_EAST] - cornersModelSpace[Quad::SOUTH_WEST], - cornersModelSpace[Quad::NORTH_EAST] - cornersModelSpace[Quad::SOUTH_WEST] - ) - ); - - programObject->setUniform("patchNormalModelSpace", patchNormalModelSpace); - programObject->setUniform("patchNormalCameraSpace", patchNormalCameraSpace); - programObject->setUniform( - "projectionTransform", - data.camera.sgctInternal.projectionMatrix() - ); - - if (!_layerManager->layerGroup(layergroupid::HeightLayers).activeLayers().empty()) { - // Apply an extra scaling to the height if the object is scaled - programObject->setUniform( - "heightScale", - static_cast(data.modelTransform.scale * data.camera.scaling()) - ); - } - - setCommonUniforms(*programObject, chunk, data); - - if (chunk.owner().ellipsoid().hasEclipseShadows()) { - calculateEclipseShadows(chunk, programObject, data); - } - - // OpenGL rendering settings - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - // render - _grid->geometry().drawUsingActiveProgram(); - - _localGpuLayerManager->deactivate(); - - // disable shader - programObject->deactivate(); -} - -} // namespace openspace:;globebrowsing diff --git a/modules/globebrowsing/rendering/chunkrenderer.h b/modules/globebrowsing/rendering/chunkrenderer.h deleted file mode 100644 index c0fda96cf5..0000000000 --- a/modules/globebrowsing/rendering/chunkrenderer.h +++ /dev/null @@ -1,111 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___CHUNK_RENDERER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___CHUNK_RENDERER___H__ - -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace { struct RenderData; } - -namespace openspace::globebrowsing { - -class Chunk; -class Ellipsoid; -class Grid; -class GPULayerManager; -class LayerManager; -class LayerShaderManager; -class RenderableGlobe; - -class ChunkRenderer { -public: - ChunkRenderer(std::shared_ptr grid, std::shared_ptr layerManager, - Ellipsoid& ellipsoid); - - ~ChunkRenderer(); - - /** - * Chooses to render a chunk either locally or globally depending on the chunklevel - * of the Chunk. - */ - void renderChunk(const Chunk& chunk, const RenderData& data); - void update(); - - void recompileShaders(const RenderableGlobe& globe); - -private: - /** - * Chunks can be rendered either globally or locally. Global rendering is performed - * in the model space of the globe. With global rendering, the vertex positions - * of a chunk are calculated in the vertex shader by transforming the geodetic - * coordinates of the chunk to model space coordinates. We can only achieve floating - * point precision by doing this which means that the camera too close to a global - * tile will lead to jagging. We only render global chunks for lower chunk levels. - */ - void renderChunkGlobally(const Chunk& chunk, const RenderData& data); - - /** - * Local rendering of chunks are done using linear interpolation in camera space. - * All four corner points of the chunk are calculated in double precision on the - * CPU and transformed to camera space with double precision matrix transforms. - * These positions can then be cast to floats and uploaded to the vertex shader. - * The vertex shader rendering performs linear interpolation between the four - * corner points to get the resulting chunk. This means that there will be an error - * due to the curvature of the globe. The smaller the patch is (with higher chunk - * levels) the better the approximation becomes. This is why we only render local - * chunks for higher chunk levels. - */ - void renderChunkLocally(const Chunk& chunk, const RenderData& data); - - ghoul::opengl::ProgramObject* getActivatedProgramWithTileData( - LayerShaderManager& layeredShaderManager, GPULayerManager& gpuLayerManager, - const Chunk& chunk); - - void calculateEclipseShadows(const Chunk& chunk, - ghoul::opengl::ProgramObject* programObject, const RenderData& data); - - void setCommonUniforms(ghoul::opengl::ProgramObject& programObject, - const Chunk& chunk, const RenderData& data); - - // shared pointer to a grid which can be the same for all rendered chunks. - std::shared_ptr _grid; - std::shared_ptr _layerManager; - - Ellipsoid& _ellipsoid; - - // Two different shader programs. One for global and one for local rendering. - std::shared_ptr _globalLayerShaderManager; - std::shared_ptr _localLayerShaderManager; - - // Layered texture uniforms are chached in the uniform ID handles. - std::shared_ptr _globalGpuLayerManager; - std::shared_ptr _localGpuLayerManager; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___CHUNK_RENDERER___H__ diff --git a/modules/globebrowsing/rendering/gpu/gpuchunktile.cpp b/modules/globebrowsing/rendering/gpu/gpuchunktile.cpp deleted file mode 100644 index a5d39c38de..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpuchunktile.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include - -namespace openspace::globebrowsing { - -void GPUChunkTile::setValue(ghoul::opengl::ProgramObject* programObject, - const ChunkTile& chunkTile) -{ - gpuTexture.setValue(programObject, chunkTile.tile.texture()); - gpuTileUvTransform.setValue(programObject, chunkTile.uvTransform); -} - -void GPUChunkTile::bind(ghoul::opengl::ProgramObject* programObject, - const std::string& nameBase) -{ - gpuTexture.bind(programObject, nameBase + "textureSampler"); - gpuTileUvTransform.bind(programObject, nameBase + "uvTransform."); -} - -void GPUChunkTile::deactivate() { - gpuTexture.deactivate(); -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gpuchunktile.h b/modules/globebrowsing/rendering/gpu/gpuchunktile.h deleted file mode 100644 index 59819b9909..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpuchunktile.h +++ /dev/null @@ -1,73 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPUCHUNKTILE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GPUCHUNKTILE___H__ - -#include - -#include -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace::globebrowsing { - -struct ChunkTile; - -/** - * Manages a GPU representation of a ChunkTile - */ -class GPUChunkTile { -public: - - /** - * Sets the value of ChunkTile to its corresponding - * GPU struct. OBS! Users must ensure bind has been - * called before setting using this method. - */ - void setValue(ghoul::opengl::ProgramObject* programObject, - const ChunkTile& chunkTile); - - /** - * Binds GLSL variables with identifiers starting with - * nameBase within the provided shader program with this object. - * After this method has been called, users may invoke setValue. - */ - void bind(ghoul::opengl::ProgramObject* programObject, const std::string& nameBase); - - /** - * Deactivates any TextureUnits assigned by this object. - * This method should be called after the OpenGL draw call. - */ - void deactivate(); - -private: - GPUTexture gpuTexture; - GPUTileUvTransform gpuTileUvTransform; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GPUCHUNKTILE___H__ diff --git a/modules/globebrowsing/rendering/gpu/gpuchunktilepile.cpp b/modules/globebrowsing/rendering/gpu/gpuchunktilepile.cpp deleted file mode 100644 index 918bf10918..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpuchunktilepile.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace openspace::globebrowsing { - -void GPUChunkTilePile::setValue(ghoul::opengl::ProgramObject* programObject, - const ChunkTilePile& chunkTilePile) -{ - ghoul_assert( - _gpuChunkTiles.size() == chunkTilePile.size(), - "GPU and CPU ChunkTilePile must have same size!" - ); - for (size_t i = 0; i < _gpuChunkTiles.size(); ++i) { - _gpuChunkTiles[i].setValue(programObject, chunkTilePile[i]); - } -} - -void GPUChunkTilePile::bind(ghoul::opengl::ProgramObject* programObject, - const std::string& nameBase, int pileSize) -{ - _gpuChunkTiles.resize(pileSize); - for (size_t i = 0; i < _gpuChunkTiles.size(); ++i) { - std::string nameExtension = "chunkTile" + std::to_string(i) + "."; - _gpuChunkTiles[i].bind(programObject, nameBase + nameExtension); - } -} - -void GPUChunkTilePile::deactivate() { - for (GPUChunkTile& t : _gpuChunkTiles) { - t.deactivate(); - } -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gpuchunktilepile.h b/modules/globebrowsing/rendering/gpu/gpuchunktilepile.h deleted file mode 100644 index c2f3f2d100..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpuchunktilepile.h +++ /dev/null @@ -1,69 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPUCHUNKTILEPILE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GPUCHUNKTILEPILE___H__ - -#include -#include -#include -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace::globebrowsing { - -/** - * Manages a GPU representation of a ChunkTilePile - */ -class GPUChunkTilePile { -public: - /** - * Sets the value of ChunkTilePile to its corresponding - * GPU struct. OBS! Users must ensure bind has been - * called before setting using this method. - */ - void setValue(ghoul::opengl::ProgramObject* programObject, - const ChunkTilePile& chunkTilePile); - - /** - * Binds this object with GLSL variables with identifiers starting - * with nameBase within the provided shader program. - * After this method has been called, users may invoke setValue. - */ - void bind(ghoul::opengl::ProgramObject* programObject, const std::string& nameBase, - int pileSize); - /** - * Deactivates any TextureUnits assigned by this object. - * This method should be called after the OpenGL draw call. - */ - void deactivate(); - -private: - std::vector _gpuChunkTiles; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GPUCHUNKTILEPILE___H__ diff --git a/modules/globebrowsing/rendering/gpu/gpuheightlayer.cpp b/modules/globebrowsing/rendering/gpu/gpuheightlayer.cpp deleted file mode 100644 index 4d84858569..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpuheightlayer.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace openspace::globebrowsing { - -void GPUHeightLayer::setValue(ghoul::opengl::ProgramObject* programObject, - const Layer& layer, const TileIndex& tileIndex, - int pileSize) -{ - GPULayer::setValue(programObject, layer, tileIndex, pileSize); - _gpuDepthTransform.setValue(programObject, layer.depthTransform()); -} - -void GPUHeightLayer::bind(ghoul::opengl::ProgramObject* programObject, const Layer& layer, - const std::string& nameBase, int pileSize) -{ - GPULayer::bind(programObject, layer, nameBase, pileSize); - _gpuDepthTransform.bind(programObject, nameBase + "depthTransform."); -} - - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gpuheightlayer.h b/modules/globebrowsing/rendering/gpu/gpuheightlayer.h deleted file mode 100644 index 7cb5e1e16c..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpuheightlayer.h +++ /dev/null @@ -1,70 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPUHEIGHTLAYER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GPUHEIGHTLAYER___H__ - -#include - -#include -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace::globebrowsing { - -class Layer; -struct TileIndex; - -/** - * Manages a GPU representation of a Layer representing - * a height map. - */ -class GPUHeightLayer : public GPULayer { -public: - virtual ~GPUHeightLayer() override = default; - - /** - * Sets the value of Layer to its corresponding - * GPU struct. OBS! Users must ensure bind has been - * called before setting using this method. - */ - virtual void setValue(ghoul::opengl::ProgramObject* programObject, const Layer& layer, - const TileIndex& tileIndex, int pileSize) override; - - /** - * Binds this object with GLSL variables with identifiers starting - * with nameBase within the provided shader program. - * After this method has been called, users may invoke setValue. - */ - virtual void bind(ghoul::opengl::ProgramObject* programObject, const Layer& layer, - const std::string& nameBase, int pileSize) override; - -private: - GPUTileDepthTransform _gpuDepthTransform; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GPUHEIGHTLAYER___H__ diff --git a/modules/globebrowsing/rendering/gpu/gpulayer.cpp b/modules/globebrowsing/rendering/gpu/gpulayer.cpp deleted file mode 100644 index 70fd0865c1..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpulayer.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace openspace::globebrowsing { - -void GPULayer::setValue(ghoul::opengl::ProgramObject* programObject, const Layer& layer, - const TileIndex& tileIndex, int pileSize) -{ - gpuRenderSettings.setValue(programObject, layer.renderSettings()); - gpuLayerAdjustment.setValue(programObject, layer.layerAdjustment()); - - switch (layer.type()) { - // Intentional fall through. Same for all tile layers - case layergroupid::TypeID::DefaultTileLayer: - case layergroupid::TypeID::SingleImageTileLayer: - case layergroupid::TypeID::SizeReferenceTileLayer: - case layergroupid::TypeID::TemporalTileLayer: - case layergroupid::TypeID::TileIndexTileLayer: - case layergroupid::TypeID::ByIndexTileLayer: - case layergroupid::TypeID::ByLevelTileLayer: { - ChunkTilePile chunkTilePile = layer.chunkTilePile(tileIndex, pileSize); - gpuChunkTilePile.setValue(programObject, chunkTilePile); - paddingStartOffset.setValue(programObject, layer.tilePixelStartOffset()); - paddingSizeDifference.setValue( - programObject, - layer.tilePixelSizeDifference() - ); - break; - } - case layergroupid::TypeID::SolidColor: - gpuColor.setValue(programObject, layer.otherTypesProperties().color.value()); - break; - default: - break; - } -} - -void GPULayer::bind(ghoul::opengl::ProgramObject* programObject, const Layer& layer, - const std::string& nameBase, int pileSize) -{ - gpuRenderSettings.bind(layer.renderSettings(), programObject, nameBase + "settings."); - gpuLayerAdjustment.bind( - layer.layerAdjustment(), - programObject, - nameBase + "adjustment." - ); - - switch (layer.type()) { - // Intentional fall through. Same for all tile layers - case layergroupid::TypeID::DefaultTileLayer: - case layergroupid::TypeID::SingleImageTileLayer: - case layergroupid::TypeID::SizeReferenceTileLayer: - case layergroupid::TypeID::TemporalTileLayer: - case layergroupid::TypeID::TileIndexTileLayer: - case layergroupid::TypeID::ByIndexTileLayer: - case layergroupid::TypeID::ByLevelTileLayer: { - gpuChunkTilePile.bind(programObject, nameBase + "pile.", pileSize); - paddingStartOffset.bind(programObject, nameBase + "padding.startOffset"); - paddingSizeDifference.bind( - programObject, - nameBase + "padding.sizeDifference" - ); - break; - } - case layergroupid::TypeID::SolidColor: - gpuColor.bind(programObject, nameBase + "color"); - break; - default: - break; - } -} - -void GPULayer::deactivate() { - gpuChunkTilePile.deactivate(); -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gpulayer.h b/modules/globebrowsing/rendering/gpu/gpulayer.h deleted file mode 100644 index dfa9dffaa7..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpulayer.h +++ /dev/null @@ -1,83 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER___H__ - -#include -#include -#include -#include -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace::globebrowsing { - -class Layer; -struct TileIndex; - -/** - * Manages a GPU representation of a Layer - */ -class GPULayer { -public: - virtual ~GPULayer() = default; - - /** - * Sets the value of Layer to its corresponding - * GPU struct. OBS! Users must ensure bind has been - * called before setting using this method. - */ - virtual void setValue(ghoul::opengl::ProgramObject* programObject, const Layer& layer, - const TileIndex& tileIndex, int pileSize); - - /** - * Binds this object with GLSL variables with identifiers starting - * with nameBase within the provided shader program. - * After this method has been called, users may invoke setValue. - */ - virtual void bind(ghoul::opengl::ProgramObject* programObject, const Layer& layer, - const std::string& nameBase, int pileSize); - - /** - * Deactivates any TextureUnits assigned by this object. - * This method should be called after the OpenGL draw call. - */ - virtual void deactivate(); - -private: - GPUChunkTilePile gpuChunkTilePile; - GPULayerRenderSettings gpuRenderSettings; - GPULayerAdjustment gpuLayerAdjustment; - - GPUData paddingStartOffset; - GPUData paddingSizeDifference; - // Adjustment layer stuff - GPUData gpuColor; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER___H__ diff --git a/modules/globebrowsing/rendering/gpu/gpulayeradjustment.cpp b/modules/globebrowsing/rendering/gpu/gpulayeradjustment.cpp deleted file mode 100644 index ebe23914bf..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpulayeradjustment.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace openspace::globebrowsing { - -void GPULayerAdjustment::setValue(ghoul::opengl::ProgramObject* programObject, - const LayerAdjustment& layerAdjustment) -{ - switch (layerAdjustment.type()) { - case layergroupid::AdjustmentTypeID::None: - break; - case layergroupid::AdjustmentTypeID::ChromaKey: { - gpuChromaKeyColor.setValue( - programObject, - layerAdjustment.chromaKeyColor() - ); - gpuChromaKeyTolerance.setValue( - programObject, - layerAdjustment.chromaKeyTolerance() - ); - break; - } - case layergroupid::AdjustmentTypeID::TransferFunction: - break; - } -} - -void GPULayerAdjustment::bind(const LayerAdjustment& layerAdjustment, - ghoul::opengl::ProgramObject* programObject, - const std::string& nameBase) -{ - switch (layerAdjustment.type()) { - case layergroupid::AdjustmentTypeID::None: - break; - case layergroupid::AdjustmentTypeID::ChromaKey: { - gpuChromaKeyColor.bind(programObject, nameBase + "chromaKeyColor"); - gpuChromaKeyTolerance.bind(programObject, nameBase + "chromaKeyTolerance"); - break; - } - case layergroupid::AdjustmentTypeID::TransferFunction: - break; - } -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gpulayeradjustment.h b/modules/globebrowsing/rendering/gpu/gpulayeradjustment.h deleted file mode 100644 index d825ff2902..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpulayeradjustment.h +++ /dev/null @@ -1,51 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER_ADJUSTMENT___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER_ADJUSTMENT___H__ - -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace::globebrowsing { - -class LayerAdjustment; - -class GPULayerAdjustment{ -public: - void setValue(ghoul::opengl::ProgramObject* programObject, - const LayerAdjustment& layerAdjustment); - - void bind(const LayerAdjustment& layerAdjustment, - ghoul::opengl::ProgramObject* programObject, const std::string& nameBase); - -private: - GPUData gpuChromaKeyColor; - GPUData gpuChromaKeyTolerance; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER_ADJUSTMENT___H__ diff --git a/modules/globebrowsing/rendering/gpu/gpulayergroup.cpp b/modules/globebrowsing/rendering/gpu/gpulayergroup.cpp deleted file mode 100644 index 13f3831078..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpulayergroup.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include - -namespace openspace::globebrowsing { - -GPULayerGroup::~GPULayerGroup() {} // NOLINT - -void GPULayerGroup::setValue(ghoul::opengl::ProgramObject* programObject, - const LayerGroup& layerGroup, const TileIndex& tileIndex) -{ - auto& activeLayers = layerGroup.activeLayers(); - ghoul_assert( - activeLayers.size() == _gpuActiveLayers.size(), - "GPU and CPU active layers must have same size!" - ); - for (unsigned int i = 0; i < activeLayers.size(); ++i) { - _gpuActiveLayers[i]->setValue( - programObject, - *activeLayers[i], - tileIndex, - layerGroup.pileSize() - ); - } -} - -void GPULayerGroup::bind(ghoul::opengl::ProgramObject* programObject, - const LayerGroup& layerGroup, const std::string& nameBase, - int category) -{ - const std::vector>& activeLayers = layerGroup.activeLayers(); - _gpuActiveLayers.resize(activeLayers.size()); - const int pileSize = layerGroup.pileSize(); - for (size_t i = 0; i < _gpuActiveLayers.size(); ++i) { - // should maybe a proper GPULayer factory - _gpuActiveLayers[i] = (category == layergroupid::GroupID::HeightLayers) ? - std::make_unique() : - std::make_unique(); - _gpuActiveLayers[i]->bind( - programObject, - *activeLayers[i], - nameBase + "[" + std::to_string(i) + "].", - pileSize - ); - } -} - -void GPULayerGroup::deactivate() { - for (std::unique_ptr& l : _gpuActiveLayers) { - l->deactivate(); - } -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gpulayermanager.cpp b/modules/globebrowsing/rendering/gpu/gpulayermanager.cpp deleted file mode 100644 index 013021aa5f..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpulayermanager.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include - -namespace openspace::globebrowsing { - -GPULayerManager::~GPULayerManager() {} // NOLINT - -void GPULayerManager::setValue(ghoul::opengl::ProgramObject* programObject, - const LayerManager& manager, const TileIndex& tileIndex) -{ - const std::vector>& layerGroups = manager.layerGroups(); - - for (size_t i = 0; i < layerGroups.size(); ++i) { - _gpuLayerGroups[i]->setValue(programObject, *layerGroups[i], tileIndex); - } -} - -void GPULayerManager::bind(ghoul::opengl::ProgramObject* programObject, - const LayerManager& manager) -{ - const std::vector>& layerGroups = manager.layerGroups(); - if (_gpuLayerGroups.size() != layerGroups.size()) { - _gpuLayerGroups.resize(layerGroups.size()); - for (std::unique_ptr& gpuLayerGroup : _gpuLayerGroups) { - gpuLayerGroup = std::make_unique(); - } - } - - for (size_t i = 0; i < layerGroups.size(); ++i) { - const std::string& nameBase = layergroupid::LAYER_GROUP_IDENTIFIERS[i]; - _gpuLayerGroups[i]->bind( - programObject, - *layerGroups[i], - nameBase, - static_cast(i) - ); - } -} - -void GPULayerManager::deactivate() { - for (std::unique_ptr& l : _gpuLayerGroups) { - l->deactivate(); - } -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gpulayermanager.h b/modules/globebrowsing/rendering/gpu/gpulayermanager.h deleted file mode 100644 index 81d3ce6ad6..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpulayermanager.h +++ /dev/null @@ -1,75 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYERMANAGER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYERMANAGER___H__ - -#include -#include -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace::globebrowsing { - -class GPULayerGroup; -class LayerManager; -struct TileIndex; - -/** - * Manages a GPU representation of a LayerGroup - */ -class GPULayerManager { -public: - ~GPULayerManager(); - - /** - * Sets the value of LayerGroup to its corresponding - * GPU struct. OBS! Users must ensure bind has been - * called before setting using this method. - */ - void setValue(ghoul::opengl::ProgramObject* programObject, - const LayerManager& manager, const TileIndex& tileIndex); - - /** - * Binds this object with GLSL variables with identifiers starting - * with nameBase within the provided shader program. - * After this method has been called, users may invoke setValue. - */ - void bind(ghoul::opengl::ProgramObject* programObject, - const LayerManager& manager); - - /** - * Deactivates any TextureUnits assigned by this object. - * This method should be called after the OpenGL draw call. - */ - void deactivate(); - -private: - std::vector> _gpuLayerGroups; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYERMANAGER___H__ diff --git a/modules/globebrowsing/rendering/gpu/gpulayerrendersettings.cpp b/modules/globebrowsing/rendering/gpu/gpulayerrendersettings.cpp deleted file mode 100644 index 4210723f02..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpulayerrendersettings.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace openspace::globebrowsing { - -void GPULayerRenderSettings::setValue(ghoul::opengl::ProgramObject* programObject, - const LayerRenderSettings& layerSettings) -{ - gpuOpacity.setValue(programObject, layerSettings.opacity.value()); - gpuGamma.setValue(programObject, layerSettings.gamma.value()); - gpuMultiplier.setValue(programObject, layerSettings.multiplier.value()); - gpuOffset.setValue(programObject, layerSettings.offset.value()); -} - -void GPULayerRenderSettings::bind(const LayerRenderSettings&, - ghoul::opengl::ProgramObject* programObject, - const std::string& nameBase) -{ - gpuOpacity.bind(programObject, nameBase + "opacity"); - gpuGamma.bind(programObject, nameBase + "gamma"); - gpuMultiplier.bind(programObject, nameBase + "multiplier"); - gpuOffset.bind(programObject, nameBase + "offset"); -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gpulayerrendersettings.h b/modules/globebrowsing/rendering/gpu/gpulayerrendersettings.h deleted file mode 100644 index 8d6ab3dead..0000000000 --- a/modules/globebrowsing/rendering/gpu/gpulayerrendersettings.h +++ /dev/null @@ -1,70 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYERRENDERSETTINGS___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYERRENDERSETTINGS___H__ - -#include -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace::globebrowsing { - -struct LayerRenderSettings; - -/** - * Manages a GPU representation of a LayerRenderSettings - */ -class GPULayerRenderSettings{ -public: - /** - * Sets the value of LayerRenderSettings to its corresponding - * GPU struct. OBS! Users must ensure bind has been - * called before setting using this method. - */ - void setValue(ghoul::opengl::ProgramObject* programObject, - const LayerRenderSettings& layerSettings); - - /** - * Binds this object with GLSL variables with identifiers starting - * with nameBase within the provided shader program. - * After this method has been called, users may invoke setValue. - */ - void bind(const LayerRenderSettings& layerSettings, - ghoul::opengl::ProgramObject* programObject, const std::string& nameBase); - -private: - GPUData gpuOpacity; - GPUData gpuGamma; - GPUData gpuMultiplier; - GPUData gpuOffset; - - // Optional - GPUData gpuValueBlending; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYERRENDERSETTINGS___H__ diff --git a/modules/globebrowsing/rendering/gpu/gputiledepthtransform.cpp b/modules/globebrowsing/rendering/gpu/gputiledepthtransform.cpp deleted file mode 100644 index bfd54fe5e5..0000000000 --- a/modules/globebrowsing/rendering/gpu/gputiledepthtransform.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace openspace::globebrowsing { - -void GPUTileDepthTransform::setValue(ghoul::opengl::ProgramObject* programObject, - const TileDepthTransform& depthTransform) -{ - _gpuDepthOffset.setValue(programObject, depthTransform.depthOffset); - _gpuDepthScale.setValue(programObject, depthTransform.depthScale); -} - -void GPUTileDepthTransform::bind(ghoul::opengl::ProgramObject* programObject, - const std::string& nameBase) -{ - _gpuDepthOffset.bind(programObject, nameBase + "depthOffset"); - _gpuDepthScale.bind(programObject, nameBase + "depthScale"); -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gputiledepthtransform.h b/modules/globebrowsing/rendering/gpu/gputiledepthtransform.h deleted file mode 100644 index 932f0f4f28..0000000000 --- a/modules/globebrowsing/rendering/gpu/gputiledepthtransform.h +++ /dev/null @@ -1,65 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPUTILEDEPTHTRANSFORM___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GPUTILEDEPTHTRANSFORM___H__ - -#include -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace::globebrowsing { - -struct TileDepthTransform; - -/** - * Manages a GPU representation of a TileDepthTransform - */ -class GPUTileDepthTransform { -public: - /** - * Sets the value of TileDepthTransform to its corresponding - * GPU struct. OBS! Users must ensure bind has been - * called before setting using this method. - */ - void setValue(ghoul::opengl::ProgramObject* programObject, - const TileDepthTransform& depthTransform); - - /** - * Binds GLSL variables with identifiers starting with - * nameBase within the provided shader program with this object. - * After this method has been called, users may invoke setValue. - */ - void bind(ghoul::opengl::ProgramObject* programObject, - const std::string& nameBase); - -private: - GPUData _gpuDepthOffset; - GPUData _gpuDepthScale; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GPUTILEDEPTHTRANSFORM___H__ diff --git a/modules/globebrowsing/rendering/gpu/gputileuvtransform.cpp b/modules/globebrowsing/rendering/gpu/gputileuvtransform.cpp deleted file mode 100644 index f92c254d2b..0000000000 --- a/modules/globebrowsing/rendering/gpu/gputileuvtransform.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include - -namespace openspace::globebrowsing { - -void GPUTileUvTransform::setValue(ghoul::opengl::ProgramObject* programObject, - const TileUvTransform& uvTransform) -{ - _gpuUvOffset.setValue(programObject, uvTransform.uvOffset); - _gpuUvScale.setValue(programObject, uvTransform.uvScale); -} - -void GPUTileUvTransform::bind(ghoul::opengl::ProgramObject* programObject, - const std::string& nameBase) -{ - _gpuUvOffset.bind(programObject, nameBase + "uvOffset"); - _gpuUvScale.bind(programObject, nameBase + "uvScale"); -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gputileuvtransform.h b/modules/globebrowsing/rendering/gpu/gputileuvtransform.h deleted file mode 100644 index da3c5ed9ea..0000000000 --- a/modules/globebrowsing/rendering/gpu/gputileuvtransform.h +++ /dev/null @@ -1,64 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPUTILEUVTRANSFORM___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___GPUTILEUVTRANSFORM___H__ - -#include -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace::globebrowsing { - -struct TileUvTransform; - -/** - * Manages a GPU representation of a TileUvTransform - */ -class GPUTileUvTransform { -public: - /** - * Sets the value of TileUvTransform to its corresponding - * GPU struct. OBS! Users must ensure bind has been - * called before setting using this method. - */ - void setValue(ghoul::opengl::ProgramObject* programObject, - const TileUvTransform& uvTransform); - - /** - * Binds GLSL variables with identifiers starting with - * nameBase within the provided shader program with this object. - * After this method has been called, users may invoke setValue. - */ - void bind(ghoul::opengl::ProgramObject* programObject, const std::string& nameBase); - -private: - GPUData _gpuUvOffset; - GPUData _gpuUvScale; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GPUTILEUVTRANSFORM___H__ diff --git a/modules/globebrowsing/rendering/layer/layermanager.cpp b/modules/globebrowsing/rendering/layer/layermanager.cpp deleted file mode 100644 index 3aba2dc51a..0000000000 --- a/modules/globebrowsing/rendering/layer/layermanager.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -namespace { - constexpr const char* _loggerCat = "LayerManager"; -} // namespace - -namespace openspace::globebrowsing { - -LayerManager::LayerManager(const ghoul::Dictionary& layerGroupsDict) - : properties::PropertyOwner({ "Layers" }) -{ - // First create empty layer groups in case not all are specified - _layerGroups.resize(layergroupid::NUM_LAYER_GROUPS); - for (size_t i = 0; i < _layerGroups.size(); ++i) { - ghoul::Dictionary emptyDict; - _layerGroups[i] = std::make_shared( - static_cast(i), emptyDict - ); - } - - const std::vector& layerGroupNamesInDict = layerGroupsDict.keys(); - - // Create all the layer groups - for (const std::string& groupName : layerGroupNamesInDict) { - layergroupid::GroupID groupId = layergroupid::getGroupIDFromName(groupName); - - if (groupId != layergroupid::GroupID::Unknown) { - ghoul::Dictionary layerGroupDict = layerGroupsDict.value( - groupName - ); - _layerGroups[static_cast(groupId)] = std::make_shared( - groupId, - layerGroupDict - ); - } - else { - LWARNING("Unknown layer group: " + groupName); - } - } - - for (const std::shared_ptr& layerGroup : _layerGroups) { - addPropertySubOwner(layerGroup.get()); - } -} - -void LayerManager::initialize() { - for (const std::shared_ptr& lg : _layerGroups) { - lg->initialize(); - } -} - -void LayerManager::deinitialize() { - for (const std::shared_ptr& lg : _layerGroups) { - lg->deinitialize(); - } -} - -std::shared_ptr LayerManager::addLayer(layergroupid::GroupID groupId, - const ghoul::Dictionary& layerDict) -{ - ghoul_assert(groupId != layergroupid::Unknown, "Layer group ID must be known"); - - return _layerGroups[groupId]->addLayer(layerDict); -} - -void LayerManager::deleteLayer(layergroupid::GroupID groupId, - const std::string& layerName) -{ - ghoul_assert(groupId != layergroupid::Unknown, "Layer group ID must be known"); - - _layerGroups[groupId]->deleteLayer(layerName); -} - -const LayerGroup& LayerManager::layerGroup(size_t groupId) { - return *_layerGroups[groupId]; -} - -const LayerGroup& LayerManager::layerGroup(layergroupid::GroupID groupId) { - return *_layerGroups[groupId]; -} - -bool LayerManager::hasAnyBlendingLayersEnabled() const { - return std::any_of( - _layerGroups.begin(), - _layerGroups.end(), - [](const std::shared_ptr& layerGroup) { - return layerGroup->layerBlendingEnabled() && - !layerGroup->activeLayers().empty(); - } - ); -} - -const std::vector>& LayerManager::layerGroups() const { - return _layerGroups; -} - -void LayerManager::update() { - for (std::shared_ptr& layerGroup : _layerGroups) { - layerGroup->update(); - } -} - -void LayerManager::reset(bool includeDisabled) { - for (std::shared_ptr& layerGroup : _layerGroups) { - for (const std::shared_ptr& layer : layerGroup->layers()) { - if (layer->enabled() || includeDisabled) { - layer->tileProvider()->reset(); - } - } - } -} - -TileTextureInitData LayerManager::getTileTextureInitData(layergroupid::GroupID id, - PadTiles padTiles, - size_t preferredTileSize) -{ - switch (id) { - case layergroupid::GroupID::HeightLayers: { - const size_t tileSize = preferredTileSize ? preferredTileSize : 64; - return TileTextureInitData( - tileSize, - tileSize, - GL_FLOAT, - ghoul::opengl::Texture::Format::Red, - TileTextureInitData::PadTiles(padTiles), - TileTextureInitData::ShouldAllocateDataOnCPU::Yes - ); - } - case layergroupid::GroupID::ColorLayers: { - const size_t tileSize = preferredTileSize ? preferredTileSize : 512; - return TileTextureInitData( - tileSize, - tileSize, - GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::BGRA, - TileTextureInitData::PadTiles(padTiles) - ); - } - case layergroupid::GroupID::Overlays: { - const size_t tileSize = preferredTileSize ? preferredTileSize : 512; - return TileTextureInitData( - tileSize, - tileSize, - GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::BGRA, - TileTextureInitData::PadTiles(padTiles) - ); - } - case layergroupid::GroupID::NightLayers: { - const size_t tileSize = preferredTileSize ? preferredTileSize : 512; - return TileTextureInitData( - tileSize, - tileSize, - GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::BGRA, - TileTextureInitData::PadTiles(padTiles) - ); - } - case layergroupid::GroupID::WaterMasks: { - const size_t tileSize = preferredTileSize ? preferredTileSize : 512; - return TileTextureInitData( - tileSize, - tileSize, - GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::BGRA, - TileTextureInitData::PadTiles(padTiles) - ); - } - default: { - ghoul_assert(false, "Unknown layer group ID"); - - const size_t tileSize = preferredTileSize ? preferredTileSize : 512; - return TileTextureInitData( - tileSize, - tileSize, - GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::BGRA, - TileTextureInitData::PadTiles(padTiles) - ); - } - } -} - -bool LayerManager::shouldPerformPreProcessingOnLayergroup(layergroupid::GroupID id) { - // Only preprocess height layers by default - switch (id) { - case layergroupid::GroupID::HeightLayers: return true; - default: return false; - } -} - -void LayerManager::onChange(std::function callback) { - for (std::shared_ptr& layerGroup : _layerGroups) { - layerGroup->onChange(callback); - } -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/layershadermanager.cpp b/modules/globebrowsing/rendering/layershadermanager.cpp deleted file mode 100644 index 124c45c12e..0000000000 --- a/modules/globebrowsing/rendering/layershadermanager.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace openspace::globebrowsing { - -bool -LayerShaderManager::LayerShaderPreprocessingData::LayerGroupPreprocessingData::operator==( - const LayerGroupPreprocessingData& other) const -{ - return layerType == other.layerType && - blendMode == other.blendMode && - layerAdjustmentType == other.layerAdjustmentType && - lastLayerIdx == other.lastLayerIdx && - layerBlendingEnabled == other.layerBlendingEnabled; -} - -bool LayerShaderManager::LayerShaderPreprocessingData::operator==( - const LayerShaderPreprocessingData& other) const -{ - if (layeredTextureInfo.size() != other.layeredTextureInfo.size() || - keyValuePairs.size() != other.keyValuePairs.size()) { - return false; - } - else { - bool equal = true; - for (size_t i = 0; i < layeredTextureInfo.size(); i++) { - equal &= (layeredTextureInfo[i] == other.layeredTextureInfo[i]); - } - for (size_t i = 0; i < keyValuePairs.size(); i++) { - equal &= (keyValuePairs[i] == other.keyValuePairs[i]); - } - return equal; - } -} - -LayerShaderManager::LayerShaderPreprocessingData -LayerShaderManager::LayerShaderPreprocessingData::get(const RenderableGlobe& globe) -{ - LayerShaderManager::LayerShaderPreprocessingData preprocessingData; - - std::shared_ptr layerManager = globe.chunkedLodGlobe()->layerManager(); - for (size_t i = 0; i < layergroupid::NUM_LAYER_GROUPS; i++) { - LayerShaderManager::LayerShaderPreprocessingData::LayerGroupPreprocessingData - layeredTextureInfo; - - const LayerGroup& layerGroup = layerManager->layerGroup(i); - const std::vector>& layers = layerGroup.activeLayers(); - - // This check was implicit before; not sure if it will fire or will be handled - // elsewhere - //ghoul_assert( - // !layerGroup.activeLayers().empty(), - // "If activeLayers is empty the following line will lead to an overflow" - //); - layeredTextureInfo.lastLayerIdx = static_cast( - layerGroup.activeLayers().size() - 1 - ); - layeredTextureInfo.layerBlendingEnabled = layerGroup.layerBlendingEnabled(); - - for (const std::shared_ptr& layer : layers) { - layeredTextureInfo.layerType.push_back(layer->type()); - layeredTextureInfo.blendMode.push_back(layer->blendMode()); - layeredTextureInfo.layerAdjustmentType.push_back( - layer->layerAdjustment().type() - ); - } - - preprocessingData.layeredTextureInfo[i] = layeredTextureInfo; - } - - const RenderableGlobe::GeneralProperties& generalProps = globe.generalProperties(); - const RenderableGlobe::DebugProperties& debugProps = globe.debugProperties(); - std::vector>& pairs = - preprocessingData.keyValuePairs; - - pairs.emplace_back("useAccurateNormals", - std::to_string(generalProps.useAccurateNormals) - ); - pairs.emplace_back("useAtmosphere", std::to_string(generalProps.atmosphereEnabled)); - pairs.emplace_back("performShading", std::to_string(generalProps.performShading)); - pairs.emplace_back( - "useEclipseShadows", - std::to_string(generalProps.eclipseShadowsEnabled) - ); - pairs.emplace_back( - "useEclipseHardShadows", - std::to_string(generalProps.eclipseHardShadows) - ); - 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::DefaultHeight)); - - return preprocessingData; -} - -LayerShaderManager::LayerShaderManager(std::string shaderName, std::string vsPath, - std::string fsPath) - : _shaderName(std::move(shaderName)) - , _vsPath(std::move(vsPath)) - , _fsPath(std::move(fsPath)) -{} - -LayerShaderManager::~LayerShaderManager() { - if (_programObject) { - global::renderEngine.removeRenderProgram(_programObject.get()); - _programObject = nullptr; - } -} - -ghoul::opengl::ProgramObject* LayerShaderManager::programObject() const { - ghoul_assert(_programObject, "Program does not exist. Needs to be compiled!"); - - return _programObject.get(); -} - -void LayerShaderManager::recompileShaderProgram( - LayerShaderPreprocessingData preprocessingData) -{ - _preprocessingData = std::move(preprocessingData); - ghoul::Dictionary shaderDictionary; - - // Different layer types can be height layers or color layers for example. - // These are used differently within the shaders. - const std::array< - LayerShaderPreprocessingData::LayerGroupPreprocessingData, - layergroupid::NUM_LAYER_GROUPS - >& textureTypes = _preprocessingData.layeredTextureInfo; - - for (size_t i = 0; i < textureTypes.size(); i++) { - // lastLayerIndex must be at least 0 for the shader to compile, - // the layer type is inactivated by setting use to false - const std::string& groupName = layergroupid::LAYER_GROUP_IDENTIFIERS[i]; - shaderDictionary.setValue( - "lastLayerIndex" + groupName, - glm::max(textureTypes[i].lastLayerIdx, 0) - ); - shaderDictionary.setValue( - "use" + groupName, - textureTypes[i].lastLayerIdx >= 0 - ); - shaderDictionary.setValue( - "blend" + groupName, - textureTypes[i].layerBlendingEnabled - ); - - // This is to avoid errors from shader preprocessor - shaderDictionary.setValue(groupName + "0" + "LayerType", 0); - - for (int j = 0; j < textureTypes[i].lastLayerIdx + 1; ++j) { - shaderDictionary.setValue( - groupName + std::to_string(j) + "LayerType", - static_cast(textureTypes[i].layerType[j]) - ); - } - - // This is to avoid errors from shader preprocessor - shaderDictionary.setValue(groupName + "0" + "BlendMode", 0); - - for (int j = 0; j < textureTypes[i].lastLayerIdx + 1; ++j) { - shaderDictionary.setValue( - groupName + std::to_string(j) + "BlendMode", - static_cast(textureTypes[i].blendMode[j]) - ); - } - - // This is to avoid errors from shader preprocessor - std::string keyLayerAdjustmentType = groupName + "0" + "LayerAdjustmentType"; - shaderDictionary.setValue(keyLayerAdjustmentType, 0); - - for (int j = 0; j < textureTypes[i].lastLayerIdx + 1; ++j) { - shaderDictionary.setValue( - groupName + std::to_string(j) + "LayerAdjustmentType", - static_cast(textureTypes[i].layerAdjustmentType[j]) - ); - } - } - - ghoul::Dictionary layerGroupNames; - for (int i = 0; i < layergroupid::NUM_LAYER_GROUPS; ++i) { - layerGroupNames.setValue( - std::to_string(i), - layergroupid::LAYER_GROUP_IDENTIFIERS[i] - ); - } - shaderDictionary.setValue("layerGroups", layerGroupNames); - - // Other settings such as "useAtmosphere" - for (const std::pair& p : _preprocessingData.keyValuePairs) - { - shaderDictionary.setValue(p.first, p.second); - } - - // Remove old program - global::renderEngine.removeRenderProgram(_programObject.get()); - - _programObject = global::renderEngine.buildRenderProgram( - _shaderName, - absPath(_vsPath), - absPath(_fsPath), - shaderDictionary - ); - - ghoul_assert(_programObject != nullptr, "Failed to initialize programObject!"); - - using IgnoreError = ghoul::opengl::ProgramObject::ProgramObject::IgnoreError; - _programObject->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes); - _programObject->setIgnoreUniformLocationError(IgnoreError::Yes); - _updatedSinceLastCall = true; -} - -bool LayerShaderManager::updatedSinceLastCall() { - const bool updated = _updatedSinceLastCall; - _updatedSinceLastCall = false; - return updated; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/layershadermanager.h b/modules/globebrowsing/rendering/layershadermanager.h deleted file mode 100644 index 60c616f614..0000000000 --- a/modules/globebrowsing/rendering/layershadermanager.h +++ /dev/null @@ -1,103 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___LAYER_SHADER_MANAGER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___LAYER_SHADER_MANAGER___H__ - -#include -#include -#include -#include -#include -#include - -namespace ghoul::opengl { class ProgramObject; } - -namespace openspace::globebrowsing { - -class RenderableGlobe; - -/** - * This class has ownership of an updated shader program for rendering tiles. - */ -class LayerShaderManager { -public: - /** - * Data needed for shader preprocessing before compiling a layered texture shader - * program. - * - * If a LayerShaderPreprocessingData is compared with another it can - * be determined wheter or not a LayerShaderManager needs to - * recompile its shader program. For each TextureGroup there is - * information about how many layers it has and whether or not to blend the texture - * levels. - */ - struct LayerShaderPreprocessingData { - /** - * Settings per texture group that contains shader preprocessing information. - */ - struct LayerGroupPreprocessingData { - bool operator==(const LayerGroupPreprocessingData& other) const; - - int lastLayerIdx; - bool layerBlendingEnabled; - std::vector layerType; - std::vector blendMode; - std::vector layerAdjustmentType; - }; - - bool operator==(const LayerShaderPreprocessingData& other) const; - static LayerShaderPreprocessingData get(const RenderableGlobe&); - - std::array - layeredTextureInfo; - std::vector> keyValuePairs; - }; - - LayerShaderManager(std::string shaderName, std::string vsPath, std::string fsPath); - ~LayerShaderManager(); - - /** - * Returns a pointer to a ProgramObject for rendering tiles. - */ - ghoul::opengl::ProgramObject* programObject() const; - - bool updatedSinceLastCall(); - - void recompileShaderProgram(LayerShaderPreprocessingData preprocessingData); - -private: - std::unique_ptr _programObject; - LayerShaderPreprocessingData _preprocessingData; - - const std::string _shaderName; - const std::string _vsPath; - const std::string _fsPath; - - bool _updatedSinceLastCall = false; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___LAYER_SHADER_MANAGER___H__ diff --git a/modules/globebrowsing/shaders/blending.hglsl b/modules/globebrowsing/shaders/blending.hglsl index 23c00f99cc..338a74ede3 100644 --- a/modules/globebrowsing/shaders/blending.hglsl +++ b/modules/globebrowsing/shaders/blending.hglsl @@ -27,10 +27,10 @@ vec4 blendNormal(vec4 oldColor, vec4 newColor) { vec4 toReturn; + toReturn.a = mix(oldColor.a, 1.0, newColor.a); toReturn.rgb = (newColor.rgb * newColor.a + oldColor.rgb * oldColor.a * (1 - newColor.a)) / - (newColor.a + oldColor.a * (1 - newColor.a)); - toReturn.a = newColor.a + oldColor.a * (1 - newColor.a); + toReturn.a; return toReturn; } @@ -46,28 +46,6 @@ vec4 blendSubtract(vec4 oldColor, vec4 newColor) { return oldColor - newColor; } -/* -vec3 rgb2hsv(vec3 c) -{ - vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - //vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - //vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy); - vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx); - - float d = q.x - min(q.w, q.y); - float e = 1.0e-10; - return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); -} - -vec3 hsv2rgb(vec3 c) -{ - vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); - vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); - return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} -*/ - vec3 hsl2rgb(in vec3 c) { vec3 rgb = clamp(abs(mod(c.x * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0); @@ -78,30 +56,29 @@ vec3 HueShift(in vec3 color, in float shift) { vec3 P = vec3(0.55735) * dot(vec3(0.55735), color); vec3 U = color - P; vec3 V = cross(vec3(0.55735), U); - vec3 c = U*cos(shift*6.2832) + V*sin(shift*6.2832) + P; + vec3 c = U * cos(shift*6.2832) + V * sin(shift*6.2832) + P; return c; } vec3 rgb2hsl(in vec3 c) { - float h = 0.0; - float s = 0.0; - float l = 0.0; float r = c.r; float g = c.g; float b = c.b; float cMin = min(r, min(g, b)); float cMax = max(r, max(g, b)); - l = (cMax + cMin) / 2.0; if (cMax > cMin) { + float l = (cMax + cMin) / 2.0; + float cDelta = cMax - cMin; //s = l < .05 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) ); Original - s = (l < 0.0) ? cDelta / (cMax + cMin) : cDelta / (2.0 - (cMax + cMin)); + float s = (l < 0.0) ? cDelta / (cMax + cMin) : cDelta / (2.0 - (cMax + cMin)); - if ( r == cMax ) { + float h = 0.0; + if (r == cMax) { h = (g - b) / cDelta; - } else if ( g == cMax ) { + } else if (g == cMax) { h = 2.0 + (b - r) / cDelta; } else { h = 4.0 + (r - g) / cDelta; @@ -111,14 +88,16 @@ vec3 rgb2hsl(in vec3 c) { h += 6.0; } h = h / 6.0; + + return vec3(h, s, l); + } + else { + return vec3(0.0); } - return vec3(h, s, l); } vec3 rgb2hsv(vec3 c) { vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); - //vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); - //vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); vec4 p = (c.g < c.b) ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy); vec4 q = (c.r < p.x) ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx); diff --git a/modules/globebrowsing/shaders/ellipsoid.hglsl b/modules/globebrowsing/shaders/ellipsoid.hglsl deleted file mode 100644 index c56f3d2816..0000000000 --- a/modules/globebrowsing/shaders/ellipsoid.hglsl +++ /dev/null @@ -1,102 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef ELLIPSOID_HGLSL -#define ELLIPSOID_HGLSL - -struct PositionNormalPair { - vec3 position; - vec3 normal; -}; - -struct Intersection { - bool intersects; - float nearParameter; // Along ray - float farParameter; // Along ray -}; - -vec3 geodeticSurfaceNormal(float latitude, float longitude) { - float cosLat = cos(latitude); - return vec3( - cosLat * cos(longitude), - cosLat * sin(longitude), - sin(latitude) - ); -} - -PositionNormalPair geodetic3ToCartesian(float latitude, float longitude, float height, - vec3 radiiSquared) -{ - vec3 normal = geodeticSurfaceNormal(latitude, longitude); - vec3 k = radiiSquared * normal; - float gamma = sqrt(dot(k, normal)); - vec3 rSurface = k / gamma; - PositionNormalPair toReturn; - toReturn.position = rSurface + height * normal; - toReturn.normal = normal; - return toReturn; -} - -PositionNormalPair geodetic2ToCartesian(float latitude, float longitude, - vec3 radiiSquared) -{ - // Position on surface : height = 0 - return geodetic3ToCartesian(latitude, longitude, 0, radiiSquared); -} - -vec3 latLonToCartesian(float latitude, float longitude, float radius) { - return radius * vec3( - cos(latitude) * cos(longitude), - cos(latitude) * sin(longitude), - sin(latitude) - ); -} - -// -// Assumes ellipsoid is at (0, 0, 0) -// -Intersection rayIntersectEllipsoid(vec3 rayOrigin, vec3 rayOriginSquared, - vec3 rayDirection, vec3 oneOverEllipsoidRadiiSquared) -{ - float a = dot(rayDirection * rayDirection, oneOverEllipsoidRadiiSquared); - float b = 2.0 * dot(rayOrigin * rayDirection, oneOverEllipsoidRadiiSquared); - float c = dot(rayOriginSquared, oneOverEllipsoidRadiiSquared) - 1.0; - float discriminant = b * b - 4.0 * a * c; - - if (discriminant < 0.0) { - return Intersection(false, 0.0, 0.0); - } - else if (discriminant == 0.0) { - float time = -0.5 * b / a; - return Intersection(true, time, time); - } - - float t = -0.5 * (b + (b > 0.0 ? 1.0 : -1.0) * sqrt(discriminant)); - float root1 = t / a; - float root2 = c / t; - - return Intersection(true, min(root1, root2), max(root1, root2)); -} - -#endif // ELLIPSOID_HGLSL diff --git a/modules/globebrowsing/shaders/globalchunkedlodpatch_fs.glsl b/modules/globebrowsing/shaders/globalchunkedlodpatch_fs.glsl deleted file mode 100644 index 1e89ba024f..0000000000 --- a/modules/globebrowsing/shaders/globalchunkedlodpatch_fs.glsl +++ /dev/null @@ -1,37 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include <${MODULE_GLOBEBROWSING}/shaders/tilefragment.hglsl> -#include "fragment.glsl" - -Fragment getFragment() { - Fragment frag; - frag = getTileFragment(); - -#if SHOW_CHUNK_EDGES - frag.color += patchBorderOverlay(fs_uv, vec3(0.0, 1.0, 0.0), 0.02); -#endif // SHOW_CHUNK_EDGES - - return frag; -} diff --git a/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl b/modules/globebrowsing/shaders/globalrenderer_vs.glsl similarity index 70% rename from modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl rename to modules/globebrowsing/shaders/globalrenderer_vs.glsl index 71b7656d76..24a1f6cbcb 100644 --- a/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl +++ b/modules/globebrowsing/shaders/globalrenderer_vs.glsl @@ -25,7 +25,6 @@ #version __CONTEXT__ #include "PowerScaling/powerScaling_vs.hglsl" -#include <${MODULE_GLOBEBROWSING}/shaders/ellipsoid.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/texturetilemapping.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/tileheight.hglsl> @@ -33,21 +32,21 @@ layout(location = 1) in vec2 in_uv; -out vec2 fs_uv; out vec4 fs_position; out vec3 fs_normal; +out vec2 fs_uv; out vec3 ellipsoidNormalCameraSpace; -out LevelWeights levelWeights; +out vec3 levelWeights; out vec3 positionCameraSpace; #if USE_ACCURATE_NORMALS -out vec3 ellipsoidTangentThetaCameraSpace; -out vec3 ellipsoidTangentPhiCameraSpace; -#endif //USE_ACCURATE_NORMALS + out vec3 ellipsoidTangentThetaCameraSpace; + out vec3 ellipsoidTangentPhiCameraSpace; +#endif // USE_ACCURATE_NORMALS #if USE_ECLIPSE_SHADOWS -out vec3 positionWorldSpace; -uniform dmat4 modelTransform; + out vec3 positionWorldSpace; + uniform dmat4 modelTransform; #endif uniform mat4 modelViewProjectionTransform; @@ -63,49 +62,55 @@ uniform float distanceScaleFactor; uniform int chunkLevel; +struct PositionNormalPair { + vec3 position; + vec3 normal; +}; + PositionNormalPair globalInterpolation(vec2 uv) { - vec2 lonLatInput; - lonLatInput.y = minLatLon.y + lonLatScalingFactor.y * uv.y; // Lat - lonLatInput.x = minLatLon.x + lonLatScalingFactor.x * uv.x; // Lon - PositionNormalPair positionPairModelSpace = geodetic2ToCartesian( - lonLatInput.y, - lonLatInput.x, - radiiSquared + vec2 lonlat = lonLatScalingFactor * uv + minLatLon; + + // geodetic surface normal + float cosLat = cos(lonlat.y); + vec3 normal = vec3(cosLat * cos(lonlat.x), cosLat * sin(lonlat.x), sin(lonlat.y)); + vec3 k = radiiSquared * normal; + float gamma = sqrt(dot(k, normal)); + + PositionNormalPair result; + result.position = k / gamma; + result.normal = normal; + return result; +} + +vec3 getLevelWeights(float distToVertexOnEllipsoid) { + float projectedScaleFactor = distanceScaleFactor / distToVertexOnEllipsoid; + float desiredLevel = log2(projectedScaleFactor); + float levelInterp = chunkLevel - desiredLevel; + + return vec3( + clamp(1.0 - levelInterp, 0.0, 1.0), + clamp(levelInterp, 0.0, 1.0) - clamp(levelInterp - 1.0, 0.0, 1.0), + clamp(levelInterp - 1.0, 0.0, 1.0) ); - return positionPairModelSpace; } void main() { PositionNormalPair pair = globalInterpolation(in_uv); - float distToVertexOnEllipsoid = - length(pair.position + pair.normal * chunkMinHeight - cameraPosition); - - float levelInterpolationParameter = - getLevelInterpolationParameter( - chunkLevel, - distanceScaleFactor, - distToVertexOnEllipsoid); + float distToVertexOnEllipsoid = length((pair.normal * chunkMinHeight + pair.position) - cameraPosition); // use level weight for height sampling, and output to fragment shader - levelWeights = getLevelWeights(levelInterpolationParameter); + levelWeights = getLevelWeights(distToVertexOnEllipsoid); - // Get the height value - float height = getTileHeight(in_uv, levelWeights); - - // Apply skirts - height -= getTileVertexSkirtLength(); + // Get the height value and apply skirts + float height = getTileHeight(in_uv, levelWeights) - getTileVertexSkirtLength(); #if USE_ACCURATE_NORMALS // Calculate tangents // tileDelta is a step length (epsilon). Should be small enough for accuracy but not // Too small for precision. 1 / 512 is good. const float tileDelta = 1.0 / 512.0; - PositionNormalPair pair10 = globalInterpolation( - in_uv + vec2(1.0, 0.0) * tileDelta - ); - PositionNormalPair pair01 = globalInterpolation( - in_uv + vec2(0.0, 1.0) * tileDelta - ); + PositionNormalPair pair10 = globalInterpolation(vec2(1.0, 0.0) * tileDelta + in_uv); + PositionNormalPair pair01 = globalInterpolation(vec2(0.0, 1.0) * tileDelta + in_uv); vec3 ellipsoidTangentTheta = normalize(pair10.position - pair.position); vec3 ellipsoidTangentPhi = normalize(pair01.position - pair.position); ellipsoidTangentThetaCameraSpace = mat3(modelViewTransform) * ellipsoidTangentTheta; @@ -113,9 +118,8 @@ void main() { #endif // USE_ACCURATE_NORMALS // Add the height in the direction of the normal - pair.position += pair.normal * height; - vec4 positionClippingSpace = - modelViewProjectionTransform * vec4(pair.position, 1.0); + pair.position = pair.normal * height + pair.position; + vec4 positionClippingSpace = modelViewProjectionTransform * vec4(pair.position, 1.0); // Write output fs_uv = in_uv; diff --git a/modules/globebrowsing/shaders/globeshading.hglsl b/modules/globebrowsing/shaders/globeshading.hglsl deleted file mode 100644 index 7273869797..0000000000 --- a/modules/globebrowsing/shaders/globeshading.hglsl +++ /dev/null @@ -1,56 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef GLOBESHADING_HGLSL -#define GLOBESHADING_HGLSL - -float orenNayarDiffuse(vec3 lightDirection, vec3 viewDirection, vec3 surfaceNormal, - float roughness) -{ - // calculate intermediary values - float NdotL = dot(surfaceNormal, lightDirection); - float NdotV = dot(surfaceNormal, viewDirection); - - float angleVN = acos(NdotV); - float angleLN = acos(NdotL); - - float alpha = max(angleVN, angleLN); - float beta = min(angleVN, angleLN); - float gamma = dot( - viewDirection - surfaceNormal * dot(viewDirection, surfaceNormal), - lightDirection - surfaceNormal * dot(lightDirection, surfaceNormal) - ); - - float roughnessSquared = roughness * roughness; - - // calculate A and B - float A = 1.0 - 0.5 * (roughnessSquared / (roughnessSquared + 0.57)); - float B = 0.45 * (roughnessSquared / (roughnessSquared + 0.09)); - float C = sin(alpha) * tan(beta); - - // put it all together - return max(0.0, NdotL) * (A + B * max(0.0, gamma) * C); -} - -#endif // GLOBESHADING_HGLSL diff --git a/modules/globebrowsing/shaders/localchunkedlodpatch_fs.glsl b/modules/globebrowsing/shaders/localchunkedlodpatch_fs.glsl deleted file mode 100644 index 4f9eec2330..0000000000 --- a/modules/globebrowsing/shaders/localchunkedlodpatch_fs.glsl +++ /dev/null @@ -1,37 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include <${MODULE_GLOBEBROWSING}/shaders/tilefragment.hglsl> -#include "fragment.glsl" - -Fragment getFragment() { - Fragment frag; - frag = getTileFragment(); - -#if SHOW_CHUNK_EDGES - frag.color += patchBorderOverlay(fs_uv, vec3(1,0,0), 0.005); -#endif // SHOW_CHUNK_EDGES - - return frag; -} diff --git a/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl b/modules/globebrowsing/shaders/localrenderer_vs.glsl similarity index 80% rename from modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl rename to modules/globebrowsing/shaders/localrenderer_vs.glsl index 188618e760..764d3411ea 100644 --- a/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl +++ b/modules/globebrowsing/shaders/localrenderer_vs.glsl @@ -25,7 +25,6 @@ #version __CONTEXT__ #include "PowerScaling/powerScaling_vs.hglsl" -#include <${MODULE_GLOBEBROWSING}/shaders/ellipsoid.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/texturetilemapping.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/tileheight.hglsl> @@ -37,12 +36,12 @@ out vec2 fs_uv; out vec4 fs_position; out vec3 fs_normal; out vec3 ellipsoidNormalCameraSpace; -out LevelWeights levelWeights; +out vec3 levelWeights; out vec3 positionCameraSpace; #if USE_ACCURATE_NORMALS -out vec3 ellipsoidTangentThetaCameraSpace; -out vec3 ellipsoidTangentPhiCameraSpace; + out vec3 ellipsoidTangentThetaCameraSpace; + out vec3 ellipsoidTangentPhiCameraSpace; #endif // USE_ACCURATE_NORMALS #if USE_ECLIPSE_SHADOWS @@ -64,10 +63,21 @@ uniform float distanceScaleFactor; uniform int chunkLevel; vec3 bilinearInterpolation(vec2 uv) { - vec3 p0 = (1 - uv.x) * p00 + uv.x * p10; - vec3 p1 = (1 - uv.x) * p01 + uv.x * p11; - vec3 p = (1 - uv.y) * p0 + uv.y * p1; - return p; + vec3 p0 = mix(p00, p10, uv.x); + vec3 p1 = mix(p01, p11, uv.x); + return mix(p0, p1, uv.y); +} + +vec3 getLevelWeights(float distToVertexOnEllipsoid) { + float projectedScaleFactor = distanceScaleFactor / distToVertexOnEllipsoid; + float desiredLevel = log2(projectedScaleFactor); + float levelInterp = chunkLevel - desiredLevel; + + return vec3( + clamp(1.0 - levelInterp, 0.0, 1.0), + clamp(levelInterp, 0.0, 1.0) - clamp(levelInterp - 1.0, 0.0, 1.0), + clamp(levelInterp - 1.0, 0.0, 1.0) + ); } void main() { @@ -76,31 +86,24 @@ void main() { // Calculate desired level based on distance to the vertex on the ellipsoid // Before any heightmapping is done - float distToVertexOnEllipsoid = - length(p + patchNormalCameraSpace * chunkMinHeight); - float levelInterpolationParameter = - getLevelInterpolationParameter( - chunkLevel, - distanceScaleFactor, - distToVertexOnEllipsoid); - + float distToVertexOnEllipsoid = length(p + patchNormalCameraSpace * chunkMinHeight); + // use level weight for height sampling, and output to fragment shader - levelWeights = getLevelWeights(levelInterpolationParameter); + levelWeights = getLevelWeights(distToVertexOnEllipsoid); // Get the height value and apply skirts - float height = - getTileHeightScaled(in_uv, levelWeights) - getTileVertexSkirtLength(); + float height = getTileHeightScaled(in_uv, levelWeights) - getTileVertexSkirtLength(); // Translate the point along normal p += patchNormalCameraSpace * height; vec4 positionClippingSpace = projectionTransform * vec4(p, 1); - - #if USE_ACCURATE_NORMALS + +#if USE_ACCURATE_NORMALS // Calculate tangents ellipsoidTangentThetaCameraSpace = normalize(p10 - p00); ellipsoidTangentPhiCameraSpace = normalize(p01 - p00); - #endif // USE_ACCURATE_NORMALS +#endif // USE_ACCURATE_NORMALS // Write output fs_uv = in_uv; @@ -110,7 +113,7 @@ void main() { fs_normal = patchNormalModelSpace; positionCameraSpace = p; - #if USE_ECLIPSE_SHADOWS +#if USE_ECLIPSE_SHADOWS positionWorldSpace = vec3(inverseViewTransform * dvec4(p, 1.0)); - #endif +#endif } diff --git a/modules/globebrowsing/shaders/pointglobe_fs.glsl b/modules/globebrowsing/shaders/pointglobe_fs.glsl deleted file mode 100644 index 00ea3c9f97..0000000000 --- a/modules/globebrowsing/shaders/pointglobe_fs.glsl +++ /dev/null @@ -1,44 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include "fragment.glsl" - -in vec4 vs_positionClipSpace; -in vec2 vs_positionModelSpace; - -//uniform vec3 directionToSunViewSpace; -uniform vec3 positionCameraSpace; -//uniform float lightOverflow; - - -Fragment getFragment() { - float alpha = - 1.0 - sqrt(pow(vs_positionModelSpace.x, 2) + pow(vs_positionModelSpace.y, 2)); - alpha = pow(alpha, 3); - Fragment frag; - frag.color = vec4(1.0, 1.0, 1.0, alpha); - frag.depth = vs_positionClipSpace.w; - frag.blend = BLEND_MODE_ADDITIVE; - return frag; -} diff --git a/modules/globebrowsing/shaders/pointglobe_vs.glsl b/modules/globebrowsing/shaders/pointglobe_vs.glsl deleted file mode 100644 index 13ae2a6ac3..0000000000 --- a/modules/globebrowsing/shaders/pointglobe_vs.glsl +++ /dev/null @@ -1,54 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#version __CONTEXT__ - -#include "PowerScaling/powerScaling_vs.hglsl" - -layout(location = 0) in vec2 in_position; - -out vec4 vs_positionClipSpace; -out vec4 vs_positionCameraSpace; -out vec2 vs_positionModelSpace; - -uniform float lightIntensityClamped; -uniform mat4 modelViewTransform; -uniform mat4 projectionTransform; -uniform mat4 directionToSunViewSpace; - -void main() { - vs_positionModelSpace = in_position; - - float totalIntensity = lightIntensityClamped; - - vec4 positionCameraSpace = modelViewTransform * vec4( - in_position * totalIntensity, - 0.0, - 1.0 - ); - - vec4 positionClipSpace = projectionTransform * positionCameraSpace; - vs_positionClipSpace = z_normalization(positionClipSpace); - gl_Position = z_normalization(positionClipSpace); -} diff --git a/modules/globebrowsing/shaders/tilefragment.hglsl b/modules/globebrowsing/shaders/renderer_fs.glsl similarity index 69% rename from modules/globebrowsing/shaders/tilefragment.hglsl rename to modules/globebrowsing/shaders/renderer_fs.glsl index a0b1e1bc59..912399ab46 100644 --- a/modules/globebrowsing/shaders/tilefragment.hglsl +++ b/modules/globebrowsing/shaders/renderer_fs.glsl @@ -22,14 +22,12 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef TILE_FRAG_COLOR_HGLSL -#define TILE_FRAG_COLOR_HGLSL +#include "fragment.glsl" #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/texturetilemapping.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/tileheight.hglsl> #include "PowerScaling/powerScaling_fs.hglsl" -#include "fragment.glsl" // Below are all the tiles that are used for contributing the actual fragment color @@ -47,18 +45,13 @@ uniform Layer Overlays[NUMLAYERS_OVERLAY]; #if USE_WATERMASK uniform Layer WaterMasks[NUMLAYERS_WATERMASK]; -float waterReflectance = 0.0; #endif // USE_WATERMASK #if SHOW_HEIGHT_RESOLUTION uniform vec2 vertexResolution; #endif -#if USE_ATMOSPHERE -// TODO atmosphere uniforms here -#endif // USE_ATMOSPHERE - -#if USE_NIGHTTEXTURE || USE_WATERMASK || USE_ATMOSPHERE || PERFORM_SHADING +#if USE_NIGHTTEXTURE || USE_WATERMASK || PERFORM_SHADING uniform vec3 lightDirectionCameraSpace; #endif @@ -67,7 +60,6 @@ uniform float orenNayarRoughness; #endif #if USE_ECLIPSE_SHADOWS -in vec3 positionWorldSpace; /******************************************************************************* ***** ALL CALCULATIONS FOR ECLIPSE ARE IN METERS AND IN WORLD SPACE SYSTEM **** @@ -77,60 +69,61 @@ in vec3 positionWorldSpace; const uint numberOfShadows = 1; struct ShadowRenderingStruct { - double xu, xp; - double rs, rc; - dvec3 sourceCasterVec; - dvec3 casterPositionVec; - bool isShadowing; + double xu, xp; + double rs, rc; + dvec3 sourceCasterVec; + dvec3 casterPositionVec; + bool isShadowing; }; // Eclipse shadow data -// JCC: Remove and use dictionary to +// JCC: Remove and use dictionary to // decides the number of shadows uniform ShadowRenderingStruct shadowDataArray[numberOfShadows]; uniform int shadows; uniform bool hardShadows; -vec4 butterworthFunc(const float d, const float r, const float n) { - return vec4(vec3(sqrt(r/(r + pow(d, 2*n)))), 1.0); -} - -vec4 calcShadow(const ShadowRenderingStruct shadowInfoArray[numberOfShadows], const dvec3 position, - const bool ground) { +vec4 calcShadow(const ShadowRenderingStruct shadowInfoArray[numberOfShadows], + const dvec3 position, const bool ground) +{ if (shadowInfoArray[0].isShadowing) { dvec3 pc = shadowInfoArray[0].casterPositionVec - position; dvec3 sc_norm = shadowInfoArray[0].sourceCasterVec; dvec3 pc_proj = dot(pc, sc_norm) * sc_norm; dvec3 d = pc - pc_proj; - + float length_d = float(length(d)); double length_pc_proj = length(pc_proj); - + float r_p_pi = float(shadowInfoArray[0].rc * (length_pc_proj + shadowInfoArray[0].xp) / shadowInfoArray[0].xp); float r_u_pi = float(shadowInfoArray[0].rc * (shadowInfoArray[0].xu - length_pc_proj) / shadowInfoArray[0].xu); - - if ( length_d < r_u_pi ) { // umbra + + if (length_d < r_u_pi) { // umbra if (ground) { -#if USE_ECLIPSE_HARD_SHADOWS +#if USE_ECLIPSE_HARD_SHADOWS return vec4(0.2, 0.2, 0.2, 1.0); +#else + // butterworthFunc + return vec4(vec3(sqrt(r_u_pi / (r_u_pi + pow(length_d, 8.0)))), 1.0); #endif - return butterworthFunc(length_d, r_u_pi, 4.0); } else { -#if USE_ECLIPSE_HARD_SHADOWS +#if USE_ECLIPSE_HARD_SHADOWS return vec4(0.5, 0.5, 0.5, 1.0); -#endif - return vec4(vec3(length_d/r_p_pi), 1.0); +#else + return vec4(vec3(length_d / r_p_pi), 1.0); +#endif } } - else if ( length_d < r_p_pi ) {// penumbra -#if USE_ECLIPSE_HARD_SHADOWS - return vec4(0.5, 0.5, 0.5, 1.0); -#endif - return vec4(vec3(length_d/r_p_pi), 1.0); + else if (length_d < r_p_pi) {// penumbra +#if USE_ECLIPSE_HARD_SHADOWS + return vec4(0.5, 0.5, 0.5, 1.0); +#else + return vec4(vec3(length_d / r_p_pi), 1.0); +#endif } } - + return vec4(1.0); } #endif @@ -139,28 +132,27 @@ in vec4 fs_position; in vec3 fs_normal; in vec2 fs_uv; in vec3 ellipsoidNormalCameraSpace; +in vec3 levelWeights; in vec3 positionCameraSpace; #if USE_ACCURATE_NORMALS -in vec3 ellipsoidTangentThetaCameraSpace; -in vec3 ellipsoidTangentPhiCameraSpace; + in vec3 ellipsoidTangentThetaCameraSpace; + in vec3 ellipsoidTangentPhiCameraSpace; -// Once deferred light calculations are done in view space this can be removed -// so that we only need one normal; in view space. -uniform mat4 invViewModelTransform; + // Once deferred light calculations are done in view space this can be removed + // so that we only need one normal; in view space. + uniform mat4 invViewModelTransform; #endif // USE_ACCURATE_NORMALS -// levelInterpolationParameter is used to interpolate between a tile and its parent tiles -// The value increases with the distance from the vertex (or fragment) to the camera -in LevelWeights levelWeights; +#if USE_ECLIPSE_SHADOWS +in vec3 positionWorldSpace; +#endif // USE_ECLIPSE_SHADOWS -/** - * This method defines the fragment color pipeline which is used in both - * the local and global chunk rendering. - * - */ -Fragment getTileFragment() { + + +Fragment getFragment() { Fragment frag; + frag.color = vec4(0.3, 0.3, 0.3, 1.0); vec3 normal = normalize(ellipsoidNormalCameraSpace); @@ -179,15 +171,11 @@ Fragment getTileFragment() { #endif /// USE_ACCURATE_NORMALS #if USE_COLORTEXTURE - frag.color = calculateColor( - frag.color, - fs_uv, - levelWeights, - ColorLayers - ); + frag.color = calculateColor(frag.color, fs_uv, levelWeights, ColorLayers); #endif // USE_COLORTEXTURE #if USE_WATERMASK + float waterReflectance = 0.0; frag.color = calculateWater( frag.color, fs_uv, @@ -223,45 +211,16 @@ Fragment getTileFragment() { ); #endif // PERFORM_SHADING -#if USE_ATMOSPHERE - // Temporary until the real atmosphere code is here - //frag.color = frag.color + vec4(0.5,0.5,1,0) * 0.3; // Just to see something for now - const vec3 n = normalize(ellipsoidNormalCameraSpace); - const vec3 l = lightDirectionCameraSpace; - const vec3 c = normalize(positionCameraSpace); - float cosFactor = 1 - clamp(dot(-n * 0.9, c), 0, 1); - cosFactor *= 1.1; - cosFactor -= 0.1; - cosFactor = clamp(cosFactor, 0.0, 1.0); - cosFactor = cosFactor + pow(cosFactor, 5); - - const float shadowLight = 0.15; - float cosFactorLight = pow(max(dot(-l, n), -shadowLight) + shadowLight, 0.8); - //float cosFactorScatter = pow(max(dot(l, n) + shadowLight, 0), 5); - //float cosFactorLight = max(dot(-lightDirectionCameraSpace, normalize(ellipsoidNormalCameraSpace)), 0); - //vec3 r = reflect(l, n); - //float scatteredLight = pow(clamp(dot(-r,c), 0, 1), 20); - const vec3 atmosphereColor = vec3(0.5, 0.5, 1.0) * 2.0; - frag.color += vec4(atmosphereColor,0) * cosFactor * cosFactorLight * 0.5; -#endif // USE_ATMOSPHERE - #if USE_ECLIPSE_SHADOWS frag.color *= calcShadow(shadowDataArray, dvec3(positionWorldSpace), true); #endif #if USE_OVERLAY - frag.color = calculateOverlay( - frag.color, - fs_uv, - levelWeights, - Overlays - ); + frag.color = calculateOverlay(frag.color, fs_uv, levelWeights, Overlays); #endif // USE_OVERLAY #if SHOW_HEIGHT_INTENSITIES - frag.color.r *= 0.1; - frag.color.g *= 0.1; - frag.color.b *= 0.1; + frag.color.rgb *= vec3(0.1); float untransformedHeight = getUntransformedTileVertexHeight(fs_uv, levelWeights); float contourLine = fract(10.0 * untransformedHeight) > 0.98 ? 1.0 : 0.0; @@ -270,7 +229,7 @@ Fragment getTileFragment() { #endif #if SHOW_HEIGHT_RESOLUTION - frag.color += 0.0001*calculateDebugColor(fs_uv, fs_position, vertexResolution); + frag.color += 0.0001 * calculateDebugColor(fs_uv, fs_position, vertexResolution); #if USE_HEIGHTMAP frag.color.r = min(frag.color.r, 0.8); frag.color.r += tileResolution(fs_uv, HeightLayers[0].pile.chunkTile0) > 0.9 ? 1 : 0; @@ -292,7 +251,18 @@ Fragment getTileFragment() { frag.gPosition = vec4(positionCameraSpace, 1.0); // in Camera Rig Space frag.depth = fs_position.w; + +#if SHOW_CHUNK_EDGES + const float BorderSize = 0.005; + const vec3 BorderColor = vec3(1.0, 0.0, 0.0); + + vec2 uvOffset = fs_uv - vec2(0.5); + float thres = 0.5 - BorderSize * 0.5; + bool isBorder = abs(uvOffset.x) > thres || abs(uvOffset.y) > thres; + if (isBorder) { + frag.color.rgb += BorderColor; + } +#endif // SHOW_CHUNK_EDGES + return frag; } - -#endif ///TILE_FRAG_COLOR_HGLSL diff --git a/modules/globebrowsing/shaders/texturetilemapping.hglsl b/modules/globebrowsing/shaders/texturetilemapping.hglsl index 516a02a09c..a83e129446 100644 --- a/modules/globebrowsing/shaders/texturetilemapping.hglsl +++ b/modules/globebrowsing/shaders/texturetilemapping.hglsl @@ -27,7 +27,6 @@ #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/blending.hglsl> -#include <${MODULE_GLOBEBROWSING}/shaders/globeshading.hglsl> // First layer type from LayerShaderManager is height map #define NUMLAYERS_HEIGHTMAP #{lastLayerIndexHeightLayers} + 1 @@ -58,7 +57,6 @@ #define CHUNK_DEFAULT_HEIGHT #{defaultHeight} // Other key value pairs used for settings -#define USE_ATMOSPHERE #{useAtmosphere} #define USE_ACCURATE_NORMALS #{useAccurateNormals} #define PERFORM_SHADING #{performShading} #define USE_ECLIPSE_SHADOWS #{useEclipseShadows} @@ -67,58 +65,88 @@ #define SHOW_HEIGHT_RESOLUTION #{showHeightResolution} #define SHOW_HEIGHT_INTENSITIES #{showHeightIntensities} -float performLayerSettingsRGB(float currentValue, LayerSettings settings) { - float newValue = currentValue; +const vec3 DefaultLevelWeights = vec3(1.0, 0.0, 0.0); - newValue = sign(newValue) * pow(abs(newValue), settings.gamma); - newValue = newValue * settings.multiplier; - newValue = newValue + settings.offset; +float orenNayarDiffuse(vec3 lightDirection, vec3 viewDirection, vec3 surfaceNormal, + float roughness) +{ + // calculate intermediary values + float NdotL = dot(surfaceNormal, lightDirection); + float NdotV = dot(surfaceNormal, viewDirection); - return newValue; -} - -vec4 performLayerSettingsRGB(vec4 currentValue, LayerSettings settings) { - vec4 newValue = vec4( - performLayerSettingsRGB(currentValue.r, settings), - performLayerSettingsRGB(currentValue.g, settings), - performLayerSettingsRGB(currentValue.b, settings), - currentValue.a + float angleVN = acos(NdotV); + float angleLN = acos(NdotL); + + float alpha = max(angleVN, angleLN); + float beta = min(angleVN, angleLN); + float gamma = dot( + viewDirection - surfaceNormal * dot(viewDirection, surfaceNormal), + lightDirection - surfaceNormal * dot(lightDirection, surfaceNormal) ); - - return newValue; -} - -float performLayerSettingsAlpha(float currentValue, LayerSettings settings) { - return currentValue * settings.opacity; -} - -vec4 performLayerSettingsAlpha(vec4 currentValue, LayerSettings settings) { - return vec4(currentValue.rgb, performLayerSettingsAlpha(currentValue.a, settings)); + + float roughnessSquared = roughness * roughness; + + // calculate A and B + float A = 1.0 - 0.5 * (roughnessSquared / (roughnessSquared + 0.57)); + float B = 0.45 * (roughnessSquared / (roughnessSquared + 0.09)); + float C = sin(alpha) * tan(beta); + + // put it all together + return max(0.0, NdotL) * (A + B * max(0.0, gamma) * C); } float performLayerSettings(float currentValue, LayerSettings settings) { - return performLayerSettingsAlpha( - performLayerSettingsRGB(currentValue, settings), - settings - ); + float v = sign(currentValue) * pow(abs(currentValue), settings.gamma) * + settings.multiplier + settings.offset; + return v * settings.opacity; } vec4 performLayerSettings(vec4 currentValue, LayerSettings settings) { - return performLayerSettingsAlpha( - performLayerSettingsRGB(currentValue, settings), - settings - ); + vec3 newValue = sign(currentValue.rgb) * pow(abs(currentValue.rgb), vec3(settings.gamma)) * + settings.multiplier + settings.offset; + return vec4(newValue, currentValue.a * settings.opacity); } +vec2 tileUVToTextureSamplePosition(ChunkTile chunkTile, vec2 tileUV, + PixelPadding padding) +{ + vec2 uv = chunkTile.uvTransform.uvOffset + chunkTile.uvTransform.uvScale * tileUV; + + // compensateSourceTextureSampling + ivec2 resolution = textureSize(chunkTile.textureSampler, 0); + vec2 sourceSize = vec2(resolution) + padding.sizeDifference; + vec2 currentSize = vec2(resolution); + vec2 sourceToCurrentSize = currentSize / sourceSize; + return sourceToCurrentSize * (uv - padding.startOffset / sourceSize); +} + +vec4 getTexVal(ChunkTilePile chunkTilePile, vec3 w, vec2 uv, + PixelPadding padding) +{ + vec4 v1 = texture( + chunkTilePile.chunkTile0.textureSampler, + tileUVToTextureSamplePosition(chunkTilePile.chunkTile0, uv, padding) + ); + vec4 v2 = texture( + chunkTilePile.chunkTile1.textureSampler, + tileUVToTextureSamplePosition(chunkTilePile.chunkTile1, uv, padding) + ); + vec4 v3 = texture( + chunkTilePile.chunkTile2.textureSampler, + tileUVToTextureSamplePosition(chunkTilePile.chunkTile2, uv, padding) + ); + + return w.x * v1 + w.y * v2 + w.z * v3; +} #for id, layerGroup in layerGroups #for i in 0..#{lastLayerIndex#{layerGroup}} -vec4 getSample#{layerGroup}#{i}(vec2 uv, LevelWeights levelWeights, +vec4 getSample#{layerGroup}#{i}(vec2 uv, vec3 levelWeights, Layer #{layerGroup}[#{lastLayerIndex#{layerGroup}} + 1]) { - vec4 color = vec4(0,0,0,1); - + vec4 color = vec4(0.0, 0.0, 0.0, 1.0); + // All tile layers are the same. Sample from texture #if (#{#{layerGroup}#{i}LayerType} == 0) // DefaultTileLayer color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding); @@ -203,7 +231,7 @@ vec4 performAdjustment#{layerGroup}#{i}(vec4 currentColor, #endfor #endfor -float calculateUntransformedHeight(vec2 uv, LevelWeights levelWeights, +float calculateUntransformedHeight(vec2 uv, vec3 levelWeights, Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { @@ -212,7 +240,7 @@ float calculateUntransformedHeight(vec2 uv, LevelWeights levelWeights, // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !HEIGHTMAP_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = DefaultLevelWeights; #endif // HEIGHTMAP_BLENDING_ENABLED #for i in 0..#{lastLayerIndexHeightLayers} @@ -227,17 +255,14 @@ float calculateUntransformedHeight(vec2 uv, LevelWeights levelWeights, return height; } -float calculateHeight( - vec2 uv, - LevelWeights levelWeights, - Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { - +float calculateHeight(vec2 uv, vec3 levelWeights, Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) +{ float height = 0; // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !HEIGHTMAP_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = DefaultLevelWeights; #endif // HEIGHTMAP_BLENDING_ENABLED @@ -247,7 +272,9 @@ float calculateHeight( colorSample = performAdjustmentHeightLayers#{i}(colorSample, HeightLayers[#{i}].adjustment); float untransformedHeight = colorSample.r; - float heightSample = getTransformedTexVal(HeightLayers[#{i}].depthTransform, untransformedHeight); + TileDepthTransform transform = HeightLayers[#{i}].depthTransform; + float heightSample = + transform.depthScale * untransformedHeight + transform.depthOffset; if (heightSample > -100000) { heightSample = performLayerSettings(heightSample, HeightLayers[#{i}].settings); height = heightSample; @@ -257,7 +284,7 @@ float calculateHeight( return height; } -vec4 calculateColor(vec4 currentColor, vec2 uv, LevelWeights levelWeights, +vec4 calculateColor(vec4 currentColor, vec2 uv, vec3 levelWeights, Layer ColorLayers[NUMLAYERS_COLORTEXTURE]) { vec4 color = currentColor; @@ -265,7 +292,7 @@ vec4 calculateColor(vec4 currentColor, vec2 uv, LevelWeights levelWeights, // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !COLORTEXTURE_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = DefaultLevelWeights; #endif // COLORTEXTURE_BLENDING_ENABLED #for i in 0..#{lastLayerIndexColorLayers} @@ -278,20 +305,20 @@ vec4 calculateColor(vec4 currentColor, vec2 uv, LevelWeights levelWeights, } #endfor - return color; + return color; } -float gridDots(vec2 uv, vec2 gridResolution){ +float gridDots(vec2 uv, vec2 gridResolution) { vec2 uvVertexSpace = fract((gridResolution) * uv) + 0.5; - vec2 uvDotSpace = abs(2*(uvVertexSpace-0.5)); - return 1-length(1-uvDotSpace); + vec2 uvDotSpace = abs(2.0 * (uvVertexSpace - 0.5)); + return 1.0 - length(1.0 - uvDotSpace); } vec4 calculateDebugColor(vec2 uv, vec4 fragPos, vec2 vertexResolution) { vec2 uvVertexSpace = fract(vertexResolution * uv); vec3 colorUv = vec3(0.3 * uv.x, 0.3 * uv.y, 0); - vec3 colorDistance = vec3(0, 0, min( 0.4 * log(fragPos.w) - 3.9, 1)); + vec3 colorDistance = vec3(0.0, 0.0, min(0.4 * log(fragPos.w) - 3.9, 1)); vec3 colorVertex = (1.0 - length(uvVertexSpace)) * vec3(0.5); vec3 colorSum = colorUv + colorDistance + colorVertex; return vec4(0.5 * colorSum, 1); @@ -303,12 +330,12 @@ float tileResolution(vec2 tileUV, ChunkTile chunkTile) { padding.sizeDifference = ivec2(0); vec2 heightResolution = textureSize(chunkTile.textureSampler, 0); - vec2 uv = TileUVToTextureSamplePosition(chunkTile, tileUV, padding); + vec2 uv = tileUVToTextureSamplePosition(chunkTile, tileUV, padding); return gridDots(uv, heightResolution); } -vec4 calculateNight(vec4 currentColor, vec2 uv, LevelWeights levelWeights, - Layer NightLayers[NUMLAYERS_NIGHTTEXTURE], +vec4 calculateNight(vec4 currentColor, vec2 uv, vec3 levelWeights, + Layer NightLayers[NUMLAYERS_NIGHTTEXTURE], vec3 ellipsoidNormalCameraSpace, vec3 lightDirectionCameraSpace) { @@ -318,7 +345,7 @@ vec4 calculateNight(vec4 currentColor, vec2 uv, LevelWeights levelWeights, // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !NIGHTTEXTURE_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = DefaultLevelWeights; #endif // NIGHTTEXTURE_BLENDING_ENABLED vec3 n = normalize(ellipsoidNormalCameraSpace); @@ -363,7 +390,7 @@ vec4 calculateShadedColor(vec4 currentColor, vec3 ellipsoidNormalCameraSpace, return color; } -vec4 calculateOverlay(vec4 currentColor, vec2 uv, LevelWeights levelWeights, +vec4 calculateOverlay(vec4 currentColor, vec2 uv, vec3 levelWeights, Layer Overlays[NUMLAYERS_OVERLAY]) { vec4 color = currentColor; @@ -371,7 +398,7 @@ vec4 calculateOverlay(vec4 currentColor, vec2 uv, LevelWeights levelWeights, // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !OVERLAY_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = DefaultLevelWeights; #endif // OVERLAY_BLENDING_ENABLED #for i in 0..#{lastLayerIndexOverlays} @@ -389,7 +416,7 @@ vec4 calculateOverlay(vec4 currentColor, vec2 uv, LevelWeights levelWeights, return color; } -vec4 calculateWater(vec4 currentColor, vec2 uv, LevelWeights levelWeights, +vec4 calculateWater(vec4 currentColor, vec2 uv, vec3 levelWeights, Layer WaterMasks[NUMLAYERS_WATERMASK], vec3 ellipsoidNormalCameraSpace, vec3 lightDirectionCameraSpace, vec3 positionCameraSpace, @@ -400,7 +427,7 @@ vec4 calculateWater(vec4 currentColor, vec2 uv, LevelWeights levelWeights, // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !WATERMASK_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = DefaultLevelWeights; #endif // WATERMASK_BLENDING_ENABLED #for i in 0..#{lastLayerIndexWaterMasks} @@ -408,8 +435,7 @@ vec4 calculateWater(vec4 currentColor, vec2 uv, LevelWeights levelWeights, vec4 colorSample = getSampleWaterMasks#{i}(uv, levelWeights, WaterMasks); colorSample = performAdjustmentWaterMasks#{i}(colorSample, WaterMasks[#{i}].adjustment); - colorSample = performLayerSettingsAlpha(colorSample, WaterMasks[#{i}].settings); - colorSample.a = performLayerSettingsRGB(colorSample.a, WaterMasks[#{i}].settings); + colorSample.a = performLayerSettings(colorSample.a, WaterMasks[#{i}].settings); waterColor = blendWaterMasks#{i}(waterColor, colorSample, 1.0); } @@ -420,8 +446,8 @@ vec4 calculateWater(vec4 currentColor, vec2 uv, LevelWeights levelWeights, float cosineFactor = clamp(dot(-reflectionDirectionCameraSpace, directionToFragmentCameraSpace), 0, 1); cosineFactor = pow(cosineFactor, 100); - vec3 specularColor = vec3(1, 1, 1); - float specularIntensity = 0.4; + const vec3 specularColor = vec3(1.0); + const float specularIntensity = 0.4; vec3 specularTotal = specularColor * cosineFactor * specularIntensity * waterColor.a; diff --git a/modules/globebrowsing/shaders/tile.hglsl b/modules/globebrowsing/shaders/tile.hglsl index bcb203818d..7b37bafe8d 100644 --- a/modules/globebrowsing/shaders/tile.hglsl +++ b/modules/globebrowsing/shaders/tile.hglsl @@ -75,91 +75,4 @@ struct Layer { vec3 color; }; -struct LevelWeights { - float w1; - float w2; - float w3; -}; - -vec4 patchBorderOverlay(vec2 uv, vec3 borderColor, float borderSize) { - vec2 uvOffset = uv - vec2(0.5); - float thres = 0.5 - borderSize/2; - bool isBorder = abs(uvOffset.x) > thres || abs(uvOffset.y) > thres; - vec3 color = isBorder ? borderColor : vec3(0); - return vec4(color, 0); -} - -float getTransformedTexVal(TileDepthTransform transform, float val) { - return transform.depthOffset + transform.depthScale * val; -} - -vec4 getTransformedTexVal(TileDepthTransform transform, vec4 val) { - return transform.depthOffset + transform.depthScale * val; -} - -vec2 compensateSourceTextureSampling(vec2 startOffset, vec2 sizeDiff, ChunkTile chunkTile, - vec2 tileUV) -{ - ivec2 resolution = textureSize(chunkTile.textureSampler, 0); - - vec2 sourceSize = vec2(resolution) + sizeDiff; - vec2 currentSize = vec2(resolution); - vec2 sourceToCurrentSize = currentSize / sourceSize; - return sourceToCurrentSize * (tileUV - startOffset / sourceSize); -} - -vec2 TileUVToTextureSamplePosition(ChunkTile chunkTile, vec2 tileUV, - PixelPadding padding) -{ - vec2 uv = chunkTile.uvTransform.uvOffset + chunkTile.uvTransform.uvScale * tileUV; - return compensateSourceTextureSampling( - padding.startOffset, - padding.sizeDifference, - chunkTile, - uv - ); -} - -vec4 getTexVal(ChunkTile chunkTile, vec2 tileUV, PixelPadding padding) { - return texture( - chunkTile.textureSampler, - TileUVToTextureSamplePosition(chunkTile, tileUV, padding) - ); -} - -float getLevelInterpolationParameter(int chunkLevel, float distanceScaleFactor, - float distToVertexOnEllipsoid) -{ - float projectedScaleFactor = distanceScaleFactor / distToVertexOnEllipsoid; - float desiredLevel = log2(projectedScaleFactor); - return chunkLevel - desiredLevel; -} - -LevelWeights getLevelWeights(float levelInterpolationParameter) { - LevelWeights levelWeights; - levelWeights.w1 = clamp(1.0 - levelInterpolationParameter, 0.0, 1.0); - levelWeights.w2 = ( - clamp(levelInterpolationParameter, 0.0, 1.0) - - clamp(levelInterpolationParameter - 1.0, 0.0, 1.0) - ); - levelWeights.w3 = clamp(levelInterpolationParameter - 1.0, 0.0, 1.0); - return levelWeights; -} - -LevelWeights getDefaultLevelWeights() { - LevelWeights levelWeights; - levelWeights.w1 = 1; - levelWeights.w2 = 0; - levelWeights.w3 = 0; - return levelWeights; -} - -vec4 getTexVal(ChunkTilePile chunkTilePile, LevelWeights w, vec2 uv, - PixelPadding padding) -{ - return w.w1 * getTexVal(chunkTilePile.chunkTile0, uv, padding) + - w.w2 * getTexVal(chunkTilePile.chunkTile1, uv, padding) + - w.w3 * getTexVal(chunkTilePile.chunkTile2, uv, padding); -} - #endif // TEXTURETILE_HGLSL diff --git a/modules/globebrowsing/shaders/tileheight.hglsl b/modules/globebrowsing/shaders/tileheight.hglsl index 02c0d26a84..3722b481f0 100644 --- a/modules/globebrowsing/shaders/tileheight.hglsl +++ b/modules/globebrowsing/shaders/tileheight.hglsl @@ -28,7 +28,6 @@ #include "PowerScaling/powerScaling_vs.hglsl" #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> -#include <${MODULE_GLOBEBROWSING}/shaders/ellipsoid.hglsl> #ifndef USE_HEIGHTMAP #define USE_HEIGHTMAP #{useAccurateNormals} @@ -51,7 +50,7 @@ uniform float deltaPhi1; uniform float tileDelta; #endif //USE_ACCURATE_NORMALS && USE_HEIGHTMAP -float getUntransformedTileHeight(vec2 uv, LevelWeights levelWeights) { +float getUntransformedTileHeight(vec2 uv, vec3 levelWeights) { float height = CHUNK_DEFAULT_HEIGHT; #if USE_HEIGHTMAP @@ -67,7 +66,7 @@ float getUntransformedTileHeight(vec2 uv, LevelWeights levelWeights) { return height; } -float getTileHeight(vec2 uv, LevelWeights levelWeights) { +float getTileHeight(vec2 uv, vec3 levelWeights) { float height = CHUNK_DEFAULT_HEIGHT; #if USE_HEIGHTMAP @@ -83,7 +82,7 @@ float getTileHeight(vec2 uv, LevelWeights levelWeights) { return height; } -float getTileHeightScaled(vec2 uv, LevelWeights levelWeights) { +float getTileHeightScaled(vec2 uv, vec3 levelWeights) { float height = getTileHeight(uv, levelWeights); #if USE_HEIGHTMAP @@ -93,7 +92,7 @@ float getTileHeightScaled(vec2 uv, LevelWeights levelWeights) { return height; } -vec3 getTileNormal(vec2 uv, LevelWeights levelWeights, vec3 ellipsoidNormalCameraSpace, +vec3 getTileNormal(vec2 uv, vec3 levelWeights, vec3 ellipsoidNormalCameraSpace, vec3 ellipsoidTangentThetaCameraSpace, vec3 ellipsoidTangentPhiCameraSpace) { diff --git a/modules/globebrowsing/tile/asynctiledataprovider.cpp b/modules/globebrowsing/src/asynctiledataprovider.cpp similarity index 66% rename from modules/globebrowsing/tile/asynctiledataprovider.cpp rename to modules/globebrowsing/src/asynctiledataprovider.cpp index e41f1b3574..7273ab967a 100644 --- a/modules/globebrowsing/tile/asynctiledataprovider.cpp +++ b/modules/globebrowsing/src/asynctiledataprovider.cpp @@ -22,13 +22,12 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include -#include #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -41,7 +40,7 @@ namespace { } // namespace AsyncTileDataProvider::AsyncTileDataProvider(std::string name, - const std::shared_ptr rawTileDataReader) + std::unique_ptr rawTileDataReader) : _name(std::move(name)) , _rawTileDataReader(std::move(rawTileDataReader)) , _concurrentJobManager(LRUThreadPool(1, 10)) @@ -52,72 +51,49 @@ AsyncTileDataProvider::AsyncTileDataProvider(std::string name, AsyncTileDataProvider::~AsyncTileDataProvider() {} // NOLINT -std::shared_ptr AsyncTileDataProvider::rawTileDataReader() const { - return _rawTileDataReader; +const RawTileDataReader& AsyncTileDataProvider::rawTileDataReader() const { + return *_rawTileDataReader; } bool AsyncTileDataProvider::enqueueTileIO(const TileIndex& tileIndex) { if (_resetMode == ResetMode::ShouldNotReset && satisfiesEnqueueCriteria(tileIndex)) { - if (_pboContainer) { - char* dataPtr = static_cast(_pboContainer->mapBuffer( - tileIndex.hashKey(), PixelBuffer::Access::WriteOnly)); - if (dataPtr) { - auto job = std::make_shared(_rawTileDataReader, tileIndex, - dataPtr); - _concurrentJobManager.enqueueJob(job, tileIndex.hashKey()); - _enqueuedTileRequests.insert(tileIndex.hashKey()); - } - else { - return false; - } - } - else { - auto job = std::make_shared(_rawTileDataReader, tileIndex); - _concurrentJobManager.enqueueJob(job, tileIndex.hashKey()); - _enqueuedTileRequests.insert(tileIndex.hashKey()); - } + auto job = std::make_unique(*_rawTileDataReader, tileIndex); + _concurrentJobManager.enqueueJob(std::move(job), tileIndex.hashKey()); + _enqueuedTileRequests.insert(tileIndex.hashKey()); return true; } return false; } -std::vector> AsyncTileDataProvider::rawTiles() { - std::vector> readyResults; - std::shared_ptr finishedJob = popFinishedRawTile(); +std::vector AsyncTileDataProvider::rawTiles() { + std::vector readyResults; + std::optional finishedJob = popFinishedRawTile(); while (finishedJob) { - readyResults.push_back(finishedJob); + readyResults.push_back(std::move(finishedJob.value())); finishedJob = popFinishedRawTile(); } return readyResults; } -std::shared_ptr AsyncTileDataProvider::popFinishedRawTile() { +std::optional AsyncTileDataProvider::popFinishedRawTile() { if (_concurrentJobManager.numFinishedJobs() > 0) { // Now the tile load job looses ownerwhip of the data pointer - std::shared_ptr product = - _concurrentJobManager.popFinishedJob()->product(); + RawTile product = _concurrentJobManager.popFinishedJob()->product(); - const TileIndex::TileHashKey key = product->tileIndex.hashKey(); + const TileIndex::TileHashKey key = product.tileIndex.hashKey(); // No longer enqueued. Remove from set of enqueued tiles _enqueuedTileRequests.erase(key); // Pbo is still mapped. Set the id for the raw tile - if (_pboContainer) { - product->pbo = _pboContainer->idOfMappedBuffer(key); - // Now we are finished with the mapping of this pbo - _pboContainer->unMapBuffer(key); - } - else { - product->pbo = 0; - if (product->error != RawTile::ReadError::None) { - delete[] product->imageData; - return nullptr; - } + product.pbo = 0; + if (product.error != RawTile::ReadError::None) { + product.imageData = nullptr; + return std::nullopt; } return product; } else { - return nullptr; + return std::nullopt; } } @@ -137,10 +113,6 @@ void AsyncTileDataProvider::endUnfinishedJobs() { std::vector unfinishedJobs = _concurrentJobManager.keysToUnfinishedJobs(); for (const TileIndex::TileHashKey& unfinishedJob : unfinishedJobs) { - // Unmap unfinished jobs - if (_pboContainer) { - _pboContainer->unMapBuffer(unfinishedJob); - } // When erasing the job before _enqueuedTileRequests.erase(unfinishedJob); } @@ -150,31 +122,11 @@ void AsyncTileDataProvider::endEnqueuedJobs() { std::vector enqueuedJobs = _concurrentJobManager.keysToEnqueuedJobs(); for (const TileIndex::TileHashKey& enqueuedJob : enqueuedJobs) { - // Unmap unfinished jobs - if (_pboContainer) { - _pboContainer->unMapBuffer(enqueuedJob); - } // When erasing the job before _enqueuedTileRequests.erase(enqueuedJob); } } -void AsyncTileDataProvider::updatePboUsage() { - const bool usingPbo = _pboContainer != nullptr; - const bool shouldUsePbo = _globeBrowsingModule->tileCache()->shouldUsePbo(); - - // If changed, we need to reset the async tile data provider. - // No need to reset the raw tile data reader when changing PBO usage. - if (usingPbo != shouldUsePbo && - _resetMode != ResetMode::ShouldResetAllButRawTileDataReader) - { - _resetMode = ResetMode::ShouldResetAllButRawTileDataReader; - LINFO(fmt::format( - "PBO usage updated, prepairing for resetting of tile reader '{}'", _name - )); - } -} - void AsyncTileDataProvider::update() { endUnfinishedJobs(); @@ -210,7 +162,6 @@ void AsyncTileDataProvider::update() { break; } case ResetMode::ShouldNotReset: { - updatePboUsage(); break; } default: @@ -226,7 +177,7 @@ void AsyncTileDataProvider::reset() { LINFO(fmt::format("Prepairing for resetting of tile reader '{}'", _name)); } -void AsyncTileDataProvider::prepairToBeDeleted() { +void AsyncTileDataProvider::prepareToBeDeleted() { _resetMode = ResetMode::ShouldBeDeleted; endEnqueuedJobs(); } @@ -238,19 +189,6 @@ bool AsyncTileDataProvider::shouldBeDeleted() { void AsyncTileDataProvider::performReset(ResetRawTileDataReader resetRawTileDataReader) { ghoul_assert(_enqueuedTileRequests.empty(), "No enqueued requests left"); - // Re-initialize PBO container - if (_globeBrowsingModule->tileCache()->shouldUsePbo()) { - size_t pboNumBytes = _rawTileDataReader->tileTextureInitData().totalNumBytes(); - _pboContainer = std::make_unique>( - pboNumBytes, - PixelBuffer::Usage::StreamDraw, - 10 - ); - } - else { - _pboContainer = nullptr; - } - // Reset raw tile data reader if (resetRawTileDataReader == ResetRawTileDataReader::Yes) { _rawTileDataReader->reset(); diff --git a/modules/globebrowsing/tile/asynctiledataprovider.h b/modules/globebrowsing/src/asynctiledataprovider.h similarity index 86% rename from modules/globebrowsing/tile/asynctiledataprovider.h rename to modules/globebrowsing/src/asynctiledataprovider.h index 5cd99e779e..3ae67142a2 100644 --- a/modules/globebrowsing/tile/asynctiledataprovider.h +++ b/modules/globebrowsing/src/asynctiledataprovider.h @@ -25,20 +25,19 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___ASYNC_TILE_DATAPROVIDER___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___ASYNC_TILE_DATAPROVIDER___H__ -#include -#include +#include +#include +#include #include #include +#include #include namespace openspace { class GlobeBrowsingModule; } namespace openspace::globebrowsing { -template class PixelBufferContainer; - struct RawTile; -class RawTileDataReader; /** * The responsibility of this class is to enqueue tile requests and fetching finished @@ -51,7 +50,7 @@ public: * tile loading. */ AsyncTileDataProvider(std::string name, - std::shared_ptr rawTileDataReader); + std::unique_ptr rawTileDataReader); ~AsyncTileDataProvider(); @@ -63,20 +62,20 @@ public: /** * Get all finished jobs. */ - std::vector> rawTiles(); + std::vector rawTiles(); /** * Get one finished job. */ - std::shared_ptr popFinishedRawTile(); + std::optional popFinishedRawTile(); void update(); void reset(); - void prepairToBeDeleted(); + void prepareToBeDeleted(); bool shouldBeDeleted(); - std::shared_ptr rawTileDataReader() const; + const RawTileDataReader& rawTileDataReader() const; float noDataValueAsFloat() const; protected: @@ -103,21 +102,17 @@ protected: void endEnqueuedJobs(); - void updatePboUsage(); - void performReset(ResetRawTileDataReader resetRawTileDataReader); private: const std::string _name; GlobeBrowsingModule* _globeBrowsingModule; /// The reader used for asynchronous reading - std::shared_ptr _rawTileDataReader; + std::unique_ptr _rawTileDataReader; PrioritizingConcurrentJobManager _concurrentJobManager; - /// nullptr if pbo is not used for texture uploading. Otherwise initialized. - std::unique_ptr> _pboContainer; std::set _enqueuedTileRequests; ResetMode _resetMode = ResetMode::ShouldResetAllButRawTileDataReader; diff --git a/modules/globebrowsing/tile/tile.h b/modules/globebrowsing/src/basictypes.h similarity index 64% rename from modules/globebrowsing/tile/tile.h rename to modules/globebrowsing/src/basictypes.h index 02b0bf2536..f9af24593b 100644 --- a/modules/globebrowsing/tile/tile.h +++ b/modules/globebrowsing/src/basictypes.h @@ -22,27 +22,95 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE___H__ +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING__BASICTYPES___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING__BASICTYPES___H__ -#include +#include #include +#include +#include namespace ghoul::opengl { class Texture; } namespace openspace::globebrowsing { -struct TileUvTransform; +struct AABB3 { + glm::vec3 min = glm::vec3(std::numeric_limits::max()); + glm::vec3 max = glm::vec3(-std::numeric_limits::max()); +}; + + + +struct Geodetic2 { + double lat; + double lon; +}; + + + +struct Geodetic3 { + Geodetic2 geodetic2; + double height; +}; + + + +struct PixelRegion { + glm::ivec2 start = glm::ivec2(0); + glm::ivec2 numPixels = glm::ivec2(0); +}; + + + +struct IODescription { + struct ReadData { + int overview; + PixelRegion region; + PixelRegion fullRegion; + } read; + + struct WriteData { + PixelRegion region; + size_t bytesPerLine; + size_t totalNumBytes; + } write; +}; + + + +enum Quad { + NORTH_WEST = 0, + NORTH_EAST, + SOUTH_WEST, + SOUTH_EAST +}; + + + +struct TileDepthTransform { + float scale; + float offset; +}; + + + +struct TileMetaData { + std::vector maxValues; + std::vector minValues; + std::vector hasMissingData; +}; + + /** * Defines a status and may have a Texture and TileMetaData */ class Tile { public: - /** - * Describe if this Tile is good for usage (OK) or otherwise - * the reason why it is not. - */ + /** + * 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. @@ -71,27 +139,30 @@ public: OK }; - Tile(ghoul::opengl::Texture* texture, std::shared_ptr metaData, - Status status); - ~Tile() = default; - - TileMetaData* metaData() const; - Status status() const; - ghoul::opengl::Texture* texture() const; - - /** - * A tile with status unavailable that any user can return to - * indicate that a tile was unavailable. - */ - static const Tile TileUnavailable; - -private: - ghoul::opengl::Texture* _texture; - std::shared_ptr _metaData; - Status _status; + ghoul::opengl::Texture* texture = nullptr; + std::optional metaData = std::nullopt; + Status status = Status::Unavailable; }; + + +struct TileUvTransform { + glm::vec2 uvOffset; + glm::vec2 uvScale; +}; + + + +struct ChunkTile { + Tile tile; + TileUvTransform uvTransform; + TileDepthTransform depthTransform; +}; + + + +using ChunkTilePile = std::vector; + } // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE___H__ +#endif // __OPENSPACE_MODULE_GLOBEBROWSING__BASICTYPES___H__ diff --git a/modules/globebrowsing/dashboard/dashboarditemglobelocation.cpp b/modules/globebrowsing/src/dashboarditemglobelocation.cpp similarity index 92% rename from modules/globebrowsing/dashboard/dashboarditemglobelocation.cpp rename to modules/globebrowsing/src/dashboarditemglobelocation.cpp index 262206fa22..80e5cb658e 100644 --- a/modules/globebrowsing/dashboard/dashboarditemglobelocation.cpp +++ b/modules/globebrowsing/src/dashboarditemglobelocation.cpp @@ -22,10 +22,10 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include -#include -#include +#include +#include #include #include #include @@ -115,7 +115,7 @@ DashboardItemGlobeLocation::DashboardItemGlobeLocation( const ghoul::Dictionary& dictionary) : DashboardItem(dictionary) , _fontName(FontNameInfo, KeyFontMono) - , _fontSize(FontSizeInfo, DefaultFontSize, 6.f, 144.f, 1.f) + , _fontSize(FontSizeInfo, DefaultFontSize, 10.f, 144.f, 1.f) , _font(global::fontManager.font(KeyFontMono, 10)) { documentation::testSpecificationAndThrow( @@ -148,14 +148,13 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) { using namespace globebrowsing; SceneGraphNode* n = global::navigationHandler.focusNode(); - const RenderableGlobe* globe = dynamic_cast(n->renderable()); + const RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { return; } const glm::dvec3 cameraPosition = global::navigationHandler.camera()->positionVec3(); - const glm::dmat4 inverseModelTransform = - global::navigationHandler.focusNode()->inverseModelTransform(); + const glm::dmat4 inverseModelTransform = n->inverseModelTransform(); const glm::dvec3 cameraPositionModelSpace = glm::dvec3(inverseModelTransform * glm::dvec4(cameraPosition, 1.0)); const SurfacePositionHandle posHandle = globe->calculateSurfacePositionHandle( @@ -175,8 +174,9 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) { bool isEast = lon > 0.0; lon = std::abs(lon); - const double altitude = glm::length(cameraPositionModelSpace - - posHandle.centerToReferenceSurface); + const double altitude = glm::length( + cameraPositionModelSpace - posHandle.centerToReferenceSurface + ); std::pair dist = simplifyDistance(altitude); penPosition.y -= _font->height(); @@ -187,7 +187,8 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) { "Position: {:03.2f}{}, {:03.2f}{} Altitude: {} {}", lat, isNorth ? "N" : "S", lon, isEast ? "E" : "W", - dist.first, dist.second) + dist.first, dist.second + ) ); } glm::vec2 DashboardItemGlobeLocation::size() const { diff --git a/modules/globebrowsing/dashboard/dashboarditemglobelocation.h b/modules/globebrowsing/src/dashboarditemglobelocation.h similarity index 100% rename from modules/globebrowsing/dashboard/dashboarditemglobelocation.h rename to modules/globebrowsing/src/dashboarditemglobelocation.h diff --git a/modules/globebrowsing/geometry/ellipsoid.cpp b/modules/globebrowsing/src/ellipsoid.cpp similarity index 72% rename from modules/globebrowsing/geometry/ellipsoid.cpp rename to modules/globebrowsing/src/ellipsoid.cpp index 4da8f6c788..a9bd4fce1d 100644 --- a/modules/globebrowsing/geometry/ellipsoid.cpp +++ b/modules/globebrowsing/src/ellipsoid.cpp @@ -22,18 +22,16 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include - -#include -#include +#include +#include #include #include #include namespace { constexpr const size_t MaxIterations = 8; -} +} // namespace namespace openspace::globebrowsing { @@ -42,30 +40,25 @@ Ellipsoid::Ellipsoid(glm::dvec3 radii) : _radii(radii) { } void Ellipsoid::updateInternalCache() { - _cached._radiiSquared = glm::dvec3( - _radii.x * _radii.x, - _radii.y * _radii.y, - _radii.z * _radii.z - ); + _cached.radiiSquared = _radii * _radii; - _cached._oneOverRadiiSquared = glm::dvec3(1.0) / _cached._radiiSquared; - _cached._radiiToTheFourth = _cached._radiiSquared * _cached._radiiSquared; + _cached.oneOverRadiiSquared = glm::dvec3(1.0) / _cached.radiiSquared; + _cached.radiiToTheFourth = _cached.radiiSquared * _cached.radiiSquared; std::array radii = { _radii.x, _radii.y, _radii.z }; std::sort(radii.begin(), radii.end()); - _cached._minimumRadius = radii[0]; - _cached._medianRadius = radii[1]; - _cached._maximumRadius = radii[2]; + _cached.minimumRadius = radii[0]; + _cached.maximumRadius = radii[2]; } glm::dvec3 Ellipsoid::geocentricSurfaceProjection(const glm::dvec3& p) const { - const double beta = 1.0 / sqrt(dot(p * p, _cached._oneOverRadiiSquared)); + const double beta = 1.0 / sqrt(dot(p * p, _cached.oneOverRadiiSquared)); return beta * p; } glm::dvec3 Ellipsoid::geodeticSurfaceProjection(const glm::dvec3& p) const { - const double beta = 1.0 / sqrt(dot(p * p, _cached._oneOverRadiiSquared)); - const double n = glm::length(beta * p * _cached._oneOverRadiiSquared); + const double beta = 1.0 / sqrt(dot(p * p, _cached.oneOverRadiiSquared)); + const double n = glm::length(beta * p * _cached.oneOverRadiiSquared); double alpha = (1.0 - beta) * (glm::length(p) / n); const glm::dvec3 p2 = p * p; @@ -79,13 +72,13 @@ glm::dvec3 Ellipsoid::geodeticSurfaceProjection(const glm::dvec3& p) const { do { alpha -= (s / dSdA); - d = glm::dvec3(1.0) + alpha * _cached._oneOverRadiiSquared; + d = glm::dvec3(1.0) + alpha * _cached.oneOverRadiiSquared; const glm::dvec3 d2 = d * d; const glm::dvec3 d3 = d * d2; - s = glm::dot(p2 / (_cached._radiiSquared * d2), glm::dvec3(1.0)) - 1.0; + s = glm::dot(p2 / (_cached.radiiSquared * d2), glm::dvec3(1.0)) - 1.0; - dSdA = -2.0 * glm::dot(p2 / (_cached._radiiToTheFourth * d3), glm::dvec3(1.0)); + dSdA = -2.0 * glm::dot(p2 / (_cached.radiiToTheFourth * d3), glm::dvec3(1.0)); ++nIterations; } while (std::abs(s) > epsilon && nIterations < MaxIterations); @@ -96,7 +89,7 @@ glm::dvec3 Ellipsoid::geodeticSurfaceProjection(const glm::dvec3& p) const { glm::dvec3 Ellipsoid::geodeticSurfaceNormalForGeocentricallyProjectedPoint( const glm::dvec3& p) const { - const glm::dvec3 normal = p * _cached._oneOverRadiiSquared; + const glm::dvec3 normal = p * _cached.oneOverRadiiSquared; return glm::normalize(normal); } @@ -114,28 +107,12 @@ const glm::dvec3& Ellipsoid::radii() const { return _radii; } -const glm::dvec3& Ellipsoid::radiiSquared() const { - return _cached._radiiSquared; -} - -const glm::dvec3& Ellipsoid::oneOverRadiiSquared() const { - return _cached._oneOverRadiiSquared; -} - -const glm::dvec3& Ellipsoid::radiiToTheFourth() const { - return _cached._radiiToTheFourth; -} - double Ellipsoid::minimumRadius() const { - return _cached._minimumRadius; + return _cached.minimumRadius; } double Ellipsoid::maximumRadius() const { - return _cached._maximumRadius; -} - -double Ellipsoid::averageRadius() const { - return (_radii.x + _radii.y + _radii.z) / 3.0; + return _cached.maximumRadius; } double Ellipsoid::longitudalDistance(double lat, double lon1, double lon2) const { @@ -155,7 +132,10 @@ double Ellipsoid::greatCircleDistance(const Geodetic2& p1, const Geodetic2& p2) glm::length(glm::cross(n1, n2)) / glm::dot(n1, n2) ); - const Geodetic2 pMid = (p1 + p2) / 2; + const Geodetic2 pMid = { + (p1.lat + p2.lat) / 2.0, + (p1.lon + p2.lon) / 2.0 + }; const glm::dvec3 centralNormal = cartesianSurfacePosition(pMid); return centralAngle * glm::length(centralNormal); @@ -163,10 +143,10 @@ double Ellipsoid::greatCircleDistance(const Geodetic2& p1, const Geodetic2& p2) Geodetic2 Ellipsoid::cartesianToGeodetic2(const glm::dvec3& p) const { const glm::dvec3 normal = geodeticSurfaceNormalForGeocentricallyProjectedPoint(p); - return Geodetic2( - asin(normal.z / length(normal)), // Latitude - atan2(normal.y, normal.x) // Longitude - ); + Geodetic2 res; + res.lat = asin(normal.z / length(normal)); + res.lon = atan2(normal.y, normal.x); + return res; } glm::dvec3 Ellipsoid::cartesianSurfacePosition(const Geodetic2& geodetic2) const { @@ -176,24 +156,22 @@ glm::dvec3 Ellipsoid::cartesianSurfacePosition(const Geodetic2& geodetic2) const glm::dvec3 Ellipsoid::cartesianPosition(const Geodetic3& geodetic3) const { const glm::dvec3 normal = geodeticSurfaceNormal(geodetic3.geodetic2); - const glm::dvec3 k = _cached._radiiSquared * normal; + const glm::dvec3 k = _cached.radiiSquared * normal; const double gamma = sqrt(dot(k, normal)); const glm::dvec3 rSurface = k / gamma; return rSurface + geodetic3.height * normal; } void Ellipsoid::setShadowConfigurationArray( - const std::vector& shadowConfArray) + std::vector shadowConfArray) { - _shadowConfArray = shadowConfArray; + _shadowConfArray = std::move(shadowConfArray); } -std::vector Ellipsoid::shadowConfigurationArray() const { +const std::vector& +Ellipsoid::shadowConfigurationArray() const +{ return _shadowConfArray; } -bool Ellipsoid::hasEclipseShadows() const { - return !_shadowConfArray.empty(); -} - } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/geometry/ellipsoid.h b/modules/globebrowsing/src/ellipsoid.h similarity index 89% rename from modules/globebrowsing/geometry/ellipsoid.h rename to modules/globebrowsing/src/ellipsoid.h index 772a308b64..3a0c83edd9 100644 --- a/modules/globebrowsing/geometry/ellipsoid.h +++ b/modules/globebrowsing/src/ellipsoid.h @@ -77,13 +77,9 @@ public: glm::dvec3 geodeticSurfaceNormal(const Geodetic2& geodetic2) const; const glm::dvec3& radii() const; - const glm::dvec3& radiiSquared() const; - const glm::dvec3& oneOverRadiiSquared() const; - const glm::dvec3& radiiToTheFourth() const; double minimumRadius() const; double maximumRadius() const; - double averageRadius() const; double longitudalDistance(double lat, double lon1, double lon2) const; double greatCircleDistance(const Geodetic2& p1, const Geodetic2& p2) const; @@ -93,19 +89,17 @@ public: glm::dvec3 cartesianPosition(const Geodetic3& geodetic3) const; void setShadowConfigurationArray( - const std::vector& shadowConfArray + std::vector shadowConfArray ); - std::vector shadowConfigurationArray() const; - bool hasEclipseShadows() const; + const std::vector& shadowConfigurationArray() const; private: struct EllipsoidCache { - glm::dvec3 _radiiSquared; - glm::dvec3 _oneOverRadiiSquared; - glm::dvec3 _radiiToTheFourth; - double _minimumRadius; - double _maximumRadius; - double _medianRadius; + glm::dvec3 radiiSquared; + glm::dvec3 oneOverRadiiSquared; + glm::dvec3 radiiToTheFourth; + double minimumRadius; + double maximumRadius; } _cached; void updateInternalCache(); diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.cpp b/modules/globebrowsing/src/gdalwrapper.cpp similarity index 86% rename from modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.cpp rename to modules/globebrowsing/src/gdalwrapper.cpp index 3b9deaed67..9a64cc8791 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.cpp +++ b/modules/globebrowsing/src/gdalwrapper.cpp @@ -22,20 +22,16 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifdef GLOBEBROWSING_USE_GDAL - -#include +#include #include #include - -#include #include +#include #include #include -#include - #include +#include namespace { constexpr const char* _loggerCat = "GdalWrapper"; @@ -53,22 +49,25 @@ namespace { "This function sets the maximum amount of RAM memory in MB that GDAL is " "permitted to use for caching." }; + + void gdalErrorHandler(CPLErr eErrClass, int, const char* msg) { + // No need to try to do this check earlier and only install this method as an error + // handler if the logging is desired as the default behavior of GDAL is to log errors + // to stderr. + if (openspace::globebrowsing::GdalWrapper::ref().logGdalErrors()) { + switch (eErrClass) { + case CE_None: break; + case CE_Debug: LDEBUGC("GDAL", msg); break; + case CE_Warning: LWARNINGC("GDAL", msg); break; + case CE_Failure: LERRORC("GDAL", msg); break; + case CE_Fatal: LFATALC("GDAL", msg); break; + } + } + } } // namespace namespace openspace::globebrowsing { -void gdalErrorHandler(CPLErr eErrClass, int, const char* msg) { - if (GdalWrapper::ref().logGdalErrors()) { - switch (eErrClass) { - case CE_None: break; - case CE_Debug: LDEBUGC ("GDAL", msg); break; - case CE_Warning: LWARNINGC("GDAL", msg); break; - case CE_Failure: LERRORC ("GDAL", msg); break; - case CE_Fatal: LFATALC ("GDAL", msg); break; - } - } -} - GdalWrapper* GdalWrapper::_singleton = nullptr; void GdalWrapper::create(size_t maximumCacheSize, size_t maximumMaximumCacheSize) { @@ -85,11 +84,11 @@ GdalWrapper& GdalWrapper::ref() { return *_singleton; } -size_t GDALCacheUsed() { +int64_t GDALCacheUsed() { return GDALGetCacheUsed64(); } -size_t GDALMaximumCacheSize() { +int64_t GDALMaximumCacheSize() { return GDALGetCacheMax64(); } @@ -100,7 +99,7 @@ bool GdalWrapper::logGdalErrors() const { GdalWrapper::GdalWrapper(size_t maximumCacheSize, size_t maximumMaximumCacheSize) : PropertyOwner({ "GdalWrapper" }) , _logGdalErrors(LogGdalErrorInfo, false) - , _gdalMaximumCacheSize ( + , _gdalMaximumCacheSize( GdalMaximumCacheInfo, static_cast(maximumCacheSize / (1024ULL * 1024ULL)), // Default 0, // Minimum: No caching @@ -124,8 +123,7 @@ GdalWrapper::GdalWrapper(size_t maximumCacheSize, size_t maximumMaximumCacheSize _gdalMaximumCacheSize.onChange([&] { // MB to Bytes GDALSetCacheMax64( - static_cast(_gdalMaximumCacheSize) * - 1024ULL * 1024ULL + static_cast(_gdalMaximumCacheSize) * 1024ULL * 1024ULL ); }); } @@ -158,5 +156,3 @@ void GdalWrapper::setGdalProxyConfiguration() { } } // namespace openspace::globebrowsing - -#endif // GLOBEBROWSING_USE_GDAL diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.h b/modules/globebrowsing/src/gdalwrapper.h similarity index 92% rename from modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.h rename to modules/globebrowsing/src/gdalwrapper.h index 9cebc88042..427bc230a4 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.h +++ b/modules/globebrowsing/src/gdalwrapper.h @@ -25,8 +25,6 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GDAL_WRAPPER___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___GDAL_WRAPPER___H__ -#ifdef GLOBEBROWSING_USE_GDAL - #include #include @@ -36,11 +34,6 @@ namespace openspace::globebrowsing { -/** - * Function for passing GDAL error messages to the GHOUL logging system. - */ -void gdalErrorHandler(CPLErr eErrClass, int errNo, const char* msg); - /** * Singleton class interfacing with global GDAL functions. */ @@ -62,13 +55,13 @@ public: * 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(); + static int64_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(); + static int64_t GDALMaximumCacheSize(); bool logGdalErrors() const; @@ -86,6 +79,4 @@ private: } // namespace openspace::globebrowsing -#endif // GLOBEBROWSING_USE_GDAL - #endif // __OPENSPACE_MODULE_GLOBEBROWSING___GDAL_WRAPPER___H__ diff --git a/modules/globebrowsing/geometry/geodeticpatch.cpp b/modules/globebrowsing/src/geodeticpatch.cpp similarity index 72% rename from modules/globebrowsing/geometry/geodeticpatch.cpp rename to modules/globebrowsing/src/geodeticpatch.cpp index db2e801ed8..80a66ceed9 100644 --- a/modules/globebrowsing/geometry/geodeticpatch.cpp +++ b/modules/globebrowsing/src/geodeticpatch.cpp @@ -22,19 +22,35 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include - -#include -#include +#include +#include #include +namespace { + // Normalizes the angle to the interval [center - pi, center + pi[ + double normalizedAngleAround(double angle, double center) { + angle -= center + glm::pi(); + + // this will cause angle to be in value range ]-2pi, 2pi[ + angle = fmod(angle, glm::two_pi()); + + // ensure _radians are positive, ie in value range [0, 2pi[ + if (angle < 0.0) { + angle += glm::two_pi(); + } + + angle += center - glm::pi(); + return angle; + } +} // namespace + namespace openspace::globebrowsing { GeodeticPatch::GeodeticPatch(double centerLat, double centerLon, double halfSizeLat, double halfSizeLon) - : _center(Geodetic2(centerLat, centerLon)) - , _halfSize(Geodetic2(halfSizeLat, halfSizeLon)) + : _center{ centerLat, centerLon } + , _halfSize{ halfSizeLat, halfSizeLon } {} GeodeticPatch::GeodeticPatch(const Geodetic2& center, const Geodetic2& halfSize) @@ -47,12 +63,12 @@ GeodeticPatch::GeodeticPatch(const TileIndex& tileIndex) { (static_cast(1 << tileIndex.level)); const double deltaLon = (2 * glm::pi()) / (static_cast(1 << tileIndex.level)); - const Geodetic2 nwCorner( - glm::pi() / 2 - deltaLat * tileIndex.y, + const Geodetic2 nwCorner{ + glm::pi() / 2.0 - deltaLat * tileIndex.y, -glm::pi() + deltaLon * tileIndex.x - ); - _halfSize = Geodetic2(deltaLat / 2, deltaLon / 2); - _center = Geodetic2(nwCorner.lat - _halfSize.lat, nwCorner.lon + _halfSize.lon); + }; + _halfSize = Geodetic2{ deltaLat / 2.0, deltaLon / 2.0 }; + _center = Geodetic2{ nwCorner.lat - _halfSize.lat, nwCorner.lon + _halfSize.lon }; } void GeodeticPatch::setCenter(Geodetic2 center) { @@ -82,16 +98,19 @@ const Geodetic2& GeodeticPatch::halfSize() const { } Geodetic2 GeodeticPatch::size() const { - return _halfSize * 2.0; + return { + _halfSize.lon * 2.0, + _halfSize.lat * 2.0 + }; } Geodetic2 GeodeticPatch::corner(Quad q) const { switch (q) { - case NORTH_WEST: return Geodetic2(maxLat(), minLon());// northWestCorner(); - 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: throw ghoul::MissingCaseException(); + case NORTH_WEST: return Geodetic2{ maxLat(), minLon() };// northWestCorner(); + 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: throw ghoul::MissingCaseException(); } } @@ -112,12 +131,15 @@ double GeodeticPatch::maxLon() const { } bool GeodeticPatch::contains(const Geodetic2& p) const { - const Geodetic2 diff = _center - p; + const Geodetic2 diff = { + _center.lat - p.lat, + _center.lon - p.lon + }; return glm::abs(diff.lat) <= _halfSize.lat && glm::abs(diff.lon) <= _halfSize.lon; } double GeodeticPatch::edgeLatitudeNearestEquator() const { - return _center.lat + _halfSize.lat * (isNorthern() ? -1 : 1); + return _center.lat + _halfSize.lat * (isNorthern() ? -1.0 : 1.0); } double GeodeticPatch::isNorthern() const { @@ -125,14 +147,6 @@ double GeodeticPatch::isNorthern() const { } Geodetic2 GeodeticPatch::clamp(const Geodetic2& p) const { - using Ang = Angle; - - // Convert to Angles for normalization - const Ang centerLat = Ang::fromRadians(_center.lat); - const Ang centerLon = Ang::fromRadians(_center.lon); - Ang pointLat = Ang::fromRadians(p.lat); - Ang pointLon = Ang::fromRadians(p.lon); - // Normalize w.r.t. the center in order for the clamping to done correctly // // Example: @@ -140,24 +154,25 @@ Geodetic2 GeodeticPatch::clamp(const Geodetic2& p) const { // --> Just clamping pointLat would be clamp(330, -10, 10) = 10 // WRONG! // Instead, if we first normalize 330 deg around 0, we get -30 deg // --> clamp(-30, -10, 10) = -10 // CORRECT! - pointLat.normalizeAround(centerLat); - pointLon.normalizeAround(centerLon); + double pointLat = normalizedAngleAround(p.lat, _center.lat); + double pointLon = normalizedAngleAround(p.lon, _center.lon); - return Geodetic2( - glm::clamp(pointLat.asRadians(), minLat(), maxLat()), - glm::clamp(pointLon.asRadians(), minLon(), maxLon()) - ); + Geodetic2 res; + res.lat = glm::clamp(pointLat, minLat(), maxLat()); + res.lon = glm::clamp(pointLon, minLon(), maxLon()); + return res; } Geodetic2 GeodeticPatch::closestCorner(const Geodetic2& p) const { - using Ang = Angle; - // LatLon vector from patch center to the point - const Geodetic2 centerToPoint = p - _center; + const Geodetic2 centerToPoint = { + p.lat - _center.lat, + p.lon - _center.lon + }; // Normalize the difference angles to be centered around 0. - const Ang latDiff = Ang::fromRadians(centerToPoint.lat).normalizeAround(Ang::ZERO); - const Ang lonDiff = Ang::fromRadians(centerToPoint.lon).normalizeAround(Ang::ZERO); + const double latDiff = normalizedAngleAround(centerToPoint.lat, 0.0); + const double lonDiff = normalizedAngleAround(centerToPoint.lon, 0.0); // If latDiff > 0 // --> point p is north of the patch center @@ -165,12 +180,12 @@ Geodetic2 GeodeticPatch::closestCorner(const Geodetic2& p) const { // --> set the corner's latitude coordinate to center.lat + halfSize.lat // else // --> set corner's latidude coordinate to center.lat - halfSize.lat - const double cornerLat = _center.lat + _halfSize.lat * (latDiff > Ang::ZERO ? 1 : -1); + const double cornerLat = _center.lat + _halfSize.lat * (latDiff > 0.0 ? 1 : -1); // We then assigned the corner's longitude coordinate in a similar fashion - const double cornerLon = _center.lon + _halfSize.lon * (lonDiff > Ang::ZERO ? 1 : -1); + const double cornerLon = _center.lon + _halfSize.lon * (lonDiff > 0.0 ? 1 : -1); - return Geodetic2(cornerLat, cornerLon); + return Geodetic2{ cornerLat, cornerLon }; } Geodetic2 GeodeticPatch::closestPoint(const Geodetic2& p) const { @@ -201,43 +216,35 @@ Geodetic2 GeodeticPatch::closestPoint(const Geodetic2& p) const { // Just doing this actually makes points returned from this methods being the // true closest point, great-circle distance-wise. - using Ang = Angle; - - // Convert to Angles for normalization - const Ang centerLat = Ang::fromRadians(_center.lat); - const Ang centerLon = Ang::fromRadians(_center.lon); - Ang pointLat = Ang::fromRadians(p.lat); - Ang pointLon = Ang::fromRadians(p.lon); // Normalize point with respect to center. This is done because the point // will later be clamped. See LatLonPatch::clamp(const LatLon&) for explanation - pointLat.normalizeAround(centerLat); - pointLon.normalizeAround(centerLon); + double pointLat = normalizedAngleAround(p.lat, _center.lat); + double pointLon = normalizedAngleAround(p.lon, _center.lon); // Calculate the longitud difference between center and point. We normalize around // zero because we want the "shortest distance" difference, i.e the difference // should be in the interval [-180 deg, 180 deg] - const Ang centerToPointLon = (centerLon - pointLon).normalizeAround(Ang::ZERO); + const double centerToPointLon = normalizedAngleAround(_center.lon - pointLon, 0.0); // Calculate the longitudinal distance to the closest patch edge - const Ang longitudeDistanceToClosestPatchEdge = centerToPointLon.abs() - - Ang::fromRadians(_halfSize.lon); + const double lonDistanceToClosestPatch = glm::abs(centerToPointLon) - _halfSize.lon; // If the longitude distance to the closest patch edge is larger than 90 deg // the latitude will have to be clamped to its closest corner, as explained in // the example above. const double clampedLat = - longitudeDistanceToClosestPatchEdge > Ang::QUARTER ? + lonDistanceToClosestPatch > glm::half_pi() ? glm::clamp( - (Ang::HALF - pointLat).normalizeAround(centerLat).asRadians(), + normalizedAngleAround(glm::pi() - pointLat, _center.lat), minLat(), maxLat()) : - glm::clamp(pointLat.asRadians(), minLat(), maxLat()); + glm::clamp(pointLat, minLat(), maxLat()); // Longitude is just clamped normally - const double clampedLon = glm::clamp(pointLon.asRadians(), minLon(), maxLon()); + const double clampedLon = glm::clamp(pointLon, minLon(), maxLon()); - return Geodetic2(clampedLat, clampedLon); + return Geodetic2{ clampedLat, clampedLon }; } } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/geometry/geodeticpatch.h b/modules/globebrowsing/src/geodeticpatch.h similarity index 97% rename from modules/globebrowsing/geometry/geodeticpatch.h rename to modules/globebrowsing/src/geodeticpatch.h index f45ee757fa..7d307070e1 100644 --- a/modules/globebrowsing/geometry/geodeticpatch.h +++ b/modules/globebrowsing/src/geodeticpatch.h @@ -25,8 +25,7 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GEODETICPATCH___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___GEODETICPATCH___H__ -#include -#include +#include namespace openspace::globebrowsing { diff --git a/modules/globebrowsing/src/gpulayergroup.cpp b/modules/globebrowsing/src/gpulayergroup.cpp new file mode 100644 index 0000000000..cdd745ad9b --- /dev/null +++ b/modules/globebrowsing/src/gpulayergroup.cpp @@ -0,0 +1,194 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include + +namespace openspace::globebrowsing { + +void GPULayerGroup::setValue(ghoul::opengl::ProgramObject& program, + const LayerGroup& layerGroup, const TileIndex& tileIndex) +{ + ghoul_assert( + layerGroup.activeLayers().size() == _gpuActiveLayers.size(), + "GPU and CPU active layers must have same size!" + ); + + const std::vector& activeLayers = layerGroup.activeLayers(); + for (unsigned int i = 0; i < activeLayers.size(); ++i) { + const GPULayer& gal = _gpuActiveLayers[i]; + auto& galuc = gal.uniformCache; + const Layer& al = *activeLayers[i]; + + program.setUniform(galuc.opacity, al.renderSettings().opacity); + program.setUniform(galuc.gamma, al.renderSettings().gamma); + program.setUniform(galuc.multiplier, al.renderSettings().multiplier); + program.setUniform(galuc.offset, al.renderSettings().offset); + + if (al.layerAdjustment().type() == layergroupid::AdjustmentTypeID::ChromaKey) { + program.setUniform( + galuc.chromaKeyColor, + al.layerAdjustment().chromaKeyColor() + ); + program.setUniform( + galuc.chromaKeyTolerance, + al.layerAdjustment().chromaKeyTolerance() + ); + } + + switch (al.type()) { + // Intentional fall through. Same for all tile layers + case layergroupid::TypeID::DefaultTileLayer: + case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SizeReferenceTileLayer: + case layergroupid::TypeID::TemporalTileLayer: + case layergroupid::TypeID::TileIndexTileLayer: + case layergroupid::TypeID::ByIndexTileLayer: + case layergroupid::TypeID::ByLevelTileLayer: { + const ChunkTilePile& ctp = al.chunkTilePile( + tileIndex, + layerGroup.pileSize() + ); + for (size_t j = 0; j < _gpuActiveLayers[i].gpuChunkTiles.size(); ++j) { + GPULayer::GPUChunkTile& t = _gpuActiveLayers[i].gpuChunkTiles[j]; + const ChunkTile& ct = ctp[j]; + + t.texUnit.activate(); + if (ct.tile.texture) { + ct.tile.texture->bind(); + } + program.setUniform(t.uniformCache.texture, t.texUnit); + + program.setUniform(t.uniformCache.uvOffset, ct.uvTransform.uvOffset); + program.setUniform(t.uniformCache.uvScale, ct.uvTransform.uvScale); + } + + program.setUniform(galuc.paddingStartOffset, al.tilePixelStartOffset()); + program.setUniform( + galuc.paddingSizeDifference, + al.tilePixelSizeDifference() + ); + break; + } + case layergroupid::TypeID::SolidColor: + program.setUniform(galuc.color, al.solidColor()); + break; + default: + break; + } + + if (gal.isHeightLayer) { + program.setUniform(galuc.depthOffset, al.depthTransform().offset); + program.setUniform(galuc.depthScale, al.depthTransform().scale); + } + } +} + +void GPULayerGroup::bind(ghoul::opengl::ProgramObject& p, + const LayerGroup& layerGroup, const std::string& nameBase, + int category) +{ + const std::vector& activeLayers = layerGroup.activeLayers(); + _gpuActiveLayers.resize(activeLayers.size()); + const int pileSize = layerGroup.pileSize(); + for (size_t i = 0; i < _gpuActiveLayers.size(); ++i) { + GPULayer& gal = _gpuActiveLayers[i]; + auto& galuc = gal.uniformCache; + const Layer& al = *activeLayers[i]; + std::string name = nameBase + "[" + std::to_string(i) + "]."; + + if (category == layergroupid::GroupID::HeightLayers) { + gal.isHeightLayer = true; + } + + galuc.opacity = p.uniformLocation(name + "settings.opacity"); + galuc.gamma = p.uniformLocation(name + "settings.gamma"); + galuc.multiplier = p.uniformLocation(name + "settings.multiplier"); + galuc.offset = p.uniformLocation(name + "settings.offset"); + + if (al.layerAdjustment().type() == layergroupid::AdjustmentTypeID::ChromaKey) { + galuc.chromaKeyColor = p.uniformLocation( + name + "adjustment.chromaKeyColor" + ); + galuc.chromaKeyTolerance = p.uniformLocation( + name + "adjustment.chromaKeyTolerance" + ); + } + + switch (al.type()) { + // Intentional fall through. Same for all tile layers + case layergroupid::TypeID::DefaultTileLayer: + case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SizeReferenceTileLayer: + case layergroupid::TypeID::TemporalTileLayer: + case layergroupid::TypeID::TileIndexTileLayer: + case layergroupid::TypeID::ByIndexTileLayer: + case layergroupid::TypeID::ByLevelTileLayer: { + gal.gpuChunkTiles.resize(pileSize); + for (size_t j = 0; j < gal.gpuChunkTiles.size(); ++j) { + GPULayer::GPUChunkTile& t = gal.gpuChunkTiles[j]; + auto& tuc = t.uniformCache; + std::string n = name + "pile.chunkTile" + std::to_string(j) + "."; + + tuc.texture = p.uniformLocation(n + "textureSampler"); + tuc.uvOffset = p.uniformLocation(n + "uvTransform.uvOffset"); + tuc.uvScale = p.uniformLocation(n + "uvTransform.uvScale"); + } + + galuc.paddingStartOffset = p.uniformLocation( + name + "padding.startOffset" + ); + galuc.paddingSizeDifference = p.uniformLocation( + name + "padding.sizeDifference" + ); + + break; + } + case layergroupid::TypeID::SolidColor: + galuc.color = p.uniformLocation(name + "color"); + break; + default: + break; + } + + if (gal.isHeightLayer) { + galuc.depthOffset = p.uniformLocation(name + "depthTransform.depthOffset"); + galuc.depthScale = p.uniformLocation(name + "depthTransform.depthScale"); + } + } +} + +void GPULayerGroup::deactivate() { + for (GPULayer& gal : _gpuActiveLayers) { + for (GPULayer::GPUChunkTile& t : gal.gpuChunkTiles) { + t.texUnit.deactivate(); + } + } +} + +} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gpulayergroup.h b/modules/globebrowsing/src/gpulayergroup.h similarity index 81% rename from modules/globebrowsing/rendering/gpu/gpulayergroup.h rename to modules/globebrowsing/src/gpulayergroup.h index efadb55efb..31961697d4 100644 --- a/modules/globebrowsing/rendering/gpu/gpulayergroup.h +++ b/modules/globebrowsing/src/gpulayergroup.h @@ -25,6 +25,8 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYERGROUP___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYERGROUP___H__ +#include +#include #include #include #include @@ -36,7 +38,6 @@ namespace openspace::globebrowsing { struct ChunkTile; class Layer; class GPULayer; -struct LayerRenderSettings; struct TileDepthTransform; struct TileUvTransform; @@ -48,14 +49,12 @@ struct TileIndex; */ class GPULayerGroup { public: - virtual ~GPULayerGroup(); - /** * Sets the value of LayerGroup to its corresponding * GPU struct. OBS! Users must ensure bind has been * called before setting using this method. */ - virtual void setValue(ghoul::opengl::ProgramObject* programObject, + void setValue(ghoul::opengl::ProgramObject& programObject, const LayerGroup& layerGroup, const TileIndex& tileIndex); /** @@ -63,17 +62,31 @@ public: * with nameBase within the provided shader program. * After this method has been called, users may invoke setValue. */ - virtual void bind(ghoul::opengl::ProgramObject* programObject, + void bind(ghoul::opengl::ProgramObject& programObject, const LayerGroup& layerGroup, const std::string& nameBase, int category); /** * Deactivates any TextureUnits assigned by this object. * This method should be called after the OpenGL draw call. */ - virtual void deactivate(); + void deactivate(); private: - std::vector> _gpuActiveLayers; + struct GPULayer { + struct GPUChunkTile { + ghoul::opengl::TextureUnit texUnit; + UniformCache(texture, uvOffset, uvScale) uniformCache; + }; + std::vector gpuChunkTiles; + + UniformCache(opacity, gamma, multiplier, offset, valueBlending, chromaKeyColor, + chromaKeyTolerance, paddingStartOffset, paddingSizeDifference, color, + depthOffset, depthScale) uniformCache; + + bool isHeightLayer = false; + }; + + std::vector _gpuActiveLayers; }; } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/layer/layer.cpp b/modules/globebrowsing/src/layer.cpp similarity index 63% rename from modules/globebrowsing/rendering/layer/layer.cpp rename to modules/globebrowsing/src/layer.cpp index 1a77bc1cc5..ac0064c9fc 100644 --- a/modules/globebrowsing/rendering/layer/layer.cpp +++ b/modules/globebrowsing/src/layer.cpp @@ -22,13 +22,12 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include -#include -#include -#include -#include -#include +#include +#include +#include +#include #include namespace openspace::globebrowsing { @@ -36,16 +35,20 @@ namespace openspace::globebrowsing { namespace { constexpr const char* _loggerCat = "Layer"; - constexpr const char* keyIdentifier = "Identifier"; - constexpr const char* keyName = "Name"; - constexpr const char* keyDescription = "Description"; - constexpr const char* keyEnabled = "Enabled"; - constexpr const char* keyLayerGroupID = "LayerGroupID"; - constexpr const char* keySettings = "Settings"; - constexpr const char* keyAdjustment = "Adjustment"; - constexpr const char* KeyBlendMode = "BlendMode"; + constexpr const char* KeyIdentifier = "Identifier"; + constexpr const char* KeyName = "Name"; + constexpr const char* KeyDesc = "Description"; + constexpr const char* KeyLayerGroupID = "LayerGroupID"; + constexpr const char* KeySettings = "Settings"; + constexpr const char* KeyAdjustment = "Adjustment"; constexpr const char* KeyPadTiles = "PadTiles"; + constexpr const char* KeyOpacity = "Opacity"; + constexpr const char* KeyGamma = "Gamma"; + constexpr const char* KeyMultiplier = "Multiplier"; + constexpr const char* KeyOffset = "Offset"; + + constexpr openspace::properties::Property::PropertyInfo TypeInfo = { "Type", "Type", @@ -93,11 +96,9 @@ namespace { Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, LayerGroup& parent) : properties::PropertyOwner({ - layerDict.value(keyIdentifier), - layerDict.hasKey(keyName) ? layerDict.value(keyName) : "", - layerDict.hasKey(keyDescription) ? - layerDict.value(keyDescription) : - "" + layerDict.value(KeyIdentifier), + layerDict.hasKey(KeyName) ? layerDict.value(KeyName) : "", + layerDict.hasKey(KeyDesc) ? layerDict.value(KeyDesc) : "" }) , _parent(parent) , _typeOption(TypeInfo, properties::OptionProperty::DisplayType::Dropdown) @@ -105,42 +106,58 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, , _enabled(EnabledInfo, false) , _reset(ResetInfo) , _remove(RemoveInfo) - , _otherTypesProperties({ - { ColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f) } - }) + , _solidColor(ColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f)) , _layerGroupId(id) { - layergroupid::TypeID typeID = parseTypeIdFromDictionary(layerDict); + layergroupid::TypeID typeID; + if (layerDict.hasKeyAndValue("Type")) { + const std::string& typeString = layerDict.value("Type"); + typeID = ghoul::from_string(typeString); + } + else { + typeID = layergroupid::TypeID::DefaultTileLayer; + } if (typeID == layergroupid::TypeID::Unknown) { throw ghoul::RuntimeError("Unknown layer type!"); } initializeBasedOnType(typeID, layerDict); - bool enabled = false; // defaults to false if unspecified - layerDict.getValue(keyEnabled, enabled); - _enabled.setValue(enabled); - - bool padTiles = true; - layerDict.getValue(KeyPadTiles, padTiles); - - TileTextureInitData initData = LayerManager::getTileTextureInitData( - _layerGroupId, - LayerManager::PadTiles(padTiles) - ); - _padTilePixelStartOffset = initData.tilePixelStartOffset(); - _padTilePixelSizeDifference = initData.tilePixelSizeDifference(); - - // Initialize settings - ghoul::Dictionary settingsDict; - if (layerDict.getValue(keySettings, settingsDict)) { - _renderSettings.setValuesFromDictionary(settingsDict); + if (layerDict.hasKeyAndValue(EnabledInfo.identifier)) { + _enabled = layerDict.value(EnabledInfo.identifier); } - // Initiallize layer adjustment - ghoul::Dictionary adjustmentDict; - if (layerDict.getValue(keyAdjustment, adjustmentDict)) { - _layerAdjustment.setValuesFromDictionary(adjustmentDict); + bool padTiles = true; + if (layerDict.hasKeyAndValue(KeyPadTiles)) { + padTiles = layerDict.value(KeyPadTiles); + } + + TileTextureInitData initData = tileTextureInitData(_layerGroupId, padTiles); + _padTilePixelStartOffset = initData.tilePixelStartOffset; + _padTilePixelSizeDifference = initData.tilePixelSizeDifference; + + if (layerDict.hasKeyAndValue(KeySettings)) { + ghoul::Dictionary dict = layerDict.value(KeySettings); + if (dict.hasKeyAndValue(KeyOpacity)) { + _renderSettings.opacity = dict.value(KeyOpacity); + } + + if (dict.hasKeyAndValue(KeyGamma)) { + _renderSettings.gamma = dict.value(KeyGamma); + } + + if (dict.hasKeyAndValue(KeyMultiplier)) { + _renderSettings.multiplier = dict.value(KeyMultiplier); + } + + if (dict.hasKeyAndValue(KeyOffset)) { + _renderSettings.offset = dict.value(KeyOffset); + } + } + if (layerDict.hasKeyAndValue(KeyAdjustment)) { + _layerAdjustment.setValuesFromDictionary( + layerDict.value(KeyAdjustment) + ); } // Add options to option properties @@ -155,10 +172,10 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, } // Initialize blend mode - std::string blendModeName; - if (layerDict.getValue(KeyBlendMode, blendModeName)) { - layergroupid::BlendModeID blendModeID = - layergroupid::getBlendModeIDFromName(blendModeName); + if (layerDict.hasKeyAndValue(BlendModeInfo.identifier)) { + using namespace layergroupid; + std::string blendMode = layerDict.value(BlendModeInfo.identifier); + BlendModeID blendModeID = ghoul::from_string(blendMode); _blendModeOption = static_cast(blendModeID); } else { @@ -174,14 +191,14 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, _reset.onChange([&]() { if (_tileProvider) { - _tileProvider->reset(); + tileprovider::reset(*_tileProvider); } }); _remove.onChange([&]() { try { if (_tileProvider) { - _tileProvider->reset(); + tileprovider::reset(*_tileProvider); } } catch (...) { @@ -191,10 +208,28 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, }); _typeOption.onChange([&]() { - removeVisibleProperties(); + switch (type()) { + // Intentional fall through. Same for all tile layers + case layergroupid::TypeID::DefaultTileLayer: + case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SizeReferenceTileLayer: + case layergroupid::TypeID::TemporalTileLayer: + case layergroupid::TypeID::TileIndexTileLayer: + case layergroupid::TypeID::ByIndexTileLayer: + case layergroupid::TypeID::ByLevelTileLayer: + if (_tileProvider) { + removePropertySubOwner(*_tileProvider); + } + break; + case layergroupid::TypeID::SolidColor: + removeProperty(_solidColor); + break; + default: + break; + } + _type = static_cast(_typeOption.value()); - ghoul::Dictionary dict; - initializeBasedOnType(type(), dict); + initializeBasedOnType(type(), {}); addVisibleProperties(); if (_onChangeCallback) { _onChangeCallback(); @@ -222,7 +257,7 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, addProperty(_reset); addProperty(_remove); - _otherTypesProperties.color.setViewOption(properties::Property::ViewOptions::Color); + _solidColor.setViewOption(properties::Property::ViewOptions::Color); addVisibleProperties(); @@ -232,25 +267,25 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, void Layer::initialize() { if (_tileProvider) { - _tileProvider->initialize(); + tileprovider::initialize(*_tileProvider); } } void Layer::deinitialize() { if (_tileProvider) { - _tileProvider->deinitialize(); + tileprovider::deinitialize(*_tileProvider); } } ChunkTilePile Layer::chunkTilePile(const TileIndex& tileIndex, int pileSize) const { if (_tileProvider) { - return _tileProvider->chunkTilePile(tileIndex, pileSize); + return tileprovider::chunkTilePile(*_tileProvider, tileIndex, pileSize); } else { ChunkTilePile chunkTilePile; chunkTilePile.resize(pileSize); for (int i = 0; i < pileSize; ++i) { - chunkTilePile[i].tile = Tile::TileUnavailable; + chunkTilePile[i].tile = Tile(); chunkTilePile[i].uvTransform.uvOffset = { 0, 0 }; chunkTilePile[i].uvTransform.uvScale = { 1, 1 }; } @@ -259,12 +294,9 @@ ChunkTilePile Layer::chunkTilePile(const TileIndex& tileIndex, int pileSize) con } Tile::Status Layer::tileStatus(const TileIndex& index) const { - if (_tileProvider) { - return _tileProvider->tileStatus(index); - } - else { - return Tile::Status::Unavailable; - } + return _tileProvider ? + tileprovider::tileStatus(*_tileProvider, index) : + Tile::Status::Unavailable; } layergroupid::TypeID Layer::type() const { @@ -276,12 +308,9 @@ layergroupid::BlendModeID Layer::blendMode() const { } TileDepthTransform Layer::depthTransform() const { - if (_tileProvider) { - return _tileProvider->depthTransform(); - } - else { - return { 1.f, 0.f }; - } + return _tileProvider ? + tileprovider::depthTransform(*_tileProvider) : + TileDepthTransform{ 1.f, 0.f }; } bool Layer::enabled() const { @@ -292,8 +321,8 @@ tileprovider::TileProvider* Layer::tileProvider() const { return _tileProvider.get(); } -const Layer::OtherTypesProperties& Layer::otherTypesProperties() const { - return _otherTypesProperties; +glm::vec3 Layer::solidColor() const { + return _solidColor; } const LayerRenderSettings& Layer::renderSettings() const { @@ -310,7 +339,7 @@ void Layer::onChange(std::function callback) { void Layer::update() { if (_tileProvider) { - _tileProvider->update(); + tileprovider::update(*_tileProvider); } } @@ -322,44 +351,21 @@ glm::ivec2 Layer::tilePixelSizeDifference() const { return _padTilePixelSizeDifference; } -glm::vec2 Layer::compensateSourceTextureSampling(glm::vec2 startOffset, - glm::vec2 sizeDiff, - glm::uvec2 resolution, glm::vec2 tileUV) -{ - const glm::vec2 sourceSize = glm::vec2(resolution) + sizeDiff; - const glm::vec2 currentSize = glm::vec2(resolution); - const glm::vec2 sourceToCurrentSize = currentSize / sourceSize; - tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize); - return tileUV; -} - -glm::vec2 Layer::TileUvToTextureSamplePosition(const TileUvTransform& uvTransform, - glm::vec2 tileUV, glm::uvec2 resolution) +glm::vec2 Layer::tileUvToTextureSamplePosition(const TileUvTransform& uvTransform, + const glm::vec2& tileUV, + const glm::uvec2& resolution) { glm::vec2 uv = uvTransform.uvOffset + uvTransform.uvScale * tileUV; - uv = compensateSourceTextureSampling( - tilePixelStartOffset(), - tilePixelSizeDifference(), - resolution, - uv); - return uv; + + const glm::vec2 sourceSize = glm::vec2(resolution) + + glm::vec2(_padTilePixelSizeDifference); + const glm::vec2 currentSize = glm::vec2(resolution); + const glm::vec2 sourceToCurrentSize = currentSize / sourceSize; + return sourceToCurrentSize * (uv - glm::vec2(_padTilePixelStartOffset) / sourceSize); } -layergroupid::TypeID Layer::parseTypeIdFromDictionary( - const ghoul::Dictionary& initDict) const -{ - if (initDict.hasKeyAndValue("Type")) { - const std::string& typeString = initDict.value("Type"); - return layergroupid::getTypeIDFromTypeString(typeString); - } - else { - return layergroupid::TypeID::DefaultTileLayer; - } -} - -void Layer::initializeBasedOnType(layergroupid::TypeID typeId, ghoul::Dictionary initDict) -{ - switch (typeId) { +void Layer::initializeBasedOnType(layergroupid::TypeID id, ghoul::Dictionary initDict) { + switch (id) { // Intentional fall through. Same for all tile layers case layergroupid::TypeID::DefaultTileLayer: case layergroupid::TypeID::SingleImageTileLayer: @@ -370,30 +376,24 @@ void Layer::initializeBasedOnType(layergroupid::TypeID typeId, ghoul::Dictionary case layergroupid::TypeID::ByLevelTileLayer: { // We add the id to the dictionary since it needs to be known by // the tile provider - initDict.setValue(keyLayerGroupID, _layerGroupId); - if (initDict.hasKeyAndValue(keyName)) { - std::string name; - initDict.getValue(keyName, name); + initDict.setValue(KeyLayerGroupID, _layerGroupId); + if (initDict.hasKeyAndValue(KeyName)) { + std::string name = initDict.value(KeyName); LDEBUG("Initializing tile provider for layer: '" + name + "'"); } - _tileProvider = std::shared_ptr( - tileprovider::TileProvider::createFromDictionary( - typeId, - std::move(initDict) - ) + _tileProvider = std::unique_ptr( + tileprovider::createFromDictionary(id, std::move(initDict)) ); break; } case layergroupid::TypeID::SolidColor: { if (initDict.hasKeyAndValue(ColorInfo.identifier)) { - glm::vec3 color; - initDict.getValue(ColorInfo.identifier, color); - _otherTypesProperties.color.setValue(color); + _solidColor = initDict.value(ColorInfo.identifier); } break; } default: - throw ghoul::RuntimeError("Unable to create layer. Unknown type."); + throw ghoul::MissingCaseException(); } } @@ -413,7 +413,7 @@ void Layer::addVisibleProperties() { break; } case layergroupid::TypeID::SolidColor: { - addProperty(_otherTypesProperties.color); + addProperty(_solidColor); break; } default: @@ -421,26 +421,4 @@ void Layer::addVisibleProperties() { } } -void Layer::removeVisibleProperties() { - switch (type()) { - // Intentional fall through. Same for all tile layers - case layergroupid::TypeID::DefaultTileLayer: - case layergroupid::TypeID::SingleImageTileLayer: - case layergroupid::TypeID::SizeReferenceTileLayer: - case layergroupid::TypeID::TemporalTileLayer: - case layergroupid::TypeID::TileIndexTileLayer: - case layergroupid::TypeID::ByIndexTileLayer: - case layergroupid::TypeID::ByLevelTileLayer: - if (_tileProvider) { - removePropertySubOwner(*_tileProvider); - } - break; - case layergroupid::TypeID::SolidColor: - removeProperty(_otherTypesProperties.color); - break; - default: - break; - } -} - } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/layer/layer.h b/modules/globebrowsing/src/layer.h similarity index 78% rename from modules/globebrowsing/rendering/layer/layer.h rename to modules/globebrowsing/src/layer.h index 476fdb0935..b0ed749a39 100644 --- a/modules/globebrowsing/rendering/layer/layer.h +++ b/modules/globebrowsing/src/layer.h @@ -27,11 +27,10 @@ #include -#include -#include -#include -#include - +#include +#include +#include +#include #include #include @@ -39,20 +38,11 @@ namespace openspace::globebrowsing { struct LayerGroup; struct TileIndex; -struct TileDepthTransform; -namespace tileprovider { class TileProvider; } +namespace tileprovider { struct TileProvider; } class Layer : public properties::PropertyOwner { public: - /** - * Properties used when the layer type is not a tile type layer. These properties - * can be added or removed depending on the layer type. - */ - struct OtherTypesProperties { - properties::Vec3Property color; - }; - Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, LayerGroup& parent); @@ -67,7 +57,7 @@ public: TileDepthTransform depthTransform() const; bool enabled() const; tileprovider::TileProvider* tileProvider() const; - const OtherTypesProperties& otherTypesProperties() const; + glm::vec3 solidColor() const; const LayerRenderSettings& renderSettings() const; const LayerAdjustment& layerAdjustment() const; @@ -77,18 +67,12 @@ public: glm::ivec2 tilePixelStartOffset() const; glm::ivec2 tilePixelSizeDifference() const; - glm::vec2 compensateSourceTextureSampling(glm::vec2 startOffset, glm::vec2 sizeDiff, - glm::uvec2 resolution, glm::vec2 tileUV); - glm::vec2 TileUvToTextureSamplePosition(const TileUvTransform& uvTransform, - glm::vec2 tileUV, glm::uvec2 resolution); + glm::vec2 tileUvToTextureSamplePosition(const TileUvTransform& uvTransform, + const glm::vec2& tileUV, const glm::uvec2& resolution); private: - layergroupid::TypeID parseTypeIdFromDictionary( - const ghoul::Dictionary& initDict) const; - void initializeBasedOnType(layergroupid::TypeID typeId, ghoul::Dictionary initDict); void addVisibleProperties(); - void removeVisibleProperties(); LayerGroup& _parent; @@ -99,8 +83,8 @@ private: properties::TriggerProperty _remove; layergroupid::TypeID _type; - std::shared_ptr _tileProvider; - OtherTypesProperties _otherTypesProperties; + std::unique_ptr _tileProvider; + properties::Vec3Property _solidColor; LayerRenderSettings _renderSettings; LayerAdjustment _layerAdjustment; diff --git a/modules/globebrowsing/rendering/layer/layeradjustment.cpp b/modules/globebrowsing/src/layeradjustment.cpp similarity index 82% rename from modules/globebrowsing/rendering/layer/layeradjustment.cpp rename to modules/globebrowsing/src/layeradjustment.cpp index bdde0efbdd..7a51e51721 100644 --- a/modules/globebrowsing/rendering/layer/layeradjustment.cpp +++ b/modules/globebrowsing/src/layeradjustment.cpp @@ -22,12 +22,12 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include namespace { - constexpr const char* keyType = "Type"; - constexpr const char* keyChromaKeyColor = "ChromaKeyColor"; - constexpr const char* keyChromaKeyTolerance = "ChromaKeyTolerance"; + constexpr const char* KeyType = "Type"; + constexpr const char* KeyChromaKeyColor = "ChromaKeyColor"; + constexpr const char* KeyChromaKeyTolerance = "ChromaKeyTolerance"; constexpr openspace::properties::Property::PropertyInfo ChromaKeyColorInfo = { "ChromaKeyColor", @@ -65,7 +65,17 @@ LayerAdjustment::LayerAdjustment() _type = static_cast(_typeOption.value()); _typeOption.onChange([&]() { - removeVisibleProperties(); + switch (type()) { + case layergroupid::AdjustmentTypeID::None: + break; + case layergroupid::AdjustmentTypeID::ChromaKey: { + removeProperty(_chromaKeyColor); + removeProperty(_chromaKeyTolerance); + break; + } + case layergroupid::AdjustmentTypeID::TransferFunction: + break; + } _type = static_cast(_typeOption.value()); addVisibleProperties(); if (_onChangeCallback) { @@ -79,21 +89,20 @@ LayerAdjustment::LayerAdjustment() } void LayerAdjustment::setValuesFromDictionary(const ghoul::Dictionary& adjustmentDict) { - if (adjustmentDict.hasKeyAndValue(keyType)) { - const std::string& dictType = adjustmentDict.value(keyType); + if (adjustmentDict.hasKeyAndValue(KeyType)) { + std::string dictType = adjustmentDict.value(KeyType); _typeOption = static_cast( - layergroupid::getAdjustmentTypeIDFromName(dictType) + ghoul::from_string(dictType) ); - } - if (adjustmentDict.hasKeyAndValue(keyChromaKeyColor)) { - glm::vec3 dictChromaKeyColor = adjustmentDict.value(keyChromaKeyColor); + if (adjustmentDict.hasKeyAndValue(KeyChromaKeyColor)) { + glm::vec3 dictChromaKeyColor = adjustmentDict.value(KeyChromaKeyColor); _chromaKeyColor = std::move(dictChromaKeyColor); } - if (adjustmentDict.hasKeyAndValue(keyChromaKeyTolerance)) { - float dictChromaKeyTolerance = adjustmentDict.value(keyChromaKeyTolerance); + if (adjustmentDict.hasKeyAndValue(KeyChromaKeyTolerance)) { + float dictChromaKeyTolerance = adjustmentDict.value(KeyChromaKeyTolerance); _chromaKeyTolerance = dictChromaKeyTolerance; } } @@ -116,20 +125,6 @@ void LayerAdjustment::addVisibleProperties() { } } -void LayerAdjustment::removeVisibleProperties() { - switch (type()) { - case layergroupid::AdjustmentTypeID::None: - break; - case layergroupid::AdjustmentTypeID::ChromaKey: { - removeProperty(_chromaKeyColor); - removeProperty(_chromaKeyTolerance); - break; - } - case layergroupid::AdjustmentTypeID::TransferFunction: - break; - } -} - glm::vec3 LayerAdjustment::chromaKeyColor() const { return _chromaKeyColor; } diff --git a/modules/globebrowsing/rendering/layer/layeradjustment.h b/modules/globebrowsing/src/layeradjustment.h similarity index 95% rename from modules/globebrowsing/rendering/layer/layeradjustment.h rename to modules/globebrowsing/src/layeradjustment.h index 9bc74ea944..3217eb4b89 100644 --- a/modules/globebrowsing/rendering/layer/layeradjustment.h +++ b/modules/globebrowsing/src/layeradjustment.h @@ -27,14 +27,14 @@ #include -#include +#include #include #include #include namespace openspace::globebrowsing { -namespace tileprovider { class TileProvider; } +namespace tileprovider { struct TileProvider; } class LayerAdjustment : public properties::PropertyOwner { public: @@ -52,7 +52,6 @@ public: private: void addVisibleProperties(); - void removeVisibleProperties(); properties::Vec3Property _chromaKeyColor; properties::FloatProperty _chromaKeyTolerance; diff --git a/modules/globebrowsing/rendering/layer/layergroup.cpp b/modules/globebrowsing/src/layergroup.cpp similarity index 81% rename from modules/globebrowsing/rendering/layer/layergroup.cpp rename to modules/globebrowsing/src/layergroup.cpp index aa673c001b..7cee7d67ed 100644 --- a/modules/globebrowsing/rendering/layer/layergroup.cpp +++ b/modules/globebrowsing/src/layergroup.cpp @@ -22,9 +22,9 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include -#include +#include #include namespace { @@ -54,9 +54,7 @@ LayerGroup::LayerGroup(layergroupid::GroupID id) addProperty(_levelBlendingEnabled); } -LayerGroup::LayerGroup(layergroupid::GroupID id, const ghoul::Dictionary& dict) - : LayerGroup(id) -{ +void LayerGroup::setLayersFromDict(const ghoul::Dictionary& dict) { for (size_t i = 1; i <= dict.size(); i++) { ghoul::Dictionary layerDict = dict.value(std::to_string(i)); @@ -75,7 +73,6 @@ LayerGroup::LayerGroup(layergroupid::GroupID id, const ghoul::Dictionary& dict) } catch (const ghoul::RuntimeError& except) { LERRORC(except.component, except.message); - continue; } } continue; @@ -84,13 +81,13 @@ LayerGroup::LayerGroup(layergroupid::GroupID id, const ghoul::Dictionary& dict) } void LayerGroup::initialize() { - for (const std::shared_ptr& l : _layers) { + for (const std::unique_ptr& l : _layers) { l->initialize(); } } void LayerGroup::deinitialize() { - for (const std::shared_ptr& l : _layers) { + for (const std::unique_ptr& l : _layers) { l->deinitialize(); } } @@ -98,40 +95,40 @@ void LayerGroup::deinitialize() { void LayerGroup::update() { _activeLayers.clear(); - for (const std::shared_ptr& layer : _layers) { + for (const std::unique_ptr& layer : _layers) { if (layer->enabled()) { layer->update(); - _activeLayers.push_back(layer); + _activeLayers.push_back(layer.get()); } } } -std::shared_ptr LayerGroup::addLayer(const ghoul::Dictionary& layerDict) { +Layer* LayerGroup::addLayer(const ghoul::Dictionary& layerDict) { if (!layerDict.hasKeyAndValue("Identifier")) { LERROR("'Identifier' must be specified for layer."); return nullptr; } - std::shared_ptr layer = std::make_shared(_groupId, layerDict, *this); + std::unique_ptr layer = std::make_unique(_groupId, layerDict, *this); layer->onChange(_onChangeCallback); if (hasPropertySubOwner(layer->identifier())) { LINFO("Layer with identifier " + layer->identifier() + " already exists."); _levelBlendingEnabled.setVisibility(properties::Property::Visibility::User); return nullptr; } - else { - _layers.push_back(layer); - //update(); - if (_onChangeCallback) { - _onChangeCallback(); - } - addPropertySubOwner(layer.get()); - _levelBlendingEnabled.setVisibility(properties::Property::Visibility::User); - return layer; + + Layer* ptr = layer.get(); + _layers.push_back(std::move(layer)); + update(); + if (_onChangeCallback) { + _onChangeCallback(); } + addPropertySubOwner(ptr); + _levelBlendingEnabled.setVisibility(properties::Property::Visibility::User); + return ptr; } void LayerGroup::deleteLayer(const std::string& layerName) { - for (std::vector>::iterator it = _layers.begin(); + for (std::vector>::iterator it = _layers.begin(); it != _layers.end(); ++it) { @@ -156,16 +153,21 @@ void LayerGroup::deleteLayer(const std::string& layerName) { LERROR("Could not find layer " + layerName); } -const std::vector>& LayerGroup::layers() const { - return _layers; +std::vector LayerGroup::layers() const { + std::vector res; + res.reserve(_layers.size()); + for (const std::unique_ptr& layer : _layers) { + res.push_back(layer.get()); + } + return res; } -const std::vector>& LayerGroup::activeLayers() const { +const std::vector& LayerGroup::activeLayers() const { return _activeLayers; } -int LayerGroup::pileSize() const{ - return _levelBlendingEnabled.value() ? 3 : 1; +int LayerGroup::pileSize() const { + return _levelBlendingEnabled ? 3 : 1; } bool LayerGroup::layerBlendingEnabled() const { @@ -175,7 +177,7 @@ bool LayerGroup::layerBlendingEnabled() const { void LayerGroup::onChange(std::function callback) { _onChangeCallback = std::move(callback); _levelBlendingEnabled.onChange(_onChangeCallback); - for (const std::shared_ptr& layer : _layers) { + for (const std::unique_ptr& layer : _layers) { layer->onChange(_onChangeCallback); } } diff --git a/modules/globebrowsing/rendering/layer/layergroup.h b/modules/globebrowsing/src/layergroup.h similarity index 86% rename from modules/globebrowsing/rendering/layer/layergroup.h rename to modules/globebrowsing/src/layergroup.h index d636775a35..e3b6d4aa0c 100644 --- a/modules/globebrowsing/rendering/layer/layergroup.h +++ b/modules/globebrowsing/src/layergroup.h @@ -27,21 +27,22 @@ #include -#include +#include #include namespace openspace::globebrowsing { class Layer; -namespace tileprovider { class TileProvider; } +namespace tileprovider { struct TileProvider; } /** * Convenience class for dealing with multiple Layers. */ struct LayerGroup : public properties::PropertyOwner { LayerGroup(layergroupid::GroupID id); - LayerGroup(layergroupid::GroupID id, const ghoul::Dictionary& dict); + + void setLayersFromDict(const ghoul::Dictionary& dict); void initialize(); void deinitialize(); @@ -49,14 +50,14 @@ struct LayerGroup : public properties::PropertyOwner { /// Updates all layers tile providers within this group void update(); - std::shared_ptr addLayer(const ghoul::Dictionary& layerDict); + Layer* addLayer(const ghoul::Dictionary& layerDict); void deleteLayer(const std::string& layerName); /// @returns const vector of all layers - const std::vector>& layers() const; + std::vector layers() const; /// @returns const vector of all active layers - const std::vector>& activeLayers() const; + const std::vector& activeLayers() const; /// @returns the size of the pile to be used in rendering of this layer int pileSize() const; @@ -67,8 +68,8 @@ struct LayerGroup : public properties::PropertyOwner { private: const layergroupid::GroupID _groupId; - std::vector> _layers; - std::vector> _activeLayers; + std::vector> _layers; + std::vector _activeLayers; properties::BoolProperty _levelBlendingEnabled; std::function _onChangeCallback; diff --git a/modules/globebrowsing/rendering/layer/layergroupid.cpp b/modules/globebrowsing/src/layergroupid.cpp similarity index 66% rename from modules/globebrowsing/rendering/layer/layergroupid.cpp rename to modules/globebrowsing/src/layergroupid.cpp index ebb9306f82..02953b78ba 100644 --- a/modules/globebrowsing/rendering/layer/layergroupid.cpp +++ b/modules/globebrowsing/src/layergroupid.cpp @@ -22,46 +22,53 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include -namespace openspace::globebrowsing::layergroupid { +using namespace openspace::globebrowsing::layergroupid; -TypeID getTypeIDFromTypeString(const std::string& typeString) { +namespace ghoul { + +template <> +TypeID from_string(const std::string& string) { for (int i = 0; i < NUM_LAYER_TYPES; ++i) { - if (typeString == LAYER_TYPE_NAMES[i]) { + if (string == LAYER_TYPE_NAMES[i]) { return static_cast(i); } } return TypeID::Unknown; } -layergroupid::GroupID getGroupIDFromName(const std::string& layerGroupName) { - for (int i = 0; i < layergroupid::NUM_LAYER_GROUPS; ++i) { - if (layerGroupName == layergroupid::LAYER_GROUP_IDENTIFIERS[i]) { - return static_cast(i); +template <> +openspace::globebrowsing::layergroupid::GroupID from_string(const std::string& string) { + for (int i = 0; i < NUM_LAYER_GROUPS; ++i) { + if (string == LAYER_GROUP_IDENTIFIERS[i]) { + return static_cast(i); } } return GroupID::Unknown; } -layergroupid::AdjustmentTypeID getAdjustmentTypeIDFromName( - const std::string& adjustmentTypeName) +template <> +openspace::globebrowsing::layergroupid::AdjustmentTypeID from_string( + const std::string& string) { - for (int i = 0; i < layergroupid::NUM_ADJUSTMENT_TYPES; ++i) { - if (adjustmentTypeName == layergroupid::ADJUSTMENT_TYPE_NAMES[i]) { - return static_cast(i); + for (int i = 0; i < NUM_ADJUSTMENT_TYPES; ++i) { + if (string == ADJUSTMENT_TYPE_NAMES[i]) { + return static_cast(i); } } return AdjustmentTypeID::None; } -layergroupid::BlendModeID getBlendModeIDFromName(const std::string& blendModeName) { - for (int i = 0; i < layergroupid::NUM_BLEND_MODES; ++i) { - if (blendModeName == layergroupid::BLEND_MODE_NAMES[i]) { - return static_cast(i); +template <> +openspace::globebrowsing::layergroupid::BlendModeID from_string(const std::string& string) +{ + for (int i = 0; i < NUM_BLEND_MODES; ++i) { + if (string == BLEND_MODE_NAMES[i]) { + return static_cast(i); } } return BlendModeID::Normal; } -} // namespace openspace::globebrowsing::layergroupid +} // namespace ghoul diff --git a/modules/globebrowsing/rendering/layer/layergroupid.h b/modules/globebrowsing/src/layergroupid.h similarity index 89% rename from modules/globebrowsing/rendering/layer/layergroupid.h rename to modules/globebrowsing/src/layergroupid.h index f851d85814..9e54d9eb05 100644 --- a/modules/globebrowsing/rendering/layer/layergroupid.h +++ b/modules/globebrowsing/src/layergroupid.h @@ -25,6 +25,7 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___LAYERGROUPID___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___LAYERGROUPID___H__ +#include #include namespace openspace::globebrowsing::layergroupid { @@ -118,16 +119,25 @@ enum class BlendModeID { Color = 4, }; -TypeID getTypeIDFromTypeString(const std::string& typeString); - -layergroupid::GroupID getGroupIDFromName(const std::string& layerGroupName); - -layergroupid::AdjustmentTypeID getAdjustmentTypeIDFromName( - const std::string& adjustmentTypeName); - -layergroupid::BlendModeID getBlendModeIDFromName( - const std::string& blendModeName); - } // namespace openspace::globebrowsing::layergroupid +namespace ghoul { + +template <> +openspace::globebrowsing::layergroupid::TypeID from_string(const std::string& string); + +template <> +openspace::globebrowsing::layergroupid::GroupID from_string(const std::string& string); + +template <> +openspace::globebrowsing::layergroupid::AdjustmentTypeID from_string( + const std::string& string); + +template <> +openspace::globebrowsing::layergroupid::BlendModeID from_string( + const std::string& string); + +} // ghoul + + #endif // __OPENSPACE_MODULE_GLOBEBROWSING___LAYERGROUPID___H__ diff --git a/modules/globebrowsing/src/layermanager.cpp b/modules/globebrowsing/src/layermanager.cpp new file mode 100644 index 0000000000..e8ea89ba5d --- /dev/null +++ b/modules/globebrowsing/src/layermanager.cpp @@ -0,0 +1,130 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +namespace openspace::globebrowsing { + +LayerManager::LayerManager() : properties::PropertyOwner({ "Layers" }) {} + +void LayerManager::initialize(const ghoul::Dictionary& layerGroupsDict) { + // First create empty layer groups in case not all are specified + for (size_t i = 0; i < _layerGroups.size(); ++i) { + _layerGroups[i] = std::make_unique(layergroupid::GroupID(i)); + } + + const std::vector& layerGroupNamesInDict = layerGroupsDict.keys(); + + // Create all the layer groups + for (const std::string& groupName : layerGroupNamesInDict) { + layergroupid::GroupID id = ghoul::from_string(groupName); + + if (id != layergroupid::GroupID::Unknown) { + ghoul::Dictionary d = layerGroupsDict.value(groupName); + _layerGroups[static_cast(id)]->setLayersFromDict(d); + } + else { + LWARNINGC("LayerManager", "Unknown layer group: " + groupName); + } + } + + for (const std::unique_ptr& layerGroup : _layerGroups) { + addPropertySubOwner(layerGroup.get()); + } + + for (const std::unique_ptr& lg : _layerGroups) { + lg->initialize(); + } +} + +void LayerManager::deinitialize() { + for (const std::unique_ptr& lg : _layerGroups) { + lg->deinitialize(); + } +} + +Layer* LayerManager::addLayer(layergroupid::GroupID groupId, + const ghoul::Dictionary& layerDict) +{ + ghoul_assert(groupId != layergroupid::Unknown, "Layer group ID must be known"); + return _layerGroups[groupId]->addLayer(layerDict); +} + +void LayerManager::deleteLayer(layergroupid::GroupID id, const std::string& layerName) { + ghoul_assert(id != layergroupid::Unknown, "Layer group ID must be known"); + _layerGroups[id]->deleteLayer(layerName); +} + +const LayerGroup& LayerManager::layerGroup(layergroupid::GroupID groupId) const { + return *_layerGroups[groupId]; +} + +bool LayerManager::hasAnyBlendingLayersEnabled() const { + return std::any_of( + _layerGroups.begin(), + _layerGroups.end(), + [](const std::unique_ptr& lg) { + return lg->layerBlendingEnabled() && !lg->activeLayers().empty(); + } + ); +} + +std::array LayerManager::layerGroups() const +{ + std::array res; + for (int i = 0; i < NumLayerGroups; ++i) { + res[i] = _layerGroups[i].get(); + } + return res; +} + +void LayerManager::update() { + for (std::unique_ptr& layerGroup : _layerGroups) { + layerGroup->update(); + } +} + +void LayerManager::reset(bool includeDisabled) { + for (std::unique_ptr& layerGroup : _layerGroups) { + for (Layer* layer : layerGroup->layers()) { + if (layer->enabled() || includeDisabled) { + tileprovider::reset(*layer->tileProvider()); + } + } + } +} + +void LayerManager::onChange(std::function callback) { + for (std::unique_ptr& layerGroup : _layerGroups) { + layerGroup->onChange(callback); + } +} + +} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/layer/layermanager.h b/modules/globebrowsing/src/layermanager.h similarity index 79% rename from modules/globebrowsing/rendering/layer/layermanager.h rename to modules/globebrowsing/src/layermanager.h index 75816c8c6c..336dde4a78 100644 --- a/modules/globebrowsing/rendering/layer/layermanager.h +++ b/modules/globebrowsing/src/layermanager.h @@ -27,10 +27,11 @@ #include -#include +#include #include -#include +#include #include +#include namespace ghoul { class Dictionary; } @@ -43,37 +44,32 @@ class TileTextureInitData; /** * Manages multiple LayerGroups. */ -class LayerManager : public properties::PropertyOwner { +class LayerManager : public properties::PropertyOwner { public: - BooleanType(PadTiles); + constexpr static const int NumLayerGroups = layergroupid::NUM_LAYER_GROUPS; - LayerManager(const ghoul::Dictionary& layerGroupsDict); + LayerManager(); - void initialize(); + void initialize(const ghoul::Dictionary& layerGroupsDict); void deinitialize(); - std::shared_ptr addLayer(layergroupid::GroupID groupId, + Layer* addLayer(layergroupid::GroupID groupId, const ghoul::Dictionary& layerDict); void deleteLayer(layergroupid::GroupID groupId, const std::string& layerName); - const LayerGroup& layerGroup(size_t groupId); - const LayerGroup& layerGroup(layergroupid::GroupID); + const LayerGroup& layerGroup(layergroupid::GroupID) const; bool hasAnyBlendingLayersEnabled() const; - const std::vector>& layerGroups() const; + std::array layerGroups() const; void update(); void reset(bool includeDisabled = false); - static TileTextureInitData getTileTextureInitData(layergroupid::GroupID id, - PadTiles padTiles, size_t preferredTileSize = 0); - - static bool shouldPerformPreProcessingOnLayergroup(layergroupid::GroupID id); void onChange(std::function callback); private: - std::vector> _layerGroups; + std::array, NumLayerGroups> _layerGroups; }; } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/rendering/layer/layerrendersettings.cpp b/modules/globebrowsing/src/layerrendersettings.cpp similarity index 77% rename from modules/globebrowsing/rendering/layer/layerrendersettings.cpp rename to modules/globebrowsing/src/layerrendersettings.cpp index 284fb8b140..06f8787e36 100644 --- a/modules/globebrowsing/rendering/layer/layerrendersettings.cpp +++ b/modules/globebrowsing/src/layerrendersettings.cpp @@ -22,14 +22,9 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include namespace { - constexpr const char* keyOpacity = "Opacity"; - constexpr const char* keyGamma = "Gamma"; - constexpr const char* keyMultiplier = "Multiplier"; - constexpr const char* keyOffset = "Offset"; - constexpr openspace::properties::Property::PropertyInfo SetDefaultInfo = { "SetDefault", "Set Default", @@ -70,11 +65,11 @@ namespace openspace::globebrowsing { LayerRenderSettings::LayerRenderSettings() : properties::PropertyOwner({ "Settings" }) - , setDefault(SetDefaultInfo) , opacity(OpacityInfo, 1.f, 0.f, 1.f) , gamma(GammaInfo, 1.f, 0.f, 5.f) , multiplier(MultiplierInfo, 1.f, 0.f, 20.f) , offset(OffsetInfo, 0.f, -10000.f, 10000.f) + , setDefault(SetDefaultInfo) { addProperty(opacity); addProperty(gamma); @@ -90,33 +85,12 @@ LayerRenderSettings::LayerRenderSettings() }); } -void LayerRenderSettings::setValuesFromDictionary( - const ghoul::Dictionary& renderSettingsDict) -{ - if (renderSettingsDict.hasKeyAndValue(keyOpacity)) { - opacity = renderSettingsDict.value(keyOpacity); - } - - if (renderSettingsDict.hasKeyAndValue(keyGamma)) { - gamma = renderSettingsDict.value(keyGamma); - } - - if (renderSettingsDict.hasKeyAndValue(keyMultiplier)) { - multiplier = renderSettingsDict.value(keyMultiplier); - } - - if (renderSettingsDict.hasKeyAndValue(keyOffset)) { - offset = renderSettingsDict.value(keyOffset); - } +float LayerRenderSettings::performLayerSettings(float v) const { + return + ((glm::sign(v) * glm::pow(glm::abs(v), gamma) * multiplier) + offset) * opacity; } -float LayerRenderSettings::performLayerSettings(float value) const { - return ((glm::sign(value) * glm::pow(glm::abs(value), gamma) * multiplier) + - offset) * - opacity; -} - -glm::vec4 LayerRenderSettings::performLayerSettings(glm::vec4 currentValue) const { +glm::vec4 LayerRenderSettings::performLayerSettings(const glm::vec4& currentValue) const { glm::vec4 newValue = glm::vec4( performLayerSettings(currentValue.r), performLayerSettings(currentValue.g), diff --git a/modules/globebrowsing/rendering/layer/layerrendersettings.h b/modules/globebrowsing/src/layerrendersettings.h similarity index 95% rename from modules/globebrowsing/rendering/layer/layerrendersettings.h rename to modules/globebrowsing/src/layerrendersettings.h index 79e71b1a70..7fd042ac69 100644 --- a/modules/globebrowsing/rendering/layer/layerrendersettings.h +++ b/modules/globebrowsing/src/layerrendersettings.h @@ -35,21 +35,18 @@ namespace openspace::globebrowsing { struct LayerRenderSettings : public properties::PropertyOwner { LayerRenderSettings(); - properties::TriggerProperty setDefault; - properties::FloatProperty opacity; properties::FloatProperty gamma; properties::FloatProperty multiplier; properties::FloatProperty offset; - - void setValuesFromDictionary(const ghoul::Dictionary& renderSettingsDict); + properties::TriggerProperty setDefault; /// This function matches the function with the same name in the /// shader code float performLayerSettings(float value) const; /// This function matches the function with the same name in the /// shader code - glm::vec4 performLayerSettings(glm::vec4 currentValue) const; + glm::vec4 performLayerSettings(const glm::vec4& currentValue) const; }; } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/cache/lrucache.h b/modules/globebrowsing/src/lrucache.h similarity index 98% rename from modules/globebrowsing/cache/lrucache.h rename to modules/globebrowsing/src/lrucache.h index 735b29ec5d..a53de0bcd1 100644 --- a/modules/globebrowsing/cache/lrucache.h +++ b/modules/globebrowsing/src/lrucache.h @@ -85,6 +85,6 @@ private: } // namespace openspace::globebrowsing::cache -#include +#include #endif // __OPENSPACE_MODULE_GLOBEBROWSING___LRU_CACHE___H__ diff --git a/modules/globebrowsing/cache/lrucache.inl b/modules/globebrowsing/src/lrucache.inl similarity index 100% rename from modules/globebrowsing/cache/lrucache.inl rename to modules/globebrowsing/src/lrucache.inl diff --git a/modules/globebrowsing/other/lruthreadpool.h b/modules/globebrowsing/src/lruthreadpool.h similarity index 93% rename from modules/globebrowsing/other/lruthreadpool.h rename to modules/globebrowsing/src/lruthreadpool.h index eb1a2be64c..47777df450 100644 --- a/modules/globebrowsing/other/lruthreadpool.h +++ b/modules/globebrowsing/src/lruthreadpool.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___LRU_THREAD_POOL___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___LRU_THREAD_POOL___H__ -#include +#include #include #include #include @@ -53,10 +53,10 @@ private: * recently enqueued task is the one that will be executed first. This class is templated * on a key type which used as an identifier to determine wheter or not a task with the * given key has been enqueued or not. This means that a task can be enqueued several - * times. The user must ensure that an enqueued task with a given key should be - * equal in outcome to a second enqueued task with the same key. This is because a second - * enqueued task with the same key will simply be bumped and prioritised before other - * enqueued tasks. The given task will be ignored. + * times. The user must ensure that an enqueued task with a given key should be equal in + * outcome to a second enqueued task with the same key. This is because a second enqueued + * task with the same key will simply be bumped and prioritised before other enqueued + * tasks. The given task will be ignored. */ template class LRUThreadPool { diff --git a/modules/globebrowsing/other/lruthreadpool.inl b/modules/globebrowsing/src/lruthreadpool.inl similarity index 97% rename from modules/globebrowsing/other/lruthreadpool.inl rename to modules/globebrowsing/src/lruthreadpool.inl index 92751799c6..b1c39fe9b4 100644 --- a/modules/globebrowsing/other/lruthreadpool.inl +++ b/modules/globebrowsing/src/lruthreadpool.inl @@ -35,7 +35,7 @@ void LRUThreadPoolWorker::operator()() { while (true) { // acquire lock { - std::unique_lock lock(_pool._queueMutex); + std::unique_lock lock(_pool._queueMutex); // look for a work item while (!_pool._stop && _pool._queuedTasks.isEmpty()) { @@ -75,7 +75,7 @@ LRUThreadPool::LRUThreadPool(const LRUThreadPool& toCopy) template LRUThreadPool::~LRUThreadPool() { { - std::unique_lock lock(_queueMutex); + std::unique_lock lock(_queueMutex); _stop = true; } _condition.notify_all(); diff --git a/modules/globebrowsing/cache/memoryawaretilecache.cpp b/modules/globebrowsing/src/memoryawaretilecache.cpp similarity index 61% rename from modules/globebrowsing/cache/memoryawaretilecache.cpp rename to modules/globebrowsing/src/memoryawaretilecache.cpp index 2d615c25db..10b5a6ecd5 100644 --- a/modules/globebrowsing/cache/memoryawaretilecache.cpp +++ b/modules/globebrowsing/src/memoryawaretilecache.cpp @@ -22,11 +22,11 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include -#include -#include -#include +#include +#include +#include #include #include #include @@ -66,17 +66,191 @@ namespace { "" // @TODO Missing documentation }; - constexpr openspace::properties::Property::PropertyInfo UsePboInfo = { - "UsePbo", - "Use PBO", - "If this value is enabled, pixel buffer objects are used to upload the texture " - "data asynchronously. If this value is disabled, the upload is synchronously." - }; + GLenum toGlTextureFormat(GLenum glType, ghoul::opengl::Texture::Format format) { + switch (format) { + case ghoul::opengl::Texture::Format::Red: + switch (glType) { + case GL_BYTE: + return GL_R8; + case GL_UNSIGNED_BYTE: + return GL_R8; + case GL_INT: + return GL_R32I; + case GL_UNSIGNED_INT: + return GL_R32UI; + case GL_FLOAT: + return GL_R32F; + case GL_HALF_FLOAT: + return GL_R16F; + default: + ghoul_assert(false, "glType data type unknown"); + throw ghoul::MissingCaseException(); + } + case ghoul::opengl::Texture::Format::RG: + switch (glType) { + case GL_BYTE: + return GL_RG8; + case GL_UNSIGNED_BYTE: + return GL_RG8; + case GL_INT: + return GL_RG32I; + case GL_UNSIGNED_INT: + return GL_RG32UI; + case GL_FLOAT: + return GL_RG32F; + case GL_HALF_FLOAT: + return GL_RG16F; + default: + ghoul_assert(false, "glType data type unknown"); + throw ghoul::MissingCaseException(); + } + case ghoul::opengl::Texture::Format::RGB: + switch (glType) { + case GL_BYTE: + return GL_RGB8; + case GL_UNSIGNED_BYTE: + return GL_RGB8; + case GL_INT: + return GL_RGB32I; + case GL_UNSIGNED_INT: + return GL_RGB32UI; + case GL_FLOAT: + return GL_RGB32F; + case GL_HALF_FLOAT: + return GL_RGB16F; + default: + ghoul_assert(false, "glType data type unknown"); + throw ghoul::MissingCaseException(); + } + case ghoul::opengl::Texture::Format::RGBA: + switch (glType) { + case GL_BYTE: + return GL_RGBA8; + case GL_UNSIGNED_BYTE: + return GL_RGBA8; + case GL_INT: + return GL_RGBA32I; + case GL_UNSIGNED_INT: + return GL_RGBA32UI; + case GL_FLOAT: + return GL_RGBA32F; + case GL_HALF_FLOAT: + return GL_RGBA16F; + default: + ghoul_assert(false, "glType data type unknown"); + throw ghoul::MissingCaseException(); + } + case ghoul::opengl::Texture::Format::BGR: + switch (glType) { + case GL_BYTE: + return GL_RGB8; + case GL_UNSIGNED_BYTE: + return GL_RGB8; + case GL_INT: + return GL_RGB32I; + case GL_UNSIGNED_INT: + return GL_RGB32UI; + case GL_FLOAT: + return GL_RGB32F; + case GL_HALF_FLOAT: + return GL_RGB16F; + default: + ghoul_assert(false, "glType data type unknown"); + throw ghoul::MissingCaseException(); + } + case ghoul::opengl::Texture::Format::BGRA: + switch (glType) { + case GL_BYTE: + return GL_RGBA8; + case GL_UNSIGNED_BYTE: + return GL_RGBA8; + case GL_INT: + return GL_RGBA32I; + case GL_UNSIGNED_INT: + return GL_RGBA32UI; + case GL_FLOAT: + return GL_RGBA32F; + case GL_HALF_FLOAT: + return GL_RGBA16F; + default: + ghoul_assert(false, "glType data type unknown"); + throw ghoul::MissingCaseException(); + } + default: + ghoul_assert(false, "Unknown format for OpenGL texture"); + throw ghoul::MissingCaseException(); + } + } + } // namespace namespace openspace::globebrowsing::cache { +// +// TextureContainer +// +MemoryAwareTileCache::TextureContainer::TextureContainer(TileTextureInitData initData, + size_t numTextures) + : _initData(std::move(initData)) + , _numTextures(numTextures) +{ + reset(); +} + +void MemoryAwareTileCache::TextureContainer::reset() { + _textures.clear(); + _freeTexture = 0; + for (size_t i = 0; i < _numTextures; ++i) { + using namespace ghoul::opengl; + std::unique_ptr tex = std::make_unique( + _initData.dimensions, + _initData.ghoulTextureFormat, + toGlTextureFormat(_initData.glType, _initData.ghoulTextureFormat), + _initData.glType, + Texture::FilterMode::Linear, + Texture::WrappingMode::ClampToEdge, + Texture::AllocateData(_initData.shouldAllocateDataOnCPU) + ); + + tex->setDataOwnership(Texture::TakeOwnership::Yes); + tex->uploadTexture(); + tex->setFilter(Texture::FilterMode::AnisotropicMipMap); + + _textures.push_back(std::move(tex)); + } +} + +void MemoryAwareTileCache::TextureContainer::reset(size_t numTextures) { + _numTextures = numTextures; + reset(); +} + +ghoul::opengl::Texture* MemoryAwareTileCache::TextureContainer::getTextureIfFree() { + if (_freeTexture < _textures.size()) { + ghoul::opengl::Texture* texture = _textures[_freeTexture].get(); + _freeTexture++; + return texture; + } + else { + return nullptr; + } +} + +const TileTextureInitData& +MemoryAwareTileCache::TextureContainer::tileTextureInitData() const +{ + return _initData; +} + +size_t MemoryAwareTileCache::TextureContainer::size() const { + return _textures.size(); +} + +// +// MemoryAwareTileCache +// + MemoryAwareTileCache::MemoryAwareTileCache() : PropertyOwner({ "TileCache" }) , _numTextureBytesAllocatedOnCPU(0) @@ -85,7 +259,6 @@ MemoryAwareTileCache::MemoryAwareTileCache() , _tileCacheSize(TileCacheSizeInfo, 1024, 128, 16384, 1) , _applyTileCacheSize(ApplyTileCacheInfo) , _clearTileCache(ClearTileCacheInfo) - , _usePbo(UsePboInfo, false) { createDefaultTextureContainers(); @@ -114,8 +287,6 @@ MemoryAwareTileCache::MemoryAwareTileCache() ); addProperty(_tileCacheSize); - addProperty(_usePbo); - setSizeEstimated(_tileCacheSize * 1024 * 1024); } @@ -133,9 +304,9 @@ void MemoryAwareTileCache::clear() { void MemoryAwareTileCache::createDefaultTextureContainers() { for (int id = 0; id < layergroupid::NUM_LAYER_GROUPS; id++) { - TileTextureInitData initData = LayerManager::getTileTextureInitData( + TileTextureInitData initData = tileTextureInitData( layergroupid::GroupID(id), - LayerManager::PadTiles::Yes + true ); assureTextureContainerExists(initData); } @@ -144,7 +315,7 @@ void MemoryAwareTileCache::createDefaultTextureContainers() { void MemoryAwareTileCache::assureTextureContainerExists( const TileTextureInitData& initData) { - TileTextureInitData::HashKey initDataKey = initData.hashKey(); + TileTextureInitData::HashKey initDataKey = initData.hashKey; if (_textureContainerMap.find(initDataKey) == _textureContainerMap.end()) { // For now create 500 textures of this type _textureContainerMap.emplace(initDataKey, @@ -167,7 +338,7 @@ void MemoryAwareTileCache::setSizeEstimated(size_t estimatedSize) { [](size_t s, const std::pair& p) { - return s + p.second.first->tileTextureInitData().totalNumBytes(); + return s + p.second.first->tileTextureInitData().totalNumBytes; } ); @@ -218,7 +389,7 @@ Tile MemoryAwareTileCache::get(const ProviderTileKey& key) { return it->second.second->get(key); } else { - return Tile::TileUnavailable; + return Tile(); } } @@ -227,7 +398,7 @@ ghoul::opengl::Texture* MemoryAwareTileCache::texture( { // if this texture type does not exist among the texture containers // it needs to be created - TileTextureInitData::HashKey initDataKey = initData.hashKey(); + TileTextureInitData::HashKey initDataKey = initData.hashKey; assureTextureContainerExists(initData); // Now we know that the texture container exists, // check if there are any unused textures @@ -237,12 +408,12 @@ ghoul::opengl::Texture* MemoryAwareTileCache::texture( if (!texture) { Tile oldTile = _textureContainerMap[initDataKey].second->popLRU().second; // Use the old tile's texture - texture = oldTile.texture(); + texture = oldTile.texture; } return texture; } -void MemoryAwareTileCache::createTileAndPut(ProviderTileKey key, RawTile& rawTile) { +void MemoryAwareTileCache::createTileAndPut(ProviderTileKey key, RawTile rawTile) { using ghoul::opengl::Texture; if (rawTile.error != RawTile::ReadError::None) { @@ -255,11 +426,12 @@ void MemoryAwareTileCache::createTileAndPut(ProviderTileKey key, RawTile& rawTil // Re-upload texture, either using PBO or by using RAM data if (rawTile.pbo != 0) { tex->reUploadTextureFromPBO(rawTile.pbo); - if (initData.shouldAllocateDataOnCPU()) { + if (initData.shouldAllocateDataOnCPU) { if (!tex->dataOwnership()) { - _numTextureBytesAllocatedOnCPU += initData.totalNumBytes(); + _numTextureBytesAllocatedOnCPU += initData.totalNumBytes; } - tex->setPixelData(rawTile.imageData, Texture::TakeOwnership::Yes); + tex->setPixelData(rawTile.imageData.release(), Texture::TakeOwnership::Yes); + rawTile.imageData = nullptr; } } else { @@ -268,17 +440,18 @@ void MemoryAwareTileCache::createTileAndPut(ProviderTileKey key, RawTile& rawTil tex->dataOwnership(), "Texture must have ownership of old data to avoid leaks" ); - tex->setPixelData(rawTile.imageData, Texture::TakeOwnership::Yes); + tex->setPixelData(rawTile.imageData.release(), Texture::TakeOwnership::Yes); + rawTile.imageData = nullptr; [[ maybe_unused ]] size_t expectedDataSize = tex->expectedPixelDataSize(); - const size_t numBytes = rawTile.textureInitData->totalNumBytes(); + const size_t numBytes = rawTile.textureInitData->totalNumBytes; ghoul_assert(expectedDataSize == numBytes, "Pixel data size is incorrect"); _numTextureBytesAllocatedOnCPU += numBytes - previousExpectedDataSize; tex->reUploadTexture(); } tex->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - Tile tile(tex, rawTile.tileMetaData, Tile::Status::OK); - TileTextureInitData::HashKey initDataKey = initData.hashKey(); - _textureContainerMap[initDataKey].second->put(std::move(key), tile); + Tile tile{ tex, std::move(rawTile.tileMetaData), Tile::Status::OK }; + TileTextureInitData::HashKey initDataKey = initData.hashKey; + _textureContainerMap[initDataKey].second->put(std::move(key), std::move(tile)); } } @@ -308,7 +481,7 @@ size_t MemoryAwareTileCache::gpuAllocatedDataSize() const { TextureContainerTileCache>& p) { const TextureContainer& textureContainer = *p.second.first; - const size_t nBytes = textureContainer.tileTextureInitData().totalNumBytes(); + const size_t nBytes = textureContainer.tileTextureInitData().totalNumBytes; return s + nBytes * textureContainer.size(); } ); @@ -324,8 +497,8 @@ size_t MemoryAwareTileCache::cpuAllocatedDataSize() const { { const TextureContainer& textureContainer = *p.second.first; const TileTextureInitData& initData = textureContainer.tileTextureInitData(); - if (initData.shouldAllocateDataOnCPU()) { - size_t bytesPerTexture = initData.totalNumBytes(); + if (initData.shouldAllocateDataOnCPU) { + size_t bytesPerTexture = initData.totalNumBytes; return s + bytesPerTexture * textureContainer.size(); } return s; @@ -334,8 +507,4 @@ size_t MemoryAwareTileCache::cpuAllocatedDataSize() const { return dataSize + _numTextureBytesAllocatedOnCPU; } -bool MemoryAwareTileCache::shouldUsePbo() const { - return _usePbo; -} - } // namespace openspace::globebrowsing::cache diff --git a/modules/globebrowsing/cache/memoryawaretilecache.h b/modules/globebrowsing/src/memoryawaretilecache.h similarity index 72% rename from modules/globebrowsing/cache/memoryawaretilecache.h rename to modules/globebrowsing/src/memoryawaretilecache.h index fbc58a9bbc..29beb51eb3 100644 --- a/modules/globebrowsing/cache/memoryawaretilecache.h +++ b/modules/globebrowsing/src/memoryawaretilecache.h @@ -25,9 +25,9 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___MEMORY_AWARE_TILE_CACHE___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___MEMORY_AWARE_TILE_CACHE___H__ -#include -#include -#include +#include +#include +#include #include #include #include @@ -55,17 +55,17 @@ struct ProviderTileKey { 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. + * 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; @@ -92,16 +92,55 @@ public: bool exist(const ProviderTileKey& key) const; Tile get(const ProviderTileKey& key); ghoul::opengl::Texture* texture(const TileTextureInitData& initData); - void createTileAndPut(ProviderTileKey key, RawTile& rawTile); + void createTileAndPut(ProviderTileKey key, RawTile rawTile); void put(const ProviderTileKey& key, const TileTextureInitData::HashKey& initDataKey, Tile tile); void update(); size_t gpuAllocatedDataSize() const; size_t cpuAllocatedDataSize() const; - bool shouldUsePbo() const; private: + /** + * Owner of texture data used for tiles. Instead of dynamically allocating textures + * one by one, they are created once and reused. + */ + class TextureContainer { + public: + /** + * \param initData is the description of the texture type. + * \param numTextures is the number of textures to allocate. + */ + TextureContainer(TileTextureInitData initData, size_t numTextures); + + ~TextureContainer() = default; + + void reset(); + void reset(size_t numTextures); + + /** + * \return A pointer to a texture if there is one texture never used before. If + * there are no textures left, nullptr is returned. TextureContainer still + * owns the texture so no delete should be called on the raw pointer. + */ + ghoul::opengl::Texture* getTextureIfFree(); + + const TileTextureInitData& tileTextureInitData() const; + + /** + * \returns the number of textures in this TextureContainer + */ + size_t size() const; + + private: + std::vector> _textures; + + const TileTextureInitData _initData; + size_t _freeTexture = 0; + size_t _numTextures; + }; + + void createDefaultTextureContainers(); void assureTextureContainerExists(const TileTextureInitData& initData); void resetTextureContainerSize(size_t numTexturesPerTextureType); @@ -125,9 +164,6 @@ private: properties::IntProperty _tileCacheSize; properties::TriggerProperty _applyTileCacheSize; properties::TriggerProperty _clearTileCache; - - /// Whether or not pixel buffer objects should be used when uploading tile data - properties::BoolProperty _usePbo; }; } // namespace openspace::globebrowsing::cache diff --git a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.h b/modules/globebrowsing/src/prioritizingconcurrentjobmanager.h similarity index 92% rename from modules/globebrowsing/other/prioritizingconcurrentjobmanager.h rename to modules/globebrowsing/src/prioritizingconcurrentjobmanager.h index 5839acbeb2..cd25bd0914 100644 --- a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.h +++ b/modules/globebrowsing/src/prioritizingconcurrentjobmanager.h @@ -25,11 +25,8 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PRIORITIZING_CONCURRENT_JOB_MANAGER___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___PRIORITIZING_CONCURRENT_JOB_MANAGER___H__ -#include - -//#include +#include #include - #include namespace openspace { template struct Job; } @@ -37,10 +34,10 @@ namespace openspace { template struct Job; } namespace openspace::globebrowsing { /** - * Concurrent job manager which prioritizes which jobs to work on depending on which - * ones were enqueued latest. The class is templated both on the job type and the key - * type which is used to identify jobs. In case a job need to be explicitly ended - * It can be identified using its key. + * Concurrent job manager which prioritizes which jobs to work on depending on which ones + * were enqueued latest. The class is templated both on the job type and the key type + * which is used to identify jobs. In case a job need to be explicitly ended. It can be + * identified using its key. */ template class PrioritizingConcurrentJobManager { diff --git a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.inl b/modules/globebrowsing/src/prioritizingconcurrentjobmanager.inl similarity index 96% rename from modules/globebrowsing/other/prioritizingconcurrentjobmanager.inl rename to modules/globebrowsing/src/prioritizingconcurrentjobmanager.inl index 6a4ff0b6d9..9690e6a4e6 100644 --- a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.inl +++ b/modules/globebrowsing/src/prioritizingconcurrentjobmanager.inl @@ -29,7 +29,7 @@ namespace openspace::globebrowsing { template PrioritizingConcurrentJobManager::PrioritizingConcurrentJobManager( LRUThreadPool pool) - : _threadPool(pool) + : _threadPool(std::move(pool)) {} template @@ -38,7 +38,7 @@ void PrioritizingConcurrentJobManager::enqueueJob(std::shared_ptrexecute(); - std::lock_guard lock(_finishedJobsMutex); + std::lock_guard lock(_finishedJobsMutex); _finishedJobs.push(job); }, key); } @@ -69,7 +69,7 @@ template std::shared_ptr> PrioritizingConcurrentJobManager::popFinishedJob() { ghoul_assert(!_finishedJobs.empty(), "There is no finished job to pop!"); - std::lock_guard lock(_finishedJobsMutex); + std::lock_guard lock(_finishedJobsMutex); std::shared_ptr> result = _finishedJobs.pop(); return result; } diff --git a/modules/globebrowsing/tile/rawtile.cpp b/modules/globebrowsing/src/rawtile.cpp similarity index 83% rename from modules/globebrowsing/tile/rawtile.cpp rename to modules/globebrowsing/src/rawtile.cpp index af86add45d..5a4638bc3d 100644 --- a/modules/globebrowsing/tile/rawtile.cpp +++ b/modules/globebrowsing/src/rawtile.cpp @@ -22,23 +22,17 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include - -#include +#include namespace openspace::globebrowsing { -RawTile RawTile::createDefault(const TileTextureInitData& initData) { +RawTile createDefaultTile(TileTextureInitData initData) { RawTile defaultRes; - defaultRes.textureInitData = std::make_shared(initData); - defaultRes.imageData = new char[initData.totalNumBytes()]; - std::fill_n( - defaultRes.imageData, - initData.totalNumBytes(), - char(0) - ); + defaultRes.textureInitData = std::move(initData); + std::byte* data = new std::byte[initData.totalNumBytes]; + defaultRes.imageData = std::unique_ptr(data); + std::fill_n(defaultRes.imageData.get(), initData.totalNumBytes, std::byte(0)); return defaultRes; - } } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/rawtile.h b/modules/globebrowsing/src/rawtile.h similarity index 87% rename from modules/globebrowsing/tile/rawtile.h rename to modules/globebrowsing/src/rawtile.h index 59cbb0fb18..95c48231e9 100644 --- a/modules/globebrowsing/tile/rawtile.h +++ b/modules/globebrowsing/src/rawtile.h @@ -25,14 +25,17 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___RAWTILE___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___RAWTILE___H__ -#include +#include +#include +#include #include #include +#include #include +#include namespace openspace::globebrowsing { -struct TileMetaData; class TileTextureInitData; struct RawTile { @@ -44,16 +47,16 @@ struct RawTile { Fatal // = CE_Fatal }; - char* imageData = nullptr; - std::shared_ptr tileMetaData = nullptr; - std::shared_ptr textureInitData = nullptr; + std::unique_ptr imageData; + TileMetaData tileMetaData; + std::optional textureInitData; TileIndex tileIndex = { 0, 0, 0 }; ReadError error = ReadError::None; GLuint pbo = 0; - - static RawTile createDefault(const TileTextureInitData& initData); }; +RawTile createDefaultTile(TileTextureInitData initData); + } // namespace openspace::globebrowsing #endif // __OPENSPACE_MODULE_GLOBEBROWSING___RAWTILE___H__ diff --git a/modules/globebrowsing/src/rawtiledatareader.cpp b/modules/globebrowsing/src/rawtiledatareader.cpp new file mode 100644 index 0000000000..413a478d85 --- /dev/null +++ b/modules/globebrowsing/src/rawtiledatareader.cpp @@ -0,0 +1,855 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning (push) + // CPL throws warning about missing DLL interface +#pragma warning (disable : 4251) +#endif // _MSC_VER + +#include +#include +#include + +#include + +#ifdef _MSC_VER +#pragma warning (pop) +#endif // _MSC_VER + +#include + +namespace openspace::globebrowsing { + +namespace { + +enum class Side { + Left = 0, + Top, + Right, + Bottom +}; + +float interpretFloat(GLenum glType, const std::byte* 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_HALF_FLOAT: + 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"); + throw ghoul::MissingCaseException(); + } +} + +GDALDataType toGDALDataType(GLenum glType) { + switch (glType) { + case GL_UNSIGNED_BYTE: + return GDT_Byte; + case GL_UNSIGNED_SHORT: + return GDT_UInt16; + case GL_SHORT: + return GDT_Int16; + case GL_UNSIGNED_INT: + return GDT_UInt32; + case GL_INT: + return GDT_Int32; + case GL_FLOAT: + return GDT_Float32; + case GL_DOUBLE: + return GDT_Float64; + default: + LERRORC("GDALRawTileDataReader", fmt::format( + "OpenGL data type unknown to GDAL: {}", static_cast(glType) + )); + throw ghoul::MissingCaseException(); + } +} + +/** + * Use as a helper function when determining the maximum tile level. This function + * returns the negated number of overviews requred to downscale the highest overview + * dataset so that it fits within minimumPixelSize pixels in the x-dimension. + */ +int calculateTileLevelDifference(GDALDataset* dataset, int minimumPixelSize) { + GDALRasterBand* firstBand = dataset->GetRasterBand(1); + GDALRasterBand* maxOverview; + int numOverviews = firstBand->GetOverviewCount(); + if (numOverviews <= 0) { // No overviews. Use first band. + maxOverview = firstBand; + } + else { // Pick the highest overview. + maxOverview = firstBand->GetOverview(numOverviews - 1); + } + const int sizeLevel0 = maxOverview->GetXSize(); + const double diff = log2(minimumPixelSize) - log2(sizeLevel0); + return static_cast(diff); +} + +/** + * Aligns one the sides of the pixel regino to the specified position. This does + * not change the number of pixels within the region. + * + * Example: Side = left and pos = 16: + * start.x = 16 and keep the size the same + */ +void alignPixelRegion(PixelRegion& pr, Side side, int pos) { + switch (side) { + case Side::Left: + pr.start.x = pos; + break; + case Side::Top: + pr.start.y = pos; + break; + case Side::Right: + pr.start.x = pos - pr.numPixels.x; + break; + case Side::Bottom: + pr.start.y = pos - pr.numPixels.y; + break; + } +} + +PixelRegion globalCut(PixelRegion& pr, Side side, int p) { + const bool lineIntersect = [pr, side, p]() { + switch (side) { + case Side::Left: + case Side::Right: + return pr.start.x <= p && p <= (pr.start.x + pr.numPixels.x); + case Side::Top: + case Side::Bottom: + return pr.start.y <= p && p <= (pr.start.y + pr.numPixels.y); + default: + throw ghoul::MissingCaseException(); + } + }(); + + if (!lineIntersect) { + return PixelRegion(); + } + + auto setSide = [](PixelRegion& pr, Side side, int pos) { + switch (side) { + case Side::Left: + pr.numPixels.x += (pr.start.x - pos); + pr.start.x = pos; + break; + case Side::Top: + pr.numPixels.y += (pr.start.y - pos); + pr.start.y = pos; + break; + case Side::Right: + pr.numPixels.x = pos - pr.start.x; + break; + case Side::Bottom: + pr.numPixels.y = pos - pr.start.y; + break; + } + }; + + PixelRegion cutOff(pr); + int cutSize = 0; + switch (side) { + case Side::Left: + setSide(pr, Side::Left, p); + setSide(cutOff, Side::Right, p - cutSize); + break; + case Side::Top: + setSide(pr, Side::Top, p); + setSide(cutOff, Side::Bottom, p - cutSize); + break; + case Side::Right: + setSide(pr, Side::Right, p); + setSide(cutOff, Side::Left, p + cutSize); + break; + case Side::Bottom: + setSide(pr, Side::Bottom, p); + setSide(cutOff, Side::Top, p + cutSize); + break; + } + return cutOff; +} + +int edge(const PixelRegion& pr, Side side) { + switch (side) { + case Side::Left: return pr.start.x; + case Side::Top: return pr.start.y; + case Side::Right: return pr.start.x + pr.numPixels.x; + case Side::Bottom: return pr.start.y + pr.numPixels.y; + default: throw ghoul::MissingCaseException(); + } +} + +PixelRegion localCut(PixelRegion& pr, Side side, int localPos) { + if (localPos < 1) { + return PixelRegion(); + } + else { + const int edgeDirectionSign = (side < Side::Right) ? -1 : 1; + return globalCut(pr, side, edge(pr, side) - edgeDirectionSign * localPos); + } +} + +bool isInside(const PixelRegion& lhs, const PixelRegion& rhs) { + glm::ivec2 e = lhs.start + lhs.numPixels; + glm::ivec2 re = rhs.start + rhs.numPixels; + return rhs.start.x <= lhs.start.x && e.x <= re.x && + rhs.start.y <= lhs.start.y && e.y <= re.y; +} + +IODescription cutIODescription(IODescription& io, Side side, int pos) { + const PixelRegion readPreCut = io.read.region; + const PixelRegion writePreCut = io.write.region; + + glm::dvec2 ratio = { + io.write.region.numPixels.x / static_cast(io.read.region.numPixels.x), + io.write.region.numPixels.y / static_cast(io.read.region.numPixels.y) + }; + + IODescription whatCameOff = io; + whatCameOff.read.region = globalCut(io.read.region, side, pos); + + glm::ivec2 cutSize = whatCameOff.read.region.numPixels; + glm::ivec2 localWriteCutSize = ratio * glm::dvec2(cutSize); + + int localWriteCutPos = + (side == Side::Left || side == Side::Right) ? + localWriteCutSize.x : + localWriteCutSize.y; + + whatCameOff.write.region = localCut(io.write.region, side, localWriteCutPos); + + return whatCameOff; +} + +/** + * Returns the geo transform from raster space to projection coordinates as defined + * by GDAL. + */ +std::array geoTransform(int rasterX, int rasterY) { + GeodeticPatch cov( + Geodetic2{ 0.0, 0.0 }, + Geodetic2{ glm::half_pi(), glm::pi() } + ); + std::array res; + res[0] = glm::degrees(cov.corner(Quad::NORTH_WEST).lon); + res[1] = glm::degrees(cov.size().lon) / rasterX; + res[2] = 0.0; + res[3] = glm::degrees(cov.corner(Quad::NORTH_WEST).lat); + res[4] = 0.0; + res[5] = glm::degrees(-cov.size().lat) / rasterY; + return res; +} + +/** + * Get the pixel corresponding to a specific position on the globe defined by the + * Geodetic2 coordinate \p geo. If the dataset has overviews the function returns the + * pixel at the lowest overview (highest resolution). + * + * \param geo The position on the globe to convert to pixel space. + * \return a pixel coordinate in the dataset. + */ +glm::ivec2 geodeticToPixel(const Geodetic2& geo, + const std::array& transform) +{ + const std::array& t = transform; + + const double Y = glm::degrees(geo.lat); + const double X = glm::degrees(geo.lon); + + const double divisor = t[2] * t[4] - t[1] * t[5]; + ghoul_assert(divisor != 0.0, "Division by zero!"); + + const double P = (t[0] * t[5] - t[2] * t[3] + t[2] * Y - t[5] * X) / divisor; + const double L = (-t[0] * t[4] + t[1] * t[3] - t[1] * Y + t[4] * 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 + + [[maybe_unused]] const double Xp = t[0] + P * t[1] + L * t[2]; + [[maybe_unused]] const double Yp = t[3] + P * t[4] + L * t[5]; + 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 glm::ivec2(glm::round(P), glm::round(L)); +} + +/** + * 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 \p geodeticPatch is a patch covering an area in geodetic coordinates + * \return A PixelRegion covering the given geodetic patch at highest resolution. + */ +PixelRegion highestResPixelRegion(const GeodeticPatch& geodeticPatch, + const std::array& transform) +{ + const Geodetic2 nwCorner = geodeticPatch.corner(Quad::NORTH_WEST); + const Geodetic2 swCorner = geodeticPatch.corner(Quad::SOUTH_EAST); + const glm::ivec2 pixelStart = geodeticToPixel(nwCorner, transform); + const glm::ivec2 pixelEnd = geodeticToPixel(swCorner, transform); + PixelRegion region; + region.start = pixelStart; + region.numPixels = pixelEnd - pixelStart; + return region; +} + +RawTile::ReadError postProcessErrorCheck(const RawTile& rawTile, size_t nRasters, + float noDataValue) +{ + // This check was implicit before and just made explicit here + ghoul_assert( + nRasters == rawTile.tileMetaData.maxValues.size(), + "Wrong numbers of max values" + ); + + const bool hasMissingData = std::any_of( + rawTile.tileMetaData.maxValues.begin(), + rawTile.tileMetaData.maxValues.end(), + [noDataValue](float v) { return v == noDataValue; } + ); + + const bool onHighLevel = rawTile.tileIndex.level > 6; + if (hasMissingData && onHighLevel) { + return RawTile::ReadError::Fatal; + } + return RawTile::ReadError::None; +} + +} // namespace + + +RawTileDataReader::RawTileDataReader(std::string filePath, + TileTextureInitData initData, + PerformPreprocessing preprocess) + : _initData(std::move(initData)) + , _preprocess(preprocess) + , _datasetFilePath(std::move(filePath)) +{ + initialize(); +} + +RawTileDataReader::~RawTileDataReader() { + std::lock_guard lockGuard(_datasetLock); + if (_dataset) { + GDALClose(_dataset); + _dataset = nullptr; + } +} + +void RawTileDataReader::initialize() { + if (_datasetFilePath.empty()) { + throw ghoul::RuntimeError("File path must not be empty"); + } + _dataset = static_cast(GDALOpen(_datasetFilePath.c_str(), GA_ReadOnly)); + if (!_dataset) { + throw ghoul::RuntimeError("Failed to load dataset: " + _datasetFilePath); + } + + // Assume all raster bands have the same data type + _rasterCount = _dataset->GetRasterCount(); + + // calculateTileDepthTransform + unsigned long long maximumValue = [t = _initData.glType]() { + switch (t) { + case GL_UNSIGNED_BYTE: return 1ULL << 8ULL; + case GL_UNSIGNED_SHORT: return 1ULL << 16ULL; + case GL_SHORT: return 1ULL << 15ULL; + case GL_UNSIGNED_INT: return 1ULL << 32ULL; + case GL_INT: return 1ULL << 31ULL; + case GL_HALF_FLOAT: return 1ULL; + case GL_FLOAT: return 1ULL; + case GL_DOUBLE: return 1ULL; + default: + ghoul_assert(false, "Unknown data type"); + throw ghoul::MissingCaseException(); + } + }(); + + + _depthTransform.scale = static_cast( + _dataset->GetRasterBand(1)->GetScale() * maximumValue + ); + _depthTransform.offset = static_cast( + _dataset->GetRasterBand(1)->GetOffset() + ); + _rasterXSize = _dataset->GetRasterXSize(); + _rasterYSize = _dataset->GetRasterYSize(); + _noDataValue = static_cast(_dataset->GetRasterBand(1)->GetNoDataValue()); + _dataType = toGDALDataType(_initData.glType); + + CPLErr error = _dataset->GetGeoTransform(_padfTransform.data()); + if (error == CE_Failure) { + _padfTransform = geoTransform(_rasterXSize, _rasterYSize); + } + + double tileLevelDifference = calculateTileLevelDifference( + _dataset, _initData.dimensions.x + ); + + const int numOverviews = _dataset->GetRasterBand(1)->GetOverviewCount(); + _maxChunkLevel = static_cast(-tileLevelDifference); + if (numOverviews > 0) { + _maxChunkLevel += numOverviews - 1; + } + _maxChunkLevel = std::max(_maxChunkLevel, 2); +} + +void RawTileDataReader::reset() { + std::lock_guard lockGuard(_datasetLock); + _maxChunkLevel = -1; + if (_dataset) { + GDALClose(_dataset); + _dataset = nullptr; + } + initialize(); +} + +RawTile::ReadError RawTileDataReader::rasterRead(int rasterBand, + const IODescription& io, + char* dataDestination) const +{ + ghoul_assert(isInside(io.read.region, io.read.fullRegion), "write region of bounds!"); + ghoul_assert( + io.write.region.start.x >= 0 && io.write.region.start.y >= 0, + "Invalid write region" + ); + + const glm::ivec2 end = io.write.region.start + io.write.region.numPixels; + [[maybe_unused]] const size_t largestIndex = + (end.y - 1) * io.write.bytesPerLine + (end.x - 1) * _initData.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 * _initData.bytesPerPixel; + + GDALRasterBand* gdalRasterBand = _dataset->GetRasterBand(rasterBand); + CPLErr readError = CE_Failure; + readError = gdalRasterBand->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 + _dataType, // Type + static_cast(_initData.bytesPerPixel), // Pixel spacing + -static_cast(io.write.bytesPerLine) // Line spacing + ); + + // Convert error to RawTile::ReadError + switch (readError) { + case CE_None: return RawTile::ReadError::None; + case CE_Debug: return RawTile::ReadError::Debug; + case CE_Warning: return RawTile::ReadError::Warning; + case CE_Failure: return RawTile::ReadError::Failure; + case CE_Fatal: return RawTile::ReadError::Fatal; + default: return RawTile::ReadError::Failure; + } +} + +RawTile RawTileDataReader::readTileData(TileIndex tileIndex) const { + size_t numBytes = _initData.totalNumBytes; + + RawTile rawTile; + rawTile.imageData = std::unique_ptr(new std::byte[numBytes]); + memset(rawTile.imageData.get(), 0xFF, numBytes); + + IODescription io = ioDescription(tileIndex); + RawTile::ReadError worstError = RawTile::ReadError::None; + readImageData(io, worstError, reinterpret_cast(rawTile.imageData.get())); + + rawTile.error = worstError; + rawTile.tileIndex = std::move(tileIndex); + rawTile.textureInitData = _initData; + + if (_preprocess) { + rawTile.tileMetaData = tileMetaData(rawTile, io.write.region); + rawTile.error = std::max( + rawTile.error, + postProcessErrorCheck(rawTile, _initData.nRasters, noDataValueAsFloat()) + ); + } + + return rawTile; +} + +void RawTileDataReader::readImageData(IODescription& io, RawTile::ReadError& worstError, + char* imageDataDest) const +{ + // Only read the minimum number of rasters + int nRastersToRead = std::min(_rasterCount, static_cast(_initData.nRasters)); + + switch (_initData.ghoulTextureFormat) { + case ghoul::opengl::Texture::Format::Red: { + char* dest = imageDataDest; + const RawTile::ReadError err = repeatedRasterRead(1, io, dest); + worstError = std::max(worstError, err); + break; + } + case ghoul::opengl::Texture::Format::RG: + case ghoul::opengl::Texture::Format::RGB: + case ghoul::opengl::Texture::Format::RGBA: { + if (nRastersToRead == 1) { // Grayscale + for (int 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* dest = imageDataDest + (i * _initData.bytesPerDatum); + const RawTile::ReadError err = repeatedRasterRead(1, io, dest); + worstError = std::max(worstError, err); + } + } + else if (nRastersToRead == 2) { // Grayscale + alpha + for (int 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* dest = imageDataDest + (i * _initData.bytesPerDatum); + const RawTile::ReadError err = repeatedRasterRead(1, io, dest); + worstError = std::max(worstError, err); + } + // Last read is the alpha channel + char* dest = imageDataDest + (3 * _initData.bytesPerDatum); + const RawTile::ReadError err = repeatedRasterRead(2, io, dest); + worstError = std::max(worstError, err); + } + else { // Three or more rasters + for (int i = 0; i < nRastersToRead; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dest = imageDataDest + (i * _initData.bytesPerDatum); + const RawTile::ReadError err = repeatedRasterRead(i + 1, io, dest); + worstError = std::max(worstError, err); + } + } + break; + } + case ghoul::opengl::Texture::Format::BGR: + case ghoul::opengl::Texture::Format::BGRA: { + if (nRastersToRead == 1) { // Grayscale + for (int 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* dest = imageDataDest + (i * _initData.bytesPerDatum); + const RawTile::ReadError err = repeatedRasterRead(1, io, dest); + worstError = std::max(worstError, err); + } + } + else if (nRastersToRead == 2) { // Grayscale + alpha + for (int 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* dest = imageDataDest + (i * _initData.bytesPerDatum); + const RawTile::ReadError err = repeatedRasterRead(1, io, dest); + worstError = std::max(worstError, err); + } + // Last read is the alpha channel + char* dest = imageDataDest + (3 * _initData.bytesPerDatum); + const RawTile::ReadError err = repeatedRasterRead(2, io, dest); + worstError = std::max(worstError, err); + } + else { // Three or more rasters + for (int i = 0; i < 3 && i < nRastersToRead; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dest = imageDataDest + (i * _initData.bytesPerDatum); + const RawTile::ReadError err = repeatedRasterRead(3 - i, io, dest); + worstError = std::max(worstError, err); + } + } + if (nRastersToRead > 3) { // Alpha channel exists + // Last read is the alpha channel + char* dest = imageDataDest + (3 * _initData.bytesPerDatum); + const RawTile::ReadError err = repeatedRasterRead(4, io, dest); + worstError = std::max(worstError, err); + } + break; + } + default: { + ghoul_assert(false, "Texture format not supported for tiles"); + break; + } + } +} + +IODescription RawTileDataReader::ioDescription(const TileIndex& tileIndex) const { + IODescription io; + io.read.region = highestResPixelRegion(tileIndex, _padfTransform); + + // write region starts in origin + io.write.region.start = glm::ivec2(0); + io.write.region.numPixels = _initData.dimensions; + + io.read.overview = 0; + io.read.fullRegion.start = { 0, 0 }; + io.read.fullRegion.numPixels = { _rasterXSize, _rasterYSize }; + // For correct sampling in dataset, we need to pad the texture tile + + PixelRegion scaledPadding; + scaledPadding.start = _initData.tilePixelStartOffset; + scaledPadding.numPixels = _initData.tilePixelSizeDifference; + + const double scale = static_cast(io.read.region.numPixels.x) / + static_cast(io.write.region.numPixels.x); + scaledPadding.numPixels *= scale; + scaledPadding.start *= scale; + + io.read.region.start += scaledPadding.start; + io.read.region.numPixels += scaledPadding.numPixels; + + io.write.bytesPerLine = _initData.bytesPerLine; + io.write.totalNumBytes = _initData.totalNumBytes; + + ghoul_assert( + io.write.region.numPixels.x == io.write.region.numPixels.y, + "Write region must be square" + ); + ghoul_assert( + io.write.region.numPixels.x == _initData.dimensions.x, + "Write region must match tile it writes to." + ); + + return io; +} + +const TileDepthTransform& RawTileDataReader::depthTransform() const { + return _depthTransform; +} + +glm::ivec2 RawTileDataReader::fullPixelSize() const { + return geodeticToPixel(Geodetic2{ 90.0, 180.0 }, _padfTransform); +} + +RawTile::ReadError RawTileDataReader::repeatedRasterRead(int rasterBand, + const IODescription& fullIO, + char* dataDestination, + int depth) const +{ + + // 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 + // | | + // +--------------+ + + RawTile::ReadError worstError = RawTile::ReadError::None; + if (!isInside(io.read.region, 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 + const Side side = static_cast(i); + IODescription cutoff = cutIODescription( + io, + side, + edge(io.read.fullRegion, 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 + // | | + // +--------------+ + + const int area = cutoff.read.region.numPixels.x * + cutoff.read.region.numPixels.y; + if (area > 0) { + // Wrap by repeating + Side oppositeSide = static_cast((i + 2) % 4); + + alignPixelRegion( + cutoff.read.region, + oppositeSide, + edge(io.read.fullRegion, 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. + const RawTile::ReadError err = repeatedRasterRead( + rasterBand, + cutoff, + dataDestination, + depth + 1 + ); + + worstError = std::max(worstError, err); + } + } + } + + const 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; +} + +TileMetaData RawTileDataReader::tileMetaData(RawTile& rawTile, + const PixelRegion& region) const +{ + const size_t bytesPerLine = _initData.bytesPerPixel * region.numPixels.x; + + TileMetaData preprocessData; + preprocessData.maxValues.resize(_initData.nRasters); + preprocessData.minValues.resize(_initData.nRasters); + preprocessData.hasMissingData.resize(_initData.nRasters); + + std::vector noDataValues(_initData.nRasters); + for (size_t raster = 0; raster < _initData.nRasters; ++raster) { + preprocessData.maxValues[raster] = -FLT_MAX; + preprocessData.minValues[raster] = FLT_MAX; + preprocessData.hasMissingData[raster] = false; + noDataValues[raster] = noDataValueAsFloat(); + } + + bool allIsMissing = true; + for (int y = 0; y < region.numPixels.y; ++y) { + const size_t yi = (region.numPixels.y - 1 - y) * bytesPerLine; + size_t i = 0; + for (int x = 0; x < region.numPixels.x; ++x) { + for (size_t raster = 0; raster < _initData.nRasters; ++raster) { + const float noDataValue = noDataValueAsFloat(); + const float val = interpretFloat( + _initData.glType, + &(rawTile.imageData.get()[yi + i]) + ); + if (val != noDataValue && val == val) { + preprocessData.maxValues[raster] = std::max( + val, + preprocessData.maxValues[raster] + ); + preprocessData.minValues[raster] = std::min( + val, + preprocessData.minValues[raster] + ); + allIsMissing = false; + } + else { + preprocessData.hasMissingData[raster] = true; + float& floatToRewrite = reinterpret_cast( + rawTile.imageData[yi + i] + ); + floatToRewrite = -std::numeric_limits::max(); + } + i += _initData.bytesPerDatum; + } + } + } + + if (allIsMissing) { + rawTile.error = RawTile::ReadError::Failure; + } + + return preprocessData; +} + +int RawTileDataReader::maxChunkLevel() const { + return _maxChunkLevel; +} + +float RawTileDataReader::noDataValueAsFloat() const { + return _noDataValue; +} + +} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.h b/modules/globebrowsing/src/rawtiledatareader.h similarity index 50% rename from modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.h rename to modules/globebrowsing/src/rawtiledatareader.h index 322605a2ae..2ba04fd852 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.h +++ b/modules/globebrowsing/src/rawtiledatareader.h @@ -25,11 +25,10 @@ #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 @@ -41,81 +40,69 @@ namespace openspace::globebrowsing { class GeodeticPatch; -class GdalRawTileDataReader : public RawTileDataReader { +class 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 TileTextureInitData& initData, - RawTileDataReader::PerformPreprocessing preprocess = - RawTileDataReader::PerformPreprocessing::No); - - virtual ~GdalRawTileDataReader() override; - - // Public virtual function overloading - virtual void reset() override; - virtual int maxChunkLevel() const override; - virtual float noDataValueAsFloat() const override; - virtual int rasterXSize() const override; - virtual int rasterYSize() const override; - virtual int dataSourceNumRasters() const override; - virtual float depthOffset() const override; - virtual float depthScale() const override; - -protected: + BooleanType(PerformPreprocessing); /** - * 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. + * 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 */ - virtual std::array geoTransform() const override; + RawTileDataReader(std::string filePath, TileTextureInitData initData, + PerformPreprocessing preprocess = PerformPreprocessing::No); + ~RawTileDataReader(); + + void reset(); + int maxChunkLevel() const; + float noDataValueAsFloat() const; + + RawTile readTileData(TileIndex tileIndex) const; + const TileDepthTransform& depthTransform() const; + glm::ivec2 fullPixelSize() const; private: - // Private virtual function overloading - virtual void initialize() override; - virtual RawTile::ReadError rasterRead(int rasterBand, const IODescription& io, - char* dst) const override; + void initialize(); - // GDAL Helper methods - GDALDataset* openGdalDataset(const std::string& filePath); + RawTile::ReadError rasterRead(int rasterBand, const IODescription& io, + char* dst) const; + + void readImageData(IODescription& io, RawTile::ReadError& worstError, + char* imageDataDest) const; + + IODescription ioDescription(const TileIndex& tileIndex) const; /** - * Use as a helper function when determining the maximum tile level. This function - * returns the negated number of overviews requred to downscale the highest overview - * dataset so that it fits within minimumPixelSize pixels in the x-dimension. + * 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. */ - int calculateTileLevelDifference(int minimumPixelSize) const; + RawTile::ReadError repeatedRasterRead(int rasterBand, const IODescription& fullIO, + char* dataDestination, int depth = 0) const; - std::string _datasetFilePath; + TileMetaData tileMetaData(RawTile& rawTile, const PixelRegion& region) const; + const std::string _datasetFilePath; GDALDataset* _dataset = nullptr; - struct GdalDatasetMetaDataCached { - int rasterCount; - float scale; - float offset; - int rasterXSize; - int rasterYSize; - float noDataValue; - std::array padfTransform; + // Dataset parameters + int _rasterCount; + int _rasterXSize; + int _rasterYSize; + float _noDataValue; + std::array _padfTransform; + GDALDataType _dataType; + int _maxChunkLevel = -1; - GDALDataType dataType; - - } _gdalDatasetMetaDataCached; + const TileTextureInitData _initData; + const PerformPreprocessing _preprocess; + TileDepthTransform _depthTransform = { 0.f, 0.f }; mutable std::mutex _datasetLock; }; } // namespace openspace::globebrowsing -#endif // GLOBEBROWSING_USE_GDAL - #endif // __OPENSPACE_MODULE_GLOBEBROWSING___GDAL_RAW_TILE_DATA_READER___H__ diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp new file mode 100644 index 0000000000..d31fd8371a --- /dev/null +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -0,0 +1,2048 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + // Global flags to modify the RenderableGlobe + constexpr const bool LimitLevelByAvailableData = false; + constexpr const bool PerformFrustumCulling = true; + constexpr const bool PreformHorizonCulling = true; + + // Shadow structure + struct ShadowRenderingStruct { + double xu; + double xp; + double rs; + double rc; + glm::dvec3 sourceCasterVec; + glm::dvec3 casterPositionVec; + bool isShadowing; + }; + + constexpr const char* KeyRadii = "Radii"; + constexpr const char* KeyLayers = "Layers"; + constexpr const char* KeyShadowGroup = "ShadowGroup"; + constexpr const char* KeyShadowSource = "Source"; + constexpr const char* KeyShadowCaster = "Caster"; + const openspace::globebrowsing::AABB3 CullingFrustum{ + glm::vec3(-1.f, -1.f, 0.f), + glm::vec3( 1.f, 1.f, 1e35) + }; + constexpr const float DefaultHeight = 0.f; + + // I tried reducing this to 16, but it left the rendering with artifacts when the + // atmosphere was enabled. The best guess to the circular artifacts are due to the + // lack of resolution when a height field is enabled, leading the triangles to cut + // into the planets surface, causing issues with the ray depth of the atmosphere + // raycaster. We tried a simple solution that uses two grids and switches between + // them at a cutoff level, and I think this might still be the best solution for the + // time being. --abock 2018-10-30 + constexpr const int DefaultSkirtedGridSegments = 64; + constexpr static const int UnknownDesiredLevel = -1; + + const openspace::globebrowsing::GeodeticPatch Coverage = + openspace::globebrowsing::GeodeticPatch(0, 0, 90, 180); + + const openspace::globebrowsing::TileIndex LeftHemisphereIndex = + openspace::globebrowsing::TileIndex(0, 0, 1); + + const openspace::globebrowsing::TileIndex RightHemisphereIndex = + openspace::globebrowsing::TileIndex(1, 0, 1); + + constexpr openspace::properties::Property::PropertyInfo ShowChunkEdgeInfo = { + "ShowChunkEdges", + "Show chunk edges", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo ShowChunkBoundsInfo = { + "ShowChunkBounds", + "Show chunk bounds", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo ShowChunkAABBInfo = { + "ShowChunkAABB", + "Show chunk AABB", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo HeightResolutionInfo = { + "ShowHeightResolution", + "Show height resolution", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo HeightIntensityInfo = { + "ShowHeightIntensities", + "Show height intensities", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo LevelProjectedAreaInfo = { + "LevelByProjectedAreaElseDistance", + "Level by projected area (else distance)", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo ResetTileProviderInfo = { + "ResetTileProviders", + "Reset tile providers", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo ModelSpaceRenderingInfo = { + "ModelSpaceRenderingCutoffLevel", + "Model Space Rendering Cutoff Level", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo PerformShadingInfo = { + "PerformShading", + "Perform shading", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo AccurateNormalsInfo = { + "UseAccurateNormals", + "Use Accurate Normals", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo EclipseInfo = { + "Eclipse", + "Eclipse", + "Enables/Disable Eclipse shadows" + }; + + constexpr openspace::properties::Property::PropertyInfo EclipseHardShadowsInfo = { + "EclipseHardShadows", + "Eclipse Hard Shadows", + "Enables the rendering of eclipse shadows using hard shadows" + }; + + constexpr openspace::properties::Property::PropertyInfo LodScaleFactorInfo = { + "LodScaleFactor", + "Level of Detail Scale Factor", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo CameraMinHeightInfo = { + "CameraMinHeight", + "Camera Minimum Height", + "" // @TODO Missing documentation + }; + + constexpr openspace::properties::Property::PropertyInfo OrenNayarRoughnessInfo = { + "OrenNayarRoughness", + "orenNayarRoughness", + "" // @TODO Missing documentation + }; +} // namespace + +using namespace openspace::properties; + +namespace openspace::globebrowsing { + +struct BoundingHeights { + float min; + float max; + bool available; +}; + +namespace { + +bool isLeaf(const Chunk& cn) { + return cn.children[0] == nullptr; +} + +const Chunk& findChunkNode(const Chunk& node, const Geodetic2& location) { + const Chunk* n = &node; + + while (!isLeaf(*n)) { + const Geodetic2 center = n->surfacePatch.center(); + int index = 0; + if (center.lon < location.lon) { + ++index; + } + if (location.lat < center.lat) { + ++index; + ++index; + } + n = n->children[static_cast(index)]; + } + return *n; +} + +std::vector> +tilesAndSettingsUnsorted(const LayerGroup& layerGroup, const TileIndex& tileIndex) +{ + std::vector> tilesAndSettings; + for (Layer* layer : layerGroup.activeLayers()) { + if (layer->tileProvider()) { + tilesAndSettings.emplace_back( + tileprovider::chunkTile(*layer->tileProvider(), tileIndex), + &layer->renderSettings() + ); + } + } + std::reverse(tilesAndSettings.begin(), tilesAndSettings.end()); + return tilesAndSettings; +} + +BoundingHeights boundingHeightsForChunk(const Chunk& chunk, const LayerManager& lm) { + using ChunkTileSettingsPair = std::pair; + + BoundingHeights boundingHeights { 0.f, 0.f, false }; + + // 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 = lm.layerGroup(layergroupid::GroupID::HeightLayers); + std::vector chunkTileSettingPairs = tilesAndSettingsUnsorted( + heightmaps, + chunk.tileIndex + ); + + bool lastHadMissingData = true; + for (const ChunkTileSettingsPair& chunkTileSettingsPair : chunkTileSettingPairs) { + const ChunkTile& chunkTile = chunkTileSettingsPair.first; + const LayerRenderSettings* settings = chunkTileSettingsPair.second; + const bool goodTile = (chunkTile.tile.status == Tile::Status::OK); + const bool hasTileMetaData = chunkTile.tile.metaData.has_value(); + + if (goodTile && hasTileMetaData) { + const TileMetaData& tileMetaData = chunkTile.tile.metaData.value(); + + const float minValue = settings->performLayerSettings( + tileMetaData.minValues[HeightChannel] + ); + const float maxValue = settings->performLayerSettings( + tileMetaData.maxValues[HeightChannel] + ); + + if (!boundingHeights.available) { + if (tileMetaData.hasMissingData[HeightChannel]) { + boundingHeights.min = std::min(DefaultHeight, minValue); + boundingHeights.max = std::max(DefaultHeight, maxValue); + } + else { + boundingHeights.min = minValue; + boundingHeights.max = maxValue; + } + boundingHeights.available = true; + } + else { + boundingHeights.min = std::min(boundingHeights.min, minValue); + boundingHeights.max = std::max(boundingHeights.max, maxValue); + } + lastHadMissingData = tileMetaData.hasMissingData[HeightChannel]; + } + + // Allow for early termination + if (!lastHadMissingData) { + break; + } + } + + return boundingHeights; +} + +std::array boundingCornersForChunk(const Chunk& chunk, + const LayerManager& lm, + const Ellipsoid& ellipsoid) +{ + const BoundingHeights& boundingHeight = boundingHeightsForChunk(chunk, lm); + + // assume worst case + const double patchCenterRadius = ellipsoid.maximumRadius(); + + const double maxCenterRadius = patchCenterRadius + boundingHeight.max; + Geodetic2 halfSize = chunk.surfacePatch.halfSize(); + + // As the patch is curved, the maximum height offsets at the corners must be long + // enough to cover large enough to cover a boundingHeight.max at the center of the + // patch. + // Approximating scaleToCoverCenter by assuming the latitude and longitude angles + // of "halfSize" are equal to the angles they create from the center of the + // globe to the patch corners. This is true for the longitude direction when + // the ellipsoid can be approximated as a sphere and for the latitude for patches + // close to the equator. Close to the pole this will lead to a bigger than needed + // value for scaleToCoverCenter. However, this is a simple calculation and a good + // Approximation. + const double y1 = tan(halfSize.lat); + const double y2 = tan(halfSize.lon); + const double scaleToCoverCenter = sqrt(1 + pow(y1, 2) + pow(y2, 2)); + + const double maxCornerHeight = maxCenterRadius * scaleToCoverCenter - + patchCenterRadius; + + const bool chunkIsNorthOfEquator = chunk.surfacePatch.isNorthern(); + + // The minimum height offset, however, we can simply + const double minCornerHeight = boundingHeight.min; + std::array corners; + + const double latCloseToEquator = chunk.surfacePatch.edgeLatitudeNearestEquator(); + const Geodetic3 p1Geodetic = { + { latCloseToEquator, chunk.surfacePatch.minLon() }, + maxCornerHeight + }; + const Geodetic3 p2Geodetic = { + { latCloseToEquator, chunk.surfacePatch.maxLon() }, + maxCornerHeight + }; + + const glm::vec3 p1 = ellipsoid.cartesianPosition(p1Geodetic); + const glm::vec3 p2 = ellipsoid.cartesianPosition(p2Geodetic); + const glm::vec3 p = 0.5f * (p1 + p2); + const Geodetic2 pGeodetic = ellipsoid.cartesianToGeodetic2(p); + const double latDiff = latCloseToEquator - pGeodetic.lat; + + for (size_t i = 0; i < 8; ++i) { + const Quad q = static_cast(i % 4); + const double cornerHeight = i < 4 ? minCornerHeight : maxCornerHeight; + Geodetic3 cornerGeodetic = { chunk.surfacePatch.corner(q), cornerHeight }; + + const bool cornerIsNorthern = !((i / 2) % 2); + const bool cornerCloseToEquator = chunkIsNorthOfEquator ^ cornerIsNorthern; + if (cornerCloseToEquator) { + cornerGeodetic.geodetic2.lat += latDiff; + } + + corners[i] = glm::dvec4(ellipsoid.cartesianPosition(cornerGeodetic), 1); + } + + return corners; +} + +void expand(AABB3& bb, const glm::vec3& p) { + bb.min = glm::min(bb.min, p); + bb.max = glm::max(bb.max, p); +} + +bool intersects(const AABB3& bb, const AABB3& o) { + return (bb.min.x <= o.max.x) && (o.min.x <= bb.max.x) + && (bb.min.y <= o.max.y) && (o.min.y <= bb.max.y) + && (bb.min.z <= o.max.z) && (o.min.z <= bb.max.z); +} + +} // namespace + +Chunk::Chunk(const TileIndex& ti) + : tileIndex(ti) + , surfacePatch(ti) +{} + +RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) + : Renderable(dictionary) + , _debugProperties({ + BoolProperty(ShowChunkEdgeInfo, false), + BoolProperty(ShowChunkBoundsInfo, false), + BoolProperty(ShowChunkAABBInfo, false), + BoolProperty(HeightResolutionInfo, false), + BoolProperty(HeightIntensityInfo, false), + BoolProperty(LevelProjectedAreaInfo, true), + BoolProperty(ResetTileProviderInfo, false), + IntProperty(ModelSpaceRenderingInfo, 14, 1, 22) + }) + , _generalProperties({ + BoolProperty(PerformShadingInfo, true), + BoolProperty(AccurateNormalsInfo, false), + BoolProperty(EclipseInfo, false), + BoolProperty(EclipseHardShadowsInfo, false), + FloatProperty(LodScaleFactorInfo, 15.f, 1.f, 50.f), + FloatProperty(CameraMinHeightInfo, 100.f, 0.f, 1000.f), + FloatProperty(OrenNayarRoughnessInfo, 0.f, 0.f, 1.f) + }) + , _debugPropertyOwner({ "Debug" }) + , _leftRoot(Chunk(LeftHemisphereIndex)) + , _rightRoot(Chunk(RightHemisphereIndex)) + , _grid(DefaultSkirtedGridSegments, DefaultSkirtedGridSegments) +{ + setIdentifier("RenderableGlobe"); + + // Read the radii in to its own dictionary + if (dictionary.hasKeyAndValue(KeyRadii)) { + _ellipsoid = Ellipsoid(dictionary.value(KeyRadii)); + setBoundingSphere(static_cast(_ellipsoid.maximumRadius())); + } + else if (dictionary.hasKeyAndValue(KeyRadii)) { + const double radius = dictionary.value(KeyRadii); + _ellipsoid = Ellipsoid({ radius, radius, radius }); + setBoundingSphere(static_cast(_ellipsoid.maximumRadius())); + } + + if (dictionary.hasValue("PerformShading")) { + _generalProperties.performShading = dictionary.value("PerformShading"); + } + + // Init layer manager + ghoul::Dictionary layersDictionary; + if (!dictionary.getValue(KeyLayers, layersDictionary)) { + throw ghoul::RuntimeError(std::string(KeyLayers) + " must be specified"); + } + + _layerManager.initialize(layersDictionary); + + addProperty(_generalProperties.performShading); + addProperty(_generalProperties.useAccurateNormals); + addProperty(_generalProperties.eclipseShadowsEnabled); + addProperty(_generalProperties.eclipseHardShadows); + _generalProperties.lodScaleFactor.onChange([this]() { _lodScaleFactorDirty = true; }); + addProperty(_generalProperties.lodScaleFactor); + addProperty(_generalProperties.cameraMinHeight); + addProperty(_generalProperties.orenNayarRoughness); + + _debugPropertyOwner.addProperty(_debugProperties.showChunkEdges); + _debugPropertyOwner.addProperty(_debugProperties.showChunkBounds); + _debugPropertyOwner.addProperty(_debugProperties.showChunkAABB); + _debugPropertyOwner.addProperty(_debugProperties.showHeightResolution); + _debugPropertyOwner.addProperty(_debugProperties.showHeightIntensities); + _debugPropertyOwner.addProperty( + _debugProperties.levelByProjectedAreaElseDistance + ); + _debugPropertyOwner.addProperty(_debugProperties.resetTileProviders); + _debugPropertyOwner.addProperty(_debugProperties.modelSpaceRenderingCutoffLevel); + + auto notifyShaderRecompilation = [&]() { + _shadersNeedRecompilation = true; + }; + _generalProperties.useAccurateNormals.onChange(notifyShaderRecompilation); + _generalProperties.eclipseShadowsEnabled.onChange(notifyShaderRecompilation); + _generalProperties.eclipseHardShadows.onChange(notifyShaderRecompilation); + _generalProperties.performShading.onChange(notifyShaderRecompilation); + _debugProperties.showChunkEdges.onChange(notifyShaderRecompilation); + _debugProperties.showHeightResolution.onChange(notifyShaderRecompilation); + _debugProperties.showHeightIntensities.onChange(notifyShaderRecompilation); + + _layerManager.onChange([&]() { + _shadersNeedRecompilation = true; + _chunkCornersDirty = true; + }); + + addPropertySubOwner(_debugPropertyOwner); + addPropertySubOwner(_layerManager); + + //================================================================ + //======== Reads Shadow (Eclipses) Entries in mod file =========== + //================================================================ + ghoul::Dictionary shadowDictionary; + bool success = dictionary.getValue(KeyShadowGroup, shadowDictionary); + bool disableShadows = false; + if (success) { + std::vector> sourceArray; + unsigned int sourceCounter = 1; + while (success) { + std::string sourceName; + success = shadowDictionary.getValue(KeyShadowSource + + std::to_string(sourceCounter) + ".Name", sourceName); + if (success) { + double sourceRadius; + success = shadowDictionary.getValue(KeyShadowSource + + std::to_string(sourceCounter) + ".Radius", sourceRadius); + if (success) { + sourceArray.emplace_back(sourceName, sourceRadius); + } + else { + //LWARNING("No Radius value expecified for Shadow Source Name " + // << sourceName << " from " << name + // << " planet.\nDisabling shadows for this planet."); + disableShadows = true; + break; + } + } + sourceCounter++; + } + + if (!disableShadows && !sourceArray.empty()) { + success = true; + std::vector> casterArray; + unsigned int casterCounter = 1; + while (success) { + std::string casterName; + success = shadowDictionary.getValue(KeyShadowCaster + + std::to_string(casterCounter) + ".Name", casterName); + if (success) { + double casterRadius; + success = shadowDictionary.getValue(KeyShadowCaster + + std::to_string(casterCounter) + ".Radius", casterRadius); + if (success) { + casterArray.emplace_back(casterName, casterRadius); + } + else { + //LWARNING("No Radius value expecified for Shadow Caster Name " + // << casterName << " from " << name + // << " planet.\nDisabling shadows for this planet."); + disableShadows = true; + break; + } + } + + casterCounter++; + } + + std::vector shadowConfArray; + if (!disableShadows && (!sourceArray.empty() && !casterArray.empty())) { + for (const auto & source : sourceArray) { + for (const auto & caster : casterArray) { + Ellipsoid::ShadowConfiguration sc; + sc.source = source; + sc.caster = caster; + shadowConfArray.push_back(sc); + } + } + _ellipsoid.setShadowConfigurationArray(shadowConfArray); + } + } + } +} + +void RenderableGlobe::initializeGL() { + _layerManager.update(); + + _grid.initializeGL(); + // Recompile the shaders directly so that it is not done the first time the render + // function is called. + recompileShaders(); +} + +void RenderableGlobe::deinitialize() { + _layerManager.deinitialize(); +} + +void RenderableGlobe::deinitializeGL() { + if (_localRenderer.program) { + global::renderEngine.removeRenderProgram(_localRenderer.program.get()); + _localRenderer.program = nullptr; + } + + if (_globalRenderer.program) { + global::renderEngine.removeRenderProgram(_globalRenderer.program.get()); + _globalRenderer.program = nullptr; + } + + _grid.deinitializeGL(); +} + +bool RenderableGlobe::isReady() const { + return true; +} + +void RenderableGlobe::render(const RenderData& data, RendererTasks& rendererTask) { + const double distanceToCamera = distance( + data.camera.positionVec3(), + data.modelTransform.translation + ); + + // This distance will be enough to render the globe as one pixel if the field of + // view is 'fov' radians and the screen resolution is 'res' pixels. + //constexpr double fov = 2 * glm::pi() / 6; // 60 degrees + //constexpr double tfov = tan(fov / 2.0); // doesn't work unfortunately + constexpr double tfov = 0.5773502691896257; + constexpr int res = 2880; + const double distance = res * boundingSphere() / tfov; + + if (distanceToCamera < distance) { + renderChunks(data, rendererTask); + } +} + +void RenderableGlobe::update(const UpdateData& data) { + setBoundingSphere(static_cast( + _ellipsoid.maximumRadius() * data.modelTransform.scale + )); + + glm::dmat4 translation = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation); + glm::dmat4 rotation = glm::dmat4(data.modelTransform.rotation); + glm::dmat4 scaling = + glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale, + data.modelTransform.scale, data.modelTransform.scale)); + + _cachedModelTransform = translation * rotation * scaling; + _cachedInverseModelTransform = glm::inverse(_cachedModelTransform); + + if (_debugProperties.resetTileProviders) { + _layerManager.reset(); + _debugProperties.resetTileProviders = false; + } + _layerManager.update(); +} + +const LayerManager& RenderableGlobe::layerManager() const { + return _layerManager; +} + +LayerManager& RenderableGlobe::layerManager() { + return _layerManager; +} + +const Ellipsoid& RenderableGlobe::ellipsoid() const { + return _ellipsoid; +} + +const glm::dmat4& RenderableGlobe::modelTransform() const { + return _cachedModelTransform; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Rendering code +////////////////////////////////////////////////////////////////////////////////////////// + +void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&) { + if (_shadersNeedRecompilation) { + recompileShaders(); + } + + // + // Setting frame-const uniforms that are not view dependent + // + if (_layerManager.hasAnyBlendingLayersEnabled()) { + if (_lodScaleFactorDirty) { + const float dsf = static_cast( + _generalProperties.lodScaleFactor * _ellipsoid.minimumRadius() + ); + _globalRenderer.program->setUniform("distanceScaleFactor", dsf); + _localRenderer.program->setUniform("distanceScaleFactor", dsf); + _lodScaleFactorDirty = false; + } + } + + if (_generalProperties.performShading) { + const bool onr = _generalProperties.orenNayarRoughness; + _localRenderer.program->setUniform("orenNayarRoughness", onr); + _globalRenderer.program->setUniform("orenNayarRoughness", onr); + } + + + if (_globalRenderer.updatedSinceLastCall) { + const std::array& layerGroups = + _layerManager.layerGroups(); + for (size_t i = 0; i < layerGroups.size(); ++i) { + const std::string& nameBase = layergroupid::LAYER_GROUP_IDENTIFIERS[i]; + _globalRenderer.gpuLayerGroups[i].bind( + *_globalRenderer.program, + *layerGroups[i], + nameBase, + static_cast(i) + ); + } + + _globalRenderer.updatedSinceLastCall = false; + } + + if (_localRenderer.updatedSinceLastCall) { + const std::array& layerGroups = + _layerManager.layerGroups(); + for (size_t i = 0; i < layerGroups.size(); ++i) { + const std::string& nameBase = layergroupid::LAYER_GROUP_IDENTIFIERS[i]; + _localRenderer.gpuLayerGroups[i].bind( + *_localRenderer.program, + *layerGroups[i], + nameBase, + static_cast(i) + ); + } + + _localRenderer.updatedSinceLastCall = false; + } + + updateChunkTree(_leftRoot, data); + updateChunkTree(_rightRoot, data); + _chunkCornersDirty = false; + + // Calculate the MVP matrix + const glm::dmat4& viewTransform = data.camera.combinedViewMatrix(); + const glm::dmat4 vp = glm::dmat4(data.camera.sgctInternal.projectionMatrix()) * + viewTransform; + const glm::dmat4 mvp = vp * _cachedModelTransform; + + // + // Setting uniforms that don't change between chunks but are view dependent + // + + // Global shader + if (_layerManager.hasAnyBlendingLayersEnabled()) { + // Calculations are done in the reference frame of the globe. Hence, the + // camera position needs to be transformed with the inverse model matrix + const glm::dvec3 cameraPosition = glm::dvec3( + _cachedInverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1.0) + ); + + _globalRenderer.program->setUniform("cameraPosition", glm::vec3(cameraPosition)); + } + + const glm::mat4 modelViewTransform = glm::mat4(viewTransform * _cachedModelTransform); + const glm::mat4 modelViewProjectionTransform = + data.camera.sgctInternal.projectionMatrix() * modelViewTransform; + + // Upload the uniform variables + _globalRenderer.program->setUniform( + "modelViewProjectionTransform", + modelViewProjectionTransform + ); + + const bool hasNightLayers = !_layerManager.layerGroup( + layergroupid::GroupID::NightLayers + ).activeLayers().empty(); + + const bool hasWaterLayer = !_layerManager.layerGroup( + layergroupid::GroupID::WaterMasks + ).activeLayers().empty(); + if (hasNightLayers || hasWaterLayer || _generalProperties.performShading) { + _globalRenderer.program->setUniform("modelViewTransform", modelViewTransform); + } + + const bool hasHeightLayer = !_layerManager.layerGroup( + layergroupid::HeightLayers + ).activeLayers().empty(); + if (_generalProperties.useAccurateNormals && hasHeightLayer) { + // Apply an extra scaling to the height if the object is scaled + _globalRenderer.program->setUniform( + "heightScale", + static_cast(data.modelTransform.scale * data.camera.scaling()) + ); + } + + const bool nightLayersActive = + !_layerManager.layerGroup(layergroupid::NightLayers).activeLayers().empty(); + const bool waterLayersActive = + !_layerManager.layerGroup(layergroupid::WaterMasks).activeLayers().empty(); + + if (nightLayersActive || waterLayersActive || _generalProperties.performShading) { + const glm::dvec3 directionToSunWorldSpace = + length(data.modelTransform.translation) > 0.0 ? + glm::normalize(-data.modelTransform.translation) : + glm::dvec3(0.0); + + const glm::vec3 directionToSunCameraSpace = glm::vec3(viewTransform * + glm::dvec4(directionToSunWorldSpace, 0)); + _globalRenderer.program->setUniform( + "lightDirectionCameraSpace", + -glm::normalize(directionToSunCameraSpace) + ); + } + + + // Local shader + _localRenderer.program->setUniform( + "projectionTransform", + data.camera.sgctInternal.projectionMatrix() + ); + + if (nightLayersActive || waterLayersActive || _generalProperties.performShading) { + const glm::dvec3 directionToSunWorldSpace = + length(data.modelTransform.translation) > 0.0 ? + glm::normalize(-data.modelTransform.translation) : + glm::dvec3(0.0); + + const glm::vec3 directionToSunCameraSpace = glm::vec3(viewTransform * + glm::dvec4(directionToSunWorldSpace, 0)); + _localRenderer.program->setUniform( + "lightDirectionCameraSpace", + -glm::normalize(directionToSunCameraSpace) + ); + } + + if (_generalProperties.useAccurateNormals && + !_layerManager.layerGroup(layergroupid::HeightLayers).activeLayers().empty()) + { + // This should not be needed once the light calculations for the atmosphere + // is performed in view space.. + _localRenderer.program->setUniform( + "invViewModelTransform", + glm::inverse( + glm::mat4(data.camera.combinedViewMatrix()) * + glm::mat4(_cachedModelTransform) + ) + ); + _globalRenderer.program->setUniform( + "invViewModelTransform", + glm::inverse( + glm::mat4(data.camera.combinedViewMatrix()) * + glm::mat4(_cachedModelTransform) + ) + ); + } + + constexpr const int ChunkBufferSize = 2048; + std::array global; + int globalCount = 0; + std::array local; + int localCount = 0; + + auto traversal = [&global, &globalCount, &local, &localCount, + cutoff = _debugProperties.modelSpaceRenderingCutoffLevel](const Chunk& node) + { + std::vector Q; + Q.reserve(256); + + // Loop through nodes in breadths first order + Q.push_back(&node); + while (!Q.empty()) { + const Chunk* n = Q.front(); + Q.erase(Q.begin()); + + if (isLeaf(*n) && n->isVisible) { + if (n->tileIndex.level < cutoff) { + global[globalCount] = n; + ++globalCount; + } + else { + local[localCount] = n; + ++localCount; + } + } + + // Add children to queue, if any + if (!isLeaf(*n)) { + for (int i = 0; i < 4; ++i) { + Q.push_back(n->children[i]); + } + } + } + }; + + traversal(_leftRoot); + traversal(_rightRoot); + + // Render all chunks that want to be rendered globally + _globalRenderer.program->activate(); + for (int i = 0; i < std::min(globalCount, ChunkBufferSize); ++i) { + renderChunkGlobally(*global[i], data); + } + _globalRenderer.program->deactivate(); + + + // Render all chunks that need to be rendered locally + _localRenderer.program->activate(); + for (int i = 0; i < std::min(localCount, ChunkBufferSize); ++i) { + renderChunkLocally(*local[i], data); + } + _localRenderer.program->deactivate(); + + + if (_debugProperties.showChunkBounds || _debugProperties.showChunkAABB) { + for (int i = 0; i < std::min(globalCount, ChunkBufferSize); ++i) { + debugRenderChunk( + *global[i], + mvp, + _debugProperties.showChunkBounds, + _debugProperties.showChunkAABB + ); + } + + for (int i = 0; i < std::min(localCount, ChunkBufferSize); ++i) { + debugRenderChunk( + *local[i], + mvp, + _debugProperties.showChunkBounds, + _debugProperties.showChunkAABB + ); + } + } +} + +void RenderableGlobe::renderChunkGlobally(const Chunk& chunk, const RenderData& data) { + //PerfMeasure("globally"); + const TileIndex& tileIndex = chunk.tileIndex; + ghoul::opengl::ProgramObject& program = *_globalRenderer.program; + + const std::array& layerGroups = + _layerManager.layerGroups(); + for (size_t i = 0; i < layerGroups.size(); ++i) { + _globalRenderer.gpuLayerGroups[i].setValue(program, *layerGroups[i], tileIndex); + } + + // The length of the skirts is proportional to its size + program.setUniform( + _globalRenderer.uniformCache.skirtLength, + static_cast( + glm::min( + chunk.surfacePatch.halfSize().lat * 1000000, + _ellipsoid.minimumRadius() + ) + ) + ); + + if (_layerManager.hasAnyBlendingLayersEnabled()) { + program.setUniform("chunkLevel", chunk.tileIndex.level); + } + + // Calculate other uniform variables needed for rendering + const Geodetic2 swCorner = chunk.surfacePatch.corner(Quad::SOUTH_WEST); + const Geodetic2& patchSize = chunk.surfacePatch.size(); + + program.setUniform( + _globalRenderer.uniformCache.minLatLon, + glm::vec2(swCorner.lon, swCorner.lat) + ); + program.setUniform( + _globalRenderer.uniformCache.lonLatScalingFactor, + glm::vec2(patchSize.lon, patchSize.lat) + ); + + setCommonUniforms(program, chunk, data); + + if (_generalProperties.eclipseShadowsEnabled && + !_ellipsoid.shadowConfigurationArray().empty()) + { + calculateEclipseShadows(program, data); + } + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + _grid.drawUsingActiveProgram(); + for (GPULayerGroup& l : _globalRenderer.gpuLayerGroups) { + l.deactivate(); + } +} + +void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& data) { + //PerfMeasure("locally"); + const TileIndex& tileIndex = chunk.tileIndex; + ghoul::opengl::ProgramObject& program = *_localRenderer.program; + + const std::array& layerGroups = + _layerManager.layerGroups(); + for (size_t i = 0; i < layerGroups.size(); ++i) { + _localRenderer.gpuLayerGroups[i].setValue(program, *layerGroups[i], tileIndex); + } + + // The length of the skirts is proportional to its size + program.setUniform( + _localRenderer.uniformCache.skirtLength, + static_cast( + glm::min( + chunk.surfacePatch.halfSize().lat * 1000000, + _ellipsoid.minimumRadius() + ) + ) + ); + + if (_layerManager.hasAnyBlendingLayersEnabled()) { + program.setUniform("chunkLevel", chunk.tileIndex.level); + } + + // Calculate other uniform variables needed for rendering + // Send the matrix inverse to the fragment for the global and local shader (JCC) + const glm::dmat4 viewTransform = data.camera.combinedViewMatrix(); + const glm::dmat4 modelViewTransform = viewTransform * _cachedModelTransform; + + + std::array cornersCameraSpace; + std::array cornersModelSpace; + for (int i = 0; i < 4; ++i) { + const Quad q = static_cast(i); + const Geodetic2 corner = chunk.surfacePatch.corner(q); + const glm::dvec3 cornerModelSpace = _ellipsoid.cartesianSurfacePosition(corner); + cornersModelSpace[i] = cornerModelSpace; + const glm::dvec3 cornerCameraSpace = glm::dvec3( + modelViewTransform * glm::dvec4(cornerModelSpace, 1) + ); + cornersCameraSpace[i] = cornerCameraSpace; + } + _localRenderer.program->setUniform( + _localRenderer.uniformCache.p01, + glm::vec3(cornersCameraSpace[0]) + ); + _localRenderer.program->setUniform( + _localRenderer.uniformCache.p11, + glm::vec3(cornersCameraSpace[1]) + ); + _localRenderer.program->setUniform( + _localRenderer.uniformCache.p00, + glm::vec3(cornersCameraSpace[2]) + ); + _localRenderer.program->setUniform( + _localRenderer.uniformCache.p10, + glm::vec3(cornersCameraSpace[3]) + ); + + // TODO: Patch normal can be calculated for all corners and then linearly + // interpolated on the GPU to avoid cracks for high altitudes. + const glm::vec3 patchNormalCameraSpace = normalize( + cross( + cornersCameraSpace[Quad::SOUTH_EAST] - cornersCameraSpace[Quad::SOUTH_WEST], + cornersCameraSpace[Quad::NORTH_EAST] - cornersCameraSpace[Quad::SOUTH_WEST] + ) + ); + + // In order to improve performance, lets use the normal in object space (model space) + // for deferred rendering. + const glm::vec3 patchNormalModelSpace = normalize( + cross( + cornersModelSpace[Quad::SOUTH_EAST] - cornersModelSpace[Quad::SOUTH_WEST], + cornersModelSpace[Quad::NORTH_EAST] - cornersModelSpace[Quad::SOUTH_WEST] + ) + ); + + program.setUniform( + _localRenderer.uniformCache.patchNormalModelSpace, + patchNormalModelSpace + ); + program.setUniform( + _localRenderer.uniformCache.patchNormalCameraSpace, + patchNormalCameraSpace + ); + + if (!_layerManager.layerGroup(layergroupid::HeightLayers).activeLayers().empty()) { + // Apply an extra scaling to the height if the object is scaled + program.setUniform( + "heightScale", + static_cast(data.modelTransform.scale * data.camera.scaling()) + ); + } + + setCommonUniforms(program, chunk, data); + + if (_generalProperties.eclipseShadowsEnabled && + !_ellipsoid.shadowConfigurationArray().empty()) + { + calculateEclipseShadows(program, data); + } + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + _grid.drawUsingActiveProgram(); + + for (GPULayerGroup& l : _localRenderer.gpuLayerGroups) { + l.deactivate(); + } +} + +void RenderableGlobe::debugRenderChunk(const Chunk& chunk, const glm::dmat4& mvp, + bool renderBounds, bool renderAABB) const { + const std::array& modelSpaceCorners = chunk.corners; + + std::vector clippingSpaceCorners(8); + AABB3 screenSpaceBounds; + + for (size_t i = 0; i < 8; ++i) { + const glm::vec4& clippingSpaceCorner = mvp * modelSpaceCorners[i]; + clippingSpaceCorners[i] = clippingSpaceCorner; + + glm::vec3 screenSpaceCorner = + glm::vec3((1.f / clippingSpaceCorner.w) * clippingSpaceCorner); + expand(screenSpaceBounds, std::move(screenSpaceCorner)); + } + + const unsigned int colorBits = 1 + chunk.tileIndex.level % 6; + const glm::vec4 color = glm::vec4( + colorBits & 1, + colorBits & 2, + colorBits & 4, + 0.3f + ); + + if (renderBounds) { + DebugRenderer::ref().renderNiceBox(clippingSpaceCorners, color); + } + + if (renderAABB) { + const std::vector& screenSpacePoints = + DebugRenderer::ref().verticesFor(screenSpaceBounds); + DebugRenderer::ref().renderNiceBox(screenSpacePoints, color); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Shader code +////////////////////////////////////////////////////////////////////////////////////////// + +void RenderableGlobe::setCommonUniforms(ghoul::opengl::ProgramObject& programObject, + const Chunk& chunk, const RenderData& data) +{ + if (_generalProperties.useAccurateNormals && + !_layerManager.layerGroup(layergroupid::HeightLayers).activeLayers().empty()) + { + const glm::dvec3 corner00 = _ellipsoid.cartesianSurfacePosition( + chunk.surfacePatch.corner(Quad::SOUTH_WEST) + ); + const glm::dvec3 corner10 = _ellipsoid.cartesianSurfacePosition( + chunk.surfacePatch.corner(Quad::SOUTH_EAST) + ); + const glm::dvec3 corner01 = _ellipsoid.cartesianSurfacePosition( + chunk.surfacePatch.corner(Quad::NORTH_WEST) + ); + const glm::dvec3 corner11 = _ellipsoid.cartesianSurfacePosition( + chunk.surfacePatch.corner(Quad::NORTH_EAST) + ); + + const glm::mat4 modelViewTransform = glm::mat4( + data.camera.combinedViewMatrix() * _cachedModelTransform + ); + + const glm::mat3& modelViewTransformMat3 = glm::mat3(modelViewTransform); + + // This is an assumption that the height tile has a resolution of 64 * 64 + // If it does not it will still produce "correct" normals. If the resolution is + // higher the shadows will be softer, if it is lower, pixels will be visible. + // Since default is 64 this will most likely work fine. + constexpr const float TileDelta = 1.f / DefaultSkirtedGridSegments; + const glm::vec3 deltaTheta0 = modelViewTransformMat3 * + (glm::vec3(corner10 - corner00) * TileDelta); + const glm::vec3 deltaTheta1 = modelViewTransformMat3 * + (glm::vec3(corner11 - corner01) * TileDelta); + const glm::vec3 deltaPhi0 = modelViewTransformMat3 * + (glm::vec3(corner01 - corner00) * TileDelta); + const glm::vec3 deltaPhi1 = modelViewTransformMat3 * + (glm::vec3(corner11 - corner10) * TileDelta); + + // Upload uniforms + programObject.setUniform("deltaTheta0", glm::length(deltaTheta0)); + programObject.setUniform("deltaTheta1", glm::length(deltaTheta1)); + programObject.setUniform("deltaPhi0", glm::length(deltaPhi0)); + programObject.setUniform("deltaPhi1", glm::length(deltaPhi1)); + programObject.setUniform("tileDelta", TileDelta); + } +} + +void RenderableGlobe::recompileShaders() { + struct LayerShaderPreprocessingData { + struct LayerGroupPreprocessingData { + int lastLayerIdx; + bool layerBlendingEnabled; + std::vector layerType; + std::vector blendMode; + std::vector layerAdjustmentType; + }; + + std::array + layeredTextureInfo; + std::vector> keyValuePairs; + }; + + // + // Create LayerShaderPreprocessingData + // + + LayerShaderPreprocessingData preprocessingData; + + for (size_t i = 0; i < layergroupid::NUM_LAYER_GROUPS; i++) { + LayerShaderPreprocessingData::LayerGroupPreprocessingData layeredTextureInfo; + + const LayerGroup& layerGroup = _layerManager.layerGroup(layergroupid::GroupID(i)); + const std::vector& layers = layerGroup.activeLayers(); + + // This check was implicit before; not sure if it will fire or will be handled + // elsewhere + //ghoul_assert( + // !layerGroup.activeLayers().empty(), + // "If activeLayers is empty the following line will lead to an overflow" + //); + layeredTextureInfo.lastLayerIdx = static_cast( + layerGroup.activeLayers().size() - 1 + ); + layeredTextureInfo.layerBlendingEnabled = layerGroup.layerBlendingEnabled(); + + for (Layer* layer : layers) { + layeredTextureInfo.layerType.push_back(layer->type()); + layeredTextureInfo.blendMode.push_back(layer->blendMode()); + layeredTextureInfo.layerAdjustmentType.push_back( + layer->layerAdjustment().type() + ); + } + + preprocessingData.layeredTextureInfo[i] = layeredTextureInfo; + } + + std::vector>& pairs = + preprocessingData.keyValuePairs; + + pairs.emplace_back("useAccurateNormals", + std::to_string(_generalProperties.useAccurateNormals) + ); + pairs.emplace_back( + "performShading", + std::to_string(_generalProperties.performShading) + ); + pairs.emplace_back( + "useEclipseShadows", + std::to_string(_generalProperties.eclipseShadowsEnabled) + ); + pairs.emplace_back( + "useEclipseHardShadows", + std::to_string(_generalProperties.eclipseHardShadows) + ); + pairs.emplace_back("showChunkEdges", std::to_string(_debugProperties.showChunkEdges)); + pairs.emplace_back("showHeightResolution", + std::to_string(_debugProperties.showHeightResolution) + ); + pairs.emplace_back("showHeightIntensities", + std::to_string(_debugProperties.showHeightIntensities) + ); + pairs.emplace_back("defaultHeight", std::to_string(DefaultHeight)); + + + // + // Create dictionary from layerpreprocessing data + // + + ghoul::Dictionary shaderDictionary; + + // Different layer types can be height layers or color layers for example. + // These are used differently within the shaders. + preprocessingData.layeredTextureInfo; + + for (size_t i = 0; i < preprocessingData.layeredTextureInfo.size(); i++) { + // lastLayerIndex must be at least 0 for the shader to compile, + // the layer type is inactivated by setting use to false + const std::string& groupName = layergroupid::LAYER_GROUP_IDENTIFIERS[i]; + shaderDictionary.setValue( + "lastLayerIndex" + groupName, + glm::max(preprocessingData.layeredTextureInfo[i].lastLayerIdx, 0) + ); + shaderDictionary.setValue( + "use" + groupName, + preprocessingData.layeredTextureInfo[i].lastLayerIdx >= 0 + ); + shaderDictionary.setValue( + "blend" + groupName, + preprocessingData.layeredTextureInfo[i].layerBlendingEnabled + ); + + // This is to avoid errors from shader preprocessor + shaderDictionary.setValue(groupName + "0" + "LayerType", 0); + + for (int j = 0; + j < preprocessingData.layeredTextureInfo[i].lastLayerIdx + 1; + ++j) + { + shaderDictionary.setValue( + groupName + std::to_string(j) + "LayerType", + static_cast(preprocessingData.layeredTextureInfo[i].layerType[j]) + ); + } + + // This is to avoid errors from shader preprocessor + shaderDictionary.setValue(groupName + "0" + "BlendMode", 0); + + for (int j = 0; + j < preprocessingData.layeredTextureInfo[i].lastLayerIdx + 1; + ++j) + { + shaderDictionary.setValue( + groupName + std::to_string(j) + "BlendMode", + static_cast(preprocessingData.layeredTextureInfo[i].blendMode[j]) + ); + } + + // This is to avoid errors from shader preprocessor + std::string keyLayerAdjustmentType = groupName + "0" + "LayerAdjustmentType"; + shaderDictionary.setValue(keyLayerAdjustmentType, 0); + + for (int j = 0; + j < preprocessingData.layeredTextureInfo[i].lastLayerIdx + 1; + ++j) + { + shaderDictionary.setValue( + groupName + std::to_string(j) + "LayerAdjustmentType", + static_cast( + preprocessingData.layeredTextureInfo[i].layerAdjustmentType[j] + ) + ); + } + } + + ghoul::Dictionary layerGroupNames; + for (int i = 0; i < layergroupid::NUM_LAYER_GROUPS; ++i) { + layerGroupNames.setValue( + std::to_string(i), + layergroupid::LAYER_GROUP_IDENTIFIERS[i] + ); + } + shaderDictionary.setValue("layerGroups", layerGroupNames); + + for (const std::pair& p : preprocessingData.keyValuePairs) + { + shaderDictionary.setValue(p.first, p.second); + } + + // + // Create local shader + // + global::renderEngine.removeRenderProgram(_localRenderer.program.get()); + _localRenderer.program = global::renderEngine.buildRenderProgram( + "LocalChunkedLodPatch", + absPath("${MODULE_GLOBEBROWSING}/shaders/localrenderer_vs.glsl"), + absPath("${MODULE_GLOBEBROWSING}/shaders/renderer_fs.glsl"), + shaderDictionary + ); + ghoul_assert(_localRenderer.program, "Failed to initialize programObject!"); + _localRenderer.updatedSinceLastCall = true; + + _localRenderer.program->setUniform("xSegments", _grid.xSegments); + + if (_debugProperties.showHeightResolution) { + _localRenderer.program->setUniform( + "vertexResolution", + glm::vec2(_grid.xSegments, _grid.ySegments) + ); + } + + ghoul::opengl::updateUniformLocations( + *_localRenderer.program, + _localRenderer.uniformCache, + { "skirtLength", "p01", "p11", "p00", "p10", "patchNormalModelSpace", + "patchNormalCameraSpace" } + ); + + + // + // Create global shader + // + global::renderEngine.removeRenderProgram(_globalRenderer.program.get()); + _globalRenderer.program = global::renderEngine.buildRenderProgram( + "GlobalChunkedLodPatch", + absPath("${MODULE_GLOBEBROWSING}/shaders/globalrenderer_vs.glsl"), + absPath("${MODULE_GLOBEBROWSING}/shaders/renderer_fs.glsl"), + shaderDictionary + ); + ghoul_assert(_globalRenderer.program, "Failed to initialize programObject!"); + + _globalRenderer.program->setUniform("xSegments", _grid.xSegments); + + if (_debugProperties.showHeightResolution) { + _globalRenderer.program->setUniform( + "vertexResolution", + glm::vec2(_grid.xSegments, _grid.ySegments) + ); + } + // Ellipsoid Radius (Model Space) + _globalRenderer.program->setUniform( + "radiiSquared", + glm::vec3(_ellipsoid.radii() * _ellipsoid.radii()) + ); + + ghoul::opengl::updateUniformLocations( + *_globalRenderer.program, + _globalRenderer.uniformCache, + { "skirtLength", "minLatLon", "lonLatScalingFactor" } + ); + + _globalRenderer.updatedSinceLastCall = true; + _shadersNeedRecompilation = false; +} + +SurfacePositionHandle RenderableGlobe::calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace) const +{ + glm::dvec3 centerToEllipsoidSurface = + _ellipsoid.geodeticSurfaceProjection(targetModelSpace); + glm::dvec3 ellipsoidSurfaceToTarget = targetModelSpace - centerToEllipsoidSurface; + // ellipsoidSurfaceOutDirection will point towards the target, we want the outward + // direction. Therefore it must be flipped in case the target is under the reference + // ellipsoid so that it always points outwards + glm::dvec3 ellipsoidSurfaceOutDirection = glm::normalize(ellipsoidSurfaceToTarget); + if (glm::dot(ellipsoidSurfaceOutDirection, centerToEllipsoidSurface) < 0) { + ellipsoidSurfaceOutDirection *= -1.0; + } + + double heightToSurface = getHeight(targetModelSpace); + heightToSurface = glm::isnan(heightToSurface) ? 0.0 : heightToSurface; + centerToEllipsoidSurface = glm::isnan(glm::length(centerToEllipsoidSurface)) ? + (glm::dvec3(0.0, 1.0, 0.0) * static_cast(boundingSphere())) : + centerToEllipsoidSurface; + ellipsoidSurfaceOutDirection = glm::isnan(glm::length(ellipsoidSurfaceOutDirection)) ? + glm::dvec3(0.0, 1.0, 0.0) : ellipsoidSurfaceOutDirection; + + return { + centerToEllipsoidSurface, + ellipsoidSurfaceOutDirection, + heightToSurface + }; +} + + + +bool RenderableGlobe::testIfCullable(const Chunk& chunk, + const RenderData& renderData) const +{ + return (PreformHorizonCulling && isCullableByHorizon(chunk, renderData)) || + (PerformFrustumCulling && isCullableByFrustum(chunk, renderData)); +} + +int RenderableGlobe::desiredLevel(const Chunk& chunk, const RenderData& renderData) const +{ + const int desiredLevel = _debugProperties.levelByProjectedAreaElseDistance ? + desiredLevelByProjectedArea(chunk, renderData) : + desiredLevelByDistance(chunk, renderData); + const int levelByAvailableData = desiredLevelByAvailableTileData(chunk); + + if (LimitLevelByAvailableData && (levelByAvailableData != UnknownDesiredLevel)) { + const int l = glm::min(desiredLevel, levelByAvailableData); + return glm::clamp(l, MinSplitDepth, MaxSplitDepth); + } + else { + return glm::clamp(desiredLevel, MinSplitDepth, MaxSplitDepth); + } +} + +float RenderableGlobe::getHeight(const glm::dvec3& position) const { + float height = 0; + + // Get the uv coordinates to sample from + const Geodetic2 geodeticPosition = _ellipsoid.cartesianToGeodetic2(position); + const Chunk& node = geodeticPosition.lon < Coverage.center().lon ? + findChunkNode(_leftRoot, geodeticPosition) : + findChunkNode(_rightRoot, geodeticPosition); + const int chunkLevel = node.tileIndex.level; + + + //TileIndex::TileIndex(const Geodetic2& point, int level_) + // : level(level_) + //{ + const int numIndicesAtLevel = 1 << chunkLevel; + const double u = 0.5 + geodeticPosition.lon / glm::two_pi(); + const double v = 0.25 - geodeticPosition.lat / glm::two_pi(); + const double xIndexSpace = u * numIndicesAtLevel; + const double yIndexSpace = v * numIndicesAtLevel; + + const int x = static_cast(floor(xIndexSpace)); + const int y = static_cast(floor(yIndexSpace)); + + const TileIndex tileIndex(x, y, chunkLevel); + const GeodeticPatch patch = GeodeticPatch(tileIndex); + + const Geodetic2 northEast = patch.corner(Quad::NORTH_EAST); + const Geodetic2 southWest = patch.corner(Quad::SOUTH_WEST); + + const Geodetic2 geoDiffPatch = { + northEast.lat - southWest.lat, + northEast.lon - southWest.lon + }; + + const Geodetic2 geoDiffPoint = { + geodeticPosition.lat - southWest.lat, + geodeticPosition.lon - southWest.lon + }; + const glm::vec2 patchUV = glm::vec2( + geoDiffPoint.lon / geoDiffPatch.lon, + geoDiffPoint.lat / geoDiffPatch.lat + ); + + // Get the tile providers for the height maps + const std::vector& heightMapLayers = + _layerManager.layerGroup(layergroupid::GroupID::HeightLayers).activeLayers(); + + for (Layer* layer : heightMapLayers) { + tileprovider::TileProvider* tileProvider = layer->tileProvider(); + if (!tileProvider) { + continue; + } + // Transform the uv coordinates to the current tile texture + const ChunkTile chunkTile = tileprovider::chunkTile(*tileProvider, tileIndex); + const Tile& tile = chunkTile.tile; + const TileUvTransform& uvTransform = chunkTile.uvTransform; + const TileDepthTransform& depthTransform = + tileprovider::depthTransform(*tileProvider); + if (tile.status != Tile::Status::OK) { + return 0; + } + + ghoul::opengl::Texture* tileTexture = tile.texture; + if (!tileTexture) { + return 0; + } + + glm::vec2 transformedUv = layer->tileUvToTextureSamplePosition( + uvTransform, + patchUV, + glm::uvec2(tileTexture->dimensions()) + ); + + // Sample and do linear interpolation + // (could possibly be moved as a function in ghoul texture) + // Suggestion: a function in ghoul::opengl::Texture that takes uv coordinates + // in range [0,1] and uses the set interpolation method and clamping. + + const glm::uvec3 dimensions = tileTexture->dimensions(); + + const glm::vec2 samplePos = transformedUv * glm::vec2(dimensions); + glm::uvec2 samplePos00 = samplePos; + samplePos00 = glm::clamp( + samplePos00, + glm::uvec2(0, 0), + glm::uvec2(dimensions) - glm::uvec2(1) + ); + const glm::vec2 samplePosFract = samplePos - glm::vec2(samplePos00); + + const glm::uvec2 samplePos10 = glm::min( + samplePos00 + glm::uvec2(1, 0), + glm::uvec2(dimensions) - glm::uvec2(1) + ); + const glm::uvec2 samplePos01 = glm::min( + samplePos00 + glm::uvec2(0, 1), + glm::uvec2(dimensions) - glm::uvec2(1) + ); + const glm::uvec2 samplePos11 = glm::min( + samplePos00 + glm::uvec2(1, 1), + glm::uvec2(dimensions) - glm::uvec2(1) + ); + + const float sample00 = tileTexture->texelAsFloat(samplePos00).x; + const float sample10 = tileTexture->texelAsFloat(samplePos10).x; + const float sample01 = tileTexture->texelAsFloat(samplePos01).x; + const float sample11 = tileTexture->texelAsFloat(samplePos11).x; + + // In case the texture has NaN or no data values don't use this height map. + const bool anySampleIsNaN = + std::isnan(sample00) || + std::isnan(sample01) || + std::isnan(sample10) || + std::isnan(sample11); + + const bool anySampleIsNoData = + sample00 == tileprovider::noDataValueAsFloat(*tileProvider) || + sample01 == tileprovider::noDataValueAsFloat(*tileProvider) || + sample10 == tileprovider::noDataValueAsFloat(*tileProvider) || + sample11 == tileprovider::noDataValueAsFloat(*tileProvider); + + if (anySampleIsNaN || anySampleIsNoData) { + continue; + } + + const float sample0 = sample00 * (1.f - samplePosFract.x) + + sample10 * samplePosFract.x; + const float sample1 = sample01 * (1.f - samplePosFract.x) + + sample11 * samplePosFract.x; + + const float sample = sample0 * (1.f - samplePosFract.y) + + sample1 * samplePosFract.y; + + // Same as is used in the shader. This is not a perfect solution but + // if the sample is actually a no-data-value (min_float) the interpolated + // value might not be. Therefore we have a cut-off. Assuming no data value + // is smaller than -100000 + if (sample > -100000) { + // Perform depth transform to get the value in meters + height = depthTransform.offset + depthTransform.scale * 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; +} + +void RenderableGlobe::calculateEclipseShadows(ghoul::opengl::ProgramObject& programObject, + const RenderData& data) +{ + constexpr const double KM_TO_M = 1000.0; + + ghoul_assert( + !_ellipsoid.shadowConfigurationArray().empty(), + "Needs to have eclipse shadows enabled" + ); + // Shadow calculations.. + std::vector shadowDataArray; + std::vector shadowConfArray = + _ellipsoid.shadowConfigurationArray(); + shadowDataArray.reserve(shadowConfArray.size()); + double lt; + for (const auto& shadowConf : shadowConfArray) { + // TO REMEMBER: all distances and lengths in world coordinates are in + // meters!!! We need to move this to view space... + // Getting source and caster: + glm::dvec3 sourcePos = SpiceManager::ref().targetPosition( + shadowConf.source.first, + "SUN", + "GALACTIC", + {}, + data.time.j2000Seconds(), + lt + ); + sourcePos *= KM_TO_M; // converting to meters + glm::dvec3 casterPos = SpiceManager::ref().targetPosition( + shadowConf.caster.first, + "SUN", + "GALACTIC", + {}, + data.time.j2000Seconds(), + lt + ); + casterPos *= KM_TO_M; // converting to meters + // psc caster_pos = PowerScaledCoordinate::CreatePowerScaledCoordinate( + // casterPos.x, + // casterPos.y, + // casterPos.z + // ); + + + // First we determine if the caster is shadowing the current planet (all + // calculations in World Coordinates): + const glm::dvec3 planetCasterVec = casterPos - data.position.dvec3(); + const glm::dvec3 sourceCasterVec = casterPos - sourcePos; + const double sc_length = glm::length(sourceCasterVec); + const glm::dvec3 planetCaster_proj = + (glm::dot(planetCasterVec, sourceCasterVec) / (sc_length*sc_length)) * + sourceCasterVec; + const double d_test = glm::length(planetCasterVec - planetCaster_proj); + const double xp_test = shadowConf.caster.second * sc_length / + (shadowConf.source.second + shadowConf.caster.second); + const double rp_test = shadowConf.caster.second * + (glm::length(planetCaster_proj) + xp_test) / xp_test; + + const glm::dvec3 sunPos = SpiceManager::ref().targetPosition( + "SUN", + "SUN", + "GALACTIC", + {}, + data.time.j2000Seconds(), + lt + ); + const double casterDistSun = glm::length(casterPos - sunPos); + const double planetDistSun = glm::length(data.position.dvec3() - sunPos); + + ShadowRenderingStruct shadowData; + shadowData.isShadowing = false; + + // Eclipse shadows considers planets and moons as spheres + if (((d_test - rp_test) < (_ellipsoid.radii().x * KM_TO_M)) && + (casterDistSun < planetDistSun)) + { + // The current caster is shadowing the current planet + shadowData.isShadowing = true; + shadowData.rs = shadowConf.source.second; + shadowData.rc = shadowConf.caster.second; + shadowData.sourceCasterVec = glm::normalize(sourceCasterVec); + shadowData.xp = xp_test; + shadowData.xu = shadowData.rc * sc_length / + (shadowData.rs - shadowData.rc); + shadowData.casterPositionVec = casterPos; + } + shadowDataArray.push_back(shadowData); + } + + const std::string uniformVarName("shadowDataArray["); + unsigned int counter = 0; + for (const ShadowRenderingStruct& sd : shadowDataArray) { + constexpr const char* NameIsShadowing = "shadowDataArray[{}].isShadowing"; + constexpr const char* NameXp = "shadowDataArray[{}].xp"; + constexpr const char* NameXu = "shadowDataArray[{}].xu"; + constexpr const char* NameRc = "shadowDataArray[{}].rc"; + constexpr const char* NameSource = "shadowDataArray[{}].sourceCasterVec"; + constexpr const char* NamePos = "shadowDataArray[{}].casterPositionVec"; + + programObject.setUniform( + fmt::format(NameIsShadowing, counter), sd.isShadowing + ); + if (sd.isShadowing) { + programObject.setUniform(fmt::format(NameXp, counter), sd.xp); + programObject.setUniform(fmt::format(NameXu, counter), sd.xu); + programObject.setUniform(fmt::format(NameRc, counter), sd.rc); + programObject.setUniform( + fmt::format(NameSource, counter), sd.sourceCasterVec + ); + programObject.setUniform( + fmt::format(NamePos, counter), sd.casterPositionVec + ); + } + counter++; + } + + programObject.setUniform( + "inverseViewTransform", + glm::inverse(data.camera.combinedViewMatrix()) + ); + programObject.setUniform("modelTransform", _cachedModelTransform); + programObject.setUniform( + "hardShadows", + _generalProperties.eclipseHardShadows + ); + programObject.setUniform("calculateEclipseShadows", true); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Desired Level +////////////////////////////////////////////////////////////////////////////////////////// + +int RenderableGlobe::desiredLevelByDistance(const Chunk& chunk, + const RenderData& data) const +{ + // Calculations are done in the reference frame of the globe + // (model space). Hence, the camera position needs to be transformed + // with the inverse model matrix + const glm::dvec3 cameraPosition = glm::dvec3(_cachedInverseModelTransform * + glm::dvec4(data.camera.positionVec3(), 1.0)); + + const Geodetic2 pointOnPatch = chunk.surfacePatch.closestPoint( + _ellipsoid.cartesianToGeodetic2(cameraPosition) + ); + const glm::dvec3 patchNormal = _ellipsoid.geodeticSurfaceNormal(pointOnPatch); + glm::dvec3 patchPosition = _ellipsoid.cartesianSurfacePosition(pointOnPatch); + + const BoundingHeights heights = boundingHeightsForChunk(chunk, _layerManager); + const double heightToChunk = heights.min; + + // Offset position according to height + patchPosition += patchNormal * heightToChunk; + + const glm::dvec3 cameraToChunk = patchPosition - cameraPosition; + + // Calculate desired level based on distance + const double distanceToPatch = glm::length(cameraToChunk); + const double distance = distanceToPatch; + + const double scaleFactor = _generalProperties.lodScaleFactor * + _ellipsoid.minimumRadius(); + const double projectedScaleFactor = scaleFactor / distance; + const int desiredLevel = static_cast(ceil(log2(projectedScaleFactor))); + return desiredLevel; +} + +int RenderableGlobe::desiredLevelByProjectedArea(const Chunk& chunk, + const RenderData& data) const +{ + // Calculations are done in the reference frame of the globe + // (model space). Hence, the camera position needs to be transformed + // with the inverse model matrix + const glm::dvec3 cameraPosition = glm::dvec3( + _cachedInverseModelTransform * glm::dvec4(data.camera.positionVec3(), 1.0) + ); + + // Approach: + // The projected area of the chunk will be calculated based on a small area that + // is close to the camera, and the scaled up to represent the full area. + // The advantage of doing this is that it will better handle the cases where the + // full patch is very curved (e.g. stretches from latitude 0 to 90 deg). + + const Geodetic2 closestCorner = chunk.surfacePatch.closestCorner( + _ellipsoid.cartesianToGeodetic2(cameraPosition) + ); + + // Camera + // | + // V + // + // oo + // [ ]< + // *geodetic space* + // + // closestCorner + // +-----------------+ <-- north east corner + // | | + // | center | + // | | + // +-----------------+ <-- south east corner + + const Geodetic2 center = chunk.surfacePatch.center(); + const BoundingHeights heights = boundingHeightsForChunk(chunk, _layerManager); + const Geodetic3 c = { center, heights.min }; + const Geodetic3 c1 = { Geodetic2{ center.lat, closestCorner.lon }, heights.min }; + const Geodetic3 c2 = { Geodetic2{ closestCorner.lat, center.lon }, heights.min }; + + // Camera + // | + // V + // + // oo + // [ ]< + // *geodetic space* + // + // +--------c2-------+ <-- north east corner + // | | + // c1 c | + // | | + // +-----------------+ <-- south east corner + + + // Go from geodetic to cartesian space and project onto unit sphere + const glm::dvec3 camToCenter = -cameraPosition; + const glm::dvec3 A = glm::normalize(camToCenter + _ellipsoid.cartesianPosition(c)); + const glm::dvec3 B = glm::normalize(camToCenter + _ellipsoid.cartesianPosition(c1)); + const glm::dvec3 C = glm::normalize(camToCenter + _ellipsoid.cartesianPosition(c2)); + + // Camera *cartesian space* + // | +--------+---+ + // V __--'' __--'' / + // C-------A--------- + + // oo / / / + //[ ]< +-------B----------+ + // + + // If the geodetic patch is small (i.e. has small width), that means the patch in + // cartesian space will be almost flat, and in turn, the triangle ABC will roughly + // correspond to 1/8 of the full area + const glm::dvec3 AB = B - A; + const glm::dvec3 AC = C - A; + const double areaABC = 0.5 * glm::length(glm::cross(AC, AB)); + const double projectedChunkAreaApprox = 8 * areaABC; + + const double scaledArea = _generalProperties.lodScaleFactor * projectedChunkAreaApprox; + return chunk.tileIndex.level + static_cast(round(scaledArea - 1)); +} + +int RenderableGlobe::desiredLevelByAvailableTileData(const Chunk& chunk) const { + const int currLevel = chunk.tileIndex.level; + + for (size_t i = 0; i < layergroupid::NUM_LAYER_GROUPS; ++i) { + for (Layer* layer : + _layerManager.layerGroup(layergroupid::GroupID(i)).activeLayers()) + { + Tile::Status status = layer->tileStatus(chunk.tileIndex); + if (status == Tile::Status::OK) { + return UnknownDesiredLevel; + } + } + } + + return currLevel - 1; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// Culling +////////////////////////////////////////////////////////////////////////////////////////// + +bool RenderableGlobe::isCullableByFrustum(const Chunk& chunk, + const RenderData& renderData) const +{ + // Calculate the MVP matrix + const glm::dmat4 viewTransform = glm::dmat4(renderData.camera.combinedViewMatrix()); + const glm::dmat4 modelViewProjectionTransform = glm::dmat4( + renderData.camera.sgctInternal.projectionMatrix() + ) * viewTransform * _cachedModelTransform; + + const std::array& corners = chunk.corners; + + // Create a bounding box that fits the patch corners + AABB3 bounds; // in screen space + for (size_t i = 0; i < 8; ++i) { + const glm::dvec4 cornerClippingSpace = modelViewProjectionTransform * corners[i]; + const glm::dvec3 ndc = glm::dvec3( + (1.f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace + ); + expand(bounds, ndc); + } + + return !(intersects(CullingFrustum, bounds)); +} + +bool RenderableGlobe::isCullableByHorizon(const Chunk& chunk, + const RenderData& renderData) const +{ + // Calculations are done in the reference frame of the globe. Hence, the camera + // position needs to be transformed with the inverse model matrix + const GeodeticPatch& patch = chunk.surfacePatch; + const float maxHeight = boundingHeightsForChunk(chunk, _layerManager).max; + const glm::dvec3 globePos = glm::dvec3(0, 0, 0); // In model space it is 0 + const double minimumGlobeRadius = _ellipsoid.minimumRadius(); + + const glm::dvec3 cameraPos = glm::dvec3( + _cachedInverseModelTransform * glm::dvec4(renderData.camera.positionVec3(), 1) + ); + + const glm::dvec3 globeToCamera = cameraPos; + + const Geodetic2 camPosOnGlobe = _ellipsoid.cartesianToGeodetic2(globeToCamera); + const Geodetic2 closestPatchPoint = patch.closestPoint(camPosOnGlobe); + glm::dvec3 objectPos = _ellipsoid.cartesianSurfacePosition(closestPatchPoint); + + // objectPosition is closest in latlon space but not guaranteed to be closest in + // castesian coordinates. Therefore we compare it to the corners and pick the + // real closest point, + std::array corners = { + _ellipsoid.cartesianSurfacePosition(chunk.surfacePatch.corner(NORTH_WEST)), + _ellipsoid.cartesianSurfacePosition(chunk.surfacePatch.corner(NORTH_EAST)), + _ellipsoid.cartesianSurfacePosition(chunk.surfacePatch.corner(SOUTH_WEST)), + _ellipsoid.cartesianSurfacePosition(chunk.surfacePatch.corner(SOUTH_EAST)) + }; + + for (int i = 0; i < 4; ++i) { + const double distance = glm::length(cameraPos - corners[i]); + if (distance < glm::length(cameraPos - objectPos)) { + objectPos = corners[i]; + } + } + + + const double objectP = pow(length(objectPos - globePos), 2); + const double horizonP = pow(minimumGlobeRadius - maxHeight, 2); + if (objectP < horizonP) { + return false; + } + + const double cameraP = pow(length(cameraPos - globePos), 2); + const double minR = pow(minimumGlobeRadius, 2); + if (cameraP < minR) { + return false; + } + + const double minimumAllowedDistanceToObjectFromHorizon = sqrt(objectP - horizonP); + const double distanceToHorizon = sqrt(cameraP - minR); + + // Minimum allowed for the object to be occluded + const double minimumAllowedDistanceToObjectSquared = + pow(distanceToHorizon + minimumAllowedDistanceToObjectFromHorizon, 2) + + pow(maxHeight, 2); + + const double distanceToObjectSquared = pow( + length(objectPos - cameraPos), + 2 + ); + return distanceToObjectSquared > minimumAllowedDistanceToObjectSquared; +} + + + +////////////////////////////////////////////////////////////////////////////////////////// +// Chunk node handling +////////////////////////////////////////////////////////////////////////////////////////// + +void RenderableGlobe::splitChunkNode(Chunk& cn, int depth) { + if (depth > 0 && isLeaf(cn)) { + std::vector memory = _chunkPool.allocate( + static_cast(cn.children.size()) + ); + for (size_t i = 0; i < cn.children.size(); ++i) { + cn.children[i] = new (memory[i]) Chunk( + cn.tileIndex.child(static_cast(i)) + ); + cn.children[i]->corners = boundingCornersForChunk( + *cn.children[i], + _layerManager, + _ellipsoid + ); + } + } + + if (depth > 1) { + for (Chunk* child : cn.children) { + splitChunkNode(*child, depth - 1); + } + } +} + +void RenderableGlobe::freeChunkNode(Chunk* n) { + _chunkPool.free(n); + for (Chunk* c : n->children) { + if (c) { + freeChunkNode(c); + } + } + n->children.fill(nullptr); +} + +void RenderableGlobe::mergeChunkNode(Chunk& cn) { + for (Chunk* child : cn.children) { + if (child) { + mergeChunkNode(*child); + freeChunkNode(child); + } + } + cn.children.fill(nullptr); +} + +bool RenderableGlobe::updateChunkTree(Chunk& cn, const RenderData& data) { + // abock: I tried turning this into a queue and use iteration, rather than recursion + // but that made the code harder to understand as the breadth-first traversal + // requires parents to be passed through the pipe twice (first to add the + // children and then again it self to be processed after the children finish). + // In addition, this didn't even improve performance --- 2018-10-04 + if (isLeaf(cn)) { + updateChunk(cn, data); + if (cn.status == Chunk::Status::WantSplit) { + splitChunkNode(cn, 1); + } + return cn.status == Chunk::Status::WantMerge; + } + else { + char requestedMergeMask = 0; + for (int i = 0; i < 4; ++i) { + if (updateChunkTree(*cn.children[i], data)) { + requestedMergeMask |= (1 << i); + } + } + + const bool allChildrenWantsMerge = requestedMergeMask == 0xf; + updateChunk(cn, data); + + if (allChildrenWantsMerge && (cn.status != Chunk::Status::WantSplit)) { + mergeChunkNode(cn); + } + + return false; + } +} + +void RenderableGlobe::updateChunk(Chunk& chunk, const RenderData& data) const { + if (_chunkCornersDirty) { + chunk.corners = boundingCornersForChunk(chunk, _layerManager, _ellipsoid); + + // The flag gets set to false globally after the updateChunkTree calls + } + + if (testIfCullable(chunk, data)) { + chunk.isVisible = false; + chunk.status = Chunk::Status::WantMerge; + return; + } + else { + chunk.isVisible = true; + } + + const int dl = desiredLevel(chunk, data); + + if (dl < chunk.tileIndex.level) { + chunk.status = Chunk::Status::WantMerge; + } + else if (chunk.tileIndex.level < dl) { + chunk.status = Chunk::Status::WantSplit; + } + else { + chunk.status = Chunk::Status::DoNothing; + } +} + +} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/src/renderableglobe.h b/modules/globebrowsing/src/renderableglobe.h new file mode 100644 index 0000000000..6627d1f7bb --- /dev/null +++ b/modules/globebrowsing/src/renderableglobe.h @@ -0,0 +1,246 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___RENDERABLEGLOBE___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___RENDERABLEGLOBE___H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace openspace::globebrowsing { + +class GPULayerGroup; +class RenderableGlobe; +struct TileIndex; + +namespace chunklevelevaluator { class Evaluator; } +namespace culling { class ChunkCuller; } + +struct Chunk { + enum class Status : uint8_t { + DoNothing, + WantMerge, + WantSplit + }; + + Chunk(const TileIndex& tileIndex); + + const TileIndex tileIndex; + const GeodeticPatch surfacePatch; + + Status status; + + bool isVisible = true; + std::array corners; + std::array children = { { nullptr, nullptr, nullptr, nullptr } }; +}; + +/** + * A RenderableGlobe is a globe modeled as an ellipsoid using a chunked LOD algorithm for + * rendering. + */ +class RenderableGlobe : public Renderable { +public: + RenderableGlobe(const ghoul::Dictionary& dictionary); + ~RenderableGlobe() = default; + + void initializeGL() override; + void deinitialize() override; + void deinitializeGL() override; + bool isReady() const override; + + void render(const RenderData& data, RendererTasks& rendererTask) override; + void update(const UpdateData& data) override; + + SurfacePositionHandle calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace) const; + + const Ellipsoid& ellipsoid() const; + const LayerManager& layerManager() const; + LayerManager& layerManager(); + const glm::dmat4& modelTransform() const; + +private: + constexpr static const int MinSplitDepth = 2; + constexpr static const int MaxSplitDepth = 22; + + struct { + properties::BoolProperty showChunkEdges; + properties::BoolProperty showChunkBounds; + properties::BoolProperty showChunkAABB; + properties::BoolProperty showHeightResolution; + properties::BoolProperty showHeightIntensities; + properties::BoolProperty levelByProjectedAreaElseDistance; + properties::BoolProperty resetTileProviders; + properties::IntProperty modelSpaceRenderingCutoffLevel; + } _debugProperties; + + struct { + properties::BoolProperty performShading; + properties::BoolProperty useAccurateNormals; + properties::BoolProperty eclipseShadowsEnabled; + properties::BoolProperty eclipseHardShadows; + properties::FloatProperty lodScaleFactor; + properties::FloatProperty cameraMinHeight; + properties::FloatProperty orenNayarRoughness; + } _generalProperties; + + properties::PropertyOwner _debugPropertyOwner; + + /** + * Test if a specific chunk can safely be culled without affecting the rendered + * image. + * + * Goes through all available ChunkCullers and check if any of them + * allows culling of the Chunks in question. + */ + bool testIfCullable(const Chunk& chunk, const RenderData& renderData) const; + + /** + * Gets the desired level which can be used to determine if a chunk should split + * or merge. + * + * Using ChunkLevelEvaluators, the desired level can be higher or + * lower than the current level of the Chunkss + * TileIndex. If the desired level is higher than that of the + * Chunk, it wants to split. If it is lower, it wants to merge with + * its siblings. + */ + int desiredLevel(const Chunk& chunk, const RenderData& renderData) const; + + /** + * Calculates the height from the surface of the reference ellipsoid to the + * height mapped surface. + * + * The height can be negative if the height map contains negative values. + * + * \param position is the position of a point that gets geodetically + * projected on the reference ellipsoid. position must be in + * cartesian model space. + * \returns the height from the reference ellipsoid to the globe surface. + */ + float getHeight(const glm::dvec3& position) const; + + void renderChunks(const RenderData& data, RendererTasks& rendererTask); + + /** + * Chunks can be rendered either globally or locally. Global rendering is performed + * in the model space of the globe. With global rendering, the vertex positions + * of a chunk are calculated in the vertex shader by transforming the geodetic + * coordinates of the chunk to model space coordinates. We can only achieve floating + * point precision by doing this which means that the camera too close to a global + * tile will lead to jagging. We only render global chunks for lower chunk levels. + */ + void renderChunkGlobally(const Chunk& chunk, const RenderData& data); + + /** + * Local rendering of chunks are done using linear interpolation in camera space. + * All four corner points of the chunk are calculated in double precision on the + * CPU and transformed to camera space with double precision matrix transforms. + * These positions can then be cast to floats and uploaded to the vertex shader. + * The vertex shader rendering performs linear interpolation between the four + * corner points to get the resulting chunk. This means that there will be an error + * due to the curvature of the globe. The smaller the patch is (with higher chunk + * levels) the better the approximation becomes. This is why we only render local + * chunks for higher chunk levels. + */ + void renderChunkLocally(const Chunk& chunk, const RenderData& data); + + void debugRenderChunk(const Chunk& chunk, const glm::dmat4& mvp, + bool renderBounds, bool renderAABB) const; + + bool isCullableByFrustum(const Chunk& chunk, const RenderData& renderData) const; + bool isCullableByHorizon(const Chunk& chunk, const RenderData& renderData) const; + + int desiredLevelByDistance(const Chunk& chunk, const RenderData& data) const; + int desiredLevelByProjectedArea(const Chunk& chunk, const RenderData& data) const; + int desiredLevelByAvailableTileData(const Chunk& chunk) const; + + + void calculateEclipseShadows(ghoul::opengl::ProgramObject& programObject, + const RenderData& data); + + void setCommonUniforms(ghoul::opengl::ProgramObject& programObject, + const Chunk& chunk, const RenderData& data); + + + void recompileShaders(); + + + void splitChunkNode(Chunk& cn, int depth); + void mergeChunkNode(Chunk& cn); + bool updateChunkTree(Chunk& cn, const RenderData& data); + void updateChunk(Chunk& chunk, const RenderData& data) const; + void freeChunkNode(Chunk* n); + + Ellipsoid _ellipsoid; + SkirtedGrid _grid; + LayerManager _layerManager; + + glm::dmat4 _cachedModelTransform; + glm::dmat4 _cachedInverseModelTransform; + + ghoul::ReusableTypedMemoryPool _chunkPool; + + Chunk _leftRoot; // Covers all negative longitudes + Chunk _rightRoot; // Covers all positive longitudes + + // Two different shader programs. One for global and one for local rendering. + struct { + std::unique_ptr program; + bool updatedSinceLastCall = false; + UniformCache(skirtLength, minLatLon, lonLatScalingFactor) uniformCache; + + std::array gpuLayerGroups; + } _globalRenderer; + + struct { + std::unique_ptr program; + bool updatedSinceLastCall = false; + UniformCache(skirtLength, p01, p11, p00, p10, patchNormalModelSpace, + patchNormalCameraSpace) uniformCache; + + std::array gpuLayerGroups; + } _localRenderer; + + bool _shadersNeedRecompilation = true; + bool _lodScaleFactorDirty = true; + bool _chunkCornersDirty = true; +}; + +} // namespace openspace::globebrowsing + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___RENDERABLEGLOBE___H__ diff --git a/modules/globebrowsing/src/skirtedgrid.cpp b/modules/globebrowsing/src/skirtedgrid.cpp new file mode 100644 index 0000000000..d3426116aa --- /dev/null +++ b/modules/globebrowsing/src/skirtedgrid.cpp @@ -0,0 +1,183 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include + +namespace { + constexpr const char* _loggerCat = "SkirtedGrid"; + + size_t numElements(int xSegments, int ySegments) { + return 3 * 2 * xSegments * ySegments; + } + + size_t numVertices(int xSegments, int ySegments) { + return (xSegments + 1) * (ySegments + 1); + } + + void validate([[maybe_unused]] int xSegments, [[maybe_unused]] int ySegments) { + ghoul_assert( + xSegments > 0 && ySegments > 0, + "Resolution must be at least 1x1. (" + std::to_string(xSegments) + ", " + + std::to_string(ySegments) + ")" + ); + } + + std::vector createElements(int xSegments, int ySegments) { + validate(xSegments, ySegments); + + std::vector elements; + elements.reserve(numElements(xSegments + 2, ySegments + 2)); + for (int y = 0; y < ySegments + 2; y++) { + for (int x = 0; x < xSegments + 2; x++) { + + // x v01---v11 x .. + // | / | + // x v00---v10 x .. + // + // x x x x .. + // : : : : + + const GLuint v00 = (y + 0) * (xSegments + 2 + 1) + x + 0; + const GLuint v10 = (y + 0) * (xSegments + 2 + 1) + x + 1; + const GLuint v01 = (y + 1) * (xSegments + 2 + 1) + x + 0; + const GLuint v11 = (y + 1) * (xSegments + 2 + 1) + x + 1; + + // add upper triangle + elements.push_back(static_cast(v00)); + elements.push_back(static_cast(v10)); + elements.push_back(static_cast(v11)); + + // add lower triangle + elements.push_back(static_cast(v00)); + elements.push_back(static_cast(v11)); + elements.push_back(static_cast(v01)); + } + } + + return elements; + } + + std::vector createTextureCoordinates(int xSegments, int ySegments) { + validate(xSegments, ySegments); + + std::vector textureCoordinates; + textureCoordinates.reserve(numVertices(xSegments + 2, ySegments + 2)); + for (int y = -1; y < ySegments + 2; y++) { + for (int x = -1; x < xSegments + 2; x++) { + textureCoordinates.emplace_back( + glm::clamp( + static_cast(x) / static_cast(xSegments), + 0.f - 1.f / (2.f * xSegments), + 1.f + 1.f / (2.f * xSegments) + ), + glm::clamp( + static_cast(y) / static_cast(ySegments), + 0.f - 1.f / (2.f * ySegments), + 1.f + 1.f / (2.f * ySegments) + ) + ); + } + } + return textureCoordinates; + } + +} // namespace + +namespace openspace::globebrowsing { + +SkirtedGrid::SkirtedGrid(unsigned int xSeg, unsigned int ySeg) + : xSegments(xSeg) + , ySegments(ySeg) + , _elementSize(static_cast(numElements(xSegments + 2, ySegments + 2))) +{} + +void SkirtedGrid::initializeGL() { + std::vector elementData = createElements(xSegments, ySegments); + + struct Vertex { + GLfloat texture[2]; + }; + + + std::vector textures = createTextureCoordinates(xSegments, ySegments); + std::vector vertexData(textures.size()); + for (size_t i = 0; i < textures.size(); ++i) { + vertexData[i].texture[0] = textures[i][0]; + vertexData[i].texture[1] = textures[i][1]; + } + + + glGenVertexArrays(1, &_vaoID); + glGenBuffers(1, &_vertexBufferID); + glGenBuffers(1, &_elementBufferID); + + // First VAO setup + glBindVertexArray(_vaoID); + + // Vertex buffer + glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID); + glBufferData(GL_ARRAY_BUFFER, + vertexData.size() * sizeof(Vertex), + vertexData.data(), + GL_STATIC_DRAW + ); + + // Textures at location 1 + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr); + + // Element buffer + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _elementBufferID); + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + elementData.size() * sizeof(GLushort), + elementData.data(), + GL_STATIC_DRAW + ); + + glBindVertexArray(0); + + ghoul_assert( + elementData.size() == _elementSize, + "Wrong element size. The correct number is assumed in the render method" + ); +} + +void SkirtedGrid::deinitializeGL() { + glDeleteBuffers(1, &_vertexBufferID); + glDeleteBuffers(1, &_elementBufferID); + glDeleteVertexArrays(1, &_vaoID); +} + +void SkirtedGrid::drawUsingActiveProgram() const { + glBindVertexArray(_vaoID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _elementBufferID); + glDrawElements(GL_TRIANGLES, _elementSize, GL_UNSIGNED_SHORT, nullptr); + glBindVertexArray(0); +} + +} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/meshes/skirtedgrid.h b/modules/globebrowsing/src/skirtedgrid.h similarity index 73% rename from modules/globebrowsing/meshes/skirtedgrid.h rename to modules/globebrowsing/src/skirtedgrid.h index 17df36b6a5..486302612a 100644 --- a/modules/globebrowsing/meshes/skirtedgrid.h +++ b/modules/globebrowsing/src/skirtedgrid.h @@ -25,21 +25,18 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___SKIRTEDGRID___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___SKIRTEDGRID___H__ -#include - -#include #include +#include #include namespace openspace::globebrowsing { /** - * This grid is the same as BasicGrid except it has skirts around its edges. - * The areas covered by the skirts have position coordinates and texture coordinates - * that are outside of the range [0, 1]. The width of the skirts is half the size of one - * segment width or a cell. + * This grid is a regular grid with skirts around its edges. The areas covered by the + * skirts have position coordinates and texture coordinates that are outside of the range + * [0, 1]. The width of the skirts is half the size of one segment width or a cell. */ -class SkirtedGrid : public Grid { +class SkirtedGrid { public: /** * \param xSegments is the number of grid cells in the x direction. @@ -51,21 +48,30 @@ public: * \param useNormals determines whether or not to upload any vertex normal data * to the GPU. */ - SkirtedGrid(unsigned int xSegments, unsigned int ySegments, - TriangleSoup::Positions usePositions, - TriangleSoup::TextureCoordinates useTextureCoordinates, - TriangleSoup::Normals useNormals); + SkirtedGrid(unsigned int xSegments, unsigned int ySegments); ~SkirtedGrid() = default; - virtual int xSegments() const override; - virtual int ySegments() const override; + void initializeGL(); + void deinitializeGL(); + + /** + * Calls OpenGL's draw function to draw the triangles defined in the vertex buffers + * using the current bound program object. + * The vertex buffer attribute input locations to the shader program comes in the + * order of positions (0), texture coordinates (1) and normals (2). + * The input locations in the shader program should be specified to match these + * locations. + */ + void drawUsingActiveProgram() const; + + const int xSegments; + const int ySegments; private: - std::vector createElements(int xSegments, int ySegments) override; - std::vector createPositions(int xSegments, int ySegments) override; - std::vector createTextureCoordinates(int xSegments, - int ySegments) override; - std::vector createNormals(int xSegments, int ySegments) override; + GLuint _vaoID = 0; + GLuint _vertexBufferID = 0; + GLuint _elementBufferID = 0; + const GLsizei _elementSize; }; } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/geometry/geodetic2.cpp b/modules/globebrowsing/src/tileindex.cpp similarity index 64% rename from modules/globebrowsing/geometry/geodetic2.cpp rename to modules/globebrowsing/src/tileindex.cpp index d38f8d3cf4..2ec8b010ae 100644 --- a/modules/globebrowsing/geometry/geodetic2.cpp +++ b/modules/globebrowsing/src/tileindex.cpp @@ -22,37 +22,48 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include namespace openspace::globebrowsing { -Geodetic2::Geodetic2(double latitude, double longitude) - : lat(latitude) - , lon(longitude) +bool operator==(const TileIndex& lhs, const TileIndex& rhs) { + return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.level == rhs.level); +} + +TileIndex::TileIndex(int x_, int y_, int level_) + : x(x_) + , y(y_) + , level(level_) {} -glm::dvec2 Geodetic2::toLonLatVec2() const { - return glm::dvec2(lon, lat); +TileIndex TileIndex::child(Quad q) const { + return TileIndex(2 * x + q % 2, 2 * y + q / 2, level + 1); } -bool Geodetic2::operator==(const Geodetic2& other) const { - return lat == other.lat && lon == other.lon; +glm::vec2 TileIndex::positionRelativeParent() const { + const bool isEastChild = (x % 2 == 1); + const bool isNorthChild = (y % 2 == 0); + + // In OpenGL, positive y direction is up + return glm::vec2(isEastChild ? 0.5f : 0.f, isNorthChild ? 0.5f : 0.f); } -Geodetic2 Geodetic2::operator+(const Geodetic2& other) const { - return Geodetic2(lat + other.lat, lon + other.lon); -} +// Creates a hash which can be used as key in hash maps. +// +// +-------+------------+-------+------------+ +// | USAGE | BIT RANGE | #BITS | MAX VALUE | +// +-------+------------+-------+------------+ +// | level | 0 - 5 | 5 | 31 | +// | x | 5 - 35 | 30 | 1073741824 | +// | y | 35 - 64 | 29 | 536870912 | +// +-------+------------+-------+------------+ +TileIndex::TileHashKey TileIndex::hashKey() const { + TileHashKey key = 0LL; + key |= level; + key |= x << 5; + key |= static_cast(y) << 35; -Geodetic2 Geodetic2::operator-(const Geodetic2& other) const { - return Geodetic2(lat - other.lat, lon - other.lon); -} - -Geodetic2 Geodetic2::operator*(double scalar) const { - return Geodetic2(lat * scalar, lon * scalar); -} - -Geodetic2 Geodetic2::operator/(double scalar) const { - return Geodetic2(lat / scalar, lon / scalar); + return key; } } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/tileuvtransform.h b/modules/globebrowsing/src/tileindex.h similarity index 79% rename from modules/globebrowsing/tile/tileuvtransform.h rename to modules/globebrowsing/src/tileindex.h index 239cce2fcf..8a892f75cd 100644 --- a/modules/globebrowsing/tile/tileuvtransform.h +++ b/modules/globebrowsing/src/tileindex.h @@ -22,18 +22,31 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEUVTRANSFORM___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEUVTRANSFORM___H__ +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_INDEX___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_INDEX___H__ +#include #include +#include namespace openspace::globebrowsing { -struct TileUvTransform { - glm::vec2 uvOffset; - glm::vec2 uvScale; +struct TileIndex { + using TileHashKey = uint64_t; + + TileIndex(int x, int y, int level); + + int x = 0; + int y = 0; + int level = 0; + + TileIndex child(Quad q) const; + glm::vec2 positionRelativeParent() const; + TileHashKey hashKey() const; }; +bool operator==(const TileIndex& lhs, const TileIndex& rhs); + } // namespace openspace::globebrowsing -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEUVTRANSFORM___H__ +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_INDEX___H__ diff --git a/modules/globebrowsing/meshes/grid.cpp b/modules/globebrowsing/src/tileloadjob.cpp similarity index 78% rename from modules/globebrowsing/meshes/grid.cpp rename to modules/globebrowsing/src/tileloadjob.cpp index d772c54c67..52ee6751db 100644 --- a/modules/globebrowsing/meshes/grid.cpp +++ b/modules/globebrowsing/src/tileloadjob.cpp @@ -22,21 +22,31 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include -#include +#include namespace openspace::globebrowsing { -Grid::Grid(int xSegments, int ySegments) - : _xSegments(xSegments) - , _ySegments(ySegments) +TileLoadJob::TileLoadJob(RawTileDataReader& rawTileDataReader, TileIndex tileIndex) + : _rawTileDataReader(rawTileDataReader) + , _chunkIndex(std::move(tileIndex)) {} -Grid::~Grid() {} // NOLINT +TileLoadJob::~TileLoadJob() { + if (_hasTile) { + _rawTile.imageData = nullptr; + } +} -TriangleSoup& Grid::geometry() { - return *_geometry; +void TileLoadJob::execute() { + _rawTile = std::move(_rawTileDataReader.readTileData(_chunkIndex)); + _hasTile = true; +} + +RawTile TileLoadJob::product() { + _hasTile = false; + return std::move(_rawTile); } } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/tileloadjob.h b/modules/globebrowsing/src/tileloadjob.h similarity index 75% rename from modules/globebrowsing/tile/tileloadjob.h rename to modules/globebrowsing/src/tileloadjob.h index 2d433d9ef7..65da1859d3 100644 --- a/modules/globebrowsing/tile/tileloadjob.h +++ b/modules/globebrowsing/src/tileloadjob.h @@ -27,12 +27,12 @@ #include -#include +#include +#include namespace openspace::globebrowsing { class RawTileDataReader; -struct RawTile; struct TileLoadJob : public Job { /** @@ -41,16 +41,7 @@ struct TileLoadJob : public Job { * called before the TileLoadJob is finished, the data will be deleted as it has not * been exposed outside of this object. */ - TileLoadJob(std::shared_ptr rawTileDataReader, - const TileIndex& tileIndex); - - /** - * No data is allocated unless specified so by the TileTextureInitData of - * rawTileDataReader but it is assumed that pboDataPtr is a mapped pointer to a pixel - * buffer object. - */ - TileLoadJob(std::shared_ptr rawTileDataReader, - const TileIndex& tileIndex, char* pboDataPtr); + TileLoadJob(RawTileDataReader& rawTileDataReader, TileIndex tileIndex); /** * Destroys the allocated data pointer if it has been allocated and the TileLoadJob @@ -70,22 +61,13 @@ struct TileLoadJob : public Job { * Unless the job is marked as finished, the pixel data will be deallocated * when the job is deleted. */ - std::shared_ptr product() override; - - /** - * Get the data ownership. if any data has been allocated (ie if the job was created - * using the CPU constructor not taking a PBO data pointer) this function is - * equivalent with asking if the job is unfinished. If the job has ownership of data, - * the data will be deleted once the job is deleted. - */ - bool hasOwnershipOfData() const; + RawTile product() override; protected: - std::shared_ptr _rawTileDataReader; - std::shared_ptr _rawTile; - TileIndex _chunkIndex; - char* _pboMappedDataDestination = nullptr; - bool _hasOwnershipOfData = false; + RawTileDataReader& _rawTileDataReader; + RawTile _rawTile; + const TileIndex _chunkIndex; + bool _hasTile = false; }; } // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/src/tileprovider.cpp b/modules/globebrowsing/src/tileprovider.cpp new file mode 100644 index 0000000000..4035dab150 --- /dev/null +++ b/modules/globebrowsing/src/tileprovider.cpp @@ -0,0 +1,1399 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cpl_minixml.h" + +namespace ghoul { + template <> + openspace::globebrowsing::tileprovider::TemporalTileProvider::TimeFormatType + from_string(const std::string& string) + { + using namespace openspace::globebrowsing::tileprovider; + if (string == "YYYY-MM-DD") { + return TemporalTileProvider::TimeFormatType::YYYY_MM_DD; + } + else if (string == "YYYY-MM-DDThh:mm:ssZ") { + return TemporalTileProvider::TimeFormatType::YYYY_MM_DDThhColonmmColonssZ; + } + else if (string == "YYYY-MM-DDThh_mm_ssZ") { + return TemporalTileProvider::TimeFormatType::YYYY_MM_DDThh_mm_ssZ; + } + else if (string == "YYYYMMDD_hhmmss") { + return TemporalTileProvider::TimeFormatType::YYYYMMDD_hhmmss; + } + else if (string == "YYYYMMDD_hhmm") { + return TemporalTileProvider::TimeFormatType::YYYYMMDD_hhmm; + } + else { + throw ghoul::RuntimeError("Unknown timeformat " + string); + } + } +} // namespace ghoul + + +namespace openspace::globebrowsing::tileprovider { + +namespace { + +std::unique_ptr DefaultTileTexture; +Tile DefaultTile = Tile{ nullptr, std::nullopt, Tile::Status::Unavailable }; + +constexpr const char* KeyFilePath = "FilePath"; + +namespace defaultprovider { + constexpr const char* KeyPerformPreProcessing = "PerformPreProcessing"; + constexpr const char* KeyTilePixelSize = "TilePixelSize"; + constexpr const char* KeyPadTiles = "PadTiles"; + + constexpr openspace::properties::Property::PropertyInfo FilePathInfo = { + "FilePath", + "File Path", + "The path of the GDAL file or the image file that is to be used in this tile " + "provider." + }; + + constexpr openspace::properties::Property::PropertyInfo TilePixelSizeInfo = { + "TilePixelSize", + "Tile Pixel Size", + "This value is the preferred size (in pixels) for each tile. Choosing the right " + "value is a tradeoff between more efficiency (larger images) and better quality " + "(smaller images). The tile pixel size has to be smaller than the size of the " + "complete image if a single image is used." + }; +} // namespace defaultprovider + +namespace singleimageprovider { + constexpr openspace::properties::Property::PropertyInfo FilePathInfo = { + "FilePath", + "File Path", + "The file path that is used for this image provider. The file must point to an " + "image that is then loaded and used for all tiles." + }; +} // namespace singleimageprovider + +namespace sizereferenceprovider { + constexpr const char* KeyRadii = "Radii"; +} // namespace sizereferenceprovider + +namespace byindexprovider { + constexpr const char* KeyDefaultProvider = "DefaultProvider"; + constexpr const char* KeyProviders = "IndexTileProviders"; + constexpr const char* KeyTileIndex = "TileIndex"; + constexpr const char* KeyTileProvider = "TileProvider"; +} // namespace byindexprovider + +namespace bylevelprovider { + constexpr const char* KeyProviders = "LevelTileProviders"; + constexpr const char* KeyMaxLevel = "MaxLevel"; + constexpr const char* KeyTileProvider = "TileProvider"; + constexpr const char* KeyLayerGroupID = "LayerGroupID"; +} // namespace bylevelprovider + +namespace temporal { + constexpr const char* KeyBasePath = "BasePath"; + constexpr const char* KeyPreCacheStartTime = "PreCacheStartTime"; + constexpr const char* KeyPreCacheEndTime = "PreCacheEndTime"; + + constexpr const char* UrlTimePlaceholder = "${OpenSpaceTimeId}"; + constexpr const char* TimeStart = "OpenSpaceTimeStart"; + constexpr const char* TimeEnd = "OpenSpaceTimeEnd"; + constexpr const char* TimeResolution = "OpenSpaceTimeResolution"; + constexpr const char* TimeFormat = "OpenSpaceTimeIdFormat"; + + constexpr openspace::properties::Property::PropertyInfo FilePathInfo = { + "FilePath", + "File Path", + "This is the path to the XML configuration file that describes the temporal tile " + "information." + }; +} // namespace temporal + +Type toType(const layergroupid::TypeID& id) { + using T = layergroupid::TypeID; + switch (id) { + case T::Unknown: throw ghoul::MissingCaseException(); + case T::DefaultTileLayer: return Type::DefaultTileProvider; + case T::SingleImageTileLayer: return Type::SingleImageTileProvider; + case T::SizeReferenceTileLayer: return Type::SizeReferenceTileProvider; + case T::TemporalTileLayer: return Type::TemporalTileProvider; + case T::TileIndexTileLayer: return Type::TileIndexTileProvider; + case T::ByIndexTileLayer: return Type::ByIndexTileProvider; + case T::ByLevelTileLayer: return Type::ByLevelTileProvider; + default: throw ghoul::MissingCaseException(); + } +} + +// +// DefaultTileProvider +// + +void initAsyncTileDataReader(DefaultTileProvider& t, TileTextureInitData initData) { + t.asyncTextureDataProvider = std::make_unique( + t.name, + std::make_unique( + t.filePath, + initData, + RawTileDataReader::PerformPreprocessing(t.performPreProcessing) + ) + ); +} + +void initTexturesFromLoadedData(DefaultTileProvider& t) { + if (t.asyncTextureDataProvider) { + std::optional tile = t.asyncTextureDataProvider->popFinishedRawTile(); + if (tile) { + const cache::ProviderTileKey key = { tile->tileIndex, t.uniqueIdentifier }; + ghoul_assert(!t.tileCache->exist(key), "Tile must not be existing in cache"); + t.tileCache->createTileAndPut(key, std::move(tile.value())); + } + } +} + + +// +// TextTileProvider +// + +void initialize(TextTileProvider& t) { + t.font = global::fontManager.font("Mono", static_cast(t.fontSize)); + t.fontRenderer = ghoul::fontrendering::FontRenderer::createDefault(); + t.fontRenderer->setFramebufferSize(glm::vec2(t.initData.dimensions)); + glGenFramebuffers(1, &t.fbo); +} + +void deinitialize(TextTileProvider& t) { + glDeleteFramebuffers(1, &t.fbo); +} + +Tile tile(TextTileProvider& t, const TileIndex& tileIndex) { + cache::ProviderTileKey key = { tileIndex, t.uniqueIdentifier }; + Tile tile = t.tileCache->get(key); + if (!tile.texture) { + ghoul::opengl::Texture* texture = t.tileCache->texture(t.initData); + + // Keep track of defaultFBO and viewport to be able to reset state when done + GLint defaultFBO; + GLint viewport[4]; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); + glGetIntegerv(GL_VIEWPORT, viewport); + + // Render to texture + glBindFramebuffer(GL_FRAMEBUFFER, t.fbo); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + *texture, + 0 + ); + + GLsizei w = static_cast(texture->width()); + GLsizei h = static_cast(texture->height()); + glViewport(0, 0, w, h); + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); + + t.fontRenderer->render(*t.font, t.textPosition, t.text, t.textColor); + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + + tile = Tile{ texture, std::nullopt, Tile::Status::OK }; + t.tileCache->put(key, t.initData.hashKey, tile); + } + return tile; +} + +void reset(TextTileProvider& t) { + t.tileCache->clear(); +} + + +// +// TileProviderByLevel +// + +TileProvider* levelProvider(TileProviderByLevel& t, int level) { + if (!t.levelTileProviders.empty()) { + int clampedLevel = glm::clamp( + level, + 0, + static_cast(t.providerIndices.size() - 1) + ); + int idx = t.providerIndices[clampedLevel]; + return t.levelTileProviders[idx].get(); + } + else { + return nullptr; + } +} + + +// +// TemporalTileProvider +// + +std::string timeStringify(TemporalTileProvider::TimeFormatType type, const Time& t) { + switch (type) { + case TemporalTileProvider::TimeFormatType::YYYY_MM_DD: + return t.ISO8601().substr(0, 10); + case TemporalTileProvider::TimeFormatType::YYYYMMDD_hhmmss: { + std::string ts = t.ISO8601().substr(0, 19); + + // YYYY_MM_DDThh_mm_ss -> YYYYMMDD_hhmmss + ts.erase(std::remove(ts.begin(), ts.end(), '-'), ts.end()); + ts.erase(std::remove(ts.begin(), ts.end(), ':'), ts.end()); + replace(ts.begin(), ts.end(), 'T', '_'); + return ts; + } + case TemporalTileProvider::TimeFormatType::YYYYMMDD_hhmm: { + std::string ts = t.ISO8601().substr(0, 16); + + // YYYY_MM_DDThh_mm -> YYYYMMDD_hhmm + ts.erase(std::remove(ts.begin(), ts.end(), '-'), ts.end()); + ts.erase(std::remove(ts.begin(), ts.end(), ':'), ts.end()); + replace(ts.begin(), ts.end(), 'T', '_'); + return ts; + } + case TemporalTileProvider::TimeFormatType::YYYY_MM_DDThhColonmmColonssZ: + return t.ISO8601().substr(0, 19) + "Z"; + case TemporalTileProvider::TimeFormatType::YYYY_MM_DDThh_mm_ssZ: { + std::string timeString = t.ISO8601().substr(0, 19) + "Z"; + replace(timeString.begin(), timeString.end(), ':', '_'); + return timeString; + } + default: + throw ghoul::MissingCaseException(); + } +} + +std::unique_ptr initTileProvider(TemporalTileProvider& t, + TemporalTileProvider::TimeKey timekey) +{ + static const std::vector IgnoredTokens = { + // From: http://www.gdal.org/frmt_wms.html + "${x}", + "${y}", + "${z}", + "${version}", + "${format}", + "${layer}" + }; + + + std::string xmlTemplate(t.gdalXmlTemplate); + const size_t pos = xmlTemplate.find(temporal::UrlTimePlaceholder); + const size_t numChars = strlen(temporal::UrlTimePlaceholder); + // @FRAGILE: This will only find the first instance. Dangerous if that instance is + // commented out ---abock + const std::string timeSpecifiedXml = xmlTemplate.replace(pos, numChars, timekey); + std::string gdalDatasetXml = timeSpecifiedXml; + + FileSys.expandPathTokens(gdalDatasetXml, IgnoredTokens); + + t.initDict.setValue(KeyFilePath, gdalDatasetXml); + return std::make_unique(t.initDict); +} + +TileProvider* getTileProvider(TemporalTileProvider& t, + const TemporalTileProvider::TimeKey& timekey) +{ + const auto it = t.tileProviderMap.find(timekey); + if (it != t.tileProviderMap.end()) { + return it->second.get(); + } + else { + std::unique_ptr tileProvider = initTileProvider(t, timekey); + initialize(*tileProvider); + + TileProvider* res = tileProvider.get(); + t.tileProviderMap[timekey] = std::move(tileProvider); + return res; + } +} + +TileProvider* getTileProvider(TemporalTileProvider& t, const Time& time) { + Time tCopy(time); + if (t.timeQuantizer.quantize(tCopy, true)) { + TemporalTileProvider::TimeKey timeKey = timeStringify(t.timeFormat, tCopy); + try { + return getTileProvider(t, timeKey); + } + catch (const ghoul::RuntimeError& e) { + LERRORC("TemporalTileProvider", e.message); + return nullptr; + } + } + return nullptr; +} + +void ensureUpdated(TemporalTileProvider& t) { + if (!t.currentTileProvider) { + update(t); + } +} + +std::string xmlValue(TemporalTileProvider& t, CPLXMLNode* node, const std::string& key, + const std::string& defaultVal) +{ + CPLXMLNode* n = CPLSearchXMLNode(node, key.c_str()); + if (!n) { + throw ghoul::RuntimeError( + fmt::format("Unable to parse file {}. {} missing", t.filePath.value(), key) + ); + } + + const bool hasValue = n && n->psChild && n->psChild->pszValue; + return hasValue ? n->psChild->pszValue : defaultVal; +} + +std::string consumeTemporalMetaData(TemporalTileProvider& t, const std::string& xml) { + CPLXMLNode* node = CPLParseXMLString(xml.c_str()); + + std::string timeStart = xmlValue(t, node, temporal::TimeStart, "2000 Jan 1"); + std::string timeResolution = xmlValue(t, node, temporal::TimeResolution, "2d"); + std::string timeEnd = xmlValue(t, node, temporal::TimeEnd, "Today"); + std::string timeIdFormat = xmlValue( + t, + node, + temporal::TimeFormat, + "YYYY-MM-DDThh:mm:ssZ" + ); + + Time start; + start.setTime(std::move(timeStart)); + Time end(Time::now()); + if (timeEnd == "Yesterday") { + end.advanceTime(-60.0 * 60.0 * 24.0); // Go back one day + } + else if (timeEnd != "Today") { + end.setTime(std::move(timeEnd)); + } + + try { + t.timeQuantizer = TimeQuantizer(start, end, timeResolution); + } + catch (const ghoul::RuntimeError& e) { + throw ghoul::RuntimeError(fmt::format( + "Could not create time quantizer for Temporal GDAL dataset '{}'. {}", + t.filePath.value(), e.message + )); + } + t.timeFormat = ghoul::from_string(timeIdFormat); + + CPLXMLNode* gdalNode = CPLSearchXMLNode(node, "GDAL_WMS"); + if (gdalNode) { + std::string gdalDescription = CPLSerializeXMLTree(gdalNode); + return gdalDescription; + } + else { + gdalNode = CPLSearchXMLNode(node, "FilePath"); + std::string gdalDescription = std::string(gdalNode->psChild->pszValue); + return gdalDescription; + } +} + +bool readFilePath(TemporalTileProvider& t) { + std::ifstream in(t.filePath.value().c_str()); + std::string xml; + if (in.is_open()) { + // read file + xml = std::string( + std::istreambuf_iterator(in), + (std::istreambuf_iterator()) + ); + } + else { + // Assume that it is already an xml + xml = t.filePath; + } + + // File path was not a path to a file but a GDAL config or empty + ghoul::filesystem::File f(t.filePath); + if (FileSys.fileExists(f)) { + t.initDict.setValue(temporal::KeyBasePath, f.directoryName()); + } + + t.gdalXmlTemplate = consumeTemporalMetaData(t, xml); + return true; +} + +} // namespace + +unsigned int TileProvider::NumTileProviders = 0; + + +// +// General functions +// +void initializeDefaultTile() { + ghoul_assert(!DefaultTile.texture, "Default tile should not have been created"); + using namespace ghoul::opengl; + + // Create pixel data + TileTextureInitData initData( + 8, + 8, + GL_UNSIGNED_BYTE, + Texture::Format::RGBA, + TileTextureInitData::PadTiles::No, + TileTextureInitData::ShouldAllocateDataOnCPU::Yes + ); + char* pixels = new char[initData.totalNumBytes]; + memset(pixels, 0, initData.totalNumBytes * sizeof(char)); + + // Create ghoul texture + DefaultTileTexture = std::make_unique(initData.dimensions); + DefaultTileTexture->setDataOwnership(Texture::TakeOwnership::Yes); + DefaultTileTexture->setPixelData(pixels); + DefaultTileTexture->uploadTexture(); + DefaultTileTexture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); + + // Create tile + DefaultTile = Tile{ DefaultTileTexture.get(), std::nullopt, Tile::Status::OK }; +} + +void deinitializeDefaultTile() { + DefaultTileTexture = nullptr; +} + +std::unique_ptr createFromDictionary(layergroupid::TypeID layerTypeID, + const ghoul::Dictionary& dictionary) +{ + const char* type = layergroupid::LAYER_TYPE_NAMES[static_cast(layerTypeID)]; + auto factory = FactoryManager::ref().factory(); + std::unique_ptr result = factory->create(type, dictionary); + return result; +} + +TileProvider::TileProvider() : properties::PropertyOwner({ "tileProvider" }) {} + +DefaultTileProvider::DefaultTileProvider(const ghoul::Dictionary& dictionary) + : filePath(defaultprovider::FilePathInfo, "") + , tilePixelSize(defaultprovider::TilePixelSizeInfo, 32, 32, 2048) +{ + type = Type::DefaultTileProvider; + + tileCache = global::moduleEngine.module()->tileCache(); + name = "Name unspecified"; + if (dictionary.hasKeyAndValue("Name")) { + name = dictionary.value("Name"); + } + std::string _loggerCat = "DefaultTileProvider (" + name + ")"; + + // 1. Get required Keys + filePath = dictionary.value(KeyFilePath); + layerGroupID = dictionary.value("LayerGroupID"); + + // 2. Initialize default values for any optional Keys + // getValue does not work for integers + int pixelSize = 0; + if (dictionary.hasKeyAndValue(defaultprovider::KeyTilePixelSize)) { + pixelSize = static_cast( + dictionary.value(defaultprovider::KeyTilePixelSize) + ); + LDEBUG(fmt::format("Default pixel size overridden: {}", pixelSize)); + } + + if (dictionary.hasKeyAndValue(defaultprovider::KeyPadTiles)) { + padTiles = dictionary.value(defaultprovider::KeyPadTiles); + } + + TileTextureInitData initData( + tileTextureInitData(layerGroupID, padTiles, pixelSize) + ); + tilePixelSize = initData.dimensions.x; + + + // Only preprocess height layers by default + switch (layerGroupID) { + case layergroupid::GroupID::HeightLayers: performPreProcessing = true; break; + default: performPreProcessing = false; break; + } + + if (dictionary.hasKeyAndValue(defaultprovider::KeyPerformPreProcessing)) { + performPreProcessing = dictionary.value( + defaultprovider::KeyPerformPreProcessing + ); + LDEBUG(fmt::format( + "Default PerformPreProcessing overridden: {}", performPreProcessing + )); + } + + initAsyncTileDataReader(*this, initData); + + addProperty(filePath); + addProperty(tilePixelSize); +} + + + + + +SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) + : filePath(singleimageprovider::FilePathInfo) +{ + type = Type::SingleImageTileProvider; + + filePath = dictionary.value(KeyFilePath); + addProperty(filePath); + + reset(*this); +} + + + + + +TextTileProvider::TextTileProvider(const TileTextureInitData& initData, size_t fontSize) + : initData(initData) + , fontSize(fontSize) +{ + tileCache = global::moduleEngine.module()->tileCache(); +} + + + + + +SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary) + : TextTileProvider(tileTextureInitData(layergroupid::GroupID::ColorLayers, false)) +{ + type = Type::SizeReferenceTileProvider; + + font = global::fontManager.font("Mono", static_cast(fontSize)); + + if (dictionary.hasKeyAndValue(sizereferenceprovider::KeyRadii)) { + ellipsoid = dictionary.value(sizereferenceprovider::KeyRadii); + } +} + + + + + +TileIndexTileProvider::TileIndexTileProvider(const ghoul::Dictionary&) + : TextTileProvider(tileTextureInitData(layergroupid::GroupID::ColorLayers, false)) +{ + type = Type::TileIndexTileProvider; +} + + + + + +TileProviderByIndex::TileProviderByIndex(const ghoul::Dictionary& dictionary) { + type = Type::ByIndexTileProvider; + + const ghoul::Dictionary& defaultProviderDict = dictionary.value( + byindexprovider::KeyDefaultProvider + ); + + layergroupid::TypeID typeID; + if (defaultProviderDict.hasKeyAndValue("Type")) { + const std::string& t = defaultProviderDict.value("Type"); + typeID = ghoul::from_string(t); + + if (typeID == layergroupid::TypeID::Unknown) { + throw ghoul::RuntimeError("Unknown layer type: " + t); + } + } + else { + typeID = layergroupid::TypeID::DefaultTileLayer; + } + + defaultTileProvider = createFromDictionary(typeID, defaultProviderDict); + + const ghoul::Dictionary& indexProvidersDict = dictionary.value( + byindexprovider::KeyProviders + ); + for (size_t i = 1; i <= indexProvidersDict.size(); i++) { + ghoul::Dictionary indexProviderDict = indexProvidersDict.value( + std::to_string(i) + ); + ghoul::Dictionary tileIndexDict = indexProviderDict.value( + byindexprovider::KeyTileIndex + ); + ghoul::Dictionary providerDict = indexProviderDict.value( + byindexprovider::KeyTileProvider + ); + + constexpr const char* KeyLevel = "Level"; + constexpr const char* KeyX = "X"; + constexpr const char* KeyY = "Y"; + + int level = static_cast(tileIndexDict.value(KeyLevel)); + int x = static_cast(tileIndexDict.value(KeyX)); + int y = static_cast(tileIndexDict.value(KeyY)); + const TileIndex tileIndex(x, y, level); + + layergroupid::TypeID providerTypeID = layergroupid::TypeID::DefaultTileLayer; + if (defaultProviderDict.hasKeyAndValue("Type")) { + const std::string& t = defaultProviderDict.value("Type"); + providerTypeID = ghoul::from_string(t); + + if (providerTypeID == layergroupid::TypeID::Unknown) { + throw ghoul::RuntimeError("Unknown layer type: " + t); + } + } + + std::unique_ptr stp = createFromDictionary( + providerTypeID, + providerDict + ); + TileIndex::TileHashKey key = tileIndex.hashKey(); + tileProviderMap.insert(std::make_pair(key, std::move(stp))); + } +} + + + + + +TileProviderByLevel::TileProviderByLevel(const ghoul::Dictionary& dictionary) { + type = Type::ByLevelTileProvider; + + layergroupid::GroupID layerGroupID = dictionary.value( + bylevelprovider::KeyLayerGroupID + ); + + if (dictionary.hasKeyAndValue(bylevelprovider::KeyProviders)) { + ghoul::Dictionary providers = dictionary.value( + bylevelprovider::KeyProviders + ); + + for (size_t i = 1; i <= providers.size(); i++) { + ghoul::Dictionary levelProviderDict = providers.value( + std::to_string(i) + ); + double floatMaxLevel = levelProviderDict.value( + bylevelprovider::KeyMaxLevel + ); + int maxLevel = static_cast(std::round(floatMaxLevel)); + + ghoul::Dictionary providerDict = levelProviderDict.value( + bylevelprovider::KeyTileProvider + ); + providerDict.setValue(bylevelprovider::KeyLayerGroupID, layerGroupID); + + layergroupid::TypeID typeID; + if (providerDict.hasKeyAndValue("Type")) { + const std::string& typeString = providerDict.value("Type"); + typeID = ghoul::from_string(typeString); + + if (typeID == layergroupid::TypeID::Unknown) { + throw ghoul::RuntimeError("Unknown layer type: " + typeString); + } + } + else { + typeID = layergroupid::TypeID::DefaultTileLayer; + } + + std::unique_ptr tp = std::unique_ptr( + createFromDictionary(typeID, providerDict) + ); + + std::string provId = providerDict.value("Identifier"); + tp->setIdentifier(provId); + std::string providerName = providerDict.value("Name"); + tp->setGuiName(providerName); + addPropertySubOwner(tp.get()); + + levelTileProviders.push_back(std::move(tp)); + + // Ensure we can represent the max level + if (static_cast(providerIndices.size()) < maxLevel) { + providerIndices.resize(maxLevel + 1, -1); + } + + // map this level to the tile provider index + providerIndices[maxLevel] = static_cast(levelTileProviders.size()) - 1; + } + } + + // Fill in the gaps (value -1 ) in provider indices, from back to end + for (int i = static_cast(providerIndices.size()) - 2; i >= 0; --i) { + if (providerIndices[i] == -1) { + providerIndices[i] = providerIndices[i + 1]; + } + } +} + + + + + +TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary) + : initDict(dictionary) + , filePath(temporal::FilePathInfo) +{ + type = Type::TemporalTileProvider; + + filePath = dictionary.value(KeyFilePath); + addProperty(filePath); + + successfulInitialization = readFilePath(*this); + + if (!successfulInitialization) { + LERRORC("TemporalTileProvider", "Unable to read file " + filePath.value()); + } +} + + + + + + +bool initialize(TileProvider& tp) { + ghoul_assert(!tp.isInitialized, "TileProvider can only be initialized once."); + + tp.uniqueIdentifier = tp.NumTileProviders++; + if (tp.NumTileProviders == std::numeric_limits::max()) { + --tp.NumTileProviders; + return false; + } + + tp.isInitialized = true; + + switch (tp.type) { + case Type::DefaultTileProvider: + break; + case Type::SingleImageTileProvider: + break; + case Type::SizeReferenceTileProvider: { + SizeReferenceTileProvider& t = static_cast(tp); + initialize(t); + break; + } + case Type::TileIndexTileProvider: { + TileIndexTileProvider& t = static_cast(tp); + initialize(t); + break; + } + case Type::ByIndexTileProvider: + break; + case Type::ByLevelTileProvider: { + TileProviderByLevel& t = static_cast(tp); + bool success = true; + for (const std::unique_ptr& prov : t.levelTileProviders) { + success &= initialize(*prov); + } + return success; + } + case Type::TemporalTileProvider: + break; + default: + throw ghoul::MissingCaseException(); + } + + return true; +} + + + + + + +bool deinitialize(TileProvider& tp) { + switch (tp.type) { + case Type::DefaultTileProvider: + break; + case Type::SingleImageTileProvider: + break; + case Type::SizeReferenceTileProvider: { + SizeReferenceTileProvider& t = static_cast(tp); + deinitialize(t); + break; + } + case Type::TileIndexTileProvider: { + TileIndexTileProvider& t = static_cast(tp); + deinitialize(t); + break; + } + case Type::ByIndexTileProvider: + break; + case Type::ByLevelTileProvider: { + TileProviderByLevel& t = static_cast(tp); + bool success = true; + for (const std::unique_ptr& prov : t.levelTileProviders) { + success &= deinitialize(*prov); + } + return success; + } + case Type::TemporalTileProvider: + break; + default: + throw ghoul::MissingCaseException(); + } + return true; +} + + + + + + +Tile tile(TileProvider& tp, const TileIndex& tileIndex) { + switch (tp.type) { + case Type::DefaultTileProvider: { + DefaultTileProvider& t = static_cast(tp); + if (t.asyncTextureDataProvider) { + if (tileIndex.level > maxLevel(t)) { + return Tile{ nullptr, std::nullopt, Tile::Status::OutOfRange }; + } + const cache::ProviderTileKey key = { tileIndex, t.uniqueIdentifier }; + const Tile tile = t.tileCache->get(key); + + if (!tile.texture) { + t.asyncTextureDataProvider->enqueueTileIO(tileIndex); + } + + return tile; + } + else { + return Tile{ nullptr, std::nullopt, Tile::Status::Unavailable }; + } + } + case Type::SingleImageTileProvider: { + SingleImageProvider& t = static_cast(tp); + return t.tile; + } + case Type::SizeReferenceTileProvider: { + SizeReferenceTileProvider& t = static_cast(tp); + + const GeodeticPatch patch(tileIndex); + const bool aboveEquator = patch.isNorthern(); + const double lat = aboveEquator ? patch.minLat() : patch.maxLat(); + const double lon1 = patch.minLon(); + const double lon2 = patch.maxLon(); + int l = static_cast(t.ellipsoid.longitudalDistance(lat, lon1, lon2)); + + const bool useKm = l > 9999; + if (useKm) { + l /= 1000; + } + l = static_cast(std::round(l)); + if (useKm) { + l *= 1000; + } + double tileLongitudalLength = l; + + const char* unit; + if (tileLongitudalLength > 9999) { + tileLongitudalLength *= 0.001; + unit = "km"; + } + else { + unit = "m"; + } + + t.text = fmt::format(" {:.0f} {:s}", tileLongitudalLength, unit); + t.textPosition = { + 0.f, + aboveEquator ? + t.fontSize / 2.f : + t.initData.dimensions.y - 3.f * t.fontSize / 2.f + }; + t.textColor = glm::vec4(1.f); + + return tile(t, tileIndex); + } + case Type::TileIndexTileProvider: { + TileIndexTileProvider& t = static_cast(tp); + t.text = fmt::format( + "level: {}\nx: {}\ny: {}", tileIndex.level, tileIndex.x, tileIndex.y + ); + t.textPosition = glm::vec2( + t.initData.dimensions.x / 4 - + (t.initData.dimensions.x / 32) * log10(1 << tileIndex.level), + t.initData.dimensions.y / 2 + t.fontSize + ); + t.textColor = glm::vec4(1.f); + + return tile(t, tileIndex); + } + case Type::ByIndexTileProvider: { + TileProviderByIndex& t = static_cast(tp); + const auto it = t.tileProviderMap.find(tileIndex.hashKey()); + const bool hasProvider = it != t.tileProviderMap.end(); + return hasProvider ? tile(*it->second, tileIndex) : Tile(); + } + case Type::ByLevelTileProvider: { + TileProviderByLevel& t = static_cast(tp); + TileProvider* provider = levelProvider(t, tileIndex.level); + if (provider) { + return tile(*provider, tileIndex); + } + else { + return Tile(); + } + } + case Type::TemporalTileProvider: { + TemporalTileProvider& t = static_cast(tp); + if (t.successfulInitialization) { + ensureUpdated(t); + return tile(*t.currentTileProvider, tileIndex); + } + else { + return Tile(); + } + } + default: + throw ghoul::MissingCaseException(); + } +} + + + + +Tile::Status tileStatus(TileProvider& tp, const TileIndex& index) { + switch (tp.type) { + case Type::DefaultTileProvider: { + DefaultTileProvider& t = static_cast(tp); + if (t.asyncTextureDataProvider) { + const RawTileDataReader& rawTileDataReader = + t.asyncTextureDataProvider->rawTileDataReader(); + + if (index.level > rawTileDataReader.maxChunkLevel()) { + return Tile::Status::OutOfRange; + } + + const cache::ProviderTileKey key = { index, t.uniqueIdentifier }; + return t.tileCache->get(key).status; + } + else { + return Tile::Status::Unavailable; + } + } + case Type::SingleImageTileProvider: { + SingleImageProvider& t = static_cast(tp); + return t.tile.status; + } + case Type::SizeReferenceTileProvider: + return Tile::Status::OK; + case Type::TileIndexTileProvider: + return Tile::Status::OK; + case Type::ByIndexTileProvider: { + TileProviderByIndex& t = static_cast(tp); + const auto it = t.tileProviderMap.find(index.hashKey()); + const bool hasProvider = it != t.tileProviderMap.end(); + return hasProvider ? + tileStatus(*it->second, index) : + Tile::Status::Unavailable; + } + case Type::ByLevelTileProvider: { + TileProviderByLevel& t = static_cast(tp); + TileProvider* provider = levelProvider(t, index.level); + return provider ? tileStatus(*provider, index) : Tile::Status::Unavailable; + } + case Type::TemporalTileProvider: { + TemporalTileProvider& t = static_cast(tp); + if (t.successfulInitialization) { + ensureUpdated(t); + return tileStatus(*t.currentTileProvider, index); + } + else { + return Tile::Status::Unavailable; + } + } + default: + throw ghoul::MissingCaseException(); + } +} + + + + + + +TileDepthTransform depthTransform(TileProvider& tp) { + switch (tp.type) { + case Type::DefaultTileProvider: { + DefaultTileProvider& t = static_cast(tp); + if (t.asyncTextureDataProvider) { + return t.asyncTextureDataProvider->rawTileDataReader().depthTransform(); + } + else { + return { 1.f, 0.f }; + } + } + case Type::SingleImageTileProvider: + return { 0.f, 1.f }; + case Type::SizeReferenceTileProvider: + return { 0.f, 1.f }; + case Type::TileIndexTileProvider: + return { 0.f, 1.f }; + case Type::ByIndexTileProvider: { + TileProviderByIndex& t = static_cast(tp); + return depthTransform(*t.defaultTileProvider); + } + case Type::ByLevelTileProvider: + return { 0.f, 1.f }; + case Type::TemporalTileProvider: { + TemporalTileProvider& t = static_cast(tp); + if (t.successfulInitialization) { + ensureUpdated(t); + return depthTransform(*t.currentTileProvider); + } + else { + return { 1.f, 0.f }; + } + } + default: + throw ghoul::MissingCaseException(); + } +} + + + + + + +void update(TileProvider& tp) { + switch (tp.type) { + case Type::DefaultTileProvider: { + DefaultTileProvider& t = static_cast(tp); + if (!t.asyncTextureDataProvider) { + break; + } + + t.asyncTextureDataProvider->update(); + initTexturesFromLoadedData(t); + + if (t.asyncTextureDataProvider->shouldBeDeleted()) { + t.asyncTextureDataProvider = nullptr; + initAsyncTileDataReader( + t, + tileTextureInitData(t.layerGroupID, t.padTiles, t.tilePixelSize) + ); + } + break; + } + case Type::SingleImageTileProvider: + break; + case Type::SizeReferenceTileProvider: + break; + case Type::TileIndexTileProvider: + break; + case Type::ByIndexTileProvider: { + TileProviderByIndex& t = static_cast(tp); + using K = TileIndex::TileHashKey; + using V = std::unique_ptr; + for (std::pair& it : t.tileProviderMap) { + update(*it.second); + } + update(*t.defaultTileProvider); + break; + } + case Type::ByLevelTileProvider: { + TileProviderByLevel& t = static_cast(tp); + for (const std::unique_ptr& provider : t.levelTileProviders) { + update(*provider); + } + break; + } + case Type::TemporalTileProvider: { + TemporalTileProvider& t = static_cast(tp); + if (t.successfulInitialization) { + TileProvider* newCurrent = getTileProvider(t, global::timeManager.time()); + if (newCurrent) { + t.currentTileProvider = newCurrent; + } + update(*t.currentTileProvider); + } + break; + } + default: + throw ghoul::MissingCaseException(); + } +} + + + + + + +void reset(TileProvider& tp) { + switch (tp.type) { + case Type::DefaultTileProvider: { + DefaultTileProvider& t = static_cast(tp); + t.tileCache->clear(); + if (t.asyncTextureDataProvider) { + t.asyncTextureDataProvider->prepareToBeDeleted(); + } + else { + initAsyncTileDataReader( + t, + tileTextureInitData(t.layerGroupID, t.padTiles, t.tilePixelSize) + ); + } + break; + } + case Type::SingleImageTileProvider: { + SingleImageProvider& t = static_cast(tp); + + if (t.filePath.value().empty()) { + return; + } + t.tileTexture = ghoul::io::TextureReader::ref().loadTexture(t.filePath); + if (!t.tileTexture) { + throw ghoul::RuntimeError( + fmt::format("Unable to load texture '{}'", t.filePath.value()) + ); + } + Tile::Status tileStatus = Tile::Status::OK; + + t.tileTexture->uploadTexture(); + t.tileTexture->setFilter( + ghoul::opengl::Texture::FilterMode::AnisotropicMipMap + ); + + t.tile = Tile{ t.tileTexture.get(), std::nullopt, tileStatus }; + break; + } + case Type::SizeReferenceTileProvider: { + SizeReferenceTileProvider& t = static_cast(tp); + reset(t); + break; + } + case Type::TileIndexTileProvider: { + TileIndexTileProvider& t = static_cast(tp); + reset(t); + break; + } + case Type::ByIndexTileProvider: { + TileProviderByIndex& t = static_cast(tp); + using K = TileIndex::TileHashKey; + using V = std::unique_ptr; + for (std::pair& it : t.tileProviderMap) { + reset(*it.second); + } + reset(*t.defaultTileProvider); + break; + } + case Type::ByLevelTileProvider: { + TileProviderByLevel& t = static_cast(tp); + for (const std::unique_ptr& provider : t.levelTileProviders) { + reset(*provider); + } + break; + } + case Type::TemporalTileProvider: { + TemporalTileProvider& t = static_cast(tp); + if (t.successfulInitialization) { + using K = TemporalTileProvider::TimeKey; + using V = std::unique_ptr; + for (std::pair& it : t.tileProviderMap) { + reset(*it.second); + } + } + break; + } + default: + throw ghoul::MissingCaseException(); + } +} + + + + + + +int maxLevel(TileProvider& tp) { + switch (tp.type) { + case Type::DefaultTileProvider: { + DefaultTileProvider& t = static_cast(tp); + // 22 is the current theoretical maximum based on the number of hashes that + // are possible to uniquely identify a tile. See ProviderTileHasher in + // memoryawaretilecache.h + return t.asyncTextureDataProvider ? + t.asyncTextureDataProvider->rawTileDataReader().maxChunkLevel() : + 22; + } + case Type::SingleImageTileProvider: + return 1337; // unlimited + case Type::SizeReferenceTileProvider: + return 1337; // unlimited + case Type::TileIndexTileProvider: + return 1337; // unlimited + case Type::ByIndexTileProvider: { + TileProviderByIndex& t = static_cast(tp); + return maxLevel(*t.defaultTileProvider); + } + case Type::ByLevelTileProvider: { + TileProviderByLevel& t = static_cast(tp); + return static_cast(t.providerIndices.size() - 1); + } + case Type::TemporalTileProvider: { + TemporalTileProvider& t = static_cast(tp); + if (t.successfulInitialization) { + ensureUpdated(t); + return maxLevel(*t.currentTileProvider); + } + else { + return 0; + } + } + default: + throw ghoul::MissingCaseException(); + } +} + + + + + + +float noDataValueAsFloat(TileProvider& tp) { + ghoul_assert(tp.isInitialized, "TileProvider was not initialized."); + switch (tp.type) { + case Type::DefaultTileProvider: { + DefaultTileProvider& t = static_cast(tp); + return t.asyncTextureDataProvider ? + t.asyncTextureDataProvider->noDataValueAsFloat() : + std::numeric_limits::min(); + } + case Type::SingleImageTileProvider: + return std::numeric_limits::min(); + case Type::SizeReferenceTileProvider: + return std::numeric_limits::min(); + case Type::TileIndexTileProvider: + return std::numeric_limits::min(); + case Type::ByIndexTileProvider: + return std::numeric_limits::min(); + case Type::ByLevelTileProvider: + return std::numeric_limits::min(); + case Type::TemporalTileProvider: + return std::numeric_limits::min(); + default: + throw ghoul::MissingCaseException(); + } +} + + + + + +ChunkTile chunkTile(TileProvider& tp, TileIndex tileIndex, int parents, int maxParents) { + ghoul_assert(tp.isInitialized, "TileProvider was not initialized."); + + auto ascendToParent = [](TileIndex& tileIndex, TileUvTransform& uv) { + uv.uvOffset *= 0.5; + uv.uvScale *= 0.5; + + uv.uvOffset += tileIndex.positionRelativeParent(); + + tileIndex.x /= 2; + tileIndex.y /= 2; + tileIndex.level--; + }; + + TileUvTransform uvTransform = { glm::vec2(0.f, 0.f), glm::vec2(1.f, 1.f) }; + + // Step 1. Traverse 0 or more parents up the chunkTree as requested by the caller + for (int i = 0; i < parents && tileIndex.level > 1; i++) { + ascendToParent(tileIndex, uvTransform); + } + maxParents -= parents; + + // Step 2. Traverse 0 or more parents up the chunkTree to make sure we're inside + // the range of defined data. + int maximumLevel = maxLevel(tp); + while (tileIndex.level > maximumLevel) { + ascendToParent(tileIndex, uvTransform); + maxParents--; + } + if (maxParents < 0) { + return ChunkTile{ Tile(), uvTransform, TileDepthTransform() }; + } + + // Step 3. Traverse 0 or more parents up the chunkTree until we find a chunk that + // has a loaded tile ready to use. + while (tileIndex.level > 1) { + Tile t = tile(tp, tileIndex); + if (t.status != Tile::Status::OK) { + if (--maxParents < 0) { + return ChunkTile{ Tile(), uvTransform, TileDepthTransform() }; + } + ascendToParent(tileIndex, uvTransform); + } + else { + return ChunkTile{ std::move(t), uvTransform, TileDepthTransform() }; + } + } + + return ChunkTile{ Tile(), uvTransform, TileDepthTransform() }; +} + + + + + + +ChunkTilePile chunkTilePile(TileProvider& tp, TileIndex tileIndex, int pileSize) { + ghoul_assert(tp.isInitialized, "TileProvider was not initialized."); + ghoul_assert(pileSize >= 0, "pileSize must be positive"); + + ChunkTilePile chunkTilePile(pileSize); + for (int i = 0; i < pileSize; ++i) { + chunkTilePile[i] = chunkTile(tp, tileIndex, i); + if (chunkTilePile[i].tile.status == Tile::Status::Unavailable) { + if (i > 0) { + // First iteration + chunkTilePile[i].tile = chunkTilePile[i - 1].tile; + chunkTilePile[i].uvTransform.uvOffset = + chunkTilePile[i - 1].uvTransform.uvOffset; + chunkTilePile[i].uvTransform.uvScale = + chunkTilePile[i - 1].uvTransform.uvScale; + } + else { + chunkTilePile[i].tile = DefaultTile; + chunkTilePile[i].uvTransform.uvOffset = { 0.f, 0.f }; + chunkTilePile[i].uvTransform.uvScale = { 1.f, 1.f }; + } + } + } + return chunkTilePile; +} + +} // namespace openspace::globebrowsing::tileprovider diff --git a/modules/globebrowsing/src/tileprovider.h b/modules/globebrowsing/src/tileprovider.h new file mode 100644 index 0000000000..68f044378f --- /dev/null +++ b/modules/globebrowsing/src/tileprovider.h @@ -0,0 +1,248 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_PROVIDER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_PROVIDER___H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct CPLXMLNode; + +namespace ghoul::fontrendering { + class Font; + class FontRenderer; +} // namespace ghoul::fontrendering + +namespace openspace { class PixelBuffer; } + +namespace openspace::globebrowsing { + class AsyncTileDataProvider; + struct RawTile; + struct TileIndex; + namespace cache { class MemoryAwareTileCache; } +} // namespace openspace::globebrowsing + +namespace openspace::globebrowsing::tileprovider { + +enum class Type { + DefaultTileProvider = 0, + SingleImageTileProvider, + SizeReferenceTileProvider, + TemporalTileProvider, + TileIndexTileProvider, + ByIndexTileProvider, + ByLevelTileProvider +}; + + +struct TileProvider : public properties::PropertyOwner { + static unsigned int NumTileProviders; + + Type type; + + TileProvider(); + virtual ~TileProvider() = default; + + std::string name; + + unsigned int uniqueIdentifier = 0; + bool isInitialized = false; +}; + +struct DefaultTileProvider : public TileProvider { + DefaultTileProvider(const ghoul::Dictionary& dictionary); + + std::unique_ptr asyncTextureDataProvider; + + cache::MemoryAwareTileCache* tileCache = nullptr; + + properties::StringProperty filePath; + properties::IntProperty tilePixelSize; + layergroupid::GroupID layerGroupID = layergroupid::GroupID::Unknown; + bool performPreProcessing = false; + bool padTiles = true; +}; + +struct SingleImageProvider : public TileProvider { + SingleImageProvider(const ghoul::Dictionary& dictionary); + + std::unique_ptr tileTexture; + Tile tile; + + properties::StringProperty filePath; +}; + +struct TextTileProvider : public TileProvider { + TextTileProvider(const TileTextureInitData& initData, size_t fontSize = 48); + + const TileTextureInitData initData; + + std::unique_ptr fontRenderer; + std::shared_ptr font; + size_t fontSize; + + std::string text; + glm::vec2 textPosition; + glm::vec4 textColor; + + GLuint fbo = 0; + + cache::MemoryAwareTileCache* tileCache; +}; + +struct SizeReferenceTileProvider : public TextTileProvider { + SizeReferenceTileProvider(const ghoul::Dictionary& dictionary); + + Ellipsoid ellipsoid; +}; + +struct TileIndexTileProvider : public TextTileProvider { + TileIndexTileProvider(const ghoul::Dictionary& dictionary); +}; + +struct TileProviderByIndex : public TileProvider { + TileProviderByIndex(const ghoul::Dictionary& dictionary); + + std::unordered_map< + TileIndex::TileHashKey, std::unique_ptr + > tileProviderMap; + std::unique_ptr defaultTileProvider; +}; + +struct TileProviderByLevel : public TileProvider { + TileProviderByLevel(const ghoul::Dictionary& dictionary); + + std::vector providerIndices; + std::vector> levelTileProviders; +}; + + +/** + * Provide Tiles from web map services that have temporal resolution. + * + * TemporalTileProviders are instantiated using a ghoul::Dictionary, + * and must define a filepath to a Openspace Temporal dataset description file. + * This is an xml-file that defines the same meta data as the GDAL wms description + * (http://www.gdal.org/frmt_wms.html), but augmented with some + * extra tags describing the temporal properties of the dataset. See + * TemporalTileProvider::TemporalXMLTags + * + */ +struct TemporalTileProvider : public TileProvider { + enum class TimeFormatType { + YYYY_MM_DD = 0, + YYYYMMDD_hhmmss, + YYYYMMDD_hhmm, + YYYY_MM_DDThhColonmmColonssZ, + YYYY_MM_DDThh_mm_ssZ + }; + + using TimeKey = std::string; + + TemporalTileProvider(const ghoul::Dictionary& dictionary); + + ghoul::Dictionary initDict; + properties::StringProperty filePath; + std::string gdalXmlTemplate; + + std::unordered_map> tileProviderMap; + + TileProvider* currentTileProvider = nullptr; + + TimeFormatType timeFormat; + TimeQuantizer timeQuantizer; + + bool successfulInitialization = false; +}; + + + +void initializeDefaultTile(); +void deinitializeDefaultTile(); + +std::unique_ptr createFromDictionary(layergroupid::TypeID layerTypeID, + const ghoul::Dictionary& dictionary); + +bool initialize(TileProvider& tp); +bool deinitialize(TileProvider& tp); + +Tile tile(TileProvider& tp, const TileIndex& tileIndex); + +ChunkTile chunkTile(TileProvider& tp, TileIndex tileIndex, int parents = 0, + int maxParents = 1337); + +ChunkTilePile chunkTilePile(TileProvider& tp, TileIndex tileIndex, int pileSize); + +/** + * Returns the status of a Tile. The Tile::Status + * corresponds the Tile that would be returned + * if the function tile would be invoked with the same + * TileIndex argument at this point in time. + */ +Tile::Status tileStatus(TileProvider& tp, const TileIndex& index); + +/** + * Get the associated depth transform for this TileProvider. + * This is necessary for TileProviders serving height map + * data, in order to correcly map pixel values to meters. + */ +TileDepthTransform depthTransform(TileProvider& tp); + +/** + * This method should be called once per frame. Here, TileProviders + * are given the opportunity to update their internal state. + */ +void update(TileProvider& tp); + +/** + * Provides a uniform way of all TileProviders to reload or + * restore all of its internal state. This is mainly useful + * for debugging purposes. + */ +void reset(TileProvider& tp); + +/** + * \returns The maximum level as defined by TileIndex + * that this TileProvider is able provide. + */ +int maxLevel(TileProvider& tp); + +/** + * \returns the no data value for the dataset. Default is the minimum float avalue. + */ +float noDataValueAsFloat(TileProvider& tp); + +} // namespace openspace::globebrowsing::tileprovider + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_PROVIDER___H__ diff --git a/modules/globebrowsing/src/tiletextureinitdata.cpp b/modules/globebrowsing/src/tiletextureinitdata.cpp new file mode 100644 index 0000000000..5839940c44 --- /dev/null +++ b/modules/globebrowsing/src/tiletextureinitdata.cpp @@ -0,0 +1,203 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace { + +const glm::ivec2 TilePixelStartOffset = glm::ivec2(-2); +const glm::ivec2 TilePixelSizeDifference = glm::ivec2(4); + +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: + case ghoul::opengl::Texture::Format::BGR: + return 3; + case ghoul::opengl::Texture::Format::RGBA: + case ghoul::opengl::Texture::Format::BGRA: + return 4; + default: { + ghoul_assert(false, "Unknown format"); + throw ghoul::MissingCaseException(); + } + } +} + +size_t numberOfBytes(GLenum glType) { + switch (glType) { + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + case GL_BYTE: return sizeof(GLbyte); + 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_HALF_FLOAT: return sizeof(GLhalf); + case GL_FLOAT: return sizeof(GLfloat); + case GL_DOUBLE: return sizeof(GLdouble); + default: + ghoul_assert(false, "Unknown data type"); + throw ghoul::MissingCaseException(); + } +} + +unsigned int uniqueIdForTextureFormat(ghoul::opengl::Texture::Format textureFormat) { + switch (textureFormat) { + case ghoul::opengl::Texture::Format::Red: return 0; + case ghoul::opengl::Texture::Format::RG: return 1; + case ghoul::opengl::Texture::Format::RGB: return 2; + case ghoul::opengl::Texture::Format::BGR: return 3; + case ghoul::opengl::Texture::Format::RGBA: return 4; + case ghoul::opengl::Texture::Format::BGRA: return 5; + case ghoul::opengl::Texture::Format::DepthComponent: return 6; + default: throw ghoul::MissingCaseException(); + } +} + +openspace::globebrowsing::TileTextureInitData::HashKey calculateHashKey( + const glm::ivec3& dimensions, + const ghoul::opengl::Texture::Format& format, + const GLenum& glType) +{ + ghoul_assert(dimensions.x > 0, "Incorrect dimension"); + ghoul_assert(dimensions.y > 0, "Incorrect dimension"); + ghoul_assert(dimensions.x <= 1024, "Incorrect dimension"); + ghoul_assert(dimensions.y <= 1024, "Incorrect dimension"); + ghoul_assert(dimensions.z == 1, "Incorrect dimension"); + unsigned int formatId = uniqueIdForTextureFormat(format); + ghoul_assert(formatId < 256, "Incorrect format"); + + openspace::globebrowsing::TileTextureInitData::HashKey res = 0ULL; + + res |= dimensions.x; + res |= dimensions.y << 10; + res |= static_cast>(glType) << (10 + 16); + res |= formatId << (10 + 16 + 4); + + return res; +} + +} // namespace + +namespace openspace::globebrowsing { + +TileTextureInitData tileTextureInitData(layergroupid::GroupID id, bool shouldPadTiles, + size_t preferredTileSize) +{ + switch (id) { + case layergroupid::GroupID::HeightLayers: { + const size_t tileSize = preferredTileSize ? preferredTileSize : 64; + return TileTextureInitData( + tileSize, + tileSize, + GL_FLOAT, + ghoul::opengl::Texture::Format::Red, + TileTextureInitData::PadTiles(shouldPadTiles), + TileTextureInitData::ShouldAllocateDataOnCPU::Yes + ); + } + case layergroupid::GroupID::ColorLayers: { + const size_t tileSize = preferredTileSize ? preferredTileSize : 512; + return TileTextureInitData( + tileSize, + tileSize, + GL_UNSIGNED_BYTE, + ghoul::opengl::Texture::Format::BGRA, + TileTextureInitData::PadTiles(shouldPadTiles) + ); + } + case layergroupid::GroupID::Overlays: { + const size_t tileSize = preferredTileSize ? preferredTileSize : 512; + return TileTextureInitData( + tileSize, + tileSize, + GL_UNSIGNED_BYTE, + ghoul::opengl::Texture::Format::BGRA, + TileTextureInitData::PadTiles(shouldPadTiles) + ); + } + case layergroupid::GroupID::NightLayers: { + const size_t tileSize = preferredTileSize ? preferredTileSize : 512; + return TileTextureInitData( + tileSize, + tileSize, + GL_UNSIGNED_BYTE, + ghoul::opengl::Texture::Format::BGRA, + TileTextureInitData::PadTiles(shouldPadTiles) + ); + } + case layergroupid::GroupID::WaterMasks: { + const size_t tileSize = preferredTileSize ? preferredTileSize : 512; + return TileTextureInitData( + tileSize, + tileSize, + GL_UNSIGNED_BYTE, + ghoul::opengl::Texture::Format::BGRA, + TileTextureInitData::PadTiles(shouldPadTiles) + ); + } + default: { + throw ghoul::MissingCaseException(); + } + } +} + +TileTextureInitData::TileTextureInitData(size_t width, size_t height, GLenum type, + ghoul::opengl::Texture::Format textureFormat, + PadTiles pad, ShouldAllocateDataOnCPU allocCpu) + : dimensions(width, height, 1) + , tilePixelStartOffset(pad ? TilePixelStartOffset : glm::ivec2(0)) + , tilePixelSizeDifference(pad ? TilePixelSizeDifference : glm::ivec2(0)) + , glType(type) + , ghoulTextureFormat(textureFormat) + , nRasters(numberOfRasters(ghoulTextureFormat)) + , bytesPerDatum(numberOfBytes(glType)) + , bytesPerPixel(nRasters * bytesPerDatum) + , bytesPerLine(bytesPerPixel * width) + , totalNumBytes(bytesPerLine * height) + , shouldAllocateDataOnCPU(allocCpu) + , padTiles(pad) + , hashKey(calculateHashKey(dimensions, ghoulTextureFormat, glType)) +{} + +TileTextureInitData TileTextureInitData::operator=(const TileTextureInitData& rhs) { + if (this == &rhs) { + return TileTextureInitData(*this); + } + + return TileTextureInitData(rhs); + +} +TileTextureInitData TileTextureInitData::operator=(TileTextureInitData&& rhs) { + if (this == &rhs) { + return TileTextureInitData(*this); + } + + return TileTextureInitData(rhs); +} + +} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/tiletextureinitdata.h b/modules/globebrowsing/src/tiletextureinitdata.h similarity index 66% rename from modules/globebrowsing/tile/tiletextureinitdata.h rename to modules/globebrowsing/src/tiletextureinitdata.h index 96e8429ff1..4dfb4efc20 100644 --- a/modules/globebrowsing/tile/tiletextureinitdata.h +++ b/modules/globebrowsing/src/tiletextureinitdata.h @@ -25,11 +25,11 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ +#include #include #include #include #include -#include namespace openspace::globebrowsing { @@ -38,57 +38,40 @@ namespace openspace::globebrowsing { */ class TileTextureInitData { public: - using HashKey = unsigned long long; + using HashKey = uint64_t; BooleanType(ShouldAllocateDataOnCPU); BooleanType(PadTiles); - using Format = ghoul::opengl::Texture::Format; - TileTextureInitData(size_t width, size_t height, GLenum glType, Format textureFormat, - PadTiles padTiles, - ShouldAllocateDataOnCPU shouldAllocateDataOnCPU = ShouldAllocateDataOnCPU::No); + TileTextureInitData(size_t width, size_t height, GLenum glType, + ghoul::opengl::Texture::Format textureFormat, PadTiles padTiles, + ShouldAllocateDataOnCPU cpuAlloc = ShouldAllocateDataOnCPU::No); - TileTextureInitData(const TileTextureInitData& original); + TileTextureInitData(const TileTextureInitData& original) = default; + TileTextureInitData(TileTextureInitData&& original) = default; + + TileTextureInitData operator=(const TileTextureInitData& rhs); + TileTextureInitData operator=(TileTextureInitData&& rhs); ~TileTextureInitData() = default; - glm::ivec3 dimensions() const; - glm::ivec2 tilePixelStartOffset() const; - glm::ivec2 tilePixelSizeDifference() const; - size_t nRasters() const; - size_t bytesPerDatum() const; - size_t bytesPerPixel() const; - size_t bytesPerLine() const; - size_t totalNumBytes() const; - GLenum glType() const; - Format ghoulTextureFormat() const; - GLenum glTextureFormat() const; - bool shouldAllocateDataOnCPU() const; - HashKey hashKey() const; - - const static glm::ivec2 TilePixelStartOffset; - const static glm::ivec2 TilePixelSizeDifference; - -private: - - void calculateHashKey(); - unsigned int getUniqueIdFromTextureFormat(Format textureFormat) const; - - HashKey _hashKey = HashKey(0); - glm::ivec3 _dimensions; - glm::ivec2 _tilePixelStartOffset; - glm::ivec2 _tilePixelSizeDifference; - GLenum _glType; - Format _ghoulTextureFormat; - GLenum _glTextureFormat; - size_t _nRasters; - size_t _bytesPerDatum; - size_t _bytesPerPixel; - size_t _bytesPerLine; - size_t _totalNumBytes; - bool _shouldAllocateDataOnCPU; - bool _padTiles; + const glm::ivec3 dimensions; + const glm::ivec2 tilePixelStartOffset; + const glm::ivec2 tilePixelSizeDifference; + const GLenum glType; + const ghoul::opengl::Texture::Format ghoulTextureFormat; + const size_t nRasters; + const size_t bytesPerDatum; + const size_t bytesPerPixel; + const size_t bytesPerLine; + const size_t totalNumBytes; + const bool shouldAllocateDataOnCPU; + const bool padTiles; + const HashKey hashKey; }; +TileTextureInitData tileTextureInitData(layergroupid::GroupID id, + bool shouldPadTiles, size_t preferredTileSize = 0); + } // namespace openspace::globebrowsing #endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ diff --git a/modules/globebrowsing/other/timequantizer.cpp b/modules/globebrowsing/src/timequantizer.cpp similarity index 96% rename from modules/globebrowsing/other/timequantizer.cpp rename to modules/globebrowsing/src/timequantizer.cpp index 636dd33599..0e774cc437 100644 --- a/modules/globebrowsing/other/timequantizer.cpp +++ b/modules/globebrowsing/src/timequantizer.cpp @@ -22,7 +22,7 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +#include #include #include @@ -42,9 +42,9 @@ TimeQuantizer::TimeQuantizer(const Time& start, const Time& end, : TimeQuantizer(start, end, parseTimeResolutionStr(resolution)) {} -double TimeQuantizer::parseTimeResolutionStr(const std::string& resoltutionStr) { - const char unit = resoltutionStr.back(); - std::string numberString = resoltutionStr.substr(0, resoltutionStr.length() - 1); +double TimeQuantizer::parseTimeResolutionStr(const std::string& resolutionStr) { + const char unit = resolutionStr.back(); + std::string numberString = resolutionStr.substr(0, resolutionStr.length() - 1); char* p; double value = strtol(numberString.c_str(), &p, 10); diff --git a/modules/globebrowsing/other/timequantizer.h b/modules/globebrowsing/src/timequantizer.h similarity index 97% rename from modules/globebrowsing/other/timequantizer.h rename to modules/globebrowsing/src/timequantizer.h index 686061083c..aabbebf98d 100644 --- a/modules/globebrowsing/other/timequantizer.h +++ b/modules/globebrowsing/src/timequantizer.h @@ -47,12 +47,11 @@ struct TimeQuantizer { * * Example: parseTimeResolutionStr("1d"); * - * \param resoltutionStr with the format {number}{unit} - * where supported units are: + * \param resolutionStr with the format {number}{unit} where supported units are: * (s)econds, (m)inutes, (h)ours, (d)ays, (y)ears * \return the time resolution in seconds */ - static double parseTimeResolutionStr(const std::string& resoltutionStr); + static double parseTimeResolutionStr(const std::string& resolutionStr); /** * Quantizes a OpenSpace Time into descrete values. If the provided Time \p t is diff --git a/modules/globebrowsing/tile/chunktile.h b/modules/globebrowsing/tile/chunktile.h deleted file mode 100644 index e6efa5fb0b..0000000000 --- a/modules/globebrowsing/tile/chunktile.h +++ /dev/null @@ -1,45 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKTILE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKTILE___H__ - -#include -#include -#include -#include - -namespace openspace::globebrowsing { - -struct ChunkTile { - Tile tile = Tile::TileUnavailable; - TileUvTransform uvTransform; - TileDepthTransform depthTransform; -}; - -using ChunkTilePile = std::vector; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___CHUNKTILE___H__ diff --git a/modules/globebrowsing/tile/pixelregion.cpp b/modules/globebrowsing/tile/pixelregion.cpp deleted file mode 100644 index 07df6763a1..0000000000 --- a/modules/globebrowsing/tile/pixelregion.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace openspace::globebrowsing { - -PixelRegion::PixelRegion(const PixelCoordinate& pixelStart, - const PixelRange& numberOfPixels) - : start(pixelStart) - , numPixels(numberOfPixels) -{} - -void PixelRegion::setSide(Side side, int pos) { - switch (side) { - case Side::LEFT: - setLeft(pos); - break; - case Side::TOP: - setTop(pos); - break; - case Side::RIGHT: - setRight(pos); - break; - case Side::BOTTOM: - setBottom(pos); - break; - } -} - -void PixelRegion::setLeft(int x) { - numPixels.x += (start.x - x); - start.x = x; -} - -void PixelRegion::setTop(int p) { - numPixels.y += (start.y - p); - start.y = p; -} - -void PixelRegion::setRight(int x) { - numPixels.x = x - start.x; -} - -void PixelRegion::setBottom(int y) { - numPixels.y = y - start.y; -} - -void PixelRegion::align(Side side, int pos) { - switch (side) { - case Side::LEFT: - alignLeft(pos); - break; - case Side::TOP: - alignTop(pos); - break; - case Side::RIGHT: - alignRight(pos); - break; - case Side::BOTTOM: - alignBottom(pos); - break; - } -} - -void PixelRegion::alignLeft(int x) { - start.x = x; -} - -void PixelRegion::alignTop(int y) { - start.y = y; -} - -void PixelRegion::alignRight(int x) { - start.x = x - numPixels.x; -} - -void PixelRegion::alignBottom(int y) { - start.y = y - numPixels.y; -} - -void PixelRegion::scale(const glm::dvec2& s) { - start = PixelCoordinate(glm::round(s * glm::dvec2(start))); - numPixels = PixelCoordinate(glm::round(s * glm::dvec2(numPixels))); -} - -void PixelRegion::scale(double s) { - scale(glm::dvec2(s)); -} - -void PixelRegion::downscalePow2(int exponent, PixelCoordinate wrt) { - start += wrt; - start.x = static_cast(ceil(start.x / static_cast(pow(2, exponent)))); - start.y = static_cast(ceil(start.y / static_cast(pow(2, exponent)))); - numPixels.x = - static_cast(ceil(numPixels.x / static_cast(pow(2, exponent)))); - numPixels.y = - static_cast(ceil(numPixels.y / static_cast(pow(2, exponent)))); - start -= wrt; -} - -void PixelRegion::upscalePow2(int exponent, PixelCoordinate wrt) { - start += wrt; - start.x <<= exponent; - start.y <<= exponent; - numPixels.x <<= exponent; - numPixels.y <<= exponent; - start -= wrt; -} - -void PixelRegion::move(Side side, int amount) { - switch (side) { - case Side::LEFT: - start.x -= amount; - break; - case Side::TOP: - start.y -= amount; - break; - case Side::RIGHT: - start.x += amount; - break; - case Side::BOTTOM: - start.y += amount; - break; - } -} - -void PixelRegion::pad(const PixelRegion& padding) { - start += padding.start; - numPixels += padding.numPixels; -} - -void PixelRegion::clampTo(const PixelRegion& boundingRegion) { - start = glm::max(start, boundingRegion.start); - numPixels = glm::min(end(), boundingRegion.end()) - start; -} - -void PixelRegion::forceNumPixelToDifferByNearestMultipleOf(unsigned int multiple) { - ghoul_assert(multiple > 0, "multiple must be 1 or larger"); - const int sizeDiff = numPixels.x - numPixels.y; - if (std::abs(sizeDiff) > 0) { - if (sizeDiff > 0) { - numPixels.y += sizeDiff % multiple; - } - else { - numPixels.x += std::abs(sizeDiff) % multiple; - } - } -} - -void PixelRegion::roundUpNumPixelToNearestMultipleOf(unsigned int multiple) { - ghoul_assert(multiple > 0, "multiple must be 1 or larger"); - - 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() { - if (numPixels.x < numPixels.y) { - numPixels.y = numPixels.x; - } - else if (numPixels.x > numPixels.y) { - numPixels.x = numPixels.y; - } -} - -PixelRegion PixelRegion::globalCut(Side side, int globalPos) { - if (!lineIntersect(side, globalPos)) { - return PixelRegion({ 0, 0 }, { 0, 0 }); - } - - PixelRegion cutOff(*this); - int cutSize = 0; - switch (side) { - case Side::LEFT: - setLeft(globalPos); - cutOff.setRight(globalPos - cutSize); - break; - case Side::TOP: - setTop(globalPos); - cutOff.setBottom(globalPos - cutSize); - break; - case Side::RIGHT: - setRight(globalPos); - cutOff.setLeft(globalPos + cutSize); - break; - case Side::BOTTOM: - setBottom(globalPos); - cutOff.setTop(globalPos + cutSize); - break; - } - return cutOff; -} - -PixelRegion PixelRegion::localCut(Side side, int localPos) { - if (localPos < 1) { - return PixelRegion({ 0, 0 }, { 0, 0 }); - } - else { - return globalCut(side, edge(side) - edgeDirectionSign(side) * localPos); - } -} - -int PixelRegion::area() const { - return numPixels.x * numPixels.y; -} - -int PixelRegion::edge(Side side) const { - switch (side) { - case Side::LEFT: return start.x; - case Side::TOP: return start.y; - case Side::RIGHT: return start.x + numPixels.x; - case Side::BOTTOM: return start.y + numPixels.y; - default: throw ghoul::MissingCaseException(); - } -} - -int PixelRegion::edgeDirectionSign(Side side) const { - return side < Side::RIGHT ? -1 : 1; -} - -PixelRegion::PixelCoordinate PixelRegion::end() const { - return start + numPixels; -} - -bool PixelRegion::lineIntersect(Side side, int p) { - switch (side) { - case Side::LEFT: - case Side::RIGHT: - return start.x <= p && p <= (start.x + numPixels.x); - - case Side::TOP: - case Side::BOTTOM: - return start.y <= p && p <= (start.y + numPixels.y); - - default: - throw ghoul::MissingCaseException(); - } -} - -bool PixelRegion::isInside(const PixelRegion& r) const { - PixelCoordinate e = end(); - PixelCoordinate re = r.end(); - return r.start.x <= start.x && e.x <= re.x && r.start.y <= start.y && e.y <= re.y; -} - -bool PixelRegion::equals(const PixelRegion& r) const { - return start == r.start && numPixels == r.numPixels; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/pixelregion.h b/modules/globebrowsing/tile/pixelregion.h deleted file mode 100644 index 6fa959dac2..0000000000 --- a/modules/globebrowsing/tile/pixelregion.h +++ /dev/null @@ -1,104 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PIXELREGION___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___PIXELREGION___H__ - -#include - -namespace openspace::globebrowsing { - -struct PixelRegion { - using PixelCoordinate = glm::ivec2; - using PixelRange = glm::ivec2; - - enum class Side { - LEFT = 0, - TOP, - RIGHT, - BOTTOM - }; - - PixelRegion(const PixelCoordinate& pixelStart = PixelCoordinate(0, 0), - const PixelRange& numberOfPixels = PixelRange(0, 0)); - PixelRegion(const PixelRegion& o) = default; - - /** - * Sets one of the sides of the pixel region the specified position. This changes - * the number of pixels in the region. - * - * Example: side = LEFT and pos 16: - * set start.x = 16 and keep the end position the same. - */ - void setSide(Side side, int pos); - void setLeft(int x); - void setTop(int p); - void setRight(int x); - void setBottom(int y); - - /** - * Aligns one the sides of the pixel regino to the specified position. This does - * not change the number of pixels within the region. - * - * Example: Side = left and pos = 16: - * start.x = 16 and keep the size the same - */ - void align(Side side, int pos); - void alignLeft(int x); - void alignTop(int y); - void alignRight(int x); - void alignBottom(int y); - - 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 move(Side side, int amount); - void pad(const PixelRegion& padding); - void clampTo(const PixelRegion& boundingRegion); - - void forceNumPixelToDifferByNearestMultipleOf(unsigned int multiple); - void roundUpNumPixelToNearestMultipleOf(unsigned int multiple); - void roundDownToQuadratic(); - - PixelRegion globalCut(Side side, int globalPos); - PixelRegion localCut(Side side, int localPos); - - int area() const; - int edge(Side side) const; - int edgeDirectionSign(Side side) const; - PixelCoordinate end() const; - - bool lineIntersect(Side side, int p); - bool isInside(const PixelRegion& r) const; - bool equals(const PixelRegion& r) const; - - PixelCoordinate start; - PixelRange numPixels; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PIXELREGION___H__ diff --git a/modules/globebrowsing/tile/quad.h b/modules/globebrowsing/tile/quad.h deleted file mode 100644 index c8b2e38bfd..0000000000 --- a/modules/globebrowsing/tile/quad.h +++ /dev/null @@ -1,42 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___QUAD___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___QUAD___H__ - -namespace openspace { -namespace globebrowsing { - -enum Quad { - NORTH_WEST = 0, - NORTH_EAST, - SOUTH_WEST, - SOUTH_EAST -}; - - -} // namespace globebrowsing -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___QUAD___H__ diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp b/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp deleted file mode 100644 index ed8ca6dc7b..0000000000 --- a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifdef GLOBEBROWSING_USE_GDAL - -#include - -#include -#include - -#ifdef _MSC_VER -#pragma warning (push) - // CPL throws warning about missing DLL interface -#pragma warning (disable : 4251) -#endif // _MSC_VER - -#include -#include -#include - -#include - -#ifdef _MSC_VER -#pragma warning (pop) -#endif // _MSC_VER - -#include - -namespace openspace::globebrowsing { - -GdalRawTileDataReader::GdalRawTileDataReader(const std::string& filePath, - const TileTextureInitData& initData, - RawTileDataReader::PerformPreprocessing preprocess) - : RawTileDataReader(initData, preprocess) -{ - _datasetFilePath = filePath; - - { - std::lock_guard lockGuard(_datasetLock); - initialize(); - } -} - -GdalRawTileDataReader::~GdalRawTileDataReader() { - std::lock_guard lockGuard(_datasetLock); - if (_dataset) { - GDALClose(_dataset); - _dataset = nullptr; - } -} - -void GdalRawTileDataReader::reset() { - std::lock_guard lockGuard(_datasetLock); - _cached._maxLevel = -1; - if (_dataset) { - GDALClose(_dataset); - _dataset = nullptr; - } - initialize(); -} - -int GdalRawTileDataReader::maxChunkLevel() const { - return _cached._maxLevel; -} - -float GdalRawTileDataReader::noDataValueAsFloat() const { - return _gdalDatasetMetaDataCached.noDataValue; -} - -int GdalRawTileDataReader::rasterXSize() const { - return _gdalDatasetMetaDataCached.rasterXSize; -} - -int GdalRawTileDataReader::rasterYSize() const { - return _gdalDatasetMetaDataCached.rasterYSize; -} - -int GdalRawTileDataReader::dataSourceNumRasters() const { - return _gdalDatasetMetaDataCached.rasterCount; -} - -float GdalRawTileDataReader::depthOffset() const { - return _gdalDatasetMetaDataCached.offset; -} - -float GdalRawTileDataReader::depthScale() const { - return _gdalDatasetMetaDataCached.scale; -} - -std::array GdalRawTileDataReader::geoTransform() const { - return _gdalDatasetMetaDataCached.padfTransform; -} - -void GdalRawTileDataReader::initialize() { - if (_datasetFilePath.empty()) { - throw ghoul::RuntimeError("File path must not be empty"); - } - _dataset = openGdalDataset(_datasetFilePath); - if (!_dataset) { - throw ghoul::RuntimeError("Failed to load dataset: " + _datasetFilePath); - } - - // Assume all raster bands have the same data type - _gdalDatasetMetaDataCached.rasterCount = _dataset->GetRasterCount(); - _gdalDatasetMetaDataCached.scale = static_cast( - _dataset->GetRasterBand(1)->GetScale() - ); - _gdalDatasetMetaDataCached.offset = static_cast( - _dataset->GetRasterBand(1)->GetOffset() - ); - _gdalDatasetMetaDataCached.rasterXSize = _dataset->GetRasterXSize(); - _gdalDatasetMetaDataCached.rasterYSize = _dataset->GetRasterYSize(); - _gdalDatasetMetaDataCached.noDataValue = static_cast( - _dataset->GetRasterBand(1)->GetNoDataValue() - ); - _gdalDatasetMetaDataCached.dataType = tiledatatype::getGdalDataType( - _initData.glType() - ); - - CPLErr err = _dataset->GetGeoTransform(&_gdalDatasetMetaDataCached.padfTransform[0]); - if (err == CE_Failure) { - _gdalDatasetMetaDataCached.padfTransform = RawTileDataReader::geoTransform(); - } - - _depthTransform = calculateTileDepthTransform(); - _cached._tileLevelDifference = calculateTileLevelDifference( - _initData.dimensions().x - ); - - const int numOverviews = _dataset->GetRasterBand(1)->GetOverviewCount(); - _cached._maxLevel = static_cast(-_cached._tileLevelDifference); - if (numOverviews > 0) { - _cached._maxLevel += numOverviews - 1; - } - _cached._maxLevel = std::max(_cached._maxLevel, 2); -} - -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" - ); - - const PixelRegion::PixelCoordinate end = io.write.region.end(); - [[maybe_unused]] const size_t largestIndex = - (end.y - 1) * io.write.bytesPerLine + (end.x - 1) * _initData.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 * _initData.bytesPerPixel(); - - GDALRasterBand* gdalRasterBand = _dataset->GetRasterBand(rasterBand); - CPLErr readError = CE_Failure; - readError = gdalRasterBand->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 - _gdalDatasetMetaDataCached.dataType, // Type - static_cast(_initData.bytesPerPixel()), // Pixel spacing - -static_cast(io.write.bytesPerLine) // Line spacing - ); - - // Convert error to RawTile::ReadError - switch (readError) { - case CE_None: return RawTile::ReadError::None; - case CE_Debug: return RawTile::ReadError::Debug; - case CE_Warning: return RawTile::ReadError::Warning; - case CE_Failure: return RawTile::ReadError::Failure; - case CE_Fatal: return RawTile::ReadError::Fatal; - default: return RawTile::ReadError::Failure; - } -} - -GDALDataset* GdalRawTileDataReader::openGdalDataset(const std::string& filePath) { - return static_cast(GDALOpen(filePath.c_str(), GA_ReadOnly)); -} - -int GdalRawTileDataReader::calculateTileLevelDifference(int minimumPixelSize) const { - GDALRasterBand* firstBand = _dataset->GetRasterBand(1); - GDALRasterBand* maxOverview; - int numOverviews = firstBand->GetOverviewCount(); - if (numOverviews <= 0) { // No overviews. Use first band. - maxOverview = firstBand; - } - else { // Pick the highest overview. - maxOverview = firstBand->GetOverview(numOverviews - 1); - } - const int sizeLevel0 = maxOverview->GetXSize(); - const double diff = log2(minimumPixelSize) - log2(sizeLevel0); - return static_cast(diff); -} - -} // namespace openspace::globebrowsing - -#endif // GLOBEBROWSING_USE_GDAL diff --git a/modules/globebrowsing/tile/rawtiledatareader/iodescription.cpp b/modules/globebrowsing/tile/rawtiledatareader/iodescription.cpp deleted file mode 100644 index e0695493a8..0000000000 --- a/modules/globebrowsing/tile/rawtiledatareader/iodescription.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include - -namespace openspace::globebrowsing { - -IODescription IODescription::cut(PixelRegion::Side side, int pos) { - const PixelRegion readPreCut = read.region; - const PixelRegion writePreCut = write.region; - - glm::dvec2 ratio = { - write.region.numPixels.x / static_cast(read.region.numPixels.x), - 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 openspace::globebrowsing diff --git a/modules/globebrowsing/tile/rawtiledatareader/iodescription.h b/modules/globebrowsing/tile/rawtiledatareader/iodescription.h deleted file mode 100644 index ab4b757136..0000000000 --- a/modules/globebrowsing/tile/rawtiledatareader/iodescription.h +++ /dev/null @@ -1,51 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___IO_DESCRIPTION___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___IO_DESCRIPTION___H__ - -#include -#include - -namespace openspace::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 openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___IO_DESCRIPTION___H__ diff --git a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp deleted file mode 100644 index e545aff7e1..0000000000 --- a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp +++ /dev/null @@ -1,527 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace openspace::globebrowsing { - -RawTileDataReader::RawTileDataReader(const TileTextureInitData& initData, - PerformPreprocessing preprocess) - : _initData(initData) - , _preprocess(preprocess) -{} - -std::shared_ptr RawTileDataReader::defaultTileData() const { - return std::make_shared(RawTile::createDefault(_initData)); -} - -std::shared_ptr RawTileDataReader::readTileData(TileIndex tileIndex, - char* dataDestination, - char* pboMappedDataDestination) const -{ - IODescription io = ioDescription(tileIndex); - RawTile::ReadError worstError = RawTile::ReadError::None; - - // Build the RawTile from the data we querred - std::shared_ptr rawTile = std::make_shared(); - - if (dataDestination && !pboMappedDataDestination) { - // Write only to cpu data destination - std::memset(dataDestination, 255, _initData.totalNumBytes()); - readImageData(io, worstError, dataDestination); - } - else if (!dataDestination && pboMappedDataDestination) { - // Write only to pbo mapped data destination - std::memset(pboMappedDataDestination, 255, _initData.totalNumBytes()); - readImageData(io, worstError, pboMappedDataDestination); - } - else if (dataDestination && pboMappedDataDestination) { - // Write to both data destinations - std::memset(dataDestination, 255, _initData.totalNumBytes()); - readImageData(io, worstError, dataDestination); - size_t numBytes = _initData.totalNumBytes(); - std::memcpy(pboMappedDataDestination, dataDestination, numBytes); - } - else { - ghoul_assert(false, "Need to specify a data destination"); - } - - rawTile->imageData = dataDestination; - rawTile->error = worstError; - rawTile->tileIndex = std::move(tileIndex); - - rawTile->textureInitData = std::make_shared(_initData); - - if (_preprocess) { - rawTile->tileMetaData = getTileMetaData(rawTile, io.write.region); - rawTile->error = std::max(rawTile->error, postProcessErrorCheck(rawTile)); - } - - return rawTile; -} - -void RawTileDataReader::readImageData(IODescription& io, RawTile::ReadError& worstError, - char* imageDataDest) const -{ - io = adjustIODescription(io); - - // Only read the minimum number of rasters - int nRastersToRead = std::min( - dataSourceNumRasters(), - static_cast(_initData.nRasters()) - ); - - switch (_initData.ghoulTextureFormat()) { - case ghoul::opengl::Texture::Format::Red: { - char* dest = imageDataDest; - const RawTile::ReadError err = repeatedRasterRead(1, io, dest); - worstError = std::max(worstError, err); - break; - } - case ghoul::opengl::Texture::Format::RG: - case ghoul::opengl::Texture::Format::RGB: - case ghoul::opengl::Texture::Format::RGBA: { - if (nRastersToRead == 1) { // Grayscale - for (int 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* dest = imageDataDest + (i * _initData.bytesPerDatum()); - const RawTile::ReadError err = repeatedRasterRead(1, io, dest); - worstError = std::max(worstError, err); - } - } - else if (nRastersToRead == 2) { // Grayscale + alpha - for (int 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* dest = imageDataDest + (i * _initData.bytesPerDatum()); - const RawTile::ReadError err = repeatedRasterRead(1, io, dest); - worstError = std::max(worstError, err); - } - // Last read is the alpha channel - char* dest = imageDataDest + (3 * _initData.bytesPerDatum()); - const RawTile::ReadError err = repeatedRasterRead(2, io, dest); - worstError = std::max(worstError, err); - } - else { // Three or more rasters - for (int i = 0; i < nRastersToRead; i++) { - // The final destination pointer is offsetted by one datum byte size - // for every raster (or data channel, i.e. R in RGB) - char* dest = imageDataDest + (i * _initData.bytesPerDatum()); - const RawTile::ReadError err = repeatedRasterRead(i + 1, io, dest); - worstError = std::max(worstError, err); - } - } - break; - } - case ghoul::opengl::Texture::Format::BGR: - case ghoul::opengl::Texture::Format::BGRA: { - if (nRastersToRead == 1) { // Grayscale - for (int 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* dest = imageDataDest + (i * _initData.bytesPerDatum()); - const RawTile::ReadError err = repeatedRasterRead(1, io, dest); - worstError = std::max(worstError, err); - } - } - else if (nRastersToRead == 2) { // Grayscale + alpha - for (int 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* dest = imageDataDest + (i * _initData.bytesPerDatum()); - const RawTile::ReadError err = repeatedRasterRead(1, io, dest); - worstError = std::max(worstError, err); - } - // Last read is the alpha channel - char* dest = imageDataDest + (3 * _initData.bytesPerDatum()); - const RawTile::ReadError err = repeatedRasterRead(2, io, dest); - worstError = std::max(worstError, err); - } - else { // Three or more rasters - for (int i = 0; i < 3 && i < nRastersToRead; i++) { - // The final destination pointer is offsetted by one datum byte size - // for every raster (or data channel, i.e. R in RGB) - char* dest = imageDataDest + (i * _initData.bytesPerDatum()); - const RawTile::ReadError err = repeatedRasterRead(3 - i, io, dest); - worstError = std::max(worstError, err); - } - } - if (nRastersToRead > 3) { // Alpha channel exists - // Last read is the alpha channel - char* dest = imageDataDest + (3 * _initData.bytesPerDatum()); - const RawTile::ReadError err = repeatedRasterRead(4, io, dest); - worstError = std::max(worstError, err); - } - break; - } - default: { - ghoul_assert(false, "Texture format not supported for tiles"); - break; - } - } -} - -IODescription RawTileDataReader::adjustIODescription(const IODescription& io) const { - return io; -} - -IODescription RawTileDataReader::ioDescription(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.dimensions().x, _initData.dimensions().y); - - io.read.overview = 0; - io.read.fullRegion = fullPixelRegion(); - // For correct sampling in dataset, we need to pad the texture tile - - const PixelRegion padding = PixelRegion( - _initData.tilePixelStartOffset(), - _initData.tilePixelSizeDifference() - ); - - PixelRegion scaledPadding = padding; - const double scale = static_cast(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 = _initData.bytesPerLine(); - io.write.totalNumBytes = _initData.totalNumBytes(); - - ghoul_assert( - io.write.region.numPixels.x == io.write.region.numPixels.y, - "Write region must be square" - ); - ghoul_assert( - io.write.region.numPixels.x == _initData.dimensions().x, - "Write region must match tile it writes to." - ); - - return io; -} - -const TileDepthTransform& RawTileDataReader::depthTransform() const { - return _depthTransform; -} - -const TileTextureInitData& RawTileDataReader::tileTextureInitData() const { - return _initData; -} - -const PixelRegion::PixelRange RawTileDataReader::fullPixelSize() const { - return glm::uvec2(geodeticToPixel(Geodetic2(90, 180))); -} - -PixelRegion RawTileDataReader::fullPixelRegion() const { - return { { 0, 0 }, { rasterXSize(), rasterYSize() } }; -} - -std::array RawTileDataReader::geoTransform() const { - GeodeticPatch cov( - Geodetic2(0,0), - Geodetic2(glm::half_pi(), glm::pi()) - ); - return { - Angle::fromRadians(cov.corner(Quad::NORTH_WEST).lon).asDegrees(), - Angle::fromRadians(cov.size().lon).asDegrees() / rasterXSize(), - 0.0, - Angle::fromRadians(cov.corner(Quad::NORTH_WEST).lat).asDegrees(), - 0.0, - -Angle::fromRadians(cov.size().lat).asDegrees() / rasterYSize() - }; -} - -PixelRegion::PixelCoordinate RawTileDataReader::geodeticToPixel( - const Geodetic2& geo) const -{ - const std::array& t = geoTransform(); - - const double Y = Angle::fromRadians(geo.lat).asDegrees(); - const double X = Angle::fromRadians(geo.lon).asDegrees(); - - const double divisor = t[2] * t[4] - t[1] * t[5]; - ghoul_assert(divisor != 0.0, "Division by zero!"); - - const double P = (t[0] * t[5] - t[2] * t[3] + t[2] * Y - t[5] * X) / divisor; - const double L = (-t[0] * t[4] + t[1] * t[3] - t[1] * Y + t[4] * 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 - - [[ maybe_unused ]] const double Xp = t[0] + P * t[1] + L * t[2]; - [[ maybe_unused ]] const double Yp = t[3] + P * t[4] + L * t[5]; - 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 = geoTransform(); - return { - padfTransform[0] + p.x * padfTransform[1] + p.y * padfTransform[2], - padfTransform[3] + p.x * padfTransform[4] + p.y * padfTransform[5] - }; -} - -PixelRegion RawTileDataReader::highestResPixelRegion( - const GeodeticPatch& geodeticPatch) const -{ - const Geodetic2 nwCorner = geodeticPatch.corner(Quad::NORTH_WEST); - const Geodetic2 swCorner = geodeticPatch.corner(Quad::SOUTH_EAST); - const PixelRegion::PixelCoordinate pixelStart = geodeticToPixel(nwCorner); - const 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 -{ - - // 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 - // | | - // +--------------+ - - RawTile::ReadError worstError = RawTile::ReadError::None; - 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 - const 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. - const RawTile::ReadError err = repeatedRasterRead( - rasterBand, - cutoff, - dataDestination, - depth + 1 - ); - - worstError = std::max(worstError, err); - } - } - } - - const 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) const -{ - const size_t bytesPerLine = _initData.bytesPerPixel() * region.numPixels.x; - - std::shared_ptr preprocessData = std::make_shared(); - preprocessData->maxValues.resize(_initData.nRasters()); - preprocessData->minValues.resize(_initData.nRasters()); - preprocessData->hasMissingData.resize(_initData.nRasters()); - - std::vector noDataValues(_initData.nRasters()); - for (size_t raster = 0; raster < _initData.nRasters(); ++raster) { - preprocessData->maxValues[raster] = -FLT_MAX; - preprocessData->minValues[raster] = FLT_MAX; - preprocessData->hasMissingData[raster] = false; - noDataValues[raster] = noDataValueAsFloat(); - } - - bool allIsMissing = true; - for (int y = 0; y < region.numPixels.y; ++y) { - const size_t yi = (region.numPixels.y - 1 - y) * bytesPerLine; - size_t i = 0; - for (int x = 0; x < region.numPixels.x; ++x) { - for (size_t raster = 0; raster < _initData.nRasters(); ++raster) { - const float noDataValue = noDataValueAsFloat(); - const float val = tiledatatype::interpretFloat( - _initData.glType(), - &(rawTile->imageData[yi + i]) - ); - if (val != noDataValue && val == val) { - preprocessData->maxValues[raster] = std::max( - val, - preprocessData->maxValues[raster] - ); - preprocessData->minValues[raster] = std::min( - val, - preprocessData->minValues[raster] - ); - allIsMissing = false; - } - else { - preprocessData->hasMissingData[raster] = true; - float& floatToRewrite = reinterpret_cast( - rawTile->imageData[yi + i] - ); - floatToRewrite = -std::numeric_limits::max(); - } - i += _initData.bytesPerDatum(); - } - } - } - - if (allIsMissing) { - rawTile->error = RawTile::ReadError::Failure; - } - - return preprocessData; -} - -float RawTileDataReader::depthOffset() const { - return 0.f; -} - -float RawTileDataReader::depthScale() const { - return 1.f; -} - -TileDepthTransform RawTileDataReader::calculateTileDepthTransform() { - const bool isFloat = - (_initData.glType() == GL_HALF_FLOAT || - _initData.glType() == GL_FLOAT || - _initData.glType() == GL_DOUBLE); - - const double maximumValue = isFloat ? - 1.f : - tiledatatype::getMaximumValue(_initData.glType()); - - return { - static_cast(depthScale() * maximumValue), - depthOffset() - }; -} - -RawTile::ReadError RawTileDataReader::postProcessErrorCheck( - std::shared_ptr rawTile) const -{ - const float missingDataValue = noDataValueAsFloat(); - - bool hasMissingData = false; - for (size_t c = 0; c < _initData.nRasters(); c++) { - hasMissingData |= rawTile->tileMetaData->maxValues[c] == missingDataValue; - } - - const bool onHighLevel = rawTile->tileIndex.level > 6; - if (hasMissingData && onHighLevel) { - return RawTile::ReadError::Fatal; - } - return RawTile::ReadError::None; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.h b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.h deleted file mode 100644 index e1d87dab5a..0000000000 --- a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.h +++ /dev/null @@ -1,164 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___RAW_TILE_DATA_READER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___RAW_TILE_DATA_READER___H__ - -#include -#include -#include -#include -#include - -namespace openspace::globebrowsing { - -class GeodeticPatch; -struct IODescription; - -class RawTileDataReader { -public: - BooleanType(PerformPreprocessing); - - RawTileDataReader(const TileTextureInitData& initData, - PerformPreprocessing preprocess = PerformPreprocessing::No); - virtual ~RawTileDataReader() = default; - - /** - * Reads data from the current dataset and initializes a RawTile - * which gets returned. - */ - std::shared_ptr readTileData(TileIndex tileIndex, - char* dataDestination, char* pboMappedDataDestination) const; - const TileDepthTransform& depthTransform() const; - const TileTextureInitData& tileTextureInitData() const; - const PixelRegion::PixelRange fullPixelSize() const; - - /** - * \return The maximum chunk level available in the dataset. Should be a value - * between 2 and 31. - */ - virtual int maxChunkLevel() const = 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 int dataSourceNumRasters() const = 0; - virtual float depthOffset() const; - virtual float depthScale() const; - PixelRegion fullPixelRegion() const; - - /** - * Returns a single channeled empty RawTile of size 16 * 16 pixels. - */ - std::shared_ptr defaultTileData() const; - -protected: - /** - * This function should set the variables _cached, - * _dataLayout and _depthTransform. - */ - virtual void initialize() = 0; - - /** - * The function returns a transform to map the pixel coordinates to cover the whole - * geodetic lat long space. - */ - virtual std::array geoTransform() 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. - */ - void readImageData( - IODescription& io, RawTile::ReadError& worstError, char* imageDataDest) const; - - /** - * The default does not affect the IODescription but this function can be used for - * example to flip the y axis. - */ - virtual IODescription adjustIODescription(const IODescription& io) const; - - virtual RawTile::ReadError rasterRead( - int rasterBand, const IODescription& io, char* dst) const = 0; - - IODescription ioDescription(const TileIndex& tileIndex) const; - - /** - * Get the pixel corresponding to a specific position on the globe defined by the - * Geodetic2 coordinate \p geo. If the dataset has overviews the function returns the - * pixel at the lowest overview (highest resolution). - * - * \param geo The position on the globe to convert to pixel space. - * \return 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 \p geodeticPatch is a patch covering an area in geodetic coordinates - * \return 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& fullIO, - char* dataDestination, int depth = 0) const; - - std::shared_ptr getTileMetaData(std::shared_ptr rawTile, - const PixelRegion& region) const; - TileDepthTransform calculateTileDepthTransform(); - RawTile::ReadError postProcessErrorCheck( - std::shared_ptr rawTile) const; - - struct Cached { - int _maxLevel = -1; - double _tileLevelDifference; - } _cached; - const TileTextureInitData _initData; - PerformPreprocessing _preprocess; - TileDepthTransform _depthTransform = { 0.f, 0.f }; -}; - -} // namespace openspace::globebrowsing - -#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 deleted file mode 100644 index cff66060ab..0000000000 --- a/modules/globebrowsing/tile/rawtiledatareader/simplerawtiledatareader.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include - -namespace openspace::globebrowsing { - -SimpleRawTileDataReader::SimpleRawTileDataReader(const std::string& filePath, - const TileTextureInitData& initData, - RawTileDataReader::PerformPreprocessing preprocess) - : RawTileDataReader(initData, preprocess) -{ - _datasetFilePath = filePath; - initialize(); -} - -void SimpleRawTileDataReader::reset() { - initialize(); -} - -int SimpleRawTileDataReader::maxChunkLevel() const { - const float ratio = static_cast(rasterYSize()) / _initData.dimensions().y; - return glm::max(2, 1 + static_cast(glm::log2(ratio))); -} - -float SimpleRawTileDataReader::noDataValueAsFloat() const { - return 0.f; -} - -int SimpleRawTileDataReader::rasterXSize() const { - return _dataTexture->dimensions().x; -} - -int SimpleRawTileDataReader::rasterYSize() const { - return _dataTexture->dimensions().y; -} - -int SimpleRawTileDataReader::dataSourceNumRasters() const { - return _dataTexture->numberOfChannels(); -} - -float SimpleRawTileDataReader::depthOffset() const { - return 0.f; -} - -float SimpleRawTileDataReader::depthScale() const { - return 1.f; -} - -void SimpleRawTileDataReader::initialize() { - _dataTexture = ghoul::io::TextureReader::ref().loadTexture(_datasetFilePath); - if (!_dataTexture) { - throw ghoul::RuntimeError(fmt::format( - "Unable to read dataset: {}. Comping with GDAL allows for better support", - _datasetFilePath - )); - } - _depthTransform = { depthScale(), depthOffset() }; -} - -RawTile::ReadError SimpleRawTileDataReader::rasterRead(int rasterBand, - const IODescription& io, - char* dataDestination) const -{ - [[maybe_unused]] const int nX = io.read.fullRegion.numPixels.x; - [[maybe_unused]] const int nY = io.read.fullRegion.numPixels.y; - ghoul_assert( - static_cast(nX) == _dataTexture->dimensions().x, - "IODescription does not match data texture." - ); - ghoul_assert( - static_cast(nY) == _dataTexture->dimensions().y, - "IODescription does not match data texture." - ); - - char* writeDataStart = dataDestination + - _initData.bytesPerLine() * io.write.region.start.y + - _initData.bytesPerPixel() * io.write.region.start.x; - - for (int y = 0; y < io.write.region.numPixels.y; ++y) { - for (int x = 0; x < io.write.region.numPixels.x; ++x) { - char* pixelWriteDestination = writeDataStart + - y * _initData.bytesPerLine() + - x * _initData.bytesPerPixel(); - - const int xInSrc = static_cast( - io.read.region.start.x + - static_cast(x) / io.write.region.numPixels.x * - io.read.region.numPixels.x - ); - const int yInSrc = static_cast( - io.read.region.start.y + - static_cast(y) / io.write.region.numPixels.y * - io.read.region.numPixels.y - ); - - const glm::vec4 sourceTexel = _dataTexture->texelAsFloat(xInSrc, yInSrc); - - // Different type reinterpreting depending on the type of the target texture - // the _initData.glType() does not necessarily have to be the same type as - // the type of the source texture. Therefore the value is cast to float first. - switch (_initData.glType()) { - case GL_UNSIGNED_BYTE: { - const unsigned char value = static_cast( - sourceTexel[rasterBand - 1] * 255 - ); - *reinterpret_cast(pixelWriteDestination) = value; - break; - } - case GL_BYTE: { - const char value = static_cast( - sourceTexel[rasterBand - 1] * 255 - ); - *pixelWriteDestination = value; - break; - } - case GL_UNSIGNED_SHORT: { - const unsigned short value = static_cast( - sourceTexel[rasterBand - 1] * 65535 - ); - *reinterpret_cast(pixelWriteDestination) = value; - break; - } - case GL_SHORT: { - const short value = static_cast( - sourceTexel[rasterBand - 1] * 65535 - ); - *reinterpret_cast(pixelWriteDestination) = value; - break; - } - case GL_UNSIGNED_INT: { - const unsigned int value = static_cast( - sourceTexel[rasterBand - 1] * 4294967295 - ); - *reinterpret_cast(pixelWriteDestination) = value; - break; - } - case GL_INT: { - const int value = static_cast( - sourceTexel[rasterBand - 1] * 4294967295 - ); - *reinterpret_cast(pixelWriteDestination) = value; - break; - } - case GL_FLOAT: { - const float value = sourceTexel[rasterBand - 1]; - *reinterpret_cast(pixelWriteDestination) = value; - break; - } - default: { - ghoul_assert(false, "Unknown texture type"); - return RawTile::ReadError::Failure; - } - } - } - } - return RawTile::ReadError::None; -} - -IODescription SimpleRawTileDataReader::adjustIODescription(const IODescription& io) const -{ - // 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; - - return modifiedIO; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/rawtiledatareader/simplerawtiledatareader.h b/modules/globebrowsing/tile/rawtiledatareader/simplerawtiledatareader.h deleted file mode 100644 index ec56999451..0000000000 --- a/modules/globebrowsing/tile/rawtiledatareader/simplerawtiledatareader.h +++ /dev/null @@ -1,72 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___SIMPLE_RAW_TILE_DATA_READER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___SIMPLE_RAW_TILE_DATA_READER___H__ - -#include - -#include - -namespace ghoul::opengl { class Texture; } - -namespace openspace::globebrowsing { - -struct IODescription; -class GeodeticPatch; - -class SimpleRawTileDataReader : public RawTileDataReader { -public: - SimpleRawTileDataReader(const std::string& filePath, - const TileTextureInitData& initData, - RawTileDataReader::PerformPreprocessing preprocess = - RawTileDataReader::PerformPreprocessing::No); - - // Public virtual function overloading - virtual void reset() override; - virtual int maxChunkLevel() const override; - virtual float noDataValueAsFloat() const override; - virtual int rasterXSize() const override; - virtual int rasterYSize() const override; - virtual int dataSourceNumRasters() const override; - virtual float depthOffset() const override; - virtual float depthScale() const override; - -protected: - virtual IODescription adjustIODescription(const IODescription& io) const override; - -private: - // Private virtual function overloading - virtual void initialize() override; - virtual RawTile::ReadError rasterRead(int rasterBand, const IODescription& io, - char* dataDestination) const override; - - // Member variables - std::string _datasetFilePath; - std::unique_ptr _dataTexture; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___SIMPLE_RAW_TILE_DATA_READER___H__ diff --git a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp deleted file mode 100644 index 6fbc13f35c..0000000000 --- a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp +++ /dev/null @@ -1,618 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include - -#ifdef GLOBEBROWSING_USE_GDAL -#ifdef _MSC_VER -#pragma warning (push) - // CPL throws warning about missing DLL interface -#pragma warning (disable : 4251) -#endif // _MSC_VER - -#include -#include - -#ifdef _MSC_VER -#pragma warning (pop) -#endif // _MSC_VER - -#endif // GLOBEBROWSING_USE_GDAL - -namespace { - constexpr const char* _loggerCat = "TileDataType"; -} // namespace - -namespace openspace::globebrowsing::tiledatatype { - -#ifdef GLOBEBROWSING_USE_GDAL - -float interpretFloat(GDALDataType gdalType, const char* src) { - switch (gdalType) { - case GDT_Byte: - return static_cast(*reinterpret_cast(src)); - case GDT_UInt16: - return static_cast(*reinterpret_cast(src)); - case GDT_Int16: - return static_cast(*reinterpret_cast(src)); - case GDT_UInt32: - return static_cast(*reinterpret_cast(src)); - case GDT_Int32: - return static_cast(*reinterpret_cast(src)); - case GDT_Float32: - return static_cast(*reinterpret_cast(src)); - case GDT_Float64: - return static_cast(*reinterpret_cast(src)); - default: - ghoul_assert(false, "Unknown data type"); - throw ghoul::MissingCaseException(); - } -} - -size_t numberOfBytes(GDALDataType gdalType) { - switch (gdalType) { - case GDT_Byte: - return sizeof(GLubyte); - case GDT_UInt16: - return sizeof(GLushort); - case GDT_Int16: - return sizeof(GLshort); - case GDT_UInt32: - return sizeof(GLuint); - case GDT_Int32: - return sizeof(GLint); - case GDT_Float32: - return sizeof(GLfloat); - case GDT_Float64: - return sizeof(GLdouble); - default: - ghoul_assert(false, "Unknown data type"); - throw ghoul::MissingCaseException(); - } -} - -size_t getMaximumValue(GDALDataType gdalType) { - switch (gdalType) { - case GDT_Byte: - return 1ULL << 8ULL; - case GDT_UInt16: - return 1ULL << 16ULL; - case GDT_Int16: - return 1ULL << 15ULL; - case GDT_UInt32: - return size_t(1) << 32ULL; - case GDT_Int32: - return 1ULL << 31ULL; - default: - ghoul_assert(false, "Unknown data type"); - throw ghoul::MissingCaseException(); - } -} - -TextureFormat getTextureFormat(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(fmt::format("GDAL data type unknown to OpenGL: {}", gdalType)); - throw ghoul::MissingCaseException(); - } - 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(fmt::format("GDAL data type unknown to OpenGL: {}", gdalType)); - throw ghoul::MissingCaseException(); - } - break; - case 3: - format.ghoulFormat = ghoul::opengl::Texture::Format::RGB; - 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(fmt::format("GDAL data type unknown to OpenGL: {}", gdalType)); - throw ghoul::MissingCaseException(); - } - break; - case 4: - format.ghoulFormat = ghoul::opengl::Texture::Format::RGBA; - 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(fmt::format("GDAL data type unknown to OpenGL: {}", gdalType)); - throw ghoul::MissingCaseException(); - } - break; - default: - LERROR(fmt::format( - "Unknown number of channels for OpenGL texture: {}", - rasterCount - )); - throw ghoul::MissingCaseException(); - } - 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(fmt::format("GDAL data type unknown to OpenGL: {}", gdalType)); - throw ghoul::MissingCaseException(); - } - 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(fmt::format("GDAL data type unknown to OpenGL: {}", gdalType)); - throw ghoul::MissingCaseException(); - } - 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(fmt::format("GDAL data type unknown to OpenGL: {}", gdalType)); - throw ghoul::MissingCaseException(); - } - 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(fmt::format("GDAL data type unknown to OpenGL: {}", gdalType)); - throw ghoul::MissingCaseException(); - } - break; - default: - LERROR(fmt::format("GDAL data type unknown to OpenGL: {}", gdalType)); - throw ghoul::MissingCaseException(); - } - return format; -} - -GLenum getOpenGLDataType(GDALDataType gdalType) { - switch (gdalType) { - case GDT_Byte: - return GL_UNSIGNED_BYTE; - case GDT_UInt16: - return GL_UNSIGNED_SHORT; - case GDT_Int16: - return GL_SHORT; - case GDT_UInt32: - return GL_UNSIGNED_INT; - case GDT_Int32: - return GL_INT; - case GDT_Float32: - return GL_FLOAT; - case GDT_Float64: - return GL_DOUBLE; - default: - LERROR(fmt::format("GDAL data type unknown to OpenGL: {}", gdalType)); - throw ghoul::MissingCaseException(); - } -} - -GDALDataType getGdalDataType(GLenum glType) { - switch (glType) { - case GL_UNSIGNED_BYTE: - return GDT_Byte; - case GL_UNSIGNED_SHORT: - return GDT_UInt16; - case GL_SHORT: - return GDT_Int16; - case GL_UNSIGNED_INT: - return GDT_UInt32; - case GL_INT: - return GDT_Int32; - case GL_FLOAT: - return GDT_Float32; - case GL_DOUBLE: - return GDT_Float64; - default: - LERROR(fmt::format( - "OpenGL data type unknown to GDAL: {}", static_cast(glType) - )); - throw ghoul::MissingCaseException(); - } -} - -#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: - case ghoul::opengl::Texture::Format::BGR: - return 3; - case ghoul::opengl::Texture::Format::RGBA: - case ghoul::opengl::Texture::Format::BGRA: - return 4; - default: { - ghoul_assert(false, "Unknown format"); - throw ghoul::MissingCaseException(); - } - } -} - -size_t numberOfBytes(GLenum glType) { - switch (glType) { - case GL_UNSIGNED_BYTE: return sizeof(GLubyte); - case GL_BYTE: return sizeof(GLbyte); - 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_HALF_FLOAT: return sizeof(GLhalf); - case GL_FLOAT: return sizeof(GLfloat); - case GL_DOUBLE: return sizeof(GLdouble); - default: - ghoul_assert(false, "Unknown data type"); - throw ghoul::MissingCaseException(); - } -} - -size_t getMaximumValue(GLenum glType) { - switch (glType) { - case GL_UNSIGNED_BYTE: return 1ULL << 8ULL; - case GL_UNSIGNED_SHORT: return 1ULL << 16ULL; - case GL_SHORT: return 1ULL << 15ULL; - case GL_UNSIGNED_INT: return 1ULL << 32ULL; - case GL_INT: return 1ULL << 31ULL; - default: - ghoul_assert(false, "Unknown data type"); - throw ghoul::MissingCaseException(); - } -} - -float interpretFloat(GLenum 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_HALF_FLOAT: - 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"); - throw ghoul::MissingCaseException(); - } -} - -GLenum glTextureFormat(GLenum glType, ghoul::opengl::Texture::Format format) { - switch (format) { - case ghoul::opengl::Texture::Format::Red: - switch (glType) { - case GL_BYTE: - return GL_R8; - case GL_UNSIGNED_BYTE: - return GL_R8; - case GL_INT: - return GL_R32I; - case GL_UNSIGNED_INT: - return GL_R32UI; - case GL_FLOAT: - return GL_R32F; - case GL_HALF_FLOAT: - return GL_R16F; - default: - ghoul_assert(false, "glType data type unknown"); - throw ghoul::MissingCaseException(); - } - case ghoul::opengl::Texture::Format::RG: - switch (glType) { - case GL_BYTE: - return GL_RG8; - case GL_UNSIGNED_BYTE: - return GL_RG8; - case GL_INT: - return GL_RG32I; - case GL_UNSIGNED_INT: - return GL_RG32UI; - case GL_FLOAT: - return GL_RG32F; - case GL_HALF_FLOAT: - return GL_RG16F; - default: - ghoul_assert(false, "glType data type unknown"); - throw ghoul::MissingCaseException(); - } - case ghoul::opengl::Texture::Format::RGB: - switch (glType) { - case GL_BYTE: - return GL_RGB8; - case GL_UNSIGNED_BYTE: - return GL_RGB8; - case GL_INT: - return GL_RGB32I; - case GL_UNSIGNED_INT: - return GL_RGB32UI; - case GL_FLOAT: - return GL_RGB32F; - case GL_HALF_FLOAT: - return GL_RGB16F; - default: - ghoul_assert(false, "glType data type unknown"); - throw ghoul::MissingCaseException(); - } - case ghoul::opengl::Texture::Format::RGBA: - switch (glType) { - case GL_BYTE: - return GL_RGBA8; - case GL_UNSIGNED_BYTE: - return GL_RGBA8; - case GL_INT: - return GL_RGBA32I; - case GL_UNSIGNED_INT: - return GL_RGBA32UI; - case GL_FLOAT: - return GL_RGBA32F; - case GL_HALF_FLOAT: - return GL_RGBA16F; - default: - ghoul_assert(false, "glType data type unknown"); - throw ghoul::MissingCaseException(); - } - case ghoul::opengl::Texture::Format::BGR: - switch (glType) { - case GL_BYTE: - return GL_RGB8; - case GL_UNSIGNED_BYTE: - return GL_RGB8; - case GL_INT: - return GL_RGB32I; - case GL_UNSIGNED_INT: - return GL_RGB32UI; - case GL_FLOAT: - return GL_RGB32F; - case GL_HALF_FLOAT: - return GL_RGB16F; - default: - ghoul_assert(false, "glType data type unknown"); - throw ghoul::MissingCaseException(); - } - case ghoul::opengl::Texture::Format::BGRA: - switch (glType) { - case GL_BYTE: - return GL_RGBA8; - case GL_UNSIGNED_BYTE: - return GL_RGBA8; - case GL_INT: - return GL_RGBA32I; - case GL_UNSIGNED_INT: - return GL_RGBA32UI; - case GL_FLOAT: - return GL_RGBA32F; - case GL_HALF_FLOAT: - return GL_RGBA16F; - default: - ghoul_assert(false, "glType data type unknown"); - throw ghoul::MissingCaseException(); - } - default: - ghoul_assert(false, "Unknown format for OpenGL texture"); - throw ghoul::MissingCaseException(); - } -} - -} // namespace openspace::globebrowsing::tiledatatype diff --git a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h deleted file mode 100644 index d7f63f65e1..0000000000 --- a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h +++ /dev/null @@ -1,68 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ - -#include - -#include - -#ifdef GLOBEBROWSING_USE_GDAL -#include -#endif // GLOBEBROWSING_USE_GDAL - -namespace openspace::globebrowsing { class Tile; } - -namespace openspace::globebrowsing::tiledatatype { - -#ifdef GLOBEBROWSING_USE_GDAL -GLenum getOpenGLDataType(GDALDataType gdalType); - -GDALDataType getGdalDataType(GLenum 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 - -GLenum glTextureFormat(GLenum glType, ghoul::opengl::Texture::Format format); - -size_t numberOfRasters(ghoul::opengl::Texture::Format format); - -size_t numberOfBytes(GLenum glType); - -size_t getMaximumValue(GLenum glType); - -float interpretFloat(GLenum glType, const char* src); - -} // namespace openspace::globebrowsing::tiledatatype - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ diff --git a/modules/globebrowsing/tile/textureformat.h b/modules/globebrowsing/tile/textureformat.h deleted file mode 100644 index abac87466a..0000000000 --- a/modules/globebrowsing/tile/textureformat.h +++ /dev/null @@ -1,39 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ - -#include - -namespace openspace::globebrowsing { - -struct TextureFormat { - ghoul::opengl::Texture::Format ghoulFormat; - GLenum glFormat; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ diff --git a/modules/globebrowsing/tile/tile.cpp b/modules/globebrowsing/tile/tile.cpp deleted file mode 100644 index 42cc580b41..0000000000 --- a/modules/globebrowsing/tile/tile.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include - -namespace openspace::globebrowsing { - -const Tile Tile::TileUnavailable(nullptr, nullptr, Tile::Status::Unavailable); - -Tile::Tile(ghoul::opengl::Texture* texture, std::shared_ptr metaData, - Status status) - : _texture(texture) - , _metaData(std::move(metaData)) - , _status(status) -{} - -TileMetaData* Tile::metaData() const { - return _metaData.get(); -} - -Tile::Status Tile::status() const { - return _status; -} - -ghoul::opengl::Texture* Tile::texture() const { - return _texture; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/tiledepthtransform.h b/modules/globebrowsing/tile/tiledepthtransform.h deleted file mode 100644 index c81d1fa093..0000000000 --- a/modules/globebrowsing/tile/tiledepthtransform.h +++ /dev/null @@ -1,37 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEDEPTHTRANSFORM___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEDEPTHTRANSFORM___H__ - -namespace openspace::globebrowsing { - -struct TileDepthTransform { - float depthScale; - float depthOffset; -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEDEPTHTRANSFORM___H__ diff --git a/modules/globebrowsing/tile/tileindex.cpp b/modules/globebrowsing/tile/tileindex.cpp deleted file mode 100644 index 4bea38b766..0000000000 --- a/modules/globebrowsing/tile/tileindex.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -#include - -#include - -namespace { - constexpr const char* KeyLevel = "Level"; - constexpr const char* KeyX = "X"; - constexpr const char* KeyY = "Y"; -} // namespace - -namespace openspace::globebrowsing { - -TileIndex::TileIndex(int x_, int y_, int level_) - : x(x_) - , y(y_) - , level(level_) -{} - -TileIndex::TileIndex(const Geodetic2& point, int level_) - : level(level_) -{ - const int numIndicesAtLevel = 1 << level; - const double u = 0.5 + point.lon / glm::two_pi(); - const double v = 0.25 - point.lat / glm::two_pi(); - const double xIndexSpace = u * numIndicesAtLevel; - const double yIndexSpace = v * numIndicesAtLevel; - - x = static_cast(floor(xIndexSpace)); - y = static_cast(floor(yIndexSpace)); -} - -TileIndex::TileIndex(const ghoul::Dictionary& dict) { - level = static_cast(dict.value(KeyLevel)); - x = static_cast(dict.value(KeyX)); - y = static_cast(dict.value(KeyY)); -} - -TileIndex TileIndex::child(Quad q) const { - return TileIndex(2 * x + q % 2, 2 * y + q / 2, level + 1); -} - -bool TileIndex::hasParent() const { - return level > 0; -} - -TileIndex TileIndex::parent() const { - //ghoul_assert(level > 0, "tile at level 0 has no parent!"); - return TileIndex(x / 2, y / 2, level - 1); -} - -bool TileIndex::isWestChild() const { - return x % 2 == 0; -} - -bool TileIndex::isEastChild() const { - return x % 2 == 1; -} - -bool TileIndex::isNorthChild() const { - return y % 2 == 0; -} - -bool TileIndex::isSouthChild() const { - return y % 2 == 1; -} - -bool TileIndex::operator==(const TileIndex& other) const { - return (x == other.x) && (y == other.y) && (level == other.level); -} - -TileIndex& TileIndex::operator--() { - x /= 2; - y /= 2; - level--; - - return *this; -} - -TileIndex TileIndex::operator--(int) { - TileIndex tmp(*this); - --(*this); - - return tmp; -} - -TileIndex& TileIndex::operator-=(unsigned int levels) { - x <<= levels; - y <<= levels; - level -= levels; - - return *this; -} - -glm::vec2 TileIndex::positionRelativeParent() const { - // In OpenGL, positive y direction is up - return glm::vec2(isEastChild() ? 0.5f : 0.f, isNorthChild() ? 0.5f : 0.f); -} - -TileIndex TileIndex::relatedTile(int deltaX, int deltaY) const { - int indicesAtThisLevel = 1 << level; - int newX = (indicesAtThisLevel + x + deltaX) % indicesAtThisLevel; - int newY = (indicesAtThisLevel + y + deltaY) % indicesAtThisLevel; - return TileIndex(newX, newY, level); -} - -int TileIndex::manhattan(const TileIndex& other) const { - ghoul_assert(level == other.level, "makes no sense if not on same level"); - - return std::abs(x - other.x) + std::abs(y - other.y); -} - -// Creates a hash which can be used as key in hash maps. -// -// +-------+------------+-------+------------+ -// | USAGE | BIT RANGE | #BITS | MAX VALUE | -// +-------+------------+-------+------------+ -// | level | 0 - 5 | 5 | 31 | -// | x | 5 - 35 | 30 | 1073741824 | -// | y | 35 - 64 | 29 | 536870912 | -// +-------+------------+-------+------------+ - -TileIndex::TileHashKey TileIndex::hashKey() const { - TileHashKey key = 0LL; - key |= level; - key |= x << 5; - key |= static_cast(y) << 35; - - return key; -} - -std::string TileIndex::toString() const { - std::stringstream ss; - for (int i = level; i > 0; i--) { - char digit = '0'; - int mask = 1 << (i - 1); - if ((x & mask) != 0) { - digit++; - } - if ((y & mask) != 0) { - digit++; - digit++; - } - ss << digit; - } - return ss.str(); -} - -std::ostream& operator<<(std::ostream& os, const TileIndex& ti) { - os << "{ x = " << ti.x << ", y = " << ti.y << ", level = " << ti.level << " }"; - return os; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/tileindex.h b/modules/globebrowsing/tile/tileindex.h deleted file mode 100644 index 24846dccda..0000000000 --- a/modules/globebrowsing/tile/tileindex.h +++ /dev/null @@ -1,104 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_INDEX___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_INDEX___H__ - -#include - -#include -#include - -namespace ghoul { class Dictionary; } - -namespace openspace::globebrowsing { - -struct Geodetic2; - -enum CardinalDirection { - WEST = 0, - EAST, - NORTH, - SOUTH, -}; - -struct TileIndex { - using TileHashKey = uint64_t; - - int x, y, level; - - TileIndex(int x_ = 0, int y_ = 0, int level_ = 0); - TileIndex(const TileIndex& other) = default; - - /** - * Creates the geodetic tile index for the Geodetic patch that covers the - * point p at the specified level - */ - TileIndex(const Geodetic2& point, int level_); - - /** - * Initializes a TileIndex from a Dictionary - */ - TileIndex(const ghoul::Dictionary& dict); - - - bool hasParent() const; - - TileIndex parent() const; - - bool operator==(const TileIndex& other) const; - - TileIndex& operator--(); - TileIndex operator--(int); - - TileIndex& operator-=(unsigned int levels); - - bool isWestChild() const; - bool isEastChild() const; - bool isNorthChild() const; - bool isSouthChild() const; - - TileIndex child(Quad q) const; - - glm::vec2 positionRelativeParent() const; - - - std::string toString() const; - - /** - * Gets the tile at a specified offset from this tile. - * Accepts delta indices ranging from [-2^level, Infinity[ - */ - TileIndex relatedTile(int deltaX, int deltaY) const; - - int manhattan(const TileIndex& other) const; - - TileHashKey hashKey() const; -}; - -std::ostream& operator<<(std::ostream& os, const TileIndex& ti); - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_INDEX___H__ diff --git a/modules/globebrowsing/tile/tileloadjob.cpp b/modules/globebrowsing/tile/tileloadjob.cpp deleted file mode 100644 index 85573d77c5..0000000000 --- a/modules/globebrowsing/tile/tileloadjob.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace openspace::globebrowsing { - -TileLoadJob::TileLoadJob(std::shared_ptr rawTileDataReader, - const TileIndex& tileIndex) - : _rawTileDataReader(std::move(rawTileDataReader)) - , _chunkIndex(tileIndex) -{} - - -TileLoadJob::TileLoadJob(std::shared_ptr rawTileDataReader, - const TileIndex& tileIndex, char* pboDataPtr) - : _rawTileDataReader(std::move(rawTileDataReader)) - , _chunkIndex(tileIndex) - , _pboMappedDataDestination(pboDataPtr) -{} - -TileLoadJob::~TileLoadJob() { - if (_hasOwnershipOfData) { - ghoul_assert(_rawTile->imageData, "Image data must exist"); - - delete[] _rawTile->imageData; - } -} - -void TileLoadJob::execute() { - size_t numBytes = _rawTileDataReader->tileTextureInitData().totalNumBytes(); - char* dataPtr = nullptr; - if (_rawTileDataReader->tileTextureInitData().shouldAllocateDataOnCPU() || - !_pboMappedDataDestination) - { - dataPtr = new char[numBytes]; - _hasOwnershipOfData = true; - } - _rawTile = _rawTileDataReader->readTileData( - _chunkIndex, - dataPtr, - _pboMappedDataDestination - ); -} - -std::shared_ptr TileLoadJob::product() { - _hasOwnershipOfData = false; - return _rawTile; -} - -bool TileLoadJob::hasOwnershipOfData() const { - return _hasOwnershipOfData; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/tilemetadata.cpp b/modules/globebrowsing/tile/tilemetadata.cpp deleted file mode 100644 index 793d3d2a97..0000000000 --- a/modules/globebrowsing/tile/tilemetadata.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace openspace::globebrowsing { - -void TileMetaData::serialize(std::ostream& os) { - os << maxValues.size() << std::endl; - for (float f : maxValues) { - os << f << " "; - } - os << std::endl; - for (float f : minValues) { - os << f << " "; - } - os << std::endl; -} - -TileMetaData TileMetaData::deserialize(std::istream& is) { - TileMetaData res; - int n; - is >> n; - res.maxValues.resize(n); - for (int i = 0; i < n; ++i) { - is >> res.maxValues[i]; - } - res.minValues.resize(n); - for (int i = 0; i < n; ++i) { - is >> res.minValues[i]; - } - - return res; -} - -} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/tile/tilemetadata.h b/modules/globebrowsing/tile/tilemetadata.h deleted file mode 100644 index 79c21fe9f9..0000000000 --- a/modules/globebrowsing/tile/tilemetadata.h +++ /dev/null @@ -1,44 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEMETADATA___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEMETADATA___H__ - -#include -#include - -namespace openspace::globebrowsing { - -struct TileMetaData { - std::vector maxValues; - std::vector minValues; - std::vector hasMissingData; - - void serialize(std::ostream& os); - static TileMetaData deserialize(std::istream& is); -}; - -} // namespace openspace::globebrowsing - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEMETADATA___H__ diff --git a/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp deleted file mode 100644 index d037ff41dd..0000000000 --- a/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - constexpr const char* KeyPerformPreProcessing = "PerformPreProcessing"; - constexpr const char* KeyTilePixelSize = "TilePixelSize"; - constexpr const char* KeyFilePath = "FilePath"; - constexpr const char* KeyPreCacheLevel = "PreCacheLevel"; - constexpr const char* KeyPadTiles = "PadTiles"; - - constexpr openspace::properties::Property::PropertyInfo FilePathInfo = { - "FilePath", - "File Path", - "The path of the GDAL file or the image file that is to be used in this tile " - "provider." - }; - - constexpr openspace::properties::Property::PropertyInfo TilePixelSizeInfo = { - "TilePixelSize", - "Tile Pixel Size", - "This value is the preferred size (in pixels) for each tile. Choosing the right " - "value is a tradeoff between more efficiency (larger images) and better quality " - "(smaller images). The tile pixel size has to be smaller than the size of the " - "complete image if a single image is used." - }; -} - -namespace openspace::globebrowsing::tileprovider { - -DefaultTileProvider::DefaultTileProvider(const ghoul::Dictionary& dictionary) - : TileProvider(dictionary) - , _filePath(FilePathInfo, "") - , _tilePixelSize(TilePixelSizeInfo, 32, 32, 2048) -{ - _tileCache = global::moduleEngine.module()->tileCache(); - _name = "Name unspecified"; - dictionary.getValue("Name", _name); - std::string _loggerCat = "DefaultTileProvider : " + _name; - - // 1. Get required Keys - _filePath = dictionary.value(KeyFilePath); - - if (!dictionary.getValue("LayerGroupID", _layerGroupID)) { - ghoul_assert(false, "Unknown layer group id"); - } - - // 2. Initialize default values for any optional Keys - // getValue does not work for integers - double pixelSize = 0.0; - int tilePixelSize = 0; - if (dictionary.getValue(KeyTilePixelSize, pixelSize)) { - LDEBUG(fmt::format("Default pixel size overridden: {}", pixelSize)); - tilePixelSize = static_cast(pixelSize); - } - - dictionary.getValue(KeyPadTiles, _padTiles); - - TileTextureInitData initData(LayerManager::getTileTextureInitData( - _layerGroupID, - LayerManager::PadTiles(_padTiles), - tilePixelSize - )); - _tilePixelSize = initData.dimensions().x; - - _performPreProcessing = LayerManager::shouldPerformPreProcessingOnLayergroup( - _layerGroupID - ); - if (dictionary.getValue(KeyPerformPreProcessing, _performPreProcessing)) { - LDEBUG(fmt::format( - "Default PerformPreProcessing overridden: {}", _performPreProcessing - )); - } - - if (dictionary.hasKeyAndValue(KeyPreCacheLevel)) { - _preCacheLevel = static_cast(dictionary.value(KeyPreCacheLevel)); - } - - initAsyncTileDataReader(initData); - - // Properties - addProperty(_filePath); - addProperty(_tilePixelSize); -} - -DefaultTileProvider::DefaultTileProvider(std::shared_ptr reader) - : _asyncTextureDataProvider(std::move(reader)) - , _filePath(FilePathInfo, "") - , _tilePixelSize(TilePixelSizeInfo, 32, 32, 2048) -{} - -DefaultTileProvider::~DefaultTileProvider() {} // NOLINT - -void DefaultTileProvider::update() { - if (_asyncTextureDataProvider) { - _asyncTextureDataProvider->update(); - initTexturesFromLoadedData(); - if (_asyncTextureDataProvider->shouldBeDeleted()) { - _asyncTextureDataProvider = nullptr; - TileTextureInitData initData(LayerManager::getTileTextureInitData( - _layerGroupID, - LayerManager::PadTiles(_padTiles), - _tilePixelSize - )); - initAsyncTileDataReader(initData); - } - } -} - -void DefaultTileProvider::reset() { - _tileCache->clear(); - if (_asyncTextureDataProvider) { - _asyncTextureDataProvider->prepairToBeDeleted(); - } - else { - TileTextureInitData initData(LayerManager::getTileTextureInitData( - _layerGroupID, - LayerManager::PadTiles(_padTiles), - _tilePixelSize - )); - initAsyncTileDataReader(initData); - } -} - -int DefaultTileProvider::maxLevel() { - if (_asyncTextureDataProvider) { - return _asyncTextureDataProvider->rawTileDataReader()->maxChunkLevel(); - } - else { - // Current theoretical maximum based on the number of hashes that are possible - // to uniquely identify a tile. See ProviderTileHasher in memoryawaretilecache.h - return 22; - } -} - -Tile DefaultTileProvider::tile(const TileIndex& tileIndex) { - if (_asyncTextureDataProvider) { - if (tileIndex.level > maxLevel()) { - return Tile(nullptr, nullptr, Tile::Status::OutOfRange); - } - - const cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; - - const Tile tile = _tileCache->get(key); - - if (!tile.texture()) { - _asyncTextureDataProvider->enqueueTileIO(tileIndex); - } - - return tile; - } - else { - return Tile(nullptr, nullptr, Tile::Status::Unavailable); - } -} - -float DefaultTileProvider::noDataValueAsFloat() { - if (_asyncTextureDataProvider) { - return _asyncTextureDataProvider->noDataValueAsFloat(); - } - else { - return std::numeric_limits::min(); - } -} - -void DefaultTileProvider::initTexturesFromLoadedData() { - if (_asyncTextureDataProvider) { - std::shared_ptr tile = _asyncTextureDataProvider->popFinishedRawTile(); - if (tile) { - const cache::ProviderTileKey key = { tile->tileIndex, uniqueIdentifier() }; - ghoul_assert(!_tileCache->exist(key), "Tile must not be existing in cache"); - _tileCache->createTileAndPut(key, *tile); - } - } -} - -void DefaultTileProvider::initAsyncTileDataReader(TileTextureInitData initData) { - const std::string _loggerCat = "DefaultTileProvider : " + _name; - - RawTileDataReader::PerformPreprocessing preprocess = - _performPreProcessing ? RawTileDataReader::PerformPreprocessing::Yes : - RawTileDataReader::PerformPreprocessing::No; - - // Initialize instance variables -#ifdef GLOBEBROWSING_USE_GDAL - std::shared_ptr tileDataset = - std::make_shared(_filePath, initData, preprocess); -#else // GLOBEBROWSING_USE_GDAL - std::shared_ptr tileDataset = - std::make_shared(_filePath, initData, preprocess); -#endif // GLOBEBROWSING_USE_GDAL - - _asyncTextureDataProvider = std::make_shared( - _name, - tileDataset - ); - - // Tiles are only available for levels 2 and higher. - if (_preCacheLevel >= 2) { - LDEBUG(fmt::format( - "Precaching '{}' with level '{}'", _filePath.value(), _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 }); - } - } - } - } -} - -Tile::Status DefaultTileProvider::tileStatus(const TileIndex& tileIndex) { - if (_asyncTextureDataProvider) { - const std::shared_ptr& rawTileDataReader = - _asyncTextureDataProvider->rawTileDataReader(); - - if (tileIndex.level > rawTileDataReader->maxChunkLevel()) { - return Tile::Status::OutOfRange; - } - - const cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; - - return _tileCache->get(key).status(); - } - else { - return Tile::Status::Unavailable; - } -} - -TileDepthTransform DefaultTileProvider::depthTransform() { - if (_asyncTextureDataProvider) { - return _asyncTextureDataProvider->rawTileDataReader()->depthTransform(); - } - else { - return { 1.f, 0.f }; - } -} - -} // namespace openspace::globebrowsing::tileprovider diff --git a/modules/globebrowsing/tile/tileprovider/defaulttileprovider.h b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.h deleted file mode 100644 index 56334a5dab..0000000000 --- a/modules/globebrowsing/tile/tileprovider/defaulttileprovider.h +++ /dev/null @@ -1,94 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___DEFAULT_TILE_PROVIDER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___DEFAULT_TILE_PROVIDER___H__ - -#include - -#include -#include -#include - -namespace openspace { class PixelBuffer; } - -namespace openspace::globebrowsing { - class AsyncTileDataProvider; - struct RawTile; - - namespace cache { class MemoryAwareTileCache; } -} // namespace openspace::globebrowsing - -namespace openspace::globebrowsing::tileprovider { - -/** - * Provides tiles loaded by AsyncTileDataProvider and - * caches them in memory using LRU caching - */ -class DefaultTileProvider : public TileProvider { -public: - DefaultTileProvider(const ghoul::Dictionary& dictionary); - DefaultTileProvider(std::shared_ptr reader); - - virtual ~DefaultTileProvider(); - - /** - * \return A Tile with status OK iff it exists in in-memory cache. If not, it may - * enqueue some IO operations on a separate thread. - */ - virtual Tile tile(const TileIndex& tileIndex) override; - - virtual Tile::Status tileStatus(const TileIndex& tileIndex) override; - virtual TileDepthTransform depthTransform() override; - virtual void update() override; - virtual void reset() override; - virtual int maxLevel() override; - virtual float noDataValueAsFloat() override; - -private: - /** - * Collects all asynchronously downloaded RawTile - * and uses createTile to create Tiles, - * which are put in the LRU cache - potentially pushing out outdated - * Tiles. - */ - void initTexturesFromLoadedData(); - - void initAsyncTileDataReader(TileTextureInitData initData); - - std::shared_ptr _asyncTextureDataProvider; - - cache::MemoryAwareTileCache* _tileCache = nullptr; - - properties::StringProperty _filePath; - properties::IntProperty _tilePixelSize; - layergroupid::GroupID _layerGroupID = layergroupid::GroupID::Unknown; - int _preCacheLevel = 0; - bool _performPreProcessing = false; - bool _padTiles = true; -}; - -} // namespace openspace::globebrowsing::tileprovider - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___DEFAULT_TILE_PROVIDER___H__ diff --git a/modules/globebrowsing/tile/tileprovider/projectiontileprovider.h b/modules/globebrowsing/tile/tileprovider/projectiontileprovider.h deleted file mode 100644 index 49e24711f6..0000000000 --- a/modules/globebrowsing/tile/tileprovider/projectiontileprovider.h +++ /dev/null @@ -1,114 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PROJECTION_TILE_PROVIDER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___PROJECTION_TILE_PROVIDER___H__ - -#include -#include - -#include -#include -#include - -namespace openspace::globebrowsing { -class AsyncTileDataProvider; -class RawTile; -} // namespace openspace::globebrowsing - -namespace openspace::globebrowsing::tileprovider { - -class ProjectionTileProvider : public TileProvider { -public: - ProjectionTileProvider(const ghoul::Dictionary& dictionary); - - virtual ~ProjectionTileProvider() override; - - virtual Tile getTile(const TileIndex& tileIndex) 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 openspace::globebrowsing::tileprovider - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PROJECTION_TILE_PROVIDER___H__ diff --git a/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp b/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp deleted file mode 100644 index 52ad871d56..0000000000 --- a/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include - -namespace { - constexpr const char* KeyFilePath = "FilePath"; - - constexpr openspace::properties::Property::PropertyInfo FilePathInfo = { - "FilePath", - "File Path", - "The file path that is used for this image provider. The file must point to an " - "image that is then loaded and used for all tiles." - }; -} // namespace - -namespace openspace::globebrowsing::tileprovider { - -SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) - : _tile(nullptr, nullptr, Tile::Status::Unavailable) - , _filePath(FilePathInfo) -{ - _filePath = dictionary.value(KeyFilePath); - addProperty(_filePath); - - reset(); -} - -SingleImageProvider::SingleImageProvider(const std::string& imagePath) - : _tile(nullptr, nullptr, Tile::Status::Unavailable) - , _filePath(FilePathInfo, imagePath) -{ - reset(); -} - -Tile SingleImageProvider::tile(const TileIndex&) { - return _tile; -} - -Tile::Status SingleImageProvider::tileStatus(const TileIndex&) { - return _tile.status(); -} - -TileDepthTransform SingleImageProvider::depthTransform() { - return { 0.f, 1.f }; -} - -void SingleImageProvider::update() { - // nothing to be done -} - -void SingleImageProvider::reset() { - if (_filePath.value().empty()) { - return; - } - _tileTexture = ghoul::io::TextureReader::ref().loadTexture(_filePath); - Tile::Status tileStatus = _tileTexture ? Tile::Status::OK : Tile::Status::IOError; - - if (!_tileTexture) { - throw std::runtime_error(std::string("Unable to load texture '") - + _filePath.value() + "'"); - } - - _tileTexture->uploadTexture(); - _tileTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - - _tile = Tile(_tileTexture.get(), nullptr, tileStatus); -} - -int SingleImageProvider::maxLevel() { - return 1337; // unlimited -} - -} // namespace openspace::globebrowsing::tileprovider diff --git a/modules/globebrowsing/tile/tileprovider/singleimageprovider.h b/modules/globebrowsing/tile/tileprovider/singleimageprovider.h deleted file mode 100644 index ae8b8d3e58..0000000000 --- a/modules/globebrowsing/tile/tileprovider/singleimageprovider.h +++ /dev/null @@ -1,56 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___SINGLE_IMAGE_PROVIDER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___SINGLE_IMAGE_PROVIDER___H__ - -#include - -#include - -namespace openspace::globebrowsing::tileprovider { - -class SingleImageProvider : public TileProvider { -public: - SingleImageProvider(const ghoul::Dictionary& dictionary); - SingleImageProvider(const std::string& imagePath); - virtual ~SingleImageProvider() = default; - - virtual Tile tile(const TileIndex& tileIndex) override; - virtual Tile::Status tileStatus(const TileIndex& index) override; - virtual TileDepthTransform depthTransform() override; - virtual void update() override; - virtual void reset() override; - virtual int maxLevel() override; - -private: - std::unique_ptr _tileTexture; - Tile _tile; - - properties::StringProperty _filePath; -}; - -} // namespace openspace::globebrowsing::tileprovider - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___SINGLE_IMAGE_PROVIDER___H__ diff --git a/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp b/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp deleted file mode 100644 index 5b93b6e325..0000000000 --- a/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - constexpr const char* KeyRadii = "Radii"; -} // namespace - -namespace openspace::globebrowsing::tileprovider { - -SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary) - : TextTileProvider( - LayerManager::getTileTextureInitData( - layergroupid::GroupID::ColorLayers, - LayerManager::PadTiles::No - ) - ) -{ - _fontSize = 50; - _font = global::fontManager.font("Mono", static_cast(_fontSize)); - - if (dictionary.hasKeyAndValue(KeyRadii)) { - _ellipsoid = dictionary.value(KeyRadii); - } -} - -void SizeReferenceTileProvider::renderText( - const ghoul::fontrendering::FontRenderer& fontRenderer, - const TileIndex& tileIndex) const -{ - const GeodeticPatch patch(tileIndex); - const bool aboveEquator = patch.isNorthern(); - - double tileLongitudalLength = roundedLongitudalLength(tileIndex); - - const char* unit; - if (tileLongitudalLength > 9999) { - tileLongitudalLength *= 0.001; - unit = "km"; - } - else { - unit = "m"; - } - - const glm::vec2 textPosition = { - 0.f, - aboveEquator ? _fontSize / 2.f : _initData.dimensions().y - 3.f * _fontSize / 2.f - }; - - fontRenderer.render( - *_font, - textPosition, - fmt::format(" {:.0f} {:s}", tileLongitudalLength, unit), - { 1.f, 1.f, 1.f, 1.f } - ); -} - -int SizeReferenceTileProvider::roundedLongitudalLength(const TileIndex& tileIndex) const { - const GeodeticPatch patch(tileIndex); - const bool aboveEquator = patch.isNorthern(); - const double lat = aboveEquator ? patch.minLat() : patch.maxLat(); - const double lon1 = patch.minLon(); - const double lon2 = patch.maxLon(); - int l = static_cast(_ellipsoid.longitudalDistance(lat, lon1, lon2)); - - const bool useKm = l > 9999; - if (useKm) { - l /= 1000; - } - l = static_cast(std::round(l)); - if (useKm) { - l *= 1000; - } - - return l; -} - -TileIndex::TileHashKey SizeReferenceTileProvider::toHash(const TileIndex& tileIndex) const -{ - const int l = roundedLongitudalLength(tileIndex); - const TileIndex::TileHashKey key = static_cast(l); - return key; -} - -} // namespace openspace::globebrowsing::tileprovider diff --git a/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.h b/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.h deleted file mode 100644 index 8310c1eb7f..0000000000 --- a/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.h +++ /dev/null @@ -1,56 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___SIZEREFERENCE_TILE_PROVIDER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___SIZEREFERENCE_TILE_PROVIDER___H__ - -#include - -#include - -namespace openspace::globebrowsing::tileprovider { - -/** - * Constructed with an ellipsoid and uses that to render the longitudal length of each - * of each tile. - */ -class SizeReferenceTileProvider : public TextTileProvider { -public: - SizeReferenceTileProvider(const ghoul::Dictionary& dictionary); - - virtual void renderText(const ghoul::fontrendering::FontRenderer& fontRenderer, - const TileIndex& tileIndex) const override; - - virtual TileIndex::TileHashKey toHash(const TileIndex& tileIndex) const override; - -private: - int roundedLongitudalLength(const TileIndex& tileIndex) const; - - Ellipsoid _ellipsoid; - Tile _backgroundTile = Tile::TileUnavailable; -}; - -} // namespace openspace::globebrowsing::tileprovider - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___SIZEREFERENCE_TILE_PROVIDER___H__ diff --git a/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp b/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp deleted file mode 100644 index b9fcb14cf5..0000000000 --- a/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp +++ /dev/null @@ -1,394 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifdef GLOBEBROWSING_USE_GDAL - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "cpl_minixml.h" - -namespace { - constexpr const char* _loggerCat = "TemporalTileProvider"; - - constexpr const char* KeyFilePath = "FilePath"; - constexpr const char* KeyBasePath = "BasePath"; - constexpr const char* KeyPreCacheStartTime = "PreCacheStartTime"; - constexpr const char* KeyPreCacheEndTime = "PreCacheEndTime"; - - constexpr openspace::properties::Property::PropertyInfo FilePathInfo = { - "FilePath", - "File Path", - "This is the path to the XML configuration file that describes the temporal tile " - "information." - }; -} // namespace - -namespace ghoul { - -template <> -openspace::globebrowsing::tileprovider::TemporalTileProvider::TimeFormatType -from_string(const std::string& string) -{ - using namespace openspace::globebrowsing::tileprovider; - if (string == "YYYY-MM-DD") { - return TemporalTileProvider::TimeFormatType::YYYY_MM_DD; - } - else if (string == "YYYY-MM-DDThh:mm:ssZ") { - return TemporalTileProvider::TimeFormatType::YYYY_MM_DDThhColonmmColonssZ; - } - else if (string == "YYYY-MM-DDThh_mm_ssZ") { - return TemporalTileProvider::TimeFormatType::YYYY_MM_DDThh_mm_ssZ; - } - else if (string == "YYYYMMDD_hhmmss") { - return TemporalTileProvider::TimeFormatType::YYYYMMDD_hhmmss; - } - else if (string == "YYYYMMDD_hhmm") { - return TemporalTileProvider::TimeFormatType::YYYYMMDD_hhmm; - } - else { - throw ghoul::RuntimeError("Unknown timeformat " + string); - } -} - -} // namespace ghoul - -namespace openspace::globebrowsing::tileprovider { - -namespace { - std::string timeStringify(TemporalTileProvider::TimeFormatType type, const Time& t) { - switch (type) { - case TemporalTileProvider::TimeFormatType::YYYY_MM_DD: - return t.ISO8601().substr(0, 10); - case TemporalTileProvider::TimeFormatType::YYYYMMDD_hhmmss: { - std::string ts = t.ISO8601().substr(0, 19); - - // YYYY_MM_DDThh_mm_ss -> YYYYMMDD_hhmmss - ts.erase(std::remove(ts.begin(), ts.end(), '-'), ts.end()); - ts.erase(std::remove(ts.begin(), ts.end(), ':'), ts.end()); - replace(ts.begin(), ts.end(), 'T', '_'); - return ts; - } - case TemporalTileProvider::TimeFormatType::YYYYMMDD_hhmm: { - std::string ts = t.ISO8601().substr(0, 16); - - // YYYY_MM_DDThh_mm -> YYYYMMDD_hhmm - ts.erase(std::remove(ts.begin(), ts.end(), '-'), ts.end()); - ts.erase(std::remove(ts.begin(), ts.end(), ':'), ts.end()); - replace(ts.begin(), ts.end(), 'T', '_'); - return ts; - } - case TemporalTileProvider::TimeFormatType::YYYY_MM_DDThhColonmmColonssZ: - return t.ISO8601().substr(0, 19) + "Z"; - case TemporalTileProvider::TimeFormatType::YYYY_MM_DDThh_mm_ssZ: { - std::string timeString = t.ISO8601().substr(0, 19) + "Z"; - replace(timeString.begin(), timeString.end(), ':', '_'); - return timeString; - } - default: - throw ghoul::MissingCaseException(); - } - } -} // namespace - -TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary) - : _initDict(dictionary) - , _filePath(FilePathInfo) - , _successfulInitialization(false) -{ - _filePath = dictionary.value(KeyFilePath); - addProperty(_filePath); - - if (readFilePath()) { - 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); - _preCacheTimes = _timeQuantizer.quantized( - Time(Time::convertTime(start)), - Time(Time::convertTime(end)) - ); - } - _successfulInitialization = true; - } - else { - LERROR("Unable to read file " + _filePath.value()); - _successfulInitialization = false; - } -} - - -bool TemporalTileProvider::initialize() { - const bool success = TileProvider::initialize(); - - if (!_preCacheTimes.empty()) { - LINFO(fmt::format("Preloading: {}", _filePath.value())); - for (const Time& t : _preCacheTimes) { - getTileProvider(t); - } - _preCacheTimes.clear(); - } - - return success; -} - -bool TemporalTileProvider::readFilePath() { - std::ifstream in(_filePath.value().c_str()); - std::string xml; - if (in.is_open()) { - // read file - xml = std::string( - std::istreambuf_iterator(in), - (std::istreambuf_iterator()) - ); - } - else { - // Assume that it is already an xml - xml = _filePath.value(); - } - - // File path was not a path to a file but a GDAL config or empty - if (FileSys.fileExists(_filePath.value())) { - _initDict.setValue( - KeyBasePath, - ghoul::filesystem::File(_filePath.value()).directoryName() - ); - } - - _gdalXmlTemplate = consumeTemporalMetaData(xml); - return true; -} - -std::string TemporalTileProvider::consumeTemporalMetaData(const std::string& xml) { - CPLXMLNode* node = CPLParseXMLString(xml.c_str()); - - std::string timeStart = getXMLValue(node, TemporalXMLTags::TimeStart, "2000 Jan 1"); - std::string timeResolution = getXMLValue(node, TemporalXMLTags::TimeResolution, "2d"); - std::string timeEnd = getXMLValue(node, TemporalXMLTags::TimeEnd, "Today"); - std::string timeIdFormat = getXMLValue( - node, - TemporalXMLTags::TimeFormat, - "YYYY-MM-DDThh:mm:ssZ" - ); - - Time start; - start.setTime(std::move(timeStart)); - Time end(Time::now()); - if (timeEnd == "Yesterday") { - end.advanceTime(-60.0 * 60.0 * 24.0); // Go back one day - } - else if (timeEnd != "Today") { - end.setTime(std::move(timeEnd)); - } - - try { - _timeQuantizer = TimeQuantizer(start, end, timeResolution); - } - catch (const ghoul::RuntimeError& e) { - throw ghoul::RuntimeError(fmt::format( - "Could not create time quantizer for Temporal GDAL dataset '{}'. {}", - _filePath.value(), e.message - )); - } - _timeFormat = ghoul::from_string(timeIdFormat); - - std::string gdalDescription; - CPLXMLNode* gdalNode = CPLSearchXMLNode(node, "GDAL_WMS"); - if (gdalNode) { - gdalDescription = CPLSerializeXMLTree(gdalNode); - } - if (!gdalNode) { - gdalNode = CPLSearchXMLNode(node, "FilePath"); - gdalDescription = std::string(gdalNode->psChild->pszValue); - } - - return gdalDescription; -} - -std::string TemporalTileProvider::getXMLValue(CPLXMLNode* node, const std::string& key, - const std::string& defaultVal) -{ - CPLXMLNode* n = CPLSearchXMLNode(node, key.c_str()); - if (!n) { - throw ghoul::RuntimeError( - fmt::format("Unable to parse file {}. {} missing", _filePath.value(), key) - ); - } - - const bool hasValue = n && n->psChild && n->psChild->pszValue; - return hasValue ? n->psChild->pszValue : defaultVal; -} - -TileDepthTransform TemporalTileProvider::depthTransform() { - if (_successfulInitialization) { - ensureUpdated(); - return _currentTileProvider->depthTransform(); - } - else { - return { 1.f, 0.f }; - } -} - -Tile::Status TemporalTileProvider::tileStatus(const TileIndex& tileIndex) { - if (_successfulInitialization) { - ensureUpdated(); - return _currentTileProvider->tileStatus(tileIndex); - } - else { - return Tile::Status::Unavailable; - } -} - -Tile TemporalTileProvider::tile(const TileIndex& tileIndex) { - if (_successfulInitialization) { - ensureUpdated(); - return _currentTileProvider->tile(tileIndex); - } - else { - return Tile::TileUnavailable; - } -} - -int TemporalTileProvider::maxLevel() { - if (_successfulInitialization) { - ensureUpdated(); - return _currentTileProvider->maxLevel(); - } - else { - return 0; - } -} - -void TemporalTileProvider::ensureUpdated() { - if (!_currentTileProvider) { - LDEBUG("Warning: update was done lazily"); - update(); - } -} - -void TemporalTileProvider::update() { - if (_successfulInitialization) { - std::shared_ptr newCurrent = getTileProvider( - global::timeManager.time() - ); - if (newCurrent) { - _currentTileProvider = newCurrent; - } - _currentTileProvider->update(); - } -} - -void TemporalTileProvider::reset() { - if (_successfulInitialization) { - using K = TimeKey; - using V = std::shared_ptr; - for (std::pair& it : _tileProviderMap) { - it.second->reset(); - } - } -} -std::shared_ptr TemporalTileProvider::getTileProvider(const Time& t) { - Time tCopy(t); - if (_timeQuantizer.quantize(tCopy, true)) { - TimeKey timeKey = timeStringify(_timeFormat, tCopy); - try { - return getTileProvider(timeKey); - } - catch (const ghoul::RuntimeError& e) { - LERROR(e.message); - return nullptr; - } - } - return nullptr; -} - -std::shared_ptr TemporalTileProvider::getTileProvider( - const TimeKey& timekey) -{ - const auto it = _tileProviderMap.find(timekey); - if (it != _tileProviderMap.end()) { - return it->second; - } - else { - std::shared_ptr tileProvider = initTileProvider(timekey); - tileProvider->initialize(); - - _tileProviderMap[timekey] = tileProvider; - return tileProvider; - } -} - -std::shared_ptr TemporalTileProvider::initTileProvider(TimeKey timekey) { - static const std::vector AllowedTokens = { - // From: http://www.gdal.org/frmt_wms.html - // @FRAGILE: What happens if a user specifies one of these as path tokens? - // ---abock - "${x}", - "${y}", - "${z}", - "${version}", - "${format}", - "${layer}" - }; - - std::string gdalDatasetXml = getGdalDatasetXML(std::move(timekey)); - FileSys.expandPathTokens(gdalDatasetXml, AllowedTokens); - - _initDict.setValue(KeyFilePath, gdalDatasetXml); - std::shared_ptr tileProvider = - std::make_shared(_initDict); - return tileProvider; -} - -std::string TemporalTileProvider::getGdalDatasetXML(const Time& t) { - TimeKey timeKey = timeStringify(_timeFormat, t); - return getGdalDatasetXML(timeKey); -} - -std::string TemporalTileProvider::getGdalDatasetXML(const TimeKey& timeKey) { - std::string xmlTemplate(_gdalXmlTemplate); - const size_t pos = xmlTemplate.find(UrlTimePlaceholder); - //size_t numChars = std::string(UrlTimePlaceholder).length(); - const size_t numChars = strlen(UrlTimePlaceholder); - // @FRAGILE: This will only find the first instance. Dangerous if that instance is - // commented out ---abock - const std::string timeSpecifiedXml = xmlTemplate.replace(pos, numChars, timeKey); - return timeSpecifiedXml; -} - -} // namespace openspace::globebrowsing::tileprovider - -#endif // GLOBEBROWSING_USE_GDAL diff --git a/modules/globebrowsing/tile/tileprovider/temporaltileprovider.h b/modules/globebrowsing/tile/tileprovider/temporaltileprovider.h deleted file mode 100644 index 95d7804030..0000000000 --- a/modules/globebrowsing/tile/tileprovider/temporaltileprovider.h +++ /dev/null @@ -1,207 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2018 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TEMPORAL_TILE_PROVIDER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TEMPORAL_TILE_PROVIDER___H__ - -#ifdef GLOBEBROWSING_USE_GDAL - -#include - -#include -#include -#include - -struct CPLXMLNode; - -namespace openspace::globebrowsing::tileprovider { - -/** - * Provide Tiles from web map services that have temporal resolution. - * - * TemporalTileProviders are instantiated using a ghoul::Dictionary, - * and must define a filepath to a Openspace Temporal dataset description file. - * This is an xml-file that defines the same meta data as the GDAL wms description - * (http://www.gdal.org/frmt_wms.html), but augmented with some - * extra tags describing the temporal properties of the dataset. See - * TemporalTileProvider::TemporalXMLTags - * - */ -class TemporalTileProvider : public TileProvider { -public: - enum class TimeFormatType { - YYYY_MM_DD = 0, - YYYYMMDD_hhmmss, - YYYYMMDD_hhmm, - YYYY_MM_DDThhColonmmColonssZ, - YYYY_MM_DDThh_mm_ssZ - }; - - /** - * Dictionary constructor. Must provide KeyFilePath as defined in .cpp file. - */ - TemporalTileProvider(const ghoul::Dictionary& dictionary); - - bool initialize() override; - - // These methods implements the TileProvider interface - - virtual Tile tile(const TileIndex& tileIndex) override; - virtual Tile::Status tileStatus(const TileIndex& tileIndex) override; - virtual TileDepthTransform depthTransform() override; - virtual void update() override; - virtual void reset() override; - virtual int maxLevel() override; - - using TimeKey = std::string; - - std::shared_ptr getTileProvider(const Time& t); - std::shared_ptr getTileProvider(const TimeKey& timekey); - -private: - /** - * A placeholder string that must be provided in the WMS template url. This - * placeholder will be replaced by quantized date-time strings during run time - * in order to access the datasets for different instances of time. - */ - constexpr static const char* UrlTimePlaceholder = "${OpenSpaceTimeId}"; - - /** - * These are tags that TemporalTileProviders must be able to read from the XML - * file provided in the ghoul::Dictionary used to create this provider. These - * tags describe the temporal properties of the dataset. - */ - struct TemporalXMLTags { - /** - * Tag should contain a ISO8601 time specifying the datasets start time - */ - constexpr static const char* TimeStart = "OpenSpaceTimeStart"; - - /** - * Tag should contain a ISO8601 time specifying the datasets end time - * Example 1: "2016 SEP 08". - * Example 2: "now" - sets the dataset's end time to the current time. - */ - constexpr static const char* TimeEnd = "OpenSpaceTimeEnd"; - - /** - * Tag should contain the time resolution of the dataset. - * The resolution is defined by a number along with a unit specifying how - * often the dataset is updated temporally. Supported units are: - * (s)econds, (m)inutes, (h)ours, (d)ays, (y)ears. - * - * Example 1: "2d" - dataset updated every other day. - * Example 2: "1h" - dataset is updated every hour. - */ - constexpr static const char* TimeResolution = "OpenSpaceTimeResolution"; - - /** - * Tag should contain a string specifying the date-time format expected by the - * WMS. - */ - constexpr static const char* TimeFormat = "OpenSpaceTimeIdFormat"; - }; - - /** - * Create a GDAL dataset description based on the time t, - * - * \param t Time to generate a GDAL dataset description for - * \return a GDAL dataset description - */ - std::string getGdalDatasetXML(const Time& t); - - /** - * Create a GDAL dataset description associated with the provided TimeKey - * - * \param timeKey The TimeKey specifying time - * \return a GDAL dataset description - */ - std::string getGdalDatasetXML(const TimeKey& timeKey); - - /** - * Instantiates a new TileProvder for the temporal dataset at the time - * specified. - * - * This method replaced the UrlTimePlaceholder in the template URL - * with the provided timekey, the opens a new GDAL dataset with that URL. - * - * \param timekey time specifying dataset's temporality - * \return newly instantiated TileProvider - */ - std::shared_ptr initTileProvider(TimeKey timekey); - - /** - * Takes as input a Openspace Temporal dataset description, extracts the temporal - * metadata provided by reading the TemporalXMLTags, removes the - * read tags from the description, and returns a GDAL template GDAL dataset - * description. The template GDAL dataset description has the a - * UrlTimePlaceholder still in it, which needs to be replaced before - * GDAL can open it as a GDALDataset. - * - * \param xml Openspace Temporal dataset description - * \returns a GDAL template data description. - */ - std::string consumeTemporalMetaData(const std::string &xml); - - /** - * Helper method to read a XML value from a XML tree. - * - * \param node XML tree to search in - * \param key XML tag to find the value for - * \param defaultVal value to return if key was not found - * \return the value of the Key, or defaultVal if key was undefined. - */ - std::string getXMLValue(CPLXMLNode* node, const std::string& key, - const std::string& defaultVal); - - /** - * Ensures that the TemporalTileProvider is up to date. - */ - void ensureUpdated(); - - bool readFilePath(); - - // Used for creation of time specific instances of CachingTileProvider - ghoul::Dictionary _initDict; - properties::StringProperty _filePath; - std::string _gdalXmlTemplate; - - std::unordered_map> _tileProviderMap; - - - std::shared_ptr _currentTileProvider; - - TimeFormatType _timeFormat; - TimeQuantizer _timeQuantizer; - - std::vector