diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index f8305b1465..38b178555c 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/shader_bridge.cpp" ) # Create 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..7e9c7df950 --- /dev/null +++ b/engine/include/cubos/engine/render/shader/plugin.hpp @@ -0,0 +1,30 @@ +/// @dir +/// @brief @ref shader-plugin plugin directory. + +/// @file +/// @brief Plugin entry point. +/// @ingroup shader-plugin + +#pragma once + +#include +#include + +namespace cubos::engine +{ + /// @defgroup shader-plugin Shader + /// @ingroup engine + /// @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 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..9afedf71a4 --- /dev/null +++ b/engine/include/cubos/engine/render/shader/shader.hpp @@ -0,0 +1,32 @@ +/// @file +/// @brief Class @ref cubos::engine::Shader. +/// @ingroup shader-plugin + +#pragma once + +#include +#include + +namespace cubos::engine +{ + /// @brief Contains a shader stage created from GLSL code. + /// @ingroup shader-plugin + class Shader final + { + public: + CUBOS_REFLECT; + + ~Shader() = default; + + /// @brief Constructs an empty shader. + Shader() = default; + + /// @brief Constructs a shader from code. + /// @param shaderStage Shader stage created from GLSL code. + Shader(cubos::core::gl::ShaderStage shaderStage) + : mShaderStage(shaderStage){}; + + private: + cubos::core::gl::ShaderStage mShaderStage; + }; +} // namespace cubos::engine diff --git a/engine/include/cubos/engine/render/shader/shader_bridge.hpp b/engine/include/cubos/engine/render/shader/shader_bridge.hpp new file mode 100644 index 0000000000..3243559771 --- /dev/null +++ b/engine/include/cubos/engine/render/shader/shader_bridge.hpp @@ -0,0 +1,35 @@ +/// @file +/// @brief Class @ref cubos::engine::ShaderBridge. +/// @ingroup shader-plugin + +#pragma once + +#include +#include + +#include +#include + +namespace cubos::engine +{ + /// @brief Bridge for loading shader assets. + /// @ingroup 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/src/render/shader/plugin.cpp b/engine/src/render/shader/plugin.cpp new file mode 100644 index 0000000000..de57157a55 --- /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..f773cfd204 --- /dev/null +++ b/engine/src/render/shader/shader.cpp @@ -0,0 +1,16 @@ +#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().withDefaultConstructor().withMoveConstructor().build()); +} diff --git a/engine/src/render/shader/shader_bridge.cpp b/engine/src/render/shader/shader_bridge.cpp new file mode 100644 index 0000000000..6e6fb48106 --- /dev/null +++ b/engine/src/render/shader/shader_bridge.cpp @@ -0,0 +1,57 @@ +#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 meta = assets.readMeta(handle); + auto stageTypeString = meta->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; + } + + Shader shader(mRenderDevice.createShaderStage(stageType, contents.c_str())); + + // Store the asset's data. + assets.store(handle, std::move(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; +}