[nostalgia/core] Add AssetManager
This commit is contained in:
parent
a3dd2b59cc
commit
e29f65f351
@ -25,6 +25,7 @@ endif()
|
|||||||
|
|
||||||
install(
|
install(
|
||||||
FILES
|
FILES
|
||||||
|
assetmanager.hpp
|
||||||
color.hpp
|
color.hpp
|
||||||
config.hpp
|
config.hpp
|
||||||
consts.hpp
|
consts.hpp
|
||||||
|
183
src/nostalgia/core/assetmanager.hpp
Normal file
183
src/nostalgia/core/assetmanager.hpp
Normal file
@ -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 <ox/model/typenamecatcher.hpp>
|
||||||
|
#include <ox/fs/fs.hpp>
|
||||||
|
#include <ox/std/hashmap.hpp>
|
||||||
|
#include <ox/std/utility.hpp>
|
||||||
|
|
||||||
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class AssetRef;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct AssetContainer {
|
||||||
|
|
||||||
|
friend AssetRef<T>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
T m_obj;
|
||||||
|
mutable int m_references = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class... Args>
|
||||||
|
explicit AssetContainer(Args&&... args): m_obj(ox::forward<Args>(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<typename T>
|
||||||
|
class AssetRef {
|
||||||
|
private:
|
||||||
|
const AssetContainer<T> *m_ctr = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit AssetRef(const AssetContainer<T> *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<typename T>
|
||||||
|
class AssetTypeManager: public AssetTypeManagerBase {
|
||||||
|
private:
|
||||||
|
ox::HashMap<ox::String, ox::UniquePtr<AssetContainer<T>>> m_cache;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ox::Result<AssetRef<T>> getAsset(const ox::String &path) const noexcept {
|
||||||
|
auto out = m_cache.at(path);
|
||||||
|
oxReturnError(out);
|
||||||
|
return AssetRef<T>(out.value.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Result<AssetRef<T>> setAsset(const ox::String &path, const T &obj) noexcept {
|
||||||
|
auto &p = m_cache[path] = ox::make_unique<AssetContainer<T>>(obj);
|
||||||
|
return AssetRef<T>(p.get());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ox::HashMap<ox::String, ox::UniquePtr<AssetTypeManagerBase>> m_assetTypeManagers;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
AssetTypeManager<T> *getTypeManager() noexcept {
|
||||||
|
#if __cplusplus >= 202002L
|
||||||
|
constexpr auto typeName = ox::getModelTypeName<T>();
|
||||||
|
static_assert(ox_strcmp(typeName, "") != 0, "Types must have TypeName to use AssetManager");
|
||||||
|
#else
|
||||||
|
const auto typeName = ox::getModelTypeName<T>();
|
||||||
|
oxAssert(ox_strcmp(typeName, "") != 0, "Types must have TypeName to use AssetManager");
|
||||||
|
#endif
|
||||||
|
auto &am = m_assetTypeManagers[typeName];
|
||||||
|
if (!am) {
|
||||||
|
am = ox::make_unique<AssetTypeManager<T>>();
|
||||||
|
}
|
||||||
|
return dynamic_cast<AssetTypeManager<T>*>(am.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
ox::Result<AssetRef<T>> getAsset(const ox::String &path) noexcept {
|
||||||
|
auto m = getTypeManager<T>();
|
||||||
|
return m->getAsset(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ox::Result<AssetRef<T>> setAsset(const ox::String &path, const T &obj) noexcept {
|
||||||
|
auto m = getTypeManager<T>();
|
||||||
|
return m->setAsset(path, obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -37,9 +37,10 @@ static void handleGlfwKeyEvent(GLFWwindow *window, int key, int, int action, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Context>> init(ox::FileSystem *fs) noexcept {
|
ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, const char *appName) noexcept {
|
||||||
auto ctx = ox::make_unique<Context>();
|
auto ctx = ox::make_unique<Context>();
|
||||||
ctx->rom = fs;
|
ctx->rom = std::move(fs);
|
||||||
|
ctx->appName = appName;
|
||||||
const auto id = new GlfwImplData;
|
const auto id = new GlfwImplData;
|
||||||
ctx->setWindowerData(id);
|
ctx->setWindowerData(id);
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
@ -16,9 +16,26 @@
|
|||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<T> readObj(Context *ctx, const ox::FileAddress &file) noexcept {
|
ox::Result<AssetRef<T>> readObj(Context *ctx, const ox::FileAddress &file, bool forceLoad = false) noexcept {
|
||||||
oxRequire(buff, ctx->rom->read(file));
|
#ifndef OX_BARE_METAL
|
||||||
return ox::readClaw<T>(buff);
|
oxRequire(path, file.getPath());
|
||||||
|
if (forceLoad) {
|
||||||
|
oxRequire(buff, ctx->rom->read(file));
|
||||||
|
oxRequire(obj, ox::readClaw<T>(buff));
|
||||||
|
oxRequire(cached, ctx->assetManager.template setAsset(path, obj));
|
||||||
|
return cached;
|
||||||
|
} else {
|
||||||
|
auto [cached, err] = ctx->assetManager.template getAsset<T>(path);
|
||||||
|
if (err) {
|
||||||
|
oxRequire(buff, ctx->rom->read(file));
|
||||||
|
oxRequire(obj, ox::readClaw<T>(buff));
|
||||||
|
oxReturnError(ctx->assetManager.template setAsset(path, obj).moveTo(&cached));
|
||||||
|
}
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return OxError(1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(const char *path) noexcept;
|
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(const char *path) noexcept;
|
||||||
|
@ -32,22 +32,22 @@ ox::Error loadBgTileSheet(Context *ctx,
|
|||||||
const ox::FileAddress &tilesheetPath,
|
const ox::FileAddress &tilesheetPath,
|
||||||
const ox::FileAddress &palettePath) noexcept {
|
const ox::FileAddress &palettePath) noexcept {
|
||||||
oxRequire(tilesheet, readObj<NostalgiaGraphic>(ctx, tilesheetPath));
|
oxRequire(tilesheet, readObj<NostalgiaGraphic>(ctx, tilesheetPath));
|
||||||
oxRequire(palette, readObj<NostalgiaPalette>(ctx, palettePath ? palettePath : tilesheet.defaultPalette));
|
oxRequire(palette, readObj<NostalgiaPalette>(ctx, palettePath ? palettePath : tilesheet->defaultPalette));
|
||||||
const unsigned bytesPerTile = tilesheet.bpp == 8 ? 64 : 32;
|
const unsigned bytesPerTile = tilesheet->bpp == 8 ? 64 : 32;
|
||||||
const auto tiles = tilesheet.pixels.size() / bytesPerTile;
|
const auto tiles = tilesheet->pixels.size() / bytesPerTile;
|
||||||
constexpr int width = 8;
|
constexpr int width = 8;
|
||||||
const int height = 8 * static_cast<int>(tiles);
|
const int height = 8 * static_cast<int>(tiles);
|
||||||
ox::Vector<uint32_t> pixels;
|
ox::Vector<uint32_t> pixels;
|
||||||
if (bytesPerTile == 64) { // 8 BPP
|
if (bytesPerTile == 64) { // 8 BPP
|
||||||
pixels.resize(tilesheet.pixels.size());
|
pixels.resize(tilesheet->pixels.size());
|
||||||
for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) {
|
for (std::size_t i = 0; i < tilesheet->pixels.size(); ++i) {
|
||||||
pixels[i] = toColor32(palette.colors[tilesheet.pixels[i]]);
|
pixels[i] = toColor32(palette->colors[tilesheet->pixels[i]]);
|
||||||
}
|
}
|
||||||
} else { // 4 BPP
|
} else { // 4 BPP
|
||||||
pixels.resize(tilesheet.pixels.size() * 2);
|
pixels.resize(tilesheet->pixels.size() * 2);
|
||||||
for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) {
|
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 + 0] = toColor32(palette->colors[tilesheet->pixels[i] & 0xF]);
|
||||||
pixels[i * 2 + 1] = toColor32(palette.colors[tilesheet.pixels[i] >> 4]);
|
pixels[i * 2 + 1] = toColor32(palette->colors[tilesheet->pixels[i] >> 4]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return renderer::loadBgTexture(ctx, section, pixels.data(), width, height);
|
return renderer::loadBgTexture(ctx, section, pixels.data(), width, height);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user