diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..8ac26a431b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 4 +insert_final_newline = true + +# overwrite default settings here, for instance like this: +# [*.cpp] +# indent_style = tabs diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..6f15cde045 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,125 @@ +* text=auto + +# GitHub files +ATTRIBUTION text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +copyright text +*COPYRIGHT* text +INSTALL text +LICENSE text +NEWS text +readme text +*README* text +TODO text + +# Other helpers +.clang-format text +.gitattributes text +.gitconfig text +.gitignore text +Doxyfile text +Jenkinsfile text +langDef text + +# Documents +*.bib text +*.cfg text +*.csv text +*.ini text +*.markdown text +*.md text +*.xml text + +# Graphics +*.eps binary +*.gif binary +*.ico binary +*.jpeg binary +*.jpg binary +*.png binary +*.svg text +*.tif binary +*.tiff binary + +# C++ sources +*.c text +*.cc text +*.cxx text +*.cpp text +*.c++ text +*.h text +*.hh text +*.hpp text +*.h++ text +*.in text +*.inl text + +# CMake +*.cmake text +*.template text + +# HTML +*.css text +*.htm text +*.html text +*.hbs text +*.js text + +# GLSL +*.glsl text +*.hglsl text +*.fs text +*.frag text +*.vert text +*.vs text + +# Other +*.am text +*.json text +*.lua text +*.py text + +# Web Server Gateway Interface +*.wsgi text + +# Compiled Dynamic libraries +*.dll binary +*.dylib binary +*.so binary + +# Compiled Static libraries +*.a binary +*.la binary +*.lai binary +*.lib binary + +# Fonts +*.otf binary +*.ttf binary + +# Resource files +*.rc text +*.qrc text + +# OpenSpace specific +*.scene text +*.mod text +*.data text + +# SPICE specific +*.tf text +*.ti text +*.tls text +*.tpc text + +# GDAL specific +*.wkt text +*.dxf text +*.gfs text +*.xsd text +*.rsc binary +*.dgn binary diff --git a/.gitignore b/.gitignore index b6c4278bba..5306c5559c 100644 --- a/.gitignore +++ b/.gitignore @@ -118,4 +118,4 @@ data/spice/nh_kernels data/spice/OsirisRexKernels data/spice/plu055.bsp data/spice/Rosetta -data/spice/sat375.bsp +data/spice/sat375.bsp \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 3321a95461..207b84ddb5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "ext/sgct"] path = ext/sgct url = https://github.com/opensgct/sgct.git +[submodule "modules/touch/ext/libTUIO11"] + path = modules/touch/ext/libTUIO11 + url = https://github.com/mkalten/TUIO11_CPP diff --git a/CREDITS.md b/CREDITS.md index eafd8ddda1..1a4fc89bbc 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -21,7 +21,7 @@ Rickard Lindtstedt Michael Sjöström Michael Novén Oskar Carlbaum -Jonathas Bosson +Jonathan Bosson Klas Eskilson Anteige diff --git a/Jenkinsfile b/Jenkinsfile index 1985a6a989..6bec006822 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -34,7 +34,7 @@ stage('Build') { cd build cmake .. ''' + flags + ''' .. - make + make -j2 ''' } } @@ -70,7 +70,7 @@ stage('Build') { mkdir ${srcDir}/build fi cd ${srcDir}/build - /Applications/CMake.app/Contents/bin/cmake -G Xcode -D NASM=/usr/local/bin/nasm ${srcDir} .. ''' + + /Applications/CMake.app/Contents/bin/cmake -G Xcode ${srcDir} .. ''' + flags + ''' xcodebuild -quiet ''' diff --git a/README.md b/README.md index d3c2d1e8de..765271bcfa 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ -OpenSpace is an open source, non-commercial, and freely available interactive data visualization software designed to visualize the entire known universe and portray our ongoing efforts to investigate the cosmos. Bringing the latest techniques from data visualization research to the general public, OpenSpace supports interactive presentation of dynamic data from observations, simulations, and space mission planning and operations. The software works on multiple operating systems (Windows, Linux, MacOS) with an extensible architecture powering high resolution tiled displays and planetarium domes, making use of the latest graphic card technologies for rapid data throughput. In addition, OpenSpace enables simultaneous connections across the globe creating opportunity for shared experiences among audiences worldwide. +[OpenSpace](http://openspaceproject.com) is an open source, non-commercial, and freely available interactive data visualization software designed to visualize the entire known universe and portray our ongoing efforts to investigate the cosmos. Bringing the latest techniques from data visualization research to the general public, OpenSpace supports interactive presentation of dynamic data from observations, simulations, and space mission planning and operations. The software works on multiple operating systems (Windows, Linux, MacOS) with an extensible architecture powering high resolution tiled displays and planetarium domes, making use of the latest graphic card technologies for rapid data throughput. In addition, OpenSpace enables simultaneous connections across the globe creating opportunity for shared experiences among audiences worldwide. -The project stems from the same academic collaboration between Sweden’s Linköping University (LiU) and the American Museum of Natural History (AMNH) that led to the creation of Uniview and its parent company SCISS. Development of the software began several years ago through a close collaboration with NASA Goddard’s Community Coordinated Modeling Center (CCMC) to model space weather forecasting and continued last year with visualization of NASA’s New Horizons mission to Pluto and ESA’s Rosetta mission. This promising set of preliminary work provided a foundation for recent NASA funding, which has extended the collaboration to include the University of Utah’s Scientific Computing and Imaging (SCI) Institute, New York University’s Tandon School of Engineering, multiple informal science institutions across the United States, and multiple, international vendors. Current areas of focus within OpenSpace include: +The project stems from the same academic collaboration between Sweden’s [Linköping University](https://www.liu.se) (LiU) and the [American Museum of Natural History](https://www.amnh.org) (AMNH) that led to the creation of Uniview and its parent company [SCISS](http://sciss.se). Development of the software began several years ago through a close collaboration with NASA Goddard’s [Community Coordinated Modeling Center](https://ccmc.gsfc.nasa.gov) (CCMC) to model space weather forecasting and continued with visualizations of NASA’s New Horizons mission to Pluto and ESA’s Rosetta mission. This promising set of preliminary work provided a foundation for recent NASA funding, which has extended the collaboration to include the University of Utah’s [Scientific Computing and Imaging](https://www.sci.utah.edu) (SCI) Institute, [New York University](https://www.nyu.edu)’s Tandon School of Engineering, multiple informal science institutions across the United States, and multiple, international vendors. Current areas of focus within OpenSpace include: - Visualization of dynamic simulations via interactive volumetric rendering, as a priority for communicating research in astrophysics. - Utilization of NASA’s SPICE observational geometry system with its Planetary Data Service (PDS) to enable space mission visualization that reveal how missions are designed to gather science. - Globe browsing techniques across spatial and temporal scales to examine scientific campaigns on multiple planets, including close up surface exploration. -This repository contains the source code and example scenes for OpenSpace, but does not contain any data. To build and install the client, we refer to the [Wiki](https://github.com/OpenSpace/OpenSpace/wiki) pages here on GitHub, specifically [building](https://github.com/OpenSpace/OpenSpace/wiki/General-Getting-Started-Guide%3A-Compiling-OpenSpace) for [Windows](https://github.com/OpenSpace/OpenSpace/wiki/Guides-Compile-OpenSpace-on-Windows), [Linux](https://github.com/OpenSpace/OpenSpace/wiki/Guides-Compile-OpenSpace-on-Linux), and [MacOS](https://github.com/OpenSpace/OpenSpace/wiki/Guides-Compile-OpenSpace-on-OSX). Required preexisting dependencies are: [NASM](http://www.nasm.us/), [Boost](http://www.boost.org/), and [Qt](http://www.qt.io/download). Feel free to create issues for missing features, bug reports, or compile problems or contact us via [email](mailto:alexander.bock@me.com?subject=OpenSpace:). \ No newline at end of file +This repository contains the source code and example scenes for OpenSpace, but does not contain any data. To build and install the client, we refer to the [Wiki](https://github.com/OpenSpace/OpenSpace/wiki) pages here on GitHub, specifically [building](https://github.com/OpenSpace/OpenSpace/wiki/General-Getting-Started-Guide%3A-Compiling-OpenSpace) for [Windows](https://github.com/OpenSpace/OpenSpace/wiki/Guides-Compile-OpenSpace-on-Windows), [Linux](https://github.com/OpenSpace/OpenSpace/wiki/Guides-Compile-OpenSpace-on-Linux), and [MacOS](https://github.com/OpenSpace/OpenSpace/wiki/Guides-Compile-OpenSpace-on-OSX). Required preexisting dependencies are: [Boost](http://www.boost.org/) and [Qt](http://www.qt.io/download). Feel free to create issues for missing features, bug reports, or compile problems or contact us via [email](mailto:alexander.bock@me.com?subject=OpenSpace:). + +Regarding any issues, you are very welcome on our [Slack support channel](https://openspacesupport.slack.com) to which you can freely [sign-up](https://join.slack.com/openspacesupport/shared_invite/MjA4ODY1MDQzNTUzLTE0OTk0MzUyODEtOGZkYTMwNmI5ZA). diff --git a/apps/Launcher/mainwindow.cpp b/apps/Launcher/mainwindow.cpp index 01602ccdac..e6786fd083 100644 --- a/apps/Launcher/mainwindow.cpp +++ b/apps/Launcher/mainwindow.cpp @@ -285,7 +285,7 @@ void MainWindow::initialize() { _syncWidget->setSceneFiles(_sceneFiles); // Load all available configuration files - QString configurationDirectory = QString::fromStdString(absPath("${SGCT}")); + QString configurationDirectory = QString::fromStdString(absPath("${CONFIG}")); d = QDir(configurationDirectory); d.setFilter(QDir::Files); list = d.entryInfoList(); diff --git a/apps/OpenSpace/CMakeLists.txt b/apps/OpenSpace/CMakeLists.txt index b4ffa29792..6f9d4bb247 100644 --- a/apps/OpenSpace/CMakeLists.txt +++ b/apps/OpenSpace/CMakeLists.txt @@ -84,10 +84,13 @@ if (OPENSPACE_SPOUT_SUPPORT) set(SPOUT_INCLUDE_DIRS ${OPENSPACE_APPS_DIR}/OpenSpace/ext/spout) set(SPOUT_LIBRARY ${OPENSPACE_APPS_DIR}/OpenSpace/ext/spout/SpoutLibrary.lib) set(SPOUT_DEFINITIONS "OPENSPACE_HAS_SPOUT") + + set(SGCT_SPOUT_SUPPORT ON CACHE BOOL "" FORCE) + endif () ######################## -# Spout section end # +# Spout section end # ######################## add_executable(${APPLICATION_NAME} diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 6ee55bb774..01c475f5e5 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -442,10 +442,10 @@ void mainMousePosCallback(double x, double y) { } } -void mainMouseScrollCallback(double, double posY) { +void mainMouseScrollCallback(double posX, double posY) { LTRACE("main::mainMouseScrollCallback(begin"); if (SgctEngine->isMaster()) { - OsEng.mouseScrollWheelCallback(posY); + OsEng.mouseScrollWheelCallback(posX, posY); } LTRACE("main::mainMouseScrollCallback(end)"); } diff --git a/config/sgct/openvr_htcVive.xml b/config/openvr_htcVive.xml similarity index 100% rename from config/sgct/openvr_htcVive.xml rename to config/openvr_htcVive.xml diff --git a/config/sgct/openvr_oculusRiftCv1.xml b/config/openvr_oculusRiftCv1.xml similarity index 100% rename from config/sgct/openvr_oculusRiftCv1.xml rename to config/openvr_oculusRiftCv1.xml diff --git a/config/sgct/single.xml b/config/single.xml similarity index 100% rename from config/sgct/single.xml rename to config/single.xml diff --git a/config/sgct/single_fisheye.xml b/config/single_fisheye.xml similarity index 100% rename from config/sgct/single_fisheye.xml rename to config/single_fisheye.xml diff --git a/config/sgct/single_gui.xml b/config/single_gui.xml similarity index 100% rename from config/sgct/single_gui.xml rename to config/single_gui.xml diff --git a/config/sgct/single_two_win.xml b/config/single_two_win.xml similarity index 100% rename from config/sgct/single_two_win.xml rename to config/single_two_win.xml diff --git a/config/transferfunctions/blue.txt b/config/transferfunctions/blue.txt deleted file mode 100644 index eb6b9b98d5..0000000000 --- a/config/transferfunctions/blue.txt +++ /dev/null @@ -1,8 +0,0 @@ -width 1024 -lower 0.0 -upper 0.7 -mappingkey 0.001 0 0 1 1 -mappingkey 0.01 2 2 0 2 -mappingkey 0.2 50 50 25 50 -mappingkey 0.35 100 100 100 100 -mappingkey 0.51 200 200 100 200 diff --git a/config/transferfunctions/fire.txt b/config/transferfunctions/fire.txt deleted file mode 100644 index 1e67f2dac9..0000000000 --- a/config/transferfunctions/fire.txt +++ /dev/null @@ -1,15 +0,0 @@ -width 1024 -lower 0.0 -upper 0.99 -mappingkey 0.0035 1 1 1 1 -mappingkey 0.0045 3 0 0 1 -mappingkey 0.0060 3 0 0 2 -mappingkey 0.0100 4 1 0 3 -mappingkey 0.0200 6 2 0 3 -mappingkey 0.0300 8 3 0 3 -mappingkey 0.0350 10 4 0 4 -mappingkey 0.0400 12 6 0 5 -mappingkey 0.0800 14 10 0 5 -mappingkey 0.1000 16 12 0 5 -mappingkey 0.2000 50 50 10 10 -mappingkey 0.2500 200 200 200 200 diff --git a/config/transferfunctions/ml.txt b/config/transferfunctions/ml.txt deleted file mode 100644 index f3e0ff894c..0000000000 --- a/config/transferfunctions/ml.txt +++ /dev/null @@ -1,8 +0,0 @@ -width 1024 -lower 0.0 -upper 1.0 -mappingkey 0.0 0 0 0 0 -mappingkey 0.45 5 0 0 5 -mappingkey 0.5 0 100 0 100 -mappingkey 0.55 0 0 5 5 -mappingkey 0.99 0 0 0 0 diff --git a/config/transferfunctions/plain.txt b/config/transferfunctions/plain.txt deleted file mode 100644 index 3fef1c1c21..0000000000 --- a/config/transferfunctions/plain.txt +++ /dev/null @@ -1,5 +0,0 @@ -width 1024 -lower 0.0 -upper 1.0 -mappingkey 0.1 20 20 20 10 -mappingkey 0.9 20 20 20 10 diff --git a/config/transferfunctions/test.txt b/config/transferfunctions/test.txt deleted file mode 100644 index 3e4abfbbcc..0000000000 --- a/config/transferfunctions/test.txt +++ /dev/null @@ -1,14 +0,0 @@ -width 1024 -lower 0.0 -upper 0.5 -mappingkey 0.0035 1 1 1 1 -mappingkey 0.0045 3 0 0 1 -mappingkey 0.0060 3 0 0 2 -mappingkey 0.0100 4 1 0 3 -mappingkey 0.0200 6 2 0 3 -mappingkey 0.0300 8 3 0 3 -mappingkey 0.0400 12 6 0 5 -mappingkey 0.0800 14 10 0 5 -mappingkey 0.1000 16 12 0 5 -mappingkey 0.2000 50 50 10 10 -mappingkey 0.2500 200 200 200 200 diff --git a/config/sgct/two_nodes.xml b/config/two_nodes.xml similarity index 100% rename from config/sgct/two_nodes.xml rename to config/two_nodes.xml diff --git a/data/scene/atmosphereearth.scene b/data/scene/atmosphereearth.scene index e00b18fc74..aea608f35b 100644 --- a/data/scene/atmosphereearth.scene +++ b/data/scene/atmosphereearth.scene @@ -41,7 +41,8 @@ return { CommonFolder = "common", Camera = { Focus = "Earth", - Position = {1, 0, 0, 2}, + Position = {1, 0, 0}, + Rotation = {0.250635, -0.028751, 0.879269, 0.404030}, }, Modules = { "sun", diff --git a/data/scene/default.scene b/data/scene/default.scene index 1e5148b004..ddd2331377 100644 --- a/data/scene/default.scene +++ b/data/scene/default.scene @@ -29,7 +29,7 @@ function postInitialization() openspace.addVirtualProperty("BoolProperty", "Show Trails", "*Trail.renderable.enabled", true, nil, nil) - openspace.resetCameraDirection() + openspace.navigation.resetCameraDirection() openspace.printInfo("Done setting default values") end diff --git a/data/scene/globebrowsing.scene b/data/scene/globebrowsing.scene index 1ae95684b4..0c2b8d23c3 100644 --- a/data/scene/globebrowsing.scene +++ b/data/scene/globebrowsing.scene @@ -6,10 +6,13 @@ function preInitialization() critical objects. ]]-- - --openspace.time.setTime(openspace.time.currentWallTime()) openspace.spice.loadKernel("${SPICE}/naif0012.tls") openspace.spice.loadKernel("${SPICE}/pck00010.tpc") + -- For unit test + --openspace.time.setTime("2016 SEP 8 23:00:00.500") + --openspace.time.togglePause() + openspace.time.setTime(openspace.time.currentWallTime()) dofile(openspace.absPath('${SCRIPTS}/bind_common_keys.lua')) @@ -75,7 +78,7 @@ function postInitialization() openspace.setPropertyValue("Earth.RenderableGlobe.Debug.levelByProjectedAreaElseDistance", false) openspace.setPropertyValue("Earth.RenderableGlobe.Layers.ColorLayers.blendTileLevels", true) - openspace.resetCameraDirection() + openspace.globebrowsing.goToGeo(0, 0, 20000000) openspace.printInfo("Done setting default values") end @@ -86,7 +89,7 @@ return { CommonFolder = "common", Camera = { Focus = "Earth", - Position = {30000000, 0, 0}, + Position = {0, 0, 0}, Rotation = {0.758797, 0.221490, -0.605693, -0.091135}, }, diff --git a/data/scene/juno.scene b/data/scene/juno.scene index 403b508435..eee0999a82 100755 --- a/data/scene/juno.scene +++ b/data/scene/juno.scene @@ -1,63 +1,63 @@ -function preInitialization() - --[[ - The scripts in this function are executed after the scene is loaded but before the - scene elements have been initialized, thus they should be used to set the time at - which the scene should start and other settings that might determine initialization - critical objects. - ]]-- - openspace.spice.loadKernel("${SPICE}/naif0012.tls") - openspace.spice.loadKernel("${SPICE}/pck00010.tpc") - - openspace.time.setTime("2016-07-05T10:05:00.00") - - dofile(openspace.absPath('${SCRIPTS}/common.lua')) - openspace.clearKeys() - helper.setCommonKeys() - helper.setDeltaTimeKeys({ - 1, 5, 10, 20, 40, 90, 360, 720, 2880, 14400, - 28800, 57600, 115200, 230400, 460800, 921600, 1843200, 3686400, 7372800, 14745600 - }) -end - -function postInitialization() - --[[ - The scripts in this function are executed after all objects in the scene have been - created and initialized, but before the first render call. This is the place to set - graphical settings for the renderables. - ]]-- - openspace.printInfo("Setting default values") - openspace.setPropertyValue("Sun.renderable.enabled", false) - openspace.setPropertyValue("SunMarker.renderable.enabled", true) - openspace.setPropertyValue("EarthMarker.renderable.enabled", true) - - openspace.setPropertyValue("MilkyWay.renderable.transparency", 0.55) - openspace.setPropertyValue("MilkyWay.renderable.segments", 50) - - openspace.setPropertyValue('Jupiter.renderable.performShading', false); - - openspace.printInfo("Done setting default values") -end - -return { - ScenePath = ".", - CommonFolder = "common", - Camera = { - Focus = "Juno", - Position = {1, 0, 0, 5}, - }, - Modules = { - "sun", - "mercury", - "venus", - "earth", - "mars", - "jupiter", - "saturn/saturn", - "uranus", - "neptune", - "stars", - "milkyway", - "missions/juno" - } -} - +function preInitialization() + --[[ + The scripts in this function are executed after the scene is loaded but before the + scene elements have been initialized, thus they should be used to set the time at + which the scene should start and other settings that might determine initialization + critical objects. + ]]-- + openspace.spice.loadKernel("${SPICE}/naif0012.tls") + openspace.spice.loadKernel("${SPICE}/pck00010.tpc") + + openspace.time.setTime("2016-07-05T10:05:00.00") + + dofile(openspace.absPath('${SCRIPTS}/common.lua')) + openspace.clearKeys() + helper.setCommonKeys() + helper.setDeltaTimeKeys({ + 1, 5, 10, 20, 40, 90, 360, 720, 2880, 14400, + 28800, 57600, 115200, 230400, 460800, 921600, 1843200, 3686400, 7372800, 14745600 + }) +end + +function postInitialization() + --[[ + The scripts in this function are executed after all objects in the scene have been + created and initialized, but before the first render call. This is the place to set + graphical settings for the renderables. + ]]-- + openspace.printInfo("Setting default values") + openspace.setPropertyValue("Sun.renderable.enabled", false) + openspace.setPropertyValue("SunMarker.renderable.enabled", true) + openspace.setPropertyValue("EarthMarker.renderable.enabled", true) + + openspace.setPropertyValue("MilkyWay.renderable.transparency", 0.55) + openspace.setPropertyValue("MilkyWay.renderable.segments", 50) + + openspace.setPropertyValue('Jupiter.renderable.performShading', false); + + openspace.printInfo("Done setting default values") +end + +return { + ScenePath = ".", + CommonFolder = "common", + Camera = { + Focus = "Juno", + Position = {1, 0, 0, 5}, + }, + Modules = { + "sun", + "mercury", + "venus", + "earth", + "mars", + "jupiter", + "saturn/saturn", + "uranus", + "neptune", + "stars", + "milkyway", + "missions/juno" + } +} + diff --git a/data/scene/lodglobes/earth/earth.mod b/data/scene/lodglobes/earth/earth.mod index 37a222bf58..0819aa8638 100644 --- a/data/scene/lodglobes/earth/earth.mod +++ b/data/scene/lodglobes/earth/earth.mod @@ -63,19 +63,17 @@ return { Renderable = { Type = "RenderableGlobe", Radii = earthEllipsoid, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { { Name = "ESRI VIIRS Combo", - Type = "ByLevel", + Type = "ByLevelTileLayer", LevelTileProviders = { { MaxLevel = 3, TileProvider = { - Type = "Temporal", + Type = "TemporalTileLayer", Name = "Temporal VIIRS SNPP", FilePath = "map_service_configs/GIBS/Temporal_VIIRS_SNPP_CorrectedReflectance_TrueColor.xml", }, }, @@ -89,23 +87,42 @@ return { }, Enabled = true, }, + { + FilePath = "map_service_configs/ESRI/ESRI_Imagery_World_2D.wms", + Name = "ESRI", + }, { - Type = "Temporal", - Name = "Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature", - FilePath = "map_service_configs/GIBS/Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature.xml", + Name = "BMNG", + FilePath = "map_service_configs/Utah/Bmng.wms" }, { - Type = "Temporal", + Type = "TemporalTileLayer", Name = "Temporal_AMSR2_GCOM_W1_Sea_Ice_Concentration", FilePath = "map_service_configs/GIBS/Temporal_AMSR2_GCOM_W1_Sea_Ice_Concentration.xml", }, { - Name = "BMNG", - FilePath = "map_service_configs/Utah/Bmng.wms" - } + Type = "TemporalTileLayer", + Name = "MODIS_Terra_Chlorophyll_A", + FilePath = openspace.globebrowsing.createTemporalGibsGdalXml( + "MODIS_Terra_Chlorophyll_A", + "2013-07-02", + "Yesterday", + "1d", + "1km", + "png") + }, + { + Type = "TemporalTileLayer", + Name = "GHRSST_L4_G1SST_Sea_Surface_Temperature", + FilePath = openspace.globebrowsing.createTemporalGibsGdalXml( + "GHRSST_L4_G1SST_Sea_Surface_Temperature", + "2010-06-21", + "Yesterday", + "1d", + "1km", + "png") + }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, NightLayers = { { Name = "Earth at Night 2012", @@ -118,7 +135,7 @@ return { }, }, { - Type = "Temporal", + Type = "TemporalTileLayer", Name = "Temporal Earth at Night", FilePath = "map_service_configs/GIBS/Temporal_VIIRS_SNPP_DayNightBand_ENCC.xml" } @@ -134,7 +151,7 @@ return { FilePath = "map_service_configs/Utah/Gebco.wms", } }, - ColorOverlays = { + Overlays = { { Name = "Coastlines", FilePath = "map_service_configs/GIBS/Coastlines.xml", @@ -148,14 +165,13 @@ return { FilePath = "map_service_configs/GIBS/Reference_Labels.xml", }, { - Type = "TileIndex", + Type = "TileIndexTileLayer", Name = "Tile Indices", }, { - Type = "SizeReference", + Type = "SizeReferenceTileLayer", Name = "Size Reference", Radii = earthEllipsoid, - BackgroundImagePath = "../arrows.png", }, }, HeightLayers = { diff --git a/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms b/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms index d7d7263f5c..7c54ed40f0 100644 --- a/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms +++ b/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms @@ -13,10 +13,5 @@ 512 3 5 - - ./GDAL_Cache/ESRI_Imagery_World_2d - 4 - .jpg - false \ No newline at end of file diff --git a/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms b/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms index 3937681945..a4a50c0a83 100644 --- a/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms +++ b/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms @@ -3,19 +3,7 @@ http://198.102.45.23/arcgis/rest/services/worldelevation3d/terrain3d? GCS_Elevation - - -180.0 - 90.0 - 180.0 - -90.0 - bottom - 2 5 - - ./GDAL_Cache/TERRAIN - 4 - .jpg - false diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml index 830e32da8a..120c022a25 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml @@ -20,10 +20,4 @@ 400 true 5 - - ./GDAL_Cache/Coastlines - 4 - .png - - false diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml index 19bbcdb9c5..1e5ed01815 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml @@ -17,11 +17,6 @@ 512 3 5 - - ./GDAL_Cache/GIBS_Aqua_MODIS_true - 4 - .jpg - false true 400 diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml index 46a1189c43..7311954847 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml @@ -17,11 +17,6 @@ 512 4 5 - - ./GDAL_Cache/MODIS_Terra_Brightness_Temp_Band31_Day - 4 - .png - false true 400 diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml index a0d82a02b0..3d9b24822d 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml @@ -17,11 +17,6 @@ 512 3 5 - - ./GDAL_Cache/MODIS_Terra_CorrectedReflectance_TrueColor - 4 - .jpg - false true 400 diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml index b3b90a2f48..4abfdde13d 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml @@ -17,13 +17,7 @@ 512 4 5 - - ./GDAL_Cache/MODIS_Water_Mask - 4 - .png - - false true - 400 + 400,204,404 true diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml index 7cb0e23db1..b4874f7db2 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml @@ -17,12 +17,6 @@ 512 4 5 - - ./GDAL_Cache/Reference_Features - 4 - .png - - false true 400 true diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml index 2731893a09..5f45a0d424 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml @@ -17,12 +17,6 @@ 512 4 5 - - ./GDAL_Cache/Reference_Labels - 4 - .png - - false true 400 true diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml index 8530c80b81..5589007002 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml @@ -17,12 +17,6 @@ 512 4 5 - - ./GDAL_Cache/VIIRS_CityLights_2012 - 4 - .jpg - - false true 400 true diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml index b6ffc234fa..d0ff0f3985 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml @@ -17,12 +17,6 @@ 512 3 5 - - ./GDAL_Cache/VIIRS_SNPP_CorrectedReflectance_TrueColor - 4 - .jpg - - false true 400 true diff --git a/data/scene/lodglobes/earth/map_service_configs/other/frmt_wms_virtualearth.xml b/data/scene/lodglobes/earth/map_service_configs/other/frmt_wms_virtualearth.xml index 3b628e9a89..42946f0a2f 100644 --- a/data/scene/lodglobes/earth/map_service_configs/other/frmt_wms_virtualearth.xml +++ b/data/scene/lodglobes/earth/map_service_configs/other/frmt_wms_virtualearth.xml @@ -3,5 +3,4 @@ http://a${server_num}.ortho.tiles.virtualearth.net/tiles/a${quadkey}.jpeg?g=90 4 - diff --git a/data/scene/lodglobes/jupiter/callisto/callisto.mod b/data/scene/lodglobes/jupiter/callisto/callisto.mod index c86a629158..302fc7a103 100644 --- a/data/scene/lodglobes/jupiter/callisto/callisto.mod +++ b/data/scene/lodglobes/jupiter/callisto/callisto.mod @@ -23,8 +23,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {2631000, 2631000, 2631000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { @@ -32,15 +30,8 @@ return { Name = "Callisto Texture", FilePath = "textures/callisto.jpg", Enabled = true, - TilePixelSize = 112, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, } }, diff --git a/data/scene/lodglobes/jupiter/europa/europa.mod b/data/scene/lodglobes/jupiter/europa/europa.mod index b3f4c1a8df..d84d20d48d 100644 --- a/data/scene/lodglobes/jupiter/europa/europa.mod +++ b/data/scene/lodglobes/jupiter/europa/europa.mod @@ -23,8 +23,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {1561000, 1561000, 1561000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { @@ -32,15 +30,8 @@ return { Name = "Europa Texture", FilePath = "textures/europa.jpg", Enabled = true, - TilePixelSize = 256, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, } }, diff --git a/data/scene/lodglobes/jupiter/ganymede/ganymede.mod b/data/scene/lodglobes/jupiter/ganymede/ganymede.mod index 0099a57786..e37a193bb8 100644 --- a/data/scene/lodglobes/jupiter/ganymede/ganymede.mod +++ b/data/scene/lodglobes/jupiter/ganymede/ganymede.mod @@ -23,8 +23,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {2631000, 2631000, 2631000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { @@ -32,15 +30,8 @@ return { Name = "Ganymede Texture", FilePath = "textures/ganymede.jpg", Enabled = true, - TilePixelSize = 112, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, } }, diff --git a/data/scene/lodglobes/jupiter/io/io.mod b/data/scene/lodglobes/jupiter/io/io.mod index 0deb7fae71..87dfc06b20 100644 --- a/data/scene/lodglobes/jupiter/io/io.mod +++ b/data/scene/lodglobes/jupiter/io/io.mod @@ -23,8 +23,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {1821300, 1821300, 1821300}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { @@ -34,12 +32,6 @@ return { Enabled = true, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, } }, diff --git a/data/scene/lodglobes/jupiter/jupiter/jupiter.mod b/data/scene/lodglobes/jupiter/jupiter/jupiter.mod index d8a50af4a5..58dc65149d 100644 --- a/data/scene/lodglobes/jupiter/jupiter/jupiter.mod +++ b/data/scene/lodglobes/jupiter/jupiter/jupiter.mod @@ -34,8 +34,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {71492000, 71492000, 66854000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { @@ -45,12 +43,6 @@ return { Enabled = true, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, } }, diff --git a/data/scene/lodglobes/mars/map_service_configs/CTX_Mosaic.xml b/data/scene/lodglobes/mars/map_service_configs/CTX_Mosaic.xml index 51fd81ce11..0491a66bd5 100644 --- a/data/scene/lodglobes/mars/map_service_configs/CTX_Mosaic.xml +++ b/data/scene/lodglobes/mars/map_service_configs/CTX_Mosaic.xml @@ -12,10 +12,6 @@ 256 256 - - ./GDAL_CTX_cache - 3 - .png - - false + 400,204,404 + true \ No newline at end of file diff --git a/data/scene/lodglobes/mars/map_service_configs/Mola_Elevation.xml b/data/scene/lodglobes/mars/map_service_configs/Mola_Elevation.xml index 9c440826b0..c003ebf07d 100644 --- a/data/scene/lodglobes/mars/map_service_configs/Mola_Elevation.xml +++ b/data/scene/lodglobes/mars/map_service_configs/Mola_Elevation.xml @@ -10,10 +10,5 @@ -90.0 bottom - - ./GDAL_MOLA_cache - 3 - .png - false \ No newline at end of file diff --git a/data/scene/lodglobes/mars/map_service_configs/Utah/CTX_Mosaic.xml b/data/scene/lodglobes/mars/map_service_configs/Utah/CTX_Mosaic.xml index 6135ce51b0..164ab0eb2f 100644 --- a/data/scene/lodglobes/mars/map_service_configs/Utah/CTX_Mosaic.xml +++ b/data/scene/lodglobes/mars/map_service_configs/Utah/CTX_Mosaic.xml @@ -17,4 +17,6 @@ 256 2 10 + 400,204,404 + true \ No newline at end of file diff --git a/data/scene/lodglobes/mars/map_service_configs/Utah/MolaCTX_Elevation.xml b/data/scene/lodglobes/mars/map_service_configs/Utah/MolaCTX_Elevation.xml index 96c96f84d7..baa437174c 100644 --- a/data/scene/lodglobes/mars/map_service_configs/Utah/MolaCTX_Elevation.xml +++ b/data/scene/lodglobes/mars/map_service_configs/Utah/MolaCTX_Elevation.xml @@ -10,10 +10,5 @@ -90.0 bottom - - ./GDAL_MOLA_cache - 3 - .png - false \ No newline at end of file diff --git a/data/scene/lodglobes/mars/mars.mod b/data/scene/lodglobes/mars/mars.mod index e25290d1c0..ceee56e4ea 100644 --- a/data/scene/lodglobes/mars/mars.mod +++ b/data/scene/lodglobes/mars/mars.mod @@ -1,4 +1,5 @@ local marsEllipsoid = {3396190.0, 3396190.0, 3376200.0} + return { -- Barycenter module { @@ -31,10 +32,7 @@ return { Renderable = { Type = "RenderableGlobe", Radii = marsEllipsoid, - CameraMinHeight = 10, SegmentsPerPatch = 90, - -- Allows camera to go down 10000 meters below the reference ellipsoid - InteractionDepthBelowEllipsoid = 10000, -- Useful when having negative height map values Layers = { ColorLayers = { { @@ -42,87 +40,30 @@ return { FilePath = "map_service_configs/MARS_Viking_MDIM21.xml", Enabled = true, }, - -- { - -- Type = "SingleImage", - -- Name = "Debug Tiles", - -- FilePath = "../../debugglobe/textures/test_tile.png", - -- }, - --{ - -- Name = "MARS_Viking", - -- FilePath = "map_service_configs/MARS_Viking_MDIM21.xml", - -- Enabled = true, - --}, { Name = "MOLA Pseudo Color", FilePath = "map_service_configs/Utah/MolaPseudoColor.xml", - -- Enabled = true, - }, - --[[ - { - Name = "Mars Viking Clr", - FilePath = "map_datasets/Viking/Mars_Viking_ClrMosaic_global_925m_longlat_full.vrt", - Enabled = true, - }, - ]] - }, - GrayScaleLayers = { - - }, - GrayScaleColorOverlays = { - { - Name = "CTX Mosaic [AWS]", - FilePath = "map_service_configs/CTX.wms", - Enabled = true, }, { Name = "CTX Mosaic [Europe]", FilePath = "map_service_configs/CTX_Mosaic.xml", - --Enabled = true, + BlendMode = "Color" }, { Name = "CTX Mosaic [Utah]", FilePath = "map_service_configs/Utah/CTX_Mosaic.xml", + BlendMode = "Color" }, - { - Name = "West Candor Chasma", - FilePath = "map_datasets/CTX/West_Candor_Chasma_longlat_global.vrt", - --Enabled = true, - }, - { - Name = "Layered Rock Outcrops in Southwest Candor Chasma", - FilePath = "map_datasets/HiRISE/Layered_Rock_Outcrops_in_Southwest_Candor_Chasma_Texture.vrt", - }, - --[[{ - Name = "Themis IR Day", - FilePath = "map_service_configs/Utah/ThemisIRDay.xml", - }, - { - Name = "Themis IR Night", - FilePath = "map_service_configs/Utah/ThemisIRNight.xml", - }, - - { - Name = "MER_Meridianni_Endeavor_Basemap_25cm", - FilePath = "map_datasets/Basemap/MER_Meridianni_Endeavor_Basemap_25cm.vrt", - }, - { - Name = "Part of Area Traversed by the Mars Exploration Rover", - FilePath = "map_datasets/HiRISE/Part_of_Area_Traversed_by_the_Mars_Exploration_Rover_Texture.vrt", - }, - ]] }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { + Overlays = { { - Type = "TileIndex", + Type = "TileIndexTileLayer", Name = "Indices", }, { - Type = "SizeReference", + Type = "SizeReferenceTileLayer", Name = "Size Reference", Radii = marsEllipsoid, - BackgroundImagePath = "../arrows.png", }, }, HeightLayers = { @@ -131,50 +72,7 @@ return { FilePath = "map_service_configs/Mola_Elevation.xml", Enabled = true, TilePixelSize = 90, - DoPreProcessing = true, }, - --[[ - { - Name = "Mola Elevation [Utah]", - FilePath = "map_service_configs/Utah/Mola_Elevation.xml", - Enabled = false, - TilePixelSize = 90, - DoPreProcessing = true, - }, - { - Name = "Mola Elevation CTX", - FilePath = "map_service_configs/Utah/MolaCTX_Elevation.xml", - -- Enabled = true, - TilePixelSize = 90, - DoPreProcessing = true, - },]] - { - Name = "West Candor Chasma", - FilePath = "map_datasets/CTX/West_Candor_Chasma_DEM_longlat_global.vrt", - --Enabled = true, - TilePixelSize = 90, - DoPreProcessing = true, - }, - { - Name = "Layered Rock Outcrops in Southwest Candor Chasma", - FilePath = "map_datasets/HiRISE/Layered_Rock_Outcrops_in_Southwest_Candor_Chasma_Heightmap.vrt", - TilePixelSize = 90, - DoPreProcessing = true, - }, - --[[ - { - Name = "West Candor Chasma", - FilePath = "map_datasets/CTX/West_Candor_Chasma_DEM_longlat_global.vrt", - --Enabled = true, - TilePixelSize = 90, - DoPreProcessing = true, - },]] - --[[ - { - Name = "Part of Area Traversed by the Mars Exploration Rover", - FilePath = "map_datasets/HiRISE/Part_of_Area_Traversed_by_the_Mars_Exploration_Rover_Heightmap.vrt", - }, - ]] }, }, } diff --git a/data/scene/lodglobes/mercury/map_service_configs/OnMercuryColor.xml b/data/scene/lodglobes/mercury/map_service_configs/OnMercuryColor.xml index d53cb3ad5e..4083bfbba8 100644 --- a/data/scene/lodglobes/mercury/map_service_configs/OnMercuryColor.xml +++ b/data/scene/lodglobes/mercury/map_service_configs/OnMercuryColor.xml @@ -25,6 +25,7 @@ 1 top + 5 512 512 \ No newline at end of file diff --git a/data/scene/lodglobes/mercury/mercury.mod b/data/scene/lodglobes/mercury/mercury.mod new file mode 100644 index 0000000000..531b855ba7 --- /dev/null +++ b/data/scene/lodglobes/mercury/mercury.mod @@ -0,0 +1,74 @@ +return { + -- Barycenter module + { + Name = "MercuryBarycenter", + Parent = "SolarSystemBarycenter", + Transform = { + Translation = { + Type = "SpiceTranslation", + Body = "MERCURY", + Observer = "SUN", + Kernels = "${OPENSPACE_DATA}/spice/de430_1850-2150.bsp" + }, + }, + }, + -- RenderableGlobe module + { + Name = "Mercury", + Parent = "MercuryBarycenter", + Transform = { + Rotation = { + Type = "SpiceRotation", + SourceFrame = "IAU_MERCURY", + DestinationFrame = "GALACTIC", + }, + Scale = { + Type = "StaticScale", + Scale = 1, + }, + }, + Renderable = { + Type = "RenderableGlobe", + Radii = {2439700, 2439700.0, 2439700.0}, + Frame = "IAU_MERCURY", + Body = "MERCURY", + + CameraMinHeight = 300, + InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values + SegmentsPerPatch = 64, + Layers = { + ColorLayers = { + { + Name = "Simple Texture", + FilePath = "textures/mercury.jpg", + Enabled = true, + }, + { + Name = "Messenger_Mosaic", + FilePath = "map_service_configs/Utah/MessengerMosaic.wms" + }, + { + Name = "Messenger_MDIS", + FilePath = "map_service_configs/Utah/MessengerMDIS.wms" + } + }, + }, + }, + }, + -- Trail module + { + Name = "MercuryTrail", + Parent = "SolarSystemBarycenter", + Renderable = { + Type = "RenderableTrailOrbit", + Translation = { + Type = "SpiceTranslation", + Body = "MERCURY", + Observer = "SUN", + }, + Color = {0.6, 0.5, 0.5 }, + Period = 87.968, + Resolution = 100 + } + } +} diff --git a/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml b/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml index d2d9d1ec11..458fdab892 100644 --- a/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml +++ b/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml @@ -61,13 +61,8 @@ top 512 - 512 + 512 true 400 true - - ./GDAL_Cache/OnMoonColor - 4 - .png - \ No newline at end of file diff --git a/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml b/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml index e008c2aa90..3f0934091c 100644 --- a/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml +++ b/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml @@ -19,9 +19,4 @@ true 400 true - - ./GDAL_Cache/OnMoonHeight - 4 - .png - \ No newline at end of file diff --git a/data/scene/lodglobes/moon/moon.mod b/data/scene/lodglobes/moon/moon.mod index 1247ae7187..1ddb3cf044 100644 --- a/data/scene/lodglobes/moon/moon.mod +++ b/data/scene/lodglobes/moon/moon.mod @@ -19,18 +19,9 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {1738140, 1738140, 1735970}, -- Moons's radius - CameraMinHeight = 300, SegmentsPerPatch = 64, - -- Allows camera to go down 10000 meters below the reference ellipsoid - InteractionDepthBelowEllipsoid = 10000, -- Useful when having negative height map values Layers = { ColorLayers = { - - }, - GrayScaleColorOverlays = { - - }, - GrayScaleLayers = { { Name = "OnMoonColorGrayscale", FilePath = "map_service_configs/OnMoonColor.xml", @@ -48,29 +39,14 @@ return { Name = "WAC", FilePath = "map_service_configs/Utah/Wac.wms" } - }, - NightLayers = { - - }, - WaterMasks = { - - }, - ColorOverlays = { - }, HeightLayers = { - { - Name = "OnMoonHeight", - FilePath = "map_service_configs/OnMoonHeight.xml", - Enabled = true, - DoPreProcessing = true, - TileSize = 64, - }, { Name = "LolaDem", FilePath = "map_service_configs/Utah/LolaDem.wms", - DoPreProcessing = true, - TileSize = 64, + Enabled = true, + TilePixelSize = 64, + Settings = { Multiplier = 0.5 }, } }, }, diff --git a/data/scene/lodglobes/neptune/neptune.mod b/data/scene/lodglobes/neptune/neptune.mod index cfb74029b9..99513e18bb 100644 --- a/data/scene/lodglobes/neptune/neptune.mod +++ b/data/scene/lodglobes/neptune/neptune.mod @@ -31,8 +31,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {24764000, 24764000, 24314000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { @@ -40,15 +38,8 @@ return { Name = "Texture", FilePath = "textures/neptune.jpg", Enabled = true, - TilePixelSize = 256, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, }, }, diff --git a/data/scene/lodglobes/saturn/saturn.mod b/data/scene/lodglobes/saturn/saturn.mod index da471b0979..dc1ef691eb 100644 --- a/data/scene/lodglobes/saturn/saturn.mod +++ b/data/scene/lodglobes/saturn/saturn.mod @@ -31,8 +31,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {60268000, 60268000, 54364000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { @@ -40,15 +38,8 @@ return { Name = "Saturn Texture", FilePath = "textures/saturn.jpg", Enabled = true, - TilePixelSize = 256, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, }, }, diff --git a/data/scene/lodglobes/uranus/uranus.mod b/data/scene/lodglobes/uranus/uranus.mod index 06b2160647..b8cda62a16 100644 --- a/data/scene/lodglobes/uranus/uranus.mod +++ b/data/scene/lodglobes/uranus/uranus.mod @@ -31,8 +31,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {25559000, 25559000, 24973000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { @@ -40,15 +38,8 @@ return { Name = "Texture", FilePath = "textures/uranus.jpg", Enabled = true, - TilePixelSize = 256, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, }, }, diff --git a/data/scene/lodglobes/venus/venus.mod b/data/scene/lodglobes/venus/venus.mod index 2ac91197ed..285f88f466 100644 --- a/data/scene/lodglobes/venus/venus.mod +++ b/data/scene/lodglobes/venus/venus.mod @@ -36,8 +36,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {6051900, 6051900, 6051800}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { @@ -45,15 +43,8 @@ return { Name = "Venus Texture", FilePath = "textures/venus.jpg", Enabled = true, - TilePixelSize = 256, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, }, }, diff --git a/data/scene/missions/juno/juno/juno.mod b/data/scene/missions/juno/juno/juno.mod index c9e4cc56df..823c8f9339 100644 --- a/data/scene/missions/juno/juno/juno.mod +++ b/data/scene/missions/juno/juno/juno.mod @@ -127,7 +127,7 @@ return { Parent = "JupiterBarycenter", Renderable = { Type = "RenderableTrailTrajectory", - Translation = { + Translation = { Type = "SpiceTranslation", Body = "JUNO", Observer = "JUPITER BARYCENTER" @@ -135,7 +135,7 @@ return { Color = { 0.70, 0.50, 0.20 }, StartTime = "2016 JUN 28", EndTime = "2016 APR 01", - SampleInterval = 3600 + SampleInterval = 3600 }, }, } diff --git a/data/scene/newhorizons.scene b/data/scene/newhorizons.scene index 3ce05ababc..30f86d1b94 100644 --- a/data/scene/newhorizons.scene +++ b/data/scene/newhorizons.scene @@ -1,4 +1,4 @@ -UseAccurateNewHorizonsKernels = true +UseAccurateNewHorizonsKernels = false -- TextureResolution = "low" TextureResolution = "med" -- TextureResolution = "high" diff --git a/data/scene/osirisrex.scene b/data/scene/osirisrex.scene index f5fff215a9..79c1e58e67 100644 --- a/data/scene/osirisrex.scene +++ b/data/scene/osirisrex.scene @@ -46,7 +46,7 @@ function postInitialization() openspace.printInfo("Done setting default values") openspace.loadMission("${OPENSPACE_DATA}/scene/missions/osirisrex/osirisrex/osirisrex.mission") - openspace.resetCameraDirection() + openspace.navigation.resetCameraDirection() end return { diff --git a/data/scene/satellites.scene b/data/scene/satellites.scene index 20eed4c4d4..5e09f29196 100644 --- a/data/scene/satellites.scene +++ b/data/scene/satellites.scene @@ -32,7 +32,7 @@ function postInitialization() openspace.setPropertyValue("EarthTrail.renderable.enabled", false) openspace.setPropertyValue("Earth.renderable.performShading", false) - openspace.resetCameraDirection() + openspace.navigation.resetCameraDirection() openspace.printInfo("Done setting default values") diff --git a/ext/ghoul b/ext/ghoul index f852572b77..67827b142e 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit f852572b77742d4fa6c78e73b6f5470633509c8f +Subproject commit 67827b142e95122b66d58e7c402fe1a28a65631e diff --git a/ext/tinythread.cpp b/ext/tinythread.cpp index 5b5bd41cf4..690eceea1a 100644 --- a/ext/tinythread.cpp +++ b/ext/tinythread.cpp @@ -1,303 +1,303 @@ -/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- -Copyright (c) 2010-2012 Marcus Geelnard - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#include -#include "tinythread.h" - -#if defined(_TTHREAD_POSIX_) - #include - #include -#elif defined(_TTHREAD_WIN32_) - #include -#endif - - -namespace tthread { - -//------------------------------------------------------------------------------ -// condition_variable -//------------------------------------------------------------------------------ -// NOTE 1: The Win32 implementation of the condition_variable class is based on -// the corresponding implementation in GLFW, which in turn is based on a -// description by Douglas C. Schmidt and Irfan Pyarali: -// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html -// -// NOTE 2: Windows Vista actually has native support for condition variables -// (InitializeConditionVariable, WakeConditionVariable, etc), but we want to -// be portable with pre-Vista Windows versions, so TinyThread++ does not use -// Vista condition variables. -//------------------------------------------------------------------------------ - -#if defined(_TTHREAD_WIN32_) - #define _CONDITION_EVENT_ONE 0 - #define _CONDITION_EVENT_ALL 1 -#endif - -#if defined(_TTHREAD_WIN32_) -condition_variable::condition_variable() : mWaitersCount(0) -{ - mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); - mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); - InitializeCriticalSection(&mWaitersCountLock); -} -#endif - -#if defined(_TTHREAD_WIN32_) -condition_variable::~condition_variable() -{ - CloseHandle(mEvents[_CONDITION_EVENT_ONE]); - CloseHandle(mEvents[_CONDITION_EVENT_ALL]); - DeleteCriticalSection(&mWaitersCountLock); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::_wait() -{ - // Wait for either event to become signaled due to notify_one() or - // notify_all() being called - int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE); - - // Check if we are the last waiter - EnterCriticalSection(&mWaitersCountLock); - -- mWaitersCount; - bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && - (mWaitersCount == 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we are the last waiter to be notified to stop waiting, reset the event - if(lastWaiter) - ResetEvent(mEvents[_CONDITION_EVENT_ALL]); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::notify_one() -{ - // Are there any waiters? - EnterCriticalSection(&mWaitersCountLock); - bool haveWaiters = (mWaitersCount > 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we have any waiting threads, send them a signal - if(haveWaiters) - SetEvent(mEvents[_CONDITION_EVENT_ONE]); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::notify_all() -{ - // Are there any waiters? - EnterCriticalSection(&mWaitersCountLock); - bool haveWaiters = (mWaitersCount > 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we have any waiting threads, send them a signal - if(haveWaiters) - SetEvent(mEvents[_CONDITION_EVENT_ALL]); -} -#endif - - -//------------------------------------------------------------------------------ -// POSIX pthread_t to unique thread::id mapping logic. -// Note: Here we use a global thread safe std::map to convert instances of -// pthread_t to small thread identifier numbers (unique within one process). -// This method should be portable across different POSIX implementations. -//------------------------------------------------------------------------------ - -#if defined(_TTHREAD_POSIX_) -static thread::id _pthread_t_to_ID(const pthread_t &aHandle) -{ - static mutex idMapLock; - static std::map idMap; - static unsigned long int idCount(1); - - lock_guard guard(idMapLock); - if(idMap.find(aHandle) == idMap.end()) - idMap[aHandle] = idCount ++; - return thread::id(idMap[aHandle]); -} -#endif // _TTHREAD_POSIX_ - - -//------------------------------------------------------------------------------ -// thread -//------------------------------------------------------------------------------ - -/// Information to pass to the new thread (what to run). -struct _thread_start_info { - void (*mFunction)(void *); ///< Pointer to the function to be executed. - void * mArg; ///< Function argument for the thread function. - thread * mThread; ///< Pointer to the thread object. -}; - -// Thread wrapper function. -#if defined(_TTHREAD_WIN32_) -unsigned WINAPI thread::wrapper_function(void * aArg) -#elif defined(_TTHREAD_POSIX_) -void * thread::wrapper_function(void * aArg) -#endif -{ - // Get thread startup information - _thread_start_info * ti = (_thread_start_info *) aArg; - - try - { - // Call the actual client thread function - ti->mFunction(ti->mArg); - } - catch(...) - { - // Uncaught exceptions will terminate the application (default behavior - // according to C++11) - std::terminate(); - } - - // The thread is no longer executing - lock_guard guard(ti->mThread->mDataMutex); - ti->mThread->mNotAThread = true; - - // The thread is responsible for freeing the startup information - delete ti; - - return 0; -} - -thread::thread(void (*aFunction)(void *), void * aArg) -{ - // Serialize access to this thread structure - lock_guard guard(mDataMutex); - - // Fill out the thread startup information (passed to the thread wrapper, - // which will eventually free it) - _thread_start_info * ti = new _thread_start_info; - ti->mFunction = aFunction; - ti->mArg = aArg; - ti->mThread = this; - - // The thread is now alive - mNotAThread = false; - - // Create the thread -#if defined(_TTHREAD_WIN32_) - mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID); -#elif defined(_TTHREAD_POSIX_) - if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0) - mHandle = 0; -#endif - - // Did we fail to create the thread? - if(!mHandle) - { - mNotAThread = true; - delete ti; - } -} - -thread::~thread() -{ - if(joinable()) - std::terminate(); -} - -void thread::join() -{ - if(joinable()) - { -#if defined(_TTHREAD_WIN32_) - WaitForSingleObject(mHandle, INFINITE); - CloseHandle(mHandle); -#elif defined(_TTHREAD_POSIX_) - pthread_join(mHandle, NULL); -#endif - } -} - -bool thread::joinable() const -{ - mDataMutex.lock(); - bool result = !mNotAThread; - mDataMutex.unlock(); - return result; -} - -void thread::detach() -{ - mDataMutex.lock(); - if(!mNotAThread) - { -#if defined(_TTHREAD_WIN32_) - CloseHandle(mHandle); -#elif defined(_TTHREAD_POSIX_) - pthread_detach(mHandle); -#endif - mNotAThread = true; - } - mDataMutex.unlock(); -} - -thread::id thread::get_id() const -{ - if(!joinable()) - return id(); -#if defined(_TTHREAD_WIN32_) - return id((unsigned long int) mWin32ThreadID); -#elif defined(_TTHREAD_POSIX_) - return _pthread_t_to_ID(mHandle); -#endif -} - -unsigned thread::hardware_concurrency() -{ -#if defined(_TTHREAD_WIN32_) - SYSTEM_INFO si; - GetSystemInfo(&si); - return (int) si.dwNumberOfProcessors; -#elif defined(_SC_NPROCESSORS_ONLN) - return (int) sysconf(_SC_NPROCESSORS_ONLN); -#elif defined(_SC_NPROC_ONLN) - return (int) sysconf(_SC_NPROC_ONLN); -#else - // The standard requires this function to return zero if the number of - // hardware cores could not be determined. - return 0; -#endif -} - - -//------------------------------------------------------------------------------ -// this_thread -//------------------------------------------------------------------------------ - -thread::id this_thread::get_id() -{ -#if defined(_TTHREAD_WIN32_) - return thread::id((unsigned long int) GetCurrentThreadId()); -#elif defined(_TTHREAD_POSIX_) - return _pthread_t_to_ID(pthread_self()); -#endif -} - -} +/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- +Copyright (c) 2010-2012 Marcus Geelnard + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#include +#include "tinythread.h" + +#if defined(_TTHREAD_POSIX_) + #include + #include +#elif defined(_TTHREAD_WIN32_) + #include +#endif + + +namespace tthread { + +//------------------------------------------------------------------------------ +// condition_variable +//------------------------------------------------------------------------------ +// NOTE 1: The Win32 implementation of the condition_variable class is based on +// the corresponding implementation in GLFW, which in turn is based on a +// description by Douglas C. Schmidt and Irfan Pyarali: +// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html +// +// NOTE 2: Windows Vista actually has native support for condition variables +// (InitializeConditionVariable, WakeConditionVariable, etc), but we want to +// be portable with pre-Vista Windows versions, so TinyThread++ does not use +// Vista condition variables. +//------------------------------------------------------------------------------ + +#if defined(_TTHREAD_WIN32_) + #define _CONDITION_EVENT_ONE 0 + #define _CONDITION_EVENT_ALL 1 +#endif + +#if defined(_TTHREAD_WIN32_) +condition_variable::condition_variable() : mWaitersCount(0) +{ + mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); + mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); + InitializeCriticalSection(&mWaitersCountLock); +} +#endif + +#if defined(_TTHREAD_WIN32_) +condition_variable::~condition_variable() +{ + CloseHandle(mEvents[_CONDITION_EVENT_ONE]); + CloseHandle(mEvents[_CONDITION_EVENT_ALL]); + DeleteCriticalSection(&mWaitersCountLock); +} +#endif + +#if defined(_TTHREAD_WIN32_) +void condition_variable::_wait() +{ + // Wait for either event to become signaled due to notify_one() or + // notify_all() being called + int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE); + + // Check if we are the last waiter + EnterCriticalSection(&mWaitersCountLock); + -- mWaitersCount; + bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && + (mWaitersCount == 0); + LeaveCriticalSection(&mWaitersCountLock); + + // If we are the last waiter to be notified to stop waiting, reset the event + if(lastWaiter) + ResetEvent(mEvents[_CONDITION_EVENT_ALL]); +} +#endif + +#if defined(_TTHREAD_WIN32_) +void condition_variable::notify_one() +{ + // Are there any waiters? + EnterCriticalSection(&mWaitersCountLock); + bool haveWaiters = (mWaitersCount > 0); + LeaveCriticalSection(&mWaitersCountLock); + + // If we have any waiting threads, send them a signal + if(haveWaiters) + SetEvent(mEvents[_CONDITION_EVENT_ONE]); +} +#endif + +#if defined(_TTHREAD_WIN32_) +void condition_variable::notify_all() +{ + // Are there any waiters? + EnterCriticalSection(&mWaitersCountLock); + bool haveWaiters = (mWaitersCount > 0); + LeaveCriticalSection(&mWaitersCountLock); + + // If we have any waiting threads, send them a signal + if(haveWaiters) + SetEvent(mEvents[_CONDITION_EVENT_ALL]); +} +#endif + + +//------------------------------------------------------------------------------ +// POSIX pthread_t to unique thread::id mapping logic. +// Note: Here we use a global thread safe std::map to convert instances of +// pthread_t to small thread identifier numbers (unique within one process). +// This method should be portable across different POSIX implementations. +//------------------------------------------------------------------------------ + +#if defined(_TTHREAD_POSIX_) +static thread::id _pthread_t_to_ID(const pthread_t &aHandle) +{ + static mutex idMapLock; + static std::map idMap; + static unsigned long int idCount(1); + + lock_guard guard(idMapLock); + if(idMap.find(aHandle) == idMap.end()) + idMap[aHandle] = idCount ++; + return thread::id(idMap[aHandle]); +} +#endif // _TTHREAD_POSIX_ + + +//------------------------------------------------------------------------------ +// thread +//------------------------------------------------------------------------------ + +/// Information to pass to the new thread (what to run). +struct _thread_start_info { + void (*mFunction)(void *); ///< Pointer to the function to be executed. + void * mArg; ///< Function argument for the thread function. + thread * mThread; ///< Pointer to the thread object. +}; + +// Thread wrapper function. +#if defined(_TTHREAD_WIN32_) +unsigned WINAPI thread::wrapper_function(void * aArg) +#elif defined(_TTHREAD_POSIX_) +void * thread::wrapper_function(void * aArg) +#endif +{ + // Get thread startup information + _thread_start_info * ti = (_thread_start_info *) aArg; + + try + { + // Call the actual client thread function + ti->mFunction(ti->mArg); + } + catch(...) + { + // Uncaught exceptions will terminate the application (default behavior + // according to C++11) + std::terminate(); + } + + // The thread is no longer executing + lock_guard guard(ti->mThread->mDataMutex); + ti->mThread->mNotAThread = true; + + // The thread is responsible for freeing the startup information + delete ti; + + return 0; +} + +thread::thread(void (*aFunction)(void *), void * aArg) +{ + // Serialize access to this thread structure + lock_guard guard(mDataMutex); + + // Fill out the thread startup information (passed to the thread wrapper, + // which will eventually free it) + _thread_start_info * ti = new _thread_start_info; + ti->mFunction = aFunction; + ti->mArg = aArg; + ti->mThread = this; + + // The thread is now alive + mNotAThread = false; + + // Create the thread +#if defined(_TTHREAD_WIN32_) + mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID); +#elif defined(_TTHREAD_POSIX_) + if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0) + mHandle = 0; +#endif + + // Did we fail to create the thread? + if(!mHandle) + { + mNotAThread = true; + delete ti; + } +} + +thread::~thread() +{ + if(joinable()) + std::terminate(); +} + +void thread::join() +{ + if(joinable()) + { +#if defined(_TTHREAD_WIN32_) + WaitForSingleObject(mHandle, INFINITE); + CloseHandle(mHandle); +#elif defined(_TTHREAD_POSIX_) + pthread_join(mHandle, NULL); +#endif + } +} + +bool thread::joinable() const +{ + mDataMutex.lock(); + bool result = !mNotAThread; + mDataMutex.unlock(); + return result; +} + +void thread::detach() +{ + mDataMutex.lock(); + if(!mNotAThread) + { +#if defined(_TTHREAD_WIN32_) + CloseHandle(mHandle); +#elif defined(_TTHREAD_POSIX_) + pthread_detach(mHandle); +#endif + mNotAThread = true; + } + mDataMutex.unlock(); +} + +thread::id thread::get_id() const +{ + if(!joinable()) + return id(); +#if defined(_TTHREAD_WIN32_) + return id((unsigned long int) mWin32ThreadID); +#elif defined(_TTHREAD_POSIX_) + return _pthread_t_to_ID(mHandle); +#endif +} + +unsigned thread::hardware_concurrency() +{ +#if defined(_TTHREAD_WIN32_) + SYSTEM_INFO si; + GetSystemInfo(&si); + return (int) si.dwNumberOfProcessors; +#elif defined(_SC_NPROCESSORS_ONLN) + return (int) sysconf(_SC_NPROCESSORS_ONLN); +#elif defined(_SC_NPROC_ONLN) + return (int) sysconf(_SC_NPROC_ONLN); +#else + // The standard requires this function to return zero if the number of + // hardware cores could not be determined. + return 0; +#endif +} + + +//------------------------------------------------------------------------------ +// this_thread +//------------------------------------------------------------------------------ + +thread::id this_thread::get_id() +{ +#if defined(_TTHREAD_WIN32_) + return thread::id((unsigned long int) GetCurrentThreadId()); +#elif defined(_TTHREAD_POSIX_) + return _pthread_t_to_ID(pthread_self()); +#endif +} + +} diff --git a/ext/tinythread.h b/ext/tinythread.h index 956cf1d166..aed7b5856b 100644 --- a/ext/tinythread.h +++ b/ext/tinythread.h @@ -1,714 +1,714 @@ -/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- -Copyright (c) 2010-2012 Marcus Geelnard - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef _TINYTHREAD_H_ -#define _TINYTHREAD_H_ - -/// @file -/// @mainpage TinyThread++ API Reference -/// -/// @section intro_sec Introduction -/// TinyThread++ is a minimal, portable implementation of basic threading -/// classes for C++. -/// -/// They closely mimic the functionality and naming of the C++11 standard, and -/// should be easily replaceable with the corresponding std:: variants. -/// -/// @section port_sec Portability -/// The Win32 variant uses the native Win32 API for implementing the thread -/// classes, while for other systems, the POSIX threads API (pthread) is used. -/// -/// @section class_sec Classes -/// In order to mimic the threading API of the C++11 standard, subsets of -/// several classes are provided. The fundamental classes are: -/// @li tthread::thread -/// @li tthread::mutex -/// @li tthread::recursive_mutex -/// @li tthread::condition_variable -/// @li tthread::lock_guard -/// @li tthread::fast_mutex -/// -/// @section misc_sec Miscellaneous -/// The following special keywords are available: #thread_local. -/// -/// For more detailed information (including additional classes), browse the -/// different sections of this documentation. A good place to start is: -/// tinythread.h. - -// Which platform are we on? -#if !defined(_TTHREAD_PLATFORM_DEFINED_) - #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) - #define _TTHREAD_WIN32_ - #else - #define _TTHREAD_POSIX_ - #endif - #define _TTHREAD_PLATFORM_DEFINED_ -#endif - -// Platform specific includes -#if defined(_TTHREAD_WIN32_) - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #define __UNDEF_LEAN_AND_MEAN - #endif - #include - #ifdef __UNDEF_LEAN_AND_MEAN - #undef WIN32_LEAN_AND_MEAN - #undef __UNDEF_LEAN_AND_MEAN - #endif -#else - #include - #include - #include - #include -#endif - -// Generic includes -#include - -/// TinyThread++ version (major number). -#define TINYTHREAD_VERSION_MAJOR 1 -/// TinyThread++ version (minor number). -#define TINYTHREAD_VERSION_MINOR 1 -/// TinyThread++ version (full version). -#define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR) - -// Do we have a fully featured C++11 compiler? -#if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L)) - #define _TTHREAD_CPP11_ -#endif - -// ...at least partial C++11? -#if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) - #define _TTHREAD_CPP11_PARTIAL_ -#endif - -// Macro for disabling assignments of objects. -#ifdef _TTHREAD_CPP11_PARTIAL_ - #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ - name(const name&) = delete; \ - name& operator=(const name&) = delete; -#else - #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ - name(const name&); \ - name& operator=(const name&); -#endif - -/// @def thread_local -/// Thread local storage keyword. -/// A variable that is declared with the @c thread_local keyword makes the -/// value of the variable local to each thread (known as thread-local storage, -/// or TLS). Example usage: -/// @code -/// // This variable is local to each thread. -/// thread_local int variable; -/// @endcode -/// @note The @c thread_local keyword is a macro that maps to the corresponding -/// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard -/// allows for non-trivial types (e.g. classes with constructors and -/// destructors) to be declared with the @c thread_local keyword, most pre-C++11 -/// compilers only allow for trivial types (e.g. @c int). So, to guarantee -/// portable code, only use trivial types for thread local storage. -/// @note This directive is currently not supported on Mac OS X (it will give -/// a compiler error), since compile-time TLS is not supported in the Mac OS X -/// executable format. Also, some older versions of MinGW (before GCC 4.x) do -/// not support this directive. -/// @hideinitializer - -#if !defined(_TTHREAD_CPP11_) && !defined(thread_local) - #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) - #define thread_local __thread - #else - #define thread_local __declspec(thread) - #endif -#endif - - -/// Main name space for TinyThread++. -/// This namespace is more or less equivalent to the @c std namespace for the -/// C++11 thread classes. For instance, the tthread::mutex class corresponds to -/// the std::mutex class. -namespace tthread { - -/// Mutex class. -/// This is a mutual exclusion object for synchronizing access to shared -/// memory areas for several threads. The mutex is non-recursive (i.e. a -/// program may deadlock if the thread that owns a mutex object calls lock() -/// on that object). -/// @see recursive_mutex -class mutex { - public: - /// Constructor. - mutex() -#if defined(_TTHREAD_WIN32_) - : mAlreadyLocked(false) -#endif - { -#if defined(_TTHREAD_WIN32_) - InitializeCriticalSection(&mHandle); -#else - pthread_mutex_init(&mHandle, NULL); -#endif - } - - /// Destructor. - ~mutex() - { -#if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mHandle); -#else - pthread_mutex_destroy(&mHandle); -#endif - } - - /// Lock the mutex. - /// The method will block the calling thread until a lock on the mutex can - /// be obtained. The mutex remains locked until @c unlock() is called. - /// @see lock_guard - inline void lock() - { -#if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mHandle); - while(mAlreadyLocked) Sleep(1000); // Simulate deadlock... - mAlreadyLocked = true; -#else - pthread_mutex_lock(&mHandle); -#endif - } - - /// Try to lock the mutex. - /// The method will try to lock the mutex. If it fails, the function will - /// return immediately (non-blocking). - /// @return @c true if the lock was acquired, or @c false if the lock could - /// not be acquired. - inline bool try_lock() - { -#if defined(_TTHREAD_WIN32_) - bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); - if(ret && mAlreadyLocked) - { - LeaveCriticalSection(&mHandle); - ret = false; - } - return ret; -#else - return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; -#endif - } - - /// Unlock the mutex. - /// If any threads are waiting for the lock on this mutex, one of them will - /// be unblocked. - inline void unlock() - { -#if defined(_TTHREAD_WIN32_) - mAlreadyLocked = false; - LeaveCriticalSection(&mHandle); -#else - pthread_mutex_unlock(&mHandle); -#endif - } - - _TTHREAD_DISABLE_ASSIGNMENT(mutex) - - private: -#if defined(_TTHREAD_WIN32_) - CRITICAL_SECTION mHandle; - bool mAlreadyLocked; -#else - pthread_mutex_t mHandle; -#endif - - friend class condition_variable; -}; - -/// Recursive mutex class. -/// This is a mutual exclusion object for synchronizing access to shared -/// memory areas for several threads. The mutex is recursive (i.e. a thread -/// may lock the mutex several times, as long as it unlocks the mutex the same -/// number of times). -/// @see mutex -class recursive_mutex { - public: - /// Constructor. - recursive_mutex() - { -#if defined(_TTHREAD_WIN32_) - InitializeCriticalSection(&mHandle); -#else - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&mHandle, &attr); -#endif - } - - /// Destructor. - ~recursive_mutex() - { -#if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mHandle); -#else - pthread_mutex_destroy(&mHandle); -#endif - } - - /// Lock the mutex. - /// The method will block the calling thread until a lock on the mutex can - /// be obtained. The mutex remains locked until @c unlock() is called. - /// @see lock_guard - inline void lock() - { -#if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mHandle); -#else - pthread_mutex_lock(&mHandle); -#endif - } - - /// Try to lock the mutex. - /// The method will try to lock the mutex. If it fails, the function will - /// return immediately (non-blocking). - /// @return @c true if the lock was acquired, or @c false if the lock could - /// not be acquired. - inline bool try_lock() - { -#if defined(_TTHREAD_WIN32_) - return TryEnterCriticalSection(&mHandle) ? true : false; -#else - return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; -#endif - } - - /// Unlock the mutex. - /// If any threads are waiting for the lock on this mutex, one of them will - /// be unblocked. - inline void unlock() - { -#if defined(_TTHREAD_WIN32_) - LeaveCriticalSection(&mHandle); -#else - pthread_mutex_unlock(&mHandle); -#endif - } - - _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) - - private: -#if defined(_TTHREAD_WIN32_) - CRITICAL_SECTION mHandle; -#else - pthread_mutex_t mHandle; -#endif - - friend class condition_variable; -}; - -/// Lock guard class. -/// The constructor locks the mutex, and the destructor unlocks the mutex, so -/// the mutex will automatically be unlocked when the lock guard goes out of -/// scope. Example usage: -/// @code -/// mutex m; -/// int counter; -/// -/// void increment() -/// { -/// lock_guard guard(m); -/// ++ counter; -/// } -/// @endcode - -template -class lock_guard { - public: - typedef T mutex_type; - - lock_guard() : mMutex(0) {} - - /// The constructor locks the mutex. - explicit lock_guard(mutex_type &aMutex) - { - mMutex = &aMutex; - mMutex->lock(); - } - - /// The destructor unlocks the mutex. - ~lock_guard() - { - if(mMutex) - mMutex->unlock(); - } - - private: - mutex_type * mMutex; -}; - -/// Condition variable class. -/// This is a signalling object for synchronizing the execution flow for -/// several threads. Example usage: -/// @code -/// // Shared data and associated mutex and condition variable objects -/// int count; -/// mutex m; -/// condition_variable cond; -/// -/// // Wait for the counter to reach a certain number -/// void wait_counter(int targetCount) -/// { -/// lock_guard guard(m); -/// while(count < targetCount) -/// cond.wait(m); -/// } -/// -/// // Increment the counter, and notify waiting threads -/// void increment() -/// { -/// lock_guard guard(m); -/// ++ count; -/// cond.notify_all(); -/// } -/// @endcode -class condition_variable { - public: - /// Constructor. -#if defined(_TTHREAD_WIN32_) - condition_variable(); -#else - condition_variable() - { - pthread_cond_init(&mHandle, NULL); - } -#endif - - /// Destructor. -#if defined(_TTHREAD_WIN32_) - ~condition_variable(); -#else - ~condition_variable() - { - pthread_cond_destroy(&mHandle); - } -#endif - - /// Wait for the condition. - /// The function will block the calling thread until the condition variable - /// is woken by @c notify_one(), @c notify_all() or a spurious wake up. - /// @param[in] aMutex A mutex that will be unlocked when the wait operation - /// starts, an locked again as soon as the wait operation is finished. - template - inline void wait(_mutexT &aMutex) - { -#if defined(_TTHREAD_WIN32_) - // Increment number of waiters - EnterCriticalSection(&mWaitersCountLock); - ++ mWaitersCount; - LeaveCriticalSection(&mWaitersCountLock); - - // Release the mutex while waiting for the condition (will decrease - // the number of waiters when done)... - aMutex.unlock(); - _wait(); - aMutex.lock(); -#else - pthread_cond_wait(&mHandle, &aMutex.mHandle); -#endif - } - - /// Notify one thread that is waiting for the condition. - /// If at least one thread is blocked waiting for this condition variable, - /// one will be woken up. - /// @note Only threads that started waiting prior to this call will be - /// woken up. -#if defined(_TTHREAD_WIN32_) - void notify_one(); -#else - inline void notify_one() - { - pthread_cond_signal(&mHandle); - } -#endif - - /// Notify all threads that are waiting for the condition. - /// All threads that are blocked waiting for this condition variable will - /// be woken up. - /// @note Only threads that started waiting prior to this call will be - /// woken up. -#if defined(_TTHREAD_WIN32_) - void notify_all(); -#else - inline void notify_all() - { - pthread_cond_broadcast(&mHandle); - } -#endif - - _TTHREAD_DISABLE_ASSIGNMENT(condition_variable) - - private: -#if defined(_TTHREAD_WIN32_) - void _wait(); - HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs. - unsigned int mWaitersCount; ///< Count of the number of waiters. - CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount. -#else - pthread_cond_t mHandle; -#endif -}; - - -/// Thread class. -class thread { - public: -#if defined(_TTHREAD_WIN32_) - typedef HANDLE native_handle_type; -#else - typedef pthread_t native_handle_type; -#endif - - class id; - - /// Default constructor. - /// Construct a @c thread object without an associated thread of execution - /// (i.e. non-joinable). - thread() : mHandle(0), mNotAThread(true) -#if defined(_TTHREAD_WIN32_) - , mWin32ThreadID(0) -#endif - {} - - /// Thread starting constructor. - /// Construct a @c thread object with a new thread of execution. - /// @param[in] aFunction A function pointer to a function of type: - /// void fun(void * arg) - /// @param[in] aArg Argument to the thread function. - /// @note This constructor is not fully compatible with the standard C++ - /// thread class. It is more similar to the pthread_create() (POSIX) and - /// CreateThread() (Windows) functions. - thread(void (*aFunction)(void *), void * aArg); - - /// Destructor. - /// @note If the thread is joinable upon destruction, @c std::terminate() - /// will be called, which terminates the process. It is always wise to do - /// @c join() before deleting a thread object. - ~thread(); - - /// Wait for the thread to finish (join execution flows). - /// After calling @c join(), the thread object is no longer associated with - /// a thread of execution (i.e. it is not joinable, and you may not join - /// with it nor detach from it). - void join(); - - /// Check if the thread is joinable. - /// A thread object is joinable if it has an associated thread of execution. - bool joinable() const; - - /// Detach from the thread. - /// After calling @c detach(), the thread object is no longer assicated with - /// a thread of execution (i.e. it is not joinable). The thread continues - /// execution without the calling thread blocking, and when the thread - /// ends execution, any owned resources are released. - void detach(); - - /// Return the thread ID of a thread object. - id get_id() const; - - /// Get the native handle for this thread. - /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this - /// is a @c pthread_t. - inline native_handle_type native_handle() - { - return mHandle; - } - - /// Determine the number of threads which can possibly execute concurrently. - /// This function is useful for determining the optimal number of threads to - /// use for a task. - /// @return The number of hardware thread contexts in the system. - /// @note If this value is not defined, the function returns zero (0). - static unsigned hardware_concurrency(); - - _TTHREAD_DISABLE_ASSIGNMENT(thread) - - private: - native_handle_type mHandle; ///< Thread handle. - mutable mutex mDataMutex; ///< Serializer for access to the thread private data. - bool mNotAThread; ///< True if this object is not a thread of execution. -#if defined(_TTHREAD_WIN32_) - unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex). -#endif - - // This is the internal thread wrapper function. -#if defined(_TTHREAD_WIN32_) - static unsigned WINAPI wrapper_function(void * aArg); -#else - static void * wrapper_function(void * aArg); -#endif -}; - -/// Thread ID. -/// The thread ID is a unique identifier for each thread. -/// @see thread::get_id() -class thread::id { - public: - /// Default constructor. - /// The default constructed ID is that of thread without a thread of - /// execution. - id() : mId(0) {}; - - id(unsigned long int aId) : mId(aId) {}; - - id(const id& aId) : mId(aId.mId) {}; - - inline id & operator=(const id &aId) - { - mId = aId.mId; - return *this; - } - - inline friend bool operator==(const id &aId1, const id &aId2) - { - return (aId1.mId == aId2.mId); - } - - inline friend bool operator!=(const id &aId1, const id &aId2) - { - return (aId1.mId != aId2.mId); - } - - inline friend bool operator<=(const id &aId1, const id &aId2) - { - return (aId1.mId <= aId2.mId); - } - - inline friend bool operator<(const id &aId1, const id &aId2) - { - return (aId1.mId < aId2.mId); - } - - inline friend bool operator>=(const id &aId1, const id &aId2) - { - return (aId1.mId >= aId2.mId); - } - - inline friend bool operator>(const id &aId1, const id &aId2) - { - return (aId1.mId > aId2.mId); - } - - inline friend std::ostream& operator <<(std::ostream &os, const id &obj) - { - os << obj.mId; - return os; - } - - private: - unsigned long int mId; -}; - - -// Related to - minimal to be able to support chrono. -typedef long long __intmax_t; - -/// Minimal implementation of the @c ratio class. This class provides enough -/// functionality to implement some basic @c chrono classes. -template <__intmax_t N, __intmax_t D = 1> class ratio { - public: - static double _as_double() { return double(N) / double(D); } -}; - -/// Minimal implementation of the @c chrono namespace. -/// The @c chrono namespace provides types for specifying time intervals. -namespace chrono { - /// Duration template class. This class provides enough functionality to - /// implement @c this_thread::sleep_for(). - template > class duration { - private: - _Rep rep_; - public: - typedef _Rep rep; - typedef _Period period; - - /// Construct a duration object with the given duration. - template - explicit duration(const _Rep2& r) : rep_(r) {}; - - /// Return the value of the duration object. - rep count() const - { - return rep_; - } - }; - - // Standard duration types. - typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds. - typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds. - typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds. - typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds. - typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes. - typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours. -} - -/// The namespace @c this_thread provides methods for dealing with the -/// calling thread. -namespace this_thread { - /// Return the thread ID of the calling thread. - thread::id get_id(); - - /// Yield execution to another thread. - /// Offers the operating system the opportunity to schedule another thread - /// that is ready to run on the current processor. - inline void yield() - { -#if defined(_TTHREAD_WIN32_) - Sleep(0); -#else - sched_yield(); -#endif - } - - /// Blocks the calling thread for a period of time. - /// @param[in] aTime Minimum time to put the thread to sleep. - /// Example usage: - /// @code - /// // Sleep for 100 milliseconds - /// this_thread::sleep_for(chrono::milliseconds(100)); - /// @endcode - /// @note Supported duration types are: nanoseconds, microseconds, - /// milliseconds, seconds, minutes and hours. - template void sleep_for(const chrono::duration<_Rep, _Period>& aTime) - { -#if defined(_TTHREAD_WIN32_) - Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); -#else - usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); -#endif - } -} - -} - -// Define/macro cleanup -#undef _TTHREAD_DISABLE_ASSIGNMENT - -#endif // _TINYTHREAD_H_ +/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- +Copyright (c) 2010-2012 Marcus Geelnard + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef _TINYTHREAD_H_ +#define _TINYTHREAD_H_ + +/// @file +/// @mainpage TinyThread++ API Reference +/// +/// @section intro_sec Introduction +/// TinyThread++ is a minimal, portable implementation of basic threading +/// classes for C++. +/// +/// They closely mimic the functionality and naming of the C++11 standard, and +/// should be easily replaceable with the corresponding std:: variants. +/// +/// @section port_sec Portability +/// The Win32 variant uses the native Win32 API for implementing the thread +/// classes, while for other systems, the POSIX threads API (pthread) is used. +/// +/// @section class_sec Classes +/// In order to mimic the threading API of the C++11 standard, subsets of +/// several classes are provided. The fundamental classes are: +/// @li tthread::thread +/// @li tthread::mutex +/// @li tthread::recursive_mutex +/// @li tthread::condition_variable +/// @li tthread::lock_guard +/// @li tthread::fast_mutex +/// +/// @section misc_sec Miscellaneous +/// The following special keywords are available: #thread_local. +/// +/// For more detailed information (including additional classes), browse the +/// different sections of this documentation. A good place to start is: +/// tinythread.h. + +// Which platform are we on? +#if !defined(_TTHREAD_PLATFORM_DEFINED_) + #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) + #define _TTHREAD_WIN32_ + #else + #define _TTHREAD_POSIX_ + #endif + #define _TTHREAD_PLATFORM_DEFINED_ +#endif + +// Platform specific includes +#if defined(_TTHREAD_WIN32_) + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN + #define __UNDEF_LEAN_AND_MEAN + #endif + #include + #ifdef __UNDEF_LEAN_AND_MEAN + #undef WIN32_LEAN_AND_MEAN + #undef __UNDEF_LEAN_AND_MEAN + #endif +#else + #include + #include + #include + #include +#endif + +// Generic includes +#include + +/// TinyThread++ version (major number). +#define TINYTHREAD_VERSION_MAJOR 1 +/// TinyThread++ version (minor number). +#define TINYTHREAD_VERSION_MINOR 1 +/// TinyThread++ version (full version). +#define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR) + +// Do we have a fully featured C++11 compiler? +#if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L)) + #define _TTHREAD_CPP11_ +#endif + +// ...at least partial C++11? +#if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) + #define _TTHREAD_CPP11_PARTIAL_ +#endif + +// Macro for disabling assignments of objects. +#ifdef _TTHREAD_CPP11_PARTIAL_ + #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ + name(const name&) = delete; \ + name& operator=(const name&) = delete; +#else + #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ + name(const name&); \ + name& operator=(const name&); +#endif + +/// @def thread_local +/// Thread local storage keyword. +/// A variable that is declared with the @c thread_local keyword makes the +/// value of the variable local to each thread (known as thread-local storage, +/// or TLS). Example usage: +/// @code +/// // This variable is local to each thread. +/// thread_local int variable; +/// @endcode +/// @note The @c thread_local keyword is a macro that maps to the corresponding +/// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard +/// allows for non-trivial types (e.g. classes with constructors and +/// destructors) to be declared with the @c thread_local keyword, most pre-C++11 +/// compilers only allow for trivial types (e.g. @c int). So, to guarantee +/// portable code, only use trivial types for thread local storage. +/// @note This directive is currently not supported on Mac OS X (it will give +/// a compiler error), since compile-time TLS is not supported in the Mac OS X +/// executable format. Also, some older versions of MinGW (before GCC 4.x) do +/// not support this directive. +/// @hideinitializer + +#if !defined(_TTHREAD_CPP11_) && !defined(thread_local) + #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) + #define thread_local __thread + #else + #define thread_local __declspec(thread) + #endif +#endif + + +/// Main name space for TinyThread++. +/// This namespace is more or less equivalent to the @c std namespace for the +/// C++11 thread classes. For instance, the tthread::mutex class corresponds to +/// the std::mutex class. +namespace tthread { + +/// Mutex class. +/// This is a mutual exclusion object for synchronizing access to shared +/// memory areas for several threads. The mutex is non-recursive (i.e. a +/// program may deadlock if the thread that owns a mutex object calls lock() +/// on that object). +/// @see recursive_mutex +class mutex { + public: + /// Constructor. + mutex() +#if defined(_TTHREAD_WIN32_) + : mAlreadyLocked(false) +#endif + { +#if defined(_TTHREAD_WIN32_) + InitializeCriticalSection(&mHandle); +#else + pthread_mutex_init(&mHandle, NULL); +#endif + } + + /// Destructor. + ~mutex() + { +#if defined(_TTHREAD_WIN32_) + DeleteCriticalSection(&mHandle); +#else + pthread_mutex_destroy(&mHandle); +#endif + } + + /// Lock the mutex. + /// The method will block the calling thread until a lock on the mutex can + /// be obtained. The mutex remains locked until @c unlock() is called. + /// @see lock_guard + inline void lock() + { +#if defined(_TTHREAD_WIN32_) + EnterCriticalSection(&mHandle); + while(mAlreadyLocked) Sleep(1000); // Simulate deadlock... + mAlreadyLocked = true; +#else + pthread_mutex_lock(&mHandle); +#endif + } + + /// Try to lock the mutex. + /// The method will try to lock the mutex. If it fails, the function will + /// return immediately (non-blocking). + /// @return @c true if the lock was acquired, or @c false if the lock could + /// not be acquired. + inline bool try_lock() + { +#if defined(_TTHREAD_WIN32_) + bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); + if(ret && mAlreadyLocked) + { + LeaveCriticalSection(&mHandle); + ret = false; + } + return ret; +#else + return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; +#endif + } + + /// Unlock the mutex. + /// If any threads are waiting for the lock on this mutex, one of them will + /// be unblocked. + inline void unlock() + { +#if defined(_TTHREAD_WIN32_) + mAlreadyLocked = false; + LeaveCriticalSection(&mHandle); +#else + pthread_mutex_unlock(&mHandle); +#endif + } + + _TTHREAD_DISABLE_ASSIGNMENT(mutex) + + private: +#if defined(_TTHREAD_WIN32_) + CRITICAL_SECTION mHandle; + bool mAlreadyLocked; +#else + pthread_mutex_t mHandle; +#endif + + friend class condition_variable; +}; + +/// Recursive mutex class. +/// This is a mutual exclusion object for synchronizing access to shared +/// memory areas for several threads. The mutex is recursive (i.e. a thread +/// may lock the mutex several times, as long as it unlocks the mutex the same +/// number of times). +/// @see mutex +class recursive_mutex { + public: + /// Constructor. + recursive_mutex() + { +#if defined(_TTHREAD_WIN32_) + InitializeCriticalSection(&mHandle); +#else + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mHandle, &attr); +#endif + } + + /// Destructor. + ~recursive_mutex() + { +#if defined(_TTHREAD_WIN32_) + DeleteCriticalSection(&mHandle); +#else + pthread_mutex_destroy(&mHandle); +#endif + } + + /// Lock the mutex. + /// The method will block the calling thread until a lock on the mutex can + /// be obtained. The mutex remains locked until @c unlock() is called. + /// @see lock_guard + inline void lock() + { +#if defined(_TTHREAD_WIN32_) + EnterCriticalSection(&mHandle); +#else + pthread_mutex_lock(&mHandle); +#endif + } + + /// Try to lock the mutex. + /// The method will try to lock the mutex. If it fails, the function will + /// return immediately (non-blocking). + /// @return @c true if the lock was acquired, or @c false if the lock could + /// not be acquired. + inline bool try_lock() + { +#if defined(_TTHREAD_WIN32_) + return TryEnterCriticalSection(&mHandle) ? true : false; +#else + return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; +#endif + } + + /// Unlock the mutex. + /// If any threads are waiting for the lock on this mutex, one of them will + /// be unblocked. + inline void unlock() + { +#if defined(_TTHREAD_WIN32_) + LeaveCriticalSection(&mHandle); +#else + pthread_mutex_unlock(&mHandle); +#endif + } + + _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) + + private: +#if defined(_TTHREAD_WIN32_) + CRITICAL_SECTION mHandle; +#else + pthread_mutex_t mHandle; +#endif + + friend class condition_variable; +}; + +/// Lock guard class. +/// The constructor locks the mutex, and the destructor unlocks the mutex, so +/// the mutex will automatically be unlocked when the lock guard goes out of +/// scope. Example usage: +/// @code +/// mutex m; +/// int counter; +/// +/// void increment() +/// { +/// lock_guard guard(m); +/// ++ counter; +/// } +/// @endcode + +template +class lock_guard { + public: + typedef T mutex_type; + + lock_guard() : mMutex(0) {} + + /// The constructor locks the mutex. + explicit lock_guard(mutex_type &aMutex) + { + mMutex = &aMutex; + mMutex->lock(); + } + + /// The destructor unlocks the mutex. + ~lock_guard() + { + if(mMutex) + mMutex->unlock(); + } + + private: + mutex_type * mMutex; +}; + +/// Condition variable class. +/// This is a signalling object for synchronizing the execution flow for +/// several threads. Example usage: +/// @code +/// // Shared data and associated mutex and condition variable objects +/// int count; +/// mutex m; +/// condition_variable cond; +/// +/// // Wait for the counter to reach a certain number +/// void wait_counter(int targetCount) +/// { +/// lock_guard guard(m); +/// while(count < targetCount) +/// cond.wait(m); +/// } +/// +/// // Increment the counter, and notify waiting threads +/// void increment() +/// { +/// lock_guard guard(m); +/// ++ count; +/// cond.notify_all(); +/// } +/// @endcode +class condition_variable { + public: + /// Constructor. +#if defined(_TTHREAD_WIN32_) + condition_variable(); +#else + condition_variable() + { + pthread_cond_init(&mHandle, NULL); + } +#endif + + /// Destructor. +#if defined(_TTHREAD_WIN32_) + ~condition_variable(); +#else + ~condition_variable() + { + pthread_cond_destroy(&mHandle); + } +#endif + + /// Wait for the condition. + /// The function will block the calling thread until the condition variable + /// is woken by @c notify_one(), @c notify_all() or a spurious wake up. + /// @param[in] aMutex A mutex that will be unlocked when the wait operation + /// starts, an locked again as soon as the wait operation is finished. + template + inline void wait(_mutexT &aMutex) + { +#if defined(_TTHREAD_WIN32_) + // Increment number of waiters + EnterCriticalSection(&mWaitersCountLock); + ++ mWaitersCount; + LeaveCriticalSection(&mWaitersCountLock); + + // Release the mutex while waiting for the condition (will decrease + // the number of waiters when done)... + aMutex.unlock(); + _wait(); + aMutex.lock(); +#else + pthread_cond_wait(&mHandle, &aMutex.mHandle); +#endif + } + + /// Notify one thread that is waiting for the condition. + /// If at least one thread is blocked waiting for this condition variable, + /// one will be woken up. + /// @note Only threads that started waiting prior to this call will be + /// woken up. +#if defined(_TTHREAD_WIN32_) + void notify_one(); +#else + inline void notify_one() + { + pthread_cond_signal(&mHandle); + } +#endif + + /// Notify all threads that are waiting for the condition. + /// All threads that are blocked waiting for this condition variable will + /// be woken up. + /// @note Only threads that started waiting prior to this call will be + /// woken up. +#if defined(_TTHREAD_WIN32_) + void notify_all(); +#else + inline void notify_all() + { + pthread_cond_broadcast(&mHandle); + } +#endif + + _TTHREAD_DISABLE_ASSIGNMENT(condition_variable) + + private: +#if defined(_TTHREAD_WIN32_) + void _wait(); + HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs. + unsigned int mWaitersCount; ///< Count of the number of waiters. + CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount. +#else + pthread_cond_t mHandle; +#endif +}; + + +/// Thread class. +class thread { + public: +#if defined(_TTHREAD_WIN32_) + typedef HANDLE native_handle_type; +#else + typedef pthread_t native_handle_type; +#endif + + class id; + + /// Default constructor. + /// Construct a @c thread object without an associated thread of execution + /// (i.e. non-joinable). + thread() : mHandle(0), mNotAThread(true) +#if defined(_TTHREAD_WIN32_) + , mWin32ThreadID(0) +#endif + {} + + /// Thread starting constructor. + /// Construct a @c thread object with a new thread of execution. + /// @param[in] aFunction A function pointer to a function of type: + /// void fun(void * arg) + /// @param[in] aArg Argument to the thread function. + /// @note This constructor is not fully compatible with the standard C++ + /// thread class. It is more similar to the pthread_create() (POSIX) and + /// CreateThread() (Windows) functions. + thread(void (*aFunction)(void *), void * aArg); + + /// Destructor. + /// @note If the thread is joinable upon destruction, @c std::terminate() + /// will be called, which terminates the process. It is always wise to do + /// @c join() before deleting a thread object. + ~thread(); + + /// Wait for the thread to finish (join execution flows). + /// After calling @c join(), the thread object is no longer associated with + /// a thread of execution (i.e. it is not joinable, and you may not join + /// with it nor detach from it). + void join(); + + /// Check if the thread is joinable. + /// A thread object is joinable if it has an associated thread of execution. + bool joinable() const; + + /// Detach from the thread. + /// After calling @c detach(), the thread object is no longer assicated with + /// a thread of execution (i.e. it is not joinable). The thread continues + /// execution without the calling thread blocking, and when the thread + /// ends execution, any owned resources are released. + void detach(); + + /// Return the thread ID of a thread object. + id get_id() const; + + /// Get the native handle for this thread. + /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this + /// is a @c pthread_t. + inline native_handle_type native_handle() + { + return mHandle; + } + + /// Determine the number of threads which can possibly execute concurrently. + /// This function is useful for determining the optimal number of threads to + /// use for a task. + /// @return The number of hardware thread contexts in the system. + /// @note If this value is not defined, the function returns zero (0). + static unsigned hardware_concurrency(); + + _TTHREAD_DISABLE_ASSIGNMENT(thread) + + private: + native_handle_type mHandle; ///< Thread handle. + mutable mutex mDataMutex; ///< Serializer for access to the thread private data. + bool mNotAThread; ///< True if this object is not a thread of execution. +#if defined(_TTHREAD_WIN32_) + unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex). +#endif + + // This is the internal thread wrapper function. +#if defined(_TTHREAD_WIN32_) + static unsigned WINAPI wrapper_function(void * aArg); +#else + static void * wrapper_function(void * aArg); +#endif +}; + +/// Thread ID. +/// The thread ID is a unique identifier for each thread. +/// @see thread::get_id() +class thread::id { + public: + /// Default constructor. + /// The default constructed ID is that of thread without a thread of + /// execution. + id() : mId(0) {}; + + id(unsigned long int aId) : mId(aId) {}; + + id(const id& aId) : mId(aId.mId) {}; + + inline id & operator=(const id &aId) + { + mId = aId.mId; + return *this; + } + + inline friend bool operator==(const id &aId1, const id &aId2) + { + return (aId1.mId == aId2.mId); + } + + inline friend bool operator!=(const id &aId1, const id &aId2) + { + return (aId1.mId != aId2.mId); + } + + inline friend bool operator<=(const id &aId1, const id &aId2) + { + return (aId1.mId <= aId2.mId); + } + + inline friend bool operator<(const id &aId1, const id &aId2) + { + return (aId1.mId < aId2.mId); + } + + inline friend bool operator>=(const id &aId1, const id &aId2) + { + return (aId1.mId >= aId2.mId); + } + + inline friend bool operator>(const id &aId1, const id &aId2) + { + return (aId1.mId > aId2.mId); + } + + inline friend std::ostream& operator <<(std::ostream &os, const id &obj) + { + os << obj.mId; + return os; + } + + private: + unsigned long int mId; +}; + + +// Related to - minimal to be able to support chrono. +typedef long long __intmax_t; + +/// Minimal implementation of the @c ratio class. This class provides enough +/// functionality to implement some basic @c chrono classes. +template <__intmax_t N, __intmax_t D = 1> class ratio { + public: + static double _as_double() { return double(N) / double(D); } +}; + +/// Minimal implementation of the @c chrono namespace. +/// The @c chrono namespace provides types for specifying time intervals. +namespace chrono { + /// Duration template class. This class provides enough functionality to + /// implement @c this_thread::sleep_for(). + template > class duration { + private: + _Rep rep_; + public: + typedef _Rep rep; + typedef _Period period; + + /// Construct a duration object with the given duration. + template + explicit duration(const _Rep2& r) : rep_(r) {}; + + /// Return the value of the duration object. + rep count() const + { + return rep_; + } + }; + + // Standard duration types. + typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds. + typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds. + typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds. + typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds. + typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes. + typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours. +} + +/// The namespace @c this_thread provides methods for dealing with the +/// calling thread. +namespace this_thread { + /// Return the thread ID of the calling thread. + thread::id get_id(); + + /// Yield execution to another thread. + /// Offers the operating system the opportunity to schedule another thread + /// that is ready to run on the current processor. + inline void yield() + { +#if defined(_TTHREAD_WIN32_) + Sleep(0); +#else + sched_yield(); +#endif + } + + /// Blocks the calling thread for a period of time. + /// @param[in] aTime Minimum time to put the thread to sleep. + /// Example usage: + /// @code + /// // Sleep for 100 milliseconds + /// this_thread::sleep_for(chrono::milliseconds(100)); + /// @endcode + /// @note Supported duration types are: nanoseconds, microseconds, + /// milliseconds, seconds, minutes and hours. + template void sleep_for(const chrono::duration<_Rep, _Period>& aTime) + { +#if defined(_TTHREAD_WIN32_) + Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); +#else + usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); +#endif + } +} + +} + +// Define/macro cleanup +#undef _TTHREAD_DISABLE_ASSIGNMENT + +#endif // _TINYTHREAD_H_ diff --git a/include/openspace/engine/configurationmanager.h b/include/openspace/engine/configurationmanager.h index 8ec3aa167d..cb8d87a35e 100644 --- a/include/openspace/engine/configurationmanager.h +++ b/include/openspace/engine/configurationmanager.h @@ -1,4 +1,4 @@ -/***************************************************************************************** +/***************************************************************************************** * * * OpenSpace * * * @@ -78,12 +78,16 @@ public: static const std::string KeySettingsScript; /// The key that stores the settings for determining log-related settings static const std::string KeyLogging; + /// The key that stores the directory for Logging + static const std::string PartLogDir; /// The key that stores the desired LogLevel for the whole application /// \sa ghoul::logging::LogManager static const std::string PartLogLevel; /// The key that stores whether the log should be immediately flushed after a n /// \sa ghoul::logging::LogManager static const std::string PartImmediateFlush; + /// The key for prefixing PerformanceMeasurement logfiles + static const std::string PartLogPerformancePrefix; /// The key that stores a subdirectory with a description for additional /// ghoul::logging::Log%s to be created /// \sa LogFactory @@ -144,6 +148,11 @@ public: static const std::string PartFilterIdentifierIdentifier; /// The part of the key storing a list of severities that should be filtered out static const std::string PartFilterSeverity; + /// The part of the key storing whether the OpenGL state should be checked each call + static const std::string KeyCheckOpenGLState; + /// The part of the key storing whether each OpenGL call should be logged + static const std::string KeyLogEachOpenGLCall; + /** * Iteratively walks the directory structure starting with \p filename to find the diff --git a/include/openspace/engine/moduleengine.h b/include/openspace/engine/moduleengine.h index aaf46f8f5a..08a9c663c3 100644 --- a/include/openspace/engine/moduleengine.h +++ b/include/openspace/engine/moduleengine.h @@ -97,7 +97,7 @@ public: ModuleSubClass* module() const { auto it = std::find_if(_modules.begin(), _modules.end(), [](const std::unique_ptr& module) { - return module->name() == ModuleSubClass::name; + return module->name() == ModuleSubClass::Name; }); if (it != _modules.end()) { return dynamic_cast(it->get()); diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 2ba32d7fb5..d27782114c 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -64,7 +64,10 @@ class SyncEngine; class TimeManager; class WindowWrapper; -namespace interaction { class InteractionHandler; } +namespace interaction { + class NavigationHandler; + class KeyBindingManager; +} namespace gui { class GUI; } namespace properties { class PropertyOwner; } namespace scripting { @@ -98,7 +101,7 @@ public: void charCallback(unsigned int codepoint, KeyModifier mod); void mouseButtonCallback(MouseButton button, MouseAction action); void mousePositionCallback(double x, double y); - void mouseScrollWheelCallback(double pos); + void mouseScrollWheelCallback(double posX, double posY); void externalControlCallback(const char* receivedChars, int size, int clientId); void encode(); void decode(); @@ -124,7 +127,8 @@ public: WindowWrapper& windowWrapper(); AssetLoader& assetLoader(); ghoul::fontrendering::FontManager& fontManager(); - interaction::InteractionHandler& interactionHandler(); + interaction::NavigationHandler& navigationHandler(); + interaction::KeyBindingManager& keyBindingManager(); properties::PropertyOwner& globalPropertyOwner(); scripting::ScriptEngine& scriptEngine(); scripting::ScriptScheduler& scriptScheduler(); @@ -163,7 +167,9 @@ public: std::function function); // Registers a callback that is called when a scroll wheel change is received - void registerModuleMouseScrollWheelCallback(std::function function); + void registerModuleMouseScrollWheelCallback( + std::function function + ); /** * Returns the Lua library that contains all Lua functions available to affect the @@ -197,7 +203,8 @@ private: std::unique_ptr _windowWrapper; std::unique_ptr _commandlineParser; std::unique_ptr _fontManager; - std::unique_ptr _interactionHandler; + std::unique_ptr _navigationHandler; + std::unique_ptr _keyBindingManager; std::unique_ptr _scriptEngine; std::unique_ptr _scriptScheduler; std::unique_ptr _virtualPropertyManager; @@ -225,7 +232,7 @@ private: std::vector> mouseButton; std::vector> mousePosition; - std::vector> mouseScrollWheel; + std::vector> mouseScrollWheel; } _moduleCallbacks; double _runTime; diff --git a/include/openspace/interaction/controller.h b/include/openspace/interaction/controller.h index 4e262a0287..baa63c12a3 100644 --- a/include/openspace/interaction/controller.h +++ b/include/openspace/interaction/controller.h @@ -33,7 +33,7 @@ namespace openspace { namespace interaction { -class InteractionHandler; +class NavigationHandler; class Controller { public: @@ -41,10 +41,10 @@ public: _handler(nullptr) {} - void setHandler(InteractionHandler* handler); + void setHandler(NavigationHandler* handler); protected: - InteractionHandler* _handler; + NavigationHandler* _handler; }; } // namespace interaction diff --git a/include/openspace/interaction/delayedvariable.h b/include/openspace/interaction/delayedvariable.h new file mode 100644 index 0000000000..ad8b7e039e --- /dev/null +++ b/include/openspace/interaction/delayedvariable.h @@ -0,0 +1,59 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___DELAYEDVARIABLE___H__ +#define __OPENSPACE_CORE___DELAYEDVARIABLE___H__ + +namespace openspace { +namespace interaction { + +/** + * Class that acts as a smoothing filter to a variable. The filter has a step + * response on a form that resembles the function y = 1-e^(-t/scale). The variable + * will be updated as soon as it is set to a value (calling the set() function). +*/ +template +class DelayedVariable { +public: + DelayedVariable(ScaleType scaleFactor, ScaleType friction); + void set(T value, double dt); + void decelerate(double dt); + void setHard(T value); + void setFriction(ScaleType friction); + void setScaleFactor(ScaleType scaleFactor); + T get() const; + +private: + ScaleType _scaleFactor; + ScaleType _friction; + T _targetValue; + T _currentValue; +}; + +} // namespace interaction +} // namespace openspace + +#include "delayedvariable.inl" + +#endif // __OPENSPACE_CORE___DELAYEDVARIABLE___H__ diff --git a/include/openspace/interaction/delayedvariable.inl b/include/openspace/interaction/delayedvariable.inl new file mode 100644 index 0000000000..03e8137f13 --- /dev/null +++ b/include/openspace/interaction/delayedvariable.inl @@ -0,0 +1,76 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include + +namespace openspace { +namespace interaction { + +template +DelayedVariable::DelayedVariable(ScaleType scaleFactor, ScaleType friction) + : _scaleFactor(std::move(scaleFactor)) + , _friction(friction) +{ + ghoul_assert(_friction >= ScaleType(0.0), "Friction must be positive"); +} + +template +void DelayedVariable::set(T value, double dt) { + _targetValue = value; + _currentValue = _currentValue + (_targetValue - _currentValue) * + glm::min(_scaleFactor * dt, 1.0); // less or equal to 1.0 keeps it stable +} + +template +void DelayedVariable::decelerate(double dt) { + _currentValue = _currentValue + (- _currentValue) * + glm::min(_scaleFactor * _friction * dt, 1.0); + // less or equal to 1.0 keeps it stable +} + +template +void DelayedVariable::setHard(T value) { + _targetValue = value; + _currentValue = value; +} + +template +void DelayedVariable::setFriction(ScaleType friction) { + _friction = friction; + ghoul_assert(_friction >= ScaleType(0.0), "Friction must be positive"); +} + +template +void DelayedVariable::setScaleFactor(ScaleType scaleFactor) { + _scaleFactor = scaleFactor; +} + +template +T DelayedVariable::get() const { + return _currentValue; +} + +} // namespace interaction +} // namespace openspace diff --git a/include/openspace/interaction/inputstate.h b/include/openspace/interaction/inputstate.h new file mode 100644 index 0000000000..250a51743a --- /dev/null +++ b/include/openspace/interaction/inputstate.h @@ -0,0 +1,70 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___INPUTSTATE___H__ +#define __OPENSPACE_CORE___INPUTSTATE___H__ + +#include +#include + +#include + +#include + +namespace openspace { +namespace interaction { + +class InputState { +public: + InputState() = default; + ~InputState() = default; + + // Callback functions + void keyboardCallback(Key key, KeyModifier modifier, KeyAction action); + void mouseButtonCallback(MouseButton button, MouseAction action); + void mousePositionCallback(double mouseX, double mouseY); + void mouseScrollWheelCallback(double mouseScrollDelta); + + // Accessors + const std::list>& getPressedKeys() const; + const std::list& getPressedMouseButtons() const; + glm::dvec2 getMousePosition() const; + double getMouseScrollDelta() const; + + bool isKeyPressed(std::pair keyModPair) const; + bool isKeyPressed(Key key) const; + bool isMouseButtonPressed(MouseButton mouseButton) const; + +private: + // Input from keyboard and mouse + std::list> _keysDown; + std::list _mouseButtonsDown; + glm::dvec2 _mousePosition; + double _mouseScrollDelta; +}; + +} // namespace interaction +} // namespace openspace + +#endif // __OPENSPACE_CORE___INPUTSTATE___H__ diff --git a/include/openspace/interaction/interactionmode.h b/include/openspace/interaction/interactionmode.h deleted file mode 100644 index dc99ec1498..0000000000 --- a/include/openspace/interaction/interactionmode.h +++ /dev/null @@ -1,286 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_CORE___INTERACTIONMODE___H__ -#define __OPENSPACE_CORE___INTERACTIONMODE___H__ - -#include -#include -#include -#include - -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED -#include -#include -#include -#endif - -#include - -namespace openspace { - -class Camera; -class SceneGraphNode; - -namespace globebrowsing { - class RenderableGlobe; -} - -namespace interaction { - - template - class Interpolator - { - public: - Interpolator(std::function transferFunction) - : _t(0.0) - , _transferFunction(transferFunction) {}; - ~Interpolator() {}; - - void start() { _t = 0.0; }; - void end() { _t = 1.0; }; - void step(double delta) { _t += delta; }; - - T value() { return _transferFunction(_t); }; - bool isInterpolating() { return _t < 1.0; }; - private: - std::function _transferFunction; - double _t; - }; - - class InputState - { - public: - InputState(); - ~InputState(); - - // Callback functions - void keyboardCallback(Key key, KeyModifier modifier, KeyAction action); - void mouseButtonCallback(MouseButton button, MouseAction action); - void mousePositionCallback(double mouseX, double mouseY); - void mouseScrollWheelCallback(double mouseScrollDelta); - - // Accessors - const std::list >& getPressedKeys() const; - const std::list& getPressedMouseButtons() const; - glm::dvec2 getMousePosition() const; - double getMouseScrollDelta() const; - const std::vector& keyframes() const; - - bool isKeyPressed(std::pair keyModPair) const; - bool isKeyPressed(Key key) const; - bool isMouseButtonPressed(MouseButton mouseButton) const; - private: - // Input from keyboard and mouse - std::list > _keysDown; - std::list _mouseButtonsDown; - glm::dvec2 _mousePosition; - double _mouseScrollDelta; - }; - - - -class InteractionMode { -public: - InteractionMode(); - virtual ~InteractionMode(); - - // Mutators - virtual void setFocusNode(SceneGraphNode* focusNode); - - // Accessors - SceneGraphNode* focusNode(); - Interpolator& rotateToFocusNodeInterpolator(); - virtual bool followingNodeRotation() const = 0; - - virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime) = 0; - virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime) = 0; - -protected: - /** - Inner class that acts as a smoothing filter to a variable. The filter has a step - response on a form that resembles the function y = 1-e^(-t/scale). The variable - will be updates as soon as it is set to a value (calling the set() function). - */ - template - class DelayedVariable { - public: - DelayedVariable(ScaleType scaleFactor, ScaleType friction) { - _scaleFactor = scaleFactor; - _friction = glm::max(friction, ScaleType(0.0)); - } - void set(T value, double dt) { - _targetValue = value; - _currentValue = _currentValue + (_targetValue - _currentValue) * - std::min(_scaleFactor * dt, 1.0); // less or equal to 1.0 keeps it stable - } - void decelerate(double dt) { - _currentValue = _currentValue + (- _currentValue) * - std::min(_scaleFactor * _friction * dt, 1.0); // less or equal to 1.0 keeps it stable - } - void setHard(T value) { - _targetValue = value; - _currentValue = value; - } - void setFriction(ScaleType friction) { - _friction = glm::max(friction, ScaleType(0.0)); - } - void setScaleFactor(ScaleType scaleFactor) { - _scaleFactor = scaleFactor; - } - T get() { - return _currentValue; - } - private: - ScaleType _scaleFactor; - ScaleType _friction; - T _targetValue; - T _currentValue; - }; - - struct MouseState { - MouseState(double scaleFactor) - : velocity(scaleFactor, 1) - , previousPosition(0.0, 0.0) {} - void setFriction(double friction) { - velocity.setFriction(friction); - } - void setVelocityScaleFactor(double scaleFactor) { - velocity.setScaleFactor(scaleFactor); - } - glm::dvec2 previousPosition; - DelayedVariable velocity; - }; - - SceneGraphNode* _focusNode = nullptr; - glm::dvec3 _previousFocusNodePosition; - glm::dquat _previousFocusNodeRotation; - - - Interpolator _rotateToFocusNodeInterpolator; -}; - -class KeyframeInteractionMode : public InteractionMode -{ -public: - struct CameraPose { - glm::dvec3 position; - glm::quat rotation; - std::string focusNode; - bool followFocusNodeRotation; - }; - - KeyframeInteractionMode(); - ~KeyframeInteractionMode(); - - virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); - virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); - bool followingNodeRotation() const override; - Timeline& timeline(); - -private: - Timeline _cameraPoseTimeline; -}; - -class GlobeBrowsingInteractionMode; - -class OrbitalInteractionMode : public InteractionMode -{ -public: - class MouseStates - { - public: - /** - \param sensitivity - \param velocityScaleFactor can be set to 60 to remove the inertia of the - interaction. Lower value will make it harder to move the camera. - */ - MouseStates(double sensitivity, double velocityScaleFactor); - void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); - void setRotationalFriction(double friction); - void setHorizontalFriction(double friction); - void setVerticalFriction(double friction); - void setSensitivity(double sensitivity); - void setVelocityScaleFactor(double scaleFactor); - - glm::dvec2 synchedGlobalRotationMouseVelocity(); - glm::dvec2 synchedLocalRotationMouseVelocity(); - glm::dvec2 synchedTruckMovementMouseVelocity(); - glm::dvec2 synchedLocalRollMouseVelocity(); - glm::dvec2 synchedGlobalRollMouseVelocity(); - - private: - double _sensitivity; - - MouseState _globalRotationMouseState; - MouseState _localRotationMouseState; - MouseState _truckMovementMouseState; - MouseState _localRollMouseState; - MouseState _globalRollMouseState; - }; - - OrbitalInteractionMode(std::shared_ptr mouseStates); - ~OrbitalInteractionMode(); - - //virtual void update(Camera& camera, const InputState& inputState, double deltaTime); - - virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); - virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); - bool followingNodeRotation() const override; - -protected: - //void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); - std::shared_ptr _mouseStates; -}; - -class GlobeBrowsingInteractionMode : public OrbitalInteractionMode -{ -public: - GlobeBrowsingInteractionMode(std::shared_ptr mouseStates); - ~GlobeBrowsingInteractionMode(); - - virtual void setFocusNode(SceneGraphNode* focusNode); - //virtual void update(Camera& camera, const InputState& inputState, double deltaTime); - virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); - bool followingNodeRotation() const override; -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - void goToChunk(Camera& camera, globebrowsing::TileIndex ti, glm::vec2 uv, - bool resetCameraDirection); - void goToGeodetic2(Camera& camera, globebrowsing::Geodetic2 geo2, - bool resetCameraDirection); - - void goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3); - void resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2); -#endif -private: - //void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - globebrowsing::RenderableGlobe* _globe; -#endif -}; - -} // namespace interaction -} // namespace openspace - -#endif // __OPENSPACE_CORE___INTERACTIONMODE___H__ diff --git a/include/openspace/interaction/interpolator.h b/include/openspace/interaction/interpolator.h new file mode 100644 index 0000000000..cf4bafb25d --- /dev/null +++ b/include/openspace/interaction/interpolator.h @@ -0,0 +1,65 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___INTERPOLATOR___H__ +#define __OPENSPACE_CORE___INTERPOLATOR___H__ + +#include + +namespace openspace { +namespace interaction { + +/* + * Interpolates a typename T using a transfer function. + */ +template +class Interpolator { +public: + Interpolator(); + ~Interpolator() = default; + + void start(); + void end(); + void setDeltaTime(float deltaTime); + void setTransferFunction(std::function transferFunction); + void setInterpolationTime(float interpolationTime); + void step(); + + float deltaTimeScaled() const; + T value() const; + bool isInterpolating() const; + +private: + std::function _transferFunction; + float _t; + float _interpolationTime; + float _scaledDeltaTime; +}; + +} // namespace interaction +} // namespace openspace + +#include "interpolator.inl" + +#endif // __OPENSPACE_CORE___INTERPOLATOR___H__ diff --git a/include/openspace/interaction/interpolator.inl b/include/openspace/interaction/interpolator.inl new file mode 100644 index 0000000000..c9ad0ed612 --- /dev/null +++ b/include/openspace/interaction/interpolator.inl @@ -0,0 +1,85 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +namespace openspace { +namespace interaction { + +template +Interpolator::Interpolator() +: _transferFunction([](float t){ return t; }) +, _t(0.0) +, _interpolationTime(1.0) {}; + +template +void Interpolator::start() { + _t = 0.0; +}; + +template +void Interpolator::end() { + _t = 1.0; +} + +template +void Interpolator::setDeltaTime(float deltaTime) { + _scaledDeltaTime = deltaTime / _interpolationTime; +} + +template +void Interpolator::setTransferFunction(std::function transferFunction) { + _transferFunction = transferFunction; +} + +template +void Interpolator::setInterpolationTime(float interpolationTime) { + _interpolationTime = interpolationTime; +} + +template +void Interpolator::step() { + _t += _scaledDeltaTime; + _t = glm::clamp(_t, 0.0f, 1.0f); +} + +template +float Interpolator::deltaTimeScaled() const { + return _scaledDeltaTime; +} + +template +T Interpolator::value() const { + return _transferFunction(_t); +} + +template +bool Interpolator::isInterpolating() const { + return _t < 1.0 && _t >= 0.0; +} + +} // namespace interaction +} // namespace openspace diff --git a/include/openspace/interaction/keybindingmanager.h b/include/openspace/interaction/keybindingmanager.h new file mode 100644 index 0000000000..2d4432f06f --- /dev/null +++ b/include/openspace/interaction/keybindingmanager.h @@ -0,0 +1,87 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___KEYBINDINGMANAGER___H__ +#define __OPENSPACE_CORE___KEYBINDINGMANAGER___H__ + +#include +#include +#include + +#include + +namespace openspace { + +class Camera; +class SceneGraphNode; + +namespace interaction { + +class KeyBindingManager : public DocumentationGenerator +{ +public: + KeyBindingManager(); + ~KeyBindingManager() = default; + + void resetKeyBindings(); + + void bindKeyLocal( + Key key, + KeyModifier modifier, + std::string luaCommand, + std::string documentation = "" + ); + + void bindKey( + Key key, + KeyModifier modifier, + std::string luaCommand, + std::string documentation = "" + ); + + static scripting::LuaLibrary luaLibrary(); + + // Callback functions + void keyboardCallback(Key key, KeyModifier modifier, KeyAction action); + +private: + using Synchronized = ghoul::Boolean; + + struct KeyInformation { + std::string command; + Synchronized synchronization; + std::string documentation; + }; + + std::string generateJson() const override; + + bool _cameraUpdatedFromScript = false; + + std::multimap _keyLua; +}; + +} // namespace interaction +} // namespace openspace + +#endif // __OPENSPACE_CORE___KEYBINDINGMANAGER___H__ diff --git a/include/openspace/interaction/keyframenavigator.h b/include/openspace/interaction/keyframenavigator.h new file mode 100644 index 0000000000..511e2ae3df --- /dev/null +++ b/include/openspace/interaction/keyframenavigator.h @@ -0,0 +1,69 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__ +#define __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__ + +#include +#include + +#include +#include + +namespace openspace { + +class Camera; + +namespace interaction { + +class KeyframeNavigator +{ +public: + struct CameraPose { + glm::dvec3 position; + glm::quat rotation; + std::string focusNode; + bool followFocusNodeRotation; + }; + + KeyframeNavigator() = default; + ~KeyframeNavigator() = default; + + void updateCamera(Camera& camera); + Timeline& timeline(); + + void addKeyframe(double timestamp, KeyframeNavigator::CameraPose pose); + void removeKeyframesAfter(double timestamp); + void clearKeyframes(); + size_t nKeyframes() const; + const std::vector& keyframes() const; + +private: + Timeline _cameraPoseTimeline; +}; + +} // namespace interaction +} // namespace openspace + +#endif // __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__ diff --git a/include/openspace/interaction/mousestate.h b/include/openspace/interaction/mousestate.h new file mode 100644 index 0000000000..c6db1380a7 --- /dev/null +++ b/include/openspace/interaction/mousestate.h @@ -0,0 +1,80 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___MOUSESTATE___H__ +#define __OPENSPACE_CORE___MOUSESTATE___H__ + +#include +#include + +#include + +namespace openspace { +namespace interaction { + +struct MouseState { + MouseState(double scaleFactor); + void setFriction(double friction); + void setVelocityScaleFactor(double scaleFactor); + + glm::dvec2 previousPosition; + DelayedVariable velocity; +}; + +class MouseStates +{ +public: + /** + \param sensitivity + \param velocityScaleFactor can be set to 60 to remove the inertia of the + interaction. Lower value will make it harder to move the camera. + */ + MouseStates(double sensitivity, double velocityScaleFactor); + void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); + void setRotationalFriction(double friction); + void setHorizontalFriction(double friction); + void setVerticalFriction(double friction); + void setSensitivity(double sensitivity); + void setVelocityScaleFactor(double scaleFactor); + + glm::dvec2 globalRotationMouseVelocity() const; + glm::dvec2 localRotationMouseVelocity() const; + glm::dvec2 truckMovementMouseVelocity() const; + glm::dvec2 localRollMouseVelocity() const; + glm::dvec2 globalRollMouseVelocity() const; + +private: + double _sensitivity; + + MouseState _globalRotationMouseState; + MouseState _localRotationMouseState; + MouseState _truckMovementMouseState; + MouseState _localRollMouseState; + MouseState _globalRollMouseState; +}; + +} // namespace interaction +} // namespace openspace + +#endif // __OPENSPACE_CORE___MOUSESTATE___H__ diff --git a/include/openspace/interaction/interactionhandler.h b/include/openspace/interaction/navigationhandler.h similarity index 59% rename from include/openspace/interaction/interactionhandler.h rename to include/openspace/interaction/navigationhandler.h index 162404d227..2d0c930d4a 100644 --- a/include/openspace/interaction/interactionhandler.h +++ b/include/openspace/interaction/navigationhandler.h @@ -22,14 +22,13 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_CORE___INTERACTIONHANDLER___H__ -#define __OPENSPACE_CORE___INTERACTIONHANDLER___H__ +#ifndef __OPENSPACE_CORE___NAVIGATIONHANDLER___H__ +#define __OPENSPACE_CORE___NAVIGATIONHANDLER___H__ -#include #include -#include -#include +#include +#include #include #include #include @@ -38,10 +37,6 @@ #include -#include - -#include - namespace openspace { class Camera; @@ -49,11 +44,10 @@ class SceneGraphNode; namespace interaction { -class InteractionHandler : public properties::PropertyOwner, public DocumentationGenerator -{ +class NavigationHandler : public properties::PropertyOwner { public: - InteractionHandler(); - ~InteractionHandler(); + NavigationHandler(); + ~NavigationHandler(); void initialize(); void deinitialize(); @@ -63,39 +57,9 @@ public: void setCamera(Camera* camera); void resetCameraDirection(); - // Interaction mode setters - void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict); - InteractionMode* interactionMode(); + void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict); - void goToChunk(int x, int y, int level); - void goToGeo(double latitude, double longitude); - - void resetKeyBindings(); - - void addKeyframe(double timestamp, KeyframeInteractionMode::CameraPose pose); - void removeKeyframesAfter(double timestamp); - void clearKeyframes(); - size_t nKeyframes() const; - const std::vector& keyframes() const; - - void bindKeyLocal( - Key key, - KeyModifier modifier, - std::string luaCommand, - std::string documentation = "" - ); - void bindKey( - Key key, - KeyModifier modifier, - std::string luaCommand, - std::string documentation = "" - ); - void lockControls(); - void unlockControls(); - - //void update(double deltaTime); void updateCamera(double deltaTime); - void updateInputStates(double timeSinceLastUpdate); // Accessors ghoul::Dictionary getCameraStateDictionary(); @@ -104,15 +68,8 @@ public: glm::quat focusNodeToCameraRotation() const; Camera* camera() const; const InputState& inputState() const; - - /** - * Returns the Lua library that contains all Lua functions available to affect the - * interaction. The functions contained are - * - openspace::luascriptfunctions::setOrigin - * \return The Lua library that contains all Lua functions available to affect the - * interaction - */ - static scripting::LuaLibrary luaLibrary(); + const OrbitalNavigator& orbitalNavigator() const; + KeyframeNavigator& keyframeNavigator() const; // Callback functions void keyboardCallback(Key key, KeyModifier modifier, KeyAction action); @@ -123,47 +80,26 @@ public: void saveCameraStateToFile(const std::string& filepath); void restoreCameraStateFromFile(const std::string& filepath); + /** + * \return The Lua library that contains all Lua functions available to affect the + * interaction + */ + static scripting::LuaLibrary luaLibrary(); private: - using Synchronized = ghoul::Boolean; - - struct KeyInformation { - std::string command; - Synchronized synchronization; - std::string documentation; - }; - - std::string generateJson() const override; - - void setInteractionMode(InteractionMode* interactionMode); - bool _cameraUpdatedFromScript = false; - std::multimap _keyLua; - std::unique_ptr _inputState; Camera* _camera; - InteractionMode* _currentInteractionMode; - - std::shared_ptr _mouseStates; - - std::unique_ptr _orbitalInteractionMode; - std::unique_ptr _globeBrowsingInteractionMode; - std::unique_ptr _keyframeInteractionMode; + std::unique_ptr _orbitalNavigator; + std::unique_ptr _keyframeNavigator; // Properties properties::StringProperty _origin; - properties::OptionProperty _interactionModeOption; - - properties::BoolProperty _rotationalFriction; - properties::BoolProperty _horizontalFriction; - properties::BoolProperty _verticalFriction; - - properties::FloatProperty _sensitivity; - properties::FloatProperty _rapidness; + properties::BoolProperty _useKeyFrameInteraction; }; } // namespace interaction } // namespace openspace -#endif // __OPENSPACE_CORE___INTERACTIONHANDLER___H__ +#endif // __OPENSPACE_CORE___NAVIGATIONHANDLER___H__ diff --git a/include/openspace/interaction/orbitalnavigator.h b/include/openspace/interaction/orbitalnavigator.h new file mode 100644 index 0000000000..bdd97f39ba --- /dev/null +++ b/include/openspace/interaction/orbitalnavigator.h @@ -0,0 +1,197 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___ORBITALNAVIGATOR___H__ +#define __OPENSPACE_CORE___ORBITALNAVIGATOR___H__ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace openspace { + +class SceneGraphNode; +class Camera; +class SurfacePositionHandle; + +namespace interaction { + +class OrbitalNavigator : public properties::PropertyOwner { +public: + OrbitalNavigator(); + ~OrbitalNavigator(); + + void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); + void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); + void setFocusNode(SceneGraphNode* focusNode); + void startInterpolateCameraDirection(const Camera& camera); + + bool followingNodeRotation() const; + SceneGraphNode* focusNode() const; + +private: + struct CameraRotationDecomposition { + glm::dquat localRotation; + glm::dquat globalRotation; + }; + + // Properties + properties::BoolProperty _rotationalFriction; + properties::BoolProperty _horizontalFriction; + properties::BoolProperty _verticalFriction; + properties::FloatProperty _followFocusNodeRotationDistance; + properties::FloatProperty _minimumAllowedDistance; + properties::FloatProperty _sensitivity; + properties::FloatProperty _motionLag; + + MouseStates _mouseStates; + + SceneGraphNode* _focusNode = nullptr; + glm::dvec3 _previousFocusNodePosition; + glm::dquat _previousFocusNodeRotation; + + Interpolator _rotateToFocusNodeInterpolator; + Interpolator _followRotationInterpolator; + + /** + * Decomposes the cameras rotation in to a global and a local rotation defined by + * CameraRotationDecomposition. The global rotation defines the rotation so that the + * camera points towards the focus node in the direction opposite to the direction + * out from the surface of the object. The local rotation defines the differential + * from the global to the current total rotation so that + * cameraRotation = globalRotation * localRotation. + */ + CameraRotationDecomposition decomposeCameraRotation( + const glm::dvec3& cameraPosition, + const glm::dquat& cameraRotation, + const glm::dvec3& cameraLookUp, + const glm::dvec3& cameraViewDirection); + + /* + * Perform a camera roll on the local camera rotation + * \returns a local camera rotation modified with a roll. + */ + glm::dquat roll(double deltaTime, const glm::dquat& localCameraRotation) const; + + /** + * Performs rotation around the cameras x and y axes. + * \returns a local camera rotation modified with two degrees of freedom. + */ + glm::dquat rotateLocally(double deltaTime, + const glm::dquat& localCameraRotation) const; + + /** + * Interpolates the local rotation towards a 0 rotation. + * \returns a modified local rotation interpolated towards 0. + */ + glm::dquat interpolateLocalRotation(double deltaTime, + const glm::dquat& localCameraRotation); + + /** + * Translates the horizontal direction. If far from the focus object, this will + * result in an orbital rotation around the object. This function does not affect the + * rotation but only the position. + * \returns a position vector adjusted in the horizontal direction. + */ + glm::dvec3 translateHorizontally(double deltaTime, const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const glm::dquat& focusNodeRotationDiff, + const glm::dquat& globalCameraRotation, + const SurfacePositionHandle& positionHandle) const; + + /* + * Adds rotation to the camera position so that it follows the rotation of the focus + * node defined by the differential focusNodeRotationDiff. + * \returns a position updated with the rotation defined by focusNodeRotationDiff + */ + glm::dvec3 followFocusNodeRotation(const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const glm::dquat& focusNodeRotationDiff) const; + + /** + * Updates the global rotation so that it points towards the focus node. + * \returns a global rotation quaternion defining a rotation towards the focus node. + */ + glm::dquat rotateGlobally(const glm::dquat& globalCameraRotation, + const glm::dvec3& objectPosition, + const glm::dquat& focusNodeRotationDiff, + const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle) const; + + /** + * Translates the camera position towards or away from the focus node. + * \returns a position vector adjusted in the vertical direction. + */ + glm::dvec3 translateVertically(double deltaTime, const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const SurfacePositionHandle& positionHandle) const; + + /** + * Rotates the camera around the out vector of the surface. + * \returns a quaternion adjusted to rotate around the out vector of the surface. + */ + glm::dquat rotateHorizontally(double deltaTime, + const glm::dquat& globalCameraRotation, + const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle) const; + + /** + * Push the camera out to the surface of the object. + * \returns a position vector adjusted to be at least minHeightAboveGround meters + * above the actual surface of the object + */ + glm::dvec3 pushToSurface(double minHeightAboveGround, + const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const SurfacePositionHandle& positionHandle) const; + + /** + * Interpolates between rotationDiff and a 0 rotation. + */ + glm::dquat interpolateRotationDifferential( + double deltaTime, double interpolationTime, + const glm::dquat& rotationDiff, + const glm::dvec3& objectPosition, + const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle); + + /** + * Calculates a SurfacePositionHandle given a camera position in world space. + */ + SurfacePositionHandle calculateSurfacePositionHandle( + const glm::dvec3 cameraPositionWorldSpace); +}; + +} // namespace interaction +} // namespace openspace + +#endif // __OPENSPACE_CORE___ORBITALNAVIGATOR___H__ diff --git a/include/openspace/performance/performancemanager.h b/include/openspace/performance/performancemanager.h index 55fca53f5b..21e7c64b27 100644 --- a/include/openspace/performance/performancemanager.h +++ b/include/openspace/performance/performancemanager.h @@ -58,14 +58,41 @@ public: void storeIndividualPerformanceMeasurement(std::string identifier, long long nanoseconds); void storeScenePerformanceMeasurements(const std::vector& sceneNodes); - PerformanceLayout* performanceData(); + void outputLogs(); + void writeData(std::ofstream& out, const std::vector& data); + + std::string formatLogName(std::string nodeName); + + void logDir(std::string dir); + std::string logDir() const; + void prefix(std::string prefix); + std::string prefix() const; + + void enableLogging(); + void disableLogging(); + void toggleLogging(); + void setLogging(bool enabled); + bool loggingEnabled() const; + + PerformanceLayout* performanceData(); private: bool _doPerformanceMeasurements; + bool _loggingEnabled; + + std::string _logDir; + std::string _prefix; + std::string _suffix; + std::string _ext; std::map individualPerformanceLocations; std::unique_ptr _performanceMemory; + + size_t _tick; + + void tick(); + bool createLogDir(); }; } // namespace performance diff --git a/include/openspace/properties/property.h b/include/openspace/properties/property.h index 5fbc8e6a78..80b446b5a3 100644 --- a/include/openspace/properties/property.h +++ b/include/openspace/properties/property.h @@ -73,6 +73,14 @@ public: User = 0 ///< Visible in User mode }; + /// An OnChangeHandle is returned by the onChange method to uniquely identify an + /// onChange callback + using OnChangeHandle = uint32_t; + + /// This OnChangeHandle can be used to remove all onChange callbacks from this + /// Property + static OnChangeHandle OnChangeHandleAll; + /** * The constructor for the property. The identifier needs to be unique * for each PropertyOwner. The guiName will be stored in the metaData @@ -92,7 +100,7 @@ public: * The destructor taking care of deallocating all unused memory. This method will not * remove the Property from the PropertyOwner. */ - virtual ~Property(); + virtual ~Property() = default; /** * This method returns the class name of the Property. The method is used by the @@ -191,12 +199,25 @@ public: * This method registers a callback function that will be called every * time if either Property:set or Property::setLuaValue was called with a value that * is different from the previously stored value. The callback can be removed by - * passing an empty std::function object. + * calling the removeOnChange method with the OnChangeHandle that was returned here. * \param callback The callback function that is called when the encapsulated type has * been successfully changed by either the Property::set or Property::setLuaValue * methods. + * \pre The callback must not be empty + * \return An OnChangeHandle that can be used in subsequent calls to remove a callback */ - virtual void onChange(std::function callback); + OnChangeHandle onChange(std::function callback); + + /** + * This method deregisters a callback that was previously registered with the onChange + * method. If OnChangeHandleAll is passed to this function, all registered callbacks + * are removed. + * \param handle An OnChangeHandle that was returned from a previous call to onChange + * by this property or OnChangeHandleAll if all callbacks should be removed. + * \pre handle must refer to a callback that has been previously registred + * \pre handle must refer to a callback that has not been removed previously + */ + void removeOnChange(OnChangeHandle handle); /** * This method returns the unique identifier of this Property. @@ -389,8 +410,11 @@ protected: /// The Dictionary containing all meta data necessary for external applications ghoul::Dictionary _metaData; - /// The callback function that will be invoked whenever the encapsulated value changes - std::function _onChangeCallback; + /// The callback function sthat will be invoked whenever the value changes + std::vector>> _onChangeCallbacks; + +private: + OnChangeHandle _currentHandleValue; }; } // namespace properties diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index b9fe5cf7a3..a5bafcc8d5 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -42,6 +42,7 @@ namespace openspace { struct RenderData; struct UpdateData; struct RendererTasks; +struct SurfacePositionHandle; namespace documentation { struct Documentation; } @@ -78,6 +79,8 @@ public: virtual void render(const RenderData& data); virtual void render(const RenderData& data, RendererTasks& rendererTask); virtual void update(const UpdateData& data); + virtual SurfacePositionHandle calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace); RenderBin renderBin() const; void setRenderBin(RenderBin bin); diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index 2fc8a14a36..ca3fdefee3 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -48,6 +48,7 @@ class Translation; class Scale; class Scene; struct UpdateData; +struct SurfacePositionHandle; namespace documentation { struct Documentation; } @@ -93,6 +94,9 @@ public: void clearDependencies(); void setDependencies(const std::vector& dependencies); + SurfacePositionHandle calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace); + const std::vector& dependencies() const; const std::vector& dependentNodes() const; diff --git a/include/openspace/util/updatestructures.h b/include/openspace/util/updatestructures.h index 6e0c007e72..47609c7994 100644 --- a/include/openspace/util/updatestructures.h +++ b/include/openspace/util/updatestructures.h @@ -75,6 +75,21 @@ struct RaycastData { std::string namespaceName; }; +/** + * Defines the position of an object relative to a surface. The surface is defined as + * a reference surface together with a height offset from that reference surface. + */ +struct SurfacePositionHandle { + /// Vector from the center of the object to the reference surface of the object + glm::dvec3 centerToReferenceSurface; + /// Direction out from the reference. Can conincide with the surface normal but does + /// not have to. + glm::dvec3 referenceSurfaceOutDirection; + /// Height from the reference surface out to the actual surface in the direction of + /// the surface normal. Can be positive or negative. + double heightToSurface; +}; + } // namespace openspace #endif // __OPENSPACE_CORE___UPDATESTRUCTURES___H__ diff --git a/logs/.gitignore b/logs/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp index 47af9e3ec5..85382d5add 100644 --- a/modules/base/basemodule.cpp +++ b/modules/base/basemodule.cpp @@ -52,9 +52,7 @@ namespace openspace { -BaseModule::BaseModule() - : OpenSpaceModule("Base") -{} +BaseModule::BaseModule() : OpenSpaceModule(BaseModule::Name) {} void BaseModule::internalInitialize() { FactoryManager::ref().addFactory( diff --git a/modules/base/basemodule.h b/modules/base/basemodule.h index 257cdec7ce..8cb316d515 100644 --- a/modules/base/basemodule.h +++ b/modules/base/basemodule.h @@ -31,6 +31,8 @@ namespace openspace { class BaseModule : public OpenSpaceModule { public: + constexpr static const char* Name = "Base"; + BaseModule(); virtual ~BaseModule() = default; std::vector documentations() const override; diff --git a/modules/debugging/debuggingmodule.cpp b/modules/debugging/debuggingmodule.cpp index 4793bbb81e..bbebf4a0db 100644 --- a/modules/debugging/debuggingmodule.cpp +++ b/modules/debugging/debuggingmodule.cpp @@ -34,7 +34,7 @@ namespace openspace { DebuggingModule::DebuggingModule() - : OpenSpaceModule("Debugging") + : OpenSpaceModule(Name) {} void DebuggingModule::internalInitialize() { @@ -42,7 +42,6 @@ void DebuggingModule::internalInitialize() { ghoul_assert(fRenderable, "No renderable factory existed"); fRenderable->registerClass("RenderableDebugPlane"); - } } // namespace openspace diff --git a/modules/debugging/debuggingmodule.h b/modules/debugging/debuggingmodule.h index a626899a89..a030471b21 100644 --- a/modules/debugging/debuggingmodule.h +++ b/modules/debugging/debuggingmodule.h @@ -31,6 +31,8 @@ namespace openspace { class DebuggingModule : public OpenSpaceModule { public: + constexpr static const char* Name = "Debugging"; + DebuggingModule(); protected: diff --git a/modules/fieldlines/fieldlinesmodule.cpp b/modules/fieldlines/fieldlinesmodule.cpp index bc74add3d4..f677bd8d95 100644 --- a/modules/fieldlines/fieldlinesmodule.cpp +++ b/modules/fieldlines/fieldlinesmodule.cpp @@ -34,7 +34,7 @@ namespace openspace { FieldlinesModule::FieldlinesModule() - : OpenSpaceModule("Fieldlines") + : OpenSpaceModule(Name) {} void FieldlinesModule::internalInitialize() { diff --git a/modules/fieldlines/fieldlinesmodule.h b/modules/fieldlines/fieldlinesmodule.h index ef06ed869c..3c3f451ee2 100644 --- a/modules/fieldlines/fieldlinesmodule.h +++ b/modules/fieldlines/fieldlinesmodule.h @@ -31,6 +31,8 @@ namespace openspace { class FieldlinesModule : public OpenSpaceModule { public: + constexpr static const char* Name = "Fieldlines"; + FieldlinesModule(); protected: diff --git a/modules/galaxy/galaxymodule.cpp b/modules/galaxy/galaxymodule.cpp index 636055634c..a304be6094 100644 --- a/modules/galaxy/galaxymodule.cpp +++ b/modules/galaxy/galaxymodule.cpp @@ -32,7 +32,7 @@ namespace openspace { -GalaxyModule::GalaxyModule() : OpenSpaceModule("Galaxy") {} +GalaxyModule::GalaxyModule() : OpenSpaceModule(Name) {} void GalaxyModule::internalInitialize() { auto fRenderable = FactoryManager::ref().factory(); diff --git a/modules/galaxy/galaxymodule.h b/modules/galaxy/galaxymodule.h index 6525a9a5a8..19442bfdd5 100644 --- a/modules/galaxy/galaxymodule.h +++ b/modules/galaxy/galaxymodule.h @@ -31,6 +31,8 @@ namespace openspace { class GalaxyModule : public OpenSpaceModule { public: + constexpr static const char* Name = "Galaxy"; + GalaxyModule(); void internalInitialize() override; }; diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index 786d6ec329..2c30b6489e 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -25,6 +25,8 @@ 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 @@ -79,12 +81,14 @@ set(HEADER_FILES ${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 @@ -102,8 +106,7 @@ set(HEADER_FILES ${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/cachingtileprovider.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/presentationslideprovider.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 @@ -123,6 +126,9 @@ set(HEADER_FILES ) 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 @@ -159,12 +165,14 @@ set(SOURCE_FILES ${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/layermanager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layerrendersettings.cpp @@ -178,8 +186,7 @@ set(SOURCE_FILES ${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/cachingtileprovider.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/presentationslideprovider.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 @@ -211,7 +218,9 @@ set(SHADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/shaders/texturetilemapping.hglsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tile.hglsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tilefragcolor.hglsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tilevertexheight.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}) diff --git a/modules/globebrowsing/cache/lrucache.h b/modules/globebrowsing/cache/lrucache.h index b23cdae9db..8ebf224a9c 100644 --- a/modules/globebrowsing/cache/lrucache.h +++ b/modules/globebrowsing/cache/lrucache.h @@ -70,6 +70,7 @@ public: */ Item popLRU(); size_t size() const; + size_t maximumCacheSize() const; private: void putWithoutCleaning(const KeyType& key, const ValueType& value); diff --git a/modules/globebrowsing/cache/lrucache.inl b/modules/globebrowsing/cache/lrucache.inl index 6141338001..47c0eb4126 100644 --- a/modules/globebrowsing/cache/lrucache.inl +++ b/modules/globebrowsing/cache/lrucache.inl @@ -120,6 +120,11 @@ size_t LRUCache::size() const { return _itemMap.size(); } +template +size_t LRUCache::maximumCacheSize() const { + return _maximumCacheSize; +} + template void LRUCache::putWithoutCleaning(const KeyType& key, const ValueType& value) diff --git a/modules/globebrowsing/cache/memoryawaretilecache.cpp b/modules/globebrowsing/cache/memoryawaretilecache.cpp index e59423515a..98f439f700 100644 --- a/modules/globebrowsing/cache/memoryawaretilecache.cpp +++ b/modules/globebrowsing/cache/memoryawaretilecache.cpp @@ -117,7 +117,7 @@ void MemoryAwareTileCache::clear() { void MemoryAwareTileCache::createDefaultTextureContainers() { for (int id = 0; id < layergroupid::NUM_LAYER_GROUPS; id++) { TileTextureInitData initData = - LayerManager::getTileTextureInitData(layergroupid::ID(id)); + LayerManager::getTileTextureInitData(layergroupid::GroupID(id)); assureTextureContainerExists(initData); } } diff --git a/modules/globebrowsing/cache/texturecontainer.h b/modules/globebrowsing/cache/texturecontainer.h index 5035587abd..bcab70e17c 100644 --- a/modules/globebrowsing/cache/texturecontainer.h +++ b/modules/globebrowsing/cache/texturecontainer.h @@ -68,8 +68,9 @@ public: private: std::vector> _textures; - size_t _freeTexture; + const TileTextureInitData _initData; + size_t _freeTexture; size_t _numTextures; }; diff --git a/modules/globebrowsing/chunk/chunk.cpp b/modules/globebrowsing/chunk/chunk.cpp index aafd7a0b2a..dca2d4697d 100644 --- a/modules/globebrowsing/chunk/chunk.cpp +++ b/modules/globebrowsing/chunk/chunk.cpp @@ -102,7 +102,7 @@ Chunk::BoundingHeights Chunk::getBoundingHeights() const { // a single raster image. If it is not we will just use the first raster // (that is channel 0). const size_t HeightChannel = 0; - const LayerGroup& heightmaps = layerManager->layerGroup(layergroupid::HeightLayers); + const LayerGroup& heightmaps = layerManager->layerGroup(layergroupid::GroupID::HeightLayers); std::vector chunkTileSettingPairs = tileselector::getTilesAndSettingsUnsorted( heightmaps, _tileIndex); diff --git a/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.cpp b/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.cpp index caaeaac038..8191439767 100644 --- a/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.cpp +++ b/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.cpp @@ -42,7 +42,7 @@ int AvailableTileData::getDesiredLevel(const Chunk& chunk, const RenderData& dat for (size_t i = 0; i < layergroupid::NUM_LAYER_GROUPS; ++i) { for (const auto& layer : layerManager->layerGroup(i).activeLayers()) { - Tile::Status status = layer->tileProvider()->getTileStatus(chunk.tileIndex()); + Tile::Status status = layer->getTileStatus(chunk.tileIndex()); if (status == Tile::Status::OK) { return UnknownDesiredLevel; } diff --git a/modules/globebrowsing/chunk/culling/frustumculler.cpp b/modules/globebrowsing/chunk/culling/frustumculler.cpp index 090d91ba4a..8d3c5ee849 100644 --- a/modules/globebrowsing/chunk/culling/frustumculler.cpp +++ b/modules/globebrowsing/chunk/culling/frustumculler.cpp @@ -40,7 +40,7 @@ bool FrustumCuller::isCullable(const Chunk& chunk, const RenderData& data) { // Calculate the MVP matrix glm::dmat4 modelTransform = chunk.owner().modelTransform(); glm::dmat4 viewTransform = glm::dmat4(data.camera.combinedViewMatrix()); - glm::dmat4 modelViewProjectionTransform = glm::dmat4(data.camera.projectionMatrix()) + glm::dmat4 modelViewProjectionTransform = glm::dmat4(data.camera.sgctInternal.projectionMatrix()) * viewTransform * modelTransform; const std::vector& corners = chunk.getBoundingPolyhedronCorners(); diff --git a/modules/globebrowsing/geometry/geodeticpatch.h b/modules/globebrowsing/geometry/geodeticpatch.h index e47cd5de3d..eff1392431 100644 --- a/modules/globebrowsing/geometry/geodeticpatch.h +++ b/modules/globebrowsing/geometry/geodeticpatch.h @@ -27,11 +27,10 @@ #include #include +#include namespace openspace { namespace globebrowsing { - -struct TileIndex; class GeodeticPatch { public: diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 79621716c0..0f5a8c2c24 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -25,10 +25,13 @@ #include #include +#include +#include #include #include +#include #include -#include +#include #include #include #include @@ -37,10 +40,11 @@ #include #include #include -#include +#include +#include #include -#include +#include #include #include @@ -48,22 +52,23 @@ #include +#include "globebrowsingmodule_lua.inl" + +namespace { + const char* _loggerCat = "GlobeBrowsingModule"; +} + namespace openspace { -const std::string GlobeBrowsingModule::name = "GlobeBrowsing"; - -GlobeBrowsingModule::GlobeBrowsingModule() - : OpenSpaceModule(name) -{ } +GlobeBrowsingModule::GlobeBrowsingModule() : OpenSpaceModule(Name) {} void GlobeBrowsingModule::internalInitialize() { using namespace globebrowsing; + // Initialize OsEng.registerModuleCallback(OpenSpaceEngine::CallbackOption::Initialize, [&] { - - _tileCache = std::make_unique(); - addPropertySubOwner(*_tileCache); - + _tileCache = std::make_unique(); + addPropertySubOwner(*_tileCache); #ifdef GLOBEBROWSING_USE_GDAL // Convert from MB to Bytes GdalWrapper::create( @@ -73,37 +78,47 @@ void GlobeBrowsingModule::internalInitialize() { #endif // GLOBEBROWSING_USE_GDAL }); + // Render OsEng.registerModuleCallback(OpenSpaceEngine::CallbackOption::Render, [&]{ _tileCache->update(); }); - + // Deinitialize OsEng.registerModuleCallback(OpenSpaceEngine::CallbackOption::Deinitialize, [&]{ #ifdef GLOBEBROWSING_USE_GDAL GdalWrapper::ref().destroy(); #endif // GLOBEBROWSING_USE_GDAL }); + // Get factories auto fRenderable = FactoryManager::ref().factory(); ghoul_assert(fRenderable, "Renderable factory was not created"); + // Create factory for TileProviders + auto fTileProvider = + std::make_unique>(); + ghoul_assert(fTileProvider, "TileProvider factory was not created"); + + // Register renderable class fRenderable->registerClass("RenderableGlobe"); - // add Tile Provider factory - auto fTileProvider = std::make_unique>(); - - fTileProvider->registerClass("LRUCaching"); - fTileProvider->registerClass("SingleImage"); + // Register TileProvider classes + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::DefaultTileLayer)]); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::SingleImageTileLayer)]); #ifdef GLOBEBROWSING_USE_GDAL - fTileProvider->registerClass("Temporal"); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::TemporalTileLayer)]); #endif // GLOBEBROWSING_USE_GDAL - - fTileProvider->registerClass("TileIndex"); - fTileProvider->registerClass("SizeReference"); - - // Combining Tile Providers - fTileProvider->registerClass("ByLevel"); - fTileProvider->registerClass("ByIndex"); - fTileProvider->registerClass("PresentationSlides"); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::TileIndexTileLayer)]); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::SizeReferenceTileLayer)]); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::ByLevelTileLayer)]); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::ByIndexTileLayer)]); + FactoryManager::ref().addFactory(std::move(fTileProvider)); } @@ -112,13 +127,231 @@ globebrowsing::cache::MemoryAwareTileCache* GlobeBrowsingModule::tileCache() { } scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { + std::string listLayerGroups = layerGroupNamesList(); return { "globebrowsing", - {}, + { + { + "addLayer", + &globebrowsing::luascriptfunctions::addLayer, + "string, string, table", + "Adds a layer to the specified globe. The first argument specifies the " + "name of the scene graph node of which to add the layer. The renderable " + "of the specified scene graph node needs to be a renderable globe. " + "The second argument is the layer group which can be any of " + + listLayerGroups + ". The third argument is the dictionary defining the " + "layer." + }, + { + "deleteLayer", + &globebrowsing::luascriptfunctions::deleteLayer, + "string, string", + "Removes a layer from the specified globe. The first argument specifies " + "the name of the scene graph node of which to remove the layer. " + "The renderable of the specified scene graph node needs to be a " + "renderable globe. The second argument is the layer group which can be " + "any of " + listLayerGroups + ". The third argument is the dictionary" + "defining the layer." + }, + { + "goToChunk", + &globebrowsing::luascriptfunctions::goToChunk, + "void", + "Go to chunk with given index x, y, level" + }, + { + "goToGeo", + &globebrowsing::luascriptfunctions::goToGeo, + "void", + "Go to geographic coordinates latitude and longitude" + } + }, { "${MODULE_GLOBEBROWSING}/scripts/layer_support.lua" + }, + { + // Documentation } }; } +void GlobeBrowsingModule::goToChunk(int x, int y, int level) { + using namespace globebrowsing; + Camera* cam = OsEng.navigationHandler().camera(); + goToChunk(*cam, TileIndex(x,y,level), glm::vec2(0.5, 0.5), true); +} + +void GlobeBrowsingModule::goToGeo(double latitude, double longitude) { + using namespace globebrowsing; + Camera* cam = OsEng.navigationHandler().camera(); + goToGeodetic2(*cam, Geodetic2(latitude, longitude) / 180 * glm::pi(), true); +} + +void GlobeBrowsingModule::goToGeo(double latitude, double longitude, + double altitude) +{ + using namespace globebrowsing; + + Camera* cam = OsEng.navigationHandler().camera(); + goToGeodetic3( + *cam, + { + Geodetic2(latitude, longitude) / 180 * glm::pi(), + altitude + }, + true + ); +} + +void GlobeBrowsingModule::goToChunk(Camera& camera, globebrowsing::TileIndex ti, + glm::vec2 uv, bool resetCameraDirection) +{ + using namespace globebrowsing; + + RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); + if (!globe) { + LERROR("Focus node must have a RenderableGlobe renderable."); + return; + } + + // Camera position in model space + glm::dvec3 camPos = camera.positionVec3(); + glm::dmat4 inverseModelTransform = globe->inverseModelTransform(); + glm::dvec3 cameraPositionModelSpace = + glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1)); + + GeodeticPatch patch(ti); + Geodetic2 corner = patch.getCorner(SOUTH_WEST); + Geodetic2 positionOnPatch = patch.getSize(); + positionOnPatch.lat *= uv.y; + positionOnPatch.lon *= uv.x; + Geodetic2 pointPosition = corner + positionOnPatch; + + glm::dvec3 positionOnEllipsoid = + globe->ellipsoid().geodeticSurfaceProjection(cameraPositionModelSpace); + double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid); + + goToGeodetic3(camera, {pointPosition, altitude}, resetCameraDirection); +} + +void GlobeBrowsingModule::goToGeodetic2(Camera& camera, + globebrowsing::Geodetic2 geo2, + bool resetCameraDirection) +{ + using namespace globebrowsing; + + RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); + if (!globe) { + LERROR("Focus node must have a RenderableGlobe renderable."); + return; + } + + // Camera position in model space + glm::dvec3 camPos = camera.positionVec3(); + glm::dmat4 inverseModelTransform = globe->inverseModelTransform(); + glm::dvec3 cameraPositionModelSpace = + glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1)); + + glm::dvec3 positionOnEllipsoid = + globe->ellipsoid().geodeticSurfaceProjection(cameraPositionModelSpace); + double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid); + + goToGeodetic3(camera, {geo2, altitude}, resetCameraDirection); +} + +void GlobeBrowsingModule::goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3, + bool resetCameraDirection) +{ + using namespace globebrowsing; + + RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); + if (!globe) { + LERROR("Focus node must have a RenderableGlobe renderable."); + return; + } + + glm::dvec3 positionModelSpace = globe->ellipsoid().cartesianPosition(geo3); + glm::dmat4 modelTransform = globe->modelTransform(); + glm::dvec3 positionWorldSpace = modelTransform * glm::dvec4(positionModelSpace, 1.0); + camera.setPositionVec3(positionWorldSpace); + + if (resetCameraDirection) { + this->resetCameraDirection(camera, geo3.geodetic2); + } +} + +void GlobeBrowsingModule::resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2) +{ + using namespace globebrowsing; + + RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); + if (!globe) { + LERROR("Focus node must have a RenderableGlobe renderable."); + return; + } + + // Camera is described in world space + glm::dmat4 modelTransform = globe->modelTransform(); + + // Lookup vector + glm::dvec3 positionModelSpace = globe->ellipsoid().cartesianSurfacePosition(geo2); + glm::dvec3 slightlyNorth = globe->ellipsoid().cartesianSurfacePosition( + Geodetic2(geo2.lat + 0.001, geo2.lon)); + glm::dvec3 lookUpModelSpace = glm::normalize(slightlyNorth - positionModelSpace); + glm::dvec3 lookUpWorldSpace = glm::dmat3(modelTransform) * lookUpModelSpace; + + // Lookat vector + glm::dvec3 lookAtWorldSpace = modelTransform * glm::dvec4(positionModelSpace, 1.0); + + // Eye position + glm::dvec3 eye = camera.positionVec3(); + + // Matrix + glm::dmat4 lookAtMatrix = glm::lookAt( + eye, lookAtWorldSpace, lookUpWorldSpace); + + // Set rotation + glm::dquat rotation = glm::quat_cast(inverse(lookAtMatrix)); + camera.setRotation(rotation); +} + +globebrowsing::RenderableGlobe* GlobeBrowsingModule::castFocusNodeRenderableToGlobe() { + using namespace globebrowsing; + + Renderable* baseRenderable = OsEng.navigationHandler().focusNode()->renderable(); + if (!baseRenderable) { + return nullptr; + } + if (globebrowsing::RenderableGlobe* globe = + dynamic_cast(baseRenderable)) + { + return globe; + } + else { + return nullptr; + } +} + +std::string GlobeBrowsingModule::layerGroupNamesList() { + std::string listLayerGroups(""); + for (int i = 0; i < globebrowsing::layergroupid::NUM_LAYER_GROUPS - 1; ++i) { + listLayerGroups += + globebrowsing::layergroupid::LAYER_GROUP_NAMES[i] + std::string(", "); + } + listLayerGroups += + std::string(" and ") + globebrowsing::layergroupid::LAYER_GROUP_NAMES[ + globebrowsing::layergroupid::NUM_LAYER_GROUPS - 1]; + return listLayerGroups; +} + +std::string GlobeBrowsingModule::layerTypeNamesList() { + std::string listLayerTypes(""); + for (int i = 0; i < globebrowsing::layergroupid::NUM_LAYER_TYPES - 1; ++i) { + listLayerTypes += globebrowsing::layergroupid::LAYER_TYPE_NAMES[i] + ", "; + } + listLayerTypes += + " and " + globebrowsing::layergroupid::LAYER_TYPE_NAMES[globebrowsing::layergroupid::NUM_LAYER_TYPES - 1]; + return listLayerTypes; +} + } // namespace openspace diff --git a/modules/globebrowsing/globebrowsingmodule.h b/modules/globebrowsing/globebrowsingmodule.h index b07b845cb6..2faad330ef 100644 --- a/modules/globebrowsing/globebrowsingmodule.h +++ b/modules/globebrowsing/globebrowsingmodule.h @@ -26,11 +26,17 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___GLOBEBROWSING_MODULE___H__ #include +#include #include namespace openspace { - + class Camera; namespace globebrowsing { + class RenderableGlobe; + class TileIndex; + class Geodetic2; + class Geodetic3; + namespace cache { class MemoryAwareTileCache; } @@ -38,19 +44,40 @@ namespace cache { class GlobeBrowsingModule : public OpenSpaceModule { public: - static const std::string name; + constexpr static const char* Name = "GlobeBrowsing"; GlobeBrowsingModule(); + void goToChunk(int x, int y, int level); + void goToGeo(double latitude, double longitude); + void goToGeo(double latitude, double longitude, double altitude); + globebrowsing::cache::MemoryAwareTileCache* tileCache(); - - scripting::LuaLibrary luaLibrary() const override; - protected: void internalInitialize() override; private: + + void goToChunk(Camera& camera, globebrowsing::TileIndex ti, glm::vec2 uv, + bool resetCameraDirection); + void goToGeodetic2(Camera& camera, globebrowsing::Geodetic2 geo2, + bool resetCameraDirection); + void goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3, + bool resetCameraDirection); + void resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2); + globebrowsing::RenderableGlobe* castFocusNodeRenderableToGlobe(); + + /** + \return a comma separated list of layer group names. + */ + static std::string layerGroupNamesList(); + + /** + \return a comma separated list of layer type names. + */ + static std::string layerTypeNamesList(); + std::unique_ptr _tileCache; }; diff --git a/modules/globebrowsing/globebrowsingmodule_lua.inl b/modules/globebrowsing/globebrowsingmodule_lua.inl new file mode 100644 index 0000000000..0ac27b6baf --- /dev/null +++ b/modules/globebrowsing/globebrowsingmodule_lua.inl @@ -0,0 +1,182 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace openspace { +namespace globebrowsing { +namespace luascriptfunctions { + +/** + Adds a layer to the specified globe. + */ +int addLayer(lua_State* L) { + using ghoul::lua::errorLocation; + + // Argument locations + const int GlobeLocation = -3; + const int LayerGroupLocation = -2; + + int nArguments = lua_gettop(L); + if (nArguments != 3) { + return luaL_error(L, "Expected %i arguments, got %i", 3, nArguments); + } + + // String arguments + const std::string GlobeName = luaL_checkstring(L, GlobeLocation); + const std::string LayerGroupName = luaL_checkstring(L, LayerGroupLocation); + + // Get the node and make sure it exists + SceneGraphNode* node = OsEng.renderEngine().scene()->sceneGraphNode(GlobeName); + if (!node) { + return luaL_error(L, ("Unknown globe name: " + GlobeName).c_str()); + } + + // Get the renderable globe + RenderableGlobe* globe = dynamic_cast(node->renderable()); + if (!globe) { + return luaL_error(L, ("Renderable is not a globe: " + GlobeName).c_str()); + } + + // Get the layer group + layergroupid::GroupID groupID = layergroupid::getGroupIDFromName(LayerGroupName); + if (groupID == layergroupid::GroupID::Unknown) { + return luaL_error(L, ("Unknown layer group: " + LayerGroupName).c_str()); + } + + // Get the dictionary defining the layer + ghoul::Dictionary d; + try { + ghoul::lua::luaDictionaryFromState(L, d); + } + catch (const ghoul::lua::LuaFormatException& e) { + LERRORC("addLayerFromDictionary", e.what()); + return 0; + } + + globe->layerManager()->addLayer(groupID, d); + + return 0; +} + +/** + Deletes a layer from the specified globe. + */ +int deleteLayer(lua_State* L) { + using ghoul::lua::errorLocation; + + // Argument locations + const int GlobeLocation = -3; + const int LayerGroupLocation = -2; + const int NameLocation = -1; + + int nArguments = lua_gettop(L); + if (nArguments != 3) { + return luaL_error(L, "Expected %i arguments, got %i", 3, nArguments); + } + + // String arguments + const std::string GlobeName = luaL_checkstring(L, GlobeLocation); + const std::string LayerGroupName = luaL_checkstring(L, LayerGroupLocation); + const std::string LayerName = luaL_checkstring(L, NameLocation); + + // Get the node and make sure it exists + SceneGraphNode* node = OsEng.renderEngine().scene()->sceneGraphNode(GlobeName); + if (!node) { + return luaL_error(L, ("Unknown globe name: " + GlobeName).c_str()); + } + + // Get the renderable globe + RenderableGlobe* globe = dynamic_cast(node->renderable()); + if (!globe) { + return luaL_error(L, ("Renderable is not a globe: " + GlobeName).c_str()); + } + + // Get the layer group + layergroupid::GroupID groupID = layergroupid::getGroupIDFromName(LayerGroupName); + if (groupID == layergroupid::GroupID::Unknown) { + return luaL_error(L, ("Unknown layer group: " + LayerGroupName).c_str()); + } + + globe->layerManager()->deleteLayer(groupID, LayerName); + + return 0; +} + +int goToChunk(lua_State* L) { + using ghoul::lua::luaTypeToString; + + // Check arguments + int nArguments = lua_gettop(L); + if (nArguments != 3) { + return luaL_error(L, "Expected %i arguments, got %i", 3, nArguments); + } + + int x = static_cast(lua_tonumber(L, 1)); + int y = static_cast(lua_tonumber(L, 2)); + int level = static_cast(lua_tonumber(L, 3)); + + OsEng.moduleEngine().module()->goToChunk(x, y, level); + + return 0; +} + +int goToGeo(lua_State* L) { + using ghoul::lua::luaTypeToString; + + int nArguments = lua_gettop(L); + if (nArguments != 2 && nArguments != 3) { + return luaL_error(L, "Expected 2 or 3 arguments."); + } + + double latitude = static_cast(lua_tonumber(L, 1)); + double longitude = static_cast(lua_tonumber(L, 2)); + + if (nArguments == 2) { + OsEng.moduleEngine().module()->goToGeo(latitude, longitude); + } + else if (nArguments == 3) { + double altitude = static_cast(lua_tonumber(L, 3)); + OsEng.moduleEngine().module()->goToGeo(latitude, longitude, + altitude); + } + + return 0; +} + + +} // namespace luascriptfunctions +} // nameapace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/globes/chunkedlodglobe.cpp b/modules/globebrowsing/globes/chunkedlodglobe.cpp index 48fffb6faa..60de75ff00 100644 --- a/modules/globebrowsing/globes/chunkedlodglobe.cpp +++ b/modules/globebrowsing/globes/chunkedlodglobe.cpp @@ -174,10 +174,13 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const { // Get the tile providers for the height maps const std::vector>& heightMapLayers = - _layerManager->layerGroup(layergroupid::HeightLayers).activeLayers(); + _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 ChunkTile chunkTile = tileProvider->getChunkTile(tileIndex); const Tile& tile = chunkTile.tile; @@ -188,8 +191,9 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const { } ghoul::opengl::Texture* tileTexture = tile.texture(); - if (!tileTexture) - return 0; + if (!tileTexture) { + return 0; + } glm::vec2 transformedUv = Tile::TileUvToTextureSamplePosition( uvTransform, @@ -253,12 +257,19 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const { float sample = sample0 * (1.0 - samplePosFract.y) + sample1 * samplePosFract.y; - // 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); + // 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; @@ -346,6 +357,7 @@ void ChunkedLodGlobe::debugRenderChunk(const Chunk& chunk, const glm::dmat4& mvp } void ChunkedLodGlobe::update(const UpdateData& data) { + setBoundingSphere(_owner.ellipsoid().maximumRadius() * data.modelTransform.scale); _renderer->update(); } diff --git a/modules/globebrowsing/globes/pointglobe.cpp b/modules/globebrowsing/globes/pointglobe.cpp index 1de34b1fa7..110571ae35 100644 --- a/modules/globebrowsing/globes/pointglobe.cpp +++ b/modules/globebrowsing/globes/pointglobe.cpp @@ -38,7 +38,20 @@ namespace globebrowsing { PointGlobe::PointGlobe(const RenderableGlobe& owner) : _owner(owner) -{} + , _intensityClamp( + "intensityClamp", + "Intensity clamp", + 1, 0, 1 + ) + , _lightIntensity( + "lightIntensity", + "Light intensity", + 1, 0, 50 + ) +{ + addProperty(_intensityClamp); + addProperty(_lightIntensity); +} PointGlobe::~PointGlobe() { glDeleteBuffers(1, &_vertexBufferID); @@ -56,21 +69,27 @@ bool PointGlobe::initialize() { glBindVertexArray(_vaoID); - // Vertex data is only one point in the origin - glm::vec3 data = glm::vec3(0,0,0); - + std::array quadVertexData = {{ + glm::vec2(-1.0f, -1.0f), + glm::vec2(1.0f, -1.0f), + glm::vec2(-1.0f, 1.0f), + glm::vec2(-1.0f, 1.0f), + glm::vec2(1.0f, -1.0f), + glm::vec2(1.0f, 1.0f) + }}; + // Vertex buffer glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID); glBufferData( GL_ARRAY_BUFFER, - sizeof(glm::vec3), - &data, + sizeof(glm::vec2) * quadVertexData.size(), + quadVertexData.data(), GL_STATIC_DRAW ); // Position at location 0 glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), 0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec2), 0); glBindVertexArray(0); @@ -91,32 +110,55 @@ void PointGlobe::render(const RenderData& data) { // Calculate variables to be used as uniform variables in shader glm::dvec3 bodyPosition = data.modelTransform.translation; + glm::dmat4 rotationTransform = glm::lookAt( + glm::dvec3(0.0f), + data.camera.positionVec3() - bodyPosition, + glm::normalize(glm::dvec3(1000000.0f) - bodyPosition)); + + glm::dvec3 camToBody = bodyPosition - data.camera.positionVec3(); + float distanceToBody = glm::length(camToBody); + + float avgRadius = _owner.ellipsoid().averageRadius(); + float lightIntensity = _lightIntensity.value() * data.modelTransform.scale * avgRadius / distanceToBody; + float lightIntensityClamped = glm::min(lightIntensity, _intensityClamp.value()); + //float lightOverflow = glm::max(lightIntensity - lightIntensityClamped, 0.0f); + + float billboardRadius = lightIntensityClamped * distanceToBody; + 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 glm::dmat4 modelTransform = glm::translate(glm::dmat4(1.0), bodyPosition) * // Translation - glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); // Scale + glm::inverse(rotationTransform) * + scaleTransform; // Scale glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; - glm::vec3 directionToSun = glm::normalize(glm::vec3(0) - glm::vec3(bodyPosition)); - glm::vec3 directionToSunViewSpace = glm::mat3(data.camera.combinedViewMatrix()) * directionToSun; + //glm::vec3 directionToSun = glm::normalize(glm::vec3(0) - glm::vec3(bodyPosition)); + //glm::vec3 directionToSunViewSpace = glm::mat3(data.camera.combinedViewMatrix()) * directionToSun; - int windowWidth = OsEng.windowWrapper().currentWindowSize().x; - float avgRadius = _owner.ellipsoid().averageRadius(); - - _programObject->setUniform("windowWidth", windowWidth); - _programObject->setUniform("globeRadius", avgRadius); - _programObject->setUniform("directionToSunViewSpace", directionToSunViewSpace); + + _programObject->setUniform("lightIntensityClamped", lightIntensityClamped); + //_programObject->setUniform("lightOverflow", lightOverflow); + //_programObject->setUniform("directionToSunViewSpace", directionToSunViewSpace); _programObject->setUniform("modelViewTransform", glm::mat4(modelViewTransform)); _programObject->setUniform("projectionTransform", data.camera.sgctInternal.projectionMatrix()); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); - + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glBindVertexArray(_vaoID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vertexBufferID); - glDrawArrays(GL_POINTS, 0, 1); + glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); - + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + _programObject->deactivate(); } diff --git a/modules/globebrowsing/globes/pointglobe.h b/modules/globebrowsing/globes/pointglobe.h index 9750444785..34c28ab6fb 100644 --- a/modules/globebrowsing/globes/pointglobe.h +++ b/modules/globebrowsing/globes/pointglobe.h @@ -26,6 +26,7 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___POINTGLOBE___H__ #include +#include #include @@ -55,6 +56,9 @@ private: GLuint _vertexBufferID; GLuint _vaoID; + + properties::FloatProperty _intensityClamp; + properties::FloatProperty _lightIntensity; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/globes/renderableglobe.cpp b/modules/globebrowsing/globes/renderableglobe.cpp index 72a80d9d3b..6b61e0f7d0 100644 --- a/modules/globebrowsing/globes/renderableglobe.cpp +++ b/modules/globebrowsing/globes/renderableglobe.cpp @@ -26,13 +26,12 @@ #include #include +#include #include namespace { const char* keyFrame = "Frame"; const char* keyRadii = "Radii"; - const char* keyInteractionDepthBelowEllipsoid = "InteractionDepthBelowEllipsoid"; - const char* keyCameraMinHeight = "CameraMinHeight"; const char* keySegmentsPerPatch = "SegmentsPerPatch"; const char* keyLayers = "Layers"; } @@ -64,11 +63,12 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) BoolProperty("enabled", "Enabled", true), BoolProperty("performShading", "perform shading", true), BoolProperty("atmosphere", "atmosphere", false), + BoolProperty("useAccurateNormals", "useAccurateNormals", false), FloatProperty("lodScaleFactor", "lodScaleFactor",10.0f, 1.0f, 50.0f), - FloatProperty("cameraMinHeight", "cameraMinHeight", 100.0f, 0.0f, 1000.0f) + FloatProperty("cameraMinHeight", "cameraMinHeight", 100.0f, 0.0f, 1000.0f), + FloatProperty("orenNayarRoughness", "orenNayarRoughness", 0.0f, 0.0f, 1.0f) }) , _debugPropertyOwner("Debug") - , _texturePropertyOwner("Textures") { setName("RenderableGlobe"); @@ -78,21 +78,12 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) glm::dvec3 radii; dictionary.getValue(keyRadii, radii); _ellipsoid = Ellipsoid(radii); - setBoundingSphere(_ellipsoid.averageRadius()); + setBoundingSphere(_ellipsoid.maximumRadius()); // Ghoul can't read ints from lua dictionaries... double patchSegmentsd; dictionary.getValue(keySegmentsPerPatch, patchSegmentsd); int patchSegments = patchSegmentsd; - - if (!dictionary.getValue(keyInteractionDepthBelowEllipsoid, - _interactionDepthBelowEllipsoid)) { - _interactionDepthBelowEllipsoid = 0; - } - - float cameraMinHeight; - dictionary.getValue(keyCameraMinHeight, cameraMinHeight); - _generalProperties.cameraMinHeight.set(cameraMinHeight); // Init layer manager ghoul::Dictionary layersDictionary; @@ -105,19 +96,18 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) _chunkedLodGlobe = std::make_shared( *this, patchSegments, _layerManager); + //_pointGlobe = std::make_shared(*this); - // 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. - double fov = 2 * glm::pi() / 6; // 60 degrees - int res = 2880; - double distance = res * _ellipsoid.maximumRadius() / tan(fov / 2); - _distanceSwitch.addSwitchValue(_chunkedLodGlobe, distance); + _distanceSwitch.addSwitchValue(_chunkedLodGlobe); + //_distanceSwitch.addSwitchValue(_pointGlobe); addProperty(_generalProperties.isEnabled); addProperty(_generalProperties.atmosphereEnabled); addProperty(_generalProperties.performShading); + addProperty(_generalProperties.useAccurateNormals); addProperty(_generalProperties.lodScaleFactor); addProperty(_generalProperties.cameraMinHeight); + addProperty(_generalProperties.orenNayarRoughness); _debugPropertyOwner.addProperty(_debugProperties.saveOrThrowCamera); _debugPropertyOwner.addProperty(_debugProperties.showChunkEdges); @@ -140,6 +130,7 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) _chunkedLodGlobe->notifyShaderRecompilation(); }; _generalProperties.atmosphereEnabled.onChange(notifyShaderRecompilation); + _generalProperties.useAccurateNormals.onChange(notifyShaderRecompilation); _generalProperties.performShading.onChange(notifyShaderRecompilation); _debugProperties.showChunkEdges.onChange(notifyShaderRecompilation); _debugProperties.showHeightResolution.onChange(notifyShaderRecompilation); @@ -149,6 +140,7 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) addPropertySubOwner(_debugPropertyOwner); addPropertySubOwner(_layerManager.get()); + //addPropertySubOwner(_pointGlobe.get()); } bool RenderableGlobe::initialize() { @@ -229,6 +221,10 @@ std::shared_ptr RenderableGlobe::chunkedLodGlobe() const{ return _chunkedLodGlobe; } +LayerManager* RenderableGlobe::layerManager() const { + return _layerManager.get(); +} + const Ellipsoid& RenderableGlobe::ellipsoid() const{ return _ellipsoid; } @@ -255,8 +251,33 @@ const std::shared_ptr RenderableGlobe::savedCamera() const { return _savedCamera; } -double RenderableGlobe::interactionDepthBelowEllipsoid() { - return _interactionDepthBelowEllipsoid; +SurfacePositionHandle RenderableGlobe::calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace) +{ + 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) { diff --git a/modules/globebrowsing/globes/renderableglobe.h b/modules/globebrowsing/globes/renderableglobe.h index b90e01eec2..73e080b2cc 100644 --- a/modules/globebrowsing/globes/renderableglobe.h +++ b/modules/globebrowsing/globes/renderableglobe.h @@ -32,11 +32,13 @@ #include #include +#include namespace openspace { namespace globebrowsing { class ChunkedLodGlobe; +class PointGlobe; class LayerManager; /** @@ -73,8 +75,10 @@ public: properties::BoolProperty isEnabled; properties::BoolProperty performShading; properties::BoolProperty atmosphereEnabled; + properties::BoolProperty useAccurateNormals; properties::FloatProperty lodScaleFactor; properties::FloatProperty cameraMinHeight; + properties::FloatProperty orenNayarRoughness; }; RenderableGlobe(const ghoul::Dictionary& dictionary); @@ -93,6 +97,7 @@ public: // Getters std::shared_ptr chunkedLodGlobe() const; + LayerManager* layerManager() const; const Ellipsoid& ellipsoid() const; const glm::dmat4& modelTransform() const; const glm::dmat4& inverseModelTransform() const; @@ -102,18 +107,22 @@ public: double interactionDepthBelowEllipsoid(); // Setters - void setSaveCamera(std::shared_ptr camera); + void setSaveCamera(std::shared_ptr camera); + + virtual SurfacePositionHandle calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace) override; + private: // Globes. These are renderables inserted in a distance switch so that the heavier // ChunkedLodGlobe does not have to be rendered at far distances. std::shared_ptr _chunkedLodGlobe; + //std::shared_ptr _pointGlobe; Ellipsoid _ellipsoid; std::shared_ptr _layerManager; DistanceSwitch _distanceSwitch; std::shared_ptr _savedCamera; - double _interactionDepthBelowEllipsoid; std::string _frame; double _time; @@ -124,7 +133,6 @@ private: DebugProperties _debugProperties; GeneralProperties _generalProperties; properties::PropertyOwner _debugPropertyOwner; - properties::PropertyOwner _texturePropertyOwner; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/meshes/trianglesoup.h b/modules/globebrowsing/meshes/trianglesoup.h index d754b0b244..5085003cec 100644 --- a/modules/globebrowsing/meshes/trianglesoup.h +++ b/modules/globebrowsing/meshes/trianglesoup.h @@ -83,7 +83,6 @@ protected: GLfloat position[4]; GLfloat texture[2]; GLfloat normal[3]; - private: GLubyte padding[28]; // Pads the struct out to 64 bytes for performance increase }; diff --git a/modules/globebrowsing/other/concurrentjobmanager.h b/modules/globebrowsing/other/concurrentjobmanager.h index 910a02ef1f..fad0a62704 100644 --- a/modules/globebrowsing/other/concurrentjobmanager.h +++ b/modules/globebrowsing/other/concurrentjobmanager.h @@ -51,7 +51,7 @@ struct Job { template class ConcurrentJobManager { public: - ConcurrentJobManager(std::shared_ptr pool); + ConcurrentJobManager(ThreadPool pool); void enqueueJob(std::shared_ptr> job); @@ -63,8 +63,8 @@ public: private: ConcurrentQueue>> _finishedJobs; - std::shared_ptr threadPool; std::mutex _finishedJobsMutex; + ThreadPool threadPool; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/other/concurrentjobmanager.inl b/modules/globebrowsing/other/concurrentjobmanager.inl index a522216f5b..763f46b848 100644 --- a/modules/globebrowsing/other/concurrentjobmanager.inl +++ b/modules/globebrowsing/other/concurrentjobmanager.inl @@ -34,13 +34,13 @@ template Job

::~Job() {} template -ConcurrentJobManager

::ConcurrentJobManager(std::shared_ptr pool) +ConcurrentJobManager

::ConcurrentJobManager(ThreadPool pool) : threadPool(pool) { } template void ConcurrentJobManager

::enqueueJob(std::shared_ptr> job) { - threadPool->enqueue([this, job]() { + threadPool.enqueue([this, job]() { job->execute(); std::lock_guard lock(_finishedJobsMutex); _finishedJobs.push(job); @@ -49,7 +49,7 @@ void ConcurrentJobManager

::enqueueJob(std::shared_ptr> job) { template void ConcurrentJobManager

::clearEnqueuedJobs() { - threadPool->clearTasks(); + threadPool.clearTasks(); } template diff --git a/modules/globebrowsing/other/distanceswitch.cpp b/modules/globebrowsing/other/distanceswitch.cpp index 1b6ff8349f..aeb95de079 100644 --- a/modules/globebrowsing/other/distanceswitch.cpp +++ b/modules/globebrowsing/other/distanceswitch.cpp @@ -32,7 +32,6 @@ namespace globebrowsing { DistanceSwitch::~DistanceSwitch() {} bool DistanceSwitch::initialize() { - _objectScale = 1.0; for (unsigned int i = 0; i < _renderables.size(); ++i) { _renderables[i]->initialize(); } @@ -46,44 +45,32 @@ bool DistanceSwitch::deinitialize() { return true; } - void DistanceSwitch::render(const RenderData& data) { - if (_maxDistances.size() == 0) { - return; - } - - double distanceToCamera = distance(data.camera.positionVec3(), data.modelTransform.translation); - - if (distanceToCamera > _maxDistances.back() * _objectScale) { - return; - } + 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 + int res = 2880; + // linear search through nodes to find which Renderable to render - for (unsigned int i = 0; i < _renderables.size(); ++i) { - if (distanceToCamera < _maxDistances[i] * _objectScale) { - _renderables[i]->render(data); - return; + for (std::shared_ptr renderable : _renderables) { + const double distance = res * renderable->boundingSphere() / tan(fov / 2); + if (distanceToCamera < distance) { + renderable->render(data); } } } void DistanceSwitch::update(const UpdateData& data) { - _objectScale = data.modelTransform.scale; - for (unsigned int i = 0; i < _renderables.size(); ++i) { - _renderables[i]->update(data); + for (std::shared_ptr renderable : _renderables) { + renderable->update(data); } } -void DistanceSwitch::addSwitchValue(std::shared_ptr renderable, - double maxDistance) -{ - ghoul_assert(maxDistance > 0, "Renderable must have a positive maxDistance"); - if (_maxDistances.size() > 0) { - ghoul_assert(maxDistance > _maxDistances.back(), - "Renderables must be inserted in ascending order wrt distance"); - } +void DistanceSwitch::addSwitchValue(std::shared_ptr renderable) { _renderables.push_back(renderable); - _maxDistances.push_back(maxDistance); } } // namespace globebrowsing diff --git a/modules/globebrowsing/other/distanceswitch.h b/modules/globebrowsing/other/distanceswitch.h index 9f26e35f43..2ba77a9d90 100644 --- a/modules/globebrowsing/other/distanceswitch.h +++ b/modules/globebrowsing/other/distanceswitch.h @@ -39,7 +39,7 @@ namespace globebrowsing { /** * Selects a specific Renderable to be used for rendering, based on distance to the * camera -*/ + */ class DistanceSwitch { public: ~DistanceSwitch(); @@ -50,20 +50,17 @@ public: /** * Picks the first Renderable with the associated maxDistance greater than the * current distance to the camera - */ + */ void render(const RenderData& data); void update(const UpdateData& data); /** - * Adds a new renderable (first argument) which may be rendered only if the distance - * to the camera is less than maxDistance (second argument) - */ - void addSwitchValue(std::shared_ptr renderable, double maxDistance); + * Adds a new renderable + */ + void addSwitchValue(std::shared_ptr renderable); private: std::vector> _renderables; - std::vector _maxDistances; - double _objectScale; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/other/lruthreadpool.h b/modules/globebrowsing/other/lruthreadpool.h index 35a370a179..1b89e04ce1 100644 --- a/modules/globebrowsing/other/lruthreadpool.h +++ b/modules/globebrowsing/other/lruthreadpool.h @@ -33,6 +33,7 @@ #include #include #include +#include // Implementatin based on http://progsch.net/wordpress/?p=81 @@ -65,6 +66,7 @@ template class LRUThreadPool { public: LRUThreadPool(size_t numThreads, size_t queueSize); + LRUThreadPool(const LRUThreadPool& toCopy); ~LRUThreadPool(); void enqueue(std::function f, KeyType key); diff --git a/modules/globebrowsing/other/lruthreadpool.inl b/modules/globebrowsing/other/lruthreadpool.inl index 329767e3bc..bcc57029b5 100644 --- a/modules/globebrowsing/other/lruthreadpool.inl +++ b/modules/globebrowsing/other/lruthreadpool.inl @@ -68,11 +68,18 @@ LRUThreadPool::LRUThreadPool(size_t numThreads, size_t queueSize) } } +template +LRUThreadPool::LRUThreadPool(const LRUThreadPool& toCopy) + : LRUThreadPool(toCopy._workers.size(), toCopy._queuedTasks.maximumCacheSize()) +{ } + // the destructor joins all threads template LRUThreadPool::~LRUThreadPool() { - // Stop all threads - _stop = true; + { + std::unique_lock lock(_queueMutex); + _stop = true; + } _condition.notify_all(); // join them diff --git a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.h b/modules/globebrowsing/other/prioritizingconcurrentjobmanager.h index f2314b07f5..6b166dd1a2 100644 --- a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.h +++ b/modules/globebrowsing/other/prioritizingconcurrentjobmanager.h @@ -43,7 +43,7 @@ namespace globebrowsing { template class PrioritizingConcurrentJobManager { public: - PrioritizingConcurrentJobManager(std::shared_ptr> pool); + PrioritizingConcurrentJobManager(LRUThreadPool pool); /** * Enqueues a job which is identified using a given key @@ -85,9 +85,10 @@ public: private: ConcurrentQueue>> _finishedJobs; - /// An LRU thread pool is used since the jobs can be bumped and hence prioritized. - std::shared_ptr> _threadPool; std::mutex _finishedJobsMutex; + /// An LRU thread pool is used since the jobs can be bumped and hence prioritized. + LRUThreadPool _threadPool; + }; } // namespace globebrowsing diff --git a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.inl b/modules/globebrowsing/other/prioritizingconcurrentjobmanager.inl index ebe0147947..dbfbcbefdf 100644 --- a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.inl +++ b/modules/globebrowsing/other/prioritizingconcurrentjobmanager.inl @@ -29,7 +29,7 @@ namespace globebrowsing { template PrioritizingConcurrentJobManager::PrioritizingConcurrentJobManager( - std::shared_ptr> pool) + LRUThreadPool pool) : _threadPool(pool) { } @@ -37,7 +37,7 @@ template void PrioritizingConcurrentJobManager::enqueueJob(std::shared_ptr> job, KeyType key) { - _threadPool->enqueue([this, job]() { + _threadPool.enqueue([this, job]() { job->execute(); std::lock_guard lock(_finishedJobsMutex); _finishedJobs.push(job); @@ -47,23 +47,23 @@ void PrioritizingConcurrentJobManager::enqueueJob(std::shared_ptr std::vector PrioritizingConcurrentJobManager::getKeysToUnfinishedJobs() { - return _threadPool->getUnqueuedTasksKeys(); + return _threadPool.getUnqueuedTasksKeys(); } template std::vector PrioritizingConcurrentJobManager::getKeysToEnqueuedJobs() { - return _threadPool->getQueuedTasksKeys(); + return _threadPool.getQueuedTasksKeys(); } template bool PrioritizingConcurrentJobManager::touch(KeyType key) { - return _threadPool->touch(key); + return _threadPool.touch(key); } template void PrioritizingConcurrentJobManager::clearEnqueuedJobs() { - _threadPool->clearEnqueuedTasks(); + _threadPool.clearEnqueuedTasks(); } template diff --git a/modules/globebrowsing/other/threadpool.cpp b/modules/globebrowsing/other/threadpool.cpp index 10de678202..a5a6fb718a 100644 --- a/modules/globebrowsing/other/threadpool.cpp +++ b/modules/globebrowsing/other/threadpool.cpp @@ -67,10 +67,17 @@ ThreadPool::ThreadPool(size_t numThreads) } } +ThreadPool::ThreadPool(const ThreadPool& toCopy) + : ThreadPool(toCopy.workers.size()) +{ } + // the destructor joins all threads ThreadPool::~ThreadPool() { // stop all threads - stop = true; + { + std::unique_lock lock(queue_mutex); + stop = true; + } condition.notify_all(); // join them diff --git a/modules/globebrowsing/other/threadpool.h b/modules/globebrowsing/other/threadpool.h index 97bf25190b..475714086f 100644 --- a/modules/globebrowsing/other/threadpool.h +++ b/modules/globebrowsing/other/threadpool.h @@ -31,6 +31,7 @@ #include #include #include +#include // Implementatin based on http://progsch.net/wordpress/?p=81 @@ -50,6 +51,7 @@ private: class ThreadPool { public: ThreadPool(size_t numThreads); + ThreadPool(const ThreadPool& toCopy); ~ThreadPool(); void enqueue(std::function f); diff --git a/modules/globebrowsing/rendering/chunkrenderer.cpp b/modules/globebrowsing/rendering/chunkrenderer.cpp index 7a35557cad..f5c931878b 100644 --- a/modules/globebrowsing/rendering/chunkrenderer.cpp +++ b/modules/globebrowsing/rendering/chunkrenderer.cpp @@ -112,6 +112,79 @@ ghoul::opengl::ProgramObject* ChunkRenderer::getActivatedProgramWithTileData( return programObject; } +void ChunkRenderer::setCommonUniforms(ghoul::opengl::ProgramObject& programObject, + const Chunk& chunk, const RenderData& data) +{ + glm::dmat4 modelTransform = chunk.owner().modelTransform(); + glm::dmat4 viewTransform = data.camera.combinedViewMatrix(); + 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) + { + glm::vec3 directionToSunWorldSpace = + glm::normalize(-data.modelTransform.translation); + glm::vec3 directionToSunCameraSpace = + (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); + programObject.setUniform( + "lightDirectionCameraSpace", -directionToSunCameraSpace); + } + + if (chunk.owner().generalProperties().performShading) { + programObject.setUniform( + "orenNayarRoughness", + chunk.owner().generalProperties().orenNayarRoughness); + } + + if (chunk.owner().generalProperties().useAccurateNormals) { + glm::dvec3 corner00 = chunk.owner().ellipsoid().cartesianSurfacePosition( + chunk.surfacePatch().getCorner(Quad::SOUTH_WEST)); + glm::dvec3 corner10 = chunk.owner().ellipsoid().cartesianSurfacePosition( + chunk.surfacePatch().getCorner(Quad::SOUTH_EAST)); + glm::dvec3 corner01 = chunk.owner().ellipsoid().cartesianSurfacePosition( + chunk.surfacePatch().getCorner(Quad::NORTH_WEST)); + glm::dvec3 corner11 = chunk.owner().ellipsoid().cartesianSurfacePosition( + chunk.surfacePatch().getCorner(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. + float tileDelta = 1.0f / 64.0f; + glm::vec3 deltaTheta0 = glm::vec3(corner10 - corner00) * tileDelta; + glm::vec3 deltaTheta1 = glm::vec3(corner11 - corner01) * tileDelta; + glm::vec3 deltaPhi0 = glm::vec3(corner01 - corner00) * tileDelta; + glm::vec3 deltaPhi1 = glm::vec3(corner11 - corner10) * tileDelta; + + // Transform to camera space + glm::mat3 modelViewTransformMat3 = glm::mat3(modelViewTransform); + deltaTheta0 = modelViewTransformMat3 * deltaTheta0; + deltaTheta1 = modelViewTransformMat3 * deltaTheta1; + deltaPhi0 = modelViewTransformMat3 * deltaPhi0; + deltaPhi1 = modelViewTransformMat3 * deltaPhi1; + + // 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); + } + + if (chunk.owner().generalProperties().performShading) { + programObject.setUniform( + "orenNayarRoughness", + chunk.owner().generalProperties().orenNayarRoughness); + } +} + void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& data){ ghoul::opengl::ProgramObject* programObject = getActivatedProgramWithTileData( @@ -155,20 +228,24 @@ void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& da programObject->setUniform("radiiSquared", glm::vec3(ellipsoid.radiiSquared())); if (_layerManager->layerGroup( - layergroupid::NightLayers).activeLayers().size() > 0 || + layergroupid::GroupID::NightLayers).activeLayers().size() > 0 || _layerManager->layerGroup( - layergroupid::WaterMasks).activeLayers().size() > 0 || + layergroupid::GroupID::WaterMasks).activeLayers().size() > 0 || chunk.owner().generalProperties().atmosphereEnabled || - chunk.owner().generalProperties().performShading) { - // This code temporary until real light sources can be implemented. - glm::vec3 directionToSunWorldSpace = - glm::normalize(-data.modelTransform.translation); - glm::vec3 directionToSunCameraSpace = - (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); + chunk.owner().generalProperties().performShading) + { programObject->setUniform("modelViewTransform", modelViewTransform); - programObject->setUniform( - "lightDirectionCameraSpace", -directionToSunCameraSpace); } + + if (chunk.owner().generalProperties().useAccurateNormals && + _layerManager->layerGroup(layergroupid::HeightLayers).activeLayers().size() > 0) + { + // Apply an extra scaling to the height if the object is scaled + programObject->setUniform( + "heightScale", static_cast(data.modelTransform.scale)); + } + + setCommonUniforms(*programObject, chunk, data); // OpenGL rendering settings glEnable(GL_DEPTH_TEST); @@ -235,21 +312,16 @@ void ChunkRenderer::renderChunkLocally(const Chunk& chunk, const RenderData& dat programObject->setUniform("patchNormalCameraSpace", patchNormalCameraSpace); programObject->setUniform("projectionTransform", data.camera.sgctInternal.projectionMatrix()); - if (_layerManager->layerGroup( - layergroupid::NightLayers).activeLayers().size() > 0 || - _layerManager->layerGroup( - layergroupid::WaterMasks).activeLayers().size() > 0 || - chunk.owner().generalProperties().atmosphereEnabled || - chunk.owner().generalProperties().performShading) - { - glm::vec3 directionToSunWorldSpace = - glm::normalize(-data.modelTransform.translation); - glm::vec3 directionToSunCameraSpace = - (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); + if (_layerManager->layerGroup(layergroupid::HeightLayers).activeLayers().size() > 0) { + // Apply an extra scaling to the height if the object is scaled programObject->setUniform( - "lightDirectionCameraSpace", -directionToSunCameraSpace); + "heightScale", static_cast(data.modelTransform.scale)); } + setCommonUniforms(*programObject, chunk, data); + + + // OpenGL rendering settings glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); diff --git a/modules/globebrowsing/rendering/chunkrenderer.h b/modules/globebrowsing/rendering/chunkrenderer.h index 90995a6f05..9caf680685 100644 --- a/modules/globebrowsing/rendering/chunkrenderer.h +++ b/modules/globebrowsing/rendering/chunkrenderer.h @@ -87,6 +87,9 @@ private: std::shared_ptr gpuLayerManager, const Chunk& chunk); + 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; diff --git a/modules/globebrowsing/rendering/gpu/gpuheightlayer.cpp b/modules/globebrowsing/rendering/gpu/gpuheightlayer.cpp index 5b77c34f9b..ce2fa871ef 100644 --- a/modules/globebrowsing/rendering/gpu/gpuheightlayer.cpp +++ b/modules/globebrowsing/rendering/gpu/gpuheightlayer.cpp @@ -38,7 +38,7 @@ void GPUHeightLayer::setValue(ghoul::opengl::ProgramObject* programObject, int pileSize) { GPULayer::setValue(programObject, layer, tileIndex, pileSize); - _gpuDepthTransform.setValue(programObject, layer.tileProvider()->depthTransform()); + _gpuDepthTransform.setValue(programObject, layer.depthTransform()); } void GPUHeightLayer::bind(ghoul::opengl::ProgramObject* programObject, const Layer& layer, diff --git a/modules/globebrowsing/rendering/gpu/gpulayer.cpp b/modules/globebrowsing/rendering/gpu/gpulayer.cpp index e02dd15a45..edfeb457ef 100644 --- a/modules/globebrowsing/rendering/gpu/gpulayer.cpp +++ b/modules/globebrowsing/rendering/gpu/gpulayer.cpp @@ -33,15 +33,51 @@ void GPULayer::setValue(ghoul::opengl::ProgramObject* programObject, const Layer const TileIndex& tileIndex, int pileSize) { ChunkTilePile chunkTilePile = layer.getChunkTilePile(tileIndex, pileSize); - gpuChunkTilePile.setValue(programObject, chunkTilePile); 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: + gpuChunkTilePile.setValue(programObject, chunkTilePile); + 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) { - gpuChunkTilePile.bind(programObject, nameBase + "pile.", 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); + break; + case layergroupid::TypeID::SolidColor: + gpuColor.bind(programObject, nameBase + "color"); + break; + default: + break; + } } void GPULayer::deactivate() { diff --git a/modules/globebrowsing/rendering/gpu/gpulayer.h b/modules/globebrowsing/rendering/gpu/gpulayer.h index 3cc2e881c9..746c581b25 100644 --- a/modules/globebrowsing/rendering/gpu/gpulayer.h +++ b/modules/globebrowsing/rendering/gpu/gpulayer.h @@ -26,6 +26,7 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER___H__ #include +#include #include #include #include @@ -73,6 +74,10 @@ public: private: GPUChunkTilePile gpuChunkTilePile; GPULayerRenderSettings gpuRenderSettings; + GPULayerAdjustment gpuLayerAdjustment; + + // Adjustment layer stuff + GPUData gpuColor; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gpulayeradjustment.cpp b/modules/globebrowsing/rendering/gpu/gpulayeradjustment.cpp new file mode 100644 index 0000000000..69ff1707bb --- /dev/null +++ b/modules/globebrowsing/rendering/gpu/gpulayeradjustment.cpp @@ -0,0 +1,64 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include + +namespace openspace { +namespace 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.value()); + gpuChromaKeyTolerance.setValue(programObject, layerAdjustment.chromaKeyTolerance.value()); + 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 globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/rendering/gpu/gpulayeradjustment.h b/modules/globebrowsing/rendering/gpu/gpulayeradjustment.h new file mode 100644 index 0000000000..3a53b8808f --- /dev/null +++ b/modules/globebrowsing/rendering/gpu/gpulayeradjustment.h @@ -0,0 +1,56 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER_ADJUSMENT___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER_ADJUSMENT___H__ + +#include + +namespace ghoul { namespace opengl { +class ProgramObject; +}} + +namespace openspace { +namespace globebrowsing { + +struct 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 globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER_ADJUSMENT___H__ diff --git a/modules/globebrowsing/rendering/gpu/gpulayergroup.cpp b/modules/globebrowsing/rendering/gpu/gpulayergroup.cpp index 407dd8c7c3..12715dff59 100644 --- a/modules/globebrowsing/rendering/gpu/gpulayergroup.cpp +++ b/modules/globebrowsing/rendering/gpu/gpulayergroup.cpp @@ -58,7 +58,7 @@ void GPULayerGroup::bind(ghoul::opengl::ProgramObject* programObject, int pileSize = layerGroup.pileSize(); for (size_t i = 0; i < _gpuActiveLayers.size(); ++i) { // should maybe a proper GPULayer factory - _gpuActiveLayers[i] = (category == layergroupid::HeightLayers) ? + _gpuActiveLayers[i] = (category == layergroupid::GroupID::HeightLayers) ? std::make_unique() : std::make_unique(); std::string nameExtension = "[" + std::to_string(i) + "]."; diff --git a/modules/globebrowsing/rendering/layer/layer.cpp b/modules/globebrowsing/rendering/layer/layer.cpp index 5f50476aab..d4f482ba8c 100644 --- a/modules/globebrowsing/rendering/layer/layer.cpp +++ b/modules/globebrowsing/rendering/layer/layer.cpp @@ -30,60 +30,296 @@ namespace openspace { namespace globebrowsing { namespace { + const char* _loggerCat = "Layer"; + const char* keyName = "Name"; const char* keyEnabled = "Enabled"; const char* keyLayerGroupID = "LayerGroupID"; const char* keySettings = "Settings"; + const char* keyAdjustment = "Adjustment"; + const char* KeyBlendMode = "BlendMode"; } -Layer::Layer(layergroupid::ID id, const ghoul::Dictionary& layerDict) +Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict) : properties::PropertyOwner(layerDict.value(keyName)) + , _typeOption( + "type", + "Type", + properties::OptionProperty::DisplayType::Dropdown + ) + , _blendModeOption( + "blendMode", + "Blend Mode", + properties::OptionProperty::DisplayType::Dropdown + ) , _enabled(properties::BoolProperty("enabled", "Enabled", false)) , _reset("reset", "Reset") -{ - // We add the id to the dictionary since it needs to be known by - // the tile provider - ghoul::Dictionary newLayerDict = layerDict; - newLayerDict.setValue(keyLayerGroupID, id); - - _tileProvider = std::shared_ptr( - tileprovider::TileProvider::createFromDictionary(newLayerDict)); - - // Something else went wrong and no exception was thrown - if (_tileProvider == nullptr) { - throw ghoul::RuntimeError("Unable to create TileProvider '" + name() + "'"); + , _tileProvider(nullptr) + , _otherTypesProperties{ + properties::Vec3Property ( + "color", + "Color", + glm::vec4(1.f, 1.f, 1.f, 1.f), + glm::vec4(0.f), + glm::vec4(1.f)) } + , _layerGroupId(id) +{ + layergroupid::TypeID typeID = parseTypeIdFromDictionary(layerDict); + 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); + // Initialize settings ghoul::Dictionary settingsDict; if (layerDict.getValue(keySettings, settingsDict)) { _renderSettings.setValuesFromDictionary(settingsDict); } - if (id == layergroupid::ID::GrayScaleColorOverlays) { - _renderSettings.addProperty(_renderSettings.valueBlending); - _renderSettings.useValueBlending = true; + + // Initiallize layer adjustment + ghoul::Dictionary adjustmentDict; + if (layerDict.getValue(keyAdjustment, adjustmentDict)) { + _layerAdjustment.setValuesFromDictionary(adjustmentDict); } - _reset.onChange([&](){ - _tileProvider->reset(); + // Add options to option properties + for (int i = 0; i < layergroupid::NUM_LAYER_TYPES; ++i) { + _typeOption.addOption(i, layergroupid::LAYER_TYPE_NAMES[i]); + } + _typeOption.setValue(static_cast(typeID)); + _type = static_cast(_typeOption.value()); + + for (int i = 0; i < layergroupid::NUM_BLEND_MODES; ++i) { + _blendModeOption.addOption(i, layergroupid::BLEND_MODE_NAMES[i]); + } + + // Initialize blend mode + std::string blendModeName; + if (layerDict.getValue(KeyBlendMode, blendModeName)) { + layergroupid::BlendModeID blendModeID = + layergroupid::getBlendModeIDFromName(blendModeName); + _blendModeOption.setValue(static_cast(blendModeID)); + } + else { + _blendModeOption.setValue(static_cast(layergroupid::BlendModeID::Normal)); + } + + // On change callbacks definitions + _enabled.onChange([&](){ + if (_onChangeCallback) { + _onChangeCallback(); + } }); + _reset.onChange([&](){ + if (_tileProvider) { + _tileProvider->reset(); + } + }); + + _typeOption.onChange([&](){ + removeVisibleProperties(); + _type = static_cast(_typeOption.value()); + ghoul::Dictionary dict; + initializeBasedOnType(type(), dict); + addVisibleProperties(); + if (_onChangeCallback) { + _onChangeCallback(); + } + }); + + _blendModeOption.onChange([&](){ + if (_onChangeCallback) { + _onChangeCallback(); + } + }); + + _layerAdjustment.onChange([&](){ + if (_onChangeCallback) { + _onChangeCallback(); + } + }); + + _typeOption.setReadOnly(true); + + // Add the properties + addProperty(_typeOption); + addProperty(_blendModeOption); addProperty(_enabled); addProperty(_reset); + _otherTypesProperties.color.setViewOption(properties::Property::ViewOptions::Color); + + addVisibleProperties(); + addPropertySubOwner(_renderSettings); - addPropertySubOwner(*_tileProvider); + addPropertySubOwner(_layerAdjustment); } ChunkTilePile Layer::getChunkTilePile(const TileIndex& tileIndex, int pileSize) const { - return _tileProvider->getChunkTilePile(tileIndex, pileSize); + if (_tileProvider) { + return _tileProvider->getChunkTilePile(tileIndex, pileSize); + } + else { + ChunkTilePile chunkTilePile; + chunkTilePile.resize(pileSize); + for (int i = 0; i < pileSize; ++i) { + chunkTilePile[i].tile = Tile::TileUnavailable; + chunkTilePile[i].uvTransform.uvOffset = { 0, 0 }; + chunkTilePile[i].uvTransform.uvScale = { 1, 1 }; + } + return chunkTilePile; + } +} + +Tile::Status Layer::getTileStatus(const TileIndex& index) const { + if (_tileProvider) { + return _tileProvider->getTileStatus(index); + } + else { + return Tile::Status::Unavailable; + } +} + +layergroupid::TypeID Layer::type() const { + return _type; +}; + +layergroupid::BlendModeID Layer::blendMode() const { + return static_cast(_blendModeOption.value()); +}; + + +TileDepthTransform Layer::depthTransform() const { + if (_tileProvider) { + return _tileProvider->depthTransform(); + } + else { + return {1.0f, 0.0f}; + } +} + +bool Layer::enabled() const { + return _enabled.value(); +} + +tileprovider::TileProvider* Layer::tileProvider() const { + return _tileProvider.get(); +} + +const Layer::OtherTypesProperties& Layer::otherTypesProperties() const { + return _otherTypesProperties; +} + +const LayerRenderSettings& Layer::renderSettings() const { + return _renderSettings; +} + +const LayerAdjustment& Layer::layerAdjustment() const { + return _layerAdjustment; } void Layer::onChange(std::function callback) { - _enabled.onChange(callback); + _onChangeCallback = callback; +} + +void Layer::update() { + if (_tileProvider) { + _tileProvider->update(); + } +} + +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) { + // 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: { + // We add the id to the dictionary since it needs to be known by + // the tile provider + ghoul::Dictionary tileProviderInitDict = initDict; + tileProviderInitDict.setValue(keyLayerGroupID, _layerGroupId); + if (tileProviderInitDict.hasKeyAndValue(keyName)) { + std::string name; + tileProviderInitDict.getValue(keyName, name); + LDEBUG("Initializing tile provider for layer: '" + name + "'"); + } + _tileProvider = std::shared_ptr( + tileprovider::TileProvider::createFromDictionary(typeId, tileProviderInitDict) + ); + break; + } + case layergroupid::TypeID::SolidColor: + break; + default: + throw ghoul::RuntimeError("Unable to create layer. Unknown type."); + break; + } +} + +void Layer::addVisibleProperties() { + 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) { + addPropertySubOwner(*_tileProvider); + } + break; + case layergroupid::TypeID::SolidColor: + addProperty(_otherTypesProperties.color); + default: + break; + } +} + +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 globebrowsing diff --git a/modules/globebrowsing/rendering/layer/layer.h b/modules/globebrowsing/rendering/layer/layer.h index 437eae8ef2..c8380e5b4f 100644 --- a/modules/globebrowsing/rendering/layer/layer.h +++ b/modules/globebrowsing/rendering/layer/layer.h @@ -25,14 +25,17 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___LAYER___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___LAYER___H__ -#include - #include + +#include #include #include +#include +#include #include #include +#include namespace openspace { namespace globebrowsing { @@ -41,29 +44,55 @@ namespace tileprovider { class TileProvider; } -/** - * Simple struct which is used to enable/disable TileProvider - * and associate is with a name. It also holds layer specific information - * which is used in rendering of layer. - */ class Layer : public properties::PropertyOwner { public: - Layer(layergroupid::ID id, const ghoul::Dictionary& layerDict); + /** + * 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); ChunkTilePile getChunkTilePile(const TileIndex& tileIndex, int pileSize) const; + Tile::Status getTileStatus(const TileIndex& index) const; - bool enabled() const { return _enabled.value(); } - tileprovider::TileProvider* tileProvider() const { return _tileProvider.get(); } - const LayerRenderSettings& renderSettings() const { return _renderSettings; } - + layergroupid::TypeID type() const; + layergroupid::BlendModeID blendMode() const; + TileDepthTransform depthTransform() const; + bool enabled() const; + tileprovider::TileProvider* tileProvider() const; + const OtherTypesProperties& otherTypesProperties() const; + const LayerRenderSettings& renderSettings() const; + const LayerAdjustment& layerAdjustment() const; + void onChange(std::function callback); + + void update(); private: + layergroupid::TypeID parseTypeIdFromDictionary(const ghoul::Dictionary& initDict) const; + void initializeBasedOnType(layergroupid::TypeID typeId, ghoul::Dictionary initDict); + void addVisibleProperties(); + void removeVisibleProperties(); + + properties::OptionProperty _typeOption; + properties::OptionProperty _blendModeOption; properties::BoolProperty _enabled; properties::TriggerProperty _reset; + + layergroupid::TypeID _type; std::shared_ptr _tileProvider; + OtherTypesProperties _otherTypesProperties; LayerRenderSettings _renderSettings; -}; + LayerAdjustment _layerAdjustment; + + const layergroupid::GroupID _layerGroupId; + + std::function _onChangeCallback; + }; } // namespace globebrowsing } // namespace openspace diff --git a/modules/globebrowsing/rendering/layer/layeradjustment.cpp b/modules/globebrowsing/rendering/layer/layeradjustment.cpp new file mode 100644 index 0000000000..fad6678097 --- /dev/null +++ b/modules/globebrowsing/rendering/layer/layeradjustment.cpp @@ -0,0 +1,134 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { +namespace globebrowsing { + +namespace { + const char* keyType = "Type"; + const char* keyChromaKeyColor = "ChromaKeyColor"; + const char* keyChromaKeyTolerance = "ChromaKeyTolerance"; +} + +LayerAdjustment::LayerAdjustment() + : properties::PropertyOwner("adjustment") + , chromaKeyColor( + "chromaKeyColor", + "Chroma key color", + glm::vec3(0.f, 0.f, 0.f), + glm::vec3(0.f), + glm::vec3(1.f) + ) + , chromaKeyTolerance( + "chromaKeyTolerance", + "Chroma key tolerance", + 0, + 0, + 1 + ) + , _typeOption( + "type", + "Type", + properties::OptionProperty::DisplayType::Dropdown + ) + , _onChangeCallback([](){}) +{ + // Add options to option properties + for (int i = 0; i < layergroupid::NUM_ADJUSTMENT_TYPES; ++i) { + _typeOption.addOption(i, layergroupid::ADJUSTMENT_TYPE_NAMES[i]); + } + _typeOption.setValue(static_cast(layergroupid::AdjustmentTypeID::None)); + _type = static_cast(_typeOption.value()); + + _typeOption.onChange([&](){ + removeVisibleProperties(); + _type = static_cast(_typeOption.value()); + addVisibleProperties(); + _onChangeCallback(); + }); + chromaKeyColor.setViewOption(properties::Property::ViewOptions::Color); + + addProperty(_typeOption); + addVisibleProperties(); +} + +void LayerAdjustment::setValuesFromDictionary( + const ghoul::Dictionary& adjustmentDict) +{ + std::string dictType; + glm::vec3 dictChromaKeyColor; + float dictChromaKeyTolerance; + + if (adjustmentDict.getValue(keyType, dictType)) { + _typeOption.setValue( + static_cast(layergroupid::getAdjustmentTypeIDFromName(dictType))); + } + if (adjustmentDict.getValue(keyChromaKeyColor, dictChromaKeyColor)) { + chromaKeyColor.setValue(dictChromaKeyColor); + } + if (adjustmentDict.getValue(keyChromaKeyTolerance, dictChromaKeyTolerance)) { + chromaKeyTolerance.setValue(dictChromaKeyTolerance); + } +} + +layergroupid::AdjustmentTypeID LayerAdjustment::type() const { + return _type; +} + +void LayerAdjustment::addVisibleProperties() { + switch (type()) { + case layergroupid::AdjustmentTypeID::None: + break; + case layergroupid::AdjustmentTypeID::ChromaKey: { + addProperty(chromaKeyColor); + addProperty(chromaKeyTolerance); + break; + } + case layergroupid::AdjustmentTypeID::TransferFunction: + break; + } +} + +void LayerAdjustment::removeVisibleProperties() { + switch (type()) { + case layergroupid::AdjustmentTypeID::None: + break; + case layergroupid::AdjustmentTypeID::ChromaKey: { + removeProperty(chromaKeyColor); + removeProperty(chromaKeyTolerance); + break; + } + case layergroupid::AdjustmentTypeID::TransferFunction: + break; + } +} + +void LayerAdjustment::onChange(std::function callback) { + _onChangeCallback = std::move(callback); +} + +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/tileprovider/presentationslideprovider.h b/modules/globebrowsing/rendering/layer/layeradjustment.h similarity index 64% rename from modules/globebrowsing/tile/tileprovider/presentationslideprovider.h rename to modules/globebrowsing/rendering/layer/layeradjustment.h index 4b331777a1..20b9f11a78 100644 --- a/modules/globebrowsing/tile/tileprovider/presentationslideprovider.h +++ b/modules/globebrowsing/rendering/layer/layeradjustment.h @@ -22,48 +22,51 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PRESENTATION_SLIDE_PROVIDER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___PRESENTATION_SLIDE_PROVIDER___H__ +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___LAYER_ADJUSTMENT___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___LAYER_ADJUSTMENT___H__ -#include -#include +#include -#include -#include +#include #include - -#include -#include +#include +#include namespace openspace { namespace globebrowsing { + namespace tileprovider { + class TileProvider; +} -class PresentationSlideProvider : public TileProvider { +class LayerAdjustment : public properties::PropertyOwner +{ public: - PresentationSlideProvider(const ghoul::Dictionary& dictionary); - PresentationSlideProvider(const std::string& imagePath); - virtual ~PresentationSlideProvider() = default; + LayerAdjustment(); + ~LayerAdjustment() = default; - virtual Tile getTile(const TileIndex& tileIndex) override; - virtual Tile::Status getTileStatus(const TileIndex& index) override; - virtual TileDepthTransform depthTransform() override; - virtual void update() override; - virtual void reset() override; - virtual int maxLevel() override; + void setValuesFromDictionary(const ghoul::Dictionary& adjustmentDict); + + layergroupid::AdjustmentTypeID type() const; + + // Properties + properties::Vec3Property chromaKeyColor; + properties::FloatProperty chromaKeyTolerance; + + void onChange(std::function callback); private: - TileProvider* slideProvider(); + void addVisibleProperties(); + void removeVisibleProperties(); + + properties::OptionProperty _typeOption; + layergroupid::AdjustmentTypeID _type; - TileIndex _tileIndex; - properties::IntProperty _slideIndex; - std::vector> _slideProviders; - std::unique_ptr _defaultProvider; + std::function _onChangeCallback; }; -} // namespace tileprovider } // namespace globebrowsing } // namespace openspace -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PRESENTATION_SLIDE_PROVIDER___H__ +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___LAYER_ADJUSTMENT___H__ diff --git a/modules/globebrowsing/rendering/layer/layergroup.cpp b/modules/globebrowsing/rendering/layer/layergroup.cpp index 94f5d8cf5d..7b038c8f58 100644 --- a/modules/globebrowsing/rendering/layer/layergroup.cpp +++ b/modules/globebrowsing/rendering/layer/layergroup.cpp @@ -26,35 +26,36 @@ #include +namespace { + const char* _loggerCat = "LayerGroup"; +} + namespace openspace { namespace globebrowsing { -LayerGroup::LayerGroup(std::string name) - : properties::PropertyOwner(std::move(name)) +LayerGroup::LayerGroup(layergroupid::GroupID id) + : properties::PropertyOwner(std::move(layergroupid::LAYER_GROUP_NAMES[id])) + , _groupId(id) , _levelBlendingEnabled("blendTileLevels", "blend tile levels", false) { addProperty(_levelBlendingEnabled); } -LayerGroup::LayerGroup(layergroupid::ID id, const ghoul::Dictionary& dict) - : LayerGroup(layergroupid::LAYER_GROUP_NAMES[id]) +LayerGroup::LayerGroup(layergroupid::GroupID id, const ghoul::Dictionary& dict) + : LayerGroup(id) { for (size_t i = 0; i < dict.size(); i++) { std::string dictKey = std::to_string(i + 1); ghoul::Dictionary layerDict = dict.value(dictKey); try { - _layers.push_back(std::make_shared(id, layerDict)); + addLayer(layerDict); } catch (const ghoul::RuntimeError& e) { LERRORC(e.component, e.message); continue; } } - - for (const auto& layer : _layers) { - addPropertySubOwner(layer.get()); - } } void LayerGroup::update() { @@ -62,12 +63,48 @@ void LayerGroup::update() { for (const auto& layer : _layers) { if (layer->enabled()) { - layer->tileProvider()->update(); + layer->update(); _activeLayers.push_back(layer); } } } +void LayerGroup::addLayer(const ghoul::Dictionary& layerDict) { + if (!layerDict.hasKeyAndValue("Name")) { + LERROR("'Name' must be specified for layer."); + return; + } + auto layer = std::make_shared(_groupId, layerDict); + layer->onChange(_onChangeCallback); + if (hasPropertySubOwner(layer->name())) { + LINFO("Layer with name " + layer->name() + " already exists."); + } + else { + _layers.push_back(layer); + update(); + if(_onChangeCallback) { + _onChangeCallback(); + } + addPropertySubOwner(layer.get()); + } +} + +void LayerGroup::deleteLayer(const std::string& layerName) { + for (std::vector>::iterator it = _layers.begin(); it != _layers.end(); ++it) { + if (it->get()->name() == layerName) { + removePropertySubOwner(it->get()); + _layers.erase(it); + update(); + if(_onChangeCallback) { + _onChangeCallback(); + } + LINFO("Deleted layer " + layerName); + return; + } + } + LERROR("Could not find layer " + layerName); +} + const std::vector>& LayerGroup::layers() const { return _layers; } @@ -81,10 +118,10 @@ int LayerGroup::pileSize() const{ } void LayerGroup::onChange(std::function callback) { - _onChangeCallback = callback; - _levelBlendingEnabled.onChange(callback); + _onChangeCallback = std::move(callback); + _levelBlendingEnabled.onChange(_onChangeCallback); for (const std::shared_ptr& layer : _layers) { - layer->onChange(callback); + layer->onChange(_onChangeCallback); } } diff --git a/modules/globebrowsing/rendering/layer/layergroup.h b/modules/globebrowsing/rendering/layer/layergroup.h index d19e9b76d6..8cf6d22d9b 100644 --- a/modules/globebrowsing/rendering/layer/layergroup.h +++ b/modules/globebrowsing/rendering/layer/layergroup.h @@ -47,12 +47,15 @@ namespace tileprovider { * Convenience class for dealing with multiple Layers. */ struct LayerGroup : public properties::PropertyOwner { - LayerGroup(std::string name); - LayerGroup(layergroupid::ID id, const ghoul::Dictionary& dict); + LayerGroup(layergroupid::GroupID id); + LayerGroup(layergroupid::GroupID id, const ghoul::Dictionary& dict); /// Updates all layers tile providers within this group void update(); + void addLayer(const ghoul::Dictionary& layerDict); + void deleteLayer(const std::string& layerName); + /// @returns const vector of all layers const std::vector>& layers() const; @@ -67,6 +70,7 @@ struct LayerGroup : public properties::PropertyOwner { void onChange(std::function callback); private: + const layergroupid::GroupID _groupId; std::vector> _layers; std::vector> _activeLayers; diff --git a/modules/globebrowsing/rendering/layer/layergroupid.h b/modules/globebrowsing/rendering/layer/layergroupid.h index 07b58ca247..8445c4b962 100644 --- a/modules/globebrowsing/rendering/layer/layergroupid.h +++ b/modules/globebrowsing/rendering/layer/layergroupid.h @@ -25,32 +25,133 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___LAYERGROUPID___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___LAYERGROUPID___H__ +#include namespace openspace { namespace globebrowsing { namespace layergroupid { -static const int NUM_LAYER_GROUPS = 7; -static const char* LAYER_GROUP_NAMES[NUM_LAYER_GROUPS] = { +static const int NUM_LAYER_GROUPS = 5; +static const std::string LAYER_GROUP_NAMES[NUM_LAYER_GROUPS] = { "HeightLayers", "ColorLayers", - "ColorOverlays", - "GrayScaleLayers", - "GrayScaleColorOverlays", + "Overlays", "NightLayers", "WaterMasks" }; -enum ID { +enum GroupID { HeightLayers, ColorLayers, - ColorOverlays, - GrayScaleLayers, - GrayScaleColorOverlays, + Overlays, NightLayers, - WaterMasks + WaterMasks, + Unknown, }; +static const int NUM_LAYER_TYPES = 8; +static const std::string LAYER_TYPE_NAMES[NUM_LAYER_TYPES] = { + "DefaultTileLayer", + "SingleImageTileLayer", + "SizeReferenceTileLayer", + "TemporalTileLayer", + "TileIndexTileLayer", + "ByIndexTileLayer", + "ByLevelTileLayer", + "SolidColor", +}; + +/** + This enumeration is specified explicitly since it is used in the shader as well. + */ +enum class TypeID { + Unknown = -1, + DefaultTileLayer = 0, + SingleImageTileLayer = 1, + SizeReferenceTileLayer = 2, + TemporalTileLayer = 3, + TileIndexTileLayer = 4, + ByIndexTileLayer = 5, + ByLevelTileLayer = 6, + SolidColor = 7, +}; + +static const int NUM_ADJUSTMENT_TYPES = 3; +static const std::string ADJUSTMENT_TYPE_NAMES[NUM_ADJUSTMENT_TYPES] = { + "None", + "ChromaKey", + "TransferFunction", +}; + +/** + This enumeration is specified explicitly since it is used in the shader as well. + */ +enum class AdjustmentTypeID { + None = 0, + ChromaKey = 1, + TransferFunction = 2, +}; + +static const int NUM_BLEND_MODES = 5; +static const std::string BLEND_MODE_NAMES[NUM_BLEND_MODES] = { + "Normal", + "Multiply", + "Add", + "Subtract", + "Color", +}; + +/** + This enumeration is specified explicitly since it is used in the shader as well. + */ +enum class BlendModeID { + Normal = 0, + Multiply = 1, + Add = 2, + Subtract = 3, + Color = 4, +}; + +static TypeID getTypeIDFromTypeString(std::string typeString) { + for (int i = 0; i < NUM_LAYER_TYPES; ++i) { + if (typeString == LAYER_TYPE_NAMES[i]) { + return static_cast(i); + } + } + return TypeID::Unknown; +} + +static layergroupid::GroupID getGroupIDFromName(std::string layerGroupName) { + for (int i = 0; i < layergroupid::NUM_LAYER_GROUPS; ++i) { + if (layerGroupName == layergroupid::LAYER_GROUP_NAMES[i]) { + return static_cast(i); + } + } + return GroupID::Unknown; +} + +static layergroupid::AdjustmentTypeID getAdjustmentTypeIDFromName( + std::string adjustmentTypeName) +{ + for (int i = 0; i < layergroupid::NUM_ADJUSTMENT_TYPES; ++i) { + if (adjustmentTypeName == layergroupid::ADJUSTMENT_TYPE_NAMES[i]) { + return static_cast(i); + } + } + return AdjustmentTypeID::None; +} + +static layergroupid::BlendModeID getBlendModeIDFromName( + std::string blendModeName) +{ + for (int i = 0; i < layergroupid::NUM_BLEND_MODES; ++i) { + if (blendModeName == layergroupid::BLEND_MODE_NAMES[i]) { + return static_cast(i); + } + } + return BlendModeID::Normal; +} + } // namespace layergroupid } // namespace globebrowsing } // namespace openspace diff --git a/modules/globebrowsing/rendering/layer/layermanager.cpp b/modules/globebrowsing/rendering/layer/layermanager.cpp index df8165bc25..b2a2a98e24 100644 --- a/modules/globebrowsing/rendering/layer/layermanager.cpp +++ b/modules/globebrowsing/rendering/layer/layermanager.cpp @@ -31,23 +31,38 @@ namespace openspace { namespace globebrowsing { +namespace { + const char* _loggerCat = "LayerManager"; +} + LayerManager::LayerManager(const ghoul::Dictionary& layerGroupsDict) : properties::PropertyOwner("Layers") { - if (layergroupid::NUM_LAYER_GROUPS != layerGroupsDict.size()) { - throw ghoul::RuntimeError( - "Number of Layer Groups must be equal to " + layergroupid::NUM_LAYER_GROUPS); + // First create empty layer groups in case not all are specified + _layerGroups.resize(layergroupid::NUM_LAYER_GROUPS); + for (int i = 0; i < _layerGroups.size(); ++i) { + ghoul::Dictionary emptyDict; + _layerGroups[i] = std::make_shared( + static_cast(i), emptyDict + ); } - // Create all the categories of tile providers - for (size_t i = 0; i < layerGroupsDict.size(); i++) { - const std::string& groupName = layergroupid::LAYER_GROUP_NAMES[i]; - ghoul::Dictionary layerGroupDict = - layerGroupsDict.value(groupName); + std::vector layerGroupNamesInDict = layerGroupsDict.keys(); - _layerGroups.push_back( - std::make_shared( - static_cast(i), layerGroupDict)); + // 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) { @@ -55,11 +70,21 @@ LayerManager::LayerManager(const ghoul::Dictionary& layerGroupsDict) } } +void LayerManager::addLayer(layergroupid::GroupID groupId, ghoul::Dictionary layerDict) { + ghoul_assert(groupId != layergroupid::Unknown, "Layer group ID must be known"); + _layerGroups[groupId]->addLayer(layerDict); +} + +void LayerManager::deleteLayer(layergroupid::GroupID groupId, 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::ID groupId) { +const LayerGroup& LayerManager::layerGroup(layergroupid::GroupID groupId) { return *_layerGroups[groupId]; } @@ -92,56 +117,49 @@ void LayerManager::reset(bool includeDisabled) { } } -TileTextureInitData LayerManager::getTileTextureInitData(layergroupid::ID id, +TileTextureInitData LayerManager::getTileTextureInitData(layergroupid::GroupID id, size_t preferredTileSize) { switch (id) { - case layergroupid::ID::HeightLayers: { + case layergroupid::GroupID::HeightLayers: { size_t tileSize = preferredTileSize ? preferredTileSize : 64; return TileTextureInitData(tileSize, tileSize, GL_FLOAT, ghoul::opengl::Texture::Format::Red, TileTextureInitData::ShouldAllocateDataOnCPU::Yes); } - case layergroupid::ID::ColorLayers: { + case layergroupid::GroupID::ColorLayers: { size_t tileSize = preferredTileSize ? preferredTileSize : 512; return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RGBA); + ghoul::opengl::Texture::Format::BGRA); } - case layergroupid::ID::ColorOverlays: { + case layergroupid::GroupID::Overlays: { size_t tileSize = preferredTileSize ? preferredTileSize : 512; return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RGBA); + ghoul::opengl::Texture::Format::BGRA); } - case layergroupid::ID::GrayScaleLayers: { + case layergroupid::GroupID::NightLayers: { size_t tileSize = preferredTileSize ? preferredTileSize : 512; return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RG); + ghoul::opengl::Texture::Format::BGRA); } - case layergroupid::ID::GrayScaleColorOverlays: { + case layergroupid::GroupID::WaterMasks: { size_t tileSize = preferredTileSize ? preferredTileSize : 512; return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RG); - } - case layergroupid::ID::NightLayers: { - size_t tileSize = preferredTileSize ? preferredTileSize : 512; - return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RGBA); - } - case layergroupid::ID::WaterMasks: { - size_t tileSize = preferredTileSize ? preferredTileSize : 512; - return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RGBA); + ghoul::opengl::Texture::Format::BGRA); } default: { ghoul_assert(false, "Unknown layer group ID"); + size_t tileSize = preferredTileSize ? preferredTileSize : 512; + return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, + ghoul::opengl::Texture::Format::BGRA); } } } -bool LayerManager::shouldPerformPreProcessingOnLayergroup(layergroupid::ID id) { +bool LayerManager::shouldPerformPreProcessingOnLayergroup(layergroupid::GroupID id) { // Only preprocess height layers by default switch (id) { - case layergroupid::ID::HeightLayers: return true; + case layergroupid::GroupID::HeightLayers: return true; default: return false; } } diff --git a/modules/globebrowsing/rendering/layer/layermanager.h b/modules/globebrowsing/rendering/layer/layermanager.h index 22ef5a79a3..454a02d9f8 100644 --- a/modules/globebrowsing/rendering/layer/layermanager.h +++ b/modules/globebrowsing/rendering/layer/layermanager.h @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -45,8 +46,11 @@ class LayerManager : public properties::PropertyOwner { public: LayerManager(const ghoul::Dictionary& textureCategoriesDictionary); + void addLayer(layergroupid::GroupID groupId, ghoul::Dictionary layerDict); + void deleteLayer(layergroupid::GroupID groupId, std::string layerName); + const LayerGroup& layerGroup(size_t groupId); - const LayerGroup& layerGroup(layergroupid::ID); + const LayerGroup& layerGroup(layergroupid::GroupID); bool hasAnyBlendingLayersEnabled() const; @@ -55,10 +59,10 @@ public: void update(); void reset(bool includingDisabled = false); - static TileTextureInitData getTileTextureInitData(layergroupid::ID id, + static TileTextureInitData getTileTextureInitData(layergroupid::GroupID id, size_t preferredTileSize = 0); - static bool shouldPerformPreProcessingOnLayergroup(layergroupid::ID id); + static bool shouldPerformPreProcessingOnLayergroup(layergroupid::GroupID id); void onChange(std::function callback); private: diff --git a/modules/globebrowsing/rendering/layer/layerrendersettings.cpp b/modules/globebrowsing/rendering/layer/layerrendersettings.cpp index 6fe1474c58..8cbbd95a79 100644 --- a/modules/globebrowsing/rendering/layer/layerrendersettings.cpp +++ b/modules/globebrowsing/rendering/layer/layerrendersettings.cpp @@ -37,11 +37,12 @@ namespace { LayerRenderSettings::LayerRenderSettings() : properties::PropertyOwner("Settings") - , opacity(properties::FloatProperty("Opacity", "opacity", 1.f, 0.f, 1.f)) - , gamma(properties::FloatProperty("Gamma", "gamma", 1, 0, 5)) - , multiplier(properties::FloatProperty("Multiplier", "multiplier", 1.f, 0.f, 20.f)) - , offset(properties::FloatProperty("Offset", "offset", 0.f, -10000.f, 10000.f)) - , valueBlending(properties::FloatProperty("Value blending", "valueBlending", + , setDefault("setDefault", "Set Default") + , opacity(properties::FloatProperty("opacity", "Opacity", 1.f, 0.f, 1.f)) + , gamma(properties::FloatProperty("gamma", "Gamma", 1, 0, 5)) + , multiplier(properties::FloatProperty("multiplier", "Multiplier", 1.f, 0.f, 20.f)) + , offset(properties::FloatProperty("offset", "Offset", 0.f, -10000.f, 10000.f)) + , valueBlending(properties::FloatProperty("valueBlending", "Value Blending", 1.f, 0.f, 1.f)) , useValueBlending(false) { @@ -50,6 +51,9 @@ LayerRenderSettings::LayerRenderSettings() addProperty(gamma); addProperty(multiplier); addProperty(offset); + addProperty(setDefault); + + setDefault.onChange([this](){ setDefaultValues(); }); } void LayerRenderSettings::setValuesFromDictionary( @@ -62,19 +66,19 @@ void LayerRenderSettings::setValuesFromDictionary( float dictValueBlending; if(renderSettingsDict.getValue(keyOpacity, dictOpacity)) { - opacity.setValue(dictOpacity); + opacity = dictOpacity; } if(renderSettingsDict.getValue(keyGamma, dictGamma)) { - gamma.setValue(dictGamma); + gamma = dictGamma; } if(renderSettingsDict.getValue(keyMultiplier, dictMultiplier)) { - multiplier.setValue(dictMultiplier); + multiplier = dictMultiplier; } if(renderSettingsDict.getValue(keyOffset, dictOffset)) { - multiplier.setValue(dictOffset); + multiplier = dictOffset; } if(renderSettingsDict.getValue(keyValueBlending, dictValueBlending)) { - valueBlending.setValue(dictValueBlending); + valueBlending = dictValueBlending; useValueBlending = true; } } @@ -100,5 +104,13 @@ glm::vec4 LayerRenderSettings::performLayerSettings(glm::vec4 currentValue) cons return newValue; } +void LayerRenderSettings::setDefaultValues() { + opacity = 1.f; + gamma = 1.f; + multiplier = 1.f; + offset = 0.f; + valueBlending = 1.f; +} + } // namespace globebrowsing } // namespace openspace diff --git a/modules/globebrowsing/rendering/layer/layerrendersettings.h b/modules/globebrowsing/rendering/layer/layerrendersettings.h index 2fb4ea2432..95538ee28d 100644 --- a/modules/globebrowsing/rendering/layer/layerrendersettings.h +++ b/modules/globebrowsing/rendering/layer/layerrendersettings.h @@ -28,6 +28,7 @@ #include #include +#include namespace openspace { namespace globebrowsing { @@ -35,6 +36,8 @@ namespace globebrowsing { struct LayerRenderSettings : public properties::PropertyOwner { LayerRenderSettings(); + properties::TriggerProperty setDefault; + properties::FloatProperty opacity; properties::FloatProperty gamma; properties::FloatProperty multiplier; @@ -52,6 +55,9 @@ struct LayerRenderSettings : public properties::PropertyOwner { /// This function matches the function with the same name in the /// shader code glm::vec4 performLayerSettings(glm::vec4 currentValue) const; + +private: + void setDefaultValues(); }; } // namespace globebrowsing diff --git a/modules/globebrowsing/rendering/layershadermanager.cpp b/modules/globebrowsing/rendering/layershadermanager.cpp index 0dc6aceb99..bf51dddfc2 100644 --- a/modules/globebrowsing/rendering/layershadermanager.cpp +++ b/modules/globebrowsing/rendering/layershadermanager.cpp @@ -40,7 +40,10 @@ namespace globebrowsing { bool LayerShaderManager::LayerShaderPreprocessingData::LayerGroupPreprocessingData::operator==( const LayerGroupPreprocessingData& other) const { - return lastLayerIdx == other.lastLayerIdx && + return layerType == other.layerType && + blendMode == other.blendMode && + layerAdjustmentType == other.layerAdjustmentType && + lastLayerIdx == other.lastLayerIdx && layerBlendingEnabled == other.layerBlendingEnabled; } @@ -72,24 +75,38 @@ LayerShaderManager::LayerShaderPreprocessingData for (size_t i = 0; i < layergroupid::NUM_LAYER_GROUPS; i++) { LayerShaderManager::LayerShaderPreprocessingData::LayerGroupPreprocessingData layeredTextureInfo; - auto layerGroup = layerManager->layerGroup(i); + + const LayerGroup& layerGroup = layerManager->layerGroup(i); + std::vector> layers = layerGroup.activeLayers(); + layeredTextureInfo.lastLayerIdx = 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 auto& generalProps = globe.generalProperties(); - const auto& debugProps = globe.debugProperties(); + const RenderableGlobe::GeneralProperties& generalProps = globe.generalProperties(); + const RenderableGlobe::DebugProperties& debugProps = globe.debugProperties(); auto& 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("showChunkEdges", std::to_string(debugProps.showChunkEdges)); pairs.emplace_back("showHeightResolution", - std::to_string(debugProps.showHeightResolution)); + std::to_string(debugProps.showHeightResolution) + ); pairs.emplace_back("showHeightIntensities", - std::to_string(debugProps.showHeightIntensities)); + std::to_string(debugProps.showHeightIntensities) + ); pairs.emplace_back("defaultHeight", std::to_string(Chunk::DEFAULT_HEIGHT)); pairs.emplace_back("tilePaddingStart", @@ -153,8 +170,41 @@ void LayerShaderManager::recompileShaderProgram( "blend" + groupName, textureTypes[i].layerBlendingEnabled ); + + // This is to avoid errors from shader preprocessor + std::string keyLayerType = groupName + "0" + "LayerType"; + shaderDictionary.setValue(keyLayerType, 0); + + for (int j = 0; j < textureTypes[i].lastLayerIdx + 1; ++j) { + std::string key = groupName + std::to_string(j) + "LayerType"; + shaderDictionary.setValue(key, static_cast(textureTypes[i].layerType[j])); + } + + // This is to avoid errors from shader preprocessor + std::string keyBlendMode = groupName + "0" + "BlendMode"; + shaderDictionary.setValue(keyBlendMode, 0); + + for (int j = 0; j < textureTypes[i].lastLayerIdx + 1; ++j) { + std::string key = groupName + std::to_string(j) + "BlendMode"; + shaderDictionary.setValue(key, 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) { + std::string key = groupName + std::to_string(j) + "LayerAdjustmentType"; + shaderDictionary.setValue(key, 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_NAMES[i]); + } + shaderDictionary.setValue("layerGroups", layerGroupNames); + // Other settings such as "useAtmosphere" auto keyValuePairs = _preprocessingData.keyValuePairs; for (size_t i = 0; i < keyValuePairs.size(); i++) { diff --git a/modules/globebrowsing/rendering/layershadermanager.h b/modules/globebrowsing/rendering/layershadermanager.h index d6712c382b..026e98ecd0 100644 --- a/modules/globebrowsing/rendering/layershadermanager.h +++ b/modules/globebrowsing/rendering/layershadermanager.h @@ -26,6 +26,7 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___LAYER_SHADER_MANAGER___H__ #include +#include #include #include @@ -63,6 +64,9 @@ public: struct LayerGroupPreprocessingData { int lastLayerIdx; bool layerBlendingEnabled; + std::vector layerType; + std::vector blendMode; + std::vector layerAdjustmentType; bool operator==(const LayerGroupPreprocessingData& other) const; }; diff --git a/modules/globebrowsing/scripts/layer_support.lua b/modules/globebrowsing/scripts/layer_support.lua index 576fb52ed0..a1af426327 100644 --- a/modules/globebrowsing/scripts/layer_support.lua +++ b/modules/globebrowsing/scripts/layer_support.lua @@ -8,6 +8,55 @@ openspace.globebrowsing.documentation = { Name = "createHeightLayers", Arguments = "table", Documentation = "Creates a table used in the 'HeightLayers' of a RenderableGlobe." + }, + { + Name = "createTemporalGibsGdalXml", + Arguments = "string, string, string, string, string, string", + Documentation = + "Creates an XML configuration for a temporal GIBS dataset." .. + "Arguments are: Name, Start date, end date, time resolution, time format," .. + "resolution, file format. For all specifications, see " .. + "https://wiki.earthdata.nasa.gov/display/GIBS/GIBS+Available+Imagery+Products" .. + "Usage:" .. + "openspace.globebrowsing.addLayer(" .. + "\"Earth\"," .. + "\"ColorLayers\"," .. + "{" .. + "Type = \"TemporalTileLayer\"," .. + "Name = \"MODIS_Terra_Chlorophyll_A\"," .. + "FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(" .. + "\"MODIS_Terra_Chlorophyll_A\"," .. + "\"2013-07-02\"," .. + "\"Yesterday\"," .. + "\"1d\"," .. + "\"1km\"," .. + "\"png\"" .. + ")" .. + "}" .. + ")" + }, + { + Name = "createGibsGdalXml", + Arguments = "string, string, string, string", + Documentation = + "Creates an XML configuration for a GIBS dataset." .. + "Arguments are: layerName, date, resolution, format." .. + "For all specifications, see " .. + "https://wiki.earthdata.nasa.gov/display/GIBS/GIBS+Available+Imagery+Products" .. + "Usage:" .. + "openspace.globebrowsing.addLayer(" .. + "\"Earth\"," .. + "\"ColorLayers\"," .. + "{" .. + "Name = \"MODIS_Terra_Chlorophyll_A\"," .. + "FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(" .. + "\"MODIS_Terra_Chlorophyll_A\"," .. + "\"2013-07-02\"," .. + "\"1km\"," .. + "\"png\"" .. + ")" .. + "}" .. + ")" } } @@ -31,7 +80,86 @@ end openspace.globebrowsing.createHeightLayers = function (patches) result = {} for k,v in pairs(patches) do - table.insert(result, { Name = v["Name"], FilePath = v["Height"], TilePixelSize = 90, DoPreProcessing = true }) + table.insert(result, { Name = v["Name"], FilePath = v["Height"], TilePixelSize = 90, PerformPreProcessing = true }) end return result end + +openspace.globebrowsing.createTemporalGibsGdalXml = function (layerName, startDate, endDate, timeResolution, resolution, format) + temporalTemplate = + "" .. + "" .. startDate .. "" .. + "" .. endDate .. "" .. + "" .. timeResolution .. "" .. + "YYYY-MM-DD" .. + openspace.globebrowsing.createGibsGdalXml(layerName, "${OpenSpaceTimeId}", resolution, format) .. + "" + return temporalTemplate +end + +openspace.globebrowsing.createGibsGdalXml = function (layerName, date, resolution, format) + tileLevel = 5 + -- These resolutions are defined by GIBS: https://wiki.earthdata.nasa.gov/display/GIBS/GIBS+API+for+Developers#GIBSAPIforDevelopers-Script-levelAccessviaGDAL + if resolution == "2km" then + tileLevel = 5 + elseif resolution == "1km" then + tileLevel = 6 + elseif resolution == "500m" then + tileLevel = 7 + elseif resolution == "250m" then + tileLevel = 8 + elseif resolution == "125m" then + tileLevel = 9 + elseif resolution == "62.5m" then + tileLevel = 10 + elseif resolution == "31.25m" then + tileLevel = 11 + elseif resolution == "15.625m" then + tileLevel = 12 + else + openspace.printError("Unknown resolution: " .. resolution) + return "" + end + + rasterCount = 3 + if format == "jpg" then + if layerName == "ASTER_GDEM_Greyscale_Shaded_Relief" then + rasterCount = 1 + else + rasterCount = 3 + end + elseif format == "png" then + rasterCount = 4 + else + openspace.printError("Unknown format \"" .. format .. "\". Use 'jpg' or 'png'") + return "" + end + + gdalWmsTemplate = + "" .. + "" .. + "https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/" .. + layerName .. "/default/" .. date .. "/" .. resolution .. + "/${z}/${y}/${x}." .. format .. "" .. + "" .. + "" .. + "-180.0" .. + "90" .. + "396.0" .. + "-198" .. + "" .. tileLevel .. "" .. + "2" .. + "1" .. + "top" .. + "" .. + "EPSG:4326" .. + "512" .. + "512" .. + "" .. rasterCount .. "" .. + "true" .. + "400,204,404" .. + "true" .. + "" + + return gdalWmsTemplate +end \ No newline at end of file diff --git a/modules/globebrowsing/shaders/blending.hglsl b/modules/globebrowsing/shaders/blending.hglsl index e6b6b64bfd..6bcba5a4b3 100644 --- a/modules/globebrowsing/shaders/blending.hglsl +++ b/modules/globebrowsing/shaders/blending.hglsl @@ -25,29 +25,25 @@ #ifndef BLENDING_HGLSL #define BLENDING_HGLSL -vec4 blendOver(vec4 oldColor, vec4 newColor) -{ - vec4 toReturn; - 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); - return toReturn; +vec4 blendNormal(vec4 oldColor, vec4 newColor) { + vec4 toReturn; + 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); + return toReturn; } -vec4 blendMultiply(vec4 oldColor, vec4 newColor) -{ - return oldColor * newColor; +vec4 blendMultiply(vec4 oldColor, vec4 newColor) { + return oldColor * newColor; } -vec4 blendAdd(vec4 oldColor, vec4 newColor) -{ - return oldColor + newColor; +vec4 blendAdd(vec4 oldColor, vec4 newColor) { + return oldColor + newColor; } -vec4 blendSubtract(vec4 oldColor, vec4 newColor) -{ - return oldColor - newColor; +vec4 blendSubtract(vec4 oldColor, vec4 newColor) { + return oldColor - newColor; } /* @@ -56,7 +52,7 @@ 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 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); @@ -72,15 +68,13 @@ vec3 hsv2rgb(vec3 c) } */ -vec3 hsl2rgb( in vec3 c ) -{ +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 ); return c.z + c.y * (rgb-0.5)*(1.0-abs(2.0*c.z-1.0)); } -vec3 HueShift (in vec3 Color, in float Shift) -{ +vec3 HueShift (in vec3 Color, in float Shift) { vec3 P = vec3(0.55735)*dot(vec3(0.55735),Color); vec3 U = Color-P; @@ -92,45 +86,44 @@ vec3 HueShift (in vec3 Color, in float Shift) return vec3(Color); } -vec3 rgb2hsl( in vec3 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 ) ); + 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 cDelta = cMax - cMin; + l = ( cMax + cMin ) / 2.0; + if ( cMax > cMin ) { + float cDelta = cMax - cMin; //s = l < .05 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) ); Original - s = l < .0 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) ); + s = l < .0 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) ); - if ( r == cMax ) { - h = ( g - b ) / cDelta; - } else if ( g == cMax ) { - h = 2.0 + ( b - r ) / cDelta; - } else { - h = 4.0 + ( r - g ) / cDelta; - } + if ( r == cMax ) { + h = ( g - b ) / cDelta; + } else if ( g == cMax ) { + h = 2.0 + ( b - r ) / cDelta; + } else { + h = 4.0 + ( r - g ) / cDelta; + } - if ( h < 0.0) { - h += 6.0; - } - h = h / 6.0; - } - return vec3( h, s, l ); + if ( h < 0.0) { + h += 6.0; + } + h = h / 6.0; + } + return vec3( h, s, l ); } -vec3 rgb2hsv(vec3 c) -{ +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 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); @@ -138,8 +131,7 @@ vec3 rgb2hsv(vec3 c) return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); } -vec3 hsv2rgb(vec3 c) -{ +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); diff --git a/modules/globebrowsing/shaders/ellipsoid.hglsl b/modules/globebrowsing/shaders/ellipsoid.hglsl index 19c702e2e2..7589bee984 100644 --- a/modules/globebrowsing/shaders/ellipsoid.hglsl +++ b/modules/globebrowsing/shaders/ellipsoid.hglsl @@ -26,62 +26,62 @@ #define ELLIPSOID_HGLSL struct PositionNormalPair { - vec3 position; - vec3 normal; + vec3 position; + vec3 normal; }; struct Intersection { bool intersects; float nearParameter;// Along ray - float farParameter; // 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)); + float cosLat = cos(latitude); + return vec3( + cosLat * cos(longitude), + cosLat * sin(longitude), + sin(latitude)); } PositionNormalPair geodetic3ToCartesian( - float latitude, - float longitude, - float height, - vec3 radiiSquared) + 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; + 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); + // 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)); + 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) + vec3 rayOrigin, + vec3 rayOriginSquared, + vec3 rayDirection, + vec3 oneOverEllipsoidRadiiSquared) { float a = dot(rayDirection * rayDirection, oneOverEllipsoidRadiiSquared); float b = 2.0 * dot(rayOrigin * rayDirection, oneOverEllipsoidRadiiSquared); diff --git a/modules/globebrowsing/shaders/globalchunkedlodpatch_fs.glsl b/modules/globebrowsing/shaders/globalchunkedlodpatch_fs.glsl index 0bdf633ec6..9bdaa4fac7 100644 --- a/modules/globebrowsing/shaders/globalchunkedlodpatch_fs.glsl +++ b/modules/globebrowsing/shaders/globalchunkedlodpatch_fs.glsl @@ -36,4 +36,3 @@ Fragment getFragment() { frag.depth = fs_position.w; return frag; } - diff --git a/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl b/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl index 86904a5db8..31dcdb1e15 100644 --- a/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl +++ b/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl @@ -28,7 +28,8 @@ #include <${MODULE_GLOBEBROWSING}/shaders/ellipsoid.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/texturetilemapping.hglsl> -#include <${MODULE_GLOBEBROWSING}/shaders/tilevertexheight.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/tileheight.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/tilevertexskirt.hglsl> uniform mat4 modelViewProjectionTransform; uniform mat4 modelViewTransform; @@ -39,6 +40,9 @@ uniform vec2 lonLatScalingFactor; uniform vec3 cameraPosition; uniform float chunkMinHeight; +uniform float distanceScaleFactor; +uniform int chunkLevel; + layout(location = 1) in vec2 in_uv; out vec2 fs_uv; @@ -47,16 +51,21 @@ out vec3 ellipsoidNormalCameraSpace; out LevelWeights levelWeights; out vec3 positionCameraSpace; -PositionNormalPair globalInterpolation() { +#if USE_ACCURATE_NORMALS +out vec3 ellipsoidTangentThetaCameraSpace; +out vec3 ellipsoidTangentPhiCameraSpace; +#endif //USE_ACCURATE_NORMALS + +PositionNormalPair globalInterpolation(vec2 uv) { vec2 lonLatInput; - lonLatInput.y = minLatLon.y + lonLatScalingFactor.y * in_uv.y; // Lat - lonLatInput.x = minLatLon.x + lonLatScalingFactor.x * in_uv.x; // Lon + 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); return positionPairModelSpace; } void main() { - PositionNormalPair pair = globalInterpolation(); + PositionNormalPair pair = globalInterpolation(in_uv); float distToVertexOnEllipsoid = length(pair.position + pair.normal * chunkMinHeight - cameraPosition); @@ -70,11 +79,24 @@ void main() { levelWeights = getLevelWeights(levelInterpolationParameter); // Get the height value - float height = getTileVertexHeight(in_uv, levelWeights); + float height = getTileHeight(in_uv, levelWeights); // Apply skirts height -= 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. + float tileDelta = 1.0f / 512.0f; + PositionNormalPair pair10 = globalInterpolation(in_uv + vec2(1.0, 0.0) * tileDelta); + PositionNormalPair pair01 = globalInterpolation(in_uv + vec2(0.0, 1.0) * tileDelta); + vec3 ellipsoidTangentTheta = normalize(pair10.position - pair.position); + vec3 ellipsoidTangentPhi = normalize(pair01.position - pair.position); + ellipsoidTangentThetaCameraSpace = mat3(modelViewTransform) * ellipsoidTangentTheta; + ellipsoidTangentPhiCameraSpace = mat3(modelViewTransform) * ellipsoidTangentPhi; +#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); diff --git a/modules/globebrowsing/shaders/globeshading.hglsl b/modules/globebrowsing/shaders/globeshading.hglsl new file mode 100644 index 0000000000..25b73cc827 --- /dev/null +++ b/modules/globebrowsing/shaders/globeshading.hglsl @@ -0,0 +1,61 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef 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 + float L1 = max(0.0, NdotL) * (A + B * max(0.0, gamma) * C); + + return L1; +} + +#endif // GLOBESHADING_HGLSL \ No newline at end of file diff --git a/modules/globebrowsing/shaders/localchunkedlodpatch_fs.glsl b/modules/globebrowsing/shaders/localchunkedlodpatch_fs.glsl index 4601915b0c..300bfe9e31 100644 --- a/modules/globebrowsing/shaders/localchunkedlodpatch_fs.glsl +++ b/modules/globebrowsing/shaders/localchunkedlodpatch_fs.glsl @@ -36,4 +36,3 @@ Fragment getFragment() { frag.depth = fs_position.w; return frag; } - diff --git a/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl b/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl index 8665e88030..7952b116a3 100644 --- a/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl +++ b/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl @@ -28,7 +28,8 @@ #include <${MODULE_GLOBEBROWSING}/shaders/ellipsoid.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/texturetilemapping.hglsl> -#include <${MODULE_GLOBEBROWSING}/shaders/tilevertexheight.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/tileheight.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/tilevertexskirt.hglsl> uniform mat4 projectionTransform; @@ -41,6 +42,9 @@ uniform vec3 p11; uniform vec3 patchNormalCameraSpace; uniform float chunkMinHeight; +uniform float distanceScaleFactor; +uniform int chunkLevel; + layout(location = 1) in vec2 in_uv; out vec2 fs_uv; @@ -49,6 +53,11 @@ out vec3 ellipsoidNormalCameraSpace; out LevelWeights levelWeights; out vec3 positionCameraSpace; +#if USE_ACCURATE_NORMALS +out vec3 ellipsoidTangentThetaCameraSpace; +out vec3 ellipsoidTangentPhiCameraSpace; +#endif // USE_ACCURATE_NORMALS + vec3 bilinearInterpolation(vec2 uv) { vec3 p0 = (1 - uv.x) * p00 + uv.x * p10; vec3 p1 = (1 - uv.x) * p01 + uv.x * p11; @@ -75,7 +84,7 @@ void main() { levelWeights = getLevelWeights(levelInterpolationParameter); // Get the height value - float height = getTileVertexHeight(in_uv, levelWeights); + float height = getTileHeightScaled(in_uv, levelWeights); // Apply skirts height -= getTileVertexSkirtLength(); @@ -85,6 +94,12 @@ void main() { vec4 positionClippingSpace = projectionTransform * vec4(p, 1); + #if USE_ACCURATE_NORMALS + // Calculate tangents + ellipsoidTangentThetaCameraSpace = normalize(p10 - p00); + ellipsoidTangentPhiCameraSpace = normalize(p01 - p00); + #endif // USE_ACCURATE_NORMALS + // Write output fs_uv = in_uv; fs_position = z_normalization(positionClippingSpace); diff --git a/modules/globebrowsing/shaders/pointglobe_fs.glsl b/modules/globebrowsing/shaders/pointglobe_fs.glsl index cafeb66d3b..5977cfddab 100644 --- a/modules/globebrowsing/shaders/pointglobe_fs.glsl +++ b/modules/globebrowsing/shaders/pointglobe_fs.glsl @@ -24,31 +24,22 @@ #include "fragment.glsl" -uniform vec3 directionToSunViewSpace; +//uniform vec3 directionToSunViewSpace; uniform vec3 positionCameraSpace; +//uniform float lightOverflow; in vec4 vs_positionClipSpace; +in vec2 vs_positionModelSpace; Fragment getFragment() { - vec2 pointCoord = (gl_PointCoord.xy - vec2(0.5)) * 2; - pointCoord.y = -pointCoord.y; // y should point up in cam space - if(length(pointCoord) > 1) // Outside of circle radius? - discard; - - // z_coord of sphere - float zCoord = sqrt(1 - pow(length(pointCoord),2)); - - // Light calculations - vec3 normal = normalize(vec3(pointCoord, zCoord)); - float cosTerm = max(dot(directionToSunViewSpace, normal), 0); - - vec3 color = vec3(1,1,1) * 0.7; - vec3 shadedColor = cosTerm * color; - + float alpha = 1 - sqrt(pow(vs_positionModelSpace.x, 2) + pow(vs_positionModelSpace.y, 2)); + alpha = pow(alpha, 3); Fragment frag; - frag.color = vec4(shadedColor,1); + frag.color = vec4(1,1,1, alpha);// + vec4(1,1,1,1) * 0.0000000001 * directionToSunViewSpace.x; + //frag.color *= 1 + (lightOverflow * lightOverflow) * 0.0001; 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 index 011e9bdf07..c68b63d1bf 100644 --- a/modules/globebrowsing/shaders/pointglobe_vs.glsl +++ b/modules/globebrowsing/shaders/pointglobe_vs.glsl @@ -26,29 +26,28 @@ #include "PowerScaling/powerScaling_vs.hglsl" -layout(location = 0) in vec3 in_position; +layout(location = 0) in vec2 in_position; -uniform int windowWidth; -uniform float globeRadius; +uniform float lightIntensityClamped; uniform mat4 modelViewTransform; uniform mat4 projectionTransform; uniform mat4 directionToSunViewSpace; out vec4 vs_positionClipSpace; out vec4 vs_positionCameraSpace; +out vec2 vs_positionModelSpace; void main() { - vec4 positionCameraSpace = modelViewTransform * vec4(in_position, 1); - vs_positionClipSpace = projectionTransform * positionCameraSpace; + vs_positionModelSpace = in_position; - vs_positionClipSpace = z_normalization(vs_positionClipSpace); - - vec4 pointSizeCameraSpace = modelViewTransform * vec4(0,0, in_position.z, 1); - pointSizeCameraSpace.x = globeRadius; - pointSizeCameraSpace.y = globeRadius; - vec4 pointSizeClipSpace = projectionTransform * pointSizeCameraSpace; - vec4 pointSizeNDC = pointSizeClipSpace / pointSizeClipSpace.w; - - gl_PointSize = pointSizeNDC.x * 2 * windowWidth; - gl_Position = vs_positionClipSpace; + float totalIntensity = lightIntensityClamped; + + vec4 positionCameraSpace = modelViewTransform * vec4(in_position * totalIntensity, 0, 1); + + // Position + vec4 positionClipSpace = projectionTransform * positionCameraSpace; + + vs_positionClipSpace = z_normalization(positionClipSpace); + + gl_Position = z_normalization(positionClipSpace); } diff --git a/modules/globebrowsing/shaders/texturetilemapping.hglsl b/modules/globebrowsing/shaders/texturetilemapping.hglsl index a582abf800..64f94dcca4 100644 --- a/modules/globebrowsing/shaders/texturetilemapping.hglsl +++ b/modules/globebrowsing/shaders/texturetilemapping.hglsl @@ -27,6 +27,7 @@ #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 @@ -38,10 +39,6 @@ #define USE_COLORTEXTURE #{useColorLayers} #define COLORTEXTURE_BLENDING_ENABLED #{blendColorLayers} -#define NUMLAYERS_GRAYSCALETEXTURE #{lastLayerIndexGrayScaleLayers} + 1 -#define USE_GRAYSCALETEXTURE #{useGrayScaleLayers} -#define GRAYSCALETEXTURE_BLENDING_ENABLED #{blendGrayScaleLayers} - // Third layer type from LayerShaderManager is water mask #define NUMLAYERS_WATERMASK #{lastLayerIndexWaterMasks} + 1 #define USE_WATERMASK #{useWaterMasks} @@ -53,345 +50,390 @@ #define NIGHTTEXTURE_BLENDING_ENABLED #{blendNightLayers} // Fifth layer type from LayerShaderManager is overlay -#define NUMLAYERS_OVERLAY #{lastLayerIndexColorOverlays} + 1 -#define USE_OVERLAY #{useColorOverlays} -#define OVERLAY_BLENDING_ENABLED #{blendColorOverlays} - -// Sixth layer type from LayerShaderManager is grayscale overlay -#define NUMLAYERS_GRAYSCALE_OVERLAY #{lastLayerIndexGrayScaleColorOverlays} + 1 -#define USE_GRAYSCALE_OVERLAY #{useGrayScaleColorOverlays} -#define GRAYSCALE_OVERLAY_BLENDING_ENABLED #{blendGrayScaleColorOverlays} +#define NUMLAYERS_OVERLAY #{lastLayerIndexOverlays} + 1 +#define USE_OVERLAY #{useOverlays} +#define OVERLAY_BLENDING_ENABLED #{blendOverlays} // Global constants #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 SHOW_CHUNK_EDGES #{showChunkEdges} #define SHOW_HEIGHT_RESOLUTION #{showHeightResolution} #define SHOW_HEIGHT_INTENSITIES #{showHeightIntensities} -float performLayerSettings(float currentValue, const LayerSettings settings) { - float newValue = currentValue; +float performLayerSettingsRGB(float currentValue, const LayerSettings settings) { + float newValue = currentValue; - newValue = sign(newValue) * pow(abs(newValue), settings.gamma); - newValue = newValue * settings.multiplier; - newValue = newValue + settings.offset; - newValue = newValue * settings.opacity; + newValue = sign(newValue) * pow(abs(newValue), settings.gamma); + newValue = newValue * settings.multiplier; + newValue = newValue + settings.offset; - return newValue; + return newValue; } +vec4 performLayerSettingsRGB(vec4 currentValue, const LayerSettings settings) { + vec4 newValue = vec4( + performLayerSettingsRGB(currentValue.r, settings), + performLayerSettingsRGB(currentValue.g, settings), + performLayerSettingsRGB(currentValue.b, settings), + currentValue.a); + + return newValue; +} + +float performLayerSettingsAlpha(float currentValue, const LayerSettings settings) { + float newValue = currentValue; + newValue = newValue * settings.opacity; + return newValue; +} + +vec4 performLayerSettingsAlpha(vec4 currentValue, const LayerSettings settings) { + vec4 newValue = currentValue; + newValue.a = performLayerSettingsAlpha(currentValue.a, settings); + return newValue; +} + +float performLayerSettings(float currentValue, const LayerSettings settings) { + float newValue = performLayerSettingsRGB(currentValue, settings); + newValue = performLayerSettingsAlpha(newValue, settings); + return newValue; +} vec4 performLayerSettings(vec4 currentValue, const LayerSettings settings) { - vec4 newValue = vec4( - performLayerSettings(currentValue.r, settings), - performLayerSettings(currentValue.g, settings), - performLayerSettings(currentValue.b, settings), - performLayerSettings(currentValue.a, settings)); - - return newValue; + vec4 newValue = performLayerSettingsRGB(currentValue, settings); + newValue = performLayerSettingsAlpha(newValue, settings); + return newValue; } + +#for id, layerGroup in layerGroups +#for i in 0..#{lastLayerIndex#{layerGroup}} + +vec4 getSample#{layerGroup}#{i}( + const vec2 uv, + const LevelWeights levelWeights, + const Layer #{layerGroup}[#{lastLayerIndex#{layerGroup}} + 1]) +{ + vec4 color = vec4(0,0,0,1); + + // All tile layers are the same. Sample from texture +#if (#{#{layerGroup}#{i}LayerType} == 0) // DefaultTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 1) // SingleImageTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 2) // SizeReferenceTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 3) // TemporalTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 4) // TileIndexTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 5) // ByIndexTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 6) // ByLevelTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 7) // SolidColor + color.rgb = #{layerGroup}[#{i}].color; +#endif + + return color; +} + +#endfor +#endfor + +#for id, layerGroup in layerGroups +#for i in 0..#{lastLayerIndex#{layerGroup}} + +vec4 blend#{layerGroup}#{i}(vec4 currentColor, vec4 newColor, float blendFactor) { +#if (#{#{layerGroup}#{i}BlendMode} == 0) // Default, Normal + return blendNormal(currentColor, vec4(newColor.rgb, newColor.a * blendFactor)); +#elif (#{#{layerGroup}#{i}BlendMode} == 1) // Multiply + return blendMultiply(currentColor, newColor * blendFactor); +#elif (#{#{layerGroup}#{i}BlendMode} == 2) // Add + return blendAdd(currentColor, newColor * blendFactor); +#elif (#{#{layerGroup}#{i}BlendMode} == 3) // Subtract + return blendSubtract(currentColor, newColor * blendFactor); +#elif (#{#{layerGroup}#{i}BlendMode} == 4) // Color + // Convert color to grayscale + float gray = (newColor.r + newColor.g + newColor.b) / 3.0; + + vec3 hsvCurrent = rgb2hsv(currentColor.rgb); + // Use gray from new color as value in hsv + vec3 hsvNew = vec3(hsvCurrent.x, hsvCurrent.y, gray); + vec3 rgbNew = hsv2rgb(hsvNew); + + vec4 color = blendNormal(currentColor, vec4(rgbNew, newColor.a * blendFactor)); + return color; +#endif +} + +#endfor +#endfor + + +#for id, layerGroup in layerGroups +#for i in 0..#{lastLayerIndex#{layerGroup}} + +vec4 performAdjustment#{layerGroup}#{i}(vec4 currentColor, const LayerAdjustment adjustment) { +#if (#{#{layerGroup}#{i}LayerAdjustmentType} == 0) // Default, None + return currentColor; +#elif (#{#{layerGroup}#{i}LayerAdjustmentType} == 1) // ChromaKey + if (distance(currentColor.rgb, adjustment.chromaKeyColor) <= adjustment.chromaKeyTolerance) { + return vec4(0,0,0,0); + } + else { + return currentColor; + } +#elif (#{#{layerGroup}#{i}LayerAdjustmentType} == 2) // TransferFunction + return currentColor; +#else + return currentColor; +#endif +} + +#endfor +#endfor + float calculateUntransformedHeight( - vec2 uv, - LevelWeights levelWeights, - const Layer HeightTextures[NUMLAYERS_HEIGHTMAP]) { + vec2 uv, + LevelWeights levelWeights, + const Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { - float height = 0; + float height = 0; - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !HEIGHTMAP_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // HEIGHTMAP_BLENDING_ENABLED - - - #for i in 0..#{lastLayerIndexHeightLayers} - { - height = getTexVal(HeightTextures[#{i}].pile, levelWeights, uv).r; + + #for i in 0..#{lastLayerIndexHeightLayers} + { + vec4 colorSample = getSampleHeightLayers#{i}(uv, levelWeights, HeightLayers); + colorSample = performAdjustmentHeightLayers#{i}(colorSample, HeightLayers[#{i}].adjustment); + height = colorSample.r; - height = performLayerSettings(height, HeightTextures[#{i}].settings); - } - #endfor - return height; + height = performLayerSettings(height, HeightLayers[#{i}].settings); + } + #endfor + return height; } float calculateHeight( - vec2 uv, - LevelWeights levelWeights, - const Layer HeightTextures[NUMLAYERS_HEIGHTMAP]) { + vec2 uv, + LevelWeights levelWeights, + const Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { - float height = 0; + float height = 0; - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !HEIGHTMAP_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // HEIGHTMAP_BLENDING_ENABLED - - #for i in 0..#{lastLayerIndexHeightLayers} - { - float untransformedHeight = getTexVal(HeightTextures[#{i}].pile, levelWeights, uv).r; + + #for i in 0..#{lastLayerIndexHeightLayers} + { + vec4 colorSample = getSampleHeightLayers#{i}(uv, levelWeights, HeightLayers); + colorSample = performAdjustmentHeightLayers#{i}(colorSample, HeightLayers[#{i}].adjustment); + float untransformedHeight = colorSample.r; - float heightSample = getTransformedTexVal(HeightTextures[#{i}].depthTransform, untransformedHeight); - if (heightSample > -100000) { - heightSample = performLayerSettings(heightSample, HeightTextures[#{i}].settings); - height = heightSample; - } - } - #endfor - return height; + float heightSample = getTransformedTexVal(HeightLayers[#{i}].depthTransform, untransformedHeight); + if (heightSample > -100000) { + heightSample = performLayerSettings(heightSample, HeightLayers[#{i}].settings); + height = heightSample; + } + } + #endfor + return height; } vec4 calculateColor( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer ColorLayers[NUMLAYERS_COLORTEXTURE]) { + const vec4 currentColor, + const vec2 uv, + LevelWeights levelWeights, + const Layer ColorLayers[NUMLAYERS_COLORTEXTURE]) { - vec4 color = currentColor; + vec4 color = currentColor; - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !COLORTEXTURE_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // COLORTEXTURE_BLENDING_ENABLED - #for i in 0..#{lastLayerIndexColorLayers} - { - vec4 colorSample = getTexVal(ColorLayers[#{i}].pile, levelWeights, uv); + #for i in 0..#{lastLayerIndexColorLayers} + { + vec4 colorSample = getSampleColorLayers#{i}(uv, levelWeights, ColorLayers); + colorSample = performAdjustmentColorLayers#{i}(colorSample, ColorLayers[#{i}].adjustment); + colorSample = performLayerSettings(colorSample, ColorLayers[#{i}].settings); - colorSample = performLayerSettings(colorSample, ColorLayers[#{i}].settings); + color = blendColorLayers#{i}(color, colorSample, 1.0); + } + #endfor - color = blendOver(color, colorSample); - } - #endfor - - return color; -} - -vec4 calculateGrayScale( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer GrayScaleLayers[NUMLAYERS_GRAYSCALETEXTURE]) { - - vec4 colorGrayScale = currentColor; - - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 -#if !GRAYSCALETEXTURE_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); -#endif // GRAYSCALE_OVERLAY_BLENDING_ENABLED - - #for i in 0..#{lastLayerIndexGrayScaleLayers} - { - vec4 colorSample = getTexVal(GrayScaleLayers[#{i}].pile, levelWeights, uv); - - colorSample = vec4(colorSample.r, colorSample.r, colorSample.r, 1); - colorSample = performLayerSettings(colorSample, GrayScaleLayers[#{i}].settings); - - colorGrayScale = blendOver(colorGrayScale, colorSample); - } - #endfor - - return colorGrayScale; + return color; } float gridDots(vec2 uv, vec2 gridResolution){ - vec2 uvVertexSpace = fract((gridResolution) * uv) + 0.5; + vec2 uvVertexSpace = fract((gridResolution) * uv) + 0.5; - vec2 uvDotSpace = abs(2*(uvVertexSpace-0.5)); - return 1-length(1-uvDotSpace); + vec2 uvDotSpace = abs(2*(uvVertexSpace-0.5)); + return 1-length(1-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 colorVertex = (1.0-length(uvVertexSpace)) * vec3(0.5); - vec3 colorSum = colorUv + colorDistance + colorVertex; - return vec4(0.5 * colorSum, 1); + 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 colorVertex = (1.0-length(uvVertexSpace)) * vec3(0.5); + vec3 colorSum = colorUv + colorDistance + colorVertex; + return vec4(0.5 * colorSum, 1); } float tileResolution(vec2 tileUV, const ChunkTile chunkTile){ - vec2 heightResolution = textureSize(chunkTile.textureSampler, 0); - vec2 uv = TileUVToTextureSamplePosition(chunkTile, tileUV); - return gridDots(uv, heightResolution); + vec2 heightResolution = textureSize(chunkTile.textureSampler, 0); + vec2 uv = TileUVToTextureSamplePosition(chunkTile, tileUV); + return gridDots(uv, heightResolution); } - vec4 calculateNight( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer NightLayers[NUMLAYERS_NIGHTTEXTURE], - const vec3 ellipsoidNormalCameraSpace, - const vec3 lightDirectionCameraSpace) { + const vec4 currentColor, + const vec2 uv, + LevelWeights levelWeights, + const Layer NightLayers[NUMLAYERS_NIGHTTEXTURE], + const vec3 ellipsoidNormalCameraSpace, + const vec3 lightDirectionCameraSpace) { - vec4 nightColor = vec4(0,0,0,0); + vec4 nightColor = vec4(0,0,0,0); + vec4 color = currentColor; - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !NIGHTTEXTURE_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // NIGHTTEXTURE_BLENDING_ENABLED - #for i in 0..#{lastLayerIndexNightLayers} - { - vec4 colorSample = getTexVal(NightLayers[#{i}].pile, levelWeights, uv); - colorSample = performLayerSettings(colorSample, NightLayers[#{i}].settings); + vec3 n = normalize(ellipsoidNormalCameraSpace); + vec3 l = lightDirectionCameraSpace; + float cosineFactor = clamp(dot(l, normalize(n + 0.15 * l)) * 3 , 0, 1); + + #for i in 0..#{lastLayerIndexNightLayers} + { + vec4 colorSample = getSampleNightLayers#{i}(uv, levelWeights, NightLayers); + colorSample = performAdjustmentNightLayers#{i}(colorSample, NightLayers[#{i}].adjustment); + colorSample = performLayerSettings(colorSample, NightLayers[#{i}].settings); - nightColor = blendOver(nightColor, colorSample); - } - #endfor + float adjustedAlpha = cosineFactor * colorSample.a; + // Filter to night side + vec4 newColor = vec4(cosineFactor * colorSample.xyz, adjustedAlpha); + color = blendNightLayers#{i}(currentColor, newColor, adjustedAlpha); + } + #endfor - vec3 n = normalize(ellipsoidNormalCameraSpace); - vec3 l = lightDirectionCameraSpace; - - float cosineFactor = clamp(dot(l, normalize(n + 0.15 * l)) * 3 , 0, 1); - - // Blend shaded color with base color - vec4 color = vec4(currentColor.rgb + (cosineFactor) * nightColor.xyz, currentColor.a); - - return color; + return color; } vec4 calculateShadedColor( - const vec4 currentColor, - const vec3 ellipsoidNormalCameraSpace, - const vec3 lightDirectionCameraSpace) { + const vec4 currentColor, + const vec3 ellipsoidNormalCameraSpace, + const vec3 lightDirectionCameraSpace, + const vec3 viewDirectionCameraSpace, + float roughness) +{ + vec3 shadedColor = currentColor.rgb * 0.05; - vec3 shadedColor = currentColor.rgb * 0.05; + vec3 n = normalize(ellipsoidNormalCameraSpace); + vec3 l = lightDirectionCameraSpace; + + float power = orenNayarDiffuse( + -lightDirectionCameraSpace, + viewDirectionCameraSpace, + ellipsoidNormalCameraSpace, + roughness); - vec3 n = normalize(ellipsoidNormalCameraSpace); - vec3 l = lightDirectionCameraSpace; - - float cosineFactor = pow(clamp(dot(-l, n), 0, 1), 0.8); - - // Blend shaded color with base color - vec4 color = vec4(cosineFactor * currentColor.xyz + (1 - cosineFactor) * shadedColor, currentColor.a); - return color; + power = max(smoothstep(0.0f, 0.1f, max(dot(-l, n), 0.0f)) * power, 0.0f); + + vec4 color = vec4(shadedColor + currentColor.rgb * power, currentColor.a); + return color; } vec4 calculateOverlay( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer ColorOverlays[NUMLAYERS_OVERLAY]) { + const vec4 currentColor, + const vec2 uv, + LevelWeights levelWeights, + const Layer Overlays[NUMLAYERS_OVERLAY]) { - vec4 color = currentColor; + vec4 color = currentColor; - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !OVERLAY_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // OVERLAY_BLENDING_ENABLED - #for i in 0..#{lastLayerIndexColorOverlays} - { - vec4 colorSample = getTexVal(ColorOverlays[#{i}].pile, levelWeights, uv); - colorSample = performLayerSettings(colorSample, ColorOverlays[#{i}].settings); + #for i in 0..#{lastLayerIndexOverlays} + { + vec4 colorSample = getSampleOverlays#{i}(uv, levelWeights, Overlays); + colorSample = performAdjustmentOverlays#{i}(colorSample, Overlays[#{i}].adjustment); - color = blendOver(color, colorSample); - } - #endfor + colorSample = performLayerSettings(colorSample, Overlays[#{i}].settings); - return color; -} + color = blendNormal(color, colorSample); + color = blendOverlays#{i}(color, colorSample, 1.0); + } + #endfor -vec4 calculateGrayScaleOverlay( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer GrayScaleColorOverlays[NUMLAYERS_GRAYSCALE_OVERLAY]) { - - vec4 colorGrayScale = currentColor; - // HSV blending - vec3 hsvCurrent = rgb2hsv(currentColor.rgb); - vec4 value = vec4(0,0,0,1); - - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 -#if !GRAYSCALE_OVERLAY_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); -#endif // GRAYSCALE_OVERLAY_BLENDING_ENABLED - - #for i in 0..#{lastLayerIndexGrayScaleColorOverlays} - { - vec4 colorSample = getTexVal(GrayScaleColorOverlays[#{i}].pile, levelWeights, uv); - - colorSample = vec4(colorSample.r, colorSample.r, colorSample.r, colorSample.g); - colorSample = performLayerSettings(colorSample, GrayScaleColorOverlays[#{i}].settings); - - colorGrayScale = blendOver(colorGrayScale, colorSample); - - float valueBlending = GrayScaleColorOverlays[#{i}].settings.valueBlending; - - hsvCurrent.z = colorGrayScale.r * valueBlending + hsvCurrent.z * (1 - valueBlending); - colorGrayScale.rgb = vec3(hsvCurrent.z); - } - #endfor - - vec3 hsvNew = vec3(hsvCurrent.x, hsvCurrent.y, hsvCurrent.z); - vec3 rgbNew = hsv2rgb(hsvNew); -/* - // HSL blending - vec3 hslCurrent = rgb2hsl(currentColor.rgb); - //hslCurrent.y = hslCurrent.z > 0.7 ? 0 : hslCurrent.y; - vec3 hslNew = vec3(hslCurrent.x, hslCurrent.y, colorGrayScale.r); - vec3 rgbNew = hsl2rgb(hslNew); -*/ - // No color blending, use grayscale - //vec3 rgbNew = colorGrayScale.rgb; - vec4 color = blendOver(currentColor, vec4(rgbNew, colorGrayScale.a)); - - return color; + return color; } vec4 calculateWater( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer WaterMasks[NUMLAYERS_WATERMASK], - const vec3 ellipsoidNormalCameraSpace, - const vec3 lightDirectionCameraSpace, - const vec3 positionCameraSpace) { + const vec4 currentColor, + const vec2 uv, + LevelWeights levelWeights, + const Layer WaterMasks[NUMLAYERS_WATERMASK], + const vec3 ellipsoidNormalCameraSpace, + const vec3 lightDirectionCameraSpace, + const vec3 positionCameraSpace) { - vec4 waterColor = vec4(0,0,0,0); + vec4 waterColor = vec4(0,0,0,0); - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !WATERMASK_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // WATERMASK_BLENDING_ENABLED - #for i in 0..#{lastLayerIndexWaterMasks} - { - vec4 colorSample = getTexVal(WaterMasks[#{i}].pile, levelWeights, uv); + #for i in 0..#{lastLayerIndexWaterMasks} + { + vec4 colorSample = getSampleWaterMasks#{i}(uv, levelWeights, WaterMasks); + colorSample = performAdjustmentWaterMasks#{i}(colorSample, WaterMasks[#{i}].adjustment); - colorSample = performLayerSettings(colorSample, WaterMasks[#{i}].settings); + colorSample = performLayerSettingsAlpha(colorSample, WaterMasks[#{i}].settings); + colorSample.a = performLayerSettingsRGB(colorSample.a, WaterMasks[#{i}].settings); - waterColor = blendOver(waterColor, colorSample); - } - #endfor + waterColor = blendWaterMasks#{i}(waterColor, colorSample, 1.0); + } + #endfor - vec3 directionToFragmentCameraSpace = normalize(positionCameraSpace - vec3(0, 0, 0)); - vec3 reflectionDirectionCameraSpace = reflect(lightDirectionCameraSpace, ellipsoidNormalCameraSpace); - float cosineFactor = clamp(dot(-reflectionDirectionCameraSpace, directionToFragmentCameraSpace), 0, 1); - cosineFactor = pow(cosineFactor, 100); + vec3 directionToFragmentCameraSpace = normalize(positionCameraSpace - vec3(0, 0, 0)); + vec3 reflectionDirectionCameraSpace = reflect(lightDirectionCameraSpace, ellipsoidNormalCameraSpace); + float cosineFactor = clamp(dot(-reflectionDirectionCameraSpace, directionToFragmentCameraSpace), 0, 1); + cosineFactor = pow(cosineFactor, 100); - vec3 specularColor = vec3(1, 1, 1); - float specularIntensity = 0.4; + vec3 specularColor = vec3(1, 1, 1); + float specularIntensity = 0.4; - vec3 specularTotal = specularColor * cosineFactor * specularIntensity * waterColor.a; + vec3 specularTotal = specularColor * cosineFactor * specularIntensity * waterColor.a; - //return blendOver(currentColor, waterColor); - return currentColor + vec4(specularTotal, 1); + //return blendNormal(currentColor, waterColor); + return currentColor + vec4(specularTotal, 1); } #endif // TEXTURETILEMAPPING_HGLSL diff --git a/modules/globebrowsing/shaders/tile.hglsl b/modules/globebrowsing/shaders/tile.hglsl index 9d5e1c79a8..922e261ee8 100644 --- a/modules/globebrowsing/shaders/tile.hglsl +++ b/modules/globebrowsing/shaders/tile.hglsl @@ -32,11 +32,11 @@ #define TILE_PIXEL_SIZE_DIFFERENCE #{tilePaddingSizeDiff} 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); + 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); } @@ -50,11 +50,11 @@ struct TileDepthTransform { }; float getTransformedTexVal(const TileDepthTransform transform, const float val){ - return transform.depthOffset + transform.depthScale * val; + return transform.depthOffset + transform.depthScale * val; } vec4 getTransformedTexVal(const TileDepthTransform transform, const vec4 val){ - return transform.depthOffset + transform.depthScale * val; + return transform.depthOffset + transform.depthScale * val; } ///////////////////////////////////////////////////////////////////// @@ -71,30 +71,30 @@ struct TileUvTransform { // ChunkTile // ///////////////////////////////////////////////////////////////////// struct ChunkTile { - sampler2D textureSampler; - TileUvTransform uvTransform; + sampler2D textureSampler; + TileUvTransform uvTransform; }; vec2 compensateSourceTextureSampling(vec2 startOffset, vec2 sizeDiff, const ChunkTile chunkTile, vec2 tileUV){ - ivec2 resolution = textureSize(chunkTile.textureSampler, 0); + ivec2 resolution = textureSize(chunkTile.textureSampler, 0); - vec2 sourceSize = vec2(resolution) + sizeDiff; - vec2 currentSize = vec2(resolution); - vec2 sourceToCurrentSize = currentSize / sourceSize; - tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize); - return tileUV; + vec2 sourceSize = vec2(resolution) + sizeDiff; + vec2 currentSize = vec2(resolution); + vec2 sourceToCurrentSize = currentSize / sourceSize; + tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize); + return tileUV; } vec2 TileUVToTextureSamplePosition(const ChunkTile chunkTile, vec2 tileUV){ - vec2 uv = chunkTile.uvTransform.uvOffset + chunkTile.uvTransform.uvScale * tileUV; - uv = compensateSourceTextureSampling(TILE_PIXEL_START_OFFSET, TILE_PIXEL_SIZE_DIFFERENCE, chunkTile, uv); - return uv; + vec2 uv = chunkTile.uvTransform.uvOffset + chunkTile.uvTransform.uvScale * tileUV; + uv = compensateSourceTextureSampling(TILE_PIXEL_START_OFFSET, TILE_PIXEL_SIZE_DIFFERENCE, chunkTile, uv); + return uv; } vec4 getTexVal(const ChunkTile chunkTile, vec2 tileUV){ - vec2 samplePosition = TileUVToTextureSamplePosition(chunkTile, tileUV); - vec4 texVal = texture(chunkTile.textureSampler, samplePosition); - return texVal; + vec2 samplePosition = TileUVToTextureSamplePosition(chunkTile, tileUV); + vec4 texVal = texture(chunkTile.textureSampler, samplePosition); + return texVal; } @@ -103,58 +103,67 @@ vec4 getTexVal(const ChunkTile chunkTile, vec2 tileUV){ // Chunk Tile Pile // ///////////////////////////////////////////////////////////////////// struct ChunkTilePile { - ChunkTile chunkTile0; - ChunkTile chunkTile1; - ChunkTile chunkTile2; + ChunkTile chunkTile0; + ChunkTile chunkTile1; + ChunkTile chunkTile2; }; struct LayerSettings { - float opacity; - float gamma; - float multiplier; - float offset; - float valueBlending; + float opacity; + float gamma; + float multiplier; + float offset; + float valueBlending; +}; + +struct LayerAdjustment { + vec3 chromaKeyColor; + float chromaKeyTolerance; }; struct Layer { - ChunkTilePile pile; - TileDepthTransform depthTransform; - LayerSettings settings; + ChunkTilePile pile; + TileDepthTransform depthTransform; + LayerSettings settings; + LayerAdjustment adjustment; + + // Other layer type properties stuff + vec3 color; }; struct LevelWeights { - float w1; - float w2; - float w3; + float w1; + float w2; + float w3; }; float getLevelInterpolationParameter(int chunkLevel, float distanceScaleFactor, float distToVertexOnEllipsoid){ - float projectedScaleFactor = distanceScaleFactor / distToVertexOnEllipsoid; - float desiredLevel = log2(projectedScaleFactor); - return chunkLevel - desiredLevel; + float projectedScaleFactor = distanceScaleFactor / distToVertexOnEllipsoid; + float desiredLevel = log2(projectedScaleFactor); + return chunkLevel - desiredLevel; } LevelWeights getLevelWeights(float levelInterpolationParameter){ - LevelWeights levelWeights; - levelWeights.w1 = clamp(1 - levelInterpolationParameter, 0 , 1); - levelWeights.w2 = (clamp(levelInterpolationParameter, 0 , 1) - clamp(levelInterpolationParameter - 1, 0 , 1)); - levelWeights.w3 = clamp(levelInterpolationParameter - 1, 0 , 1); - return levelWeights; + LevelWeights levelWeights; + levelWeights.w1 = clamp(1 - levelInterpolationParameter, 0 , 1); + levelWeights.w2 = (clamp(levelInterpolationParameter, 0 , 1) - clamp(levelInterpolationParameter - 1, 0 , 1)); + levelWeights.w3 = clamp(levelInterpolationParameter - 1, 0 , 1); + return levelWeights; } LevelWeights getDefaultLevelWeights(){ - LevelWeights levelWeights; - levelWeights.w1 = 1; - levelWeights.w2 = 0; - levelWeights.w3 = 0; - return levelWeights; + LevelWeights levelWeights; + levelWeights.w1 = 1; + levelWeights.w2 = 0; + levelWeights.w3 = 0; + return levelWeights; } vec4 getTexVal(const ChunkTilePile chunkTilePile, const LevelWeights w, const vec2 uv){ - return w.w1 * getTexVal(chunkTilePile.chunkTile0, uv) + - w.w2 * getTexVal(chunkTilePile.chunkTile1, uv) + - w.w3 * getTexVal(chunkTilePile.chunkTile2, uv); + return w.w1 * getTexVal(chunkTilePile.chunkTile0, uv) + + w.w2 * getTexVal(chunkTilePile.chunkTile1, uv) + + w.w3 * getTexVal(chunkTilePile.chunkTile2, uv); } diff --git a/modules/globebrowsing/shaders/tilefragcolor.hglsl b/modules/globebrowsing/shaders/tilefragcolor.hglsl index 6cf772c073..c3e377a99a 100644 --- a/modules/globebrowsing/shaders/tilefragcolor.hglsl +++ b/modules/globebrowsing/shaders/tilefragcolor.hglsl @@ -27,6 +27,7 @@ #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/texturetilemapping.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/tileheight.hglsl> #include "PowerScaling/powerScaling_fs.hglsl" @@ -37,22 +38,14 @@ uniform Layer ColorLayers[NUMLAYERS_COLORTEXTURE]; #endif // USE_COLORTEXTURE -#if USE_GRAYSCALETEXTURE -uniform Layer GrayScaleLayers[NUMLAYERS_GRAYSCALETEXTURE]; -#endif // USE_GRAYSCALETEXTURE - #if USE_NIGHTTEXTURE uniform Layer NightLayers[NUMLAYERS_NIGHTTEXTURE]; #endif // USE_NIGHTTEXTURE #if USE_OVERLAY -uniform Layer ColorOverlays[NUMLAYERS_OVERLAY]; +uniform Layer Overlays[NUMLAYERS_OVERLAY]; #endif // USE_OVERLAY -#if USE_GRAYSCALE_OVERLAY -uniform Layer GrayScaleColorOverlays[NUMLAYERS_GRAYSCALE_OVERLAY]; -#endif // USE_GRAYSCALE_OVERLAY - #if USE_WATERMASK uniform Layer WaterMasks[NUMLAYERS_WATERMASK]; #endif // USE_WATERMASK @@ -66,7 +59,11 @@ uniform vec2 vertexResolution; #endif // USE_ATMOSPHERE #if USE_NIGHTTEXTURE || USE_WATERMASK || USE_ATMOSPHERE || PERFORM_SHADING - uniform vec3 lightDirectionCameraSpace; + uniform vec3 lightDirectionCameraSpace; +#endif + +#if PERFORM_SHADING + uniform float orenNayarRoughness; #endif in vec4 fs_position; @@ -74,162 +71,123 @@ in vec2 fs_uv; in vec3 ellipsoidNormalCameraSpace; in vec3 positionCameraSpace; +#if USE_ACCURATE_NORMALS +in vec3 ellipsoidTangentThetaCameraSpace; +in vec3 ellipsoidTangentPhiCameraSpace; +#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; - -///////////////////////////////////////////////////////////////////// - -// The heightmaps is only used in the fragment shader visually debugging -// the alignment and resolution of the heightmaps - -#if USE_HEIGHTMAP -uniform Layer HeightLayers[NUMLAYERS_HEIGHTMAP]; -#endif // USE_HEIGHTMAP - -float getUntransformedTileVertexHeight(vec2 uv, LevelWeights levelWeights){ - float height = CHUNK_DEFAULT_HEIGHT; - -#if USE_HEIGHTMAP - // Calculate desired level based on distance to the vertex on the ellipsoid - // Before any heightmapping is done - height = calculateUntransformedHeight( - uv, - levelWeights, // Variable to determine which texture to sample from - HeightLayers); // Three textures to sample from - -#endif // USE_HEIGHTMAP - - return height; -} - -///////////////////////////////////////////////////////////////////// - - - - /** * This method defines the fragment color pipeline which is used in both * the local and global chunk rendering. * */ -vec4 getTileFragColor(){ +vec4 getTileFragColor() { - vec4 color = vec4(0.3,0.3,0.3,1); + vec4 color = vec4(0.3,0.3,0.3,1); + + vec3 normal = normalize(ellipsoidNormalCameraSpace); +#if USE_ACCURATE_NORMALS + normal = getTileNormal(fs_uv, levelWeights, + normalize(ellipsoidNormalCameraSpace), + normalize(ellipsoidTangentThetaCameraSpace), + normalize(ellipsoidTangentPhiCameraSpace)); +#endif /// USE_ACCURATE_NORMALS #if USE_COLORTEXTURE - - color = calculateColor( - color, - fs_uv, - levelWeights, - ColorLayers); -#endif // USE_COLORTEXTURE - -#if USE_GRAYSCALETEXTURE - color = calculateGrayScale( - color, - fs_uv, - levelWeights, - GrayScaleLayers); -#endif // USE_GRAYSCALETEXTURE - -#if USE_GRAYSCALE_OVERLAY - - color = calculateGrayScaleOverlay( - color, - fs_uv, - levelWeights, - GrayScaleColorOverlays); - + color = calculateColor( + color, + fs_uv, + levelWeights, + ColorLayers); #endif // USE_COLORTEXTURE #if USE_WATERMASK - color = calculateWater( - color, - fs_uv, - levelWeights, - WaterMasks, - normalize(ellipsoidNormalCameraSpace), - lightDirectionCameraSpace, // Should already be normalized - positionCameraSpace); + color = calculateWater( + color, + fs_uv, + levelWeights, + WaterMasks, + normal, + lightDirectionCameraSpace, // Should already be normalized + positionCameraSpace); #endif // USE_WATERMASK #if USE_NIGHTTEXTURE - color = calculateNight( - color, - fs_uv, - levelWeights, - NightLayers, - normalize(ellipsoidNormalCameraSpace), - lightDirectionCameraSpace); // Should already be normalized + color = calculateNight( + color, + fs_uv, + levelWeights, + NightLayers, + normalize(ellipsoidNormalCameraSpace), + lightDirectionCameraSpace); // Should already be normalized #endif // USE_NIGHTTEXTURE #if PERFORM_SHADING - color = calculateShadedColor( - color, - normalize(ellipsoidNormalCameraSpace), - lightDirectionCameraSpace); + color = calculateShadedColor( + color, + normal, + lightDirectionCameraSpace, + normalize(positionCameraSpace), + orenNayarRoughness); #endif // PERFORM_SHADING #if USE_ATMOSPHERE - // Temporary until the real atmosphere code is here - //color = color + vec4(0.5,0.5,1,0) * 0.3; // Just to see something for now - vec3 n = normalize(ellipsoidNormalCameraSpace); - vec3 l = lightDirectionCameraSpace; - 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, 1); - cosFactor = cosFactor + pow(cosFactor, 5); - - 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); - vec3 atmosphereColor = vec3(0.5,0.5,1) * 2; - color = color + vec4(atmosphereColor,0) * cosFactor * cosFactorLight * 0.5; + // Temporary until the real atmosphere code is here + //color = color + vec4(0.5,0.5,1,0) * 0.3; // Just to see something for now + vec3 n = normalize(ellipsoidNormalCameraSpace); + vec3 l = lightDirectionCameraSpace; + 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, 1); + cosFactor = cosFactor + pow(cosFactor, 5); + + 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); + vec3 atmosphereColor = vec3(0.5,0.5,1) * 2; + color = color + vec4(atmosphereColor,0) * cosFactor * cosFactorLight * 0.5; #endif // USE_ATMOSPHERE #if USE_OVERLAY - color = calculateOverlay( - color, - fs_uv, - levelWeights, - ColorOverlays); + color = calculateOverlay( + color, + fs_uv, + levelWeights, + Overlays); #endif // USE_OVERLAY - - #if SHOW_HEIGHT_INTENSITIES - color.r *= 0.1; - color.g *= 0.1; - color.b *= 0.1; + color.r *= 0.1; + color.g *= 0.1; + color.b *= 0.1; - float untransformedHeight = getUntransformedTileVertexHeight(fs_uv, levelWeights); - float contourLine = fract(10*untransformedHeight) > 0.98 ? 1 : 0; - color.r += untransformedHeight; - color.b = contourLine; + float untransformedHeight = getUntransformedTileVertexHeight(fs_uv, levelWeights); + float contourLine = fract(10*untransformedHeight) > 0.98 ? 1 : 0; + color.r += untransformedHeight; + color.b = contourLine; #endif - #if SHOW_HEIGHT_RESOLUTION - color += 0.0001*calculateDebugColor(fs_uv, fs_position, vertexResolution); - #if USE_HEIGHTMAP - color.r = min(color.r, 0.8); - color.r += tileResolution(fs_uv, HeightLayers[0].pile.chunkTile0) > 0.9 ? 1 : 0; - #endif + color += 0.0001*calculateDebugColor(fs_uv, fs_position, vertexResolution); + #if USE_HEIGHTMAP + color.r = min(color.r, 0.8); + color.r += tileResolution(fs_uv, HeightLayers[0].pile.chunkTile0) > 0.9 ? 1 : 0; + #endif #endif - return color; + return color; } diff --git a/modules/globebrowsing/shaders/tileheight.hglsl b/modules/globebrowsing/shaders/tileheight.hglsl new file mode 100644 index 0000000000..2f8b6ea746 --- /dev/null +++ b/modules/globebrowsing/shaders/tileheight.hglsl @@ -0,0 +1,125 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef TILE_HEIGHT_HGLSL +#define TILE_HEIGHT_HGLSL + +#include "PowerScaling/powerScaling_vs.hglsl" + +#include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/ellipsoid.hglsl> + + +#ifndef USE_HEIGHTMAP +#define USE_HEIGHTMAP #{useAccurateNormals} +#endif //USE_HEIGHTMAP + +#ifndef USE_ACCURATE_NORMALS +#define USE_ACCURATE_NORMALS #{useAccurateNormals} +#endif //USE_ACCURATE_NORMALS + +#if USE_HEIGHTMAP +uniform Layer HeightLayers[NUMLAYERS_HEIGHTMAP]; +uniform float heightScale; +#endif // USE_HEIGHTMAP + +#if USE_ACCURATE_NORMALS +uniform float deltaTheta0; +uniform float deltaTheta1; +uniform float deltaPhi0; +uniform float deltaPhi1; +uniform float tileDelta; +#endif //USE_ACCURATE_NORMALS + +float getUntransformedTileHeight(vec2 uv, LevelWeights levelWeights){ + float height = CHUNK_DEFAULT_HEIGHT; + +#if USE_HEIGHTMAP + // Calculate desired level based on distance to the vertex on the ellipsoid + // Before any heightmapping is done + height = calculateUntransformedHeight( + uv, + levelWeights, // Variable to determine which texture to sample from + HeightLayers); // Three textures to sample from + +#endif // USE_HEIGHTMAP + + return height; +} + +float getTileHeight(vec2 uv, LevelWeights levelWeights){ + float height = CHUNK_DEFAULT_HEIGHT; + +#if USE_HEIGHTMAP + // Calculate desired level based on distance to the vertex on the ellipsoid + // Before any heightmapping is done + height = calculateHeight( + uv, + levelWeights, // Variable to determine which texture to sample from + HeightLayers); // Three textures to sample from +#endif // USE_HEIGHTMAP + + return height; +} + +float getTileHeightScaled(vec2 uv, LevelWeights levelWeights){ + float height = getTileHeight(uv, levelWeights); + +#if USE_HEIGHTMAP + height *= heightScale; +#endif // USE_HEIGHTMAP + + return height; +} + +vec3 getTileNormal( + vec2 uv, + LevelWeights levelWeights, + vec3 ellipsoidNormalCameraSpace, + vec3 ellipsoidTangentThetaCameraSpace, + vec3 ellipsoidTangentPhiCameraSpace) +{ + vec3 normal = ellipsoidNormalCameraSpace; + +#if USE_ACCURATE_NORMALS + float deltaPhi = mix(deltaPhi0, deltaPhi1, uv.x); + float deltaTheta = mix(deltaTheta0, deltaTheta1, uv.y); + + vec3 deltaPhiVec = ellipsoidTangentPhiCameraSpace * deltaPhi; + vec3 deltaThetaVec = ellipsoidTangentThetaCameraSpace * deltaTheta; + + float height00 = getTileHeightScaled(uv, levelWeights); + float height10 = getTileHeightScaled(uv + vec2(tileDelta, 0.0f), levelWeights); + float height01 = getTileHeightScaled(uv + vec2(0.0f, tileDelta), levelWeights); + + vec3 diffTheta = deltaThetaVec + ellipsoidNormalCameraSpace * (height10 - height00); + vec3 diffPhi = deltaPhiVec + ellipsoidNormalCameraSpace * (height01 - height00); + + normal = normalize(cross(diffTheta, diffPhi)); +#endif // USE_ACCURATE_NORMALS + return normal; +} + + +#endif // TILE_HEIGHT_HGLSL diff --git a/modules/globebrowsing/shaders/tilevertexheight.hglsl b/modules/globebrowsing/shaders/tilevertexheight.hglsl deleted file mode 100644 index 6733b30c96..0000000000 --- a/modules/globebrowsing/shaders/tilevertexheight.hglsl +++ /dev/null @@ -1,126 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef TILE_VERTEX_HEIGHT_HGLSL -#define TILE_VERTEX_HEIGHT_HGLSL - -#include "PowerScaling/powerScaling_vs.hglsl" - -#include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> - - -#if USE_HEIGHTMAP -uniform Layer HeightLayers[NUMLAYERS_HEIGHTMAP]; -#endif // USE_HEIGHTMAP - -uniform int xSegments; -uniform float skirtLength; - -uniform float distanceScaleFactor; -uniform int chunkLevel; - - -float getUntransformedTileVertexHeight(vec2 uv, LevelWeights levelWeights){ - float height = CHUNK_DEFAULT_HEIGHT; - -#if USE_HEIGHTMAP - // Calculate desired level based on distance to the vertex on the ellipsoid - // Before any heightmapping is done - height = calculateUntransformedHeight( - uv, - levelWeights, // Variable to determine which texture to sample from - HeightLayers); // Three textures to sample from - -#endif // USE_HEIGHTMAP - - return height; -} - - -float getTileVertexHeight(vec2 uv, LevelWeights levelWeights){ - float height = CHUNK_DEFAULT_HEIGHT; - -#if USE_HEIGHTMAP - // Calculate desired level based on distance to the vertex on the ellipsoid - // Before any heightmapping is done - height = calculateHeight( - uv, - levelWeights, // Variable to determine which texture to sample from - HeightLayers); // Three textures to sample from - -#endif // USE_HEIGHTMAP - - return height; -} - -// This function is currently not correct -vec3 getTileVertexNormal( - vec2 uv, - LevelWeights levelWeights, - vec3 ellipsoidNormal) { - vec3 normal = ellipsoidNormal; - -#if USE_HEIGHTMAP - float sampleDelta = 1.0 / xSegments; - - float heightCenter = calculateHeight( - uv, - levelWeights, - HeightLayers); - float heightOffsetX = calculateHeight( - uv + vec2(sampleDelta, 0.0), - levelWeights, - HeightLayers); - float heightOffsetY = calculateHeight( - uv + vec2(0.0, sampleDelta), - levelWeights, - HeightLayers); - - vec3 e0 = normalize(cross(vec3(0,0,1), ellipsoidNormal)); - vec3 e1 = cross(ellipsoidNormal, e0); - vec3 e2 = ellipsoidNormal; - - vec3 v0 = e0 * sampleDelta * 3000000 + e2 * heightOffsetX; - vec3 v1 = e1 * sampleDelta * 3000000 + e2 * heightOffsetY; - - vec3 n = cross(v0, v1); - - normal = normalize(n); - -#endif // USE_HEIGHTMAP - return normal; -} - -bool tileVertexIsSkirtVertex(){ - int vertexIDx = gl_VertexID % (xSegments + 3); - int vertexIDy = gl_VertexID / (xSegments + 3); - return vertexIDx == 0 || vertexIDy == 0 || - vertexIDx == (xSegments + 2) || vertexIDy == (xSegments + 2); -} - -float getTileVertexSkirtLength(){ - return tileVertexIsSkirtVertex() ? skirtLength : 0.0; -} - -#endif // TILE_VERTEX_HEIGHT_HGLSL diff --git a/modules/globebrowsing/shaders/tilevertexskirt.hglsl b/modules/globebrowsing/shaders/tilevertexskirt.hglsl new file mode 100644 index 0000000000..1c86a24986 --- /dev/null +++ b/modules/globebrowsing/shaders/tilevertexskirt.hglsl @@ -0,0 +1,44 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef TILE_VERTEX_SKIRT_HGLSL +#define TILE_VERTEX_SKIRT_HGLSL + +#include "PowerScaling/powerScaling_vs.hglsl" + +uniform int xSegments; +uniform float skirtLength; + +bool tileVertexIsSkirtVertex(){ + int vertexIDx = gl_VertexID % (xSegments + 3); + int vertexIDy = gl_VertexID / (xSegments + 3); + return vertexIDx == 0 || vertexIDy == 0 || + vertexIDx == (xSegments + 2) || vertexIDy == (xSegments + 2); +} + +float getTileVertexSkirtLength(){ + return tileVertexIsSkirtVertex() ? skirtLength : 0.0; +} + +#endif // TILE_VERTEX_SKIRT_HGLSL diff --git a/modules/globebrowsing/tile/asynctiledataprovider.cpp b/modules/globebrowsing/tile/asynctiledataprovider.cpp index 31ece2f257..46723e5fbc 100644 --- a/modules/globebrowsing/tile/asynctiledataprovider.cpp +++ b/modules/globebrowsing/tile/asynctiledataprovider.cpp @@ -24,6 +24,7 @@ #include +#include #include #include @@ -47,10 +48,10 @@ AsyncTileDataProvider::AsyncTileDataProvider(const std::string& name, const std::shared_ptr rawTileDataReader) : _name(name) , _rawTileDataReader(rawTileDataReader) - , _concurrentJobManager( - std::make_shared>(1, 10)) + , _concurrentJobManager(LRUThreadPool(1, 10)) , _pboContainer(nullptr) , _resetMode(ResetMode::ShouldResetAllButRawTileDataReader) + , _shouldBeDeleted(false) { _globeBrowsingModule = OsEng.moduleEngine().module(); performReset(ResetRawTileDataReader::No); @@ -176,7 +177,6 @@ void AsyncTileDataProvider::updatePboUsage() { } void AsyncTileDataProvider::update() { - updatePboUsage(); endUnfinishedJobs(); // May reset @@ -203,8 +203,19 @@ void AsyncTileDataProvider::update() { } break; } - case ResetMode::ShouldNotReset: + case ResetMode::ShouldBeDeleted: { + // Clean all finished jobs + getRawTiles(); + // Only allow resetting if there are no jobs currently running + if (_enqueuedTileRequests.size() == 0) { + _shouldBeDeleted = true; + } break; + } + case ResetMode::ShouldNotReset: { + updatePboUsage(); + break; + } default: break; } @@ -219,6 +230,15 @@ void AsyncTileDataProvider::reset() { "'" + _name + "'"); } +void AsyncTileDataProvider::prepairToBeDeleted() { + _resetMode = ResetMode::ShouldBeDeleted; + endEnqueuedJobs(); +} + +bool AsyncTileDataProvider::shouldBeDeleted() { + return _shouldBeDeleted; +} + void AsyncTileDataProvider::performReset(ResetRawTileDataReader resetRawTileDataReader) { ghoul_assert(_enqueuedTileRequests.size() == 0, "No enqueued requests left"); diff --git a/modules/globebrowsing/tile/asynctiledataprovider.h b/modules/globebrowsing/tile/asynctiledataprovider.h index c84c4e5d92..d318eb3851 100644 --- a/modules/globebrowsing/tile/asynctiledataprovider.h +++ b/modules/globebrowsing/tile/asynctiledataprovider.h @@ -76,6 +76,9 @@ public: void update(); void reset(); + void prepairToBeDeleted(); + + bool shouldBeDeleted(); std::shared_ptr getRawTileDataReader() const; float noDataValueAsFloat() const; @@ -86,6 +89,7 @@ protected: enum class ResetMode { ShouldResetAll, ShouldResetAllButRawTileDataReader, + ShouldBeDeleted, ShouldNotReset }; @@ -121,6 +125,7 @@ private: std::set _enqueuedTileRequests; ResetMode _resetMode; + bool _shouldBeDeleted; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp b/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp index dfcf8d1d01..45eaa90a8b 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp @@ -151,6 +151,9 @@ IODescription GdalRawTileDataReader::getIODescription(const TileIndex& tileIndex } void GdalRawTileDataReader::initialize() { + if (_datasetFilePath.empty()) { + throw ghoul::RuntimeError("File path must not be empty"); + } _dataset = openGdalDataset(_datasetFilePath); // Assume all raster bands have the same data type @@ -176,6 +179,7 @@ void GdalRawTileDataReader::initialize() { if (numOverviews > 0) { _cached._maxLevel += numOverviews - 1; } + _cached._maxLevel = std::max(_cached._maxLevel, 2); } void GdalRawTileDataReader::readImageData( @@ -187,47 +191,108 @@ void GdalRawTileDataReader::readImageData( switch (_initData.ghoulTextureFormat()) { case ghoul::opengl::Texture::Format::Red: + if (nRastersToRead == 1) { // One channel + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageDataDest + _initData.bytesPerDatum(); + + RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + break; case ghoul::opengl::Texture::Format::RG: case ghoul::opengl::Texture::Format::RGB: case ghoul::opengl::Texture::Format::RGBA: { - // Read the data (each rasterband is a separate channel) - 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* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + 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* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); - RawTile::ReadError err = repeatedRasterRead(i + 1, io, dataDestination); + RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + 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* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + // Last read is the alpha channel + char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum()); + RawTile::ReadError err = repeatedRasterRead(2, io, dataDestination); // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 worstError = std::max(worstError, err); } - break; - } - case ghoul::opengl::Texture::Format::BGR: { - // Read the data (each rasterband is a separate channel) - 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* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + 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* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); - RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); + RawTile::ReadError err = repeatedRasterRead(i + 1, io, dataDestination); - // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 - worstError = std::max(worstError, err); + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } } break; } + case ghoul::opengl::Texture::Format::BGR: case ghoul::opengl::Texture::Format::BGRA: { - 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* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + 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* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); - RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); + RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + 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* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + // Last read is the alpha channel + char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum()); + RawTile::ReadError err = repeatedRasterRead(2, io, dataDestination); // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 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* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + } if (nRastersToRead > 3) { // Alpha channel exists // Last read is the alpha channel char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum()); @@ -272,8 +337,8 @@ RawTile::ReadError GdalRawTileDataReader::rasterRead( dataDest += io.write.region.start.x * _initData.bytesPerPixel(); GDALRasterBand* gdalRasterBand = _dataset->GetRasterBand(rasterBand); - CPLErr readError = CE_Failure; - readError = gdalRasterBand->RasterIO( + 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 @@ -321,14 +386,13 @@ int GdalRawTileDataReader::calculateTileLevelDifference(int minimumPixelSize) co GDALRasterBand* firstBand = _dataset->GetRasterBand(1); GDALRasterBand* maxOverview; int numOverviews = firstBand->GetOverviewCount(); - int sizeLevel0; if (numOverviews <= 0) { // No overviews. Use first band. maxOverview = firstBand; } else { // Pick the highest overview. maxOverview = firstBand->GetOverview(numOverviews - 1); } - sizeLevel0 = maxOverview->GetXSize(); + int sizeLevel0 = maxOverview->GetXSize(); double diff = log2(minimumPixelSize) - log2(sizeLevel0); return diff; } @@ -336,4 +400,4 @@ int GdalRawTileDataReader::calculateTileLevelDifference(int minimumPixelSize) co } // namespace globebrowsing } // namespace openspace -#endif // GLOBEBROWSING_USE_GDAL +#endif // GLOBEBROWSING_USE_GDAL \ No newline at end of file diff --git a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp index a2f9e000b6..b88fb167ed 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp @@ -330,6 +330,8 @@ std::shared_ptr RawTileDataReader::getTileMetaData( noDataValues[raster] = noDataValueAsFloat(); } + bool allIsMissing = true; + for (int y = 0; y < region.numPixels.y; ++y) { size_t yi = (region.numPixels.y - 1 - y) * bytesPerLine; size_t i = 0; @@ -340,7 +342,9 @@ std::shared_ptr RawTileDataReader::getTileMetaData( _initData.glType(), &(rawTile->imageData[yi + i]) ); - if (val != noDataValue && val == val) { + if (val != noDataValue && + val == val) + { preprocessData->maxValues[raster] = std::max( val, preprocessData->maxValues[raster] @@ -349,14 +353,21 @@ std::shared_ptr RawTileDataReader::getTileMetaData( val, preprocessData->minValues[raster] ); + allIsMissing = false; } else { preprocessData->hasMissingData[raster] = true; + float& floatToRewrite = reinterpret_cast(rawTile->imageData[yi + i]); + floatToRewrite = -FLT_MAX; } i += _initData.bytesPerDatum(); } } } + + if (allIsMissing) { + rawTile->error = RawTile::ReadError::Failure; + } return std::shared_ptr(preprocessData); } diff --git a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp index 03a08c4ed0..4278175d9b 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp @@ -415,7 +415,10 @@ size_t numberOfRasters(ghoul::opengl::Texture::Format format) { case ghoul::opengl::Texture::Format::BGR: return 3; case ghoul::opengl::Texture::Format::RGBA:; // Intentional fallthrough case ghoul::opengl::Texture::Format::BGRA: return 4; - default: ghoul_assert(false, "Unknown format"); + default: { + ghoul_assert(false, "Unknown format"); + return 0; + } } } @@ -430,8 +433,10 @@ size_t numberOfBytes(GLenum glType) { case GL_HALF_FLOAT: return sizeof(GLhalf); case GL_FLOAT: return sizeof(GLfloat); case GL_DOUBLE: return sizeof(GLdouble); - default: + default: { ghoul_assert(false, "Unknown data type"); + return 0; + } } } @@ -447,8 +452,10 @@ size_t getMaximumValue(GLenum glType) { return size_t(1) << 32; case GL_INT: return 1 << 31; - default: + default: { ghoul_assert(false, "Unknown data type"); + return 0; + } } } @@ -470,8 +477,10 @@ float interpretFloat(GLenum glType, const char* src) { return static_cast(*reinterpret_cast(src)); case GL_DOUBLE: return static_cast(*reinterpret_cast(src)); - default: + default: { ghoul_assert(false, "Unknown data type"); + return 0; + } } } diff --git a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.cpp b/modules/globebrowsing/tile/tileprovider/cachingtileprovider.cpp deleted file mode 100644 index eb2d003bf8..0000000000 --- a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -namespace { - const char* KeyPerformPreProcessing = "PerformPreProcessing"; - const char* KeyTilePixelSize = "TilePixelSize"; - const char* KeyFilePath = "FilePath"; - const char* KeyBasePath = "BasePath"; - const char* KeyPreCacheLevel = "PreCacheLevel"; -} - -namespace openspace { -namespace globebrowsing { -namespace tileprovider { - -CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary) - : TileProvider(dictionary) -{ - _tileCache = OsEng.moduleEngine().module()->tileCache(); - _name = "Name unspecified"; - dictionary.getValue("Name", _name); - std::string _loggerCat = "CachingTileProvider : " + _name; - - // 1. Get required Keys - std::string filePath; - if (!dictionary.getValue(KeyFilePath, filePath)) { - throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'"); - } - - layergroupid::ID layerGroupID; - 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("Default pixel size overridden: " << pixelSize); - tilePixelSize = static_cast(pixelSize); - } - - TileTextureInitData initData(LayerManager::getTileTextureInitData( - layerGroupID, tilePixelSize)); - - bool performPreProcessing = - LayerManager::shouldPerformPreProcessingOnLayergroup(layerGroupID); - if (dictionary.getValue(KeyPerformPreProcessing, performPreProcessing)) { - LDEBUG("Default PerformPreProcessing overridden: " << performPreProcessing); - } - RawTileDataReader::PerformPreprocessing preprocess = - performPreProcessing ? RawTileDataReader::PerformPreprocessing::Yes : - RawTileDataReader::PerformPreprocessing::No; - - std::string basePath; - dictionary.getValue(KeyBasePath, basePath); - - // Initialize instance variables -#ifdef GLOBEBROWSING_USE_GDAL - auto tileDataset = std::make_shared(filePath, initData, - basePath, preprocess); -#else // GLOBEBROWSING_USE_GDAL - auto tileDataset = std::make_shared(filePath, initData, - preprocess); -#endif // GLOBEBROWSING_USE_GDAL - - _asyncTextureDataProvider = std::make_shared(_name, tileDataset); - - if (dictionary.hasKeyAndValue(KeyPreCacheLevel)) { - int preCacheLevel = static_cast(dictionary.value(KeyPreCacheLevel)); - LDEBUG("Precaching '" << filePath << "' with level '" << preCacheLevel << "'"); - for (int level = 0; level <= preCacheLevel; ++level) { - for (int x = 0; x <= level * 2; ++x) { - for (int y = 0; y <= level; ++y) { - _asyncTextureDataProvider->enqueueTileIO({ x, y, level }); - } - } - } - } -} - -CachingTileProvider::CachingTileProvider( - std::shared_ptr tileReader) - : _asyncTextureDataProvider(tileReader) -{ } - -CachingTileProvider::~CachingTileProvider() -{ } - -void CachingTileProvider::update() { - _asyncTextureDataProvider->update(); - initTexturesFromLoadedData(); -} - -void CachingTileProvider::reset() { - _tileCache->clear(); - _asyncTextureDataProvider->reset(); -} - -int CachingTileProvider::maxLevel() { - return _asyncTextureDataProvider->getRawTileDataReader()->maxChunkLevel(); -} - -Tile CachingTileProvider::getTile(const TileIndex& tileIndex) { - if (tileIndex.level > maxLevel()) { - return Tile(nullptr, nullptr, Tile::Status::OutOfRange); - } - - cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; - - Tile tile = _tileCache->get(key); - - if (tile.texture() == nullptr) { - _asyncTextureDataProvider->enqueueTileIO(tileIndex); - } - - return tile; -} - -float CachingTileProvider::noDataValueAsFloat() { - return _asyncTextureDataProvider->noDataValueAsFloat(); -} - -void CachingTileProvider::initTexturesFromLoadedData() { - std::shared_ptr rawTile = _asyncTextureDataProvider->popFinishedRawTile(); - if (rawTile) { - cache::ProviderTileKey key = { rawTile->tileIndex, uniqueIdentifier() }; - ghoul_assert(!_tileCache->exist(key), "Tile must not be existing in cache"); - _tileCache->createTileAndPut(key, rawTile); - } -} - -Tile::Status CachingTileProvider::getTileStatus(const TileIndex& tileIndex) { - auto rawTileDataReader = _asyncTextureDataProvider->getRawTileDataReader(); - if (tileIndex.level > rawTileDataReader->maxChunkLevel()) { - return Tile::Status::OutOfRange; - } - - cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; - - return _tileCache->get(key).status(); -} - -TileDepthTransform CachingTileProvider::depthTransform() { - return _asyncTextureDataProvider->getRawTileDataReader()->getDepthTransform(); -} - -} // namespace tileprovider -} // namespace globebrowsing -} // namespace openspace diff --git a/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp new file mode 100644 index 0000000000..e7343007f0 --- /dev/null +++ b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp @@ -0,0 +1,254 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace { + const char* KeyPerformPreProcessing = "PerformPreProcessing"; + const char* KeyTilePixelSize = "TilePixelSize"; + const char* KeyFilePath = "FilePath"; + const char* KeyBasePath = "BasePath"; + const char* KeyPreCacheLevel = "PreCacheLevel"; +} + +namespace openspace { +namespace globebrowsing { +namespace tileprovider { + +DefaultTileProvider::DefaultTileProvider(const ghoul::Dictionary& dictionary) + : TileProvider(dictionary) + , _filePath("filePath", "File Path", "") + , _tilePixelSize("tilePixelSize", "Tile Pixel Size", 32, 32, 1024) + , _preCacheLevel(0) +{ + _tileCache = OsEng.moduleEngine().module()->tileCache(); + _name = "Name unspecified"; + dictionary.getValue("Name", _name); + std::string _loggerCat = "DefaultTileProvider : " + _name; + + // 1. Get required Keys + std::string filePath; + dictionary.getValue(KeyFilePath, filePath); + //filePath = absPath(filePath); + _filePath.setValue(filePath); + + 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("Default pixel size overridden: " << pixelSize); + tilePixelSize = pixelSize; + } + TileTextureInitData initData(LayerManager::getTileTextureInitData( + _layerGroupID, tilePixelSize)); + _tilePixelSize.setValue(initData.dimensionsWithoutPadding().x); + + _performPreProcessing = + LayerManager::shouldPerformPreProcessingOnLayergroup(_layerGroupID); + if (dictionary.getValue(KeyPerformPreProcessing, _performPreProcessing)) { + LDEBUG("Default PerformPreProcessing overridden: " << _performPreProcessing); + } + + if (dictionary.hasKeyAndValue(KeyPreCacheLevel)) { + _preCacheLevel = static_cast(dictionary.value(KeyPreCacheLevel)); + } + + dictionary.getValue(KeyBasePath, _basePath); + + initAsyncTileDataReader(initData); + + // Properties + addProperty(_filePath); + addProperty(_tilePixelSize); +} + +DefaultTileProvider::DefaultTileProvider( + std::shared_ptr tileReader) + : _asyncTextureDataProvider(tileReader) + , _filePath("filePath", "File Path", "") + , _tilePixelSize("tilePixelSize", "Tile Pixel Size", 32, 32, 1024) +{ } + +DefaultTileProvider::~DefaultTileProvider() +{ } + +void DefaultTileProvider::update() { + if (_asyncTextureDataProvider) { + _asyncTextureDataProvider->update(); + initTexturesFromLoadedData(); + if (_asyncTextureDataProvider->shouldBeDeleted()) { + _asyncTextureDataProvider = nullptr; + TileTextureInitData initData(LayerManager::getTileTextureInitData( + _layerGroupID, _tilePixelSize)); + initAsyncTileDataReader(initData); + } + } +} + +void DefaultTileProvider::reset() { + _tileCache->clear(); + if (_asyncTextureDataProvider) { + _asyncTextureDataProvider->prepairToBeDeleted(); + } + else { + TileTextureInitData initData(LayerManager::getTileTextureInitData( + _layerGroupID, _tilePixelSize)); + initAsyncTileDataReader(initData); + } +} + +int DefaultTileProvider::maxLevel() { + if (_asyncTextureDataProvider) { + return _asyncTextureDataProvider->getRawTileDataReader()->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::getTile(const TileIndex& tileIndex) { + if (_asyncTextureDataProvider) { + if (tileIndex.level > maxLevel()) { + return Tile(nullptr, nullptr, Tile::Status::OutOfRange); + } + + cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; + + Tile tile = _tileCache->get(key); + + if (tile.texture() == nullptr) { + _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 rawTile = _asyncTextureDataProvider->popFinishedRawTile(); + if (rawTile) { + cache::ProviderTileKey key = { rawTile->tileIndex, uniqueIdentifier() }; + ghoul_assert(!_tileCache->exist(key), "Tile must not be existing in cache"); + _tileCache->createTileAndPut(key, rawTile); + } + } +} + +void DefaultTileProvider::initAsyncTileDataReader(TileTextureInitData initData) { + std::string _loggerCat = "DefaultTileProvider : " + _name; + + RawTileDataReader::PerformPreprocessing preprocess = + _performPreProcessing ? RawTileDataReader::PerformPreprocessing::Yes : + RawTileDataReader::PerformPreprocessing::No; + + // Initialize instance variables +#ifdef GLOBEBROWSING_USE_GDAL + auto tileDataset = std::make_shared(_filePath, initData, + _basePath, preprocess); +#else // GLOBEBROWSING_USE_GDAL + auto tileDataset = std::make_shared(_filePath, initData, + preprocess); +#endif // GLOBEBROWSING_USE_GDAL + + _asyncTextureDataProvider = std::make_shared(_name, tileDataset); + + if (_preCacheLevel > -1) { + LDEBUG("Precaching '" << _filePath << "' with level '" << _preCacheLevel << "'"); + for (int level = 0; level <= _preCacheLevel; ++level) { + for (int x = 0; x <= level * 2; ++x) { + for (int y = 0; y <= level; ++y) { + _asyncTextureDataProvider->enqueueTileIO({ x, y, level }); + } + } + } + } +} + +Tile::Status DefaultTileProvider::getTileStatus(const TileIndex& tileIndex) { + if (_asyncTextureDataProvider) { + auto rawTileDataReader = _asyncTextureDataProvider->getRawTileDataReader(); + if (tileIndex.level > rawTileDataReader->maxChunkLevel()) { + return Tile::Status::OutOfRange; + } + + cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; + + return _tileCache->get(key).status(); + } + else { + return Tile::Status::Unavailable; + } +} + +TileDepthTransform DefaultTileProvider::depthTransform() { + if (_asyncTextureDataProvider) { + return _asyncTextureDataProvider->getRawTileDataReader()->getDepthTransform(); + } + else { + return { 1.0f, 0.0f }; + } +} + +} // namespace tileprovider +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.h b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.h similarity index 86% rename from modules/globebrowsing/tile/tileprovider/cachingtileprovider.h rename to modules/globebrowsing/tile/tileprovider/defaulttileprovider.h index 6fd5c0fa03..bf2928dd37 100644 --- a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.h +++ b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.h @@ -28,6 +28,9 @@ #include #include +#include +#include + namespace openspace { class PixelBuffer; @@ -43,12 +46,12 @@ namespace tileprovider { * Provides tiles loaded by AsyncTileDataProvider and * caches them in memory using LRU caching */ -class CachingTileProvider : public TileProvider { +class DefaultTileProvider : public TileProvider { public: - CachingTileProvider(const ghoul::Dictionary& dictionary); - CachingTileProvider(std::shared_ptr tileReader); + DefaultTileProvider(const ghoul::Dictionary& dictionary); + DefaultTileProvider(std::shared_ptr tileReader); - virtual ~CachingTileProvider() override; + virtual ~DefaultTileProvider() override; /** * \returns a Tile with status OK iff it exists in in-memory @@ -73,9 +76,18 @@ private: */ void initTexturesFromLoadedData(); + void initAsyncTileDataReader(TileTextureInitData initData); + std::shared_ptr _asyncTextureDataProvider; cache::MemoryAwareTileCache* _tileCache; + + properties::StringProperty _filePath; + properties::IntProperty _tilePixelSize; + layergroupid::GroupID _layerGroupID; + std::string _basePath; + int _preCacheLevel; + bool _performPreProcessing; }; } // namespace tileprovider diff --git a/modules/globebrowsing/tile/tileprovider/presentationslideprovider.cpp b/modules/globebrowsing/tile/tileprovider/presentationslideprovider.cpp index 8c16349993..0cca078164 100644 --- a/modules/globebrowsing/tile/tileprovider/presentationslideprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/presentationslideprovider.cpp @@ -22,6 +22,8 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#if 0 + #include #include #include @@ -112,3 +114,5 @@ TileProvider* PresentationSlideProvider::slideProvider() { } // namespace tileprovider } // namespace globebrowsing } // namespace openspace + +#endif diff --git a/modules/globebrowsing/tile/tileprovider/projectiontileprovider.cpp b/modules/globebrowsing/tile/tileprovider/projectiontileprovider.cpp deleted file mode 100644 index 944c4594ed..0000000000 --- a/modules/globebrowsing/tile/tileprovider/projectiontileprovider.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -namespace { - const char* _loggerCat = "ProjectionTileProvider"; - - const char* keyGeometry = "Geometry"; - const char* keyProjection = "Projection"; - const char* keyMeridianShift = "Textures.MeridianShift"; - const char* keyColorTexture = "Textures.Color"; - const char* keyHeightTexture = "Textures.Height"; - - const char* keyRadius = "Geometry.Radius"; - const char* keyShading = "PerformShading"; - const char* _mainFrame = "GALACTIC"; -} - -namespace openspace { -namespace globebrowsing { -namespace tileprovider { - -/* -documentation::Documentation ProjectionTileProvider::Documentation() { - using namespace openspace::documentation; - return { - "Renderable Planet Projection", - "newhorizons_renderable_planetprojection", - { - { - "Type", - new StringEqualVerifier("RenderablePlanetProjection"), - "", - Optional::No - }, - { - keyGeometry, - new ReferencingVerifier("space_geometry_planet"), - "The geometry that is used for rendering this planet.", - Optional::No - }, - { - keyProjection, - new ReferencingVerifier("newhorizons_projectioncomponent"), - "Contains information about projecting onto this planet.", - Optional::No - }, - { - keyMeridianShift, - new BoolVerifier, - "Determines whether the meridian of the planet should be shifted by 180 " - "degrees. The default value is 'false'", - Optional::Yes - }, - { - keyColorTexture, - new StringVerifier, - "The path to the base color texture that is used on the planet prior to " - "any image projection. The path can use tokens of the form '${...}' or " - "be specified relative to the directory of the mod file.", - Optional::No - }, - { - keyHeightTexture, - new StringVerifier, - "The path to the height map texture that is used on the planet. The path " - "can use tokens of the form '${...}' or be specified relative to the " - "directory of the mod file. If no height map is specified the planet " - "does not use a height field.", - Optional::Yes - } - } - }; -} -*/ - -ProjectionTileProvider::ProjectionTileProvider(const ghoul::Dictionary& dictionary) - : _fboProgramObject(nullptr) - , _capture(false) - , _defaultTile(Tile::TileUnavailable) -{ - - ghoul::Dictionary geometryDictionary; - bool success = dictionary.getValue( - keyGeometry, geometryDictionary); - if (success) { - geometryDictionary.setValue(SceneGraphNode::KeyName, "TestGeometry"); - using planetgeometry::PlanetGeometry; - _geometry = std::unique_ptr( - PlanetGeometry::createFromDictionary(geometryDictionary) - ); - } - - _projectionComponent.initialize(dictionary.value(keyProjection)); - - - addPropertySubOwner(_geometry.get()); - addPropertySubOwner(_projectionComponent); -} - -ProjectionTileProvider::~ProjectionTileProvider(){ - -} - -bool ProjectionTileProvider::initialize() { - bool completeSuccess = true; - completeSuccess &= TileProvider::initialize(); - - _fboProgramObject = ghoul::opengl::ProgramObject::Build("fboPassProgram", - "${MODULE_NEWHORIZONS}/shaders/renderablePlanetProjection_vs.glsl", - "${MODULE_NEWHORIZONS}/shaders/renderablePlanetProjection_fs.glsl" - ); - - completeSuccess &= _projectionComponent.initializeGL(); - completeSuccess &= _geometry->initialize(nullptr); - - if (completeSuccess) { - //completeSuccess &= auxiliaryRendertarget(); - // SCREEN-QUAD - const GLfloat size = 1.f; - const GLfloat w = 1.f; - const GLfloat vertex_data[] = { - -size, -size, 0.f, w, 0.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, - -size, size, 0.f, w, 0.f, 1.f, - -size, -size, 0.f, w, 0.f, 0.f, - size, -size, 0.f, w, 1.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, - }; - - glGenVertexArrays(1, &_quad); - glBindVertexArray(_quad); - glGenBuffers(1, &_vertexPositionBuffer); - glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(0)); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(sizeof(GLfloat) * 4)); - - glBindVertexArray(0); - } - - return completeSuccess; -} - -bool ProjectionTileProvider::deinitialize() { - _projectionComponent.deinitialize(); - _geometry = nullptr; - - glDeleteVertexArrays(1, &_quad); - glDeleteBuffers(1, &_vertexPositionBuffer); - - _fboProgramObject = nullptr; - - return true; -} - -void ProjectionTileProvider::update() { - // Update - if (_fboProgramObject->isDirty()) { - _fboProgramObject->rebuildFromFile(); - } - - _projectionComponent.update(); - - _time = Time::ref().j2000Seconds(); - _capture = false; - - if (openspace::ImageSequencer::ref().isReady()){ - openspace::ImageSequencer::ref().updateSequencer(_time); - if (_projectionComponent.doesPerformProjection()) { - _capture = openspace::ImageSequencer::ref().getImagePaths( - _imageTimes, - _projectionComponent.projecteeId(), - _projectionComponent.instrumentId() - ); - } - } - - _stateMatrix = glm::dmat3(1.0); - - - - - - - - - - - - - - - // Projection - - if (_projectionComponent.needsClearProjection()) - _projectionComponent.clearAllProjections(); - - _camScaling = glm::vec2(1.0);// data.camera.scaling(); - _up = glm::vec3(0,1,0);// data.camera.lookUpVectorCameraSpace(); - - if (_capture && _projectionComponent.doesPerformProjection()) { - for (const Image& img : _imageTimes) { - attitudeParameters(img.timeRange.start); - imageProjectGPU(_projectionComponent.loadProjectionTexture(img.path)); - } - _capture = false; - } - attitudeParameters(_time); - _imageTimes.clear(); - -} - -void ProjectionTileProvider::reset() { -} - -int ProjectionTileProvider::maxLevel() { - return 3; -} - -Tile ProjectionTileProvider::getTile(const TileIndex& tileIndex) { - _projectionComponent.projectionTexture(); -} - -float ProjectionTileProvider::noDataValueAsFloat() { - -} - -Tile ProjectionTileProvider::getDefaultTile() { - -} - -Tile::Status ProjectionTileProvider::getTileStatus(const TileIndex& tileIndex) { - return Tile::Status::OK; -} - -TileDepthTransform ProjectionTileProvider::depthTransform() { - -} - -void ProjectionTileProvider::attitudeParameters(double time) { - // precomputations for shader - _instrumentMatrix = SpiceManager::ref().positionTransformMatrix( - _projectionComponent.instrumentId(), _mainFrame, time - ); - - _transform = glm::mat4(1); - //90 deg rotation w.r.t spice req. - glm::mat4 rot = glm::rotate( - _transform, - static_cast(M_PI_2), - glm::vec3(1, 0, 0) - ); - glm::mat4 roty = glm::rotate( - _transform, - static_cast(M_PI_2), - glm::vec3(0, -1, 0) - ); - - _transform = glm::mat4(_stateMatrix); - - glm::dvec3 bs; - try { - SpiceManager::FieldOfViewResult res = SpiceManager::ref().fieldOfView(_projectionComponent.instrumentId()); - bs = std::move(res.boresightVector); - } - catch (const SpiceManager::SpiceException& e) { - LERRORC(e.component, e.what()); - return; - } - - double lightTime; - glm::dvec3 p = SpiceManager::ref().targetPosition( - _projectionComponent.projectorId(), - _projectionComponent.projecteeId(), - _mainFrame, - _projectionComponent.aberration(), - time, - lightTime - ); - psc position = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); - - //change to KM and add psc camera scaling. - position[3] += (3 + _camScaling[1]); - //position[3] += 3; - glm::vec3 cpos = position.vec3(); - - float distance = glm::length(cpos); - float radius = 1185000.0f; - - _projectorMatrix = _projectionComponent.computeProjectorMatrix( - cpos, - bs, - _up, - _instrumentMatrix, - _projectionComponent.fieldOfViewY(), - _projectionComponent.aspectRatio(), - distance - radius, - distance + radius, - _boresight - ); -} - -void ProjectionTileProvider::imageProjectGPU( - std::shared_ptr projectionTexture) -{ - _projectionComponent.imageProjectBegin(); - - _fboProgramObject->activate(); - - ghoul::opengl::TextureUnit unitFbo; - unitFbo.activate(); - projectionTexture->bind(); - _fboProgramObject->setUniform("projectionTexture", unitFbo); - - _fboProgramObject->setUniform("ProjectorMatrix", _projectorMatrix); - _fboProgramObject->setUniform("ModelTransform" , _transform); - _fboProgramObject->setUniform("_scaling" , _camScaling); - _fboProgramObject->setUniform("boresight" , _boresight); - - if (_geometry->hasProperty("radius")){ - ghoul::any r = _geometry->property("radius")->get(); - if (glm::vec4* radius = ghoul::any_cast(&r)){ - _fboProgramObject->setUniform("_radius", radius); - } - }else{ - LERROR("Geometry object needs to provide radius"); - } - if (_geometry->hasProperty("segments")){ - ghoul::any s = _geometry->property("segments")->get(); - if (int* segments = ghoul::any_cast(&s)){ - _fboProgramObject->setUniform("_segments", segments[0]); - } - }else{ - LERROR("Geometry object needs to provide segment count"); - } - - glBindVertexArray(_quad); - glDrawArrays(GL_TRIANGLES, 0, 6); - _fboProgramObject->deactivate(); - - _projectionComponent.imageProjectEnd(); -} - - -} // namespace tileprovider -} // namespace globebrowsing -} // namespace openspace diff --git a/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp b/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp index 413784a698..38efce4ba6 100644 --- a/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp @@ -38,18 +38,21 @@ namespace tileprovider { SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) : _tile(nullptr, nullptr, Tile::Status::Unavailable) + , _filePath("filePath", "File Path", "") { // Required input - if (!dictionary.getValue(KeyFilePath, _imagePath)) { - throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'"); - } + std::string filePath; + dictionary.getValue(KeyFilePath, filePath); + _filePath.setValue(filePath); + + addProperty(_filePath); reset(); } SingleImageProvider::SingleImageProvider(const std::string& imagePath) - : _imagePath(imagePath) - , _tile(nullptr, nullptr, Tile::Status::Unavailable) + : _tile(nullptr, nullptr, Tile::Status::Unavailable) + , _filePath("filePath", "File Path", imagePath) { reset(); } @@ -74,12 +77,15 @@ void SingleImageProvider::update() { } void SingleImageProvider::reset() { - _tileTexture = ghoul::io::TextureReader::ref().loadTexture(_imagePath); + 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 '") - + _imagePath + "'"); + + _filePath.value() + "'"); } _tileTexture->uploadTexture(); diff --git a/modules/globebrowsing/tile/tileprovider/singleimageprovider.h b/modules/globebrowsing/tile/tileprovider/singleimageprovider.h index e4f0ac7f34..d15aaa77f7 100644 --- a/modules/globebrowsing/tile/tileprovider/singleimageprovider.h +++ b/modules/globebrowsing/tile/tileprovider/singleimageprovider.h @@ -27,6 +27,8 @@ #include +#include + namespace openspace { namespace globebrowsing { namespace tileprovider { @@ -46,8 +48,9 @@ public: private: std::unique_ptr _tileTexture; - std::string _imagePath; Tile _tile; + + properties::StringProperty _filePath; }; } // namespace tileprovider diff --git a/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp b/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp index 042d06c9cb..fb12db848a 100644 --- a/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp @@ -47,7 +47,7 @@ namespace { } SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary) - : TextTileProvider(LayerManager::getTileTextureInitData(layergroupid::ID::ColorLayers)) + : TextTileProvider(LayerManager::getTileTextureInitData(layergroupid::GroupID::ColorLayers)) , _backgroundTile(Tile::TileUnavailable) { @@ -55,9 +55,7 @@ SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& di _font = OsEng.fontManager().font("Mono", _fontSize); glm::dvec3 radii(1,1,1); - if (!dictionary.getValue(KeyRadii, radii)) { - throw std::runtime_error("Must define key '" + std::string(KeyRadii) + "'"); - } + dictionary.getValue(KeyRadii, radii); _ellipsoid = Ellipsoid(radii); } diff --git a/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp b/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp index e7a622e5ac..1c3666e0eb 100644 --- a/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp @@ -26,7 +26,7 @@ #include -#include +#include #include #include @@ -57,47 +57,73 @@ const char* TemporalTileProvider::TemporalXMLTags::TIME_RESOLUTION = const char* TemporalTileProvider::TemporalXMLTags::TIME_FORMAT = "OpenSpaceTimeIdFormat"; TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary) - : _initDict(dictionary) + : _initDict(dictionary) + , _filePath("filePath", "File Path", "") + , _successfulInitialization(false) { - if (!dictionary.getValue(KeyFilePath, _datasetFile)) { - throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'"); + std::string filePath; + dictionary.getValue(KeyFilePath, filePath); + try { + filePath = absPath(filePath); + } + catch (const std::runtime_error& e) { + // File path was not a path to a file but a GDAL config or empty + } + + _filePath.setValue(filePath); + 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); + std::vector