#pragma once #ifndef SNAKE_ASSETMANAGER_HXX #define SNAKE_ASSETMANAGER_HXX #include "../SDLRenderer.hxx" #include #include #include #include #include #include #include "../NonCopyable.hxx" class AssetManager final : private NonCopyable { public: explicit AssetManager(SDLRenderer& renderer); ~AssetManager(); static AssetManager& instance() noexcept; float get_progress() const; SDL_Texture* get_texture_asset(std::string const& filepath); SDL_Surface* get_surface_asset(std::string const& filepath); TTF_Font* get_font_asset(std::string const& filepath); private: void load_assets(std::filesystem::path const& asset_directory); static AssetManager* instance_; std::atomic assets_loaded_{0u}; std::atomic total_assets_{0u}; std::thread loading_thread_; SDLRenderer& renderer_; std::unordered_map surface_assets_; std::unordered_map texture_assets_; std::unordered_map font_assets_; }; template concept Pointer = std::is_pointer_v; template struct AssetTraits; template<> struct AssetTraits final { using type = SDL_Texture*; static type get(std::string const& name) { return AssetManager::instance().get_texture_asset(name); } }; template<> struct AssetTraits final { using type = TTF_Font*; static type get(std::string const& name) { return AssetManager::instance().get_font_asset(name); } }; template class Asset final { using traits = AssetTraits; public: explicit Asset(std::string name) :name_{std::move(name)}, asset_{nullptr} { } Asset(Asset const&) = default; Asset& operator=(Asset const&) = default; operator T&() // NOLINT(*-explicit-constructor) { evaluate(); return asset_; } operator T const&() const // NOLINT(*-explicit-constructor) { evaluate(); return asset_; } private: void evaluate() const { if (asset_==nullptr) { asset_ = traits::get(name_); } } std::string name_; mutable T asset_; }; #endif // SNAKE_ASSETMANAGER_HXX