#pragma once #ifndef SNAKE_ASSETMANAGER_HXX #define SNAKE_ASSETMANAGER_HXX #include "../SDLRenderer.hxx" #include #include #include #include #include #include #include class AssetManager final : private boost::noncopyable { public: explicit AssetManager(SDLRenderer& renderer); ~AssetManager(); static AssetManager& instance() noexcept; float get_progress() const; SDL_Texture* get_texture_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 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(Asset const&) = default; Asset& operator=(Asset const&) = default; operator T& () { // NOLINT(*-explicit-constructor) evaluate(); return asset_.value(); } operator T const& () const { // NOLINT(*-explicit-constructor) evaluate(); return asset_.value(); } private: void evaluate() const { if (!asset_.has_value()) { asset_ = traits::get(name_); } } std::string name_; mutable std::optional asset_; }; #endif // SNAKE_ASSETMANAGER_HXX