3 Copyright (C) 2022 x2048, Dmitry Kostenko <codeforsmile@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "irrlichttypes_extrabloated.h"
34 struct PipelineContext
36 PipelineContext(IrrlichtDevice *_device, Client *_client, Hud *_hud, ShadowRenderer *_shadow_renderer, video::SColor _color, v2u32 _target_size)
37 : device(_device), client(_client), hud(_hud), shadow_renderer(_shadow_renderer), clear_color(_color), target_size(_target_size)
41 IrrlichtDevice *device;
44 ShadowRenderer *shadow_renderer;
45 video::SColor clear_color;
49 bool show_minimap {true};
50 bool draw_wield_tool {true};
51 bool draw_crosshair {true};
55 * Base object that can be owned by RenderPipeline
58 class RenderPipelineObject
61 virtual ~RenderPipelineObject() = default;
62 virtual void reset(PipelineContext &context) {}
66 * Represents a source of rendering information such as textures
68 class RenderSource : virtual public RenderPipelineObject
72 * Return the number of textures in the source.
74 virtual u8 getTextureCount() = 0;
77 * Get a texture by index.
78 * Returns nullptr is the texture does not exist.
80 virtual video::ITexture *getTexture(u8 index) = 0;
84 * Represents a render target (screen or framebuffer)
86 class RenderTarget : virtual public RenderPipelineObject
90 * Activate the render target and configure OpenGL state for the output.
91 * This is usually done by @see RenderStep implementations.
93 virtual void activate(PipelineContext &context)
99 * Resets the state of the object for the next pipeline iteration
101 virtual void reset(PipelineContext &context) override
111 * Texture buffer represents a framebuffer with a multiple attached textures.
113 * @note Use of TextureBuffer requires use of gl_FragData[] in the shader
115 class TextureBuffer : public RenderSource
118 virtual ~TextureBuffer() override;
121 * Configure fixed-size texture for the specific index
123 * @param index index of the texture
124 * @param size width and height of the texture in pixels
125 * @param height height of the texture in pixels
126 * @param name unique name of the texture
127 * @param format color format
129 void setTexture(u8 index, core::dimension2du size, const std::string& name, video::ECOLOR_FORMAT format);
132 * Configure relative-size texture for the specific index
134 * @param index index of the texture
135 * @param scale_factor relation of the texture dimensions to the screen dimensions
136 * @param name unique name of the texture
137 * @param format color format
139 void setTexture(u8 index, v2f scale_factor, const std::string& name, video::ECOLOR_FORMAT format);
141 virtual u8 getTextureCount() override { return m_textures.size(); }
142 virtual video::ITexture *getTexture(u8 index) override;
143 virtual void reset(PipelineContext &context) override;
144 void swapTextures(u8 texture_a, u8 texture_b);
146 static const u8 NO_DEPTH_TEXTURE = 255;
148 struct TextureDefinition
150 bool valid { false };
151 bool fixed_size { false };
152 bool dirty { false };
154 core::dimension2du size;
156 video::ECOLOR_FORMAT format;
160 * Make sure the texture in the given slot matches the texture definition given the current context.
161 * @param textureSlot address of the texture pointer to verify and populate.
162 * @param definition logical definition of the texture
163 * @param context current context of the rendering pipeline
164 * @return true if a new texture was created and put into the slot
165 * @return false if the slot was not modified
167 bool ensureTexture(video::ITexture **textureSlot, const TextureDefinition& definition, PipelineContext &context);
169 video::IVideoDriver *m_driver { nullptr };
170 std::vector<TextureDefinition> m_definitions;
171 core::array<video::ITexture *> m_textures;
175 * Targets output to designated texture in texture buffer
177 class TextureBufferOutput : public RenderTarget
180 TextureBufferOutput(TextureBuffer *buffer, u8 texture_index);
181 TextureBufferOutput(TextureBuffer *buffer, const std::vector<u8> &texture_map);
182 TextureBufferOutput(TextureBuffer *buffer, const std::vector<u8> &texture_map, u8 depth_stencil);
183 virtual ~TextureBufferOutput() override;
184 void activate(PipelineContext &context) override;
186 static const u8 NO_DEPTH_TEXTURE = 255;
188 TextureBuffer *buffer;
189 std::vector<u8> texture_map;
190 u8 depth_stencil { NO_DEPTH_TEXTURE };
191 video::IRenderTarget* render_target { nullptr };
192 video::IVideoDriver* driver { nullptr };
196 * Allows remapping texture indicies in another RenderSource.
198 * @note all unmapped indexes are passed through to the underlying render source.
200 class RemappingSource : RenderSource
203 RemappingSource(RenderSource *source)
208 * Maps texture index to a different index in the dependent source.
210 * @param index texture index as requested by the @see RenderStep.
211 * @param target_index matching texture index in the underlying @see RenderSource.
213 void setMapping(u8 index, u8 target_index)
215 if (index >= m_mappings.size()) {
216 u8 start = m_mappings.size();
217 m_mappings.resize(index);
218 for (u8 i = start; i < m_mappings.size(); ++i)
222 m_mappings[index] = target_index;
225 virtual u8 getTextureCount() override
227 return m_mappings.size();
230 virtual video::ITexture *getTexture(u8 index) override
232 if (index < m_mappings.size())
233 index = m_mappings[index];
235 return m_source->getTexture(index);
238 RenderSource *m_source;
239 std::vector<u8> m_mappings;
242 class DynamicSource : public RenderSource
245 bool isConfigured() { return upstream != nullptr; }
246 void setRenderSource(RenderSource *value) { upstream = value; }
249 * Return the number of textures in the source.
251 virtual u8 getTextureCount() override;
254 * Get a texture by index.
255 * Returns nullptr is the texture does not exist.
257 virtual video::ITexture *getTexture(u8 index) override;
259 RenderSource *upstream { nullptr };
263 * Implements direct output to screen framebuffer.
265 class ScreenTarget : public RenderTarget
268 virtual void activate(PipelineContext &context) override;
269 virtual void reset(PipelineContext &context) override;
271 core::dimension2du size;
274 class DynamicTarget : public RenderTarget
277 bool isConfigured() { return upstream != nullptr; }
278 void setRenderTarget(RenderTarget *value) { upstream = value; }
279 virtual void activate(PipelineContext &context) override;
281 RenderTarget *upstream { nullptr };
285 * Base class for rendering steps in the pipeline
287 class RenderStep : virtual public RenderPipelineObject
291 * Assigns render source to this step.
293 * @param source source of rendering information
295 virtual void setRenderSource(RenderSource *source) = 0;
298 * Assigned render target to this step.
300 * @param target render target to send output to.
302 virtual void setRenderTarget(RenderTarget *target) = 0;
305 * Runs the step. This method is invoked by the pipeline.
307 virtual void run(PipelineContext &context) = 0;
311 * Provides default empty implementation of supporting methods in a rendering step.
313 class TrivialRenderStep : public RenderStep
316 virtual void setRenderSource(RenderSource *source) override {}
317 virtual void setRenderTarget(RenderTarget *target) override {}
318 virtual void reset(PipelineContext &) override {}
322 * Dynamically changes render target of another step.
324 * This allows re-running parts of the pipeline with different outputs
326 class SetRenderTargetStep : public TrivialRenderStep
329 SetRenderTargetStep(RenderStep *step, RenderTarget *target);
330 virtual void run(PipelineContext &context) override;
333 RenderTarget *target;
337 * Swaps two textures in the texture buffer.
340 class SwapTexturesStep : public TrivialRenderStep
343 SwapTexturesStep(TextureBuffer *buffer, u8 texture_a, u8 texture_b);
344 virtual void run(PipelineContext &context) override;
346 TextureBuffer *buffer;
352 * Render Pipeline provides a flexible way to execute rendering steps in the engine.
354 * RenderPipeline also implements @see RenderStep, allowing for nesting of the pipelines.
356 class RenderPipeline : public RenderStep
360 * Add a step to the end of the pipeline
362 * @param step reference to a @see RenderStep implementation.
364 RenderStep *addStep(RenderStep *step)
366 m_pipeline.push_back(step);
371 * Capture ownership of a dynamically created @see RenderStep instance.
373 * RenderPipeline will delete the instance when the pipeline is destroyed.
375 * @param step reference to the instance.
376 * @return RenderStep* value of the 'step' parameter.
379 T *own(std::unique_ptr<T> &&object)
381 T* result = object.release();
382 m_objects.push_back(std::unique_ptr<RenderPipelineObject>(result));
387 * Create a new object that will be managed by the pipeline
389 * @tparam T type of the object to be created
390 * @tparam Args types of constructor arguments
391 * @param args constructor arguments
392 * @return T* pointer to the newly created object
394 template<typename T, typename... Args>
395 T *createOwned(Args&&... args) {
396 return own(std::make_unique<T>(std::forward<Args>(args)...));
400 * Create and add a step managed by the pipeline and return a pointer
401 * to the step for further configuration.
403 * @tparam T Type of the step to be added.
404 * @tparam Args Types of the constructor parameters
405 * @param args Constructor parameters
406 * @return RenderStep* Pointer to the created step for further configuration.
408 template<typename T, typename... Args>
409 T *addStep(Args&&... args) {
410 T* result = own(std::make_unique<T>(std::forward<Args>(args)...));
415 RenderSource *getInput();
416 RenderTarget *getOutput();
418 v2f getScale() { return scale; }
419 void setScale(v2f value) { scale = value; }
421 virtual void reset(PipelineContext &context) override {}
422 virtual void run(PipelineContext &context) override;
424 virtual void setRenderSource(RenderSource *source) override;
425 virtual void setRenderTarget(RenderTarget *target) override;
427 std::vector<RenderStep *> m_pipeline;
428 std::vector< std::unique_ptr<RenderPipelineObject> > m_objects;
429 DynamicSource m_input;
430 DynamicTarget m_output;
431 v2f scale { 1.0f, 1.0f };