From e29f65f351941f88dda198301fa60a45f6ce9ee7 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sat, 30 Oct 2021 17:03:24 -0500 Subject: [PATCH] [nostalgia/core] Add AssetManager --- src/nostalgia/core/CMakeLists.txt | 1 + src/nostalgia/core/assetmanager.hpp | 183 ++++++++++++++++++++++++++++ src/nostalgia/core/glfw/core.cpp | 5 +- src/nostalgia/core/media.hpp | 23 +++- src/nostalgia/core/userland/gfx.cpp | 20 +-- 5 files changed, 217 insertions(+), 15 deletions(-) create mode 100644 src/nostalgia/core/assetmanager.hpp diff --git a/src/nostalgia/core/CMakeLists.txt b/src/nostalgia/core/CMakeLists.txt index 92bfc075..73de3f3e 100644 --- a/src/nostalgia/core/CMakeLists.txt +++ b/src/nostalgia/core/CMakeLists.txt @@ -25,6 +25,7 @@ endif() install( FILES + assetmanager.hpp color.hpp config.hpp consts.hpp diff --git a/src/nostalgia/core/assetmanager.hpp b/src/nostalgia/core/assetmanager.hpp new file mode 100644 index 00000000..9599d275 --- /dev/null +++ b/src/nostalgia/core/assetmanager.hpp @@ -0,0 +1,183 @@ +/* + * Copyright 2016 - 2021 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include +#include + +namespace nostalgia::core { + +template +class AssetRef; + +template +struct AssetContainer { + + friend AssetRef; + + private: + T m_obj; + mutable int m_references = 0; + + public: + template + explicit AssetContainer(Args&&... args): m_obj(ox::forward(args)...) { + } + + constexpr T *get() noexcept { + return &m_obj; + } + + constexpr const T *get() const noexcept { + return &m_obj; + } + + protected: + constexpr void incRefs() const noexcept { + ++m_references; + } + + constexpr void decRefs() const noexcept { + --m_references; + } + +}; + +template +class AssetRef { + private: + const AssetContainer *m_ctr = nullptr; + + public: + explicit AssetRef(const AssetContainer *c = nullptr) noexcept: m_ctr(c) { + } + + AssetRef(const AssetRef &h) noexcept { + m_ctr = h.m_ctr; + if (m_ctr) { + m_ctr->incRefs(); + } + } + + AssetRef(AssetRef &&h) noexcept { + m_ctr = h.m_ctr; + h.m_ctr = nullptr; + } + + ~AssetRef() noexcept { + if (m_ctr) { + m_ctr->decRefs(); + } + } + + constexpr const T *get() const noexcept { + return m_ctr->get(); + } + + constexpr const T &operator*() const & noexcept { + return *m_ctr->get(); + } + + constexpr const T &&operator*() const && noexcept { + return *m_ctr->get(); + } + + constexpr const T *operator->() const noexcept { + return m_ctr->get(); + } + + AssetRef &operator=(const AssetRef &h) noexcept { + if (this == &h) { + return *this; + } + if (m_ctr) { + m_ctr->decRefs(); + } + m_ctr = h.m_ctr; + if (m_ctr) { + m_ctr->incRefs(); + } + return *this; + } + + AssetRef &operator=(AssetRef &&h) noexcept { + if (this == &h) { + return *this; + } + m_ctr = h.m_ctr; + h.m_ctr = nullptr; + return *this; + } + + explicit constexpr operator bool() const noexcept { + return m_ctr; + } + +}; + +class AssetManager { + private: + class AssetTypeManagerBase { + public: + virtual ~AssetTypeManagerBase() = default; + }; + + template + class AssetTypeManager: public AssetTypeManagerBase { + private: + ox::HashMap>> m_cache; + + public: + ox::Result> getAsset(const ox::String &path) const noexcept { + auto out = m_cache.at(path); + oxReturnError(out); + return AssetRef(out.value.get()); + } + + ox::Result> setAsset(const ox::String &path, const T &obj) noexcept { + auto &p = m_cache[path] = ox::make_unique>(obj); + return AssetRef(p.get()); + } + }; + + ox::HashMap> m_assetTypeManagers; + + template + AssetTypeManager *getTypeManager() noexcept { +#if __cplusplus >= 202002L + constexpr auto typeName = ox::getModelTypeName(); + static_assert(ox_strcmp(typeName, "") != 0, "Types must have TypeName to use AssetManager"); +#else + const auto typeName = ox::getModelTypeName(); + oxAssert(ox_strcmp(typeName, "") != 0, "Types must have TypeName to use AssetManager"); +#endif + auto &am = m_assetTypeManagers[typeName]; + if (!am) { + am = ox::make_unique>(); + } + return dynamic_cast*>(am.get()); + } + + public: + template + ox::Result> getAsset(const ox::String &path) noexcept { + auto m = getTypeManager(); + return m->getAsset(path); + } + + template + ox::Result> setAsset(const ox::String &path, const T &obj) noexcept { + auto m = getTypeManager(); + return m->setAsset(path, obj); + } +}; + +} \ No newline at end of file diff --git a/src/nostalgia/core/glfw/core.cpp b/src/nostalgia/core/glfw/core.cpp index db6af7f2..8f22f655 100644 --- a/src/nostalgia/core/glfw/core.cpp +++ b/src/nostalgia/core/glfw/core.cpp @@ -37,9 +37,10 @@ static void handleGlfwKeyEvent(GLFWwindow *window, int key, int, int action, int } } -ox::Result> init(ox::FileSystem *fs) noexcept { +ox::Result> init(ox::UniquePtr fs, const char *appName) noexcept { auto ctx = ox::make_unique(); - ctx->rom = fs; + ctx->rom = std::move(fs); + ctx->appName = appName; const auto id = new GlfwImplData; ctx->setWindowerData(id); using namespace std::chrono; diff --git a/src/nostalgia/core/media.hpp b/src/nostalgia/core/media.hpp index b4875573..054fab34 100644 --- a/src/nostalgia/core/media.hpp +++ b/src/nostalgia/core/media.hpp @@ -16,9 +16,26 @@ namespace nostalgia::core { template -ox::Result readObj(Context *ctx, const ox::FileAddress &file) noexcept { - oxRequire(buff, ctx->rom->read(file)); - return ox::readClaw(buff); +ox::Result> readObj(Context *ctx, const ox::FileAddress &file, bool forceLoad = false) noexcept { +#ifndef OX_BARE_METAL + oxRequire(path, file.getPath()); + if (forceLoad) { + oxRequire(buff, ctx->rom->read(file)); + oxRequire(obj, ox::readClaw(buff)); + oxRequire(cached, ctx->assetManager.template setAsset(path, obj)); + return cached; + } else { + auto [cached, err] = ctx->assetManager.template getAsset(path); + if (err) { + oxRequire(buff, ctx->rom->read(file)); + oxRequire(obj, ox::readClaw(buff)); + oxReturnError(ctx->assetManager.template setAsset(path, obj).moveTo(&cached)); + } + return cached; + } +#else + return OxError(1); +#endif } ox::Result> loadRomFs(const char *path) noexcept; diff --git a/src/nostalgia/core/userland/gfx.cpp b/src/nostalgia/core/userland/gfx.cpp index 979a0c47..c502713a 100644 --- a/src/nostalgia/core/userland/gfx.cpp +++ b/src/nostalgia/core/userland/gfx.cpp @@ -32,22 +32,22 @@ ox::Error loadBgTileSheet(Context *ctx, const ox::FileAddress &tilesheetPath, const ox::FileAddress &palettePath) noexcept { oxRequire(tilesheet, readObj(ctx, tilesheetPath)); - oxRequire(palette, readObj(ctx, palettePath ? palettePath : tilesheet.defaultPalette)); - const unsigned bytesPerTile = tilesheet.bpp == 8 ? 64 : 32; - const auto tiles = tilesheet.pixels.size() / bytesPerTile; + oxRequire(palette, readObj(ctx, palettePath ? palettePath : tilesheet->defaultPalette)); + const unsigned bytesPerTile = tilesheet->bpp == 8 ? 64 : 32; + const auto tiles = tilesheet->pixels.size() / bytesPerTile; constexpr int width = 8; const int height = 8 * static_cast(tiles); ox::Vector pixels; if (bytesPerTile == 64) { // 8 BPP - pixels.resize(tilesheet.pixels.size()); - for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) { - pixels[i] = toColor32(palette.colors[tilesheet.pixels[i]]); + pixels.resize(tilesheet->pixels.size()); + for (std::size_t i = 0; i < tilesheet->pixels.size(); ++i) { + pixels[i] = toColor32(palette->colors[tilesheet->pixels[i]]); } } else { // 4 BPP - pixels.resize(tilesheet.pixels.size() * 2); - for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) { - pixels[i * 2 + 0] = toColor32(palette.colors[tilesheet.pixels[i] & 0xF]); - pixels[i * 2 + 1] = toColor32(palette.colors[tilesheet.pixels[i] >> 4]); + pixels.resize(tilesheet->pixels.size() * 2); + for (std::size_t i = 0; i < tilesheet->pixels.size(); ++i) { + pixels[i * 2 + 0] = toColor32(palette->colors[tilesheet->pixels[i] & 0xF]); + pixels[i * 2 + 1] = toColor32(palette->colors[tilesheet->pixels[i] >> 4]); } } return renderer::loadBgTexture(ctx, section, pixels.data(), width, height);