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)
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;
59 void TextureBuffer::setTexture(u8 index, v2f scale_factor, const std::string &name, video::ECOLOR_FORMAT format)
61 assert(index != NO_DEPTH_TEXTURE);
63 if (m_definitions.size() <= index)
64 m_definitions.resize(index + 1);
66 auto &definition = m_definitions[index];
67 definition.valid = true;
68 definition.dirty = true;
69 definition.fixed_size = false;
70 definition.scale_factor = scale_factor;
71 definition.name = name;
72 definition.format = format;
75 void TextureBuffer::reset(PipelineContext &context)
78 m_driver = context.device->getVideoDriver();
80 // remove extra textures
81 if (m_textures.size() > m_definitions.size()) {
82 for (unsigned i = m_definitions.size(); i < m_textures.size(); i++)
84 m_driver->removeTexture(m_textures[i]);
86 m_textures.set_used(m_definitions.size());
89 // add placeholders for new definitions
90 while (m_textures.size() < m_definitions.size())
91 m_textures.push_back(nullptr);
93 // change textures to match definitions
94 for (u32 i = 0; i < m_definitions.size(); i++) {
95 video::ITexture **ptr = &m_textures[i];
97 ensureTexture(ptr, m_definitions[i], context);
98 m_definitions[i].dirty = false;
101 RenderSource::reset(context);
104 bool TextureBuffer::ensureTexture(video::ITexture **texture, const TextureDefinition& definition, PipelineContext &context)
107 core::dimension2du size;
108 if (definition.valid) {
109 if (definition.fixed_size)
110 size = definition.size;
112 size = core::dimension2du(
113 (u32)(context.target_size.X * definition.scale_factor.X),
114 (u32)(context.target_size.Y * definition.scale_factor.Y));
116 modify = definition.dirty || (*texture == nullptr) || (*texture)->getSize() != size;
119 modify = (*texture != nullptr);
126 m_driver->removeTexture(*texture);
128 if (definition.valid)
129 *texture = m_driver->addRenderTargetTexture(size, definition.name.c_str(), definition.format);
136 TextureBufferOutput::TextureBufferOutput(TextureBuffer *_buffer, u8 _texture_index)
137 : buffer(_buffer), texture_map({_texture_index})
140 TextureBufferOutput::TextureBufferOutput(TextureBuffer *_buffer, const std::vector<u8> &_texture_map)
141 : buffer(_buffer), texture_map(_texture_map)
144 TextureBufferOutput::TextureBufferOutput(TextureBuffer *_buffer, const std::vector<u8> &_texture_map, u8 _depth_stencil)
145 : buffer(_buffer), texture_map(_texture_map), depth_stencil(_depth_stencil)
148 TextureBufferOutput::~TextureBufferOutput()
150 if (render_target && driver)
151 driver->removeRenderTarget(render_target);
154 void TextureBufferOutput::activate(PipelineContext &context)
157 driver = context.device->getVideoDriver();
160 render_target = driver->addRenderTarget();
162 core::array<video::ITexture *> textures;
163 core::dimension2du size(0, 0);
164 for (size_t i = 0; i < texture_map.size(); i++) {
165 video::ITexture *texture = buffer->getTexture(texture_map[i]);
166 textures.push_back(texture);
167 if (texture && size.Width == 0)
168 size = texture->getSize();
171 // Use legacy call when there's single texture without depth texture
172 // This binds default depth buffer to the FBO
173 if (textures.size() == 1 && depth_stencil == NO_DEPTH_TEXTURE) {
174 driver->setRenderTarget(textures[0], m_clear, m_clear, context.clear_color);
178 video::ITexture *depth_texture = nullptr;
179 if (depth_stencil != NO_DEPTH_TEXTURE)
180 depth_texture = buffer->getTexture(depth_stencil);
182 render_target->setTexture(textures, depth_texture);
184 driver->setRenderTargetEx(render_target, m_clear ? video::ECBF_ALL : video::ECBF_NONE, context.clear_color);
185 driver->OnResize(size);
187 RenderTarget::activate(context);
190 u8 DynamicSource::getTextureCount()
192 assert(isConfigured());
193 return upstream->getTextureCount();
196 video::ITexture *DynamicSource::getTexture(u8 index)
198 assert(isConfigured());
199 return upstream->getTexture(index);
202 void ScreenTarget::activate(PipelineContext &context)
204 auto driver = context.device->getVideoDriver();
205 driver->setRenderTarget(nullptr, m_clear, m_clear, context.clear_color);
206 driver->OnResize(size);
207 RenderTarget::activate(context);
210 void DynamicTarget::activate(PipelineContext &context)
213 throw std::logic_error("Dynamic render target is not configured before activation.");
214 upstream->activate(context);
217 void ScreenTarget::reset(PipelineContext &context)
219 RenderTarget::reset(context);
220 size = context.device->getVideoDriver()->getScreenSize();
223 SetRenderTargetStep::SetRenderTargetStep(RenderStep *_step, RenderTarget *_target)
224 : step(_step), target(_target)
228 void SetRenderTargetStep::run(PipelineContext &context)
230 step->setRenderTarget(target);
233 RenderSource *RenderPipeline::getInput()
238 RenderTarget *RenderPipeline::getOutput()
243 void RenderPipeline::run(PipelineContext &context)
245 v2u32 original_size = context.target_size;
246 context.target_size = v2u32(original_size.X * scale.X, original_size.Y * scale.Y);
248 for (auto &object : m_objects)
249 object->reset(context);
251 for (auto &step: m_pipeline)
254 context.target_size = original_size;
257 void RenderPipeline::setRenderSource(RenderSource *source)
259 m_input.setRenderSource(source);
262 void RenderPipeline::setRenderTarget(RenderTarget *target)
264 m_output.setRenderTarget(target);