[nostalgia/core] Add loading multiple tile sheets

This commit is contained in:
Gary Talent 2023-12-22 01:03:41 -06:00
parent 6de0e882e9
commit 8526b3fa51
3 changed files with 185 additions and 15 deletions

View File

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

View File

@ -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) {
t->targetBpp = t->bpp;
}
if (t->targetBpp != t->bpp && t->bpp == 8) {
return OxError(1, "Cannot load an 8 BPP tilesheet into a 4 BPP CBB");
}
ox::Error out{};
if (t->targetBpp == t->bpp) {
const auto handleTileMap = [t, &intermediate](std::size_t i, uint8_t const*tile) {
if (i & 1) { // i is odd if (i & 1) { // i is odd
intermediate |= static_cast<uint16_t>(*tile) << 8; intermediate |= static_cast<uint16_t>(*tile) << 8;
t->tileMap[i / 2] = intermediate; t->tileMap[i / 2] = intermediate;
++t->tileWriteIdx;
} else { // i is even } else { // i is even
intermediate = *tile & 0x00ff; intermediate = *tile & 0x00ff;
} }
return OxError(0); return ox::Error{};
}; };
return io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap); 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 = &REG_BG0CTL; bgCtl <= &REG_BG3CTL; bgCtl += 2) { for (auto bgCtl = &REG_BG0CTL; bgCtl <= &REG_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;
} }
} }

View File

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