lxgui
Loading...
Searching...
No Matches
gui_renderer.cpp
1#include "lxgui/gui_renderer.hpp"
2
3#include "lxgui/gui_atlas.hpp"
4#include "lxgui/gui_out.hpp"
5#include "lxgui/gui_quad.hpp"
6#include "lxgui/gui_render_target.hpp"
7#include "lxgui/utils_string.hpp"
8
9namespace lxgui::gui {
10
11void renderer::begin(std::shared_ptr<render_target> target) {
13 current_material_ = nullptr;
14
16 try {
17 if (quad_cache_[0].cache == nullptr) {
18 for (std::size_t index = 0u; index < batching_cache_cycle_size; ++index) {
19 quad_cache_[index].cache = create_vertex_cache(vertex_cache::type::quads);
20 }
21 }
22 } catch (const std::exception& e) {
23 gui::out << gui::warning << e.what() << std::endl;
25 << "gui::renderer: Failed to create caches for quad batching. Vertex "
26 "caches will be disabled."
27 << std::endl;
28
29 vertex_cache_enabled_ = false;
30 }
31 }
32 }
33
34 begin_(std::move(target));
35}
36
40 }
41
42 end_();
43}
44
46 last_frame_batch_count_ = batch_count_;
47 last_frame_vertex_count_ = vertex_count_;
48 batch_count_ = 0;
49 vertex_count_ = 0;
50}
51
52std::size_t renderer::get_batch_count() const {
53 return last_frame_batch_count_;
54}
55
56std::size_t renderer::get_vertex_count() const {
57 return last_frame_vertex_count_;
58}
59
60void renderer::set_view(const matrix4f& view_matrix) {
63 }
64
65 set_view_(view_matrix);
66}
67
69 render_quads(q.mat.get(), {q.v});
70}
71
72bool renderer::uses_same_texture_(const material* mat1, const material* mat2) const {
73 if (mat1 == mat2)
74 return true;
75
76 if (mat1 && mat2 && mat1->uses_same_texture(*mat2))
77 return true;
78
80 if (mat1 && mat1->is_in_atlas() && !mat2)
81 return true;
82 if (mat2 && mat2->is_in_atlas() && !mat1)
83 return true;
84 }
85
86 return false;
87}
88
90 const material* mat, const std::vector<std::array<vertex, 4>>& quad_list) {
91 if (quad_list.empty())
92 return;
93
95 // Render immediately
96 vertex_count_ += quad_list.size() * 6;
97 render_quads_(mat, quad_list);
98 ++batch_count_;
99 return;
100 }
101
102 if (!uses_same_texture_(mat, current_material_)) {
103 // Render current batch and start a new one
105 current_material_ = mat;
106 }
107
108 if (quad_cache_[current_quad_cache_].data.empty()) {
109 // Start a new batch
110 current_material_ = mat;
111 }
112
113 if (!current_material_) {
114 // Previous quads had no material, override with the new one
115 current_material_ = mat;
116 }
117
118 // Add to the cache
119 auto& cache = quad_cache_[current_quad_cache_];
120
122 // To allow quads with no texture to enter the batch
123 // with atlas textures, we just change their UV coordinates
124 // to map to the first top-left pixel of the atlas, which is always white.
125 cache.data.reserve(cache.data.size() + quad_list.size());
126 for (const auto& orig_quad : quad_list) {
127 cache.data.push_back(orig_quad);
128 auto& quad = cache.data.back();
129 quad[0].uvs = quad[1].uvs = quad[2].uvs = quad[3].uvs = vector2f(0.0f, 0.0f);
130 }
131 } else {
132 cache.data.insert(cache.data.end(), quad_list.begin(), quad_list.end());
133 }
134}
135
137 auto& cache = quad_cache_[current_quad_cache_];
138 if (cache.data.empty())
139 return;
140
141 vertex_count_ += cache.data.size() * 6;
142
143 if (cache.cache) {
144 cache.cache->update(cache.data[0].data(), cache.data.size() * 4);
145 render_cache_(current_material_, *cache.cache, matrix4f::identity);
146 } else {
147 render_quads_(current_material_, cache.data);
148 }
149
150 cache.data.clear();
151 current_material_ = nullptr;
152
153 ++current_quad_cache_;
154 if (current_quad_cache_ == batching_cache_cycle_size)
155 current_quad_cache_ = 0u;
156
157 ++batch_count_;
158}
159
161 const material* mat, const vertex_cache& cache, const matrix4f& model_transform) {
164 }
165
166 vertex_count_ += cache.get_vertex_count();
167
168 render_cache_(mat, cache, model_transform);
169
170 ++batch_count_;
171}
172
174 return quad_batching_enabled_;
175}
176
178 quad_batching_enabled_ = enabled;
179}
180
181std::shared_ptr<gui::material>
182renderer::create_material(const std::string& file_name, material::filter filt) {
183 std::string backed_name = utils::to_string(static_cast<std::size_t>(filt)) + '|' + file_name;
184 auto iter = texture_list_.find(backed_name);
185 if (iter != texture_list_.end()) {
186 if (std::shared_ptr<gui::material> lock = iter->second.lock())
187 return lock;
188 else
189 texture_list_.erase(iter);
190 }
191
192 try {
193 std::shared_ptr<gui::material> tex = create_material_(file_name, filt);
194 texture_list_[file_name] = tex;
195 return tex;
196 } catch (const std::exception& e) {
197 gui::out << gui::warning << e.what() << std::endl;
198 return nullptr;
199 }
200}
201
202namespace {
203std::string hash_font_parameters(
204 const std::string& font_file,
205 std::size_t size,
206 std::size_t outline,
207 const std::vector<code_point_range>& code_points,
208 char32_t default_code_point) {
209 std::string font_name = font_file + "|s" + utils::to_string(size);
210 if (outline > 0u)
211 font_name += "|o" + utils::to_string(outline);
212
213 for (const code_point_range& range : code_points)
214 font_name += "|c" + utils::to_string(range.first) + "-" + utils::to_string(range.last);
215
216 font_name += "|d" + utils::to_string(default_code_point);
217
218 return font_name;
219}
220} // namespace
221
222std::shared_ptr<gui::font> renderer::create_font(
223 const std::string& font_file,
224 std::size_t size,
225 std::size_t outline,
226 const std::vector<code_point_range>& code_points,
227 char32_t default_code_point) {
228 const std::string font_name =
229 hash_font_parameters(font_file, size, outline, code_points, default_code_point);
230
231 auto iter = font_list_.find(font_name);
232 if (iter != font_list_.end()) {
233 if (std::shared_ptr<gui::font> lock = iter->second.lock())
234 return lock;
235 else
236 font_list_.erase(iter);
237 }
238
239 std::shared_ptr<gui::font> fnt =
240 create_font_(font_file, size, outline, code_points, default_code_point);
241
242 font_list_[font_name] = fnt;
243 return fnt;
244}
245
247 return texture_atlas_enabled_ && is_texture_atlas_supported();
248}
249
251 texture_atlas_enabled_ = enabled;
252}
253
255 if (texture_atlas_page_size_ == 0u)
256 return std::min<std::size_t>(4096u, get_texture_max_size());
257 else
258 return texture_atlas_page_size_;
259}
260
261void renderer::set_texture_atlas_page_size(std::size_t page_size) {
262 texture_atlas_page_size_ = page_size;
263}
264
266 std::size_t count = 0;
267
268 for (const auto& page : atlas_list_) {
269 count += page.second->get_page_count();
270 }
271
272 return count;
273}
274
276 return vertex_cache_enabled_ && is_vertex_cache_supported();
277}
278
280 vertex_cache_enabled_ = enabled;
281}
282
284 vertex_cache_enabled_ = true;
285 texture_atlas_enabled_ = true;
286 quad_batching_enabled_ = true;
287}
288
289atlas& renderer::get_atlas_(const std::string& atlas_category, material::filter filt) {
290 std::shared_ptr<gui::atlas> atlas;
291
292 std::string baked_atlas_name =
293 utils::to_string(static_cast<std::size_t>(filt)) + '|' + atlas_category;
294 auto iter = atlas_list_.find(baked_atlas_name);
295 if (iter != atlas_list_.end()) {
296 atlas = iter->second;
297 }
298
299 if (!atlas) {
300 atlas = create_atlas_(filt);
301 atlas_list_[baked_atlas_name] = atlas;
302 }
303
304 return *atlas;
305}
306
307std::shared_ptr<material> renderer::create_atlas_material(
308 const std::string& atlas_category, const std::string& file_name, material::filter filt) {
310 return create_material(file_name, filt);
311
312 auto& atlas = get_atlas_(atlas_category, filt);
313
314 auto tex = atlas.fetch_material(file_name);
315 if (tex)
316 return tex;
317
318 tex = create_material(file_name, filt);
319 if (!tex)
320 return nullptr;
321
322 auto added_tex = atlas.add_material(file_name, *tex);
323 if (added_tex)
324 return added_tex;
325 else
326 return tex;
327}
328
329std::shared_ptr<font> renderer::create_atlas_font(
330 const std::string& atlas_category,
331 const std::string& font_file,
332 std::size_t size,
333 std::size_t outline,
334 const std::vector<code_point_range>& code_points,
335 char32_t default_code_point) {
337 return create_font(font_file, size, outline, code_points, default_code_point);
338
339 auto& atlas = get_atlas_(atlas_category, material::filter::none);
340
341 const std::string font_name =
342 hash_font_parameters(font_file, size, outline, code_points, default_code_point);
343
344 auto fnt = atlas.fetch_font(font_name);
345 if (fnt)
346 return fnt;
347
348 fnt = create_font(font_file, size, outline, code_points, default_code_point);
349 if (!fnt)
350 return nullptr;
351
352 if (atlas.add_font(font_name, fnt))
353 return fnt;
354
355 font_list_[font_name] = fnt;
356 return fnt;
357}
358
359std::shared_ptr<material> renderer::create_material(std::shared_ptr<render_target> target) {
360 const auto& rect = target->get_rect();
361 return create_material(std::move(target), rect);
362}
363
365
366} // namespace lxgui::gui
A class that holds multiple materials for efficient rendering.
std::shared_ptr< material > add_material(const std::string &file_name, const material &mat)
Add a new material to the atlas.
bool add_font(const std::string &font_name, std::shared_ptr< gui::font > fnt)
Add a new font to the atlas.
std::shared_ptr< material > fetch_material(const std::string &file_name) const
Find a material in this atlas (nullptr if not found).
std::shared_ptr< font > fetch_font(const std::string &font_name) const
Find a font in this atlas (nullptr if not found).
A class that holds rendering data.
virtual bool uses_same_texture(const material &other) const =0
Checks if another material is based on the same texture as the current material.
bool is_in_atlas() const
Checks if the material is embedded in an atlas.
bool is_quad_batching_enabled() const
Checks if the renderer has quad render batching enabled.
std::shared_ptr< material > create_atlas_material(const std::string &atlas_category, const std::string &file_name, material::filter filt=material::filter::none)
Creates a new material from a texture file.
std::size_t get_batch_count() const
Returns the number of batches of vertices sent to the GPU since the last call to reset_counters.
std::shared_ptr< font > create_atlas_font(const std::string &atlas_category, const std::string &font_file, std::size_t size, std::size_t outline, const std::vector< code_point_range > &code_points, char32_t default_code_point)
Creates a new font.
virtual std::shared_ptr< atlas > create_atlas_(material::filter filt)=0
Creates a new atlas with a given texture filter mode.
std::size_t get_texture_atlas_page_size() const
Returns the width/height of a texture atlas page (in pixels).
virtual std::shared_ptr< vertex_cache > create_vertex_cache(gui::vertex_cache::type type)=0
Creates a new empty vertex cache.
virtual std::shared_ptr< material > create_material_(const std::string &file_name, material::filter filt)=0
Creates a new material from a texture file.
bool is_texture_atlas_enabled() const
Checks if the renderer has texture atlases enabled.
void render_quad(const quad &q)
Renders a quad.
void set_view(const matrix4f &view_matrix)
Sets the view matrix to use when rendering (viewport).
void end()
Ends rendering.
virtual std::shared_ptr< font > create_font_(const std::string &font_file, std::size_t size, std::size_t outline, const std::vector< code_point_range > &code_points, char32_t default_code_point)=0
Creates a new font.
virtual bool is_texture_atlas_supported() const =0
Checks if the renderer supports texture atlases natively.
void render_cache(const material *mat, const vertex_cache &cache, const matrix4f &model_transform=matrix4f::identity)
Renders a vertex cache.
virtual void notify_window_resized(const vector2ui &dimensions)
Notifies the renderer that the render window has been resized.
std::size_t get_vertex_count() const
Returns the number of vertices sent to the GPU since the last call to reset_counters.
std::unordered_map< std::string, std::weak_ptr< gui::font > > font_list_
virtual void render_quads_(const material *mat, const std::vector< std::array< vertex, 4 > > &quad_list)=0
Renders a set of quads.
void auto_detect_settings()
Automatically determines the best rendering settings for the current platform.
std::size_t get_texture_atlas_page_count() const
Count the total number of texture atlas pages currently in use.
void set_texture_atlas_enabled(bool enabled)
Enables/disables texture atlases.
atlas & get_atlas_(const std::string &atlas_category, material::filter filt)
virtual bool is_vertex_cache_supported() const =0
Checks if the renderer supports vertex caches.
void render_quads(const material *mat, const std::vector< std::array< vertex, 4 > > &quad_list)
Renders a set of quads.
virtual std::size_t get_texture_max_size() const =0
Returns the maximum texture width/height (in pixels).
virtual void set_view_(const matrix4f &view_matrix)=0
Sets the view matrix to use when rendering (viewport).
void set_quad_batching_enabled(bool enabled)
Enables/disables quad batching.
void begin(std::shared_ptr< render_target > target=nullptr)
Begins rendering on a particular render target.
void set_texture_atlas_page_size(std::size_t page_size)
Set the width/height of a texture atlas page (in pixels).
virtual void end_()=0
Ends rendering.
std::unordered_map< std::string, std::weak_ptr< gui::material > > texture_list_
std::unordered_map< std::string, std::shared_ptr< gui::atlas > > atlas_list_
void reset_counters()
Resets the number of batches to zero (for analytics only).
void flush_quad_batch()
Flushes any pending quad batch render operation.
virtual bool is_texture_vertex_color_supported() const =0
Checks if the renderer supports setting colors for each vertex of a textured quad.
std::shared_ptr< font > create_font(const std::string &font_file, std::size_t size, std::size_t outline, const std::vector< code_point_range > &code_points, char32_t default_code_point)
Creates a new font.
bool is_vertex_cache_enabled() const
Checks if the renderer has enabled support for vertex caches.
void set_vertex_cache_enabled(bool enabled)
Enables/disables vertex caches.
virtual void render_cache_(const material *mat, const vertex_cache &cache, const matrix4f &model_transform)=0
Renders a vertex cache.
virtual void begin_(std::shared_ptr< render_target > target)=0
Begins rendering on a particular render target.
std::shared_ptr< material > create_material(const std::string &file_name, material::filter filt=material::filter::none)
Creates a new material from a texture file.
An object representing cached vertex data on the GPU.
@ quads
3 vertices per element
std::size_t get_vertex_count() const
Returns the number of vertices stored in this cache.
vector2< float > vector2f
Holds 2D coordinates (as floats)
std::ostream out
const std::string warning
Definition gui_out.cpp:6
Represents a contiguous range of unicode code points.
A 4x4 matrix, used for coordinate transformations.
static const matrix4f identity
Simple structure holding four vertices and a material.
Definition gui_quad.hpp:18
std::shared_ptr< material > mat
Definition gui_quad.hpp:20