#pragma once #include #include #include #include #include #include #include #include #include #include #include "util/stringutil.hpp" #include "graphics/core/TextureAnimation.hpp" class Assets; enum class AssetType { TEXTURE, SHADER, FONT, ATLAS, LAYOUT, SOUND, MODEL, POST_EFFECT }; namespace assetload { /// @brief final work to do in the main thread using postfunc = std::function; using setupfunc = std::function; template void assets_setup(const Assets*); class error : public std::runtime_error { AssetType type; std::string filename; std::string reason; public: error(AssetType type, std::string filename, std::string reason) : std::runtime_error(filename + ": " + reason), type(type), filename(std::move(filename)), reason(std::move(reason)) { } AssetType getAssetType() const { return type; } const std::string& getFilename() const { return filename; } const std::string& getReason() const { return reason; } }; } class Assets { std::vector animations; using assets_map = std::unordered_map>; std::unordered_map assets; std::vector setupFuncs; public: Assets() = default; Assets(const Assets&) = delete; ~Assets(); const std::vector& getAnimations(); void store(const TextureAnimation& animation); template void store(std::unique_ptr asset, const std::string& name) { assets[typeid(T)][name].reset(asset.release()); } template void store(std::shared_ptr asset, const std::string& name) { assets[typeid(T)][name] = std::move(asset); } template T* get(const std::string& name) const { const auto& mapIter = assets.find(typeid(T)); if (mapIter == assets.end()) { return nullptr; } const auto& map = mapIter->second; const auto& found = map.find(name); if (found == map.end()) { return nullptr; } return static_cast(found->second.get()); } template std::shared_ptr getShared(const std::string& name) const { const auto& mapIter = assets.find(typeid(T)); if (mapIter == assets.end()) { return nullptr; } const auto& map = mapIter->second; const auto& found = map.find(name); if (found == map.end()) { return nullptr; } return std::static_pointer_cast(found->second); } template T& require(const std::string& name) const { T* asset = get(name); if (asset == nullptr) { throw std::runtime_error(util::quote(name) + " not found"); } return *asset; } template std::optional getMap() const { const auto& mapIter = assets.find(typeid(T)); if (mapIter == assets.end()) { return std::nullopt; } return &mapIter->second; } void setup() { for (auto& setupFunc : setupFuncs) { setupFunc(this); } } void addSetupFunc(assetload::setupfunc setupfunc) { setupFuncs.push_back(setupfunc); } }; template void assetload::assets_setup(const Assets* assets) { if (auto mapPtr = assets->getMap()) { for (const auto& entry : **mapPtr) { static_cast(entry.second.get())->setup(); } } }