[nostalgia/core] Add loading multiple tile sheets
This commit is contained in:
parent
6de0e882e9
commit
8526b3fa51
@ -14,6 +14,8 @@
|
|||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
struct Sprite {
|
struct Sprite {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.Sprite";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
@ -39,6 +41,42 @@ oxModelBegin(Sprite)
|
|||||||
oxModelField(priority)
|
oxModelField(priority)
|
||||||
oxModelEnd()
|
oxModelEnd()
|
||||||
|
|
||||||
|
struct TileSheetSetEntrySection {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheetSetEntrySection";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
int32_t begin = 0;
|
||||||
|
int32_t size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
oxModelBegin(TileSheetSetEntrySection)
|
||||||
|
oxModelField(begin)
|
||||||
|
oxModelField(size)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
|
struct TileSheetSetEntry {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheetSetEntry";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
ox::FileAddress tilesheet;
|
||||||
|
ox::Vector<TileSheetSetEntrySection> sections;
|
||||||
|
};
|
||||||
|
|
||||||
|
oxModelBegin(TileSheetSetEntry)
|
||||||
|
oxModelField(tilesheet)
|
||||||
|
oxModelField(sections)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
|
struct TileSheetSet {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheetSet";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
int bpp = 0;
|
||||||
|
ox::Vector<TileSheetSetEntry> entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
oxModelBegin(TileSheetSet)
|
||||||
|
oxModelField(bpp)
|
||||||
|
oxModelField(entries)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
ox::Error loadBgPalette(
|
ox::Error loadBgPalette(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
ox::FileAddress const&paletteAddr) noexcept;
|
ox::FileAddress const&paletteAddr) noexcept;
|
||||||
@ -47,6 +85,11 @@ ox::Error loadSpritePalette(
|
|||||||
Context &ctx,
|
Context &ctx,
|
||||||
ox::FileAddress const&paletteAddr) noexcept;
|
ox::FileAddress const&paletteAddr) noexcept;
|
||||||
|
|
||||||
|
ox::Error loadBgTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
unsigned cbb,
|
||||||
|
TileSheetSet const&set) noexcept;
|
||||||
|
|
||||||
ox::Error loadBgTileSheet(
|
ox::Error loadBgTileSheet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
unsigned cbb,
|
unsigned cbb,
|
||||||
|
@ -23,6 +23,7 @@ namespace nostalgia::core {
|
|||||||
|
|
||||||
constexpr auto GbaTileColumns = 32;
|
constexpr auto GbaTileColumns = 32;
|
||||||
constexpr auto GbaTileRows = 32;
|
constexpr auto GbaTileRows = 32;
|
||||||
|
constexpr auto SpriteCount = 128;
|
||||||
|
|
||||||
struct GbaPaletteTarget {
|
struct GbaPaletteTarget {
|
||||||
static constexpr auto TypeName = Palette::TypeName;
|
static constexpr auto TypeName = Palette::TypeName;
|
||||||
@ -33,9 +34,13 @@ struct GbaPaletteTarget {
|
|||||||
struct GbaTileMapTarget {
|
struct GbaTileMapTarget {
|
||||||
static constexpr auto TypeName = CompactTileSheet::TypeName;
|
static constexpr auto TypeName = CompactTileSheet::TypeName;
|
||||||
static constexpr auto TypeVersion = CompactTileSheet::TypeVersion;
|
static constexpr auto TypeVersion = CompactTileSheet::TypeVersion;
|
||||||
BgCbbData *cbbData = nullptr;
|
unsigned &bpp;
|
||||||
ox::FileAddress defaultPalette;
|
ox::FileAddress defaultPalette;
|
||||||
volatile uint16_t *tileMap = nullptr;
|
volatile uint16_t *tileMap = nullptr;
|
||||||
|
// the following values are not actually in CompactTileSheet,
|
||||||
|
// and only exist to communicate with the loading process
|
||||||
|
size_t tileWriteIdx = 0;
|
||||||
|
unsigned targetBpp = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> auto *t) noexcept {
|
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> auto *t) noexcept {
|
||||||
@ -56,25 +61,56 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> auto *t)
|
|||||||
|
|
||||||
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t) noexcept {
|
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t) noexcept {
|
||||||
oxReturnError(io->template setTypeInfo<CompactTileSheet>());
|
oxReturnError(io->template setTypeInfo<CompactTileSheet>());
|
||||||
oxReturnError(io->field("bpp", &t->cbbData->bpp));
|
oxReturnError(io->field("bpp", &t->bpp));
|
||||||
oxReturnError(io->field("defaultPalette", &t->defaultPalette));
|
oxReturnError(io->field("defaultPalette", &t->defaultPalette));
|
||||||
uint16_t intermediate = 0;
|
uint16_t intermediate = 0;
|
||||||
const auto handleTileMap = [t, &intermediate](std::size_t i, const uint8_t *tile) {
|
if (t->targetBpp == 0) {
|
||||||
if (i & 1) { // i is odd
|
t->targetBpp = t->bpp;
|
||||||
intermediate |= static_cast<uint16_t>(*tile) << 8;
|
}
|
||||||
t->tileMap[i / 2] = intermediate;
|
if (t->targetBpp != t->bpp && t->bpp == 8) {
|
||||||
} else { // i is even
|
return OxError(1, "Cannot load an 8 BPP tilesheet into a 4 BPP CBB");
|
||||||
intermediate = *tile & 0x00ff;
|
}
|
||||||
}
|
ox::Error out{};
|
||||||
return OxError(0);
|
if (t->targetBpp == t->bpp) {
|
||||||
};
|
const auto handleTileMap = [t, &intermediate](std::size_t i, uint8_t const*tile) {
|
||||||
return io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
if (i & 1) { // i is odd
|
||||||
|
intermediate |= static_cast<uint16_t>(*tile) << 8;
|
||||||
|
t->tileMap[i / 2] = intermediate;
|
||||||
|
++t->tileWriteIdx;
|
||||||
|
} else { // i is even
|
||||||
|
intermediate = *tile & 0x00ff;
|
||||||
|
}
|
||||||
|
return ox::Error{};
|
||||||
|
};
|
||||||
|
out = io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
||||||
|
} else if (t->targetBpp > t->bpp) { // 4 -> 8 bits
|
||||||
|
const auto handleTileMap = [t, &intermediate](std::size_t i, uint8_t const*tile) {
|
||||||
|
if (i & 1) { // i is odd
|
||||||
|
intermediate |= static_cast<uint16_t>(*tile) << 8;
|
||||||
|
// write 4 pixels from intermediate
|
||||||
|
t->tileMap[i - 3] = (intermediate & 0b0000'0000'0000'1111) >> 0;
|
||||||
|
t->tileMap[i - 2] = (intermediate & 0b0000'0000'1111'0000) >> 4;
|
||||||
|
t->tileMap[i - 1] = (intermediate & 0b0000'1111'0000'0000) >> 8;
|
||||||
|
t->tileMap[i - 0] = (intermediate & 0b1111'0000'0000'0000) >> 14;
|
||||||
|
++t->tileWriteIdx;
|
||||||
|
} else { // i is even
|
||||||
|
intermediate = *tile & 0x00ff;
|
||||||
|
}
|
||||||
|
return ox::Error{};
|
||||||
|
};
|
||||||
|
out = io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error initGfx(Context&, InitParams const&) noexcept {
|
ox::Error initGfx(Context&, InitParams const&) noexcept {
|
||||||
for (auto bgCtl = ®_BG0CTL; bgCtl <= ®_BG3CTL; bgCtl += 2) {
|
for (auto bgCtl = ®_BG0CTL; bgCtl <= ®_BG3CTL; bgCtl += 2) {
|
||||||
teagba::bgSetSbb(*bgCtl, 28);
|
teagba::bgSetSbb(*bgCtl, 28);
|
||||||
}
|
}
|
||||||
|
for (uint16_t i = 0; i < SpriteCount; ++i) {
|
||||||
|
auto &sa = teagba::spriteAttr(i);
|
||||||
|
sa.idx = i;
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +136,27 @@ ox::Error loadSpritePalette(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ox::Error loadTileSheetSet(
|
||||||
|
Context &ctx,
|
||||||
|
unsigned &bpp,
|
||||||
|
uint16_t *tileMapTargetMem,
|
||||||
|
TileSheetSet const&set) noexcept {
|
||||||
|
auto &rom = ctx.rom();
|
||||||
|
size_t tileWriteIdx = 0;
|
||||||
|
for (auto const&entry : set.entries) {
|
||||||
|
oxRequire(tsStat, rom.stat(entry.tilesheet));
|
||||||
|
oxRequire(ts, rom.directAccess(entry.tilesheet));
|
||||||
|
GbaTileMapTarget target{
|
||||||
|
.bpp = bpp,
|
||||||
|
.defaultPalette = {},
|
||||||
|
.tileMap = tileMapTargetMem + tileWriteIdx,
|
||||||
|
};
|
||||||
|
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
|
||||||
|
tileWriteIdx += target.tileWriteIdx;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
ox::Error loadBgTileSheet(
|
ox::Error loadBgTileSheet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
unsigned cbb,
|
unsigned cbb,
|
||||||
@ -109,7 +166,7 @@ ox::Error loadBgTileSheet(
|
|||||||
oxRequire(tsStat, rom.stat(tilesheetAddr));
|
oxRequire(tsStat, rom.stat(tilesheetAddr));
|
||||||
oxRequire(ts, rom.directAccess(tilesheetAddr));
|
oxRequire(ts, rom.directAccess(tilesheetAddr));
|
||||||
GbaTileMapTarget target{
|
GbaTileMapTarget target{
|
||||||
.cbbData = &ctx.cbbData[cbb],
|
.bpp = ctx.cbbData[cbb].bpp,
|
||||||
.defaultPalette = {},
|
.defaultPalette = {},
|
||||||
.tileMap = MEM_BG_TILES[cbb].data(),
|
.tileMap = MEM_BG_TILES[cbb].data(),
|
||||||
};
|
};
|
||||||
@ -127,14 +184,40 @@ ox::Error loadBgTileSheet(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ox::Error loadBgTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
unsigned cbb,
|
||||||
|
TileSheetSet const&set) noexcept {
|
||||||
|
auto &bpp = ctx.cbbData[cbb].bpp;
|
||||||
|
oxReturnError(loadTileSheetSet(ctx, bpp, MEM_BG_TILES[cbb].data(), set));
|
||||||
|
// update bpp of all bgs with the updated cbb
|
||||||
|
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
|
||||||
|
if (teagba::bgCbb(bgCtl) == cbb) {
|
||||||
|
teagba::bgSetBpp(bgCtl, bpp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setSpritesBpp(unsigned const bpp) noexcept {
|
||||||
|
auto const eightBpp = static_cast<uint16_t >(bpp == 8);
|
||||||
|
for (auto i = 0u; i < SpriteCount; ++i) {
|
||||||
|
auto &sa = teagba::spriteAttr(i);
|
||||||
|
auto &a = sa.attr0;
|
||||||
|
a |= static_cast<uint16_t>((a & ~static_cast<uint16_t>(1u << 13)) | (eightBpp << 13));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ox::Error loadSpriteTileSheet(
|
ox::Error loadSpriteTileSheet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
ox::FileAddress const&tilesheetAddr,
|
ox::FileAddress const&tilesheetAddr,
|
||||||
bool loadDefaultPalette) noexcept {
|
bool loadDefaultPalette) noexcept {
|
||||||
auto &rom = ctx.rom();
|
auto &rom = ctx.rom();
|
||||||
oxRequire(tsStat, ctx.rom().stat(tilesheetAddr));
|
oxRequire(tsStat, rom.stat(tilesheetAddr));
|
||||||
oxRequire(ts, rom.directAccess(tilesheetAddr));
|
oxRequire(ts, rom.directAccess(tilesheetAddr));
|
||||||
|
unsigned bpp{};
|
||||||
GbaTileMapTarget target{
|
GbaTileMapTarget target{
|
||||||
|
.bpp = bpp,
|
||||||
.defaultPalette = {},
|
.defaultPalette = {},
|
||||||
.tileMap = MEM_SPRITE_TILES,
|
.tileMap = MEM_SPRITE_TILES,
|
||||||
};
|
};
|
||||||
@ -142,6 +225,16 @@ ox::Error loadSpriteTileSheet(
|
|||||||
if (loadDefaultPalette && target.defaultPalette) {
|
if (loadDefaultPalette && target.defaultPalette) {
|
||||||
oxReturnError(loadSpritePalette(ctx, target.defaultPalette));
|
oxReturnError(loadSpritePalette(ctx, target.defaultPalette));
|
||||||
}
|
}
|
||||||
|
setSpritesBpp(bpp);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error loadSpriteTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
TileSheetSet const&set) noexcept {
|
||||||
|
unsigned bpp{};
|
||||||
|
oxReturnError(loadTileSheetSet(ctx, bpp, MEM_SPRITE_TILES, set));
|
||||||
|
setSpritesBpp(bpp);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +313,7 @@ void setSprite(Context&, uint_t idx, Sprite const&s) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint_t spriteCount(Context&) noexcept {
|
uint_t spriteCount(Context&) noexcept {
|
||||||
return 128;
|
return SpriteCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -504,6 +504,23 @@ ox::Error loadSpritePalette(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ox::Result<TileSheetData> buildSetTsd(
|
||||||
|
Context &ctx,
|
||||||
|
TileSheetSet const&set) noexcept {
|
||||||
|
auto &kctx = keelCtx(ctx.turbineCtx);
|
||||||
|
TileSheetData setTsd;
|
||||||
|
setTsd.width = TileWidth;
|
||||||
|
for (auto const&entry : set.entries) {
|
||||||
|
oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, entry.tilesheet));
|
||||||
|
oxRequire(tsd, normalizeTileSheet(*tilesheet));
|
||||||
|
for (auto const p : tsd.pixels) {
|
||||||
|
setTsd.pixels.push_back(p);
|
||||||
|
}
|
||||||
|
setTsd.height += tsd.height;
|
||||||
|
}
|
||||||
|
return setTsd;
|
||||||
|
}
|
||||||
|
|
||||||
ox::Error loadBgTileSheet(
|
ox::Error loadBgTileSheet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
uint_t cbb,
|
uint_t cbb,
|
||||||
@ -520,6 +537,15 @@ ox::Error loadBgTileSheet(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ox::Error loadBgTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
unsigned cbb,
|
||||||
|
TileSheetSet const&set) noexcept {
|
||||||
|
oxRequire(setTsd, buildSetTsd(ctx, set));
|
||||||
|
ctx.cbbs[cbb].tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
ox::Error loadSpriteTileSheet(
|
ox::Error loadSpriteTileSheet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
ox::FileAddress const&tilesheetAddr,
|
ox::FileAddress const&tilesheetAddr,
|
||||||
@ -535,6 +561,14 @@ ox::Error loadSpriteTileSheet(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ox::Error loadSpriteTileSheet(
|
||||||
|
Context &ctx,
|
||||||
|
TileSheetSet const&set) noexcept {
|
||||||
|
oxRequire(setTsd, buildSetTsd(ctx, set));
|
||||||
|
ctx.spriteBlocks.tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void setBgTile(
|
void setBgTile(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
uint_t bgIdx,
|
uint_t bgIdx,
|
||||||
|
Loading…
Reference in New Issue
Block a user