diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index f8305b1465..be83c65d9c 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -92,6 +92,10 @@ set(CUBOS_ENGINE_SOURCE "src/screen_picker/screen_picker.cpp" "src/fixed_step/plugin.cpp" + + "src/render/shader/plugin.cpp" + "src/render/shader/shader.cpp" + "src/render/shader/bridge.cpp" ) # Create cubos engine diff --git a/engine/include/cubos/engine/render/module.dox b/engine/include/cubos/engine/render/module.dox new file mode 100644 index 0000000000..9fba45aab8 --- /dev/null +++ b/engine/include/cubos/engine/render/module.dox @@ -0,0 +1,9 @@ +/// @dir +/// @brief @ref render-plugins module. + +namespace cubos::engine +{ + /// @defgroup render-plugins Render + /// @ingroup engine + /// @brief Provides plugins for graphics rendering. +} // namespace cubos::engine diff --git a/engine/include/cubos/engine/render/shader/bridge.hpp b/engine/include/cubos/engine/render/shader/bridge.hpp new file mode 100644 index 0000000000..37a9d18600 --- /dev/null +++ b/engine/include/cubos/engine/render/shader/bridge.hpp @@ -0,0 +1,35 @@ +/// @file +/// @brief Class @ref cubos::engine::ShaderBridge. +/// @ingroup render-shader-plugin + +#pragma once + +#include +#include + +#include +#include + +namespace cubos::engine +{ + /// @brief Bridge for loading shader assets. + /// @ingroup render-shader-plugin + class ShaderBridge : public FileBridge + { + public: + /// @brief Constructs a bridge. + /// @param renderDevice Render device used to create the shader. + ShaderBridge(core::gl::RenderDevice& renderDevice) + : FileBridge(cubos::core::reflection::reflect()) + , mRenderDevice(renderDevice) + { + } + + protected: + bool loadFromFile(Assets& assets, const AnyAsset& handle, cubos::core::memory::Stream& stream) override; + bool saveToFile(const Assets& assets, const AnyAsset& handle, cubos::core::memory::Stream& stream) override; + + private: + core::gl::RenderDevice& mRenderDevice; ///< Render device used to create the shader. + }; +} // namespace cubos::engine diff --git a/engine/include/cubos/engine/render/shader/plugin.hpp b/engine/include/cubos/engine/render/shader/plugin.hpp new file mode 100644 index 0000000000..1036076fbe --- /dev/null +++ b/engine/include/cubos/engine/render/shader/plugin.hpp @@ -0,0 +1,30 @@ +/// @dir +/// @brief @ref render-shader-plugin plugin directory. + +/// @file +/// @brief Plugin entry point. +/// @ingroup render-shader-plugin + +#pragma once + +#include +#include + +namespace cubos::engine +{ + /// @defgroup render-shader-plugin Shader + /// @ingroup render-plugins + /// @brief Adds shader assets to @b CUBOS. + /// + /// ## Bridges + /// - @ref ShaderBridge - registered with the `.glsl` extension, loads @ref Shader assets. + /// + /// ## Dependencies + /// - @ref assets-plugin + /// - @ref window-plugin + + /// @brief Plugin entry function. + /// @param cubos @b CUBOS. main class. + /// @ingroup render-shader-plugin + void shaderPlugin(Cubos& cubos); +} // namespace cubos::engine diff --git a/engine/include/cubos/engine/render/shader/shader.hpp b/engine/include/cubos/engine/render/shader/shader.hpp new file mode 100644 index 0000000000..67677ae04e --- /dev/null +++ b/engine/include/cubos/engine/render/shader/shader.hpp @@ -0,0 +1,31 @@ +/// @file +/// @brief Class @ref cubos::engine::Shader. +/// @ingroup render-shader-plugin + +#pragma once + +#include +#include + +namespace cubos::engine +{ + /// @brief Contains a shader stage created from GLSL code. + /// @ingroup render-shader-plugin + class Shader final + { + public: + CUBOS_REFLECT; + + ~Shader() = default; + + /// @brief Constructs a shader from code. + /// @param shaderStage Shader stage created from GLSL code. + Shader(cubos::core::gl::ShaderStage shaderStage) + : mShaderStage(std::move(shaderStage)){}; + + cubos::core::gl::ShaderStage getShaderStage() const; + + private: + cubos::core::gl::ShaderStage mShaderStage; + }; +} // namespace cubos::engine diff --git a/engine/src/render/shader/bridge.cpp b/engine/src/render/shader/bridge.cpp new file mode 100644 index 0000000000..6ed6b9606d --- /dev/null +++ b/engine/src/render/shader/bridge.cpp @@ -0,0 +1,62 @@ +#include + +#include + +using namespace cubos::engine; + +using cubos::core::memory::Stream; + +bool ShaderBridge::loadFromFile(Assets& assets, const AnyAsset& handle, Stream& stream) +{ + // Dump the shader code into a string. + std::string contents; + stream.readUntil(contents, nullptr); + + // Read shader stage type + auto stageTypeString = assets.readMeta(handle)->get("stage"); + cubos::core::gl::Stage stageType; + if (stageTypeString == "Vertex") + { + stageType = cubos::core::gl::Stage::Vertex; + } + else if (stageTypeString == "Geometry") + { + stageType = cubos::core::gl::Stage::Geometry; + } + else if (stageTypeString == "Pixel") + { + stageType = cubos::core::gl::Stage::Pixel; + } + else if (stageTypeString == "Compute") + { + stageType = cubos::core::gl::Stage::Compute; + } + else + { + CUBOS_ERROR("Shader assets must specify a stage type"); + return false; + } + + cubos::core::gl::ShaderStage shaderStage = mRenderDevice.createShaderStage(stageType, contents.c_str()); + if (shaderStage == nullptr) + { + return false; + } + + Shader shader(shaderStage); + + // Store the asset's data. + assets.store(handle, shader); + return true; +} + +bool ShaderBridge::saveToFile(const Assets& assets, const AnyAsset& handle, cubos::core::memory::Stream& stream) +{ + // Ignore unused argument warnings + (void)assets; + (void)handle; + (void)stream; + + CUBOS_ERROR("Shader assets are not saveable"); + return false; +} diff --git a/engine/src/render/shader/plugin.cpp b/engine/src/render/shader/plugin.cpp new file mode 100644 index 0000000000..19c94c5c1a --- /dev/null +++ b/engine/src/render/shader/plugin.cpp @@ -0,0 +1,25 @@ +#include + +#include +#include +#include +#include +#include +#include + +using cubos::core::io::Window; +using cubos::engine::ShaderBridge; + +void cubos::engine::shaderPlugin(Cubos& cubos) +{ + cubos.addPlugin(assetsPlugin); + cubos.addPlugin(windowPlugin); + + cubos.startupSystem("setup Shader asset bridge") + .tagged("cubos.assets.bridge") + .after("cubos.window.init") + .call([](Assets& assets, Window& window) { + // Add the bridge to load .glsl files. + assets.registerBridge(".glsl", std::make_unique(window->renderDevice())); + }); +} diff --git a/engine/src/render/shader/shader.cpp b/engine/src/render/shader/shader.cpp new file mode 100644 index 0000000000..b0a9dfde30 --- /dev/null +++ b/engine/src/render/shader/shader.cpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +#include + +using namespace cubos::engine; + +CUBOS_REFLECT_IMPL(Shader) +{ + using namespace cubos::core::reflection; + + return Type::create("cubos::engine::Shader") + .with(ConstructibleTrait::typed().withMoveConstructor().build()); +} + +cubos::core::gl::ShaderStage Shader::getShaderStage() const +{ + return mShaderStage; +}