lxgui
gui_texture.cpp
1 #include "lxgui/gui_texture.hpp"
2 
3 #include "lxgui/gui_layered_region.hpp"
4 #include "lxgui/gui_manager.hpp"
5 #include "lxgui/gui_material.hpp"
6 #include "lxgui/gui_out.hpp"
7 #include "lxgui/gui_region_tpl.hpp"
8 #include "lxgui/gui_render_target.hpp"
9 #include "lxgui/gui_renderer.hpp"
10 #include "lxgui/utils_file_system.hpp"
11 
12 #include <sstream>
13 
14 namespace lxgui::gui {
15 
16 texture::texture(utils::control_block& block, manager& mgr, const region_core_attributes& attr) :
17  layered_region(block, mgr, attr), renderer_(mgr.get_renderer()) {
18 
19  initialize_(*this, attr);
20 }
21 
22 std::string texture::serialize(const std::string& tab) const {
23  std::ostringstream str;
24  str << base::serialize(tab);
25 
26  std::visit(
27  [&](const auto& data) {
28  using content_type = std::decay_t<decltype(data)>;
29 
30  if constexpr (std::is_same_v<content_type, std::string>) {
31  str << tab << " # File : " << data << "\n";
32  } else if constexpr (std::is_same_v<content_type, gradient>) {
33  str << tab << " # Gradient :\n";
34  str << tab << " #-###\n";
35  str << tab << " | # min color : " << data.min_color << "\n";
36  str << tab << " | # max color : " << data.max_color << "\n";
37  str << tab << " | # orientation: " << utils::to_string(data.orient) << "\n";
38  str << tab << " #-###\n";
39  } else if constexpr (std::is_same_v<content_type, color>) {
40  str << tab << " # Color : " << data << "\n";
41  }
42  },
43  content_);
44 
45  str << tab << " # Tex. coord. :\n";
46  str << tab << " #-###\n";
47  str << tab << " | # top-left : (" << quad_.v[0].uvs << ")\n";
48  str << tab << " | # top-right : (" << quad_.v[1].uvs << ")\n";
49  str << tab << " | # bottom-right: (" << quad_.v[2].uvs << ")\n";
50  str << tab << " | # bottom-left : (" << quad_.v[3].uvs << ")\n";
51  str << tab << " #-###\n";
52  str << tab << " # Stretching: " << is_texture_stretching_enabled_ << "\n";
53  str << tab << " # Blend mode : " << utils::to_string(blend_mode_) << "\n";
54  str << tab << " # Filter : " << utils::to_string(filter_) << "\n";
55  str << tab << " # Desaturated: " << is_desaturated_ << "\n";
56 
57  return str.str();
58 }
59 
60 void texture::render() const {
61  base::render();
62 
63  if (!is_visible())
64  return;
65 
66  float alpha = get_effective_alpha();
67 
68  if (alpha != 1.0f) {
69  quad blended_quad = quad_;
70  for (std::size_t i = 0; i < 4; ++i)
71  blended_quad.v[i].col.a *= alpha;
72 
73  renderer_.render_quad(blended_quad);
74  } else {
75  renderer_.render_quad(quad_);
76  }
77 }
78 
79 void texture::copy_from(const region& obj) {
80  base::copy_from(obj);
81 
82  const texture* tex_obj = down_cast<texture>(&obj);
83  if (!tex_obj)
84  return;
85 
86  if (tex_obj->has_texture_file())
87  this->set_texture(tex_obj->get_texture_file());
88  else if (tex_obj->has_gradient())
89  this->set_gradient(tex_obj->get_gradient());
90  else if (tex_obj->has_solid_color())
91  this->set_solid_color(tex_obj->get_solid_color());
92 
93  this->set_blend_mode(tex_obj->get_blend_mode());
94  this->set_tex_coord(tex_obj->get_tex_coord());
96  this->set_desaturated(tex_obj->is_desaturated());
97 }
98 
100  return blend_mode_;
101 }
102 
104  return filter_;
105 }
106 
108  return std::holds_alternative<color>(content_);
109 }
110 
112  return std::get<color>(content_);
113 }
114 
115 bool texture::has_gradient() const {
116  return std::holds_alternative<gradient>(content_);
117 }
118 
120  return std::get<gradient>(content_);
121 }
122 
123 std::array<float, 8> texture::get_tex_coord() const {
124  std::array<float, 8> coords{};
125 
126  if (quad_.mat) {
127  for (std::size_t i = 0; i < 4; ++i) {
128  const vector2f uv = quad_.mat->get_local_uv(quad_.v[i].uvs, true);
129  coords[2 * i + 0] = uv.x;
130  coords[2 * i + 1] = uv.y;
131  }
132  } else {
133  for (std::size_t i = 0; i < 4; ++i) {
134  coords[2 * i + 0] = quad_.v[i].uvs.x;
135  coords[2 * i + 1] = quad_.v[i].uvs.y;
136  }
137  }
138 
139  return coords;
140 }
141 
143  return is_texture_stretching_enabled_;
144 }
145 
147  return std::holds_alternative<std::string>(content_);
148 }
149 
150 const std::string& texture::get_texture_file() const {
151  return std::get<std::string>(content_);
152 }
153 
154 color texture::get_vertex_color(std::size_t index) const {
155  if (index >= 4) {
156  gui::out << gui::error << "gui::" << get_region_type() << ": "
157  << "Vertex index out of bound (" << index << ")." << std::endl;
158  return color::white;
159  }
160 
161  return quad_.v[index].col;
162 }
163 
165  return is_desaturated_;
166 }
167 
169  if (mode != blend_mode::blend) {
170  gui::out << gui::warning << "gui::" << get_region_type() << ": "
171  << "texture::set_blend_mode other than \"BLEND\" is not yet implemented."
172  << std::endl;
173  return;
174  }
175 
176  if (blend_mode_ == mode)
177  return;
178 
179  blend_mode_ = mode;
180 
182 }
183 
185  if (filter_ == filt)
186  return;
187 
188  filter_ = filt;
189 
190  if (std::holds_alternative<std::string>(content_)) {
191  // Force re-load of the material
192  std::string file_name = std::get<std::string>(content_);
193  content_ = std::string{};
194  set_texture(file_name);
195  }
196 }
197 
198 void texture::set_desaturated(bool is_desaturated) {
199  if (is_desaturated_ == is_desaturated)
200  return;
201 
202  is_desaturated_ = is_desaturated;
203  if (is_desaturated) {
204  gui::out << gui::warning << "gui::" << get_region_type() << ": "
205  << "Texture de-saturation is not yet implemented." << std::endl;
206  }
207 
209 }
210 
212  content_ = g;
213 
214  quad_.mat = nullptr;
215 
216  if (g.orient == orientation::horizontal) {
217  quad_.v[0].col = g.min_color;
218  quad_.v[1].col = g.max_color;
219  quad_.v[2].col = g.max_color;
220  quad_.v[3].col = g.min_color;
221  } else {
222  quad_.v[0].col = g.min_color;
223  quad_.v[1].col = g.min_color;
224  quad_.v[2].col = g.max_color;
225  quad_.v[3].col = g.max_color;
226  }
227 
229 }
230 
231 void texture::set_tex_rect(const std::array<float, 4>& texture_rect) {
232  if (quad_.mat) {
233  quad_.v[0].uvs = quad_.mat->get_canvas_uv(vector2f(texture_rect[0], texture_rect[1]), true);
234  quad_.v[1].uvs = quad_.mat->get_canvas_uv(vector2f(texture_rect[2], texture_rect[1]), true);
235  quad_.v[2].uvs = quad_.mat->get_canvas_uv(vector2f(texture_rect[2], texture_rect[3]), true);
236  quad_.v[3].uvs = quad_.mat->get_canvas_uv(vector2f(texture_rect[0], texture_rect[3]), true);
237 
238  if (!is_texture_stretching_enabled_)
239  update_dimensions_from_tex_coord_();
240  } else {
241  quad_.v[0].uvs = vector2f(texture_rect[0], texture_rect[1]);
242  quad_.v[1].uvs = vector2f(texture_rect[2], texture_rect[1]);
243  quad_.v[2].uvs = vector2f(texture_rect[2], texture_rect[3]);
244  quad_.v[3].uvs = vector2f(texture_rect[0], texture_rect[3]);
245  }
246 
248 }
249 
250 void texture::set_tex_coord(const std::array<float, 8>& texture_coords) {
251  if (quad_.mat) {
252  quad_.v[0].uvs =
253  quad_.mat->get_canvas_uv(vector2f(texture_coords[0], texture_coords[1]), true);
254  quad_.v[1].uvs =
255  quad_.mat->get_canvas_uv(vector2f(texture_coords[2], texture_coords[3]), true);
256  quad_.v[2].uvs =
257  quad_.mat->get_canvas_uv(vector2f(texture_coords[4], texture_coords[5]), true);
258  quad_.v[3].uvs =
259  quad_.mat->get_canvas_uv(vector2f(texture_coords[6], texture_coords[7]), true);
260 
261  if (!is_texture_stretching_enabled_)
262  update_dimensions_from_tex_coord_();
263  } else {
264  quad_.v[0].uvs = vector2f(texture_coords[0], texture_coords[1]);
265  quad_.v[1].uvs = vector2f(texture_coords[2], texture_coords[3]);
266  quad_.v[2].uvs = vector2f(texture_coords[4], texture_coords[5]);
267  quad_.v[3].uvs = vector2f(texture_coords[6], texture_coords[7]);
268  }
269 
271 }
272 
273 void texture::set_texture_stretching(bool texture_stretching) {
274  if (is_texture_stretching_enabled_ != texture_stretching) {
275  is_texture_stretching_enabled_ = texture_stretching;
276 
277  if (!is_texture_stretching_enabled_ && quad_.mat)
278  update_dimensions_from_tex_coord_();
279  }
280 }
281 
282 void texture::update_dimensions_from_tex_coord_() {
283  vector2f extent = quad_.v[2].uvs - quad_.v[0].uvs;
284  set_dimensions(extent * vector2f(quad_.mat->get_canvas_dimensions()));
285 }
286 
287 void texture::set_texture(const std::string& file_name) {
288  std::string parsed_file = parse_file_name(file_name);
289  content_ = parsed_file;
290 
291  auto& renderer = get_manager().get_renderer();
292 
293  std::shared_ptr<gui::material> mat;
294  if (utils::file_exists(parsed_file))
295  mat = renderer.create_atlas_material("GUI", parsed_file, filter_);
296 
297  quad_.mat = mat;
298 
299  if (mat) {
300  quad_.v[0].uvs = quad_.mat->get_canvas_uv(vector2f(0, 0), true);
301  quad_.v[1].uvs = quad_.mat->get_canvas_uv(vector2f(1, 0), true);
302  quad_.v[2].uvs = quad_.mat->get_canvas_uv(vector2f(1, 1), true);
303  quad_.v[3].uvs = quad_.mat->get_canvas_uv(vector2f(0, 1), true);
304 
306  set_width(quad_.mat->get_rect().width());
307 
309  set_height(quad_.mat->get_rect().height());
310  } else if (!parsed_file.empty()) {
311  gui::out << gui::error << "gui::" << get_region_type() << ": "
312  << "Cannot load file \"" << parsed_file << "\" for \"" << name_
313  << "\". Using white texture instead." << std::endl;
314  }
315 
317 }
318 
319 void texture::set_texture(std::shared_ptr<render_target> target) {
320  content_ = std::string{};
321 
322  auto& renderer = get_manager().get_renderer();
323 
324  std::shared_ptr<gui::material> mat;
325  if (target)
326  mat = renderer.create_material(std::move(target));
327 
328  quad_.mat = mat;
329 
330  if (mat) {
331  quad_.v[0].uvs = quad_.mat->get_canvas_uv(vector2f(0, 0), true);
332  quad_.v[1].uvs = quad_.mat->get_canvas_uv(vector2f(1, 0), true);
333  quad_.v[2].uvs = quad_.mat->get_canvas_uv(vector2f(1, 1), true);
334  quad_.v[3].uvs = quad_.mat->get_canvas_uv(vector2f(0, 1), true);
335 
337  set_width(quad_.mat->get_rect().width());
338 
340  set_height(quad_.mat->get_rect().height());
341  } else {
342  gui::out << gui::error << "gui::" << get_region_type() << ": "
343  << "Cannot create a texture from render target. Using white texture instead."
344  << std::endl;
345  }
346 
348 }
349 
351  content_ = c;
352 
353  quad_.mat = nullptr;
354  quad_.v[0].col = c;
355  quad_.v[1].col = c;
356  quad_.v[2].col = c;
357  quad_.v[3].col = c;
358 
360 }
361 
362 void texture::set_quad(const quad& q) {
363  content_ = std::string{};
364 
365  quad_ = q;
366  vector2f extent = quad_.v[2].pos - quad_.v[0].pos;
367  set_dimensions(extent);
368 
370 }
371 
372 void texture::set_vertex_color(const color& c, std::size_t index) {
373  if (index == std::numeric_limits<std::size_t>::max()) {
374  for (std::size_t i = 0; i < 4; ++i)
375  quad_.v[i].col = c;
376 
378  return;
379  }
380 
381  if (index >= 4) {
382  gui::out << gui::error << "gui::" << get_region_type() << ": "
383  << "Vertex index out of bound (" << index << ")." << std::endl;
384  return;
385  }
386 
387  quad_.v[index].col = c;
388 
390 }
391 
392 void texture::update_borders_() {
394 
395  quad_.v[0].pos = borders_.top_left();
396  quad_.v[1].pos = borders_.top_right();
397  quad_.v[2].pos = borders_.bottom_right();
398  quad_.v[3].pos = borders_.bottom_left();
399 }
400 
401 const std::vector<std::string>& texture::get_type_list_() const {
402  return get_type_list_impl_<texture>();
403 }
404 
405 } // namespace lxgui::gui
Holds a single color (float RGBA, 128 bits)
Definition: gui_color.hpp:12
static const color white
Definition: gui_color.hpp:43
A region that can be rendered in a layer.
void notify_renderer_need_redraw() override
Notifies the renderer of this region that it needs to be redrawn.
std::string serialize(const std::string &tab) const override
Prints all relevant information about this region in a string.
Manages the user interface.
Definition: gui_manager.hpp:44
const renderer & get_renderer() const
Returns the renderer implementation.
The base class of all elements in the GUI.
Definition: gui_region.hpp:161
virtual void set_width(float abs_width)
Changes this region's absolute width (in pixels).
Definition: gui_region.cpp:227
const std::string & get_region_type() const
Returns the type of this region.
Definition: gui_region.cpp:148
void initialize_(T &self, const region_core_attributes &attr)
Set up function to call in all derived class constructors.
float get_effective_alpha() const
Returns this region's effective alpha (opacity).
Definition: gui_region.cpp:161
bool is_apparent_width_defined() const
Checks if this region's apparent width is defined.
Definition: gui_region.cpp:280
bool is_visible() const
Checks if this region can be seen on the screen.
Definition: gui_region.cpp:207
manager & get_manager()
Returns this region's manager.
Definition: gui_region.hpp:693
virtual void render() const
Renders this region on the current render target.
Definition: gui_region.cpp:765
virtual void set_height(float abs_height)
Changes this region's absolute height (in pixels).
Definition: gui_region.cpp:239
std::string name_
Definition: gui_region.hpp:804
virtual void set_dimensions(const vector2f &dimensions)
Changes this region's absolute dimensions (in pixels).
Definition: gui_region.cpp:215
bool is_apparent_height_defined() const
Checks if this region's apparent height is defined.
Definition: gui_region.cpp:284
virtual void copy_from(const region &obj)
Copies a region's parameters into this region (inheritance).
Definition: gui_region.cpp:128
std::string parse_file_name(const std::string &file_name) const
Convert an addon-relative file path to a application-relative path.
Definition: gui_region.cpp:818
virtual void update_borders_()
Definition: gui_region.cpp:669
Abstract type for implementation specific management.
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.
void render_quad(const quad &q)
Renders a quad.
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.
A layered_region that can draw images and colored rectangles.
Definition: gui_texture.hpp:23
bool get_texture_stretching() const
Checks if this texture can stretch to match the region dimensions.
std::string serialize(const std::string &tab) const override
Prints all relevant information about this region in a string.
Definition: gui_texture.cpp:22
void set_gradient(const gradient &g)
Adds a gradient effect to this texture.
void set_blend_mode(blend_mode mode)
Sets this texture's blending mode.
void copy_from(const region &obj) override
Copies a region's parameters into this texture (inheritance).
Definition: gui_texture.cpp:79
void set_tex_rect(const std::array< float, 4 > &texture_rect)
Sets this texture's texture coordinates.
const gradient & get_gradient() const
Returns this texture's gradient.
material::filter get_filter_mode() const
Returns this texture's filtering algorithm.
void set_solid_color(const color &c)
Sets this texture's color.
const color & get_solid_color() const
Returns this texture's color.
void set_desaturated(bool is_desaturated)
Makes this texture appear without any color.
void set_tex_coord(const std::array< float, 8 > &texture_coords)
Sets this texture's texture coordinates.
void set_texture_stretching(bool texture_stretching)
Sets whether this texture can stretch to match the region dimensions.
texture(utils::control_block &block, manager &mgr, const region_core_attributes &attr)
Constructor.
Definition: gui_texture.cpp:16
bool has_solid_color() const
Checks if this texture is defined as solid color.
color get_vertex_color(std::size_t index) const
Returns this texture's vertex color.
void set_filter_mode(material::filter filt)
Sets this texture's filtering mode.
blend_mode get_blend_mode() const
Returns this texture's blending mode.
Definition: gui_texture.cpp:99
const std::string & get_texture_file() const
Returns this texture's texture file.
void set_quad(const quad &q)
Directly sets this texture's underlying quad (vertices and material).
bool is_desaturated() const
Checks if this texture is desaturated.
void set_vertex_color(const color &c, std::size_t index=std::numeric_limits< std::size_t >::max())
Sets this texture's vertex color.
std::array< float, 8 > get_tex_coord() const
Returns this texture's texture coordinates.
bool has_texture_file() const
Checks if this texture is defined as a texture file.
void render() const override
Renders this region on the current render target.
Definition: gui_texture.cpp:60
bool has_gradient() const
Checks if this texture is defined as a gradient.
void set_texture(const std::string &file_name)
Sets this texture's texture file.
vector2< float > vector2f
Holds 2D coordinates (as floats)
std::ostream out
const std::string warning
Definition: gui_out.cpp:6
const std::string error
Definition: gui_out.cpp:7
bool file_exists(const std::string &file)
vector2< T > bottom_left() const noexcept
Definition: gui_bounds2.hpp:44
vector2< T > bottom_right() const noexcept
Definition: gui_bounds2.hpp:40
vector2< T > top_right() const noexcept
Definition: gui_bounds2.hpp:36
vector2< T > top_left() const noexcept
Definition: gui_bounds2.hpp:32
Represents color gradients.
Simple structure holding four vertices and a material.
Definition: gui_quad.hpp:18
std::shared_ptr< material > mat
Definition: gui_quad.hpp:20
std::array< vertex, 4 > v
Definition: gui_quad.hpp:19
Struct holding all the core information about a region necessary for its creation.