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 "client/client.h"
22 #include "client/hud.h"
28 TextureBuffer::~TextureBuffer()
30 for (u32 index = 0; index < m_textures.size(); index++)
31 m_driver->removeTexture(m_textures[index]);
35 video::ITexture *TextureBuffer::getTexture(u8 index)
37 if (index >= m_textures.size())
39 return m_textures[index];
43 void TextureBuffer::setTexture(u8 index, core::dimension2du size, const std::string &name, video::ECOLOR_FORMAT format, bool clear)
45 assert(index != NO_DEPTH_TEXTURE);
47 if (m_definitions.size() <= index)
48 m_definitions.resize(index + 1);
50 auto &definition = m_definitions[index];
51 definition.valid = true;
52 definition.dirty = true;
53 definition.fixed_size = true;
54 definition.size = size;
55 definition.name = name;
56 definition.format = format;
57 definition.clear = clear;
60 void TextureBuffer::setTexture(u8 index, v2f scale_factor, const std::string &name, video::ECOLOR_FORMAT format, bool clear)
62 assert(index != NO_DEPTH_TEXTURE);
64 if (m_definitions.size() <= index)
65 m_definitions.resize(index + 1);
67 auto &definition = m_definitions[index];
68 definition.valid = true;
69 definition.dirty = true;
70 definition.fixed_size = false;
71 definition.scale_factor = scale_factor;
72 definition.name = name;
73 definition.format = format;
74 definition.clear = clear;
77 void TextureBuffer::reset(PipelineContext &context)
80 m_driver = context.device->getVideoDriver();
82 // remove extra textures
83 if (m_textures.size() > m_definitions.size()) {
84 for (unsigned i = m_definitions.size(); i < m_textures.size(); i++)
86 m_driver->removeTexture(m_textures[i]);
88 m_textures.set_used(m_definitions.size());
91 // add placeholders for new definitions
92 while (m_textures.size() < m_definitions.size())
93 m_textures.push_back(nullptr);
95 // change textures to match definitions
96 for (u32 i = 0; i < m_definitions.size(); i++) {
97 video::ITexture **ptr = &m_textures[i];
99 ensureTexture(ptr, m_definitions[i], context);
100 m_definitions[i].dirty = false;
103 RenderSource::reset(context);
106 void TextureBuffer::swapTextures(u8 texture_a, u8 texture_b)
108 assert(m_definitions[texture_a].valid && m_definitions[texture_b].valid);
110 video::ITexture *temp = m_textures[texture_a];
111 m_textures[texture_a] = m_textures[texture_b];
112 m_textures[texture_b] = temp;
116 bool TextureBuffer::ensureTexture(video::ITexture **texture, const TextureDefinition& definition, PipelineContext &context)
119 core::dimension2du size;
120 if (definition.valid) {
121 if (definition.fixed_size)
122 size = definition.size;
124 size = core::dimension2du(
125 (u32)(context.target_size.X * definition.scale_factor.X),
126 (u32)(context.target_size.Y * definition.scale_factor.Y));
128 modify = definition.dirty || (*texture == nullptr) || (*texture)->getSize() != size;
131 modify = (*texture != nullptr);
138 m_driver->removeTexture(*texture);
140 if (definition.valid) {
141 if (definition.clear) {
142 video::IImage *image = m_driver->createImage(definition.format, size);
144 *texture = m_driver->addTexture(definition.name.c_str(), image);
148 *texture = m_driver->addRenderTargetTexture(size, definition.name.c_str(), definition.format);
158 TextureBufferOutput::TextureBufferOutput(TextureBuffer *_buffer, u8 _texture_index)
159 : buffer(_buffer), texture_map({_texture_index})
162 TextureBufferOutput::TextureBufferOutput(TextureBuffer *_buffer, const std::vector<u8> &_texture_map)
163 : buffer(_buffer), texture_map(_texture_map)
166 TextureBufferOutput::TextureBufferOutput(TextureBuffer *_buffer, const std::vector<u8> &_texture_map, u8 _depth_stencil)
167 : buffer(_buffer), texture_map(_texture_map), depth_stencil(_depth_stencil)
170 TextureBufferOutput::~TextureBufferOutput()
172 if (render_target && driver)
173 driver->removeRenderTarget(render_target);
176 void TextureBufferOutput::activate(PipelineContext &context)
179 driver = context.device->getVideoDriver();
182 render_target = driver->addRenderTarget();
184 core::array<video::ITexture *> textures;
185 core::dimension2du size(0, 0);
186 for (size_t i = 0; i < texture_map.size(); i++) {
187 video::ITexture *texture = buffer->getTexture(texture_map[i]);
188 textures.push_back(texture);
189 if (texture && size.Width == 0)
190 size = texture->getSize();
193 // Use legacy call when there's single texture without depth texture
194 // This binds default depth buffer to the FBO
195 if (textures.size() == 1 && depth_stencil == NO_DEPTH_TEXTURE) {
196 driver->setRenderTarget(textures[0], m_clear, m_clear, context.clear_color);
200 video::ITexture *depth_texture = nullptr;
201 if (depth_stencil != NO_DEPTH_TEXTURE)
202 depth_texture = buffer->getTexture(depth_stencil);
204 render_target->setTexture(textures, depth_texture);
206 driver->setRenderTargetEx(render_target, m_clear ? video::ECBF_ALL : video::ECBF_NONE, context.clear_color);
207 driver->OnResize(size);
209 RenderTarget::activate(context);
212 u8 DynamicSource::getTextureCount()
214 assert(isConfigured());
215 return upstream->getTextureCount();
218 video::ITexture *DynamicSource::getTexture(u8 index)
220 assert(isConfigured());
221 return upstream->getTexture(index);
224 void ScreenTarget::activate(PipelineContext &context)
226 auto driver = context.device->getVideoDriver();
227 driver->setRenderTarget(nullptr, m_clear, m_clear, context.clear_color);
228 driver->OnResize(size);
229 RenderTarget::activate(context);
232 void DynamicTarget::activate(PipelineContext &context)
235 throw std::logic_error("Dynamic render target is not configured before activation.");
236 upstream->activate(context);
239 void ScreenTarget::reset(PipelineContext &context)
241 RenderTarget::reset(context);
242 size = context.device->getVideoDriver()->getScreenSize();
245 SetRenderTargetStep::SetRenderTargetStep(RenderStep *_step, RenderTarget *_target)
246 : step(_step), target(_target)
250 void SetRenderTargetStep::run(PipelineContext &context)
252 step->setRenderTarget(target);
255 SwapTexturesStep::SwapTexturesStep(TextureBuffer *_buffer, u8 _texture_a, u8 _texture_b)
256 : buffer(_buffer), texture_a(_texture_a), texture_b(_texture_b)
260 void SwapTexturesStep::run(PipelineContext &context)
262 buffer->swapTextures(texture_a, texture_b);
265 RenderSource *RenderPipeline::getInput()
270 RenderTarget *RenderPipeline::getOutput()
275 void RenderPipeline::run(PipelineContext &context)
277 v2u32 original_size = context.target_size;
278 context.target_size = v2u32(original_size.X * scale.X, original_size.Y * scale.Y);
280 for (auto &object : m_objects)
281 object->reset(context);
283 for (auto &step: m_pipeline)
286 context.target_size = original_size;
289 void RenderPipeline::setRenderSource(RenderSource *source)
291 m_input.setRenderSource(source);
294 void RenderPipeline::setRenderTarget(RenderTarget *target)
296 m_output.setRenderTarget(target);