From 46d1313797c8e34f04ac45145c456e0bfbb75ed5 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sat, 23 Dec 2023 01:23:31 -0600 Subject: [PATCH] [nostalgia/core] Get TileSheetSet working with 8bpp setting --- .../core/include/nostalgia/core/gfx.hpp | 2 + src/nostalgia/modules/core/src/gba/gfx.cpp | 91 ++++++++++--------- src/nostalgia/player/app.cpp | 10 +- 3 files changed, 57 insertions(+), 46 deletions(-) diff --git a/src/nostalgia/modules/core/include/nostalgia/core/gfx.hpp b/src/nostalgia/modules/core/include/nostalgia/core/gfx.hpp index aae3ef0f..10d64268 100644 --- a/src/nostalgia/modules/core/include/nostalgia/core/gfx.hpp +++ b/src/nostalgia/modules/core/include/nostalgia/core/gfx.hpp @@ -23,6 +23,7 @@ struct Sprite { unsigned spriteShape = 0; unsigned spriteSize = 0; unsigned flipX = 0; + unsigned bpp = 0; /** * Valid priorities: 0-3 */ @@ -38,6 +39,7 @@ oxModelBegin(Sprite) oxModelField(spriteShape) oxModelField(spriteSize) oxModelField(flipX) + oxModelField(bpp) oxModelField(priority) oxModelEnd() diff --git a/src/nostalgia/modules/core/src/gba/gfx.cpp b/src/nostalgia/modules/core/src/gba/gfx.cpp index c614e349..764c6bb1 100644 --- a/src/nostalgia/modules/core/src/gba/gfx.cpp +++ b/src/nostalgia/modules/core/src/gba/gfx.cpp @@ -60,6 +60,25 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith auto *t) } } +[[nodiscard]] +static bool loadPixel(TileSheetSetEntry const&setEntry, size_t §ionIdx, int tileIdx) noexcept { + if (setEntry.sections.size() <= sectionIdx) { + return false; + } + auto §ion = setEntry.sections[sectionIdx]; + if (tileIdx < section.begin) { + return false; + } + if (tileIdx > section.end()) { + if (sectionIdx >= setEntry.sections.size()) { + return false; + } + ++sectionIdx; + return tileIdx > section.begin && tileIdx <= section.end(); + } + return true; +} + constexpr ox::Error model(auto *io, ox::CommonPtrWith auto *t) noexcept { oxReturnError(io->template setTypeInfo()); oxReturnError(io->field("bpp", &t->bpp)); @@ -71,43 +90,27 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith auto *t) return OxError(1, "Cannot load an 8 BPP tilesheet into a 4 BPP CBB"); } ox::Error out{}; - uint16_t intermediate = 0; if (t->setEntry) { // The following code is atrocious, but it works. // It might be possible to clean it up a little, but it probably // cannot be seriously optimized without preloading TileSheets. - // Consider building an array of bitmaps (Array) - // so this can be done with a single bitmap look up. + size_t sectionIdx = 0; if (t->targetBpp == t->bpp) { TileSheetSetEntrySection const*section = &t->setEntry->sections[0]; - size_t sectionIdx = 1; size_t writeIt = 0; + uint16_t intermediate = 0; size_t const fourBpp = t->bpp == 4; const auto handleTileMap = [t, &intermediate, §ion, §ionIdx, &writeIt, fourBpp] - (std::size_t i, uint8_t const *tile) { - if (!section) { - return ox::Error{}; - } + (std::size_t i, uint8_t const*tile) { auto const tileIdx = static_cast((i * (2 * fourBpp)) / PixelsPerTile); - if (tileIdx < section->begin) { + if (!loadPixel(*t->setEntry, sectionIdx, tileIdx)) { return ox::Error{}; } - if (tileIdx > section->end()) { - if (sectionIdx >= t->setEntry->sections.size()) { - section = nullptr; - return ox::Error{}; - } - section = &t->setEntry->sections[sectionIdx]; - ++sectionIdx; - if (tileIdx < section->begin || tileIdx > section->end()) { - return ox::Error{}; - } - } - if (writeIt & 1) { // writeIt is odd + if (writeIt & 1) { // i is odd intermediate |= static_cast(*tile) << 8; t->tileMap[writeIt / 2] = intermediate; ++t->tileWriteIdx; - } else { // writeIt is even + } else { // i is even intermediate = *tile & 0x00ff; } ++writeIt; @@ -115,31 +118,30 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith auto *t) }; out = io->template field("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(*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; + const auto handleTileMap = [t, §ionIdx](std::size_t writeIt, uint8_t const*tile) { + auto constexpr BytesPerTile4Bpp = 32; + auto const tileIdx = static_cast(writeIt / BytesPerTile4Bpp); + if (!loadPixel(*t->setEntry, sectionIdx, tileIdx)) { + return ox::Error{}; } + uint16_t const px1 = *tile & 0xf; + uint16_t const px2 = *tile >> 4; + t->tileMap[t->tileWriteIdx] = static_cast(px1 | (px2 << 8)); + ++t->tileWriteIdx; return ox::Error{}; }; out = io->template field("tileMap", handleTileMap); } } else { - const auto handleTileMap = [t, &intermediate](std::size_t i, const uint8_t *tile) { + uint16_t intermediate = 0; + const auto handleTileMap = [t, &intermediate](std::size_t i, const uint8_t*tile) { if (i & 1) { // i is odd intermediate |= static_cast(*tile) << 8; t->tileMap[i / 2] = intermediate; } else { // i is even intermediate = *tile & 0x00ff; } - return OxError(0); + return ox::Error{}; }; out = io->template field("tileMap", handleTileMap); } @@ -181,7 +183,6 @@ ox::Error loadSpritePalette( static ox::Error loadTileSheetSet( Context &ctx, - unsigned &bpp, uint16_t *tileMapTargetMem, TileSheetSet const&set) noexcept { auto &rom = ctx.rom(); @@ -189,10 +190,12 @@ static ox::Error loadTileSheetSet( for (auto const&entry : set.entries) { oxRequire(tsStat, rom.stat(entry.tilesheet)); oxRequire(ts, rom.directAccess(entry.tilesheet)); + unsigned tilesheetBpp{}; GbaTileMapTarget target{ - .bpp = bpp, + .bpp = tilesheetBpp, .defaultPalette = {}, .tileMap = tileMapTargetMem + tileWriteIdx, + .targetBpp = static_cast(set.bpp), .setEntry = &entry, }; oxReturnError(ox::readMC(ts, static_cast(tsStat.size), &target)); @@ -232,9 +235,10 @@ 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)); + auto const bpp = static_cast(set.bpp); + oxReturnError(loadTileSheetSet(ctx, MEM_BG_TILES[cbb].data(), set)); // update bpp of all bgs with the updated cbb + ctx.cbbData[cbb].bpp = bpp; teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) { if (teagba::bgCbb(bgCtl) == cbb) { teagba::bgSetBpp(bgCtl, bpp); @@ -276,8 +280,8 @@ ox::Error loadSpriteTileSheet( ox::Error loadSpriteTileSheet( Context &ctx, TileSheetSet const&set) noexcept { - unsigned bpp{}; - oxReturnError(loadTileSheetSet(ctx, bpp, MEM_SPRITE_TILES, set)); + auto const bpp = static_cast(set.bpp); + oxReturnError(loadTileSheetSet(ctx, MEM_SPRITE_TILES, set)); setSpritesBpp(bpp); return {}; } @@ -340,17 +344,20 @@ void showSprite(Context&, unsigned idx) noexcept { void setSprite(Context&, uint_t idx, Sprite const&s) noexcept { //oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow"); + uint16_t const eightBpp = s.bpp == 8; teagba::addSpriteUpdate({ .attr0 = static_cast( (static_cast(s.y & ox::onMask(0b111'1111))) | (static_cast(1) << 10) // enable alpha + | (static_cast(eightBpp) << 13) | (static_cast(s.spriteShape) << 14)), .attr1 = static_cast( (static_cast(s.x) & ox::onMask(8)) | (static_cast(s.flipX) << 12) | (static_cast(s.spriteSize) << 14)), .attr2 = static_cast( - (static_cast(s.tileIdx & ox::onMask(8))) + // double tileIdx if 8 bpp + (static_cast((s.tileIdx * (1 + eightBpp)) & ox::onMask(8))) | (static_cast(s.priority & 0b11) << 10)), .idx = static_cast(idx), }); diff --git a/src/nostalgia/player/app.cpp b/src/nostalgia/player/app.cpp index 19a82174..3af8ebe0 100644 --- a/src/nostalgia/player/app.cpp +++ b/src/nostalgia/player/app.cpp @@ -105,16 +105,18 @@ static ox::Error runTileSheetSetTest(turbine::Context &tctx) { core::setBgTile(*cctx, 0, 11, 9, 2); core::setBgTile(*cctx, 0, 13, 9, 4); core::setSprite(*cctx, 16, { - .enabled = true, - .x = 12 * 8, - .y = 9 * 8, - .tileIdx = 3, + .enabled = true, + .x = 12 * 8, + .y = 9 * 8, + .tileIdx = 3, + .bpp = static_cast(set.bpp), }); core::setSprite(*cctx, 17, { .enabled = true, .x = 14 * 8, .y = 9 * 8, .tileIdx = 5, + .bpp = static_cast(set.bpp), }); turbine::setKeyEventHandler(tctx, testKeyEventHandler); return turbine::run(tctx);