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