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, dependencies<filesystem::filesystem_module>{});
155
156public:
157
159 : _thread_pool{std::thread::hardware_concurrency()} {
160 _register_asset_root(std::filesystem::current_path());
161 }
162
163 ~assets_module() override {
164 for (const auto& container : _containers) {
165 container->clear();
166 }
167 }
168
169 auto update() -> void override {
170
171 }
172
173 auto asset_root() const -> std::filesystem::path {
174 auto& filesystem_module = core::engine::get_module<filesystem::filesystem_module>();
175
176 return filesystem_module.native_path_of(std::string{"res://"});
177 }
178
179 auto set_asset_root(const std::filesystem::path& root) -> void {
180 if (!std::filesystem::exists(root)) {
181 throw utility::runtime_error{"New asset root path '{}' does not exist", root.string()};
182 }
183
184 utility::logger<"assets">::debug("Setting asset_root to '{}'", root.string());
185
186 _register_asset_root(root);
187 }
188
189 auto resolve_path(const std::filesystem::path& path) -> std::filesystem::path {
190 auto& filesystem_module = core::engine::get_module<filesystem::filesystem_module>();
191
192 return filesystem_module.native_path_of(path);
193 }
194
195 template<typename Function, typename... Args>
196 requires (std::is_invocable_v<Function, Args...>)
197 auto submit(Function&& function, Args&&... args) -> std::future<std::invoke_result_t<Function, Args...>> {
198 return _thread_pool.submit(std::forward<Function>(function), std::forward<Args>(args)...);
199 }
200
201 template<utility::string_literal Type, typename... Args>
202 auto load_asset(const std::filesystem::path& path, Args&&... args) -> asset_handle<Type> {
203
204 }
205
206 template<typename Type, std::invocable<void> Save, std::invocable<void> Load>
207 auto register_asset(const std::string& name, Save&& save, Load&& load) -> void {
208 _asset_io_registry.register_asset<Type>(name, std::forward<Save>(save), std::forward<Load>(load));
209 }
210
211 auto asset_io(const std::uint32_t id) -> asset_io& {
212 return _asset_io_registry.get(id);
213 }
214
215 auto has_asset_io(const std::uint32_t id) -> bool {
216 return _asset_io_registry.has(id);
217 }
218
219 template<typename Type, typename... Args>
220 auto add_asset(Args&&... args) -> math::uuid {
221 const auto id = math::uuid{};
222 const auto type = type_id<Type>::value();
223
224 if (type >= _containers.size()) {
225 _containers.resize(std::max(_containers.size(), static_cast<std::size_t>(type + 1u)));
226 }
227
228 if (!_containers[type]) {
229 _containers[type] = std::make_unique<container<Type>>();
230 }
231
232 static_cast<container<Type>*>(_containers[type].get())->add(id, std::forward<Args>(args)...);
233
234 return id;
235 }
236
237 template<typename Type>
238 auto add_asset(std::unique_ptr<Type>&& asset) -> math::uuid {
239 const auto id = math::uuid{};
240 const auto type = type_id<Type>::value();
241
242 if (type >= _containers.size()) {
243 _containers.resize(std::max(_containers.size(), static_cast<std::size_t>(type + 1u)));
244 }
245
246 if (!_containers[type]) {
247 _containers[type] = std::make_unique<container<Type>>();
248 }
249
250 static_cast<container<Type>*>(_containers[type].get())->add(id, std::move(asset));
251
252 return id;
253 }
254
255 template<typename Type>
256 auto get_asset(const math::uuid& id) const -> const Type& {
257 const auto type = type_id<Type>::value();
258
259 if (type >= _containers.size() || !_containers[type]) {
260 throw std::runtime_error{"Asset does not exist"};
261 }
262
263 return static_cast<const container<Type>*>(_containers[type].get())->get(id);
264 }
265
266 template<typename Type>
267 auto get_asset(const math::uuid& id) -> Type& {
268 const auto type = type_id<Type>::value();
269
270 if (type >= _containers.size() || !_containers[type]) {
271 throw std::runtime_error{"Asset does not exist"};
272 }
273
274 return static_cast<container<Type>*>(_containers[type].get())->get(id);
275 }
276
277private:
278
279 auto _register_asset_root(const std::filesystem::path& root) -> void {
280 auto& filesystem_module = core::engine::get_module<filesystem::filesystem_module>();
281
282 const auto alias = filesystem::alias{"res://"};
283
284 if (filesystem_module.is_alias_registered(alias)) {
285 filesystem_module.unregister_alias(alias);
286 }
287
288 filesystem_module.create_filesystem<filesystem::native_filesystem>(alias, root.generic_string());
289 }
290
291 thread_pool _thread_pool;
292
293 struct container_base {
294 virtual ~container_base() = default;
295 virtual auto remove(const math::uuid& id) -> void = 0;
296 virtual auto clear() -> void = 0;
297 };
298
299 template<typename Type>
300 class container : public container_base {
301
302 public:
303
304 container() {
305
306 }
307
308 ~container() override {
309
310 }
311
312 auto remove(const math::uuid& id) -> void override {
313 _assets.erase(id);
314 }
315
316 auto clear() -> void override {
317 _assets.clear();
318 }
319
320 template<typename... Args>
321 auto add(const math::uuid& id, Args&&... args) -> void {
322 _assets.insert({id, std::make_unique<Type>(std::forward<Args>(args)...)});
323 }
324
325 auto add(const math::uuid& id, std::unique_ptr<Type>&& asset) -> void {
326 _assets.insert({id, std::move(asset)});
327 }
328
329 auto get(const math::uuid& id) const -> const Type& {
330 const auto entry = _assets.find(id);
331
332 if (entry == _assets.end()) {
333 throw utility::runtime_error{"Asset with ID '{}' not found", id};
334 }
335
336 return *entry->second;
337 }
338
339 auto get(const math::uuid& id) -> Type& {
340 auto entry = _assets.find(id);
341
342 if (entry == _assets.end()) {
343 throw utility::runtime_error{"Asset with ID '{}' not found", id};
344 }
345
346 return *entry->second;
347 }
348
349 private:
350
351 std::unordered_map<math::uuid, std::unique_ptr<Type>> _assets;
352
353 };
354
355 std::vector<std::unique_ptr<container_base>> _containers;
356
357 asset_io_registry _asset_io_registry;
358
359}; // class assets_module
360
361} // namespace sbx::assets
362
363#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:15
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