diff --git a/include/openspace/rendering/texturecomponent.h b/include/openspace/rendering/texturecomponent.h new file mode 100644 index 0000000000..0046ea1cc0 --- /dev/null +++ b/include/openspace/rendering/texturecomponent.h @@ -0,0 +1,70 @@ +/***************************************************************************************** + * * + * 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 +#include +#include + +namespace ghoul::filesystem { class File; } +namespace ghoul::opengl {class Texture; } + +namespace openspace { + +class TextureComponent { + using Texture = ghoul::opengl::Texture; + +public: + TextureComponent() = default; + TextureComponent(const Texture::FilterMode filterMode, bool watchFile = true); + ~TextureComponent() = default; + + Texture* texture() const; + + 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 = nullptr; + std::unique_ptr _texture = nullptr; + + Texture::FilterMode _filterMode = Texture::FilterMode::LinearMipMap; + bool _shouldWatchFile = true; + + bool _fileIsDirty = false; + bool _textureIsDirty = false; +}; + +} // namespace openspace + +#endif // __OPENSPACE_CORE___TEXTURECOMPONENT___H__ diff --git a/modules/base/rendering/renderabledisc.cpp b/modules/base/rendering/renderabledisc.cpp index 8d4e71e104..cb29d17b28 100644 --- a/modules/base/rendering/renderabledisc.cpp +++ b/modules/base/rendering/renderabledisc.cpp @@ -31,14 +31,14 @@ #include #include #include -#include #include #include #include -#include #include namespace { + constexpr const char* _loggerCat = "RenderableDisc"; + constexpr const std::array UniformNames = { "modelViewProjectionTransform", "opacity", "width", "colorTexture" }; @@ -106,8 +106,6 @@ RenderableDisc::RenderableDisc(const ghoul::Dictionary& dictionary) , _size(SizeInfo, 1.f, 0.f, 1e13f) , _width(WidthInfo, 0.5f, 0.f, 1.f) { - using ghoul::filesystem::File; - documentation::testSpecificationAndThrow( Documentation(), dictionary, @@ -120,25 +118,26 @@ RenderableDisc::RenderableDisc(const ghoul::Dictionary& dictionary) addProperty(_size); _texturePath = absPath(dictionary.value(TextureInfo.identifier)); - _textureFile = std::make_unique(_texturePath); + _texturePath.onChange([&]() { _texture->loadFromFile(_texturePath); }); + addProperty(_texturePath); if (dictionary.hasKey(WidthInfo.identifier)) { _width = dictionary.value(WidthInfo.identifier); } addProperty(_width); - _texturePath.onChange([&]() { loadTexture(); }); - addProperty(_texturePath); - - _textureFile->setCallback([&](const File&) { _textureIsDirty = true; }); - addProperty(_opacity); - - _plane = std::make_unique(2*_size); } bool RenderableDisc::isReady() const { - return _shader && _texture; + return _shader && _texture && _plane; +} + +void RenderableDisc::initialize() { + _texture = std::make_unique( + ghoul::opengl::Texture::FilterMode::AnisotropicMipMap + ); + _plane = std::make_unique(2 * _size); } void RenderableDisc::initializeGL() { @@ -150,15 +149,15 @@ void RenderableDisc::initializeGL() { ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); + _texture->loadFromFile(_texturePath); + _texture->uploadToGpu(); + _plane->initialize(); - loadTexture(); } void RenderableDisc::deinitializeGL() { _plane->deinitialize(); _plane = nullptr; - - _textureFile = nullptr; _texture = nullptr; global::renderEngine->removeRenderProgram(_shader.get()); @@ -210,40 +209,11 @@ void RenderableDisc::update(const UpdateData&) { } if (_planeIsDirty) { - _plane->updateSize(2*_size); + _plane->updateSize(2 * _size); _planeIsDirty = false; } - if (_textureIsDirty) { - loadTexture(); - _textureIsDirty = false; - } -} - -void RenderableDisc::loadTexture() { - if (!_texturePath.value().empty()) { - using namespace ghoul::io; - using namespace ghoul::opengl; - std::unique_ptr texture = TextureReader::ref().loadTexture( - absPath(_texturePath) - ); - - if (texture) { - LDEBUGC( - "RenderableDisc", - 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; } - ); - } - } + _texture->update(); } } // namespace openspace diff --git a/modules/base/rendering/renderabledisc.h b/modules/base/rendering/renderabledisc.h index 6cbe6baa75..886e2f9b74 100644 --- a/modules/base/rendering/renderabledisc.h +++ b/modules/base/rendering/renderabledisc.h @@ -25,19 +25,16 @@ #ifndef __OPENSPACE_MODULE_BASE___RENDERABLEDISC___H__ #define __OPENSPACE_MODULE_BASE___RENDERABLEDISC___H__ -#include - #include #include +#include +#include #include #include #include namespace ghoul::filesystem { class File; } -namespace ghoul::opengl { - class ProgramObject; - class Texture; -} // namespace ghoul::opengl +namespace ghoul::opengl { class ProgramObject; } namespace openspace { @@ -47,6 +44,7 @@ class RenderableDisc : public Renderable { public: RenderableDisc(const ghoul::Dictionary& dictionary); + void initialize() override; void initializeGL() override; void deinitializeGL() override; @@ -58,20 +56,16 @@ public: static documentation::Documentation Documentation(); private: - void loadTexture(); - properties::StringProperty _texturePath; properties::FloatProperty _size; properties::FloatProperty _width; std::unique_ptr _shader; UniformCache(modelViewProjection, opacity, width, texture) _uniformCache; - std::unique_ptr _texture; - std::unique_ptr _textureFile; std::unique_ptr _plane; + std::unique_ptr _texture; - bool _textureIsDirty = false; bool _planeIsDirty = false; }; diff --git a/modules/exoplanets/rendering/renderableorbitdisc.cpp b/modules/exoplanets/rendering/renderableorbitdisc.cpp index fdef0e820a..891380ddc3 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 { @@ -144,13 +142,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) ); @@ -158,12 +152,17 @@ RenderableOrbitDisc::RenderableOrbitDisc(const ghoul::Dictionary& dictionary) addProperty(_eccentricity); addProperty(_opacity); - - _plane = std::make_unique(planeSize()); } bool RenderableOrbitDisc::isReady() const { - return _shader && _texture; + return _shader && _texture && _plane; +} + +void RenderableOrbitDisc::initialize() { + _texture = std::make_unique( + ghoul::opengl::Texture::FilterMode::AnisotropicMipMap + ); + _plane = std::make_unique(planeSize()); } void RenderableOrbitDisc::initializeGL() { @@ -175,15 +174,15 @@ void RenderableOrbitDisc::initializeGL() { ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); + _texture->loadFromFile(_texturePath); + _texture->uploadToGpu(); + _plane->initialize(); - loadTexture(); } void RenderableOrbitDisc::deinitializeGL() { _plane->deinitialize(); _plane = nullptr; - - _textureFile = nullptr; _texture = nullptr; global::renderEngine->removeRenderProgram(_shader.get()); @@ -240,33 +239,7 @@ void RenderableOrbitDisc::update(const UpdateData&) { _planeIsDirty = false; } - if (_textureIsDirty) { - loadTexture(); - _textureIsDirty = false; - } -} - -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; } - ); - } - } + _texture->update(); } float RenderableOrbitDisc::planeSize() const { diff --git a/modules/exoplanets/rendering/renderableorbitdisc.h b/modules/exoplanets/rendering/renderableorbitdisc.h index 1aea4ae413..8a3be1b5d7 100644 --- a/modules/exoplanets/rendering/renderableorbitdisc.h +++ b/modules/exoplanets/rendering/renderableorbitdisc.h @@ -29,9 +29,9 @@ #include #include #include +#include #include #include -#include #include namespace ghoul::filesystem { class File; } @@ -47,6 +47,7 @@ class RenderableOrbitDisc : public Renderable { public: RenderableOrbitDisc(const ghoul::Dictionary& dictionary); + void initialize() override; void initializeGL() override; void deinitializeGL() override; @@ -58,8 +59,6 @@ public: static documentation::Documentation Documentation(); private: - void loadTexture(); - // Computes the size of the plane quad using the relevant properties float planeSize() const; @@ -71,12 +70,10 @@ private: std::unique_ptr _shader = nullptr; UniformCache(modelViewProjection, offset, opacity, texture, eccentricity, semiMajorAxis) _uniformCache; - std::unique_ptr _texture = nullptr; - std::unique_ptr _textureFile; std::unique_ptr _plane; + std::unique_ptr _texture; - bool _textureIsDirty = false; bool _planeIsDirty = false; }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8ad4ff0933..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 @@ -323,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 @@ -333,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 diff --git a/src/rendering/texturecomponent.cpp b/src/rendering/texturecomponent.cpp new file mode 100644 index 0000000000..62e9aabf5a --- /dev/null +++ b/src/rendering/texturecomponent.cpp @@ -0,0 +1,96 @@ +/***************************************************************************************** + * * + * 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 { + +TextureComponent::TextureComponent(const Texture::FilterMode filterMode, bool watchFile) + : _filterMode(filterMode), _shouldWatchFile(watchFile) +{} + +ghoul::opengl::Texture* TextureComponent::texture() const { + return _texture.get(); +} + +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); +} + +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 = nullptr; + _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