sandbox
Loading...
Searching...
No Matches
assets_module.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_ASSETS_ASSETS_MODULE_HPP_
3#define LIBSBX_ASSETS_ASSETS_MODULE_HPP_
4
5#include <vector>
6#include <unordered_map>
7#include <typeindex>
8#include <memory>
9#include <filesystem>
10
11#include <libsbx/utility/compression.hpp>
12#include <libsbx/utility/exception.hpp>
13#include <libsbx/utility/type_id.hpp>
14#include <libsbx/utility/iterator.hpp>
15#include <libsbx/utility/logger.hpp>
16#include <libsbx/utility/hashed_string.hpp>
17#include <libsbx/utility/string_literal.hpp>
18
19#include <libsbx/math/uuid.hpp>
20
21#include <libsbx/core/module.hpp>
22
23#include <libsbx/filesystem/alias.hpp>
24#include <libsbx/filesystem/filesystem_module.hpp>
25#include <libsbx/filesystem/native_filesystem.hpp>
26
27#include <libsbx/assets/thread_pool.hpp>
28#include <libsbx/assets/metadata.hpp>
29
30namespace sbx::assets {
31
32namespace detail {
33
35
36} // namespace detail
37
38template<utility::string_literal String>
39requires (String.size() == 4u)
40constexpr auto fourcc() -> std::uint32_t {
41 return String[0] | (String[1] << 8) | (String[2] << 16) | (String[3] << 24);
42}
43
49template<typename Type>
51
52template<utility::string_literal Type>
54
55 inline static constexpr auto hash = Type.hash();
56
57 inline static constexpr auto invalid = std::uint32_t{0xFFFFFFFF};
58
59 constexpr asset_handle()
60 : _handle{invalid},
61 _generation{0} { }
62
63 constexpr asset_handle(const std::uint32_t handle, const std::uint32_t generation)
64 : _handle{handle},
65 _generation{generation} { }
66
67 constexpr auto handle() const noexcept -> std::uint32_t {
68 return _handle;
69 }
70
71 constexpr auto generation() const noexcept -> std::uint32_t {
72 return _generation;
73 }
74
75 constexpr auto operator==(const asset_handle& other) const noexcept -> bool {
76 return _handle == other._handle && _generation == other._generation;
77 }
78
79 constexpr auto is_valid() const noexcept -> bool {
80 return _handle != invalid;
81 }
82
83 constexpr operator bool() const noexcept {
84 return is_valid();
85 }
86
87private:
88
89 std::uint32_t _handle;
90 std::uint32_t _generation;
91
92}; // struct asset_handle
93
95 std::filesystem::path path;
96 std::string name;
97 std::string type{"unknown"};
98 std::string source{"dynamic"};
99}; // struct asset_metadata
100
101struct asset_io {
102 std::string name;
103 std::function<void()> save;
104 std::function<void()> load;
105}; // struct asset_io
106
108
109 struct scope { };
110
111public:
112
113 template<typename Type>
115
116 template<typename Type, std::invocable<const Type&> Save, std::invocable<void> Load>
117 auto register_asset(const std::string& name, Save&& save, Load&& load) -> void {
118 const auto id = assets::type_id<Type>::value();
119
120 _by_name[name] = id;
121
122 _by_id[id] = asset_io{
123 .name = name,
124 .save = [s = std::forward<Save>(save)]() -> void {
125 std::invoke(s);
126 },
127 .load = []() -> void {
128
129 }
130 };
131 }
132
133 auto get(const std::uint32_t id) -> asset_io& {
134 return _by_id.at(id);
135 }
136
137 auto has(const std::uint32_t id) -> bool {
138 return _by_id.contains(id);
139 }
140
141 auto get(const std::string& name) -> asset_io& {
142 return _by_id.at(_by_name.at(name));
143 }
144
145private:
146
147 std::unordered_map<std::uint32_t, asset_io> _by_id;
148 std::unordered_map<std::string, std::uint32_t> _by_name;
149
150}; // class asset_io_registry
151
152class assets_module : public core::module<assets_module> {
153
154 inline static const auto is_registered = register_module(stage::post);
155
156 inline static constexpr auto prefix = std::string_view{"res://"};
157
158public:
159
161 : _thread_pool{std::thread::hardware_concurrency()},
162 _asset_root{std::filesystem::current_path()} {
163 utility::logger<"assets">::info("4cc of 'IMAG': {:#010x}", fourcc<"IMAG">());
164 }
165
166 ~assets_module() override {
167 for (const auto& container : _containers) {
168 container->clear();
169 }
170 }
171
172 auto update() -> void override {
173
174 }
175
176 auto asset_root() const -> const std::filesystem::path& {
177 return _asset_root;
178 }
179
180 auto set_asset_root(const std::filesystem::path& root) -> void {
181 if (!std::filesystem::exists(root)) {
182 throw utility::runtime_error{"New asset root path '{}' does not exist", root.string()};
183 }
184
185 utility::logger<"assets">::debug("Setting asset_root to '{}'", root.string());
186
187 _asset_root = root;
188
189 auto& filesystem_module = core::engine::get_module<filesystem::filesystem_module>();
190
191 const auto alias = filesystem::alias{"res://"};
192
193 if (filesystem_module.is_alias_registered(alias)) {
194 filesystem_module.unregister_alias(alias);
195 }
196
197 filesystem_module.create_filesystem<filesystem::native_filesystem>(alias, root.generic_string());
198 }
199
200 auto resolve_path(const std::filesystem::path& path) -> std::filesystem::path {
201 if (path.empty()) {
202 return path;
203 }
204
205 auto& filesystem_module = core::engine::get_module<filesystem::filesystem_module>();
206
207 if (filesystem_module.is_alias_registered(filesystem::alias{"res://"})) {
208 return filesystem_module.native_path_of(path);
209 }
210
211 const auto& path_string = path.string();
212
213 if (path_string.starts_with(prefix)) {
214 return _asset_root / path_string.substr(prefix.size());
215 }
216
217 return path;
218 }
219
220 template<typename Function, typename... Args>
221 requires (std::is_invocable_v<Function, Args...>)
222 auto submit(Function&& function, Args&&... args) -> std::future<std::invoke_result_t<Function, Args...>> {
223 return _thread_pool.submit(std::forward<Function>(function), std::forward<Args>(args)...);
224 }
225
226 template<utility::string_literal Type, typename... Args>
227 auto load_asset(const std::filesystem::path& path, Args&&... args) -> asset_handle<Type> {
228
229 }
230
231 template<typename Type, std::invocable<void> Save, std::invocable<void> Load>
232 auto register_asset(const std::string& name, Save&& save, Load&& load) -> void {
233 _asset_io_registry.register_asset<Type>(name, std::forward<Save>(save), std::forward<Load>(load));
234 }
235
236 auto asset_io(const std::uint32_t id) -> asset_io& {
237 return _asset_io_registry.get(id);
238 }
239
240 auto has_asset_io(const std::uint32_t id) -> bool {
241 return _asset_io_registry.has(id);
242 }
243
244 template<typename Type, typename... Args>
245 auto add_asset(Args&&... args) -> math::uuid {
246 const auto id = math::uuid{};
247 const auto type = type_id<Type>::value();
248
249 if (type >= _containers.size()) {
250 _containers.resize(std::max(_containers.size(), static_cast<std::size_t>(type + 1u)));
251 }
252
253 if (!_containers[type]) {
254 _containers[type] = std::make_unique<container<Type>>();
255 }
256
257 static_cast<container<Type>*>(_containers[type].get())->add(id, std::forward<Args>(args)...);
258
259 return id;
260 }
261
262 template<typename Type>
263 auto add_asset(std::unique_ptr<Type>&& asset) -> math::uuid {
264 const auto id = math::uuid{};
265 const auto type = type_id<Type>::value();
266
267 if (type >= _containers.size()) {
268 _containers.resize(std::max(_containers.size(), static_cast<std::size_t>(type + 1u)));
269 }
270
271 if (!_containers[type]) {
272 _containers[type] = std::make_unique<container<Type>>();
273 }
274
275 static_cast<container<Type>*>(_containers[type].get())->add(id, std::move(asset));
276
277 return id;
278 }
279
280 template<typename Type>
281 auto get_asset(const math::uuid& id) const -> const Type& {
282 const auto type = type_id<Type>::value();
283
284 if (type >= _containers.size() || !_containers[type]) {
285 throw std::runtime_error{"Asset does not exist"};
286 }
287
288 return static_cast<const container<Type>*>(_containers[type].get())->get(id);
289 }
290
291 template<typename Type>
292 auto get_asset(const math::uuid& id) -> Type& {
293 const auto type = type_id<Type>::value();
294
295 if (type >= _containers.size() || !_containers[type]) {
296 throw std::runtime_error{"Asset does not exist"};
297 }
298
299 return static_cast<container<Type>*>(_containers[type].get())->get(id);
300 }
301
302private:
303
304 thread_pool _thread_pool;
305 std::filesystem::path _asset_root;
306
307 struct container_base {
308 virtual ~container_base() = default;
309 virtual auto remove(const math::uuid& id) -> void = 0;
310 virtual auto clear() -> void = 0;
311 };
312
313 template<typename Type>
314 class container : public container_base {
315
316 public:
317
318 container() {
319
320 }
321
322 ~container() override {
323
324 }
325
326 auto remove(const math::uuid& id) -> void override {
327 _assets.erase(id);
328 }
329
330 auto clear() -> void override {
331 _assets.clear();
332 }
333
334 template<typename... Args>
335 auto add(const math::uuid& id, Args&&... args) -> void {
336 _assets.insert({id, std::make_unique<Type>(std::forward<Args>(args)...)});
337 }
338
339 auto add(const math::uuid& id, std::unique_ptr<Type>&& asset) -> void {
340 _assets.insert({id, std::move(asset)});
341 }
342
343 auto get(const math::uuid& id) const -> const Type& {
344 const auto entry = _assets.find(id);
345
346 if (entry == _assets.end()) {
347 throw utility::runtime_error{"Asset with ID '{}' not found", id};
348 }
349
350 return *entry->second;
351 }
352
353 auto get(const math::uuid& id) -> Type& {
354 auto entry = _assets.find(id);
355
356 if (entry == _assets.end()) {
357 throw utility::runtime_error{"Asset with ID '{}' not found", id};
358 }
359
360 return *entry->second;
361 }
362
363 private:
364
365 std::unordered_map<math::uuid, std::unique_ptr<Type>> _assets;
366
367 };
368
369 std::vector<std::unique_ptr<container_base>> _containers;
370
371 asset_io_registry _asset_io_registry;
372
373}; // class assets_module
374
375} // namespace sbx::assets
376
377#endif // LIBSBX_ASSETS_ASSETS_MODULE_HPP_
Definition: assets_module.hpp:107
Definition: assets_module.hpp:152
Definition: thread_pool.hpp:23
Definition: module.hpp:92
Definition: alias.hpp:13
Definition: native_filesystem.hpp:20
Definition: uuid.hpp:160
Definition: string_literal.hpp:30
Definition: logger.hpp:124
Definition: assets_module.hpp:53
Definition: assets_module.hpp:101
Definition: assets_module.hpp:94
Definition: assets_module.hpp:34
Definition: exception.hpp:18
A scoped type ID generator. Allows for generating unique IDs for types within a specific scope.
Definition: type_id.hpp:31
static auto value() noexcept -> std::uint32_t
Generates a unique ID for the type.
Definition: type_id.hpp:41