X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fclient%2Frender%2Fpipeline.h;fp=src%2Fclient%2Frender%2Fpipeline.h;h=4a6df7de268fd22038b7d55b3c1e1d765855a242;hb=ff6dcfea82974df6db5a557e31aaddb6bdb7a71f;hp=0000000000000000000000000000000000000000;hpb=464043b8abdbd936640757604ecb21662592043b;p=minetest.git diff --git a/src/client/render/pipeline.h b/src/client/render/pipeline.h new file mode 100644 index 000000000..4a6df7de2 --- /dev/null +++ b/src/client/render/pipeline.h @@ -0,0 +1,431 @@ +/* +Minetest +Copyright (C) 2022 x2048, Dmitry Kostenko + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#pragma once + +#include "irrlichttypes_extrabloated.h" + +#include +#include +#include + +class RenderSource; +class RenderTarget; +class RenderStep; +class Client; +class Hud; +class ShadowRenderer; + +struct PipelineContext +{ + PipelineContext(IrrlichtDevice *_device, Client *_client, Hud *_hud, ShadowRenderer *_shadow_renderer, video::SColor _color, v2u32 _target_size) + : device(_device), client(_client), hud(_hud), shadow_renderer(_shadow_renderer), clear_color(_color), target_size(_target_size) + { + } + + IrrlichtDevice *device; + Client *client; + Hud *hud; + ShadowRenderer *shadow_renderer; + video::SColor clear_color; + v2u32 target_size; + + bool show_hud {true}; + bool show_minimap {true}; + bool draw_wield_tool {true}; + bool draw_crosshair {true}; +}; + +/** + * Base object that can be owned by RenderPipeline + * + */ +class RenderPipelineObject +{ +public: + virtual ~RenderPipelineObject() = default; + virtual void reset(PipelineContext &context) {} +}; + +/** + * Represents a source of rendering information such as textures + */ +class RenderSource : virtual public RenderPipelineObject +{ +public: + /** + * Return the number of textures in the source. + */ + virtual u8 getTextureCount() = 0; + + /** + * Get a texture by index. + * Returns nullptr is the texture does not exist. + */ + virtual video::ITexture *getTexture(u8 index) = 0; +}; + +/** + * Represents a render target (screen or framebuffer) + */ +class RenderTarget : virtual public RenderPipelineObject +{ +public: + /** + * Activate the render target and configure OpenGL state for the output. + * This is usually done by @see RenderStep implementations. + */ + virtual void activate(PipelineContext &context) + { + m_clear = false; + } + + /** + * Resets the state of the object for the next pipeline iteration + */ + virtual void reset(PipelineContext &context) override + { + m_clear = true; + } + +protected: + bool m_clear {true}; +}; + +/** + * Texture buffer represents a framebuffer with a multiple attached textures. + * + * @note Use of TextureBuffer requires use of gl_FragData[] in the shader + */ +class TextureBuffer : public RenderSource, public RenderTarget +{ +public: + virtual ~TextureBuffer() override; + + /** + * Configure fixed-size texture for the specific index + * + * @param index index of the texture + * @param size width and height of the texture in pixels + * @param height height of the texture in pixels + * @param name unique name of the texture + * @param format color format + */ + void setTexture(u8 index, core::dimension2du size, const std::string& name, video::ECOLOR_FORMAT format); + + /** + * Configure relative-size texture for the specific index + * + * @param index index of the texture + * @param scale_factor relation of the texture dimensions to the screen dimensions + * @param name unique name of the texture + * @param format color format + */ + void setTexture(u8 index, v2f scale_factor, const std::string& name, video::ECOLOR_FORMAT format); + + /** + * @Configure depth texture and assign index + * + * @param index index to use for the depth texture + * @param size width and height of the texture in pixels + * @param name unique name for the texture + * @param format color format + */ + void setDepthTexture(u8 index, core::dimension2du size, const std::string& name, video::ECOLOR_FORMAT format); + + /** + * @Configure depth texture and assign index + * + * @param index index to use for the depth texture + * @param scale_factor relation of the texture dimensions to the screen dimensions + * @param name unique name for the texture + * @param format color format + */ + void setDepthTexture(u8 index, v2f scale_factor, const std::string& name, video::ECOLOR_FORMAT format); + + virtual u8 getTextureCount() override { return m_textures.size(); } + virtual video::ITexture *getTexture(u8 index) override; + virtual void activate(PipelineContext &context) override; + virtual void reset(PipelineContext &context) override; +private: + static const u8 NO_DEPTH_TEXTURE = 255; + + struct TextureDefinition + { + bool valid { false }; + bool fixed_size { false }; + bool dirty { false }; + v2f scale_factor; + core::dimension2du size; + std::string name; + video::ECOLOR_FORMAT format; + }; + + /** + * Make sure the texture in the given slot matches the texture definition given the current context. + * @param textureSlot address of the texture pointer to verify and populate. + * @param definition logical definition of the texture + * @param context current context of the rendering pipeline + * @return true if a new texture was created and put into the slot + * @return false if the slot was not modified + */ + bool ensureTexture(video::ITexture **textureSlot, const TextureDefinition& definition, PipelineContext &context); + + video::IVideoDriver *m_driver { nullptr }; + std::vector m_definitions; + core::array m_textures; + video::ITexture *m_depth_texture { nullptr }; + u8 m_depth_texture_index { NO_DEPTH_TEXTURE }; + video::IRenderTarget *m_render_target { nullptr }; +}; + +/** + * Targets output to designated texture in texture buffer + */ +class TextureBufferOutput : public RenderTarget +{ +public: + TextureBufferOutput(TextureBuffer *buffer, u8 texture_index); + void activate(PipelineContext &context) override; +private: + TextureBuffer *buffer; + u8 texture_index; +}; + +/** + * Allows remapping texture indicies in another RenderSource. + * + * @note all unmapped indexes are passed through to the underlying render source. + */ +class RemappingSource : RenderSource +{ +public: + RemappingSource(RenderSource *source) + : m_source(source) + {} + + /** + * Maps texture index to a different index in the dependent source. + * + * @param index texture index as requested by the @see RenderStep. + * @param target_index matching texture index in the underlying @see RenderSource. + */ + void setMapping(u8 index, u8 target_index) + { + if (index >= m_mappings.size()) { + u8 start = m_mappings.size(); + m_mappings.resize(index); + for (u8 i = start; i < m_mappings.size(); ++i) + m_mappings[i] = i; + } + + m_mappings[index] = target_index; + } + + virtual u8 getTextureCount() override + { + return m_mappings.size(); + } + + virtual video::ITexture *getTexture(u8 index) override + { + if (index < m_mappings.size()) + index = m_mappings[index]; + + return m_source->getTexture(index); + } +public: + RenderSource *m_source; + std::vector m_mappings; +}; + +class DynamicSource : public RenderSource +{ +public: + bool isConfigured() { return upstream != nullptr; } + void setRenderSource(RenderSource *value) { upstream = value; } + + /** + * Return the number of textures in the source. + */ + virtual u8 getTextureCount() override; + + /** + * Get a texture by index. + * Returns nullptr is the texture does not exist. + */ + virtual video::ITexture *getTexture(u8 index) override; +private: + RenderSource *upstream { nullptr }; +}; + +/** + * Implements direct output to screen framebuffer. + */ +class ScreenTarget : public RenderTarget +{ +public: + virtual void activate(PipelineContext &context) override; + virtual void reset(PipelineContext &context) override; +private: + core::dimension2du size; +}; + +class DynamicTarget : public RenderTarget +{ +public: + bool isConfigured() { return upstream != nullptr; } + void setRenderTarget(RenderTarget *value) { upstream = value; } + virtual void activate(PipelineContext &context) override; +private: + RenderTarget *upstream { nullptr }; +}; + +/** + * Base class for rendering steps in the pipeline + */ +class RenderStep : virtual public RenderPipelineObject +{ +public: + /** + * Assigns render source to this step. + * + * @param source source of rendering information + */ + virtual void setRenderSource(RenderSource *source) = 0; + + /** + * Assigned render target to this step. + * + * @param target render target to send output to. + */ + virtual void setRenderTarget(RenderTarget *target) = 0; + + /** + * Runs the step. This method is invoked by the pipeline. + */ + virtual void run(PipelineContext &context) = 0; +}; + +/** + * Provides default empty implementation of supporting methods in a rendering step. + */ +class TrivialRenderStep : public RenderStep +{ +public: + virtual void setRenderSource(RenderSource *source) override {} + virtual void setRenderTarget(RenderTarget *target) override {} + virtual void reset(PipelineContext &) override {} +}; + +/** + * Dynamically changes render target of another step. + * + * This allows re-running parts of the pipeline with different outputs + */ +class SetRenderTargetStep : public TrivialRenderStep +{ +public: + SetRenderTargetStep(RenderStep *step, RenderTarget *target); + virtual void run(PipelineContext &context) override; +private: + RenderStep *step; + RenderTarget *target; +}; + +/** + * Render Pipeline provides a flexible way to execute rendering steps in the engine. + * + * RenderPipeline also implements @see RenderStep, allowing for nesting of the pipelines. + */ +class RenderPipeline : public RenderStep +{ +public: + /** + * Add a step to the end of the pipeline + * + * @param step reference to a @see RenderStep implementation. + */ + RenderStep *addStep(RenderStep *step) + { + m_pipeline.push_back(step); + return step; + } + + /** + * Capture ownership of a dynamically created @see RenderStep instance. + * + * RenderPipeline will delete the instance when the pipeline is destroyed. + * + * @param step reference to the instance. + * @return RenderStep* value of the 'step' parameter. + */ + template + T *own(std::unique_ptr &&object) + { + T* result = object.release(); + m_objects.push_back(std::unique_ptr(result)); + return result; + } + + /** + * Create a new object that will be managed by the pipeline + * + * @tparam T type of the object to be created + * @tparam Args types of constructor arguments + * @param args constructor arguments + * @return T* pointer to the newly created object + */ + template + T *createOwned(Args&&... args) { + return own(std::make_unique(std::forward(args)...)); + } + + /** + * Create and add a step managed by the pipeline and return a pointer + * to the step for further configuration. + * + * @tparam T Type of the step to be added. + * @tparam Args Types of the constructor parameters + * @param args Constructor parameters + * @return RenderStep* Pointer to the created step for further configuration. + */ + template + RenderStep *addStep(Args&&... args) { + T* result = own(std::make_unique(std::forward(args)...)); + return addStep(result); + } + + RenderSource *getInput(); + RenderTarget *getOutput(); + + v2f getScale() { return scale; } + void setScale(v2f value) { scale = value; } + + virtual void reset(PipelineContext &context) override {} + virtual void run(PipelineContext &context) override; + + virtual void setRenderSource(RenderSource *source) override; + virtual void setRenderTarget(RenderTarget *target) override; +private: + std::vector m_pipeline; + std::vector< std::unique_ptr > m_objects; + DynamicSource m_input; + DynamicTarget m_output; + v2f scale { 1.0f, 1.0f }; +};