[nostalgia] Split part of Core out into Foundation, add module system

This commit is contained in:
Gary Talent 2023-02-03 00:41:24 -06:00
parent 83589287bc
commit 7868b0678f
50 changed files with 742 additions and 470 deletions

View File

@ -1,7 +1,9 @@
#project packages #project packages
add_subdirectory(appmodules)
add_subdirectory(core) add_subdirectory(core)
add_subdirectory(foundation)
add_subdirectory(geo) add_subdirectory(geo)
add_subdirectory(scene) add_subdirectory(scene)
add_subdirectory(world) add_subdirectory(world)

View File

@ -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
)

View File

@ -0,0 +1,27 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/std/array.hpp>
#include <nostalgia/foundation/module.hpp>
#include <nostalgia/core/module.hpp>
namespace nostalgia {
void loadModules() noexcept {
static bool done = false;
if (done) {
return;
}
const ox::Array<foundation::Module*, 1> mods = {
&core::CoreModule::mod,
};
for (const auto m : mods) {
foundation::registerModule(m);
}
done = true;
}
}

View File

@ -0,0 +1,11 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
namespace nostalgia {
void loadModules() noexcept;
}

View File

@ -1,8 +1,7 @@
add_library( add_library(
NostalgiaCore-Common OBJECT NostalgiaCore-Common OBJECT
gfx.cpp gfx.cpp
media.cpp module.cpp
typeconv.cpp
typestore.cpp typestore.cpp
) )
@ -10,7 +9,6 @@ add_library(
NostalgiaCore-Headless NostalgiaCore-Headless
headless/core.cpp headless/core.cpp
headless/gfx.cpp headless/gfx.cpp
headless/media.cpp
) )
add_library(NostalgiaCore) add_library(NostalgiaCore)
@ -23,7 +21,6 @@ if(NOT NOSTALGIA_BUILD_TYPE STREQUAL "GBA")
glfw/gfx.cpp glfw/gfx.cpp
userland/gfx.cpp userland/gfx.cpp
userland/gfx_opengl.cpp userland/gfx_opengl.cpp
userland/media.cpp
) )
target_link_libraries( target_link_libraries(
NostalgiaCore PUBLIC NostalgiaCore PUBLIC
@ -44,7 +41,6 @@ else()
gba/gfx.cpp gba/gfx.cpp
gba/irq.arm.cpp gba/irq.arm.cpp
gba/irq.s gba/irq.s
gba/media.cpp
gba/panic.cpp gba/panic.cpp
) )
target_link_libraries( target_link_libraries(
@ -59,8 +55,7 @@ endif()
target_link_libraries( target_link_libraries(
NostalgiaCore-Common PUBLIC NostalgiaCore-Common PUBLIC
OxClaw NostalgiaFoundation
OxFS
) )
target_link_libraries( target_link_libraries(
@ -79,7 +74,6 @@ endif()
install( install(
FILES FILES
assetmanager.hpp
clipboard.hpp clipboard.hpp
color.hpp color.hpp
config.hpp config.hpp
@ -89,7 +83,6 @@ install(
event.hpp event.hpp
gfx.hpp gfx.hpp
input.hpp input.hpp
media.hpp
typeconv.hpp typeconv.hpp
typestore.hpp typestore.hpp
DESTINATION DESTINATION

View File

@ -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 #pragma once
#include <ox/fs/fs.hpp> #include <ox/fs/fs.hpp>
#include <ox/model/desctypes.hpp>
#include <ox/std/buffer.hpp> #include <ox/std/buffer.hpp>
#include "assetmanager.hpp" #include <nostalgia/foundation/context.hpp>
#include "event.hpp" #include "event.hpp"
#include "input.hpp" #include "input.hpp"
@ -19,15 +21,14 @@ namespace nostalgia::core {
class BaseClipboardObject { class BaseClipboardObject {
public: public:
virtual ~BaseClipboardObject() = default; virtual ~BaseClipboardObject() noexcept = default;
[[nodiscard]] [[nodiscard]]
virtual ox::String typeId() const noexcept = 0; virtual ox::String typeId() const noexcept = 0;
[[nodiscard]] [[nodiscard]]
constexpr auto typeMatch(auto name, auto version) const noexcept { constexpr auto typeMatch(auto name, auto version) const noexcept {
auto inId = ox::sfmt("{};{}", name, version); return typeId() == ox::buildTypeId(name, version);
return typeId() == inId;
} }
}; };
@ -35,7 +36,7 @@ template<typename T>
class ClipboardObject: public BaseClipboardObject { class ClipboardObject: public BaseClipboardObject {
[[nodiscard]] [[nodiscard]]
ox::String typeId() const noexcept final { 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 // User Input Output
class Context { class Context: public foundation::Context {
friend constexpr void setApplicationData(Context *ctx, void *applicationData) noexcept; friend constexpr void setApplicationData(Context *ctx, void *applicationData) noexcept;
template<typename T> template<typename T>
friend constexpr T *applicationData(Context *ctx) noexcept; friend constexpr T *applicationData(Context *ctx) noexcept;
@ -68,7 +69,7 @@ class Context {
const struct CompactTileSheet &tilesheetAddr) noexcept; const struct CompactTileSheet &tilesheetAddr) noexcept;
friend ox::Error run(Context *ctx) noexcept; friend ox::Error run(Context *ctx) noexcept;
friend void shutdown(Context *ctx) noexcept; friend void shutdown(Context *ctx) noexcept;
friend ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, ox::CRStringView appName) noexcept; friend ox::Result<ox::UPtr<Context>> init(ox::UPtr<ox::FileSystem> fs, ox::CRStringView appName) noexcept;
friend ox::String getClipboardText(Context *ctx) noexcept; friend ox::String getClipboardText(Context *ctx) noexcept;
friend uint64_t ticksMs(Context *ctx) noexcept; friend uint64_t ticksMs(Context *ctx) noexcept;
friend uint8_t bgStatus(Context *ctx) noexcept; friend uint8_t bgStatus(Context *ctx) noexcept;
@ -93,17 +94,13 @@ class Context {
friend void hideSprite(Context *ctx, unsigned idx) noexcept; friend void hideSprite(Context *ctx, unsigned idx) noexcept;
public: public:
ox::UniquePtr<ox::FileSystem> rom;
ox::Vector<Drawer*, 5> drawers; ox::Vector<Drawer*, 5> drawers;
ox::StringView appName = "Nostalgia";
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL
AssetManager assetManager;
int uninterruptedRefreshes = 3; int uninterruptedRefreshes = 3;
ox::UniquePtr<BaseClipboardObject> clipboard; ox::UPtr<BaseClipboardObject> clipboard;
#else #else
bool running = true; bool running = true;
std::size_t preloadSectionOffset = 0;
#endif #endif
protected: protected:
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL

View File

@ -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 #pragma once
#include <ox/fs/fs.hpp> #include <ox/fs/fs.hpp>
#include "assetmanager.hpp"
#include "clipboard.hpp" #include "clipboard.hpp"
#include "consts.hpp" #include "consts.hpp"
#include "event.hpp" #include "event.hpp"
#include "gfx.hpp" #include "gfx.hpp"
#include "input.hpp" #include "input.hpp"
#include "media.hpp" #include "module.hpp"
#include "typeconv.hpp" #include "typeconv.hpp"
namespace nostalgia::core { namespace nostalgia::core {

View File

@ -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 <ox/fs/fs.hpp> #include <ox/fs/fs.hpp>
#include <ox/mc/mc.hpp> #include <ox/mc/mc.hpp>
#include <ox/std/array.hpp> #include <ox/std/array.hpp>
#include <nostalgia/core/media.hpp> #include <nostalgia/foundation/media.hpp>
#include <nostalgia/core/context.hpp>
#include <nostalgia/core/gfx.hpp> #include <nostalgia/core/gfx.hpp>
#include "addresses.hpp" #include "addresses.hpp"
@ -129,7 +130,7 @@ ox::Error initConsole(Context *ctx) noexcept {
setBgStatus(ctx, 0b0001); setBgStatus(ctx, 0b0001);
if (!ctx) { if (!ctx) {
ctx = new (ox_alloca(sizeof(Context))) Context(); ctx = new (ox_alloca(sizeof(Context))) Context();
oxRequire(rom, loadRom()); oxRequire(rom, foundation::loadRom());
ox::FileStore32 fs(rom, 32 * ox::units::MB); ox::FileStore32 fs(rom, 32 * ox::units::MB);
auto romFs = new (ox_alloca(sizeof(ox::FileSystem32))) ox::FileSystem32(fs); auto romFs = new (ox_alloca(sizeof(ox::FileSystem32))) ox::FileSystem32(fs);
new (&ctx->rom) ox::UniquePtr<ox::FileSystem>(romFs); new (&ctx->rom) ox::UniquePtr<ox::FileSystem>(romFs);

View File

@ -1,50 +0,0 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/mc/read.hpp>
#include <ox/std/std.hpp>
#include "../media.hpp"
#include "addresses.hpp"
namespace nostalgia::core {
ox::Result<char*> 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<char*>(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<std::size_t> getPreloadAddr(Context *ctx, ox::CRStringView path) noexcept {
oxRequire(stat, ctx->rom->stat(path));
oxRequire(buff, static_cast<ox::MemFS*>(ctx->rom.get())->directAccess(path));
PreloadPtr p;
oxReturnError(ox::readMC(buff, stat.size, &p));
return p.preloadAddr + ctx->preloadSectionOffset;
}
ox::Result<std::size_t> getPreloadAddr(Context *ctx, const ox::FileAddress &file) noexcept {
oxRequire(stat, ctx->rom->stat(file));
oxRequire(buff, static_cast<ox::MemFS*>(ctx->rom.get())->directAccess(file));
PreloadPtr p;
oxReturnError(ox::readMC(buff, stat.size, &p));
return p.preloadAddr + ctx->preloadSectionOffset;
}
}

View File

@ -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 <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <nostalgia/foundation/foundation.hpp>
#include <nostalgia/core/gfx.hpp> #include <nostalgia/core/gfx.hpp>
#include <nostalgia/core/input.hpp> #include <nostalgia/core/input.hpp>
#include <nostalgia/core/userland/gfx.hpp> #include <nostalgia/core/userland/gfx.hpp>
@ -13,10 +14,8 @@
namespace nostalgia::core { namespace nostalgia::core {
ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, ox::CRStringView appName) noexcept { ox::Result<ox::UPtr<Context>> init(ox::UPtr<ox::FileSystem> fs, ox::CRStringView appName) noexcept {
auto ctx = ox::make_unique<Context>(); auto ctx = foundation::init<Context>(std::move(fs), appName);
ctx->rom = std::move(fs);
ctx->appName = appName;
const auto id = ox::make<GlfwImplData>(); const auto id = ox::make<GlfwImplData>();
ctx->setWindowerData(id); ctx->setWindowerData(id);
using namespace std::chrono; using namespace std::chrono;

View File

@ -1,18 +0,0 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/std/std.hpp>
#include "../media.hpp"
namespace nostalgia::core {
ox::Result<char*> loadRom(ox::CRStringView) noexcept {
return OxError(1);
}
void unloadRom(char*) noexcept {
}
}

View File

@ -1,24 +0,0 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "media.hpp"
namespace nostalgia::core {
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(ox::CRStringView path) noexcept {
const auto lastDot = ox_lastIndexOf(path, '.');
const auto fsExt = lastDot != -1 ? path.substr(static_cast<std::size_t>(lastDot)) : "";
if (ox_strcmp(fsExt, ".oxfs") == 0) {
oxRequire(rom, core::loadRom(path));
return {ox::make_unique<ox::FileSystem32>(rom, 32 * ox::units::MB, unloadRom)};
} else {
#ifdef OX_HAS_PASSTHROUGHFS
return {ox::make_unique<ox::PassThroughFS>(path)};
#else
return OxError(2);
#endif
}
}
}

View File

@ -0,0 +1,23 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <nostalgia/foundation/module.hpp>
#include "typeconv.hpp"
#include "module.hpp"
namespace nostalgia::core {
ox::Vector<foundation::BaseConverter*> CoreModule::converters() const noexcept {
return {
&nostalgiaPaletteToPaletteConverter,
&nostalgiaGraphicToTileSheetConverter,
&tileSheetToCompactTileSheetConverter,
};
}
CoreModule CoreModule::mod;
}

View File

@ -0,0 +1,25 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <nostalgia/foundation/module.hpp>
#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<foundation::BaseConverter*> converters() const noexcept override;
};
}

View File

@ -11,7 +11,7 @@
namespace nostalgia::core { namespace nostalgia::core {
ox::Vector<studio::EditorMaker> Module::editors(core::Context *ctx) noexcept { ox::Vector<studio::EditorMaker> StudioModule::editors(core::Context *ctx) noexcept {
return { return {
{ {
{"ng"}, {"ng"},
@ -32,7 +32,7 @@ ox::Vector<studio::EditorMaker> Module::editors(core::Context *ctx) noexcept {
}; };
} }
ox::Vector<ox::UniquePtr<studio::ItemMaker>> Module::itemMakers(core::Context*) noexcept { ox::Vector<ox::UniquePtr<studio::ItemMaker>> StudioModule::itemMakers(core::Context*) noexcept {
ox::Vector<ox::UniquePtr<studio::ItemMaker>> out; ox::Vector<ox::UniquePtr<studio::ItemMaker>> out;
out.emplace_back(ox::make<studio::ItemMakerT<core::TileSheet>>("Tile Sheet", "TileSheets", "ng")); out.emplace_back(ox::make<studio::ItemMakerT<core::TileSheet>>("Tile Sheet", "TileSheets", "ng"));
out.emplace_back(ox::make<studio::ItemMakerT<core::Palette>>("Palette", "Palettes", "npal")); out.emplace_back(ox::make<studio::ItemMakerT<core::Palette>>("Palette", "Palettes", "npal"));

View File

@ -8,7 +8,7 @@
namespace nostalgia::core { namespace nostalgia::core {
class Module: public studio::Module { class StudioModule: public studio::Module {
public: public:
ox::Vector<studio::EditorMaker> editors(core::Context *ctx) noexcept override; ox::Vector<studio::EditorMaker> editors(core::Context *ctx) noexcept override;
ox::Vector<ox::UniquePtr<studio::ItemMaker>> itemMakers(core::Context*) noexcept override; ox::Vector<ox::UniquePtr<studio::ItemMaker>> itemMakers(core::Context*) noexcept override;

View File

@ -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 <imgui.h> #include <imgui.h>
#include <nostalgia/core/gfx.hpp> #include <nostalgia/core/gfx.hpp>
#include <nostalgia/core/media.hpp> #include <nostalgia/foundation/media.hpp>
#include <ox/std/memory.hpp> #include <ox/std/memory.hpp>
#include "paletteeditor.hpp" #include "paletteeditor.hpp"
@ -19,7 +19,7 @@ ox::Result<PaletteEditorImGui*> PaletteEditorImGui::make(Context *ctx, ox::CRStr
out->m_itemPath = path; out->m_itemPath = path;
const auto lastSlash = std::find(out->m_itemPath.rbegin(), out->m_itemPath.rend(), '/').offset(); const auto lastSlash = std::find(out->m_itemPath.rbegin(), out->m_itemPath.rend(), '/').offset();
out->m_itemName = out->m_itemPath.substr(lastSlash + 1); out->m_itemName = out->m_itemPath.substr(lastSlash + 1);
oxRequire(pal, core::readObj<Palette>(out->m_ctx, ox::FileAddress(out->m_itemPath.c_str()))); oxRequire(pal, foundation::readObj<Palette>(out->m_ctx, ox::FileAddress(out->m_itemPath.c_str())));
out->m_pal = *pal; out->m_pal = *pal;
return out.release(); return out.release();
} }

View File

@ -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 <imgui.h> #include <imgui.h>
#include <lodepng.h> #include <lodepng.h>
#include <nostalgia/core/media.hpp> #include <nostalgia/foundation/media.hpp>
#include <nostalgia/geo/point.hpp> #include <nostalgia/geo/point.hpp>
#include "tilesheeteditor-imgui.hpp" #include "tilesheeteditor-imgui.hpp"

View File

@ -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 <ox/std/memory.hpp> #include <ox/std/memory.hpp>
#include <nostalgia/core/clipboard.hpp> #include <nostalgia/core/clipboard.hpp>
#include <nostalgia/core/media.hpp> #include <nostalgia/foundation/media.hpp>
#include "tilesheeteditormodel.hpp" #include "tilesheeteditormodel.hpp"

View File

@ -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 #pragma once
@ -23,7 +23,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
static const Palette s_defaultPalette; static const Palette s_defaultPalette;
TileSheet m_img; TileSheet m_img;
TileSheet::SubSheetIdx m_activeSubsSheetIdx; TileSheet::SubSheetIdx m_activeSubsSheetIdx;
AssetRef<Palette> m_pal; foundation::AssetRef<Palette> m_pal;
studio::UndoStack m_undoStack; studio::UndoStack m_undoStack;
class DrawCommand *m_ongoingDrawCommand = nullptr; class DrawCommand *m_ongoingDrawCommand = nullptr;
bool m_updated = false; bool m_updated = false;

View File

@ -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 <nostalgia/core/consts.hpp> #include <nostalgia/core/consts.hpp>
#include <nostalgia/core/media.hpp> #include <nostalgia/foundation/media.hpp>
#include <nostalgia/geo/point.hpp> #include <nostalgia/geo/point.hpp>
#include "tilesheeteditorview.hpp" #include "tilesheeteditorview.hpp"

View File

@ -1,92 +0,0 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/claw/read.hpp>
#include "gfx.hpp"
#include "typeconv.hpp"
namespace nostalgia::core {
struct NostalgiaGraphicToTileSheetConverter: public Converter<NostalgiaGraphic, TileSheet> {
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<NostalgiaPalette, Palette> {
ox::Error convert(NostalgiaPalette *src, Palette *dst) noexcept final {
dst->colors = std::move(src->colors);
return OxError(0);
}
};
struct TileSheetToCompactTileSheetConverter: public Converter<TileSheet, CompactTileSheet> {
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<ox::UniquePtr<BaseConverter>, 3> converters;
converters.emplace_back(ox::make<NostalgiaGraphicToTileSheetConverter>());
converters.emplace_back(ox::make<NostalgiaPaletteToPaletteConverter>());
converters.emplace_back(ox::make<TileSheetToCompactTileSheetConverter>());
return converters;
}();
[[nodiscard]]
static auto findConverter(ox::CRStringView srcTypeName, int srcTypeVersion,
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept -> ox::Result<BaseConverter*> {
for (auto &c : converters) {
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
return c.get();
}
}
return OxError(1, "Could not find converter");
};
static ox::Result<ox::UniquePtr<Wrap>> 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<ox::UniquePtr<Wrap>> 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
}

View File

@ -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 #pragma once
#include "gfx.hpp"
#include <nostalgia/foundation/typeconv.hpp>
#include <ox/std/def.hpp> #include <ox/std/def.hpp>
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
#include <ox/std/optional.hpp>
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <ox/claw/read.hpp> #include <ox/claw/read.hpp>
#include <ox/claw/write.hpp> #include <ox/claw/write.hpp>
#include "context.hpp"
namespace nostalgia::core { namespace nostalgia::core {
class Wrap { // Type converters
public:
virtual ~Wrap() = default; struct NostalgiaPaletteToPaletteConverter: public foundation::Converter<NostalgiaPalette, Palette> {
ox::Error convert(foundation::Context*, NostalgiaPalette *src, Palette *dst) noexcept final {
dst->colors = std::move(src->colors);
return {};
}
}; };
template<typename T> struct NostalgiaGraphicToTileSheetConverter: public foundation::Converter<NostalgiaGraphic, TileSheet> {
class WrapInline: public Wrap { ox::Error convert(foundation::Context*, NostalgiaGraphic *src, TileSheet *dst) noexcept final {
private: dst->bpp = src->bpp;
T m_obj; dst->subsheet.name = "Root";
dst->subsheet.rows = src->rows;
public: dst->subsheet.columns = src->columns;
constexpr WrapInline() = default; dst->defaultPalette = std::move(src->defaultPalette);
dst->subsheet.pixels = std::move(src->pixels);
template<typename... Args> return {};
constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward<Args>(args)...) { }
}
[[nodiscard]]
constexpr auto obj() noexcept {
return &m_obj;
}
}; };
template<typename T, typename... Args> struct TileSheetToCompactTileSheetConverter: public foundation::Converter<TileSheet, CompactTileSheet> {
constexpr auto makeWrap(Args &&...args) noexcept { ox::Error convert(foundation::Context*, TileSheet *src, CompactTileSheet *dst) noexcept final {
return ox::make_unique<WrapInline<T>>(ox::forward<Args>(args)...); dst->bpp = src->bpp;
} dst->defaultPalette = std::move(src->defaultPalette);
dst->pixels = src->pixels();
template<typename T> return {};
constexpr auto wrapCast(auto ptr) noexcept {
return static_cast<WrapInline<T>*>(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<ox::UniquePtr<Wrap>> convertPtrToPtr(Wrap *src) noexcept = 0;
virtual ox::Result<ox::UniquePtr<Wrap>> 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);
} }
}; };
template<typename SrcType, typename DstType>
struct Converter: public BaseConverter {
virtual ox::Error convert(SrcType*, DstType*) noexcept = 0;
[[nodiscard]]
ox::StringView srcTypeName() noexcept final {
return ox::requireModelTypeName<SrcType>();
}
[[nodiscard]]
int srcTypeVersion() noexcept final {
return ox::requireModelTypeVersion<SrcType>();
}
[[nodiscard]]
bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept final {
static constexpr auto SrcTypeName = ox::requireModelTypeName<SrcType>();
static constexpr auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
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<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
return ox_strcmp(dstTypeName, DstTypeName) == 0
&& dstTypeVersion == DstTypeVersion;
}
ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(Wrap *src) noexcept final {
auto dst = makeWrap<DstType>();
oxReturnError(convert(wrapCast<SrcType>(src), wrapCast<DstType>(dst.get())));
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
}
ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(const ox::Buffer &srcBuff) noexcept final {
oxRequireM(src, ox::readClaw<SrcType>(srcBuff));
auto dst = makeWrap<DstType>();
oxReturnError(convert(&src, wrapCast<DstType>(dst.get())));
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
}
};
ox::Result<ox::UniquePtr<Wrap>> convert(const ox::Buffer &srcBuffer,
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept;
template<typename DstType>
ox::Result<DstType> convert(const ox::Buffer &srcBuffer) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(out, convert(srcBuffer, DstTypeName, DstTypeVersion));
return wrapCast<DstType>(out);
}
template<typename DstType>
ox::Error convert(const ox::Buffer &buff, DstType *outObj) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(outPtr, convert(buff, DstTypeName, DstTypeVersion));
*outObj = std::move(*wrapCast<DstType>(outPtr.get()));
return OxError(0);
}
template<typename DstType>
ox::Result<ox::Buffer> convertBuffToBuff(const ox::Buffer &srcBuffer, ox::ClawFormat fmt) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(out, convert(srcBuffer, DstTypeName, DstTypeVersion));
return ox::writeClaw<DstType>(wrapCast<DstType>(out.get()), fmt);
}
} }

View File

@ -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" #include "typestore.hpp"

View File

@ -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 #pragma once

View File

@ -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 <nostalgia/core/gfx.hpp> #include <nostalgia/core/gfx.hpp>
#include <nostalgia/core/media.hpp> #include <nostalgia/foundation/media.hpp>
#include "gfx.hpp" #include "gfx.hpp"

View File

@ -1,39 +0,0 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <fstream>
#include <ox/std/trace.hpp>
#include "../media.hpp"
namespace nostalgia::core {
ox::Result<char*> 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<std::size_t>(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<void*> findPreloadSection() noexcept {
return OxError(1, "findPreloadSection is unsupported on this platform");
}
}

View File

@ -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
)

View File

@ -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 #pragma once
@ -10,7 +10,7 @@
#include <ox/std/hashmap.hpp> #include <ox/std/hashmap.hpp>
#include <ox/std/utility.hpp> #include <ox/std/utility.hpp>
namespace nostalgia::core { namespace nostalgia::foundation {
class AssetManager; class AssetManager;
@ -295,4 +295,4 @@ class AssetRef {
}; };
#endif #endif
} }

View File

@ -0,0 +1,34 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/fs/fs.hpp>
#include <ox/std/memory.hpp>
#include <ox/std/stringview.hpp>
#include "assetmanager.hpp"
namespace nostalgia::foundation {
class Context {
public:
ox::UPtr<ox::FileSystem> rom;
ox::StringView appName = "Nostalgia Foundation App";
#ifndef OX_BARE_METAL
AssetManager assetManager;
ox::Vector<class BaseConverter*> 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;
};
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/memory.hpp>
#include "context.hpp"
#include "module.hpp"
namespace nostalgia::foundation {
template<typename Context = foundation::Context>
ox::UPtr<Context> init(ox::UPtr<ox::FileSystem> &&fs, ox::CRStringView appName) noexcept {
auto ctx = ox::make_unique<Context>();
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;
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "media.hpp"
#ifndef OX_BARE_METAL
#include <fstream>
#include <ox/std/trace.hpp>
#include <nostalgia/foundation/media.hpp>
namespace nostalgia::foundation {
ox::Result<char*> 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<std::size_t>(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<void*> findPreloadSection() noexcept {
return OxError(1, "findPreloadSection is unsupported on this platform");
}
}
#else
#include "context.hpp"
#define MEM_ROM reinterpret_cast<char*>(0x0800'0000)
namespace nostalgia::foundation {
ox::Result<char*> 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<char*>(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<std::size_t> getPreloadAddr(foundation::Context *ctx, ox::CRStringView path) noexcept {
oxRequire(stat, ctx->rom->stat(path));
oxRequire(buff, static_cast<ox::MemFS*>(ctx->rom.get())->directAccess(path));
PreloadPtr p;
oxReturnError(ox::readMC(buff, stat.size, &p));
return p.preloadAddr + ctx->preloadSectionOffset;
}
ox::Result<std::size_t> getPreloadAddr(foundation::Context *ctx, const ox::FileAddress &file) noexcept {
oxRequire(stat, ctx->rom->stat(file));
oxRequire(buff, static_cast<ox::MemFS*>(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<ox::UniquePtr<ox::FileSystem>> loadRomFs(ox::CRStringView path) noexcept {
const auto lastDot = ox_lastIndexOf(path, '.');
const auto fsExt = lastDot != -1 ? path.substr(static_cast<std::size_t>(lastDot)) : "";
if (ox_strcmp(fsExt, ".oxfs") == 0) {
oxRequire(rom, loadRom(path));
return {ox::make_unique<ox::FileSystem32>(rom, 32 * ox::units::MB, unloadRom)};
} else {
#ifdef OX_HAS_PASSTHROUGHFS
return {ox::make_unique<ox::PassThroughFS>(path)};
#else
return OxError(2);
#endif
}
}
}

View File

@ -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 #pragma once
@ -10,10 +10,11 @@
#include <ox/fs/fs.hpp> #include <ox/fs/fs.hpp>
#include <ox/model/metadata.hpp> #include <ox/model/metadata.hpp>
#include "context.hpp" #include <nostalgia/foundation/context.hpp>
#include "typeconv.hpp" #include "typeconv.hpp"
namespace nostalgia::core { namespace nostalgia::foundation {
struct PreloadPtr { struct PreloadPtr {
static constexpr auto TypeName = "net.drinkingtea.ox.PreloadPtr"; static constexpr auto TypeName = "net.drinkingtea.ox.PreloadPtr";
@ -25,20 +26,20 @@ oxModelBegin(PreloadPtr)
oxModelField(preloadAddr) oxModelField(preloadAddr)
oxModelEnd() oxModelEnd()
ox::Result<std::size_t> getPreloadAddr(Context *ctx, const ox::FileAddress &file) noexcept; ox::Result<std::size_t> getPreloadAddr(foundation::Context *ctx, const ox::FileAddress &file) noexcept;
ox::Result<std::size_t> getPreloadAddr(Context *ctx, ox::CRStringView file) noexcept; ox::Result<std::size_t> getPreloadAddr(foundation::Context *ctx, ox::CRStringView file) noexcept;
template<typename T> template<typename T>
ox::Result<AssetRef<T>> readObj([[maybe_unused]] Context *ctx, [[maybe_unused]] ox::CRStringView path, ox::Result<foundation::AssetRef<T>> readObj([[maybe_unused]] foundation::Context *ctx, [[maybe_unused]] ox::CRStringView path,
[[maybe_unused]] bool forceLoad = false) noexcept { [[maybe_unused]] bool forceLoad = false) noexcept {
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL
constexpr auto readConvert = [](const ox::Buffer &buff) -> ox::Result<T> { const auto readConvert = [ctx](const ox::Buffer &buff) -> ox::Result<T> {
auto [obj, err] = ox::readClaw<T>(buff); auto [obj, err] = ox::readClaw<T>(buff);
if (err) { if (err) {
if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) { if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
return err; return err;
} }
oxReturnError(convert<T>(buff, &obj)); oxReturnError(convert<T>(ctx, buff, &obj));
} }
return std::move(obj); return std::move(obj);
}; };
@ -59,7 +60,7 @@ ox::Result<AssetRef<T>> readObj([[maybe_unused]] Context *ctx, [[maybe_unused]]
#else #else
if constexpr(ox::preloadable<T>::value) { if constexpr(ox::preloadable<T>::value) {
oxRequire(addr, getPreloadAddr(ctx, path)); oxRequire(addr, getPreloadAddr(ctx, path));
return AssetRef<T>(reinterpret_cast<const T*>(addr)); return foundation::AssetRef<T>(reinterpret_cast<const T*>(addr));
} else { } else {
return OxError(1); return OxError(1);
} }
@ -67,15 +68,15 @@ ox::Result<AssetRef<T>> readObj([[maybe_unused]] Context *ctx, [[maybe_unused]]
} }
template<typename T> template<typename T>
ox::Result<AssetRef<T>> readObj(Context *ctx, const ox::FileAddress &file, ox::Result<foundation::AssetRef<T>> readObj(foundation::Context *ctx, const ox::FileAddress &file,
[[maybe_unused]] bool forceLoad = false) noexcept { [[maybe_unused]] bool forceLoad = false) noexcept {
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL
oxRequire(path, file.getPath()); oxRequire(path, file.getPath());
return readObj<T>(ctx, ox::StringView(path), forceLoad); return readObj<T>(ctx, ox::StringView(path), forceLoad);
#else #else
if constexpr(ox::preloadable<T>::value) { if constexpr(ox::preloadable<T>::value) {
oxRequire(addr, getPreloadAddr(ctx, file)); oxRequire(addr, getPreloadAddr(ctx, file));
return AssetRef<T>(reinterpret_cast<const T*>(addr)); return foundation::AssetRef<T>(reinterpret_cast<const T*>(addr));
} else { } else {
return OxError(1); return OxError(1);
} }
@ -83,7 +84,7 @@ ox::Result<AssetRef<T>> readObj(Context *ctx, const ox::FileAddress &file,
} }
template<typename T> template<typename T>
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 { ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept {
oxRequire(objBuff, ox::writeClaw(&obj, fmt)); oxRequire(objBuff, ox::writeClaw(&obj, fmt));
return ctx->rom->write(file, objBuff.data(), objBuff.size()); return ctx->rom->write(file, objBuff.data(), objBuff.size());

View File

@ -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<const Module*> *moduleRegistry() noexcept {
#ifdef OX_BARE_METAL
return nullptr;
#else
static ox::Vector<const Module*> modules;
return &modules;
#endif
}
void registerModule(const Module *mod) noexcept {
auto mods = moduleRegistry();
if (mods) {
mods->emplace_back(mod);
}
}
[[nodiscard]]
const ox::Vector<const Module*> *modules() noexcept {
return moduleRegistry();
}
ox::Vector<foundation::BaseConverter*> Module::converters() const noexcept {
return {};
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/vector.hpp>
#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<foundation::BaseConverter*> converters() const noexcept;
};
void registerModule(const Module *mod) noexcept;
[[nodiscard]]
const ox::Vector<const foundation::Module*> *modules() noexcept;
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/claw/read.hpp>
#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<BaseConverter*> {
for (auto &c : ctx->converters) {
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
return c;
}
}
return OxError(1, "Could not find converter");
};
static ox::Result<ox::UniquePtr<Wrap>> 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<ox::UniquePtr<Wrap>> 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
}

View File

@ -0,0 +1,155 @@
/*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/def.hpp>
#include <ox/std/error.hpp>
#include <ox/std/string.hpp>
#include <ox/claw/read.hpp>
#include <ox/claw/write.hpp>
#include "context.hpp"
namespace nostalgia::foundation {
class Wrap {
public:
virtual ~Wrap() = default;
};
template<typename T>
class WrapInline: public Wrap {
private:
T m_obj;
public:
constexpr WrapInline() = default;
template<typename... Args>
constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward<Args>(args)...) {
}
[[nodiscard]]
constexpr auto obj() noexcept {
return &m_obj;
}
};
template<typename T, typename... Args>
constexpr auto makeWrap(Args &&...args) noexcept {
return ox::make_unique<WrapInline<T>>(ox::forward<Args>(args)...);
}
template<typename T>
constexpr auto wrapCast(auto ptr) noexcept {
return static_cast<WrapInline<T>*>(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<ox::UniquePtr<Wrap>> convertPtrToPtr(foundation::Context *ctx, Wrap *src) noexcept = 0;
virtual ox::Result<ox::UniquePtr<Wrap>> 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<typename SrcType, typename DstType>
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<SrcType>();
}
[[nodiscard]]
int srcTypeVersion() noexcept final {
return ox::requireModelTypeVersion<SrcType>();
}
[[nodiscard]]
bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept final {
static constexpr auto SrcTypeName = ox::requireModelTypeName<SrcType>();
static constexpr auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
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<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
return ox_strcmp(dstTypeName, DstTypeName) == 0
&& dstTypeVersion == DstTypeVersion;
}
ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(foundation::Context *ctx, Wrap *src) noexcept final {
auto dst = makeWrap<DstType>();
oxReturnError(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(dst.get())));
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
}
ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) noexcept final {
oxRequireM(src, ox::readClaw<SrcType>(srcBuff));
auto dst = makeWrap<DstType>();
oxReturnError(convert(ctx, &src, wrapCast<DstType>(dst.get())));
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
}
};
ox::Result<ox::UniquePtr<Wrap>> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer,
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept;
template<typename DstType>
ox::Result<DstType> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
return wrapCast<DstType>(out);
}
template<typename DstType>
ox::Error convert(foundation::Context *ctx, const ox::Buffer &buff, DstType *outObj) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(outPtr, convert(ctx, buff, DstTypeName, DstTypeVersion));
*outObj = std::move(*wrapCast<DstType>(outPtr.get()));
return OxError(0);
}
template<typename DstType>
ox::Result<ox::Buffer> convertBuffToBuff(foundation::Context *ctx, const ox::Buffer &srcBuffer, ox::ClawFormat fmt) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
return ox::writeClaw<DstType>(wrapCast<DstType>(out.get()), fmt);
}
}

View File

@ -22,8 +22,7 @@ endif()
target_link_libraries( target_link_libraries(
nostalgia nostalgia
NostalgiaWorld NostalgiaAppModules
NostalgiaCore
OxLogConn OxLogConn
) )

View File

@ -3,6 +3,7 @@
*/ */
#include <nostalgia/core/core.hpp> #include <nostalgia/core/core.hpp>
#include <nostalgia/foundation/media.hpp>
using namespace nostalgia; using namespace nostalgia;
@ -33,6 +34,7 @@ static int updateHandler(core::Context *ctx) noexcept {
} }
spriteX += xmod; spriteX += xmod;
spriteY += ymod; spriteY += ymod;
//constexpr ox::StringView sprites = "nostalgia";
for (unsigned i = 0; i < sprites.len(); ++i) { for (unsigned i = 0; i < sprites.len(); ++i) {
const auto c = static_cast<unsigned>(sprites[i] - ('a' - 1)); const auto c = static_cast<unsigned>(sprites[i] - ('a' - 1));
core::setSprite(ctx, i, spriteX + 8 * (static_cast<int>(i) + 1), spriteY, c, 0, 0, 0); core::setSprite(ctx, i, spriteX + 8 * (static_cast<int>(i) + 1), spriteY, c, 0, 0, 0);

View File

@ -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 <ox/logconn/logconn.hpp> #include <ox/logconn/logconn.hpp>
#include <nostalgia/core/core.hpp> #include <nostalgia/core/core.hpp>
#include <nostalgia/foundation/media.hpp>
#include <nostalgia/appmodules/appmodules.hpp>
#include "app.hpp" #include "app.hpp"
static ox::Error run(int argc, const char **argv) noexcept { static ox::Error run(int argc, const char **argv) noexcept {
ox::trace::init(); 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 #ifdef DEBUG
ox::LoggerConn loggerConn; ox::LoggerConn loggerConn;
const auto loggerErr = loggerConn.initConn("Nostalgia Player"); 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); ox::trace::setLogger(&loggerConn);
} }
#endif #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); const auto err = run(argc, argv);
oxAssert(err, "Something went wrong..."); oxAssert(err, "Something went wrong...");
return static_cast<int>(err); return static_cast<int>(err);

View File

@ -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 #pragma once
#include <ox/fs/fs.hpp> #include <ox/fs/fs.hpp>
#include <ox/preloader/preloader.hpp>
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
#include <ox/std/vector.hpp> #include <ox/std/vector.hpp>
namespace nostalgia::scene { namespace nostalgia::scene {
struct TileDoc { struct Tile {
constexpr static auto Preloadable = true;
constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.Tile"; constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.Tile";
constexpr static auto TypeVersion = 1; constexpr static auto TypeVersion = 1;
constexpr static auto Preloadable = true;
uint16_t sheetIdx = 0; ox::String sheetIdx;
uint8_t type = 0; uint8_t type = 0;
}; };
oxModelBegin(TileDoc) oxModelBegin(Tile)
oxModelField(sheetIdx); oxModelFieldRename(sheet_idx, sheetIdx);
oxModelField(type); oxModelField(type);
oxModelEnd() oxModelEnd()
struct SceneDoc { struct Scene {
using TileMapRow = ox::Vector<TileDoc>; using TileMapRow = ox::Vector<Tile>;
using TileMapLayer = ox::Vector<TileMapRow>; using TileMapLayer = ox::Vector<TileMapRow>;
using TileMap = ox::Vector<TileMapLayer>; using TileMap = ox::Vector<TileMapLayer>;
constexpr static auto Preloadable = true;
constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.Scene"; constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.Scene";
constexpr static auto TypeVersion = 1; constexpr static auto TypeVersion = 1;
constexpr static auto Preloadable = true;
ox::FileAddress tilesheet; ox::FileAddress tilesheet;
ox::FileAddress palette; ox::FileAddress palette;
@ -44,7 +43,7 @@ struct SceneDoc {
}; };
oxModelBegin(SceneDoc) oxModelBegin(Scene)
oxModelField(tilesheet) oxModelField(tilesheet)
oxModelField(palette) oxModelField(palette)
oxModelField(tiles) oxModelField(tiles)
@ -63,8 +62,8 @@ struct SceneInstance {
struct Layer { struct Layer {
uint16_t &columns; uint16_t &columns;
uint16_t &rows; uint16_t &rows;
uint16_t *tileMapIdx; uint16_t *tileMapIdx = nullptr;
uint8_t *tileType; uint8_t *tileType = nullptr;
constexpr Layer(uint16_t &pColumns, constexpr Layer(uint16_t &pColumns,
uint16_t &pRows, uint16_t &pRows,
uint16_t *pTileMapIdx, uint16_t *pTileMapIdx,
@ -90,6 +89,15 @@ struct SceneInstance {
constexpr Layer layer(std::size_t i) noexcept { constexpr Layer layer(std::size_t i) noexcept {
return {columns[i], rows[i], tileMapIdx[i].data(), tileType[i].data()}; 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()
} }

View File

@ -16,6 +16,7 @@ target_link_libraries(
nostalgia-studio nostalgia-studio
OxClArgs OxClArgs
OxLogConn OxLogConn
NostalgiaAppModules
NostalgiaStudio NostalgiaStudio
NostalgiaCore-Studio NostalgiaCore-Studio
) )

View File

@ -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 #pragma once
@ -13,8 +13,8 @@ namespace nostalgia {
[[maybe_unused]] // GCC warns about the existence of this "unused" constexpr list in a header file... [[maybe_unused]] // GCC warns about the existence of this "unused" constexpr list in a header file...
constexpr auto BuiltinModules = { constexpr auto BuiltinModules = {
[] { [] {
return ox::make_unique<core::Module>(); return ox::make_unique<core::StudioModule>();
}, },
}; };
} }

View File

@ -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 <ox/logconn/logconn.hpp> #include <ox/logconn/logconn.hpp>
#include <ox/std/trace.hpp> #include <ox/std/trace.hpp>
#include <nostalgia/appmodules/appmodules.hpp>
#include <nostalgia/core/core.hpp> #include <nostalgia/core/core.hpp>
#include <nostalgia/foundation/media.hpp>
#include "lib/context.hpp" #include "lib/context.hpp"
#include "studioapp.hpp" #include "studioapp.hpp"
@ -55,18 +56,10 @@ static ox::Error run(ox::UniquePtr<ox::FileSystem> fs) noexcept {
static ox::Error run(int argc, const char **argv) noexcept { static ox::Error run(int argc, const char **argv) noexcept {
ox::trace::init(); ox::trace::init();
#ifdef DEBUG loadModules();
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
if (argc >= 2) { if (argc >= 2) {
const auto path = argv[1]; const auto path = argv[1];
oxRequireM(fs, core::loadRomFs(path)); oxRequireM(fs, foundation::loadRomFs(path));
return run(std::move(fs)); return run(std::move(fs));
} else { } else {
return run(ox::UniquePtr<ox::FileSystem>(nullptr)); return run(ox::UniquePtr<ox::FileSystem>(nullptr));
@ -76,6 +69,15 @@ static ox::Error run(int argc, const char **argv) noexcept {
} }
int main(int argc, const char **argv) { 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); const auto err = nostalgia::run(argc, argv);
oxAssert(err, "Something went wrong..."); oxAssert(err, "Something went wrong...");
return static_cast<int>(err); return static_cast<int>(err);

View File

@ -5,6 +5,7 @@
#include <imgui.h> #include <imgui.h>
#include <nostalgia/core/core.hpp> #include <nostalgia/core/core.hpp>
#include <nostalgia/foundation/media.hpp>
#include "lib/configio.hpp" #include "lib/configio.hpp"
#include "builtinmodules.hpp" #include "builtinmodules.hpp"
@ -284,7 +285,7 @@ void StudioUI::save() noexcept {
} }
ox::Error StudioUI::openProject(ox::CRStringView path) 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); m_ctx->rom = std::move(fs);
core::setWindowTitle(m_ctx, ox::sfmt("Nostalgia Studio - {}", path)); core::setWindowTitle(m_ctx, ox::sfmt("Nostalgia Studio - {}", path));
m_project = ox::make_unique<studio::Project>(m_ctx->rom.get(), path); m_project = ox::make_unique<studio::Project>(m_ctx->rom.get(), path);

View File

@ -5,6 +5,7 @@ target_link_libraries(
OxClArgs OxClArgs
OxLogConn OxLogConn
NostalgiaPack NostalgiaPack
NostalgiaAppModules
) )
if(CMAKE_BUILD_TYPE STREQUAL "Release" AND NOT WIN32) if(CMAKE_BUILD_TYPE STREQUAL "Release" AND NOT WIN32)

View File

@ -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 <fstream> #include <fstream>
@ -8,6 +8,7 @@
#include <ox/fs/fs.hpp> #include <ox/fs/fs.hpp>
#include <ox/logconn/logconn.hpp> #include <ox/logconn/logconn.hpp>
#include <nostalgia/appmodules/appmodules.hpp>
#include <nostalgia/core/typestore.hpp> #include <nostalgia/core/typestore.hpp>
#include "pack/pack.hpp" #include "pack/pack.hpp"
@ -43,6 +44,7 @@ static ox::Result<ox::Buffer> readFileBuff(ox::CRStringView path) noexcept {
} }
static ox::Error run(const ox::ClArgs &args) noexcept { static ox::Error run(const ox::ClArgs &args) noexcept {
loadModules();
const auto argSrc = args.getString("src", ""); const auto argSrc = args.getString("src", "");
const auto argRomBin = args.getString("rom-bin", ""); const auto argRomBin = args.getString("rom-bin", "");
if (argSrc == "") { if (argSrc == "") {

View File

@ -7,6 +7,7 @@ add_library(
target_link_libraries( target_link_libraries(
NostalgiaPack PUBLIC NostalgiaPack PUBLIC
NostalgiaCore-Headless NostalgiaCore-Headless
NostalgiaFoundation
OxPreloader OxPreloader
) )

View File

@ -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 <ox/claw/read.hpp> #include <ox/claw/read.hpp>
@ -8,9 +8,9 @@
#include <ox/model/modelvalue.hpp> #include <ox/model/modelvalue.hpp>
#include <nostalgia/core/gfx.hpp> #include <nostalgia/core/gfx.hpp>
#include <nostalgia/core/media.hpp>
#include <nostalgia/core/typeconv.hpp> #include <nostalgia/core/typeconv.hpp>
#include <nostalgia/core/typestore.hpp> #include <nostalgia/core/typestore.hpp>
#include <nostalgia/foundation/media.hpp>
#include "pack.hpp" #include "pack.hpp"
@ -64,7 +64,7 @@ static ox::Error doTransformations(core::TypeStore *ts, ox::FileSystem *dest, ox
oxRequire(s, dest->stat(filePath)); oxRequire(s, dest->stat(filePath));
oxRequireM(buff, dest->read(s.inode)); oxRequireM(buff, dest->read(s.inode));
if (endsWith(filePath, ".ng")) { if (endsWith(filePath, ".ng")) {
oxReturnError(core::convertBuffToBuff<core::CompactTileSheet>(buff, ox::ClawFormat::Metal).moveTo(&buff)); oxReturnError(foundation::convertBuffToBuff<core::CompactTileSheet>(nullptr, buff, ox::ClawFormat::Metal).moveTo(&buff));
} }
oxRequireM(obj, ox::readClaw(ts, buff)); oxRequireM(obj, ox::readClaw(ts, buff));
// do transformations // do transformations
@ -153,7 +153,7 @@ static ox::Error preloadObj(core::TypeStore *ts, ox::FileSystem *romFs, GbaPrelo
const auto err = ox::preload<GbaPlatSpec, decltype(obj)>(pl, &obj); const auto err = ox::preload<GbaPlatSpec, decltype(obj)>(pl, &obj);
oxReturnError(pl->endAlloc()); oxReturnError(pl->endAlloc());
oxReturnError(err); oxReturnError(err);
const core::PreloadPtr p{.preloadAddr = static_cast<uint32_t>(a)}; const foundation::PreloadPtr p{.preloadAddr = static_cast<uint32_t>(a)};
oxReturnError(ox::writeMC(&p).moveTo(&buff)); oxReturnError(ox::writeMC(&p).moveTo(&buff));
} else { } else {
// strip the Claw header (it is not needed after preloading) and write back out to dest fs // strip the Claw header (it is not needed after preloading) and write back out to dest fs

View File

@ -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 <ox/preloader/preloader.hpp> #include <ox/preloader/preloader.hpp>