[nostalgia/core] Expand conversion system to allow raw-to-raw
This commit is contained in:
parent
fba203a1e7
commit
b87c2f0c50
@ -29,8 +29,8 @@ struct GbaPaletteTarget {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct GbaTileMapTarget {
|
struct GbaTileMapTarget {
|
||||||
static constexpr auto TypeName = TileSheet::TypeName;
|
static constexpr auto TypeName = CompactTileSheet::TypeName;
|
||||||
static constexpr auto TypeVersion = TileSheet::TypeVersion;
|
static constexpr auto TypeVersion = CompactTileSheet::TypeVersion;
|
||||||
volatile uint16_t *bgCtl = nullptr;
|
volatile uint16_t *bgCtl = nullptr;
|
||||||
ox::FileAddress defaultPalette;
|
ox::FileAddress defaultPalette;
|
||||||
GbaPaletteTarget pal;
|
GbaPaletteTarget pal;
|
||||||
@ -51,10 +51,7 @@ template<typename T>
|
|||||||
constexpr ox::Error modelRead(T *io, GbaTileMapTarget *t) noexcept {
|
constexpr ox::Error modelRead(T *io, GbaTileMapTarget *t) noexcept {
|
||||||
io->template setTypeInfo<GbaTileMapTarget>();
|
io->template setTypeInfo<GbaTileMapTarget>();
|
||||||
uint8_t bpp;
|
uint8_t bpp;
|
||||||
int dummy;
|
|
||||||
oxReturnError(io->field("bpp", &bpp));
|
oxReturnError(io->field("bpp", &bpp));
|
||||||
oxReturnError(io->field("rows", &dummy));
|
|
||||||
oxReturnError(io->field("columns", &dummy));
|
|
||||||
constexpr auto Bpp8 = 1 << 7;
|
constexpr auto Bpp8 = 1 << 7;
|
||||||
if (t->bgCtl) {
|
if (t->bgCtl) {
|
||||||
*t->bgCtl = (28 << 8) | 1;
|
*t->bgCtl = (28 << 8) | 1;
|
||||||
@ -65,7 +62,6 @@ constexpr ox::Error modelRead(T *io, GbaTileMapTarget *t) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
oxReturnError(io->field("defaultPalette", &t->defaultPalette));
|
oxReturnError(io->field("defaultPalette", &t->defaultPalette));
|
||||||
oxReturnError(io->field("pal", &t->pal));
|
|
||||||
uint16_t intermediate = 0;
|
uint16_t intermediate = 0;
|
||||||
const auto handleTileMap = [t, &intermediate](std::size_t i, uint8_t *tile) {
|
const auto handleTileMap = [t, &intermediate](std::size_t i, uint8_t *tile) {
|
||||||
if (i & 1) { // i is odd
|
if (i & 1) { // i is odd
|
||||||
|
@ -29,13 +29,20 @@ enum class TileSheetSpace {
|
|||||||
Sprite
|
Sprite
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Palette {
|
struct NostalgiaPalette {
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaPalette";
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaPalette";
|
||||||
static constexpr auto TypeVersion = 1;
|
static constexpr auto TypeVersion = 1;
|
||||||
ox::Vector<Color16> colors;
|
ox::Vector<Color16> colors;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TileSheetV1 {
|
struct Palette {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.Palette";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
ox::Vector<Color16> colors;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Predecessor to TileSheet, kept for backward compatibility
|
||||||
|
struct NostalgiaGraphic {
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaGraphic";
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaGraphic";
|
||||||
static constexpr auto TypeVersion = 1;
|
static constexpr auto TypeVersion = 1;
|
||||||
int8_t bpp = 0;
|
int8_t bpp = 0;
|
||||||
@ -45,69 +52,6 @@ struct TileSheetV1 {
|
|||||||
ox::FileAddress defaultPalette;
|
ox::FileAddress defaultPalette;
|
||||||
Palette pal;
|
Palette pal;
|
||||||
ox::Vector<uint8_t> pixels;
|
ox::Vector<uint8_t> pixels;
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr uint8_t getPixel4Bpp(std::size_t idx) const noexcept {
|
|
||||||
oxAssert(bpp == 4, "TileSheetV1::getPixel4Bpp: wrong bpp");
|
|
||||||
if (idx & 1) {
|
|
||||||
return this->pixels[idx / 2] >> 4;
|
|
||||||
} else {
|
|
||||||
return this->pixels[idx / 2] & 0b0000'1111;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr uint8_t getPixel8Bpp(std::size_t idx) const noexcept {
|
|
||||||
oxAssert(bpp == 8, "TileSheetV1::getPixel8Bpp: wrong bpp");
|
|
||||||
return this->pixels[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr auto getPixel(std::size_t idx) const noexcept {
|
|
||||||
if (this->bpp == 4) {
|
|
||||||
return getPixel4Bpp(idx);
|
|
||||||
} else {
|
|
||||||
return getPixel8Bpp(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr auto getPixel4Bpp(const geo::Point &pt) const noexcept {
|
|
||||||
oxAssert(bpp == 4, "TileSheetV1::getPixel4Bpp: wrong bpp");
|
|
||||||
const auto idx = ptToIdx(pt, this->columns);
|
|
||||||
return getPixel4Bpp(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr auto getPixel8Bpp(const geo::Point &pt) const noexcept {
|
|
||||||
oxAssert(bpp == 8, "TileSheetV1::getPixel8Bpp: wrong bpp");
|
|
||||||
const auto idx = ptToIdx(pt, this->columns);
|
|
||||||
return getPixel8Bpp(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr auto getPixel(const geo::Point &pt) const noexcept {
|
|
||||||
const auto idx = ptToIdx(pt, this->columns);
|
|
||||||
return getPixel(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void setPixel(uint64_t idx, uint8_t palIdx) noexcept {
|
|
||||||
auto &pixel = this->pixels[idx / 2];
|
|
||||||
if (bpp == 4) {
|
|
||||||
if (idx & 1) {
|
|
||||||
pixel = (pixel & 0b0000'1111) | (palIdx << 4);
|
|
||||||
} else {
|
|
||||||
pixel = (pixel & 0b1111'0000) | (palIdx);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pixel = palIdx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void setPixel(const geo::Point &pt, uint8_t palIdx) noexcept {
|
|
||||||
const auto idx = ptToIdx(pt, this->columns);
|
|
||||||
setPixel(idx, palIdx);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TileSheet {
|
struct TileSheet {
|
||||||
@ -115,7 +59,7 @@ struct TileSheet {
|
|||||||
|
|
||||||
struct SubSheet {
|
struct SubSheet {
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet.SubSheet";
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet.SubSheet";
|
||||||
static constexpr auto TypeVersion = "net.drinkingtea.nostalgia.core.TileSheet.SubSheet";
|
static constexpr auto TypeVersion = 1;
|
||||||
ox::BString<32> name;
|
ox::BString<32> name;
|
||||||
std::size_t begin = 0;
|
std::size_t begin = 0;
|
||||||
std::size_t size = 0;
|
std::size_t size = 0;
|
||||||
@ -125,11 +69,9 @@ struct TileSheet {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet";
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet";
|
||||||
static constexpr auto TypeVersion = 2;
|
static constexpr auto TypeVersion = 1;
|
||||||
int8_t bpp = 0;
|
int8_t bpp = 0;
|
||||||
// rows and columns are really only used by TileSheetEditor
|
|
||||||
ox::FileAddress defaultPalette;
|
ox::FileAddress defaultPalette;
|
||||||
Palette pal;
|
|
||||||
ox::Vector<uint8_t> pixels;
|
ox::Vector<uint8_t> pixels;
|
||||||
SubSheet subsheet;
|
SubSheet subsheet;
|
||||||
|
|
||||||
@ -243,11 +185,23 @@ struct TileSheet {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CompactTileSheet {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.CompactTileSheet";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
int8_t bpp = 0;
|
||||||
|
ox::FileAddress defaultPalette;
|
||||||
|
ox::Vector<uint8_t> pixels;
|
||||||
|
};
|
||||||
|
|
||||||
|
oxModelBegin(NostalgiaPalette)
|
||||||
|
oxModelField(colors)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
oxModelBegin(Palette)
|
oxModelBegin(Palette)
|
||||||
oxModelField(colors)
|
oxModelField(colors)
|
||||||
oxModelEnd()
|
oxModelEnd()
|
||||||
|
|
||||||
oxModelBegin(TileSheetV1)
|
oxModelBegin(NostalgiaGraphic)
|
||||||
oxModelField(bpp)
|
oxModelField(bpp)
|
||||||
oxModelField(rows)
|
oxModelField(rows)
|
||||||
oxModelField(columns)
|
oxModelField(columns)
|
||||||
@ -256,14 +210,6 @@ oxModelBegin(TileSheetV1)
|
|||||||
oxModelField(pixels)
|
oxModelField(pixels)
|
||||||
oxModelEnd()
|
oxModelEnd()
|
||||||
|
|
||||||
oxModelBegin(TileSheet)
|
|
||||||
oxModelField(bpp)
|
|
||||||
oxModelField(defaultPalette)
|
|
||||||
oxModelField(pal)
|
|
||||||
oxModelField(pixels)
|
|
||||||
oxModelField(subsheet)
|
|
||||||
oxModelEnd()
|
|
||||||
|
|
||||||
oxModelBegin(TileSheet::SubSheet)
|
oxModelBegin(TileSheet::SubSheet)
|
||||||
oxModelField(name);
|
oxModelField(name);
|
||||||
oxModelField(begin);
|
oxModelField(begin);
|
||||||
@ -273,6 +219,19 @@ oxModelBegin(TileSheet::SubSheet)
|
|||||||
oxModelField(subsheets)
|
oxModelField(subsheets)
|
||||||
oxModelEnd()
|
oxModelEnd()
|
||||||
|
|
||||||
|
oxModelBegin(TileSheet)
|
||||||
|
oxModelField(bpp)
|
||||||
|
oxModelField(defaultPalette)
|
||||||
|
oxModelField(pixels)
|
||||||
|
oxModelField(subsheet)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
|
oxModelBegin(CompactTileSheet)
|
||||||
|
oxModelField(bpp)
|
||||||
|
oxModelField(defaultPalette)
|
||||||
|
oxModelField(pixels)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
struct Sprite {
|
struct Sprite {
|
||||||
unsigned idx = 0;
|
unsigned idx = 0;
|
||||||
unsigned x = 0;
|
unsigned x = 0;
|
||||||
|
@ -47,6 +47,12 @@ ox::Result<AssetRef<T>> readObj(Context *ctx, const ox::FileAddress &file, bool
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ox::Error writeObj(Context *ctx, const ox::FileAddress &file, T &obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept {
|
||||||
|
oxRequire(objBuff, ox::writeClaw(&obj, fmt));
|
||||||
|
return ctx->rom-write(file, objBuff);
|
||||||
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(const char *path) noexcept;
|
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(const char *path) noexcept;
|
||||||
|
|
||||||
ox::Result<char*> loadRom(const char *path = "") noexcept;
|
ox::Result<char*> loadRom(const char *path = "") noexcept;
|
||||||
|
@ -4,55 +4,53 @@
|
|||||||
|
|
||||||
#include <ox/std/defines.hpp>
|
#include <ox/std/defines.hpp>
|
||||||
|
|
||||||
#ifndef OX_BARE_METAL
|
|
||||||
#include <ox/claw/read.hpp>
|
#include <ox/claw/read.hpp>
|
||||||
|
|
||||||
#include "typeconv.hpp"
|
#include "typeconv.hpp"
|
||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
struct Converter {
|
struct NostalgiaGraphicToTileSheetConverter: public Converter<NostalgiaGraphic, TileSheet> {
|
||||||
virtual bool matches(const ox::String &srcTypeName, int srcTypeVersion, const ox::String &dstTypeName, int dstTypeVersion) noexcept = 0;
|
ox::Error convert(NostalgiaGraphic *src, TileSheet *dst) noexcept final {
|
||||||
|
dst->bpp = src->bpp;
|
||||||
virtual ~Converter() noexcept = default;
|
dst->subsheet.name = "Root";
|
||||||
|
dst->subsheet.rows = src->rows;
|
||||||
virtual ox::Error convert(const ox::Buffer &pV1Buff, void *pV2) noexcept = 0;
|
dst->subsheet.columns = src->columns;
|
||||||
};
|
dst->subsheet.size = src->pixels.size();
|
||||||
|
dst->defaultPalette = std::move(src->defaultPalette);
|
||||||
struct TileSheetV1ToV2Converter: public Converter {
|
dst->pixels = std::move(src->pixels);
|
||||||
constexpr TileSheetV1ToV2Converter() noexcept = default;
|
|
||||||
|
|
||||||
virtual ~TileSheetV1ToV2Converter() noexcept = default;
|
|
||||||
|
|
||||||
bool matches(const ox::String &srcTypeName, int srcTypeVersion, const ox::String &dstTypeName, int dstTypeVersion) noexcept final {
|
|
||||||
return srcTypeName == TileSheetV1::TypeName
|
|
||||||
&& srcTypeVersion == TileSheetV1::TypeVersion
|
|
||||||
&& dstTypeName == TileSheet::TypeName
|
|
||||||
&& dstTypeVersion == TileSheet::TypeVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
ox::Error convert(const ox::Buffer &pV1Buff, void *pV2) noexcept final {
|
|
||||||
oxRequire(v1, ox::readClaw<TileSheetV1>(pV1Buff));
|
|
||||||
auto v2 = static_cast<TileSheet*>(pV2);
|
|
||||||
v2->bpp = v1.bpp;
|
|
||||||
v2->subsheet.name = "Root";
|
|
||||||
v2->subsheet.rows = v1.rows;
|
|
||||||
v2->subsheet.columns = v1.columns;
|
|
||||||
v2->subsheet.size = v1.pixels.size();
|
|
||||||
v2->defaultPalette = v1.defaultPalette;
|
|
||||||
v2->pal = v1.pal;
|
|
||||||
v2->pixels = std::move(v1.pixels);
|
|
||||||
return OxError(0);
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Src>
|
||||||
|
struct ToCompactTileSheetConverter: public Converter<Src, CompactTileSheet> {
|
||||||
|
ox::Error convert(Src *src, CompactTileSheet *dst) noexcept final {
|
||||||
|
dst->bpp = src->bpp;
|
||||||
|
dst->defaultPalette = std::move(src->defaultPalette);
|
||||||
|
dst->pixels = std::move(src->pixels);
|
||||||
|
return OxError(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef OX_BARE_METAL
|
||||||
static const auto converters = [] {
|
static const auto converters = [] {
|
||||||
ox::Vector<ox::UniquePtr<Converter>, 1> converters;
|
ox::Vector<ox::UniquePtr<BaseConverter>, 4> converters;
|
||||||
converters.emplace_back(new TileSheetV1ToV2Converter());
|
converters.emplace_back(new NostalgiaGraphicToTileSheetConverter());
|
||||||
|
converters.emplace_back(new NostalgiaPaletteToPaletteConverter());
|
||||||
|
converters.emplace_back(new ToCompactTileSheetConverter<NostalgiaGraphic>());
|
||||||
|
converters.emplace_back(new ToCompactTileSheetConverter<TileSheet>());
|
||||||
return converters;
|
return converters;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
static auto findConverter(const ox::String &srcTypeName, int srcTypeVersion, const ox::String &dstTypeName, int dstTypeVersion) noexcept -> ox::Result<Converter*> {
|
static auto findConverter(const ox::String &srcTypeName, int srcTypeVersion, const ox::String &dstTypeName, int dstTypeVersion) noexcept -> ox::Result<BaseConverter*> {
|
||||||
for (auto &c : converters) {
|
for (auto &c : converters) {
|
||||||
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
|
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
|
||||||
return c.get();
|
return c.get();
|
||||||
@ -64,8 +62,8 @@ static auto findConverter(const ox::String &srcTypeName, int srcTypeVersion, con
|
|||||||
ox::Error convert(const ox::Buffer &srcBuffer, const ox::String &dstTypeName, int dstTypeVersion, void *dstObj) noexcept {
|
ox::Error convert(const ox::Buffer &srcBuffer, const ox::String &dstTypeName, int dstTypeVersion, void *dstObj) noexcept {
|
||||||
oxRequire(hdr, ox::readClawHeader(srcBuffer));
|
oxRequire(hdr, ox::readClawHeader(srcBuffer));
|
||||||
oxRequire(c, findConverter(hdr.typeName, hdr.typeVersion, dstTypeName, dstTypeVersion));
|
oxRequire(c, findConverter(hdr.typeName, hdr.typeVersion, dstTypeName, dstTypeVersion));
|
||||||
return c->convert(srcBuffer, dstObj);
|
return c->convertRaw(srcBuffer, dstObj);
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -8,10 +8,58 @@
|
|||||||
#include <ox/std/error.hpp>
|
#include <ox/std/error.hpp>
|
||||||
#include <ox/std/string.hpp>
|
#include <ox/std/string.hpp>
|
||||||
|
|
||||||
|
#include <ox/claw/write.hpp>
|
||||||
|
|
||||||
#include "gfx.hpp"
|
#include "gfx.hpp"
|
||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
struct BaseConverter {
|
||||||
|
virtual ~BaseConverter() noexcept = default;
|
||||||
|
|
||||||
|
virtual bool matches(const ox::String &srcTypeName, int srcTypeVersion, const ox::String &dstTypeName, int dstTypeVersion) noexcept = 0;
|
||||||
|
|
||||||
|
virtual ox::Error convertRaw(const ox::Buffer &pV1Buff, void *pV2) noexcept = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename SrcType, typename DstType>
|
||||||
|
struct Converter: public BaseConverter{
|
||||||
|
bool matches(const ox::String &srcTypeName, int srcTypeVersion, const ox::String &dstTypeName, int dstTypeVersion) noexcept override {
|
||||||
|
return srcTypeName == SrcType::TypeName
|
||||||
|
&& dstTypeName == DstType::TypeName
|
||||||
|
&& srcTypeVersion == SrcType::TypeVersion
|
||||||
|
&& dstTypeVersion == DstType::TypeVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ox::Error convert(SrcType*, DstType*) noexcept {
|
||||||
|
return OxError(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error convertRaw(const ox::Buffer &pV1Buff, void *pV2) noexcept override {
|
||||||
|
oxRequireM(src, ox::readClaw<SrcType>(pV1Buff));
|
||||||
|
auto dst = static_cast<DstType*>(pV2);
|
||||||
|
return convert(&src, dst);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ox::Error convert(const ox::Buffer &srcBuffer, const ox::String &dstTypeName, int dstTypeVersion, void *dstObj) noexcept;
|
ox::Error convert(const ox::Buffer &srcBuffer, const ox::String &dstTypeName, int dstTypeVersion, void *dstObj) noexcept;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ox::Error convert(const ox::Buffer &srcBuffer, T *dstObj) noexcept {
|
||||||
|
return convert((srcBuffer, T::TypeName, T::TypeVersion, &dstObj));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ox::Result<ox::Buffer> convert(const ox::Buffer &srcBuffer, ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept {
|
||||||
|
T dstObj;
|
||||||
|
oxReturnError(convert(srcBuffer, T::TypeName, T::TypeVersion, &dstObj));
|
||||||
|
return ox::writeClaw(&dstObj, fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ox::Error convert(ox::Buffer *buff) noexcept {
|
||||||
|
return convert<T>(*buff).moveTo(buff);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user