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/assets/thread_pool.hpp>
24#include <libsbx/assets/metadata.hpp>
26namespace sbx::assets {
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);
45template<
typename Type>
48template<utility::
string_literal Type>
51 inline static constexpr auto hash = Type.hash();
53 inline static constexpr auto invalid = std::uint32_t{0xFFFFFFFF};
59 constexpr asset_handle(
const std::uint32_t handle,
const std::uint32_t generation)
61 _generation{generation} { }
63 constexpr auto handle()
const noexcept -> std::uint32_t {
67 constexpr auto generation()
const noexcept -> std::uint32_t {
71 constexpr auto operator==(
const asset_handle& other)
const noexcept ->
bool {
72 return _handle == other._handle && _generation == other._generation;
75 constexpr auto is_valid()
const noexcept ->
bool {
76 return _handle != invalid;
79 constexpr operator bool()
const noexcept {
85 std::uint32_t _handle;
86 std::uint32_t _generation;
91 std::filesystem::path path;
93 std::string type{
"unknown"};
94 std::string source{
"dynamic"};
99 std::function<void()> save;
100 std::function<void()> load;
109 template<
typename Type>
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 {
120 .save = [s = std::forward<Save>(save)]() ->
void {
123 .load = []() ->
void {
129 auto get(
const std::uint32_t
id) ->
asset_io& {
130 return _by_id.at(
id);
133 auto has(
const std::uint32_t
id) ->
bool {
134 return _by_id.contains(
id);
137 auto get(
const std::string& name) ->
asset_io& {
138 return _by_id.at(_by_name.at(name));
143 std::unordered_map<std::uint32_t, asset_io> _by_id;
144 std::unordered_map<std::string, std::uint32_t> _by_name;
150 inline static const auto is_registered = register_module(stage::post);
152 inline static constexpr auto prefix = std::string_view{
"res://"};
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">());
163 for (
const auto& container : _containers) {
168 auto update() ->
void override {
172 auto asset_root()
const ->
const std::filesystem::path& {
176 auto set_asset_root(
const std::filesystem::path& root) ->
void {
177 if (!std::filesystem::exists(root)) {
181 utility::logger<
"assets">::debug(
"Setting asset_root to '{}'", root.string());
186 auto resolve_path(
const std::filesystem::path& path) -> std::filesystem::path {
191 const auto& path_string = path.string();
193 if (path_string.starts_with(prefix)) {
194 return _asset_root / path_string.substr(prefix.size());
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)...);
207 auto load_asset(
const std::filesystem::path& path, Args&&... args) ->
asset_handle<Type> {
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));
217 return _asset_io_registry.get(
id);
220 auto has_asset_io(
const std::uint32_t
id) ->
bool {
221 return _asset_io_registry.has(
id);
224 template<
typename Type,
typename... Args>
225 auto add_asset(Args&&... args) ->
math::uuid {
229 if (type >= _containers.size()) {
230 _containers.resize(std::max(_containers.size(),
static_cast<std::size_t
>(type + 1u)));
233 if (!_containers[type]) {
234 _containers[type] = std::make_unique<container<Type>>();
237 static_cast<container<Type>*
>(_containers[type].get())->add(
id, std::forward<Args>(args)...);
242 template<
typename Type>
243 auto add_asset(std::unique_ptr<Type>&& asset) ->
math::uuid {
247 if (type >= _containers.size()) {
248 _containers.resize(std::max(_containers.size(),
static_cast<std::size_t
>(type + 1u)));
251 if (!_containers[type]) {
252 _containers[type] = std::make_unique<container<Type>>();
255 static_cast<container<Type>*
>(_containers[type].get())->add(
id, std::move(asset));
260 template<
typename Type>
261 auto get_asset(
const math::uuid&
id)
const ->
const Type& {
264 if (type >= _containers.size() || !_containers[type]) {
265 throw std::runtime_error{
"Asset does not exist"};
268 return static_cast<const container<Type>*
>(_containers[type].get())->get(
id);
271 template<
typename Type>
272 auto get_asset(
const math::uuid&
id) -> Type& {
275 if (type >= _containers.size() || !_containers[type]) {
276 throw std::runtime_error{
"Asset does not exist"};
279 return static_cast<container<Type>*
>(_containers[type].get())->get(
id);
285 std::filesystem::path _asset_root;
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;
293 template<
typename Type>
294 class container :
public container_base {
302 ~container()
override {
306 auto remove(
const math::uuid&
id) ->
void override {
310 auto clear() ->
void override {
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)...)});
319 auto add(
const math::uuid&
id, std::unique_ptr<Type>&& asset) ->
void {
320 _assets.insert({id, std::move(asset)});
323 auto get(
const math::uuid&
id)
const ->
const Type& {
324 const auto entry = _assets.find(
id);
326 if (entry == _assets.end()) {
330 return *entry->second;
334 auto entry = _assets.find(
id);
336 if (entry == _assets.end()) {
340 return *entry->second;
345 std::unordered_map<math::uuid, std::unique_ptr<Type>> _assets;
349 std::vector<std::unique_ptr<container_base>> _containers;
Definition: assets_module.hpp:103
Definition: assets_module.hpp:148
Definition: thread_pool.hpp:23
Definition: module.hpp:92
Definition: string_literal.hpp:30
Definition: logger.hpp:124
Definition: assets_module.hpp:49
Definition: assets_module.hpp:97
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