From 7868b0678fec65bd6455dce1430d9302121221fa Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Fri, 3 Feb 2023 00:41:24 -0600 Subject: [PATCH] [nostalgia] Split part of Core out into Foundation, add module system --- src/nostalgia/CMakeLists.txt | 2 + src/nostalgia/appmodules/CMakeLists.txt | 20 +++ src/nostalgia/appmodules/appmodules.cpp | 27 +++ src/nostalgia/appmodules/appmodules.hpp | 11 ++ src/nostalgia/core/CMakeLists.txt | 11 +- src/nostalgia/core/context.hpp | 23 ++- src/nostalgia/core/core.hpp | 5 +- src/nostalgia/core/gba/gfx.cpp | 7 +- src/nostalgia/core/gba/media.cpp | 50 ------ src/nostalgia/core/glfw/core.cpp | 9 +- src/nostalgia/core/headless/media.cpp | 18 -- src/nostalgia/core/media.cpp | 24 --- src/nostalgia/core/module.cpp | 23 +++ src/nostalgia/core/module.hpp | 25 +++ src/nostalgia/core/studio/module.cpp | 4 +- src/nostalgia/core/studio/module.hpp | 2 +- .../core/studio/paletteeditor-imgui.cpp | 6 +- .../core/studio/tilesheeteditor-imgui.cpp | 4 +- .../core/studio/tilesheeteditormodel.cpp | 4 +- .../core/studio/tilesheeteditormodel.hpp | 4 +- .../core/studio/tilesheeteditorview.cpp | 4 +- src/nostalgia/core/typeconv.cpp | 92 ---------- src/nostalgia/core/typeconv.hpp | 161 ++++-------------- src/nostalgia/core/typestore.cpp | 2 +- src/nostalgia/core/typestore.hpp | 2 +- src/nostalgia/core/userland/gfx.cpp | 4 +- src/nostalgia/core/userland/media.cpp | 39 ----- src/nostalgia/foundation/CMakeLists.txt | 26 +++ .../{core => foundation}/assetmanager.hpp | 6 +- src/nostalgia/foundation/context.hpp | 34 ++++ src/nostalgia/foundation/foundation.hpp | 31 ++++ src/nostalgia/foundation/media.cpp | 110 ++++++++++++ src/nostalgia/{core => foundation}/media.hpp | 29 ++-- src/nostalgia/foundation/module.cpp | 36 ++++ src/nostalgia/foundation/module.hpp | 30 ++++ src/nostalgia/foundation/typeconv.cpp | 55 ++++++ src/nostalgia/foundation/typeconv.hpp | 155 +++++++++++++++++ src/nostalgia/player/CMakeLists.txt | 3 +- src/nostalgia/player/app.cpp | 2 + src/nostalgia/player/main.cpp | 26 +-- src/nostalgia/scene/scene.hpp | 34 ++-- src/nostalgia/studio/CMakeLists.txt | 1 + src/nostalgia/studio/builtinmodules.hpp | 6 +- src/nostalgia/studio/main.cpp | 26 +-- src/nostalgia/studio/studioapp.cpp | 3 +- src/nostalgia/tools/CMakeLists.txt | 1 + src/nostalgia/tools/pack.cpp | 4 +- src/nostalgia/tools/pack/CMakeLists.txt | 1 + src/nostalgia/tools/pack/pack.cpp | 8 +- src/nostalgia/tools/pack/pack.hpp | 2 +- 50 files changed, 742 insertions(+), 470 deletions(-) create mode 100644 src/nostalgia/appmodules/CMakeLists.txt create mode 100644 src/nostalgia/appmodules/appmodules.cpp create mode 100644 src/nostalgia/appmodules/appmodules.hpp delete mode 100644 src/nostalgia/core/gba/media.cpp delete mode 100644 src/nostalgia/core/headless/media.cpp delete mode 100644 src/nostalgia/core/media.cpp create mode 100644 src/nostalgia/core/module.cpp create mode 100644 src/nostalgia/core/module.hpp delete mode 100644 src/nostalgia/core/typeconv.cpp delete mode 100644 src/nostalgia/core/userland/media.cpp create mode 100644 src/nostalgia/foundation/CMakeLists.txt rename src/nostalgia/{core => foundation}/assetmanager.hpp (98%) create mode 100644 src/nostalgia/foundation/context.hpp create mode 100644 src/nostalgia/foundation/foundation.hpp create mode 100644 src/nostalgia/foundation/media.cpp rename src/nostalgia/{core => foundation}/media.hpp (63%) create mode 100644 src/nostalgia/foundation/module.cpp create mode 100644 src/nostalgia/foundation/module.hpp create mode 100644 src/nostalgia/foundation/typeconv.cpp create mode 100644 src/nostalgia/foundation/typeconv.hpp diff --git a/src/nostalgia/CMakeLists.txt b/src/nostalgia/CMakeLists.txt index 50a8ad6e..8165e929 100644 --- a/src/nostalgia/CMakeLists.txt +++ b/src/nostalgia/CMakeLists.txt @@ -1,7 +1,9 @@ #project packages +add_subdirectory(appmodules) add_subdirectory(core) +add_subdirectory(foundation) add_subdirectory(geo) add_subdirectory(scene) add_subdirectory(world) diff --git a/src/nostalgia/appmodules/CMakeLists.txt b/src/nostalgia/appmodules/CMakeLists.txt new file mode 100644 index 00000000..ded19ad3 --- /dev/null +++ b/src/nostalgia/appmodules/CMakeLists.txt @@ -0,0 +1,20 @@ +add_library( + NostalgiaAppModules OBJECT + appmodules.cpp +) + +if(NOT MSVC) + target_compile_options(NostalgiaAppModules PRIVATE -Wsign-conversion) +endif() + +target_link_libraries( + NostalgiaAppModules PUBLIC + NostalgiaCore +) + +install( + FILES + appmodules.hpp + DESTINATION + include/nostalgia/appmodules +) diff --git a/src/nostalgia/appmodules/appmodules.cpp b/src/nostalgia/appmodules/appmodules.cpp new file mode 100644 index 00000000..98d17a33 --- /dev/null +++ b/src/nostalgia/appmodules/appmodules.cpp @@ -0,0 +1,27 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include + +#include + +#include + +namespace nostalgia { + +void loadModules() noexcept { + static bool done = false; + if (done) { + return; + } + const ox::Array mods = { + &core::CoreModule::mod, + }; + for (const auto m : mods) { + foundation::registerModule(m); + } + done = true; +} + +} diff --git a/src/nostalgia/appmodules/appmodules.hpp b/src/nostalgia/appmodules/appmodules.hpp new file mode 100644 index 00000000..cf82c6d6 --- /dev/null +++ b/src/nostalgia/appmodules/appmodules.hpp @@ -0,0 +1,11 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +namespace nostalgia { + +void loadModules() noexcept; + +} diff --git a/src/nostalgia/core/CMakeLists.txt b/src/nostalgia/core/CMakeLists.txt index e6e11575..b0695bf0 100644 --- a/src/nostalgia/core/CMakeLists.txt +++ b/src/nostalgia/core/CMakeLists.txt @@ -1,8 +1,7 @@ add_library( NostalgiaCore-Common OBJECT gfx.cpp - media.cpp - typeconv.cpp + module.cpp typestore.cpp ) @@ -10,7 +9,6 @@ add_library( NostalgiaCore-Headless headless/core.cpp headless/gfx.cpp - headless/media.cpp ) add_library(NostalgiaCore) @@ -23,7 +21,6 @@ if(NOT NOSTALGIA_BUILD_TYPE STREQUAL "GBA") glfw/gfx.cpp userland/gfx.cpp userland/gfx_opengl.cpp - userland/media.cpp ) target_link_libraries( NostalgiaCore PUBLIC @@ -44,7 +41,6 @@ else() gba/gfx.cpp gba/irq.arm.cpp gba/irq.s - gba/media.cpp gba/panic.cpp ) target_link_libraries( @@ -59,8 +55,7 @@ endif() target_link_libraries( NostalgiaCore-Common PUBLIC - OxClaw - OxFS + NostalgiaFoundation ) target_link_libraries( @@ -79,7 +74,6 @@ endif() install( FILES - assetmanager.hpp clipboard.hpp color.hpp config.hpp @@ -89,7 +83,6 @@ install( event.hpp gfx.hpp input.hpp - media.hpp typeconv.hpp typestore.hpp DESTINATION diff --git a/src/nostalgia/core/context.hpp b/src/nostalgia/core/context.hpp index 7fc46dde..da8be4d9 100644 --- a/src/nostalgia/core/context.hpp +++ b/src/nostalgia/core/context.hpp @@ -1,13 +1,15 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once #include +#include #include -#include "assetmanager.hpp" +#include + #include "event.hpp" #include "input.hpp" @@ -19,15 +21,14 @@ namespace nostalgia::core { class BaseClipboardObject { public: - virtual ~BaseClipboardObject() = default; + virtual ~BaseClipboardObject() noexcept = default; [[nodiscard]] virtual ox::String typeId() const noexcept = 0; [[nodiscard]] constexpr auto typeMatch(auto name, auto version) const noexcept { - auto inId = ox::sfmt("{};{}", name, version); - return typeId() == inId; + return typeId() == ox::buildTypeId(name, version); } }; @@ -35,7 +36,7 @@ template class ClipboardObject: public BaseClipboardObject { [[nodiscard]] ox::String typeId() const noexcept final { - return ox::sfmt("{};{}", T::TypeName, T::TypeVersion); + return ox::buildTypeId(T::TypeName, T::TypeVersion); } }; @@ -46,7 +47,7 @@ struct BgCbbData { }; // User Input Output -class Context { +class Context: public foundation::Context { friend constexpr void setApplicationData(Context *ctx, void *applicationData) noexcept; template friend constexpr T *applicationData(Context *ctx) noexcept; @@ -68,7 +69,7 @@ class Context { const struct CompactTileSheet &tilesheetAddr) noexcept; friend ox::Error run(Context *ctx) noexcept; friend void shutdown(Context *ctx) noexcept; - friend ox::Result> init(ox::UniquePtr fs, ox::CRStringView appName) noexcept; + friend ox::Result> init(ox::UPtr fs, ox::CRStringView appName) noexcept; friend ox::String getClipboardText(Context *ctx) noexcept; friend uint64_t ticksMs(Context *ctx) noexcept; friend uint8_t bgStatus(Context *ctx) noexcept; @@ -93,17 +94,13 @@ class Context { friend void hideSprite(Context *ctx, unsigned idx) noexcept; public: - ox::UniquePtr rom; ox::Vector drawers; - ox::StringView appName = "Nostalgia"; #ifndef OX_BARE_METAL - AssetManager assetManager; int uninterruptedRefreshes = 3; - ox::UniquePtr clipboard; + ox::UPtr clipboard; #else bool running = true; - std::size_t preloadSectionOffset = 0; #endif protected: #ifndef OX_BARE_METAL diff --git a/src/nostalgia/core/core.hpp b/src/nostalgia/core/core.hpp index 628d05f9..4d41ecaa 100644 --- a/src/nostalgia/core/core.hpp +++ b/src/nostalgia/core/core.hpp @@ -1,18 +1,17 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once #include -#include "assetmanager.hpp" #include "clipboard.hpp" #include "consts.hpp" #include "event.hpp" #include "gfx.hpp" #include "input.hpp" -#include "media.hpp" +#include "module.hpp" #include "typeconv.hpp" namespace nostalgia::core { diff --git a/src/nostalgia/core/gba/gfx.cpp b/src/nostalgia/core/gba/gfx.cpp index 522e8aeb..767e6ae2 100644 --- a/src/nostalgia/core/gba/gfx.cpp +++ b/src/nostalgia/core/gba/gfx.cpp @@ -1,12 +1,13 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include #include #include -#include +#include +#include #include #include "addresses.hpp" @@ -129,7 +130,7 @@ ox::Error initConsole(Context *ctx) noexcept { setBgStatus(ctx, 0b0001); if (!ctx) { ctx = new (ox_alloca(sizeof(Context))) Context(); - oxRequire(rom, loadRom()); + oxRequire(rom, foundation::loadRom()); ox::FileStore32 fs(rom, 32 * ox::units::MB); auto romFs = new (ox_alloca(sizeof(ox::FileSystem32))) ox::FileSystem32(fs); new (&ctx->rom) ox::UniquePtr(romFs); diff --git a/src/nostalgia/core/gba/media.cpp b/src/nostalgia/core/gba/media.cpp deleted file mode 100644 index 6efaa922..00000000 --- a/src/nostalgia/core/gba/media.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. - */ - -#include -#include - -#include "../media.hpp" - -#include "addresses.hpp" - -namespace nostalgia::core { - -ox::Result loadRom(ox::CRStringView) noexcept { - // put the header in the wrong order to prevent mistaking this code for the - // media section - constexpr auto headerP2 = "HEADER__________"; - constexpr auto headerP1 = "NOSTALGIA_MEDIA_"; - constexpr auto headerP1Len = ox_strlen(headerP2); - constexpr auto headerP2Len = ox_strlen(headerP1); - constexpr auto headerLen = headerP1Len + headerP2Len; - for (auto current = MEM_ROM; current < reinterpret_cast(0x0a000000); current += headerLen) { - if (ox_memcmp(current, headerP1, headerP1Len) == 0 && - ox_memcmp(current + headerP1Len, headerP2, headerP2Len) == 0) { - return current + headerLen; - } - } - return OxError(1); -} - -void unloadRom(char*) noexcept { -} - -ox::Result getPreloadAddr(Context *ctx, ox::CRStringView path) noexcept { - oxRequire(stat, ctx->rom->stat(path)); - oxRequire(buff, static_cast(ctx->rom.get())->directAccess(path)); - PreloadPtr p; - oxReturnError(ox::readMC(buff, stat.size, &p)); - return p.preloadAddr + ctx->preloadSectionOffset; -} - -ox::Result getPreloadAddr(Context *ctx, const ox::FileAddress &file) noexcept { - oxRequire(stat, ctx->rom->stat(file)); - oxRequire(buff, static_cast(ctx->rom.get())->directAccess(file)); - PreloadPtr p; - oxReturnError(ox::readMC(buff, stat.size, &p)); - return p.preloadAddr + ctx->preloadSectionOffset; -} - -} diff --git a/src/nostalgia/core/glfw/core.cpp b/src/nostalgia/core/glfw/core.cpp index 3c528790..4033e8db 100644 --- a/src/nostalgia/core/glfw/core.cpp +++ b/src/nostalgia/core/glfw/core.cpp @@ -1,10 +1,11 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include #include +#include #include #include #include @@ -13,10 +14,8 @@ namespace nostalgia::core { -ox::Result> init(ox::UniquePtr fs, ox::CRStringView appName) noexcept { - auto ctx = ox::make_unique(); - ctx->rom = std::move(fs); - ctx->appName = appName; +ox::Result> init(ox::UPtr fs, ox::CRStringView appName) noexcept { + auto ctx = foundation::init(std::move(fs), appName); const auto id = ox::make(); ctx->setWindowerData(id); using namespace std::chrono; diff --git a/src/nostalgia/core/headless/media.cpp b/src/nostalgia/core/headless/media.cpp deleted file mode 100644 index dcfeaac8..00000000 --- a/src/nostalgia/core/headless/media.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. - */ - -#include - -#include "../media.hpp" - -namespace nostalgia::core { - -ox::Result loadRom(ox::CRStringView) noexcept { - return OxError(1); -} - -void unloadRom(char*) noexcept { -} - -} diff --git a/src/nostalgia/core/media.cpp b/src/nostalgia/core/media.cpp deleted file mode 100644 index ebcbe4c5..00000000 --- a/src/nostalgia/core/media.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. - */ - -#include "media.hpp" - -namespace nostalgia::core { - -ox::Result> loadRomFs(ox::CRStringView path) noexcept { - const auto lastDot = ox_lastIndexOf(path, '.'); - const auto fsExt = lastDot != -1 ? path.substr(static_cast(lastDot)) : ""; - if (ox_strcmp(fsExt, ".oxfs") == 0) { - oxRequire(rom, core::loadRom(path)); - return {ox::make_unique(rom, 32 * ox::units::MB, unloadRom)}; - } else { -#ifdef OX_HAS_PASSTHROUGHFS - return {ox::make_unique(path)}; -#else - return OxError(2); -#endif - } -} - -} diff --git a/src/nostalgia/core/module.cpp b/src/nostalgia/core/module.cpp new file mode 100644 index 00000000..f67ed51b --- /dev/null +++ b/src/nostalgia/core/module.cpp @@ -0,0 +1,23 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include + +#include "typeconv.hpp" + +#include "module.hpp" + +namespace nostalgia::core { + +ox::Vector CoreModule::converters() const noexcept { + return { + &nostalgiaPaletteToPaletteConverter, + &nostalgiaGraphicToTileSheetConverter, + &tileSheetToCompactTileSheetConverter, + }; +} + +CoreModule CoreModule::mod; + +} diff --git a/src/nostalgia/core/module.hpp b/src/nostalgia/core/module.hpp new file mode 100644 index 00000000..1bcc7874 --- /dev/null +++ b/src/nostalgia/core/module.hpp @@ -0,0 +1,25 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include + +#include "typeconv.hpp" + +namespace nostalgia::core { + +class CoreModule: public foundation::Module { + private: + mutable NostalgiaPaletteToPaletteConverter nostalgiaPaletteToPaletteConverter; + mutable NostalgiaGraphicToTileSheetConverter nostalgiaGraphicToTileSheetConverter; + mutable TileSheetToCompactTileSheetConverter tileSheetToCompactTileSheetConverter; + + public: + static CoreModule mod; + [[nodiscard]] + ox::Vector converters() const noexcept override; +}; + +} diff --git a/src/nostalgia/core/studio/module.cpp b/src/nostalgia/core/studio/module.cpp index b38c882e..044cc507 100644 --- a/src/nostalgia/core/studio/module.cpp +++ b/src/nostalgia/core/studio/module.cpp @@ -11,7 +11,7 @@ namespace nostalgia::core { -ox::Vector Module::editors(core::Context *ctx) noexcept { +ox::Vector StudioModule::editors(core::Context *ctx) noexcept { return { { {"ng"}, @@ -32,7 +32,7 @@ ox::Vector Module::editors(core::Context *ctx) noexcept { }; } -ox::Vector> Module::itemMakers(core::Context*) noexcept { +ox::Vector> StudioModule::itemMakers(core::Context*) noexcept { ox::Vector> out; out.emplace_back(ox::make>("Tile Sheet", "TileSheets", "ng")); out.emplace_back(ox::make>("Palette", "Palettes", "npal")); diff --git a/src/nostalgia/core/studio/module.hpp b/src/nostalgia/core/studio/module.hpp index d0eed570..b59c7a4e 100644 --- a/src/nostalgia/core/studio/module.hpp +++ b/src/nostalgia/core/studio/module.hpp @@ -8,7 +8,7 @@ namespace nostalgia::core { -class Module: public studio::Module { +class StudioModule: public studio::Module { public: ox::Vector editors(core::Context *ctx) noexcept override; ox::Vector> itemMakers(core::Context*) noexcept override; diff --git a/src/nostalgia/core/studio/paletteeditor-imgui.cpp b/src/nostalgia/core/studio/paletteeditor-imgui.cpp index 8cdad656..f19026d4 100644 --- a/src/nostalgia/core/studio/paletteeditor-imgui.cpp +++ b/src/nostalgia/core/studio/paletteeditor-imgui.cpp @@ -1,11 +1,11 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include #include -#include +#include #include #include "paletteeditor.hpp" @@ -19,7 +19,7 @@ ox::Result PaletteEditorImGui::make(Context *ctx, ox::CRStr out->m_itemPath = path; const auto lastSlash = std::find(out->m_itemPath.rbegin(), out->m_itemPath.rend(), '/').offset(); out->m_itemName = out->m_itemPath.substr(lastSlash + 1); - oxRequire(pal, core::readObj(out->m_ctx, ox::FileAddress(out->m_itemPath.c_str()))); + oxRequire(pal, foundation::readObj(out->m_ctx, ox::FileAddress(out->m_itemPath.c_str()))); out->m_pal = *pal; return out.release(); } diff --git a/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp b/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp index 8b684af2..395afd89 100644 --- a/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp +++ b/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp @@ -1,11 +1,11 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include #include -#include +#include #include #include "tilesheeteditor-imgui.hpp" diff --git a/src/nostalgia/core/studio/tilesheeteditormodel.cpp b/src/nostalgia/core/studio/tilesheeteditormodel.cpp index 43fb6221..4a820fe0 100644 --- a/src/nostalgia/core/studio/tilesheeteditormodel.cpp +++ b/src/nostalgia/core/studio/tilesheeteditormodel.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ @@ -9,7 +9,7 @@ #include #include -#include +#include #include "tilesheeteditormodel.hpp" diff --git a/src/nostalgia/core/studio/tilesheeteditormodel.hpp b/src/nostalgia/core/studio/tilesheeteditormodel.hpp index 12246f33..25094bd8 100644 --- a/src/nostalgia/core/studio/tilesheeteditormodel.hpp +++ b/src/nostalgia/core/studio/tilesheeteditormodel.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once @@ -23,7 +23,7 @@ class TileSheetEditorModel: public ox::SignalHandler { static const Palette s_defaultPalette; TileSheet m_img; TileSheet::SubSheetIdx m_activeSubsSheetIdx; - AssetRef m_pal; + foundation::AssetRef m_pal; studio::UndoStack m_undoStack; class DrawCommand *m_ongoingDrawCommand = nullptr; bool m_updated = false; diff --git a/src/nostalgia/core/studio/tilesheeteditorview.cpp b/src/nostalgia/core/studio/tilesheeteditorview.cpp index daee65ef..4b301197 100644 --- a/src/nostalgia/core/studio/tilesheeteditorview.cpp +++ b/src/nostalgia/core/studio/tilesheeteditorview.cpp @@ -1,9 +1,9 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include -#include +#include #include #include "tilesheeteditorview.hpp" diff --git a/src/nostalgia/core/typeconv.cpp b/src/nostalgia/core/typeconv.cpp deleted file mode 100644 index 11e1eb49..00000000 --- a/src/nostalgia/core/typeconv.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. - */ - -#include - -#include "gfx.hpp" - -#include "typeconv.hpp" - -namespace nostalgia::core { - -struct NostalgiaGraphicToTileSheetConverter: public Converter { - ox::Error convert(NostalgiaGraphic *src, TileSheet *dst) noexcept final { - dst->bpp = src->bpp; - dst->subsheet.name = "Root"; - dst->subsheet.rows = src->rows; - dst->subsheet.columns = src->columns; - dst->defaultPalette = std::move(src->defaultPalette); - dst->subsheet.pixels = std::move(src->pixels); - return OxError(0); - } -}; - -struct NostalgiaPaletteToPaletteConverter: public Converter { - ox::Error convert(NostalgiaPalette *src, Palette *dst) noexcept final { - dst->colors = std::move(src->colors); - return OxError(0); - } -}; - -struct TileSheetToCompactTileSheetConverter: public Converter { - ox::Error convert(TileSheet *src, CompactTileSheet *dst) noexcept final { - dst->bpp = src->bpp; - dst->defaultPalette = std::move(src->defaultPalette); - dst->pixels = src->pixels(); - return OxError(0); - } -}; - -#ifndef OX_BARE_METAL - -static const auto converters = [] { - ox::Vector, 3> converters; - converters.emplace_back(ox::make()); - converters.emplace_back(ox::make()); - converters.emplace_back(ox::make()); - return converters; -}(); - -[[nodiscard]] -static auto findConverter(ox::CRStringView srcTypeName, int srcTypeVersion, - ox::CRStringView dstTypeName, int dstTypeVersion) noexcept -> ox::Result { - for (auto &c : converters) { - if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) { - return c.get(); - } - } - return OxError(1, "Could not find converter"); -}; - -static ox::Result> convert(const ox::Buffer &srcBuffer, - ox::CRStringView srcTypeName, int srcTypeVersion, - ox::CRStringView dstTypeName, int dstTypeVersion) noexcept { - // look for direct converter - auto [c, err] = findConverter(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion); - if (!err) { - return c->convertBuffToPtr(srcBuffer); - } - // try to chain multiple converters - for (const auto &subConverter : converters) { - if (!subConverter->dstMatches(dstTypeName, dstTypeVersion)) { - continue; - } - const auto [intermediate, chainErr] = - convert(srcBuffer, srcTypeName, srcTypeVersion, - subConverter->srcTypeName(), subConverter->srcTypeVersion()); - if (!chainErr) { - return subConverter->convertPtrToPtr(intermediate.get()); - } - } - return OxError(1, "Could not convert between types"); -} - -ox::Result> convert(const ox::Buffer &srcBuffer, ox::CRStringView dstTypeName, int dstTypeVersion) noexcept { - oxRequire(hdr, ox::readClawHeader(srcBuffer)); - return convert(srcBuffer, hdr.typeName, hdr.typeVersion, dstTypeName, dstTypeVersion); -} - -#endif - -} diff --git a/src/nostalgia/core/typeconv.hpp b/src/nostalgia/core/typeconv.hpp index f54dd587..c2f001f9 100644 --- a/src/nostalgia/core/typeconv.hpp +++ b/src/nostalgia/core/typeconv.hpp @@ -1,152 +1,51 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once +#include "gfx.hpp" + +#include + #include #include -#include #include #include #include +#include "context.hpp" + namespace nostalgia::core { -class Wrap { - public: - virtual ~Wrap() = default; +// Type converters + +struct NostalgiaPaletteToPaletteConverter: public foundation::Converter { + ox::Error convert(foundation::Context*, NostalgiaPalette *src, Palette *dst) noexcept final { + dst->colors = std::move(src->colors); + return {}; + } }; -template -class WrapInline: public Wrap { - private: - T m_obj; - - public: - constexpr WrapInline() = default; - - template - constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward(args)...) { - } - - [[nodiscard]] - constexpr auto obj() noexcept { - return &m_obj; - } - +struct NostalgiaGraphicToTileSheetConverter: public foundation::Converter { + ox::Error convert(foundation::Context*, NostalgiaGraphic *src, TileSheet *dst) noexcept final { + dst->bpp = src->bpp; + dst->subsheet.name = "Root"; + dst->subsheet.rows = src->rows; + dst->subsheet.columns = src->columns; + dst->defaultPalette = std::move(src->defaultPalette); + dst->subsheet.pixels = std::move(src->pixels); + return {}; + } }; -template -constexpr auto makeWrap(Args &&...args) noexcept { - return ox::make_unique>(ox::forward(args)...); -} - -template -constexpr auto wrapCast(auto ptr) noexcept { - return static_cast*>(ptr)->obj(); -} - -struct BaseConverter { - virtual ~BaseConverter() noexcept = default; - - [[nodiscard]] - virtual ox::StringView srcTypeName() noexcept = 0; - - [[nodiscard]] - virtual int srcTypeVersion() noexcept = 0; - - [[nodiscard]] - virtual bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept = 0; - - [[nodiscard]] - virtual bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept = 0; - - virtual ox::Result> convertPtrToPtr(Wrap *src) noexcept = 0; - - virtual ox::Result> convertBuffToPtr(const ox::Buffer &srcBuff) noexcept = 0; - - [[nodiscard]] - inline bool matches(ox::CRStringView srcTypeName, int srcTypeVersion, - ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept { - return srcMatches(srcTypeName, srcTypeVersion) - && dstMatches(dstTypeName, dstTypeVersion); +struct TileSheetToCompactTileSheetConverter: public foundation::Converter { + ox::Error convert(foundation::Context*, TileSheet *src, CompactTileSheet *dst) noexcept final { + dst->bpp = src->bpp; + dst->defaultPalette = std::move(src->defaultPalette); + dst->pixels = src->pixels(); + return {}; } - }; -template -struct Converter: public BaseConverter { - - virtual ox::Error convert(SrcType*, DstType*) noexcept = 0; - - [[nodiscard]] - ox::StringView srcTypeName() noexcept final { - return ox::requireModelTypeName(); - } - - [[nodiscard]] - int srcTypeVersion() noexcept final { - return ox::requireModelTypeVersion(); - } - - [[nodiscard]] - bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept final { - static constexpr auto SrcTypeName = ox::requireModelTypeName(); - static constexpr auto SrcTypeVersion = ox::requireModelTypeVersion(); - return ox_strcmp(srcTypeName, SrcTypeName) == 0 - && srcTypeVersion == SrcTypeVersion; - } - - [[nodiscard]] - bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept final { - static constexpr auto DstTypeName = ox::requireModelTypeName(); - static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); - return ox_strcmp(dstTypeName, DstTypeName) == 0 - && dstTypeVersion == DstTypeVersion; - } - - ox::Result> convertPtrToPtr(Wrap *src) noexcept final { - auto dst = makeWrap(); - oxReturnError(convert(wrapCast(src), wrapCast(dst.get()))); - return ox::Result>(std::move(dst)); - } - - ox::Result> convertBuffToPtr(const ox::Buffer &srcBuff) noexcept final { - oxRequireM(src, ox::readClaw(srcBuff)); - auto dst = makeWrap(); - oxReturnError(convert(&src, wrapCast(dst.get()))); - return ox::Result>(std::move(dst)); - } - -}; - -ox::Result> convert(const ox::Buffer &srcBuffer, - ox::CRStringView dstTypeName, int dstTypeVersion) noexcept; - -template -ox::Result convert(const ox::Buffer &srcBuffer) noexcept { - static constexpr auto DstTypeName = ox::requireModelTypeName(); - static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); - oxRequire(out, convert(srcBuffer, DstTypeName, DstTypeVersion)); - return wrapCast(out); -} - -template -ox::Error convert(const ox::Buffer &buff, DstType *outObj) noexcept { - static constexpr auto DstTypeName = ox::requireModelTypeName(); - static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); - oxRequire(outPtr, convert(buff, DstTypeName, DstTypeVersion)); - *outObj = std::move(*wrapCast(outPtr.get())); - return OxError(0); -} - -template -ox::Result convertBuffToBuff(const ox::Buffer &srcBuffer, ox::ClawFormat fmt) noexcept { - static constexpr auto DstTypeName = ox::requireModelTypeName(); - static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); - oxRequire(out, convert(srcBuffer, DstTypeName, DstTypeVersion)); - return ox::writeClaw(wrapCast(out.get()), fmt); -} - } diff --git a/src/nostalgia/core/typestore.cpp b/src/nostalgia/core/typestore.cpp index ee3af451..d61e0f85 100644 --- a/src/nostalgia/core/typestore.cpp +++ b/src/nostalgia/core/typestore.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include "typestore.hpp" diff --git a/src/nostalgia/core/typestore.hpp b/src/nostalgia/core/typestore.hpp index c0a58acc..2ebf0c8e 100644 --- a/src/nostalgia/core/typestore.hpp +++ b/src/nostalgia/core/typestore.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once diff --git a/src/nostalgia/core/userland/gfx.cpp b/src/nostalgia/core/userland/gfx.cpp index ce4b1c63..e33d5a19 100644 --- a/src/nostalgia/core/userland/gfx.cpp +++ b/src/nostalgia/core/userland/gfx.cpp @@ -1,9 +1,9 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include -#include +#include #include "gfx.hpp" diff --git a/src/nostalgia/core/userland/media.cpp b/src/nostalgia/core/userland/media.cpp deleted file mode 100644 index 5c695e51..00000000 --- a/src/nostalgia/core/userland/media.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. - */ - -#include - -#include - -#include "../media.hpp" - -namespace nostalgia::core { - -ox::Result loadRom(ox::CRStringView path) noexcept { - std::ifstream file(std::string(toStdStringView(path)), std::ios::binary | std::ios::ate); - if (!file.good()) { - oxErrorf("Could not find ROM file: {}", path); - return OxError(1, "Could not find ROM file"); - } - try { - const auto size = file.tellg(); - file.seekg(0, std::ios::beg); - auto buff = new char[static_cast(size)]; - file.read(buff, size); - return buff; - } catch (const std::ios_base::failure &e) { - oxErrorf("Could not read ROM file: {}", e.what()); - return OxError(2, "Could not read ROM file"); - } -} - -void unloadRom(char *rom) noexcept { - ox::safeDelete(rom); -} - -ox::Result findPreloadSection() noexcept { - return OxError(1, "findPreloadSection is unsupported on this platform"); -} - -} diff --git a/src/nostalgia/foundation/CMakeLists.txt b/src/nostalgia/foundation/CMakeLists.txt new file mode 100644 index 00000000..32e564f7 --- /dev/null +++ b/src/nostalgia/foundation/CMakeLists.txt @@ -0,0 +1,26 @@ + +add_library( + NostalgiaFoundation + foundation.hpp + media.cpp + module.cpp + typeconv.cpp +) + +target_link_libraries( + NostalgiaFoundation PUBLIC + OxClaw + OxEvent + OxFS + OxModel + OxStd +) +install( + FILES + media.hpp + module.hpp + typeconv.hpp + DESTINATION + include/nostalgia/core +) + diff --git a/src/nostalgia/core/assetmanager.hpp b/src/nostalgia/foundation/assetmanager.hpp similarity index 98% rename from src/nostalgia/core/assetmanager.hpp rename to src/nostalgia/foundation/assetmanager.hpp index 0a687aca..b32e41a7 100644 --- a/src/nostalgia/core/assetmanager.hpp +++ b/src/nostalgia/foundation/assetmanager.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once @@ -10,7 +10,7 @@ #include #include -namespace nostalgia::core { +namespace nostalgia::foundation { class AssetManager; @@ -295,4 +295,4 @@ class AssetRef { }; #endif -} \ No newline at end of file +} diff --git a/src/nostalgia/foundation/context.hpp b/src/nostalgia/foundation/context.hpp new file mode 100644 index 00000000..017b446a --- /dev/null +++ b/src/nostalgia/foundation/context.hpp @@ -0,0 +1,34 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include +#include + +#include "assetmanager.hpp" + +namespace nostalgia::foundation { + +class Context { + public: + ox::UPtr rom; + ox::StringView appName = "Nostalgia Foundation App"; +#ifndef OX_BARE_METAL + AssetManager assetManager; + ox::Vector converters; +#else + std::size_t preloadSectionOffset = 0; +#endif + + constexpr Context() noexcept = default; + Context(const Context&) noexcept = delete; + Context(Context&&) noexcept = delete; + Context &operator=(const Context&) noexcept = delete; + Context &operator=(Context&&) noexcept = delete; + constexpr virtual ~Context() noexcept = default; +}; + +} diff --git a/src/nostalgia/foundation/foundation.hpp b/src/nostalgia/foundation/foundation.hpp new file mode 100644 index 00000000..a1838f86 --- /dev/null +++ b/src/nostalgia/foundation/foundation.hpp @@ -0,0 +1,31 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include + +#include "context.hpp" +#include "module.hpp" + +namespace nostalgia::foundation { + +template +ox::UPtr init(ox::UPtr &&fs, ox::CRStringView appName) noexcept { + auto ctx = ox::make_unique(); + ctx->rom = std::move(fs); + ctx->appName = appName; + auto mods = modules(); + if (mods) { + for (auto &mod : *mods) { + // load type converters + for (auto c : mod->converters()) { + ctx->converters.emplace_back(c); + } + } + } + return ctx; +} + +} diff --git a/src/nostalgia/foundation/media.cpp b/src/nostalgia/foundation/media.cpp new file mode 100644 index 00000000..f07b8370 --- /dev/null +++ b/src/nostalgia/foundation/media.cpp @@ -0,0 +1,110 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include "media.hpp" + +#ifndef OX_BARE_METAL + +#include + +#include + +#include + +namespace nostalgia::foundation { + +ox::Result loadRom(ox::CRStringView path) noexcept { + std::ifstream file(std::string(toStdStringView(path)), std::ios::binary | std::ios::ate); + if (!file.good()) { + oxErrorf("Could not find ROM file: {}", path); + return OxError(1, "Could not find ROM file"); + } + try { + const auto size = file.tellg(); + file.seekg(0, std::ios::beg); + auto buff = new char[static_cast(size)]; + file.read(buff, size); + return buff; + } catch (const std::ios_base::failure &e) { + oxErrorf("Could not read ROM file: {}", e.what()); + return OxError(2, "Could not read ROM file"); + } +} + +void unloadRom(char *rom) noexcept { + ox::safeDelete(rom); +} + +ox::Result findPreloadSection() noexcept { + return OxError(1, "findPreloadSection is unsupported on this platform"); +} + +} + +#else + +#include "context.hpp" + +#define MEM_ROM reinterpret_cast(0x0800'0000) + +namespace nostalgia::foundation { + +ox::Result loadRom(ox::CRStringView) noexcept { + // put the header in the wrong order to prevent mistaking this code for the + // media section + constexpr auto headerP2 = "HEADER__________"; + constexpr auto headerP1 = "NOSTALGIA_MEDIA_"; + constexpr auto headerP1Len = ox_strlen(headerP2); + constexpr auto headerP2Len = ox_strlen(headerP1); + constexpr auto headerLen = headerP1Len + headerP2Len; + for (auto current = MEM_ROM; current < reinterpret_cast(0x0a000000); current += headerLen) { + if (ox_memcmp(current, headerP1, headerP1Len) == 0 && + ox_memcmp(current + headerP1Len, headerP2, headerP2Len) == 0) { + return current + headerLen; + } + } + return OxError(1); +} + +void unloadRom(char*) noexcept { +} + +ox::Result getPreloadAddr(foundation::Context *ctx, ox::CRStringView path) noexcept { + oxRequire(stat, ctx->rom->stat(path)); + oxRequire(buff, static_cast(ctx->rom.get())->directAccess(path)); + PreloadPtr p; + oxReturnError(ox::readMC(buff, stat.size, &p)); + return p.preloadAddr + ctx->preloadSectionOffset; +} + +ox::Result getPreloadAddr(foundation::Context *ctx, const ox::FileAddress &file) noexcept { + oxRequire(stat, ctx->rom->stat(file)); + oxRequire(buff, static_cast(ctx->rom.get())->directAccess(file)); + PreloadPtr p; + oxReturnError(ox::readMC(buff, stat.size, &p)); + return p.preloadAddr + ctx->preloadSectionOffset; +} + +} + +#endif + +namespace nostalgia::foundation { + +ox::Result> loadRomFs(ox::CRStringView path) noexcept { + const auto lastDot = ox_lastIndexOf(path, '.'); + const auto fsExt = lastDot != -1 ? path.substr(static_cast(lastDot)) : ""; + if (ox_strcmp(fsExt, ".oxfs") == 0) { + oxRequire(rom, loadRom(path)); + return {ox::make_unique(rom, 32 * ox::units::MB, unloadRom)}; + } else { +#ifdef OX_HAS_PASSTHROUGHFS + return {ox::make_unique(path)}; +#else + return OxError(2); +#endif + } +} + +} diff --git a/src/nostalgia/core/media.hpp b/src/nostalgia/foundation/media.hpp similarity index 63% rename from src/nostalgia/core/media.hpp rename to src/nostalgia/foundation/media.hpp index 1bff8b41..0a723796 100644 --- a/src/nostalgia/core/media.hpp +++ b/src/nostalgia/foundation/media.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once @@ -10,10 +10,11 @@ #include #include -#include "context.hpp" +#include + #include "typeconv.hpp" -namespace nostalgia::core { +namespace nostalgia::foundation { struct PreloadPtr { static constexpr auto TypeName = "net.drinkingtea.ox.PreloadPtr"; @@ -25,20 +26,20 @@ oxModelBegin(PreloadPtr) oxModelField(preloadAddr) oxModelEnd() -ox::Result getPreloadAddr(Context *ctx, const ox::FileAddress &file) noexcept; -ox::Result getPreloadAddr(Context *ctx, ox::CRStringView file) noexcept; +ox::Result getPreloadAddr(foundation::Context *ctx, const ox::FileAddress &file) noexcept; +ox::Result getPreloadAddr(foundation::Context *ctx, ox::CRStringView file) noexcept; template -ox::Result> readObj([[maybe_unused]] Context *ctx, [[maybe_unused]] ox::CRStringView path, - [[maybe_unused]] bool forceLoad = false) noexcept { +ox::Result> readObj([[maybe_unused]] foundation::Context *ctx, [[maybe_unused]] ox::CRStringView path, + [[maybe_unused]] bool forceLoad = false) noexcept { #ifndef OX_BARE_METAL - constexpr auto readConvert = [](const ox::Buffer &buff) -> ox::Result { + const auto readConvert = [ctx](const ox::Buffer &buff) -> ox::Result { auto [obj, err] = ox::readClaw(buff); if (err) { if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) { return err; } - oxReturnError(convert(buff, &obj)); + oxReturnError(convert(ctx, buff, &obj)); } return std::move(obj); }; @@ -59,7 +60,7 @@ ox::Result> readObj([[maybe_unused]] Context *ctx, [[maybe_unused]] #else if constexpr(ox::preloadable::value) { oxRequire(addr, getPreloadAddr(ctx, path)); - return AssetRef(reinterpret_cast(addr)); + return foundation::AssetRef(reinterpret_cast(addr)); } else { return OxError(1); } @@ -67,15 +68,15 @@ ox::Result> readObj([[maybe_unused]] Context *ctx, [[maybe_unused]] } template -ox::Result> readObj(Context *ctx, const ox::FileAddress &file, - [[maybe_unused]] bool forceLoad = false) noexcept { +ox::Result> readObj(foundation::Context *ctx, const ox::FileAddress &file, + [[maybe_unused]] bool forceLoad = false) noexcept { #ifndef OX_BARE_METAL oxRequire(path, file.getPath()); return readObj(ctx, ox::StringView(path), forceLoad); #else if constexpr(ox::preloadable::value) { oxRequire(addr, getPreloadAddr(ctx, file)); - return AssetRef(reinterpret_cast(addr)); + return foundation::AssetRef(reinterpret_cast(addr)); } else { return OxError(1); } @@ -83,7 +84,7 @@ ox::Result> readObj(Context *ctx, const ox::FileAddress &file, } template -ox::Error writeObj(Context *ctx, const ox::FileAddress &file, const T &obj, +ox::Error writeObj(foundation::Context *ctx, const ox::FileAddress &file, const T &obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept { oxRequire(objBuff, ox::writeClaw(&obj, fmt)); return ctx->rom->write(file, objBuff.data(), objBuff.size()); diff --git a/src/nostalgia/foundation/module.cpp b/src/nostalgia/foundation/module.cpp new file mode 100644 index 00000000..6f3efa2a --- /dev/null +++ b/src/nostalgia/foundation/module.cpp @@ -0,0 +1,36 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include "module.hpp" + +namespace nostalgia::foundation { + +[[nodiscard]] +static ox::Vector *moduleRegistry() noexcept { +#ifdef OX_BARE_METAL + return nullptr; +#else + static ox::Vector modules; + return &modules; +#endif +} + +void registerModule(const Module *mod) noexcept { + auto mods = moduleRegistry(); + if (mods) { + mods->emplace_back(mod); + } +} + +[[nodiscard]] +const ox::Vector *modules() noexcept { + return moduleRegistry(); +} + + +ox::Vector Module::converters() const noexcept { + return {}; +} + +} diff --git a/src/nostalgia/foundation/module.hpp b/src/nostalgia/foundation/module.hpp new file mode 100644 index 00000000..34d8b2ac --- /dev/null +++ b/src/nostalgia/foundation/module.hpp @@ -0,0 +1,30 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include + +#include "typeconv.hpp" + +namespace nostalgia::foundation { + +class Module { + public: + constexpr Module() noexcept = default; + Module(const Module&) noexcept = delete; + Module(Module&&) noexcept = delete; + Module &operator=(const Module&) noexcept = delete; + Module &operator=(Module&&) noexcept = delete; + constexpr virtual ~Module() noexcept = default; + [[nodiscard]] + virtual ox::Vector converters() const noexcept; +}; + +void registerModule(const Module *mod) noexcept; + +[[nodiscard]] +const ox::Vector *modules() noexcept; + +} diff --git a/src/nostalgia/foundation/typeconv.cpp b/src/nostalgia/foundation/typeconv.cpp new file mode 100644 index 00000000..8f281abc --- /dev/null +++ b/src/nostalgia/foundation/typeconv.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include + +#include "typeconv.hpp" + +namespace nostalgia::foundation { + +#ifndef OX_BARE_METAL + +[[nodiscard]] +static auto findConverter(foundation::Context *ctx, + ox::CRStringView srcTypeName, int srcTypeVersion, + ox::CRStringView dstTypeName, int dstTypeVersion) noexcept -> ox::Result { + for (auto &c : ctx->converters) { + if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) { + return c; + } + } + return OxError(1, "Could not find converter"); +}; + +static ox::Result> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer, + ox::CRStringView srcTypeName, int srcTypeVersion, + ox::CRStringView dstTypeName, int dstTypeVersion) noexcept { + // look for direct converter + auto [c, err] = findConverter(ctx, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion); + if (!err) { + return c->convertBuffToPtr(nullptr, srcBuffer); + } + // try to chain multiple converters + for (const auto &subConverter : ctx->converters) { + if (!subConverter->dstMatches(dstTypeName, dstTypeVersion)) { + continue; + } + const auto [intermediate, chainErr] = + convert(ctx, srcBuffer, srcTypeName, srcTypeVersion, + subConverter->srcTypeName(), subConverter->srcTypeVersion()); + if (!chainErr) { + return subConverter->convertPtrToPtr(ctx, intermediate.get()); + } + } + return OxError(1, "Could not convert between types"); +} + +ox::Result> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer, ox::CRStringView dstTypeName, int dstTypeVersion) noexcept { + oxRequire(hdr, ox::readClawHeader(srcBuffer)); + return convert(ctx, srcBuffer, hdr.typeName, hdr.typeVersion, dstTypeName, dstTypeVersion); +} + +#endif + +} diff --git a/src/nostalgia/foundation/typeconv.hpp b/src/nostalgia/foundation/typeconv.hpp new file mode 100644 index 00000000..c998e3f0 --- /dev/null +++ b/src/nostalgia/foundation/typeconv.hpp @@ -0,0 +1,155 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "context.hpp" + +namespace nostalgia::foundation { + +class Wrap { + public: + virtual ~Wrap() = default; +}; + +template +class WrapInline: public Wrap { + private: + T m_obj; + + public: + constexpr WrapInline() = default; + + template + constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward(args)...) { + } + + [[nodiscard]] + constexpr auto obj() noexcept { + return &m_obj; + } + +}; + +template +constexpr auto makeWrap(Args &&...args) noexcept { + return ox::make_unique>(ox::forward(args)...); +} + +template +constexpr auto wrapCast(auto ptr) noexcept { + return static_cast*>(ptr)->obj(); +} + +class BaseConverter { + public: + virtual ~BaseConverter() noexcept = default; + + [[nodiscard]] + virtual ox::StringView srcTypeName() noexcept = 0; + + [[nodiscard]] + virtual int srcTypeVersion() noexcept = 0; + + [[nodiscard]] + virtual bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept = 0; + + [[nodiscard]] + virtual bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept = 0; + + virtual ox::Result> convertPtrToPtr(foundation::Context *ctx, Wrap *src) noexcept = 0; + + virtual ox::Result> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) noexcept = 0; + + [[nodiscard]] + inline bool matches(ox::CRStringView srcTypeName, int srcTypeVersion, + ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept { + return srcMatches(srcTypeName, srcTypeVersion) + && dstMatches(dstTypeName, dstTypeVersion); + } + +}; + +template +class Converter: public BaseConverter { + public: + virtual ox::Error convert(foundation::Context *ctx, SrcType*, DstType*) noexcept = 0; + + [[nodiscard]] + ox::StringView srcTypeName() noexcept final { + return ox::requireModelTypeName(); + } + + [[nodiscard]] + int srcTypeVersion() noexcept final { + return ox::requireModelTypeVersion(); + } + + [[nodiscard]] + bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept final { + static constexpr auto SrcTypeName = ox::requireModelTypeName(); + static constexpr auto SrcTypeVersion = ox::requireModelTypeVersion(); + return ox_strcmp(srcTypeName, SrcTypeName) == 0 + && srcTypeVersion == SrcTypeVersion; + } + + [[nodiscard]] + bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept final { + static constexpr auto DstTypeName = ox::requireModelTypeName(); + static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); + return ox_strcmp(dstTypeName, DstTypeName) == 0 + && dstTypeVersion == DstTypeVersion; + } + + ox::Result> convertPtrToPtr(foundation::Context *ctx, Wrap *src) noexcept final { + auto dst = makeWrap(); + oxReturnError(convert(ctx, wrapCast(src), wrapCast(dst.get()))); + return ox::Result>(std::move(dst)); + } + + ox::Result> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) noexcept final { + oxRequireM(src, ox::readClaw(srcBuff)); + auto dst = makeWrap(); + oxReturnError(convert(ctx, &src, wrapCast(dst.get()))); + return ox::Result>(std::move(dst)); + } + +}; + +ox::Result> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer, + ox::CRStringView dstTypeName, int dstTypeVersion) noexcept; + +template +ox::Result convert(foundation::Context *ctx, const ox::Buffer &srcBuffer) noexcept { + static constexpr auto DstTypeName = ox::requireModelTypeName(); + static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); + oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion)); + return wrapCast(out); +} + +template +ox::Error convert(foundation::Context *ctx, const ox::Buffer &buff, DstType *outObj) noexcept { + static constexpr auto DstTypeName = ox::requireModelTypeName(); + static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); + oxRequire(outPtr, convert(ctx, buff, DstTypeName, DstTypeVersion)); + *outObj = std::move(*wrapCast(outPtr.get())); + return OxError(0); +} + +template +ox::Result convertBuffToBuff(foundation::Context *ctx, const ox::Buffer &srcBuffer, ox::ClawFormat fmt) noexcept { + static constexpr auto DstTypeName = ox::requireModelTypeName(); + static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); + oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion)); + return ox::writeClaw(wrapCast(out.get()), fmt); +} + + +} diff --git a/src/nostalgia/player/CMakeLists.txt b/src/nostalgia/player/CMakeLists.txt index c6997d69..ea225292 100644 --- a/src/nostalgia/player/CMakeLists.txt +++ b/src/nostalgia/player/CMakeLists.txt @@ -22,8 +22,7 @@ endif() target_link_libraries( nostalgia - NostalgiaWorld - NostalgiaCore + NostalgiaAppModules OxLogConn ) diff --git a/src/nostalgia/player/app.cpp b/src/nostalgia/player/app.cpp index b1a51c43..c4ee6652 100644 --- a/src/nostalgia/player/app.cpp +++ b/src/nostalgia/player/app.cpp @@ -3,6 +3,7 @@ */ #include +#include using namespace nostalgia; @@ -33,6 +34,7 @@ static int updateHandler(core::Context *ctx) noexcept { } spriteX += xmod; spriteY += ymod; + //constexpr ox::StringView sprites = "nostalgia"; for (unsigned i = 0; i < sprites.len(); ++i) { const auto c = static_cast(sprites[i] - ('a' - 1)); core::setSprite(ctx, i, spriteX + 8 * (static_cast(i) + 1), spriteY, c, 0, 0, 0); diff --git a/src/nostalgia/player/main.cpp b/src/nostalgia/player/main.cpp index 533fa89f..8ab23f0f 100644 --- a/src/nostalgia/player/main.cpp +++ b/src/nostalgia/player/main.cpp @@ -1,15 +1,29 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include #include +#include + +#include #include "app.hpp" static ox::Error run(int argc, const char **argv) noexcept { ox::trace::init(); + nostalgia::loadModules(); + if (argc < 2) { + oxErr("Please provide path to project directory or OxFS file.\n"); + return OxError(1); + } + const auto path = argv[1]; + oxRequireM(fs, nostalgia::foundation::loadRomFs(path)); + return run(std::move(fs)); +} + +int main(int argc, const char **argv) { #ifdef DEBUG ox::LoggerConn loggerConn; const auto loggerErr = loggerConn.initConn("Nostalgia Player"); @@ -19,16 +33,6 @@ static ox::Error run(int argc, const char **argv) noexcept { ox::trace::setLogger(&loggerConn); } #endif - if (argc < 2) { - oxErr("Please provide path to project directory or OxFS file.\n"); - return OxError(1); - } - const auto path = argv[1]; - oxRequireM(fs, nostalgia::core::loadRomFs(path)); - return run(std::move(fs)); -} - -int main(int argc, const char **argv) { const auto err = run(argc, argv); oxAssert(err, "Something went wrong..."); return static_cast(err); diff --git a/src/nostalgia/scene/scene.hpp b/src/nostalgia/scene/scene.hpp index 4dc357dc..1a00fec9 100644 --- a/src/nostalgia/scene/scene.hpp +++ b/src/nostalgia/scene/scene.hpp @@ -1,42 +1,41 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once #include -#include #include #include #include namespace nostalgia::scene { -struct TileDoc { +struct Tile { - constexpr static auto Preloadable = true; constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.Tile"; constexpr static auto TypeVersion = 1; + constexpr static auto Preloadable = true; - uint16_t sheetIdx = 0; + ox::String sheetIdx; uint8_t type = 0; }; -oxModelBegin(TileDoc) - oxModelField(sheetIdx); +oxModelBegin(Tile) + oxModelFieldRename(sheet_idx, sheetIdx); oxModelField(type); oxModelEnd() -struct SceneDoc { +struct Scene { - using TileMapRow = ox::Vector; + using TileMapRow = ox::Vector; using TileMapLayer = ox::Vector; using TileMap = ox::Vector; - constexpr static auto Preloadable = true; constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.Scene"; constexpr static auto TypeVersion = 1; + constexpr static auto Preloadable = true; ox::FileAddress tilesheet; ox::FileAddress palette; @@ -44,7 +43,7 @@ struct SceneDoc { }; -oxModelBegin(SceneDoc) +oxModelBegin(Scene) oxModelField(tilesheet) oxModelField(palette) oxModelField(tiles) @@ -63,8 +62,8 @@ struct SceneInstance { struct Layer { uint16_t &columns; uint16_t &rows; - uint16_t *tileMapIdx; - uint8_t *tileType; + uint16_t *tileMapIdx = nullptr; + uint8_t *tileType = nullptr; constexpr Layer(uint16_t &pColumns, uint16_t &pRows, uint16_t *pTileMapIdx, @@ -90,6 +89,15 @@ struct SceneInstance { constexpr Layer layer(std::size_t i) noexcept { return {columns[i], rows[i], tileMapIdx[i].data(), tileType[i].data()}; } + }; +oxModelBegin(SceneInstance) + oxModelField(layers) + oxModelField(columns) + oxModelField(rows) + oxModelFieldRename(tile_map_idx, tileMapIdx) + oxModelFieldRename(tile_type, tileType) +oxModelEnd() + } diff --git a/src/nostalgia/studio/CMakeLists.txt b/src/nostalgia/studio/CMakeLists.txt index f593f943..5e7cd647 100644 --- a/src/nostalgia/studio/CMakeLists.txt +++ b/src/nostalgia/studio/CMakeLists.txt @@ -16,6 +16,7 @@ target_link_libraries( nostalgia-studio OxClArgs OxLogConn + NostalgiaAppModules NostalgiaStudio NostalgiaCore-Studio ) diff --git a/src/nostalgia/studio/builtinmodules.hpp b/src/nostalgia/studio/builtinmodules.hpp index 60526a6c..533dacaf 100644 --- a/src/nostalgia/studio/builtinmodules.hpp +++ b/src/nostalgia/studio/builtinmodules.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once @@ -13,8 +13,8 @@ namespace nostalgia { [[maybe_unused]] // GCC warns about the existence of this "unused" constexpr list in a header file... constexpr auto BuiltinModules = { [] { - return ox::make_unique(); + return ox::make_unique(); }, }; -} \ No newline at end of file +} diff --git a/src/nostalgia/studio/main.cpp b/src/nostalgia/studio/main.cpp index fe29fc5c..b7dea528 100644 --- a/src/nostalgia/studio/main.cpp +++ b/src/nostalgia/studio/main.cpp @@ -1,12 +1,13 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include - #include +#include #include +#include #include "lib/context.hpp" #include "studioapp.hpp" @@ -55,18 +56,10 @@ static ox::Error run(ox::UniquePtr fs) noexcept { static ox::Error run(int argc, const char **argv) noexcept { ox::trace::init(); -#ifdef DEBUG - ox::LoggerConn loggerConn; - const auto loggerErr = loggerConn.initConn("Nostalgia Studio"); - if (loggerErr) { - oxErrf("Could not connect to logger: {}\n", toStr(loggerErr)); - } else { - ox::trace::setLogger(&loggerConn); - } -#endif + loadModules(); if (argc >= 2) { const auto path = argv[1]; - oxRequireM(fs, core::loadRomFs(path)); + oxRequireM(fs, foundation::loadRomFs(path)); return run(std::move(fs)); } else { return run(ox::UniquePtr(nullptr)); @@ -76,6 +69,15 @@ static ox::Error run(int argc, const char **argv) noexcept { } int main(int argc, const char **argv) { +#ifdef DEBUG + ox::LoggerConn loggerConn; + const auto loggerErr = loggerConn.initConn("Nostalgia Studio"); + if (loggerErr) { + oxErrf("Could not connect to logger: {}\n", toStr(loggerErr)); + } else { + ox::trace::setLogger(&loggerConn); + } +#endif const auto err = nostalgia::run(argc, argv); oxAssert(err, "Something went wrong..."); return static_cast(err); diff --git a/src/nostalgia/studio/studioapp.cpp b/src/nostalgia/studio/studioapp.cpp index 76b1831b..ecf3f43b 100644 --- a/src/nostalgia/studio/studioapp.cpp +++ b/src/nostalgia/studio/studioapp.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "lib/configio.hpp" #include "builtinmodules.hpp" @@ -284,7 +285,7 @@ void StudioUI::save() noexcept { } ox::Error StudioUI::openProject(ox::CRStringView path) noexcept { - oxRequireM(fs, core::loadRomFs(path)); + oxRequireM(fs, foundation::loadRomFs(path)); m_ctx->rom = std::move(fs); core::setWindowTitle(m_ctx, ox::sfmt("Nostalgia Studio - {}", path)); m_project = ox::make_unique(m_ctx->rom.get(), path); diff --git a/src/nostalgia/tools/CMakeLists.txt b/src/nostalgia/tools/CMakeLists.txt index a7bc0a21..0c30cf9d 100644 --- a/src/nostalgia/tools/CMakeLists.txt +++ b/src/nostalgia/tools/CMakeLists.txt @@ -5,6 +5,7 @@ target_link_libraries( OxClArgs OxLogConn NostalgiaPack + NostalgiaAppModules ) if(CMAKE_BUILD_TYPE STREQUAL "Release" AND NOT WIN32) diff --git a/src/nostalgia/tools/pack.cpp b/src/nostalgia/tools/pack.cpp index d3ef5d3f..ef2471fa 100644 --- a/src/nostalgia/tools/pack.cpp +++ b/src/nostalgia/tools/pack.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include @@ -8,6 +8,7 @@ #include #include +#include #include #include "pack/pack.hpp" @@ -43,6 +44,7 @@ static ox::Result readFileBuff(ox::CRStringView path) noexcept { } static ox::Error run(const ox::ClArgs &args) noexcept { + loadModules(); const auto argSrc = args.getString("src", ""); const auto argRomBin = args.getString("rom-bin", ""); if (argSrc == "") { diff --git a/src/nostalgia/tools/pack/CMakeLists.txt b/src/nostalgia/tools/pack/CMakeLists.txt index 7976d50a..3d8e1f0f 100644 --- a/src/nostalgia/tools/pack/CMakeLists.txt +++ b/src/nostalgia/tools/pack/CMakeLists.txt @@ -7,6 +7,7 @@ add_library( target_link_libraries( NostalgiaPack PUBLIC NostalgiaCore-Headless + NostalgiaFoundation OxPreloader ) diff --git a/src/nostalgia/tools/pack/pack.cpp b/src/nostalgia/tools/pack/pack.cpp index 66d01774..a1f880db 100644 --- a/src/nostalgia/tools/pack/pack.cpp +++ b/src/nostalgia/tools/pack/pack.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include @@ -8,9 +8,9 @@ #include #include -#include #include #include +#include #include "pack.hpp" @@ -64,7 +64,7 @@ static ox::Error doTransformations(core::TypeStore *ts, ox::FileSystem *dest, ox oxRequire(s, dest->stat(filePath)); oxRequireM(buff, dest->read(s.inode)); if (endsWith(filePath, ".ng")) { - oxReturnError(core::convertBuffToBuff(buff, ox::ClawFormat::Metal).moveTo(&buff)); + oxReturnError(foundation::convertBuffToBuff(nullptr, buff, ox::ClawFormat::Metal).moveTo(&buff)); } oxRequireM(obj, ox::readClaw(ts, buff)); // do transformations @@ -153,7 +153,7 @@ static ox::Error preloadObj(core::TypeStore *ts, ox::FileSystem *romFs, GbaPrelo const auto err = ox::preload(pl, &obj); oxReturnError(pl->endAlloc()); oxReturnError(err); - const core::PreloadPtr p{.preloadAddr = static_cast(a)}; + const foundation::PreloadPtr p{.preloadAddr = static_cast(a)}; oxReturnError(ox::writeMC(&p).moveTo(&buff)); } else { // strip the Claw header (it is not needed after preloading) and write back out to dest fs diff --git a/src/nostalgia/tools/pack/pack.hpp b/src/nostalgia/tools/pack/pack.hpp index 48b411d1..aa3bc03b 100644 --- a/src/nostalgia/tools/pack/pack.hpp +++ b/src/nostalgia/tools/pack/pack.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include