#pragma once #ifndef SNAKE_ASSETMANAGER_HXX #define SNAKE_ASSETMANAGER_HXX #include "../SDLRenderer.hxx" #include <atomic> #include <concepts> #include <filesystem> #include <thread> #include <unordered_map> #include <SDL_ttf.h> #include <boost/noncopyable.hpp> 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<size_t> assets_loaded_{0u}; std::atomic<size_t> total_assets_{0u}; std::thread loading_thread_; SDLRenderer& renderer_; std::unordered_map<std::string, SDL_Surface*> surface_assets_; std::unordered_map<std::string, SDL_Texture*> texture_assets_; std::unordered_map<std::string, TTF_Font*> font_assets_; }; template<typename T> concept Pointer = std::is_pointer_v<T>; template<Pointer T> struct AssetTraits; template<> struct AssetTraits<SDL_Texture*> final { using type = SDL_Texture*; static type get(std::string const& name) { return AssetManager::instance().get_texture_asset(name); } }; template<> struct AssetTraits<TTF_Font*> final { using type = TTF_Font*; static type get(std::string const& name) { return AssetManager::instance().get_font_asset(name); } }; template<typename T> class Asset final { using traits = AssetTraits<T>; 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