1 #include "lxgui/gui_atlas.hpp"
3 #include "lxgui/gui_exception.hpp"
4 #include "lxgui/gui_font.hpp"
5 #include "lxgui/gui_out.hpp"
6 #include "lxgui/gui_renderer.hpp"
7 #include "lxgui/gui_vertex.hpp"
8 #include "lxgui/utils_string.hpp"
15 auto iter = texture_list_.find(file_name);
16 if (iter != texture_list_.end()) {
17 if (std::shared_ptr<gui::material> lock = iter->second.lock())
24 std::shared_ptr<gui::material>
28 const auto location = find_location_(rect.width(), rect.height());
29 if (!location.has_value())
32 std::shared_ptr<gui::material> tex =
add_material_(mat, location.value());
33 texture_list_[file_name] = tex;
35 }
catch (
const std::exception& e) {
42 auto iter = font_list_.find(font_name);
43 if (iter != font_list_.end()) {
44 if (std::shared_ptr<gui::font> lock = iter->second.lock())
53 if (
const auto mat = fnt->get_texture().lock()) {
54 const auto rect = mat->get_rect();
55 const auto location = find_location_(rect.width(), rect.height());
56 if (!location.has_value())
59 std::shared_ptr<gui::material> tex =
add_material_(*mat, location.value());
60 fnt->update_texture(tex);
62 font_list_[font_name] = std::move(fnt);
66 }
catch (
const std::exception& e) {
73 for (
const auto& mat : texture_list_) {
74 if (std::shared_ptr<gui::material> lock = mat.second.lock())
78 for (
const auto& fnt : font_list_) {
79 if (std::shared_ptr<gui::font> lock = fnt.second.lock())
86 std::optional<bounds2f> atlas_page::find_location_(
float width,
float height)
const {
87 constexpr
float padding = 1.0f;
89 bounds2f start_quad(0, width, 0, height);
96 std::vector<bounds2f> occupied_space;
97 occupied_space.reserve(texture_list_.size());
99 float max_width = 0.0f;
100 float max_height = 0.0f;
102 auto apply_padding = [&](
bounds2f rect) {
103 rect.right += padding;
104 rect.bottom += padding;
108 for (
const auto& mat : texture_list_) {
109 if (std::shared_ptr<gui::material> lock = mat.second.lock()) {
110 occupied_space.push_back(apply_padding(lock->get_rect()));
111 max_width = std::max(max_width, occupied_space.back().right);
112 max_height = std::max(max_height, occupied_space.back().bottom);
116 for (
const auto& fnt : font_list_) {
117 if (std::shared_ptr<gui::font> lock = fnt.second.lock()) {
118 occupied_space.push_back(apply_padding(lock->get_texture().lock()->get_rect()));
119 max_width = std::max(max_width, occupied_space.back().right);
120 max_height = std::max(max_height, occupied_space.back().bottom);
124 float best_area = std::numeric_limits<float>::infinity();
127 for (
const auto& rect_source : occupied_space) {
128 auto test_position = [&](
const vector2f& pos) {
129 const bounds2f test_quad = start_quad + pos;
130 if (test_quad.right > atlas_width || test_quad.bottom > atlast_height)
133 const float new_max_width = std::max(max_width, test_quad.right);
134 const float new_max_height = std::max(max_height, test_quad.bottom);
135 const float new_area = new_max_width * new_max_height;
137 if (new_area >= best_area)
140 for (
const auto& rect_other : occupied_space) {
141 if (test_quad.overlaps(rect_other))
145 best_area = new_area;
146 best_quad = test_quad;
149 test_position(rect_source.top_right());
150 test_position(rect_source.bottom_left());
153 if (std::isfinite(best_area))
162 for (
const auto& item : page_list_) {
163 auto tex = item.page->fetch_material(file_name);
171 std::shared_ptr<gui::material>
174 for (
const auto& item : page_list_) {
175 auto tex = item.page->add_material(file_name, mat);
179 if (item.page->empty()) {
181 <<
"' on any atlas page." << std::endl;
187 auto tex = page_list_.back().page->add_material(file_name, mat);
192 }
catch (
const std::exception& e) {
199 for (
const auto& item : page_list_) {
200 auto fnt = item.page->fetch_font(font_name);
210 for (
const auto& item : page_list_) {
211 if (item.page->add_font(font_name, fnt))
214 if (item.page->empty()) {
216 <<
"' on any atlas page." << std::endl;
223 return page_list_.back().page->add_font(font_name, std::move(fnt));
224 }
catch (
const std::exception& e) {
231 return page_list_.size();
234 void atlas::add_page_() {
241 color32 pixel{255, 255, 255, 255};
243 item.no_texture_mat = item.page->add_material(
"", *tex);
245 page_list_.push_back(std::move(item));
virtual std::shared_ptr< material > add_material_(const material &mat, const bounds2f &location)=0
Adds a new material to this page, at the provided location.
atlas_page(material::filter filt)
Constructor.
std::shared_ptr< material > add_material(const std::string &file_name, const material &mat)
Creates a new material from a texture file.
std::shared_ptr< font > fetch_font(const std::string &font_name) const
Find a font in this page (nullptr if not found).
bool add_font(const std::string &font_name, std::shared_ptr< gui::font > fnt)
Creates a new font from a texture file.
virtual float get_height_() const =0
Return the height of this page (in pixels).
std::shared_ptr< material > fetch_material(const std::string &file_name) const
Find a material in this page (nullptr if not found).
virtual float get_width_() const =0
Return the width of this page (in pixels).
bool empty() const
Checks if this page is empty (contains no materials).
std::size_t get_page_count() const
Return the number of pages in this atlas.
std::shared_ptr< material > add_material(const std::string &file_name, const material &mat)
Add a new material to the atlas.
virtual std::unique_ptr< atlas_page > create_page_()=0
Create a new page in this 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).
atlas(renderer &rdr, material::filter filt)
Constructor.
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 bounds2f get_rect() const =0
Returns the pixel rect in pixels of the canvas containing this texture (if any).
Abstract type for implementation specific management.
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.
vector2< float > vector2f
Holds 2D coordinates (as floats)
bounds2< float > bounds2f
Holds 2D bounds of a region (as floats).
vector2< std::size_t > vector2ui
Holds 2D coordinates (as unsigned integers)
const std::string warning
Holds a single color (byte RGBA, 32 bits)