galaxy 1.0.0
Real-Time C++23 Game Programming Framework. Built on data-driven design principles and agile software engineering.
Loading...
Searching...
No Matches
TextureAtlas.cpp
Go to the documentation of this file.
1
7
8#include <format>
9
10#include <glad/glad.h>
11
13#include "galaxy/core/ServiceLocator.hpp"
16
17#include "TextureAtlas.hpp"
18
19namespace galaxy
20{
21 namespace resource
22 {
24 : m_max_bindings {0}
25 , m_size {0}
26 {
27 init();
28 }
29
34
35 void TextureAtlas::add(const std::string& file)
36 {
37 auto& fs = core::ServiceLocator<fs::VirtualFileSystem>::ref();
38 auto data = fs.read_binary(file);
39 if (!data.empty())
40 {
41 graphics::Texture texture;
42 texture.load_mem(data);
43
44 const auto path = std::filesystem::path(file);
45 const auto name = path.filename().string();
46
47 if (!m_data.contains(name))
48 {
49 m_data[name] = {};
50
51 std::optional<math::iRect> packed = std::nullopt;
52 for (auto i = 0; i < m_sheets.size(); i++)
53 {
54 if (!m_sheets[i])
55 {
56 m_sheets[i] = std::make_unique<Sheet>();
57 m_sheets[i]->m_packer.init(m_size, m_size);
58 m_sheets[i]->m_render_texture.create(m_size, m_size);
59 }
60
61 packed = m_sheets[i]->m_packer.pack(texture.get_width(), texture.get_height());
62 if (packed.has_value())
63 {
64 m_data[name].m_index = i;
65 break;
66 }
67 }
68
69 if (packed.has_value())
70 {
71 auto& sheet = m_sheets[m_data[name].m_index];
72 auto& renderer = core::ServiceLocator<graphics::Renderer>::ref();
73
74 m_data[name].m_handle = sheet->m_render_texture.get_texture();
75 m_data[name].m_region = packed.value();
76
77 // Convert to texel coords.
78 const auto sw = sheet->m_render_texture.get_width();
79 const auto sh = sheet->m_render_texture.get_height();
80
81 m_data[name].m_sheet_width = sw;
82 m_data[name].m_sheet_height = sh;
83
84 m_data[name].m_texel_region.m_ul_texels.x = map_x_texel(m_data[name].m_region.x, sw);
85 m_data[name].m_texel_region.m_ul_texels.y = map_y_texel(m_data[name].m_region.y, sh);
86
87 m_data[name].m_texel_region.m_ur_texels.x = map_x_texel(m_data[name].m_region.x + m_data[name].m_region.width, sw);
88 m_data[name].m_texel_region.m_ur_texels.y = map_y_texel(m_data[name].m_region.y, sh);
89
90 m_data[name].m_texel_region.m_br_texels.x = map_x_texel(m_data[name].m_region.x + m_data[name].m_region.width, sw);
91 m_data[name].m_texel_region.m_br_texels.y = map_y_texel(m_data[name].m_region.y + m_data[name].m_region.height, sh);
92
93 m_data[name].m_texel_region.m_bl_texels.x = map_x_texel(m_data[name].m_region.x, sw);
94 m_data[name].m_texel_region.m_bl_texels.y = map_y_texel(m_data[name].m_region.y + m_data[name].m_region.height, sh);
95
96 // Update transform.
97 m_transform.set_pos(static_cast<float>(m_data[name].m_region.x), static_cast<float>(m_data[name].m_region.y));
98
99 // Redefine vertices.
100 std::array<graphics::Vertex, 4> vertices;
101 vertices[0].m_pos = {0.0f, 0.0f};
102 vertices[0].m_texels = {0.0f, 0.0f};
103
104 vertices[1].m_pos = {m_data[name].m_region.width, 0.0f};
105 vertices[1].m_texels = {1.0f, 0.0f};
106
107 vertices[2].m_pos = {m_data[name].m_region.width, m_data[name].m_region.height};
108 vertices[2].m_texels = {1.0f, 1.0f};
109
110 vertices[3].m_pos = {0.0f, m_data[name].m_region.height};
111 vertices[3].m_texels = {0.0f, 1.0f};
112
114
115 sheet->m_render_texture.bind(false);
116 renderer.draw_texture_to_target(sheet->m_render_texture, texture, m_vao, m_transform);
117 glBindFramebuffer(GL_FRAMEBUFFER, 0);
118 }
119 else
120 {
121 GALAXY_LOG(GALAXY_ERROR, "Unable to find room to pack '{0}' into a texture atlas.", file);
122 }
123 }
124 else
125 {
126 GALAXY_LOG(GALAXY_WARNING, "Attempted to add duplicate texture to texture atlas.");
127 }
128
129 glBindTexture(GL_TEXTURE_2D, 0);
130 glBindFramebuffer(GL_FRAMEBUFFER, 0);
131 }
132 else
133 {
134 GALAXY_LOG(GALAXY_ERROR, "Failed to read '{0}' from vfs.", file);
135 }
136 }
137
139 {
140 clear();
141
142 for (const auto& file : core::ServiceLocator<fs::VirtualFileSystem>::ref().list(GALAXY_ATLAS_DIR))
143 {
144 add(file);
145 }
146 }
147
149 {
150 for (auto i = 0; i < m_sheets.size(); i++)
151 {
152 if (m_sheets[i] != nullptr)
153 {
154 m_sheets[i]->m_render_texture.save(std::format("dump/sheet{0}.png", i));
155 }
156 }
157 }
158
160 {
161 m_sheets.clear();
162 m_data.clear();
163 m_transform.reset();
164
165 init();
166 }
167
168 bool TextureAtlas::contains(const std::string& key)
169 {
170 return m_data.contains(key);
171 }
172
173 meta::optional_ref<TextureAtlas::Info> TextureAtlas::query(const std::string& key)
174 {
175 if (contains(key))
176 {
177 return std::make_optional(std::ref(m_data[key]));
178 }
179 else
180 {
181 return std::nullopt;
182 }
183 }
184
185 meta::vector<std::string> TextureAtlas::keys()
186 {
187 meta::vector<std::string> keys;
188 keys.reserve(m_data.size());
189
190 for (const auto& [key, _] : m_data)
191 {
192 keys.emplace_back(key);
193 }
194
195 return keys;
196 }
197
199 {
200 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &m_max_bindings);
201 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_size);
202
203 auto& config = core::ServiceLocator<core::Config>::ref();
204 auto user_size = config.get<int>("texture_atlas_size", "graphics");
205
206 if (user_size >= m_size)
207 {
208 user_size = m_size;
209 }
210
211 if (m_size != 1024 && m_size != 2048 && m_size != 4096 && m_size != 8192)
212 {
213 m_size = 4096;
214 }
215
216 // Hard limit bindings count.
217 m_max_bindings = std::min(m_max_bindings, 32);
218
219 m_sheets.resize(m_max_bindings);
220
221 auto vertices = graphics::Vertex::gen_quad_vertices(1, 1);
222 m_vao.create(vertices, graphics::StorageFlag::DYNAMIC_DRAW, graphics::Vertex::get_default_indices(), graphics::StorageFlag::STATIC_DRAW);
223 }
224 } // namespace resource
225} // namespace galaxy
#define GALAXY_LOG(level, msg,...)
Definition Log.hpp:28
#define GALAXY_ERROR
Definition Log.hpp:24
thread_local const float vertices[]
Video.cpp galaxy.
Definition Video.cpp:19
OpenGL 2D Texture.
Definition Texture.hpp:26
void sub_buffer(const unsigned int index, std::span< Vertex > vertices)
Sub-buffer vertex array.
virtual ~TextureAtlas()
Destructor.
robin_hood::unordered_flat_map< std::string, Info > m_data
Index'd list of textures on a sheet.
void init()
Initialize atlas.
int m_size
Maxinum size of an atlas texture.
components::Transform m_transform
Default transform to use when building an atlas.
graphics::VertexArray m_vao
Default vertex array to use when building an atlas.
meta::vector< std::string > keys()
Get a list of keys in the cache.
void add_from_vfs()
Loads all atlas textures in the vfs.
void clear()
Clear all data.
int m_max_bindings
Max number of active textures allowed.
void save()
Save all created atlas' to disk.
meta::vector< std::unique_ptr< Sheet > > m_sheets
Texture atlas sheets.
meta::optional_ref< Info > query(const std::string &key)
Get data about texture in atlas.
static float map_y_texel(const Type y, const Type height)
Takes in a y positon texture coord and maps it to a texel.
void add(const std::string &file)
Add a single file.
static float map_x_texel(const Type x, const Type width)
Takes in a x positon texture coord and maps it to a texel.
bool contains(const std::string &key)
Check if atlas contains a texture.
Animated.cpp galaxy.
Definition Animated.cpp:16