2#ifndef LIBSBX_ASSETS_ASSETS_MODULE_HPP_
3#define LIBSBX_ASSETS_ASSETS_MODULE_HPP_
6#include <unordered_map>
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>
19#include <libsbx/math/uuid.hpp>
21#include <libsbx/core/module.hpp>
23#include <libsbx/filesystem/alias.hpp>
24#include <libsbx/filesystem/filesystem_module.hpp>
25#include <libsbx/filesystem/native_filesystem.hpp>
27#include <libsbx/assets/thread_pool.hpp>
28#include <libsbx/assets/metadata.hpp>
30namespace sbx::assets {
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);
49template<
typename Type>
52template<utility::
string_literal Type>
55 inline static constexpr auto hash = Type.hash();
57 inline static constexpr auto invalid = std::uint32_t{0xFFFFFFFF};
63 constexpr asset_handle(
const std::uint32_t handle,
const std::uint32_t generation)
65 _generation{generation} { }
67 constexpr auto handle()
const noexcept -> std::uint32_t {
71 constexpr auto generation()
const noexcept -> std::uint32_t {
75 constexpr auto operator==(
const asset_handle& other)
const noexcept ->
bool {
76 return _handle == other._handle && _generation == other._generation;
79 constexpr auto is_valid()
const noexcept ->
bool {
80 return _handle != invalid;
83 constexpr operator bool()
const noexcept {
89 std::uint32_t _handle;
90 std::uint32_t _generation;
95 std::filesystem::path path;
97 std::string type{
"unknown"};
98 std::string source{
"dynamic"};
103 std::function<void()> save;
104 std::function<void()> load;
113 template<
typename Type>
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 {
124 .save = [s = std::forward<Save>(save)]() ->
void {
127 .load = []() ->
void {
133 auto get(
const std::uint32_t
id) ->
asset_io& {
134 return _by_id.at(
id);
137 auto has(
const std::uint32_t
id) ->
bool {
138 return _by_id.contains(
id);
141 auto get(
const std::string& name) ->
asset_io& {
142 return _by_id.at(_by_name.at(name));
147 std::unordered_map<std::uint32_t, asset_io> _by_id;
148 std::unordered_map<std::string, std::uint32_t> _by_name;
154 inline static const auto is_registered = register_module(stage::post);
156 inline static constexpr auto prefix = std::string_view{
"res://"};
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">());
167 for (
const auto& container : _containers) {
172 auto update() ->
void override {
176 auto asset_root()
const ->
const std::filesystem::path& {
180 auto set_asset_root(
const std::filesystem::path& root) ->
void {
181 if (!std::filesystem::exists(root)) {
185 utility::logger<
"assets">::debug(
"Setting asset_root to '{}'", root.string());
189 auto& filesystem_module = core::engine::get_module<filesystem::filesystem_module>();
193 if (filesystem_module.is_alias_registered(alias)) {
194 filesystem_module.unregister_alias(alias);
200 auto resolve_path(
const std::filesystem::path& path) -> std::filesystem::path {
205 auto& filesystem_module = core::engine::get_module<filesystem::filesystem_module>();
208 return filesystem_module.native_path_of(path);
211 const auto& path_string = path.string();
213 if (path_string.starts_with(prefix)) {
214 return _asset_root / path_string.substr(prefix.size());
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)...);
227 auto load_asset(
const std::filesystem::path& path, Args&&... args) ->
asset_handle<Type> {
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));
237 return _asset_io_registry.get(
id);
240 auto has_asset_io(
const std::uint32_t
id) ->
bool {
241 return _asset_io_registry.has(
id);
244 template<
typename Type,
typename... Args>
245 auto add_asset(Args&&... args) ->
math::uuid {
249 if (type >= _containers.size()) {
250 _containers.resize(std::max(_containers.size(),
static_cast<std::size_t
>(type + 1u)));
253 if (!_containers[type]) {
254 _containers[type] = std::make_unique<container<Type>>();
257 static_cast<container<Type>*
>(_containers[type].get())->add(
id, std::forward<Args>(args)...);
262 template<
typename Type>
263 auto add_asset(std::unique_ptr<Type>&& asset) ->
math::uuid {
267 if (type >= _containers.size()) {
268 _containers.resize(std::max(_containers.size(),
static_cast<std::size_t
>(type + 1u)));
271 if (!_containers[type]) {
272 _containers[type] = std::make_unique<container<Type>>();
275 static_cast<container<Type>*
>(_containers[type].get())->add(
id, std::move(asset));
280 template<
typename Type>
281 auto get_asset(
const math::uuid&
id)
const ->
const Type& {
284 if (type >= _containers.size() || !_containers[type]) {
285 throw std::runtime_error{
"Asset does not exist"};
288 return static_cast<const container<Type>*
>(_containers[type].get())->get(
id);
291 template<
typename Type>
292 auto get_asset(
const math::uuid&
id) -> Type& {
295 if (type >= _containers.size() || !_containers[type]) {
296 throw std::runtime_error{
"Asset does not exist"};
299 return static_cast<container<Type>*
>(_containers[type].get())->get(
id);
305 std::filesystem::path _asset_root;
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;
313 template<
typename Type>
314 class container :
public container_base {
322 ~container()
override {
326 auto remove(
const math::uuid&
id) ->
void override {
330 auto clear() ->
void override {
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)...)});
339 auto add(
const math::uuid&
id, std::unique_ptr<Type>&& asset) ->
void {
340 _assets.insert({id, std::move(asset)});
343 auto get(
const math::uuid&
id)
const ->
const Type& {
344 const auto entry = _assets.find(
id);
346 if (entry == _assets.end()) {
350 return *entry->second;
354 auto entry = _assets.find(
id);
356 if (entry == _assets.end()) {
360 return *entry->second;
365 std::unordered_map<math::uuid, std::unique_ptr<Type>> _assets;
369 std::vector<std::unique_ptr<container_base>> _containers;
Definition: assets_module.hpp:107
Definition: assets_module.hpp:152
Definition: thread_pool.hpp:23
Definition: module.hpp:92
Definition: native_filesystem.hpp:20
Definition: string_literal.hpp:30
Definition: logger.hpp:124
Definition: assets_module.hpp:53
Definition: assets_module.hpp:101
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