sandbox
Loading...
Searching...
No Matches
asset_registry.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_SCENES_ASSET_REGISTRY_HPP_
3#define LIBSBX_SCENES_ASSET_REGISTRY_HPP_
4
5#include <unordered_map>
6#include <filesystem>
7
8#include <libsbx/utility/hashed_string.hpp>
9#include <libsbx/utility/exception.hpp>
10
11#include <libsbx/math/uuid.hpp>
12
13#include <libsbx/core/engine.hpp>
14
15#include <libsbx/assets/assets_module.hpp>
16
17#include <libsbx/graphics/graphics_module.hpp>
18#include <libsbx/graphics/images/image2d.hpp>
19#include <libsbx/graphics/images/cube_image.hpp>
20
21namespace sbx::scenes {
22
24 std::filesystem::path path;
25 std::string name;
26 std::string type{"unknown"};
27 std::string source{"dynamic"};
28}; // struct asset_metadata
29
30template<typename Handle>
32
33public:
34
35 auto has(const utility::hashed_string& name) const -> bool {
36 return _by_name.contains(name);
37 }
38
39 auto get(const utility::hashed_string& name) const -> const Handle& {
40 if (auto entry = _by_name.find(name); entry != _by_name.end()) {
41 return entry->second;
42 }
43
44 throw utility::runtime_error{"Could not find asset '{}'", name.str()};
45 }
46
47 auto insert(const utility::hashed_string& name, const Handle& handle, asset_metadata metadata) -> bool {
48 if (_by_name.contains(name)) {
49 return false;
50 }
51
52 _by_name.emplace(name, handle);
53 _metadata.emplace(handle, std::move(metadata));
54
55 return true;
56 }
57
58 auto metadata(const Handle& handle) const -> const asset_metadata& {
59 return _metadata.at(handle);
60 }
61
62 auto size() const -> std::size_t {
63 return _by_name.size();
64 }
65
66 auto begin() const {
67 return _metadata.begin();
68 }
69
70 auto end() const {
71 return _metadata.end();
72 }
73
74 auto begin() {
75 return _metadata.begin();
76 }
77
78 auto end() {
79 return _metadata.end();
80 }
81
82private:
83
84 std::unordered_map<utility::hashed_string, Handle> _by_name;
85 std::unordered_map<Handle, asset_metadata> _metadata;
86
87}; // class asset_table
88
90
91public:
92
93 template<typename... Args>
94 auto request_image(const utility::hashed_string& name, const std::filesystem::path& path, Args&&... args) -> graphics::image2d_handle {
95 if (_images.has(name)) {
96 return _images.get(name);
97 }
98
99 auto& gfx = core::engine::get_module<graphics::graphics_module>();
100
101 const auto handle = gfx.add_resource<graphics::image2d>(path, std::forward<Args>(args)...);
102
103 _images.insert(name, handle, asset_metadata{path, name.str(), "image", "disk"});
104
105 return handle;
106 }
107
108 auto has_image(const utility::hashed_string& name) const -> bool {
109 return _images.has(name);
110 }
111
112 auto get_image(const utility::hashed_string& name) const -> graphics::image2d_handle {
113 return _images.get(name);
114 }
115
116 auto image_metadata(const graphics::image2d_handle& handle) const -> const asset_metadata& {
117 return _images.metadata(handle);
118 }
119
120 auto images() const -> const asset_table<graphics::image2d_handle>& {
121 return _images;
122 }
123
124 template<typename... Args>
125 auto request_cube_image(const utility::hashed_string& name, const std::filesystem::path& path, Args&&... args) -> graphics::cube_image2d_handle {
126 if (_cube_images.has(name)) {
127 return _cube_images.get(name);
128 }
129
130 auto& gfx = core::engine::get_module<graphics::graphics_module>();
131
132 const auto handle = gfx.add_resource<graphics::cube_image>(path, std::forward<Args>(args)...);
133
134 _cube_images.insert(name, handle, asset_metadata{path, name.str(), "cube_image", "disk"});
135
136 return handle;
137 }
138
139 auto has_cube_image(const utility::hashed_string& name) const -> bool {
140 return _cube_images.has(name);
141 }
142
143 auto get_cube_image(const utility::hashed_string& name) const -> graphics::cube_image2d_handle {
144 return _cube_images.get(name);
145 }
146
147 auto cube_image_metadata(const graphics::cube_image2d_handle& handle) const -> const asset_metadata& {
148 return _cube_images.metadata(handle);
149 }
150
151 auto cube_images() const -> const asset_table<graphics::cube_image2d_handle>& {
152 return _cube_images;
153 }
154
155 template<typename Mesh, typename... Args>
156 auto request_mesh(const utility::hashed_string& name, Args&&... args) -> math::uuid {
157 if (_meshes.has(name)) {
158 return _meshes.get(name);
159 }
160
161 auto& assets_module = core::engine::get_module<assets::assets_module>();
162
163 const auto id = assets_module.add_asset<Mesh>(std::forward<Args>(args)...);
164
165 _meshes.insert(name, id, asset_metadata{"", name.str(), "mesh", "generated"});
166
167 return id;
168 }
169
170 template<typename Mesh, typename Path, typename... Args>
171 requires (std::is_constructible_v<std::filesystem::path, Path>)
172 auto request_mesh(const utility::hashed_string& name, const Path& path, Args&&... args) -> math::uuid {
173 if (_meshes.has(name)) {
174 return _meshes.get(name);
175 }
176
177 auto& assets_module = core::engine::get_module<assets::assets_module>();
178
179 const auto id = assets_module.add_asset<Mesh>(path, std::forward<Args>(args)...);
180
181 _meshes.insert(name, id, asset_metadata{path, name.str(), "mesh", "disk"});
182
183 return id;
184 }
185
186 auto has_mesh(const utility::hashed_string& name) const -> bool {
187 return _meshes.has(name);
188 }
189
190 auto get_mesh(const utility::hashed_string& name) const -> math::uuid {
191 return _meshes.get(name);
192 }
193
194 auto mesh_metadata(const math::uuid& handle) const -> const asset_metadata& {
195 return _meshes.metadata(handle);
196 }
197
198 auto meshes() const -> const asset_table<math::uuid>& {
199 return _meshes;
200 }
201
202 template<typename Animation, typename... Args>
203 auto request_animation(const utility::hashed_string& name, Args&&... args) -> math::uuid {
204 if (_animations.has(name)) {
205 return _animations.get(name);
206 }
207
208 auto& assets_module = core::engine::get_module<assets::assets_module>();
209
210 const auto id = assets_module.add_asset<Animation>(std::forward<Args>(args)...);
211
212 _animations.insert(name, id, asset_metadata{"", name.str(), "animation", "generated"});
213
214 return id;
215 }
216
217 auto has_animation(const utility::hashed_string& name) const -> bool {
218 return _animations.has(name);
219 }
220
221 auto get_animation(const utility::hashed_string& name) const -> math::uuid {
222 return _animations.get(name);
223 }
224
225 auto animations() const -> const asset_table<math::uuid>& {
226 return _animations;
227 }
228
229 template<typename Material, typename... Args>
230 auto request_material(const utility::hashed_string& name, Args&&... args) -> Material& {
231 auto& assets_module = core::engine::get_module<assets::assets_module>();
232
233 if (_materials.has(name)) {
234 return assets_module.get_asset<Material>(_materials.get(name));
235 }
236
237 const auto id = assets_module.add_asset<Material>(std::forward<Args>(args)...);
238
239 _materials.insert(name, id, asset_metadata{"", name.str(), "material", "dynamic"});
240
241 return assets_module.get_asset<Material>(id);
242 }
243
244 auto has_material(const utility::hashed_string& name) const -> bool {
245 return _materials.has(name);
246 }
247
248 auto get_material(const utility::hashed_string& name) const -> math::uuid {
249 return _materials.get(name);
250 }
251
252 auto material_metadata(const math::uuid& handle) const -> const asset_metadata& {
253 return _materials.metadata(handle);
254 }
255
256 auto materials() const -> const asset_table<math::uuid>& {
257 return _materials;
258 }
259
260 auto rebase_paths(std::string_view old_uri, std::string_view new_uri) -> void {
261 _rebase_table(_images, old_uri, new_uri);
262 _rebase_table(_cube_images, old_uri, new_uri);
263 _rebase_table(_meshes, old_uri, new_uri);
264 _rebase_table(_animations, old_uri, new_uri);
265 _rebase_table(_materials, old_uri, new_uri);
266 }
267
268 auto clear_paths_under(std::string_view uri) -> void {
269 _clear_table_paths_under(_images, uri);
270 _clear_table_paths_under(_cube_images, uri);
271 _clear_table_paths_under(_meshes, uri);
272 _clear_table_paths_under(_animations, uri);
273 _clear_table_paths_under(_materials, uri);
274 }
275
276private:
277
278 template<typename Table>
279 static auto _rebase_table(Table& table, std::string_view old_uri, std::string_view new_uri) -> void {
280 for (auto& [handle, metadata] : table) {
281 static_cast<void>(handle);
282
283 if (metadata.path.empty()) {
284 continue;
285 }
286
287 const auto current = metadata.path.generic_string();
288
289 if (!_uri_starts_with(current, old_uri)) {
290 continue;
291 }
292
293 auto rebuilt = std::string{new_uri};
294 rebuilt.append(current, old_uri.size(), std::string::npos);
295
296 metadata.path = std::filesystem::path{rebuilt};
297 }
298 }
299
300 template<typename Table>
301 static auto _clear_table_paths_under(Table& table, std::string_view uri) -> void {
302 for (auto& [handle, metadata] : table) {
303 static_cast<void>(handle);
304
305 if (metadata.path.empty()) {
306 continue;
307 }
308
309 const auto current = metadata.path.generic_string();
310
311 if (!_uri_starts_with(current, uri)) {
312 continue;
313 }
314
315 metadata.path.clear();
316 }
317 }
318
319 static auto _uri_starts_with(std::string_view path, std::string_view prefix) -> bool {
320 if (path.size() < prefix.size()) {
321 return false;
322 }
323
324 if (path.substr(0, prefix.size()) != prefix) {
325 return false;
326 }
327
328 if (path.size() == prefix.size()) {
329 return true;
330 }
331
332 return path[prefix.size()] == '/';
333 }
334
338 asset_table<math::uuid> _animations;
339 asset_table<math::uuid> _materials;
340
341}; // class asset_registry
342
343} // namespace sbx::scenes
344
345#endif // LIBSBX_SCENES_ASSET_REGISTRY_HPP_
Definition: cube_image.hpp:21
Definition: image2d.hpp:53
Definition: resource_storage.hpp:18
Definition: uuid.hpp:15
Definition: asset_registry.hpp:89
Definition: asset_registry.hpp:31
Definition: id.hpp:9
Definition: hashed_string.hpp:17
Definition: asset_registry.hpp:23
Definition: exception.hpp:18