]> git.lizzy.rs Git - minetest.git/blob - src/client/render/pipeline.h
Clear exposure compensation state textures on creation (#13151)
[minetest.git] / src / client / render / pipeline.h
1 /*
2 Minetest
3 Copyright (C) 2022 x2048, Dmitry Kostenko <codeforsmile@gmail.com>
4
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.
9
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.
14
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.
18 */
19 #pragma once
20
21 #include "irrlichttypes_extrabloated.h"
22
23 #include <vector>
24 #include <memory>
25 #include <string>
26
27 class RenderSource;
28 class RenderTarget;
29 class RenderStep;
30 class Client;
31 class Hud;
32 class ShadowRenderer;
33
34 struct PipelineContext
35 {
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)
38         {
39         }
40
41         IrrlichtDevice *device;
42         Client *client;
43         Hud *hud;
44         ShadowRenderer *shadow_renderer;
45         video::SColor clear_color;
46         v2u32 target_size;
47
48         bool show_hud {true};
49         bool show_minimap {true};
50         bool draw_wield_tool {true};
51         bool draw_crosshair {true};
52 };
53
54 /**
55  * Base object that can be owned by RenderPipeline
56  *
57  */
58 class RenderPipelineObject
59 {
60 public:
61         virtual ~RenderPipelineObject() = default;
62         virtual void reset(PipelineContext &context) {}
63 };
64
65 /**
66  * Represents a source of rendering information such as textures
67  */
68 class RenderSource : virtual public RenderPipelineObject
69 {
70 public:
71         /**
72          * Return the number of textures in the source.
73          */
74         virtual u8 getTextureCount() = 0;
75
76         /**
77          * Get a texture by index.
78          * Returns nullptr is the texture does not exist.
79          */
80         virtual video::ITexture *getTexture(u8 index) = 0;
81 };
82
83 /**
84  *      Represents a render target (screen or framebuffer)
85  */
86 class RenderTarget : virtual public RenderPipelineObject
87 {
88 public:
89         /**
90          * Activate the render target and configure OpenGL state for the output.
91          * This is usually done by @see RenderStep implementations.
92          */
93         virtual void activate(PipelineContext &context)
94         {
95                 m_clear = false;
96         }
97
98         /**
99          * Resets the state of the object for the next pipeline iteration
100          */
101         virtual void reset(PipelineContext &context) override
102         {
103                 m_clear = true;
104         }
105
106 protected:
107         bool m_clear {true};
108 };
109
110 /**
111  * Texture buffer represents a framebuffer with a multiple attached textures.
112  *
113  * @note Use of TextureBuffer requires use of gl_FragData[] in the shader
114  */
115 class TextureBuffer : public RenderSource
116 {
117 public:
118         virtual ~TextureBuffer() override;
119
120         /**
121          * Configure fixed-size texture for the specific index
122          *
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
128          */
129         void setTexture(u8 index, core::dimension2du size, const std::string& name, video::ECOLOR_FORMAT format, bool clear = false);
130
131         /**
132          * Configure relative-size texture for the specific index
133          *
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
138          */
139         void setTexture(u8 index, v2f scale_factor, const std::string& name, video::ECOLOR_FORMAT format, bool clear = false);
140
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);
145 private:
146         static const u8 NO_DEPTH_TEXTURE = 255;
147
148         struct TextureDefinition
149         {
150                 bool valid { false };
151                 bool fixed_size { false };
152                 bool dirty { false };
153                 bool clear { false };
154                 v2f scale_factor;
155                 core::dimension2du size;
156                 std::string name;
157                 video::ECOLOR_FORMAT format;
158         };
159
160         /**
161          * Make sure the texture in the given slot matches the texture definition given the current context.
162          * @param textureSlot address of the texture pointer to verify and populate.
163          * @param definition logical definition of the texture
164          * @param context current context of the rendering pipeline
165          * @return true if a new texture was created and put into the slot
166          * @return false if the slot was not modified
167          */
168         bool ensureTexture(video::ITexture **textureSlot, const TextureDefinition& definition, PipelineContext &context);
169
170         video::IVideoDriver *m_driver { nullptr };
171         std::vector<TextureDefinition> m_definitions;
172         core::array<video::ITexture *> m_textures;
173 };
174
175 /**
176  * Targets output to designated texture in texture buffer
177  */
178 class TextureBufferOutput : public RenderTarget
179 {
180 public:
181         TextureBufferOutput(TextureBuffer *buffer, u8 texture_index);
182         TextureBufferOutput(TextureBuffer *buffer, const std::vector<u8> &texture_map);
183         TextureBufferOutput(TextureBuffer *buffer, const std::vector<u8> &texture_map, u8 depth_stencil);
184         virtual ~TextureBufferOutput() override;
185         void activate(PipelineContext &context) override;
186 private:
187         static const u8 NO_DEPTH_TEXTURE = 255;
188
189         TextureBuffer *buffer;
190         std::vector<u8> texture_map;
191         u8 depth_stencil { NO_DEPTH_TEXTURE };
192         video::IRenderTarget* render_target { nullptr };
193         video::IVideoDriver* driver { nullptr };
194 };
195
196 /**
197  * Allows remapping texture indicies in another RenderSource.
198  *
199  * @note all unmapped indexes are passed through to the underlying render source.
200  */
201 class RemappingSource : RenderSource
202 {
203 public:
204         RemappingSource(RenderSource *source)
205                         : m_source(source)
206         {}
207
208         /**
209          * Maps texture index to a different index in the dependent source.
210          *
211          * @param index texture index as requested by the @see RenderStep.
212          * @param target_index matching texture index in the underlying @see RenderSource.
213          */
214         void setMapping(u8 index, u8 target_index)
215         {
216                 if (index >= m_mappings.size()) {
217                         u8 start = m_mappings.size();
218                         m_mappings.resize(index);
219                         for (u8 i = start; i < m_mappings.size(); ++i)
220                                 m_mappings[i] = i;
221                 }
222
223                 m_mappings[index] = target_index;
224         }
225
226         virtual u8 getTextureCount() override
227         {
228                 return m_mappings.size();
229         }
230
231         virtual video::ITexture *getTexture(u8 index) override
232         {
233                 if (index < m_mappings.size())
234                         index = m_mappings[index];
235
236                 return m_source->getTexture(index);
237         }
238 public:
239         RenderSource *m_source;
240         std::vector<u8> m_mappings;
241 };
242
243 class DynamicSource : public RenderSource
244 {
245 public:
246         bool isConfigured() { return upstream != nullptr; }
247         void setRenderSource(RenderSource *value) { upstream = value; }
248
249         /**
250          * Return the number of textures in the source.
251          */
252         virtual u8 getTextureCount() override;
253
254         /**
255          * Get a texture by index.
256          * Returns nullptr is the texture does not exist.
257          */
258         virtual video::ITexture *getTexture(u8 index) override;
259 private:
260         RenderSource *upstream { nullptr };
261 };
262
263 /**
264  * Implements direct output to screen framebuffer.
265  */
266 class ScreenTarget : public RenderTarget
267 {
268 public:
269         virtual void activate(PipelineContext &context) override;
270         virtual void reset(PipelineContext &context) override;
271 private:
272         core::dimension2du size;
273 };
274
275 class DynamicTarget : public RenderTarget
276 {
277 public:
278         bool isConfigured() { return upstream != nullptr; }
279         void setRenderTarget(RenderTarget *value) { upstream = value; }
280         virtual void activate(PipelineContext &context) override;
281 private:
282         RenderTarget *upstream { nullptr };
283 };
284
285 /**
286  * Base class for rendering steps in the pipeline
287  */
288 class RenderStep : virtual public RenderPipelineObject
289 {
290 public:
291         /**
292          * Assigns render source to this step.
293          *
294          * @param source source of rendering information
295          */
296         virtual void setRenderSource(RenderSource *source) = 0;
297
298         /**
299          * Assigned render target to this step.
300          *
301          * @param target render target to send output to.
302          */
303         virtual void setRenderTarget(RenderTarget *target) = 0;
304
305         /**
306          * Runs the step. This method is invoked by the pipeline.
307          */
308         virtual void run(PipelineContext &context) = 0;
309 };
310
311 /**
312  * Provides default empty implementation of supporting methods in a rendering step.
313  */
314 class TrivialRenderStep : public RenderStep
315 {
316 public:
317         virtual void setRenderSource(RenderSource *source) override {}
318         virtual void setRenderTarget(RenderTarget *target) override {}
319         virtual void reset(PipelineContext &) override {}
320 };
321
322 /**
323  * Dynamically changes render target of another step.
324  *
325  * This allows re-running parts of the pipeline with different outputs
326  */
327 class SetRenderTargetStep : public TrivialRenderStep
328 {
329 public:
330         SetRenderTargetStep(RenderStep *step, RenderTarget *target);
331         virtual void run(PipelineContext &context) override;
332 private:
333         RenderStep *step;
334         RenderTarget *target;
335 };
336
337 /**
338  * Swaps two textures in the texture buffer.
339  *
340  */
341 class SwapTexturesStep : public TrivialRenderStep
342 {
343 public:
344         SwapTexturesStep(TextureBuffer *buffer, u8 texture_a, u8 texture_b);
345         virtual void run(PipelineContext &context) override;
346 private:
347         TextureBuffer *buffer;
348         u8 texture_a;
349         u8 texture_b;
350 };
351
352 /**
353  * Render Pipeline provides a flexible way to execute rendering steps in the engine.
354  *
355  * RenderPipeline also implements @see RenderStep, allowing for nesting of the pipelines.
356  */
357 class RenderPipeline : public RenderStep
358 {
359 public:
360         /**
361          * Add a step to the end of the pipeline
362          *
363          * @param step reference to a @see RenderStep implementation.
364          */
365         RenderStep *addStep(RenderStep *step)
366         {
367                 m_pipeline.push_back(step);
368                 return step;
369         }
370
371         /**
372          * Capture ownership of a dynamically created @see RenderStep instance.
373          *
374          * RenderPipeline will delete the instance when the pipeline is destroyed.
375          *
376          * @param step reference to the instance.
377          * @return RenderStep* value of the 'step' parameter.
378          */
379         template<typename T>
380         T *own(std::unique_ptr<T> &&object)
381         {
382                 T* result = object.release();
383                 m_objects.push_back(std::unique_ptr<RenderPipelineObject>(result));
384                 return result;
385         }
386
387         /**
388          * Create a new object that will be managed by the pipeline
389          *
390          * @tparam T type of the object to be created
391          * @tparam Args types of constructor arguments
392          * @param args constructor arguments
393          * @return T* pointer to the newly created object
394          */
395         template<typename T, typename... Args>
396         T *createOwned(Args&&... args) {
397                 return own(std::make_unique<T>(std::forward<Args>(args)...));
398         }
399
400         /**
401          * Create and add a step managed by the pipeline and return a pointer
402          * to the step for further configuration.
403          *
404          * @tparam T Type of the step to be added.
405          * @tparam Args Types of the constructor parameters
406          * @param args Constructor parameters
407          * @return RenderStep* Pointer to the created step for further configuration.
408          */
409         template<typename T, typename... Args>
410         T *addStep(Args&&... args) {
411                 T* result = own(std::make_unique<T>(std::forward<Args>(args)...));
412                 addStep(result);
413                 return result;
414         }
415
416         RenderSource *getInput();
417         RenderTarget *getOutput();
418
419         v2f getScale() { return scale; }
420         void setScale(v2f value) { scale = value; }
421
422         virtual void reset(PipelineContext &context) override {}
423         virtual void run(PipelineContext &context) override;
424
425         virtual void setRenderSource(RenderSource *source) override;
426         virtual void setRenderTarget(RenderTarget *target) override;
427 private:
428         std::vector<RenderStep *> m_pipeline;
429         std::vector< std::unique_ptr<RenderPipelineObject> > m_objects;
430         DynamicSource m_input;
431         DynamicTarget m_output;
432         v2f scale { 1.0f, 1.0f };
433 };