diff --git a/data/assets/base.asset b/data/assets/base.asset index 60d4e207e7..e89a6a74c9 100644 --- a/data/assets/base.asset +++ b/data/assets/base.asset @@ -7,6 +7,7 @@ asset.require('./base_blank') -- Specifying which other assets should be loaded in this scene asset.require('scene/solarsystem/sun/sun') asset.require('scene/solarsystem/sun/glare') +asset.require('scene/solarsystem/sun/habitablezone') asset.require('scene/solarsystem/sun/default_layers') asset.require('scene/solarsystem/planets/planets') asset.require('scene/solarsystem/planets/default_layers') @@ -19,9 +20,11 @@ asset.require('scene/milkyway/constellations/constellation_keybinds') asset.require('scene/milkyway/objects/orionnebula/orionnebula') asset.require('util/launcher_images') -local assetHelper = asset.require('util/asset_helper') +-- For exoplanet system visualizations asset.require('scene/milkyway/exoplanets/exoplanets_data') asset.require('scene/milkyway/exoplanets/exoplanets_textures') + +local assetHelper = asset.require('util/asset_helper') asset.require('scene/digitaluniverse/2dF') asset.require('scene/digitaluniverse/2mass') asset.require('scene/digitaluniverse/6dF') diff --git a/data/assets/examples/discs.asset b/data/assets/examples/discs.asset new file mode 100644 index 0000000000..0b15b2115b --- /dev/null +++ b/data/assets/examples/discs.asset @@ -0,0 +1,25 @@ +local assetHelper = asset.require('util/asset_helper') + +local color = {0.0, 1.0, 1.0} + +-- @TODO (emmbr 2020-02-03) Potential threading issue later on? This will run on the main thread +local singeColorTexturePath = openspace.createSingeColorImage("example_ring_color", color) + +local BasicDisc = { + Identifier = "BasicDisc", + Parent = "Root", + Renderable = { + Type = "RenderableDisc", + Texture = singeColorTexturePath, + Size = 1e10, + Width = 0.5 + }, + GUI = { + Name = "Basic Disc", + Path = "/Examples/Discs" + } +} + +assetHelper.registerSceneGraphNodesAndExport(asset, { + BasicDisc +}) diff --git a/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset b/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset index b75b5aa1a5..0d2ab171e8 100644 --- a/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset +++ b/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset @@ -5,3 +5,14 @@ local DataPath = asset.syncedResource({ Version = 2 }) asset.export("DataPath", DataPath) + +asset.meta = { + Name = "Exoplanet Data", + Version = "2.0", + Description = [[ The data that is used for the exoplanet systems. The data has been + derived from the 'Planetary Systems Composite Data' dataset from the NASA Exoplanet + Archive]], + Author = "OpenSpace Team", + URL = "https://exoplanetarchive.ipac.caltech.edu/docs/data.html", + License = "MIT license", +} diff --git a/data/assets/scene/milkyway/exoplanets/exoplanets_textures.asset b/data/assets/scene/milkyway/exoplanets/exoplanets_textures.asset index 287b29d61e..9efd63b65c 100644 --- a/data/assets/scene/milkyway/exoplanets/exoplanets_textures.asset +++ b/data/assets/scene/milkyway/exoplanets/exoplanets_textures.asset @@ -1,7 +1,19 @@ +asset.require('./../habitable_zones/habitable_zone_textures') + local TexturesPath = asset.syncedResource({ Name = "Exoplanet Textures", Type = "HttpSynchronization", Identifier = "exoplanets_textures", - Version = 1 + Version = 2 }) asset.export("TexturesPath", TexturesPath) + +asset.meta = { + Name = "Exoplanet Textures", + Version = "2.0", + Description = [[ Adds all textures that are required for the exoplanet system + visualizations]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license", +} diff --git a/data/assets/scene/milkyway/habitable_zones/habitable_zone_textures.asset b/data/assets/scene/milkyway/habitable_zones/habitable_zone_textures.asset new file mode 100644 index 0000000000..0687c70693 --- /dev/null +++ b/data/assets/scene/milkyway/habitable_zones/habitable_zone_textures.asset @@ -0,0 +1,17 @@ +local TexturesPath = asset.syncedResource({ + Name = "Habitable Zone Textures", + Type = "HttpSynchronization", + Identifier = "habitable_zone_textures", + Version = 1 +}) +asset.export("TexturesPath", TexturesPath) + +asset.meta = { + Name = "Habitable Zone Textures", + Version = "1.0", + Description = [[ Default textures that can be used for the habitable zone + rendering]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license", +} diff --git a/data/assets/scene/solarsystem/sun/habitablezone.asset b/data/assets/scene/solarsystem/sun/habitablezone.asset new file mode 100644 index 0000000000..9727e641fa --- /dev/null +++ b/data/assets/scene/solarsystem/sun/habitablezone.asset @@ -0,0 +1,34 @@ +local assetHelper = asset.require("util/asset_helper") +local transforms = asset.require("./transforms") +local textures = asset.require('scene/milkyway/habitable_zones/habitable_zone_textures').TexturesPath + +local HabitableZone = { + Identifier = "SunHabitableZone", + Parent = transforms.SunECLIPJ2000.Identifier, + Renderable = { + Type = "RenderableHabitableZone", + Enabled = false, + Texture = textures .. "/hot_to_cold_faded.png", + EffectiveTemperature = 5780, -- Kelvin + Luminosity = 1, -- solar + Opacity = 0.1 + }, + GUI = { + Name = "Sun Habitable Zone", + Path = "/Solar System/Sun", + Description = "Habitable zone for the sun in our solar system." + } +} + +assetHelper.registerSceneGraphNodesAndExport(asset, { HabitableZone }) + +asset.meta = { + Name = "Sun Habitable Zone", + Version = "1.0", + Description = [[ The habitable zone around our sun, computed using formula and + coefficients by Kopparapu et al. (2015) https://arxiv.org/abs/1404.5292]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license", + Identifiers = {"SunHabitableZone"} +} diff --git a/include/openspace/rendering/texturecomponent.h b/include/openspace/rendering/texturecomponent.h new file mode 100644 index 0000000000..5c4d905a7c --- /dev/null +++ b/include/openspace/rendering/texturecomponent.h @@ -0,0 +1,72 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * 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___TEXTURECOMPONENT___H__ +#define __OPENSPACE_CORE___TEXTURECOMPONENT___H__ + +#include + +namespace ghoul::filesystem { class File; } +namespace ghoul::opengl {class Texture; } + +namespace openspace { + +class TextureComponent { +public: + using Texture = ghoul::opengl::Texture; + + const Texture* texture() const; + Texture* texture(); + + void setFilterMode(Texture::FilterMode filterMode); + void setWrapping(Texture::WrappingMode wrapping); + void setShouldWatchFileForChanges(bool value); + void setShouldPurgeFromRAM(bool value); + + void bind(); + void uploadToGpu(); + + // Loads a texture from a file on disk + void loadFromFile(const std::string& path); + + // Function to call in a renderable's update function to make sure + // the texture is kept up to date + void update(); + +private: + std::unique_ptr _textureFile; + std::unique_ptr _texture; + + Texture::FilterMode _filterMode = Texture::FilterMode::LinearMipMap; + Texture::WrappingMode _wrappingMode = Texture::WrappingMode::Repeat; + bool _shouldWatchFile = true; + bool _shouldPurgeFromRAM = true; + + bool _fileIsDirty = false; + bool _textureIsDirty = false; +}; + +} // namespace openspace + +#endif // __OPENSPACE_CORE___TEXTURECOMPONENT___H__ diff --git a/include/openspace/util/planegeometry.h b/include/openspace/util/planegeometry.h new file mode 100644 index 0000000000..2b29302c79 --- /dev/null +++ b/include/openspace/util/planegeometry.h @@ -0,0 +1,57 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * 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___PLANEGEOMETRY___H__ +#define __OPENSPACE_CORE___PLANEGEOMETRY___H__ + +#include +#include + +namespace openspace { + +class PlaneGeometry { +public: + PlaneGeometry(glm::vec2 size); + PlaneGeometry(float size); + + ~PlaneGeometry(); + + void initialize(); + void deinitialize(); + void render(); + + void updateSize(const glm::vec2& size); + void updateSize(const float size); + +private: + void updateGeometry(); + + GLuint _vaoId = 0; + GLuint _vBufferId = 0; + glm::vec2 _size = glm::vec2(0.f); +}; + +} // namespace openspace + +#endif // __OPENSPACE_CORE___PLANEGEOMETRY___H__ diff --git a/modules/base/CMakeLists.txt b/modules/base/CMakeLists.txt index 55519e8c01..521cf3f950 100644 --- a/modules/base/CMakeLists.txt +++ b/modules/base/CMakeLists.txt @@ -45,6 +45,7 @@ set(HEADER_FILES rendering/grids/renderableradialgrid.h rendering/grids/renderablesphericalgrid.h rendering/renderablecartesianaxes.h + rendering/renderabledisc.h rendering/renderablelabels.h rendering/renderablemodel.h rendering/renderablenodeline.h @@ -73,7 +74,6 @@ set(HEADER_FILES translation/luatranslation.h translation/statictranslation.h translation/timelinetranslation.h - ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -98,6 +98,7 @@ set(SOURCE_FILES rendering/grids/renderableradialgrid.cpp rendering/grids/renderablesphericalgrid.cpp rendering/renderablecartesianaxes.cpp + rendering/renderabledisc.cpp rendering/renderablelabels.cpp rendering/renderablemodel.cpp rendering/renderablenodeline.cpp @@ -132,6 +133,8 @@ source_group("Source Files" FILES ${SOURCE_FILES}) set(SHADER_FILES shaders/axes_fs.glsl shaders/axes_vs.glsl + shaders/disc_fs.glsl + shaders/disc_vs.glsl shaders/grid_vs.glsl shaders/grid_fs.glsl shaders/imageplane_fs.glsl diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp index 6a9ebdce24..09ef673631 100644 --- a/modules/base/basemodule.cpp +++ b/modules/base/basemodule.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -129,6 +130,7 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) { fRenderable->registerClass("RenderableBoxGrid"); fRenderable->registerClass("RenderableCartesianAxes"); + fRenderable->registerClass("RenderableDisc"); fRenderable->registerClass("RenderableGrid"); fRenderable->registerClass("RenderableLabels"); fRenderable->registerClass("RenderableModel"); @@ -206,6 +208,7 @@ std::vector BaseModule::documentations() const { RenderableNodeLine::Documentation(), RenderablePlane::Documentation(), RenderableRadialGrid::Documentation(), + RenderableDisc::Documentation(), RenderableSphere::Documentation(), RenderableSphericalGrid::Documentation(), RenderableTrailOrbit::Documentation(), diff --git a/modules/base/rendering/renderabledisc.cpp b/modules/base/rendering/renderabledisc.cpp new file mode 100644 index 0000000000..c3de8be2b1 --- /dev/null +++ b/modules/base/rendering/renderabledisc.cpp @@ -0,0 +1,230 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + constexpr const char _loggerCat[] = "RenderableDisc"; + + constexpr const std::array UniformNames = { + "modelViewProjectionTransform", "opacity", "width", "colorTexture" + }; + + constexpr openspace::properties::Property::PropertyInfo TextureInfo = { + "Texture", + "Texture", + "This value is the path to a texture on disk that contains a one-dimensional " + "texture to be used for the color." + }; + + constexpr openspace::properties::Property::PropertyInfo SizeInfo = { + "Size", + "Size", + "This value specifies the outer radius of the disc in meter." + }; + + constexpr openspace::properties::Property::PropertyInfo WidthInfo = { + "Width", + "Width", + "This value is used to set the width of the disc. The actual width is set " + "based on the given size and this value should be set between 0 and 1. A value " + "of 1 results in a full circle and 0.5 a disc with an inner radius of 0.5*size." + }; +} // namespace + +namespace openspace { + +documentation::Documentation RenderableDisc::Documentation() { + using namespace documentation; + return { + "Renderable Disc", + "renderable_disc", + { + { + TextureInfo.identifier, + new StringVerifier, + Optional::No, + TextureInfo.description + }, + { + SizeInfo.identifier, + new DoubleVerifier, + Optional::Yes, + SizeInfo.description + }, + { + WidthInfo.identifier, + new DoubleVerifier, + Optional::Yes, + WidthInfo.description + } + } + }; +} + +RenderableDisc::RenderableDisc(const ghoul::Dictionary& dictionary) + : Renderable(dictionary) + , _texturePath(TextureInfo) + , _size(SizeInfo, 1.f, 0.f, 1e13f) + , _width(WidthInfo, 0.5f, 0.f, 1.f) +{ + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "RenderableDisc" + ); + + _texturePath = absPath(dictionary.value(TextureInfo.identifier)); + _texturePath.onChange([&]() { _texture->loadFromFile(_texturePath); }); + addProperty(_texturePath); + + if (dictionary.hasKey(SizeInfo.identifier)) { + _size = static_cast(dictionary.value(SizeInfo.identifier)); + } + setBoundingSphere(_size); + _size.onChange([&]() { _planeIsDirty = true; }); + addProperty(_size); + + if (dictionary.hasKey(WidthInfo.identifier)) { + _width = static_cast(dictionary.value(WidthInfo.identifier)); + } + addProperty(_width); + addProperty(_opacity); + + setRenderBin(Renderable::RenderBin::PostDeferredTransparent); +} + +bool RenderableDisc::isReady() const { + return _shader && _texture && _plane; +} + +void RenderableDisc::initialize() { + _texture = std::make_unique(); + _texture->setFilterMode(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + _texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge); + _texture->setShouldWatchFileForChanges(true); + + _plane = std::make_unique(planeSize()); +} + +void RenderableDisc::initializeGL() { + initializeShader(); + + _texture->loadFromFile(_texturePath); + _texture->uploadToGpu(); + + _plane->initialize(); +} + +void RenderableDisc::deinitializeGL() { + _plane->deinitialize(); + _plane = nullptr; + _texture = nullptr; + + global::renderEngine->removeRenderProgram(_shader.get()); + _shader = nullptr; +} + +void RenderableDisc::render(const RenderData& data, RendererTasks&) { + _shader->activate(); + + glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * + glm::dmat4(data.modelTransform.rotation) * + glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); + + glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; + + _shader->setUniform( + _uniformCache.modelViewProjection, + data.camera.projectionMatrix() * glm::mat4(modelViewTransform) + ); + _shader->setUniform(_uniformCache.width, _width); + + _shader->setUniform(_uniformCache.opacity, _opacity); + + ghoul::opengl::TextureUnit unit; + unit.activate(); + _texture->bind(); + _shader->setUniform(_uniformCache.texture, unit); + + glEnablei(GL_BLEND, 0); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(false); + glDisable(GL_CULL_FACE); + + _plane->render(); + + _shader->deactivate(); + + // Restores GL State + global::renderEngine->openglStateCache().resetBlendState(); + global::renderEngine->openglStateCache().resetDepthState(); + global::renderEngine->openglStateCache().resetPolygonAndClippingState(); +} + +void RenderableDisc::update(const UpdateData&) { + if (_shader->isDirty()) { + _shader->rebuildFromFile(); + updateUniformLocations(); + } + + if (_planeIsDirty) { + _plane->updateSize(planeSize()); + _planeIsDirty = false; + } + + _texture->update(); +} + +void RenderableDisc::initializeShader() { + _shader = global::renderEngine->buildRenderProgram( + "DiscProgram", + absPath("${MODULE_BASE}/shaders/disc_vs.glsl"), + absPath("${MODULE_BASE}/shaders/disc_fs.glsl") + ); + updateUniformLocations(); +} + +void RenderableDisc::updateUniformLocations() { + ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); +} + +float RenderableDisc::planeSize() const { + return _size; +} + +} // namespace openspace diff --git a/modules/base/rendering/renderabledisc.h b/modules/base/rendering/renderabledisc.h new file mode 100644 index 0000000000..ccd5d52288 --- /dev/null +++ b/modules/base/rendering/renderabledisc.h @@ -0,0 +1,81 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_BASE___RENDERABLEDISC___H__ +#define __OPENSPACE_MODULE_BASE___RENDERABLEDISC___H__ + +#include +#include +#include +#include +#include +#include +#include + +namespace ghoul::filesystem { class File; } +namespace ghoul::opengl { class ProgramObject; } + +namespace openspace { + +namespace documentation { struct Documentation; } + +class RenderableDisc : public Renderable { +public: + RenderableDisc(const ghoul::Dictionary& dictionary); + + void initialize() override; + void initializeGL() override; + void deinitializeGL() override; + + bool isReady() const override; + + void render(const RenderData& data, RendererTasks& rendererTask) override; + void update(const UpdateData& data) override; + + static documentation::Documentation Documentation(); + +protected: + virtual void initializeShader(); + virtual void updateUniformLocations(); + + virtual float planeSize() const; + + properties::StringProperty _texturePath; + properties::FloatProperty _size; + properties::FloatProperty _width; + + std::unique_ptr _shader; + + std::unique_ptr _plane; + std::unique_ptr _texture; + +private: + UniformCache(modelViewProjection, opacity, width, texture) _uniformCache; + + bool _planeIsDirty = false; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_BASE___RENDERABLEDISC___H__ diff --git a/modules/base/shaders/disc_fs.glsl b/modules/base/shaders/disc_fs.glsl new file mode 100644 index 0000000000..839d6464f5 --- /dev/null +++ b/modules/base/shaders/disc_fs.glsl @@ -0,0 +1,58 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "fragment.glsl" + +in vec2 vs_st; +in float vs_screenSpaceDepth; + +uniform sampler1D colorTexture; +uniform float width; +uniform float opacity; + +Fragment getFragment() { + // The length of the texture coordinates vector is our distance from the center + float radius = length(vs_st); + + // We only want to consider ring-like objects so we need to discard everything else + if (radius > 1.0) { + discard; + } + + // Remapping the texture coordinates + // Radius \in [0,1], + float inner = 1.0 - width; + float texCoord = (radius - inner) / (1.0 - inner); + if (texCoord < 0.0 || texCoord > 1.0) { + discard; + } + + vec4 diffuse = texture(colorTexture, texCoord); + diffuse.a *= opacity; + + Fragment frag; + frag.color = diffuse; + frag.depth = vs_screenSpaceDepth; + return frag; +} diff --git a/modules/base/shaders/disc_vs.glsl b/modules/base/shaders/disc_vs.glsl new file mode 100644 index 0000000000..d5796d62d9 --- /dev/null +++ b/modules/base/shaders/disc_vs.glsl @@ -0,0 +1,47 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +#include "PowerScaling/powerScaling_vs.hglsl" + +layout(location = 0) in vec2 in_position; +layout(location = 1) in vec2 in_st; + +out vec2 vs_st; +out float vs_screenSpaceDepth; + +uniform mat4 modelViewProjectionTransform; + +void main() { + vec4 position = vec4(in_position.xy, 0.0, 1.0); + vec4 positionScreenSpace = z_normalization(modelViewProjectionTransform * position); + + // Moving the origin to the center + vs_st = (in_st - vec2(0.5)) * 2.0; + + vs_screenSpaceDepth = positionScreenSpace.w; + + gl_Position = positionScreenSpace; +} diff --git a/modules/exoplanets/exoplanetshelper.cpp b/modules/exoplanets/exoplanetshelper.cpp index d0becf0cc9..17bf9b5fe8 100644 --- a/modules/exoplanets/exoplanetshelper.cpp +++ b/modules/exoplanets/exoplanetshelper.cpp @@ -136,50 +136,6 @@ glm::dmat3 computeSystemRotation(glm::dvec3 starPosition) { ); } -glm::vec2 computeHabitableZone(float teff, float luminosity) { - // Kopparapu's formula only considers stars with teff in range [2600, 7200] K. - // However, we want to use the formula for more stars, so add some flexibility to - // the teff boundaries - if (teff > 8000.f || teff < 2000.f) { - // For the other stars, use a method by Tom E. Morris: - // https://www.planetarybiology.com/calculating_habitable_zone.html - float inner = std::sqrt(luminosity / 1.1f); - float outer = std::sqrt(luminosity / 0.53f); - return glm::vec2(inner, outer); - } - - struct Coefficients { - float seffSun; - float a; - float b; - float c; - float d; - }; - - // Coefficients for planets of 1 Earth mass. Received from: - // https://depts.washington.edu/naivpl/sites/default/files/HZ_coefficients.dat - constexpr const Coefficients coefficients[] = { - // Inner boundary - Runaway greenhouse - {1.10700E+00f, 1.33200E-04f, 1.58000E-08f, -8.30800E-12f, -1.93100E-15f}, - // Outer boundary - Maximum greenhouse - {3.56000E-01f, 6.17100E-05f, 1.69800E-09f, -3.19800E-12f, -5.57500E-16f} - }; - - const float tstar = teff - 5780.f; - const float tstar2 = tstar * tstar; - - glm::vec2 distances; - for (int i = 0; i < 2; ++i) { - const Coefficients& coeffs = coefficients[i]; - float seff = coeffs.seffSun + (coeffs.a * tstar) + (coeffs.b * tstar2) + - (coeffs.c * tstar * tstar2) + (coeffs.d * tstar2 * tstar2); - - distances[i] = std::pow(luminosity / seff, 0.5f); - } - - return distances; -} - std::string createIdentifier(std::string name) { std::replace(name.begin(), name.end(), ' ', '_'); std::replace(name.begin(), name.end(), '.', '-'); diff --git a/modules/exoplanets/exoplanetshelper.h b/modules/exoplanets/exoplanetshelper.h index 43bf96e66a..527bdf4b01 100644 --- a/modules/exoplanets/exoplanetshelper.h +++ b/modules/exoplanets/exoplanetshelper.h @@ -108,17 +108,6 @@ glm::dmat4 computeOrbitPlaneRotationMatrix(float i, float bigom = 180.f, // so that x is pointing from star to the sun. glm::dmat3 computeSystemRotation(glm::dvec3 starPosition); -/** - * Compute the inner and outer boundary of the habitable zone of a star, accordring to - * formula and coefficients by Kopparapu et al. (2015) https://arxiv.org/abs/1404.5292 - * - * \param teff The effective temperature of the star, in Kelvin - * \param luminosity The luminosity of the star, in solar luminosities - * \return A vec2 with the lower and upper boundary in atronomical units, if a habitable - zone could be computed. Otherwise an std::nullopt - */ -glm::vec2 computeHabitableZone(float teff, float luminosity); - // Create an identifier without whitespaces std::string createIdentifier(std::string name); diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl index bd12c170e1..a92408f154 100644 --- a/modules/exoplanets/exoplanetsmodule_lua.inl +++ b/modules/exoplanets/exoplanetsmodule_lua.inl @@ -39,22 +39,24 @@ #include namespace { - constexpr const char* _loggerCat = "ExoplanetsModule"; + constexpr const char _loggerCat[] = "ExoplanetsModule"; } // namespace namespace openspace::exoplanets::luascriptfunctions { -constexpr const char* ExoplanetsGuiPath = "/Milky Way/Exoplanets/Exoplanet Systems/"; +constexpr const char ExoplanetsGuiPath[] = "/Milky Way/Exoplanets/Exoplanet Systems/"; -constexpr const char* LookUpTablePath = "${SYNC}/http/exoplanets_data/2/lookup.txt"; -constexpr const char* ExoplanetsDataPath = +constexpr const char LookUpTablePath[] = "${SYNC}/http/exoplanets_data/2/lookup.txt"; +constexpr const char ExoplanetsDataPath[] = "${SYNC}/http/exoplanets_data/2/exoplanets_data.bin"; -constexpr const char* StarTextureFile = "${SYNC}/http/exoplanets_textures/1/sun.jpg"; -constexpr const char* NoDataTextureFile = - "${SYNC}/http/exoplanets_textures/1/grid-32.png"; -constexpr const char* DiscTextureFile = - "${SYNC}/http/exoplanets_textures/1/disc_texture.png"; +constexpr const char StarTextureFile[] = "${SYNC}/http/exoplanets_textures/2/sun.jpg"; +constexpr const char NoDataTextureFile[] = + "${SYNC}/http/exoplanets_textures/2/grid-32.png"; +constexpr const char DiscTextureFile[] = + "${SYNC}/http/exoplanets_textures/2/disc_bw_texture.png"; +constexpr const char HabitableZoneTextureFile[] = + "${SYNC}/http/habitable_zone_textures/1/hot_to_cold_faded.png"; constexpr const float AU = static_cast(distanceconstants::AstronomicalUnit); constexpr const float SolarRadius = static_cast(distanceconstants::SolarRadius); @@ -387,7 +389,7 @@ void createExoplanetSystem(const std::string& starName) { std::to_string(lowerOffset) + ", " + std::to_string(upperOffset) + "}," //min / max extend - "Opacity = 0.3" + "Opacity = 0.25" "}," "Transform = {" "Rotation = {" @@ -451,16 +453,6 @@ void createExoplanetSystem(const std::string& starName) { bool hasLuminosity = !std::isnan(system.starData.luminosity); if (hasTeff && hasLuminosity) { - const glm::vec2 zone = computeHabitableZone( - system.starData.teff, - system.starData.luminosity - ); - - glm::vec2 limitsInMeter = zone * AU; - float half = 0.5f * (limitsInMeter[1] - limitsInMeter[0]); - float center = limitsInMeter[0] + half; - float relativeOffset = half / center; - constexpr const char* description = "The habitable zone is the region around a star in which an Earth-like " "planet can potentially have liquid water on its surface." @@ -476,17 +468,12 @@ void createExoplanetSystem(const std::string& starName) { "Parent = '" + starIdentifier + "'," "Enabled = true," "Renderable = {" - "Type = 'RenderableOrbitDisc'," - "Texture = openspace.absPath(" - "openspace.createPixelImage('exo_habitable_zone', {0, 0.92, 0.81})" - ")," - "Size = " + std::to_string(center) + "," - "Eccentricity = 0," - "Offset = { " + - std::to_string(relativeOffset) + ", " + - std::to_string(relativeOffset) + - "}," //min / max extend - "Opacity = 0.05" + "Type = 'RenderableHabitableZone'," + "Texture = openspace.absPath('" + HabitableZoneTextureFile + "')," + "Luminosity = " + std::to_string(system.starData.luminosity) + "," + "EffectiveTemperature = " + std::to_string(system.starData.teff) + "," + "Optimistic = true," + "Opacity = 0.07" "}," "Transform = {" "Rotation = {" diff --git a/modules/exoplanets/include.cmake b/modules/exoplanets/include.cmake index ffea0ac430..c186634837 100644 --- a/modules/exoplanets/include.cmake +++ b/modules/exoplanets/include.cmake @@ -1 +1,4 @@ set(DEFAULT_MODULE ON) +set (OPENSPACE_DEPENDENCIES + space +) diff --git a/modules/exoplanets/rendering/renderableorbitdisc.cpp b/modules/exoplanets/rendering/renderableorbitdisc.cpp index 2887a6bae9..15bd28072f 100644 --- a/modules/exoplanets/rendering/renderableorbitdisc.cpp +++ b/modules/exoplanets/rendering/renderableorbitdisc.cpp @@ -33,10 +33,8 @@ #include #include #include -#include #include #include -#include #include namespace { @@ -49,7 +47,7 @@ namespace { "Texture", "Texture", "This value is the path to a texture on disk that contains a one-dimensional " - "texture which is used for these rings." + "texture which is used for the color." }; static const openspace::properties::Property::PropertyInfo SizeInfo = { @@ -123,8 +121,6 @@ RenderableOrbitDisc::RenderableOrbitDisc(const ghoul::Dictionary& dictionary) , _eccentricity(EccentricityInfo, 0.f, 0.f, 1.f) , _offset(OffsetInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(1.f)) { - using ghoul::filesystem::File; - documentation::testSpecificationAndThrow( Documentation(), dictionary, @@ -144,13 +140,9 @@ RenderableOrbitDisc::RenderableOrbitDisc(const ghoul::Dictionary& dictionary) setBoundingSphere(_size + _offset.value().y * _size); _texturePath = absPath(dictionary.value(TextureInfo.identifier)); - _textureFile = std::make_unique(_texturePath); - - _texturePath.onChange([&]() { _textureIsDirty = true; }); + _texturePath.onChange([&]() { _texture->loadFromFile(_texturePath); }); addProperty(_texturePath); - _textureFile->setCallback([&](const File&) { _textureIsDirty = true; }); - _eccentricity = static_cast( dictionary.value(EccentricityInfo.identifier) ); @@ -161,33 +153,34 @@ RenderableOrbitDisc::RenderableOrbitDisc(const ghoul::Dictionary& dictionary) } bool RenderableOrbitDisc::isReady() const { - return _shader && _texture; + return _shader && _texture && _plane; +} + +void RenderableOrbitDisc::initialize() { + _texture = std::make_unique(); + _texture->setFilterMode(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + _texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge); + _plane = std::make_unique(planeSize()); } void RenderableOrbitDisc::initializeGL() { _shader = global::renderEngine->buildRenderProgram( - "OrbitdiscProgram", + "OrbitDiscProgram", absPath("${BASE}/modules/exoplanets/shaders/orbitdisc_vs.glsl"), absPath("${BASE}/modules/exoplanets/shaders/orbitdisc_fs.glsl") ); ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); - glGenVertexArrays(1, &_quad); - glGenBuffers(1, &_vertexPositionBuffer); + _texture->loadFromFile(_texturePath); + _texture->uploadToGpu(); - createPlane(); - loadTexture(); + _plane->initialize(); } void RenderableOrbitDisc::deinitializeGL() { - glDeleteVertexArrays(1, &_quad); - _quad = 0; - - glDeleteBuffers(1, &_vertexPositionBuffer); - _vertexPositionBuffer = 0; - - _textureFile = nullptr; + _plane->deinitialize(); + _plane = nullptr; _texture = nullptr; global::renderEngine->removeRenderProgram(_shader.get()); @@ -223,8 +216,7 @@ void RenderableOrbitDisc::render(const RenderData& data, RendererTasks&) { glDepthMask(false); glDisable(GL_CULL_FACE); - glBindVertexArray(_quad); - glDrawArrays(GL_TRIANGLES, 0, 6); + _plane->render(); _shader->deactivate(); @@ -241,80 +233,17 @@ void RenderableOrbitDisc::update(const UpdateData&) { } if (_planeIsDirty) { - createPlane(); + _plane->updateSize(planeSize()); _planeIsDirty = false; } - if (_textureIsDirty) { - loadTexture(); - _textureIsDirty = false; - } + _texture->update(); } -void RenderableOrbitDisc::loadTexture() { - if (!_texturePath.value().empty()) { - std::unique_ptr texture = - ghoul::io::TextureReader::ref().loadTexture(absPath(_texturePath)); - - if (texture) { - LDEBUGC( - "RenderableOrbitDisc", - fmt::format("Loaded texture from '{}'", absPath(_texturePath)) - ); - _texture = std::move(texture); - - _texture->uploadTexture(); - _texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - - _textureFile = std::make_unique(_texturePath); - _textureFile->setCallback( - [&](const ghoul::filesystem::File&) { _textureIsDirty = true; } - ); - } - } -} - -void RenderableOrbitDisc::createPlane() { - const GLfloat outerDistance = (_size + _offset.value().y * _size); - const GLfloat size = outerDistance * (1.f + _eccentricity); - - struct VertexData { - GLfloat x; - GLfloat y; - GLfloat s; - GLfloat t; - }; - - VertexData data[] = { - { -size, -size, 0.f, 0.f }, - { size, size, 1.f, 1.f }, - { -size, size, 0.f, 1.f }, - { -size, -size, 0.f, 0.f }, - { size, -size, 1.f, 0.f }, - { size, size, 1.f, 1.f }, - }; - - glBindVertexArray(_quad); - glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer( - 0, - 2, - GL_FLOAT, - GL_FALSE, - sizeof(VertexData), - nullptr - ); - glEnableVertexAttribArray(1); - glVertexAttribPointer( - 1, - 2, - GL_FLOAT, - GL_FALSE, - sizeof(VertexData), - reinterpret_cast(offsetof(VertexData, s)) - ); +float RenderableOrbitDisc::planeSize() const { + float maxRadius = _size + _offset.value().y * _size; + maxRadius *= (1.f + _eccentricity); + return maxRadius; } } // namespace openspace diff --git a/modules/exoplanets/rendering/renderableorbitdisc.h b/modules/exoplanets/rendering/renderableorbitdisc.h index 5a94a2bfc1..b467a9cb90 100644 --- a/modules/exoplanets/rendering/renderableorbitdisc.h +++ b/modules/exoplanets/rendering/renderableorbitdisc.h @@ -29,14 +29,13 @@ #include #include #include +#include +#include #include -#include #include namespace ghoul::filesystem { class File; } -namespace ghoul::opengl { - class ProgramObject; -} // namespace ghoul::opengl +namespace ghoul::opengl { class ProgramObject; } // namespace ghoul::opengl namespace openspace { @@ -46,6 +45,7 @@ class RenderableOrbitDisc : public Renderable { public: RenderableOrbitDisc(const ghoul::Dictionary& dictionary); + void initialize() override; void initializeGL() override; void deinitializeGL() override; @@ -57,8 +57,8 @@ public: static documentation::Documentation Documentation(); private: - void loadTexture(); - void createPlane(); + // Computes the size of the plane quad using the relevant properties + float planeSize() const; properties::StringProperty _texturePath; properties::FloatProperty _size; @@ -68,13 +68,11 @@ private: std::unique_ptr _shader = nullptr; UniformCache(modelViewProjection, offset, opacity, texture, eccentricity, semiMajorAxis) _uniformCache; - std::unique_ptr _texture = nullptr; - std::unique_ptr _textureFile; - bool _textureIsDirty = false; + std::unique_ptr _plane; + std::unique_ptr _texture; + bool _planeIsDirty = false; - GLuint _quad = 0; - GLuint _vertexPositionBuffer = 0; }; } // namespace openspace diff --git a/modules/space/CMakeLists.txt b/modules/space/CMakeLists.txt index 2c1a4e5e48..583e3e89ab 100644 --- a/modules/space/CMakeLists.txt +++ b/modules/space/CMakeLists.txt @@ -27,6 +27,7 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES rendering/planetgeometry.h rendering/renderableconstellationbounds.h + rendering/renderablehabitablezone.h rendering/renderablerings.h rendering/renderableorbitalkepler.h rendering/renderablesatellites.h @@ -44,6 +45,7 @@ source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES rendering/planetgeometry.cpp rendering/renderableconstellationbounds.cpp + rendering/renderablehabitablezone.cpp rendering/renderablerings.cpp rendering/renderableorbitalkepler.cpp rendering/renderablesatellites.cpp @@ -63,6 +65,8 @@ set(SHADER_FILES shaders/constellationbounds_vs.glsl shaders/debrisViz_fs.glsl shaders/debrisViz_vs.glsl + shaders/habitablezone_vs.glsl + shaders/habitablezone_fs.glsl shaders/rings_vs.glsl shaders/rings_fs.glsl shaders/star_fs.glsl diff --git a/modules/space/include.cmake b/modules/space/include.cmake index ffea0ac430..f5adeba225 100644 --- a/modules/space/include.cmake +++ b/modules/space/include.cmake @@ -1 +1,4 @@ set(DEFAULT_MODULE ON) +set (OPENSPACE_DEPENDENCIES + base +) diff --git a/modules/space/rendering/renderablehabitablezone.cpp b/modules/space/rendering/renderablehabitablezone.cpp new file mode 100644 index 0000000000..f2888a28c0 --- /dev/null +++ b/modules/space/rendering/renderablehabitablezone.cpp @@ -0,0 +1,302 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + constexpr const char _loggerCat[] = "RenderableHabitableZone"; + + constexpr const std::array UniformNames = { + "modelViewProjectionTransform", "opacity", "width", "transferFunctionTexture", + "conservativeBounds", "showOptimistic" + }; + + constexpr openspace::properties::Property::PropertyInfo EffectiveTemperatureInfo = { + "EffectiveTemperature", + "Effective Temperature", + "The effective temperature of the corresponding star, in Kelvin. " + "Used to compute the width and size of the disc." + }; + + constexpr openspace::properties::Property::PropertyInfo LuminosityInfo = { + "Luminosity", + "Luminosity", + "The luminosity of the corresponding star, in units of solar luminosities. " + "Used to compute the width and size of the disc." + }; + + constexpr openspace::properties::Property::PropertyInfo OptimisticInfo = { + "Optimistic", + "Optimistic" , + "If true, the habitable zone disc is rendered with the optimistic boundaries " + "rather than the conservative ones." + }; + + constexpr openspace::properties::Property::PropertyInfo KopparapuTeffIntervalInfo = { + "KopparapuTeffInterval", + "Effective Temperature Interval (Kopparapu's formula)" , + "The range for which Kopparapu's formula is used for the habitable zone " + "computation. For stars with effective temperatures outside the range, a " + "simpler method by Tom E. Harris is used. This method only uses the star " + "luminosity and does not include computation of the optimistic boundaries." + }; +} // namespace + +namespace openspace { + +documentation::Documentation RenderableHabitableZone::Documentation() { + using namespace documentation; + documentation::Documentation doc { + "Renderable Habitable Zone", + "exoplanets_renderable_habitable_zone", + { + { + EffectiveTemperatureInfo.identifier, + new DoubleVerifier, + Optional::No, + EffectiveTemperatureInfo.description + }, + { + LuminosityInfo.identifier, + new DoubleVerifier, + Optional::No, + LuminosityInfo.description + }, + { + OptimisticInfo.identifier, + new BoolVerifier, + Optional::Yes, + OptimisticInfo.description + }, + { + KopparapuTeffIntervalInfo.identifier, + new DoubleVector2Verifier, + Optional::Yes, + KopparapuTeffIntervalInfo.description + } + } + }; + + // @TODO cleanup + // Insert the parents documentation entries until we have a verifier that can deal + // with class hierarchy + documentation::Documentation parentDoc = RenderableDisc::Documentation(); + doc.entries.insert( + doc.entries.end(), + parentDoc.entries.begin(), + parentDoc.entries.end() + ); + + return doc; +} + +RenderableHabitableZone::RenderableHabitableZone(const ghoul::Dictionary& dictionary) + : RenderableDisc(dictionary) + , _teff(EffectiveTemperatureInfo, 5780.f, 0.f, 7.5e4f) + , _luminosity(LuminosityInfo, 1.f, 0.f, 1e8f) + , _showOptimistic(OptimisticInfo, false) + , _kopparapuTeffInterval(KopparapuTeffIntervalInfo, glm::vec2(2000.f, 8000.f)) +{ + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "RenderableHabitableZone" + ); + + if (dictionary.hasKey(EffectiveTemperatureInfo.identifier)) { + _teff = static_cast( + dictionary.value(EffectiveTemperatureInfo.identifier) + ); + } + _teff.onChange([this]() { computeZone(); }); + addProperty(_teff); + + if (dictionary.hasKey(LuminosityInfo.identifier)) { + _luminosity = static_cast( + dictionary.value(LuminosityInfo.identifier) + ); + } + _luminosity.onChange([this]() { computeZone(); }); + addProperty(_luminosity); + + if (dictionary.hasKey(OptimisticInfo.identifier)) { + _showOptimistic = dictionary.value(OptimisticInfo.identifier); + } + addProperty(_showOptimistic); + + // The user should not be able to change this property. It's just used to communicate + // the different rendering that happens outside of this interval + addProperty(_kopparapuTeffInterval); + _kopparapuTeffInterval.setReadOnly(true); + + // Make parent's size related properties read only. We want to set them based on the + // given temperature and luminosity + _size.setReadOnly(true); + _width.setReadOnly(true); + + computeZone(); +} + +void RenderableHabitableZone::render(const RenderData& data, RendererTasks&) { + _shader->activate(); + + glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * + glm::dmat4(data.modelTransform.rotation) * + glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); + + glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; + + _shader->setUniform( + _uniformCache.modelViewProjection, + data.camera.projectionMatrix() * glm::mat4(modelViewTransform) + ); + _shader->setUniform(_uniformCache.width, _width); + _shader->setUniform(_uniformCache.opacity, _opacity); + _shader->setUniform(_uniformCache.conservativeBounds, _conservativeBounds); + _shader->setUniform(_uniformCache.showOptimistic, _showOptimistic); + + ghoul::opengl::TextureUnit unit; + unit.activate(); + _texture->bind(); + _shader->setUniform(_uniformCache.texture, unit); + + glEnablei(GL_BLEND, 0); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(false); + glDisable(GL_CULL_FACE); + + _plane->render(); + + _shader->deactivate(); + + // Restores GL State + global::renderEngine->openglStateCache().resetBlendState(); + global::renderEngine->openglStateCache().resetDepthState(); + global::renderEngine->openglStateCache().resetPolygonAndClippingState(); +} + +void RenderableHabitableZone::initializeShader() { + _shader = global::renderEngine->buildRenderProgram( + "HabitableZoneProgram", + absPath("${MODULE_SPACE}/shaders/habitablezone_vs.glsl"), + absPath("${MODULE_SPACE}/shaders/habitablezone_fs.glsl") + ); + ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); +} + +void RenderableHabitableZone::updateUniformLocations() { + ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); +} + +void RenderableHabitableZone::computeZone() { + glm::dvec4 distancesInAu = computeKopparapuZoneBoundaries(_teff, _luminosity); + constexpr const double AU = distanceconstants::AstronomicalUnit; + const double inner = distancesInAu[0] * AU; + const double innerConservative = distancesInAu[1] * AU; + const double outerConservative = distancesInAu[2] * AU; + const double outer = distancesInAu[3] * AU; + + double discWidth = 0.0; + if (outer > 0.0) { + discWidth = (outer - inner) / outer; + } + + _size = static_cast(outer); + _width = static_cast(discWidth); + + // Compute the coservative bounds normalized by the size of the disc, i.e. in [0, 1] + _conservativeBounds = glm::vec2(innerConservative, outerConservative); + _conservativeBounds /= _size; +} + +glm::dvec4 RenderableHabitableZone::computeKopparapuZoneBoundaries(float teff, + float luminosity) +{ + // Kopparapu's formula only considers stars with teff in range [2600, 7200] K. + // However, we want to use the formula for more stars, so add some flexibility to + // the teff boundaries (see constructor). + // OBS! This also prevents problems with too large teff values in the computation + const glm::vec2 teffBounds = _kopparapuTeffInterval; + if (teff > teffBounds.y || teff < teffBounds.x) { + // For the other stars, use a method by Tom E. Morris: + // https://www.planetarybiology.com/calculating_habitable_zone.html + const double L = static_cast(luminosity); + double inner = std::sqrt(L / 1.1); + double outer = std::sqrt(L / 0.53); + return glm::dvec4(inner, inner, outer, outer); + } + + struct Coefficients { + double seffSun; + double a; + double b; + double c; + double d; + }; + + // Coefficients for planets of 1 Earth mass. Received from: + // https://depts.washington.edu/naivpl/sites/default/files/HZ_coefficients.dat + constexpr const Coefficients coefficients[] = { + // Optimistic Inner boundary - Recent Venus + {1.77600E+00, 2.13600E-04, 2.53300E-08, -1.33200E-11, -3.09700E-15}, + // Conservative Inner boundary - Runaway greenhouse + {1.10700E+00, 1.33200E-04, 1.58000E-08, -8.30800E-12, -1.93100E-15}, + // Conservative Outer boundary - Maximum greenhouse + {3.56000E-01, 6.17100E-05, 1.69800E-09, -3.19800E-12, -5.57500E-16}, + // Optimistic Outer boundary - Early Mars + {3.20000E-01, 5.54700E-05, 1.52600E-09, -2.87400E-12, -5.01100E-16} + }; + + const double tstar = static_cast(teff - 5780.f); + const double tstar2 = tstar * tstar; + const double L = static_cast(luminosity); + + glm::dvec4 distances; + for (int i = 0; i < 4; ++i) { + const Coefficients& coeffs = coefficients[i]; + double seff = coeffs.seffSun + (coeffs.a * tstar) + (coeffs.b * tstar2) + + (coeffs.c * tstar * tstar2) + (coeffs.d * tstar2 * tstar2); + + distances[i] = std::pow(L / seff, 0.5); + } + + return distances; +} + +} // namespace openspace diff --git a/modules/space/rendering/renderablehabitablezone.h b/modules/space/rendering/renderablehabitablezone.h new file mode 100644 index 0000000000..6aa5d7f31b --- /dev/null +++ b/modules/space/rendering/renderablehabitablezone.h @@ -0,0 +1,75 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * 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_EXOPLANETS___RENDERABLEHABITABLEZONE___H__ +#define __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEHABITABLEZONE___H__ + +#include +#include +#include +#include + +namespace openspace { + +namespace documentation { struct Documentation; } + +class RenderableHabitableZone : public RenderableDisc { +public: + RenderableHabitableZone(const ghoul::Dictionary& dictionary); + + void render(const RenderData& data, RendererTasks& rendererTask) override; + + static documentation::Documentation Documentation(); + +private: + void initializeShader() override; + void updateUniformLocations() override; + void computeZone(); + + /** + * Compute the inner and outer boundary of the habitable zone of a star, according to + * formula and coefficients by Kopparapu et al. (2015) https://arxiv.org/abs/1404.5292 + * + * \param teff The effective temperature of the star, in Kelvin + * \param luminosity The luminosity of the star, in solar luminosities + * \return A vec4 with the boundaries in atronomical units, in the order: + optimistic inner, conservative inner, conservative outer, optimistic outer + */ + glm::dvec4 computeKopparapuZoneBoundaries(float teff, float luminosity); + + properties::FloatProperty _teff; + properties::FloatProperty _luminosity; + properties::BoolProperty _showOptimistic; + + properties::Vec2Property _kopparapuTeffInterval; + + glm::vec2 _conservativeBounds; + + UniformCache(modelViewProjection, opacity, width, texture, + conservativeBounds, showOptimistic) _uniformCache; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEHABITABLEZONE___H__ diff --git a/modules/space/shaders/habitablezone_fs.glsl b/modules/space/shaders/habitablezone_fs.glsl new file mode 100644 index 0000000000..11bcca4f3b --- /dev/null +++ b/modules/space/shaders/habitablezone_fs.glsl @@ -0,0 +1,87 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "fragment.glsl" + +in vec2 vs_st; +in float vs_screenSpaceDepth; + +uniform sampler1D transferFunctionTexture; +uniform float width; +uniform float opacity; +uniform vec2 conservativeBounds; +uniform bool showOptimistic; + +// Remap the radius to texture coordinates in the trasfer function texture. The texture +// is treated as a linear scale where the color represent too cold to too hot. Account +// for the conservative bounds my mapping one third of the texture ouside each boundary. +// All parameters \in [0,1], where 1.0 corresponds to the max radius. +float computeTextureCoord(float radius, float innerRadius, + float conservativeInner, float conservativeOuter) +{ + const float t1 = 1.0 / 3.0; + const float t2 = 2.0 / 3.0; + + if (radius < conservativeInner) { + float t = (radius - innerRadius) / (conservativeInner - innerRadius); + return mix(0.0, t1, t); + } + else if (radius > conservativeOuter) { + float t = (radius - conservativeOuter) / (1.0 - conservativeOuter); + return mix(t2, 1.0, t); + } + else { + float t = (radius - conservativeInner) / (conservativeOuter - conservativeInner); + return mix(t1, t2, t); + } +} + +Fragment getFragment() { + // The length of the texture coordinates vector is our distance from the center + float radius = length(vs_st); + float innerRadius = 1.0 - width; + + // We only want to consider ring-like objects so we need to discard everything else + if (radius > 1.0 || radius < innerRadius) { + discard; + } + + float consInner = conservativeBounds.x; + float consOuter = conservativeBounds.y; + bool outsideConservative = (radius < consInner) || (radius > consOuter); + + if (!showOptimistic && outsideConservative) { + discard; + } + + float texCoord = computeTextureCoord(radius, innerRadius, consInner, consOuter); + + vec4 diffuse = texture(transferFunctionTexture, texCoord); + diffuse.a *= opacity; + + Fragment frag; + frag.color = diffuse; + frag.depth = vs_screenSpaceDepth; + return frag; +} diff --git a/modules/space/shaders/habitablezone_vs.glsl b/modules/space/shaders/habitablezone_vs.glsl new file mode 100644 index 0000000000..d5796d62d9 --- /dev/null +++ b/modules/space/shaders/habitablezone_vs.glsl @@ -0,0 +1,47 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +#include "PowerScaling/powerScaling_vs.hglsl" + +layout(location = 0) in vec2 in_position; +layout(location = 1) in vec2 in_st; + +out vec2 vs_st; +out float vs_screenSpaceDepth; + +uniform mat4 modelViewProjectionTransform; + +void main() { + vec4 position = vec4(in_position.xy, 0.0, 1.0); + vec4 positionScreenSpace = z_normalization(modelViewProjectionTransform * position); + + // Moving the origin to the center + vs_st = (in_st - vec2(0.5)) * 2.0; + + vs_screenSpaceDepth = positionScreenSpace.w; + + gl_Position = positionScreenSpace; +} diff --git a/modules/space/spacemodule.cpp b/modules/space/spacemodule.cpp index cdc90d3768..95c576e14f 100644 --- a/modules/space/spacemodule.cpp +++ b/modules/space/spacemodule.cpp @@ -24,8 +24,8 @@ #include -#include #include +#include #include #include #include @@ -80,7 +80,7 @@ void SpaceModule::internalInitialize(const ghoul::Dictionary& dictionary) { fRenderable->registerClass( "RenderableConstellationBounds" ); - + fRenderable->registerClass("RenderableHabitableZone"); fRenderable->registerClass("RenderableRings"); fRenderable->registerClass("RenderableSatellites"); fRenderable->registerClass("RenderableSmallBody"); @@ -119,6 +119,7 @@ void SpaceModule::internalDeinitializeGL() { std::vector SpaceModule::documentations() const { return { RenderableConstellationBounds::Documentation(), + RenderableHabitableZone::Documentation(), RenderableRings::Documentation(), RenderableSatellites::Documentation(), RenderableSmallBody::Documentation(), diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bdd8c0b8b2..f095c64271 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -143,6 +143,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/rendering/renderengine.cpp ${OPENSPACE_BASE_DIR}/src/rendering/renderengine_lua.inl ${OPENSPACE_BASE_DIR}/src/rendering/screenspacerenderable.cpp + ${OPENSPACE_BASE_DIR}/src/rendering/texturecomponent.cpp ${OPENSPACE_BASE_DIR}/src/rendering/transferfunction.cpp ${OPENSPACE_BASE_DIR}/src/rendering/volumeraycaster.cpp ${OPENSPACE_BASE_DIR}/src/scene/asset.cpp @@ -178,6 +179,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/util/httprequest.cpp ${OPENSPACE_BASE_DIR}/src/util/keys.cpp ${OPENSPACE_BASE_DIR}/src/util/openspacemodule.cpp + ${OPENSPACE_BASE_DIR}/src/util/planegeometry.cpp ${OPENSPACE_BASE_DIR}/src/util/progressbar.cpp ${OPENSPACE_BASE_DIR}/src/util/resourcesynchronization.cpp ${OPENSPACE_BASE_DIR}/src/util/screenlog.cpp @@ -322,6 +324,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/rendering/dashboard.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/dashboarditem.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/framebufferrenderer.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcaster.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcasterlistener.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcastermanager.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/loadingscreen.h @@ -332,11 +335,11 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/rendering/renderable.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/renderer.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/renderengine.h - ${OPENSPACE_BASE_DIR}/include/openspace/rendering/volume.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/screenspacerenderable.h - ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcaster.h - ${OPENSPACE_BASE_DIR}/include/openspace/rendering/volumeraycaster.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/texturecomponent.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/transferfunction.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/volume.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/volumeraycaster.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/asset.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/assetlistener.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/assetloader.h @@ -373,6 +376,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/util/memorymanager.h ${OPENSPACE_BASE_DIR}/include/openspace/util/mouse.h ${OPENSPACE_BASE_DIR}/include/openspace/util/openspacemodule.h + ${OPENSPACE_BASE_DIR}/include/openspace/util/planegeometry.h ${OPENSPACE_BASE_DIR}/include/openspace/util/progressbar.h ${OPENSPACE_BASE_DIR}/include/openspace/util/resourcesynchronization.h ${OPENSPACE_BASE_DIR}/include/openspace/util/screenlog.h diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index b9512adff6..00c135152d 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1540,8 +1540,8 @@ scripting::LuaLibrary OpenSpaceEngine::luaLibrary() { "Removes a tag (second argument) from a scene graph node (first argument)" }, { - "createPixelImage", - &luascriptfunctions::createPixelImage, + "createSingeColorImage", + &luascriptfunctions::createSingeColorImage, {}, "string, vec3", "Creates a 1 pixel image with a certain color in the cache folder and " diff --git a/src/engine/openspaceengine_lua.inl b/src/engine/openspaceengine_lua.inl index d19a6aab6c..96cb96f3c2 100644 --- a/src/engine/openspaceengine_lua.inl +++ b/src/engine/openspaceengine_lua.inl @@ -294,11 +294,11 @@ int downloadFile(lua_State* L) { /** * \ingroup LuaScripts -* createPixelImage(): -* Creates a one pixel image with a given color and returns the p +* createSingeColorImage(): +* Creates a one pixel image with a given color and returns the path to the cached file */ -int createPixelImage(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::createPixelImage"); +int createSingeColorImage(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::createSingeColorImage"); const std::string& name = ghoul::lua::value(L, 1); const ghoul::Dictionary& d = ghoul::lua::value(L, 2); diff --git a/src/rendering/texturecomponent.cpp b/src/rendering/texturecomponent.cpp new file mode 100644 index 0000000000..ce771887f8 --- /dev/null +++ b/src/rendering/texturecomponent.cpp @@ -0,0 +1,115 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include + +namespace { + constexpr const char _loggerCat[] = "TextureComponent"; +} // namespace + +namespace openspace { + +const ghoul::opengl::Texture* TextureComponent::texture() const { + return _texture.get(); +} + +ghoul::opengl::Texture* TextureComponent::texture() { + return _texture.get(); +} + +void TextureComponent::setFilterMode(Texture::FilterMode filterMode) { + _filterMode = filterMode; +} + +void TextureComponent::setWrapping(Texture::WrappingMode wrapping) { + _wrappingMode = wrapping; +} + +void TextureComponent::setShouldWatchFileForChanges(bool value) { + _shouldWatchFile = value; +} + +void TextureComponent::setShouldPurgeFromRAM(bool value) { + _shouldPurgeFromRAM = value; +} + +void TextureComponent::bind() { + ghoul_assert(_texture, "Texture must be loaded before binding"); + _texture->bind(); +} + +void TextureComponent::uploadToGpu() { + if (!_texture) { + LERROR("Could not upload texture to GPU. Texture not loaded"); + return; + } + _texture->uploadTexture(); + _texture->setFilter(_filterMode); + _texture->setWrapping(_wrappingMode); + if (_shouldPurgeFromRAM) { + _texture->purgeFromRAM(); + } +} + +void TextureComponent::loadFromFile(const std::string& path) { + if (!path.empty()) { + using namespace ghoul::io; + using namespace ghoul::opengl; + std::unique_ptr texture = TextureReader::ref().loadTexture( + absPath(path) + ); + + if (texture) { + LDEBUG(fmt::format("Loaded texture from '{}'", absPath(path))); + _texture = std::move(texture); + + _textureFile = std::make_unique(path); + if (_shouldWatchFile) { + _textureFile->setCallback( + [&](const ghoul::filesystem::File&) { _fileIsDirty = true; } + ); + } + + _fileIsDirty = false; + _textureIsDirty = true; + } + } +} + +void TextureComponent::update() { + if (_fileIsDirty) { + loadFromFile(_textureFile->path()); + } + + if (_textureIsDirty) { + uploadToGpu(); + _textureIsDirty = false; + } +} +} // namespace openspace diff --git a/src/util/planegeometry.cpp b/src/util/planegeometry.cpp new file mode 100644 index 0000000000..69a8c92317 --- /dev/null +++ b/src/util/planegeometry.cpp @@ -0,0 +1,108 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include + +namespace { + constexpr const char* _loggerCat = "PlaneGeometry"; +} // namespace + +namespace openspace { + +PlaneGeometry::PlaneGeometry(glm::vec2 size) : _size(std::move(size)) {} + +PlaneGeometry::PlaneGeometry(float size) : PlaneGeometry(glm::vec2(size, size)) {} + +PlaneGeometry::~PlaneGeometry() { + glDeleteBuffers(1, &_vBufferId); + glDeleteVertexArrays(1, &_vaoId); +} + +void PlaneGeometry::initialize() { + glGenVertexArrays(1, &_vaoId); + glGenBuffers(1, &_vBufferId); + updateGeometry(); +} + +void PlaneGeometry::deinitialize() { + glDeleteVertexArrays(1, &_vaoId); + _vaoId = 0; + + glDeleteBuffers(1, &_vBufferId); + _vBufferId = 0; +} + +void PlaneGeometry::render() { + glBindVertexArray(_vaoId); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); +} + +void PlaneGeometry::updateSize(const glm::vec2& size) { + _size = size; + updateGeometry(); +} + +void PlaneGeometry::updateSize(const float size) { + updateSize(glm::vec2(size)); +} + +void PlaneGeometry::updateGeometry() { + const glm::vec2 size = _size; + struct VertexData { + GLfloat x; + GLfloat y; + GLfloat s; + GLfloat t; + }; + + VertexData vertices[] = { + { -size.x, -size.y, 0.f, 0.f }, + { size.x, size.y, 1.f, 1.f }, + { -size.x, size.y, 0.f, 1.f }, + { -size.x, -size.y, 0.f, 0.f }, + { size.x, -size.y, 1.f, 0.f }, + { size.x, size.y, 1.f, 1.f } + }; + + glBindVertexArray(_vaoId); + glBindBuffer(GL_ARRAY_BUFFER, _vBufferId); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), nullptr); + glEnableVertexAttribArray(1); + glVertexAttribPointer( + 1, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(VertexData), + reinterpret_cast(offsetof(VertexData, s)) // NOLINT + ); +} + +} // namespace openspace