[nostalgia/core] Get TileSheetSet working with 8bpp setting
This commit is contained in:
parent
fcf6f00797
commit
46d1313797
@ -23,6 +23,7 @@ struct Sprite {
|
|||||||
unsigned spriteShape = 0;
|
unsigned spriteShape = 0;
|
||||||
unsigned spriteSize = 0;
|
unsigned spriteSize = 0;
|
||||||
unsigned flipX = 0;
|
unsigned flipX = 0;
|
||||||
|
unsigned bpp = 0;
|
||||||
/**
|
/**
|
||||||
* Valid priorities: 0-3
|
* Valid priorities: 0-3
|
||||||
*/
|
*/
|
||||||
@ -38,6 +39,7 @@ oxModelBegin(Sprite)
|
|||||||
oxModelField(spriteShape)
|
oxModelField(spriteShape)
|
||||||
oxModelField(spriteSize)
|
oxModelField(spriteSize)
|
||||||
oxModelField(flipX)
|
oxModelField(flipX)
|
||||||
|
oxModelField(bpp)
|
||||||
oxModelField(priority)
|
oxModelField(priority)
|
||||||
oxModelEnd()
|
oxModelEnd()
|
||||||
|
|
||||||
|
@ -60,6 +60,25 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> 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<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->bpp));
|
oxReturnError(io->field("bpp", &t->bpp));
|
||||||
@ -71,43 +90,27 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t)
|
|||||||
return OxError(1, "Cannot load an 8 BPP tilesheet into a 4 BPP CBB");
|
return OxError(1, "Cannot load an 8 BPP tilesheet into a 4 BPP CBB");
|
||||||
}
|
}
|
||||||
ox::Error out{};
|
ox::Error out{};
|
||||||
uint16_t intermediate = 0;
|
|
||||||
if (t->setEntry) {
|
if (t->setEntry) {
|
||||||
// The following code is atrocious, but it works.
|
// The following code is atrocious, but it works.
|
||||||
// It might be possible to clean it up a little, but it probably
|
// It might be possible to clean it up a little, but it probably
|
||||||
// cannot be seriously optimized without preloading TileSheets.
|
// cannot be seriously optimized without preloading TileSheets.
|
||||||
// Consider building an array of bitmaps (Array<uint64_t, 4>)
|
size_t sectionIdx = 0;
|
||||||
// so this can be done with a single bitmap look up.
|
|
||||||
if (t->targetBpp == t->bpp) {
|
if (t->targetBpp == t->bpp) {
|
||||||
TileSheetSetEntrySection const*section = &t->setEntry->sections[0];
|
TileSheetSetEntrySection const*section = &t->setEntry->sections[0];
|
||||||
size_t sectionIdx = 1;
|
|
||||||
size_t writeIt = 0;
|
size_t writeIt = 0;
|
||||||
|
uint16_t intermediate = 0;
|
||||||
size_t const fourBpp = t->bpp == 4;
|
size_t const fourBpp = t->bpp == 4;
|
||||||
const auto handleTileMap = [t, &intermediate, §ion, §ionIdx, &writeIt, fourBpp]
|
const auto handleTileMap = [t, &intermediate, §ion, §ionIdx, &writeIt, fourBpp]
|
||||||
(std::size_t i, uint8_t const *tile) {
|
(std::size_t i, uint8_t const*tile) {
|
||||||
if (!section) {
|
|
||||||
return ox::Error{};
|
|
||||||
}
|
|
||||||
auto const tileIdx = static_cast<int>((i * (2 * fourBpp)) / PixelsPerTile);
|
auto const tileIdx = static_cast<int>((i * (2 * fourBpp)) / PixelsPerTile);
|
||||||
if (tileIdx < section->begin) {
|
if (!loadPixel(*t->setEntry, sectionIdx, tileIdx)) {
|
||||||
return ox::Error{};
|
return ox::Error{};
|
||||||
}
|
}
|
||||||
if (tileIdx > section->end()) {
|
if (writeIt & 1) { // i is odd
|
||||||
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
|
|
||||||
intermediate |= static_cast<uint16_t>(*tile) << 8;
|
intermediate |= static_cast<uint16_t>(*tile) << 8;
|
||||||
t->tileMap[writeIt / 2] = intermediate;
|
t->tileMap[writeIt / 2] = intermediate;
|
||||||
++t->tileWriteIdx;
|
++t->tileWriteIdx;
|
||||||
} else { // writeIt is even
|
} else { // i is even
|
||||||
intermediate = *tile & 0x00ff;
|
intermediate = *tile & 0x00ff;
|
||||||
}
|
}
|
||||||
++writeIt;
|
++writeIt;
|
||||||
@ -115,31 +118,30 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t)
|
|||||||
};
|
};
|
||||||
out = 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
|
} else if (t->targetBpp > t->bpp) { // 4 -> 8 bits
|
||||||
const auto handleTileMap = [t, &intermediate](std::size_t i, uint8_t const *tile) {
|
const auto handleTileMap = [t, §ionIdx](std::size_t writeIt, uint8_t const*tile) {
|
||||||
if (i & 1) { // i is odd
|
auto constexpr BytesPerTile4Bpp = 32;
|
||||||
intermediate |= static_cast<uint16_t>(*tile) << 8;
|
auto const tileIdx = static_cast<int>(writeIt / BytesPerTile4Bpp);
|
||||||
// write 4 pixels from intermediate
|
if (!loadPixel(*t->setEntry, sectionIdx, tileIdx)) {
|
||||||
t->tileMap[i - 3] = (intermediate & 0b0000'0000'0000'1111) >> 0;
|
return ox::Error{};
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
uint16_t const px1 = *tile & 0xf;
|
||||||
|
uint16_t const px2 = *tile >> 4;
|
||||||
|
t->tileMap[t->tileWriteIdx] = static_cast<uint16_t>(px1 | (px2 << 8));
|
||||||
|
++t->tileWriteIdx;
|
||||||
return ox::Error{};
|
return ox::Error{};
|
||||||
};
|
};
|
||||||
out = io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
out = io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
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;
|
||||||
} else { // i is even
|
} else { // i is even
|
||||||
intermediate = *tile & 0x00ff;
|
intermediate = *tile & 0x00ff;
|
||||||
}
|
}
|
||||||
return OxError(0);
|
return ox::Error{};
|
||||||
};
|
};
|
||||||
out = io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
out = io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
||||||
}
|
}
|
||||||
@ -181,7 +183,6 @@ ox::Error loadSpritePalette(
|
|||||||
|
|
||||||
static ox::Error loadTileSheetSet(
|
static ox::Error loadTileSheetSet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
unsigned &bpp,
|
|
||||||
uint16_t *tileMapTargetMem,
|
uint16_t *tileMapTargetMem,
|
||||||
TileSheetSet const&set) noexcept {
|
TileSheetSet const&set) noexcept {
|
||||||
auto &rom = ctx.rom();
|
auto &rom = ctx.rom();
|
||||||
@ -189,10 +190,12 @@ static ox::Error loadTileSheetSet(
|
|||||||
for (auto const&entry : set.entries) {
|
for (auto const&entry : set.entries) {
|
||||||
oxRequire(tsStat, rom.stat(entry.tilesheet));
|
oxRequire(tsStat, rom.stat(entry.tilesheet));
|
||||||
oxRequire(ts, rom.directAccess(entry.tilesheet));
|
oxRequire(ts, rom.directAccess(entry.tilesheet));
|
||||||
|
unsigned tilesheetBpp{};
|
||||||
GbaTileMapTarget target{
|
GbaTileMapTarget target{
|
||||||
.bpp = bpp,
|
.bpp = tilesheetBpp,
|
||||||
.defaultPalette = {},
|
.defaultPalette = {},
|
||||||
.tileMap = tileMapTargetMem + tileWriteIdx,
|
.tileMap = tileMapTargetMem + tileWriteIdx,
|
||||||
|
.targetBpp = static_cast<unsigned>(set.bpp),
|
||||||
.setEntry = &entry,
|
.setEntry = &entry,
|
||||||
};
|
};
|
||||||
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
|
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
|
||||||
@ -232,9 +235,10 @@ ox::Error loadBgTileSheet(
|
|||||||
Context &ctx,
|
Context &ctx,
|
||||||
unsigned cbb,
|
unsigned cbb,
|
||||||
TileSheetSet const&set) noexcept {
|
TileSheetSet const&set) noexcept {
|
||||||
auto &bpp = ctx.cbbData[cbb].bpp;
|
auto const bpp = static_cast<unsigned>(set.bpp);
|
||||||
oxReturnError(loadTileSheetSet(ctx, bpp, MEM_BG_TILES[cbb].data(), set));
|
oxReturnError(loadTileSheetSet(ctx, MEM_BG_TILES[cbb].data(), set));
|
||||||
// update bpp of all bgs with the updated cbb
|
// update bpp of all bgs with the updated cbb
|
||||||
|
ctx.cbbData[cbb].bpp = bpp;
|
||||||
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
|
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
|
||||||
if (teagba::bgCbb(bgCtl) == cbb) {
|
if (teagba::bgCbb(bgCtl) == cbb) {
|
||||||
teagba::bgSetBpp(bgCtl, bpp);
|
teagba::bgSetBpp(bgCtl, bpp);
|
||||||
@ -276,8 +280,8 @@ ox::Error loadSpriteTileSheet(
|
|||||||
ox::Error loadSpriteTileSheet(
|
ox::Error loadSpriteTileSheet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
TileSheetSet const&set) noexcept {
|
TileSheetSet const&set) noexcept {
|
||||||
unsigned bpp{};
|
auto const bpp = static_cast<unsigned>(set.bpp);
|
||||||
oxReturnError(loadTileSheetSet(ctx, bpp, MEM_SPRITE_TILES, set));
|
oxReturnError(loadTileSheetSet(ctx, MEM_SPRITE_TILES, set));
|
||||||
setSpritesBpp(bpp);
|
setSpritesBpp(bpp);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -340,17 +344,20 @@ void showSprite(Context&, unsigned idx) noexcept {
|
|||||||
|
|
||||||
void setSprite(Context&, uint_t idx, Sprite const&s) noexcept {
|
void setSprite(Context&, uint_t idx, Sprite const&s) noexcept {
|
||||||
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||||
|
uint16_t const eightBpp = s.bpp == 8;
|
||||||
teagba::addSpriteUpdate({
|
teagba::addSpriteUpdate({
|
||||||
.attr0 = static_cast<uint16_t>(
|
.attr0 = static_cast<uint16_t>(
|
||||||
(static_cast<uint16_t>(s.y & ox::onMask<uint8_t>(0b111'1111)))
|
(static_cast<uint16_t>(s.y & ox::onMask<uint8_t>(0b111'1111)))
|
||||||
| (static_cast<uint16_t>(1) << 10) // enable alpha
|
| (static_cast<uint16_t>(1) << 10) // enable alpha
|
||||||
|
| (static_cast<uint16_t>(eightBpp) << 13)
|
||||||
| (static_cast<uint16_t>(s.spriteShape) << 14)),
|
| (static_cast<uint16_t>(s.spriteShape) << 14)),
|
||||||
.attr1 = static_cast<uint16_t>(
|
.attr1 = static_cast<uint16_t>(
|
||||||
(static_cast<uint16_t>(s.x) & ox::onMask<uint8_t>(8))
|
(static_cast<uint16_t>(s.x) & ox::onMask<uint8_t>(8))
|
||||||
| (static_cast<uint16_t>(s.flipX) << 12)
|
| (static_cast<uint16_t>(s.flipX) << 12)
|
||||||
| (static_cast<uint16_t>(s.spriteSize) << 14)),
|
| (static_cast<uint16_t>(s.spriteSize) << 14)),
|
||||||
.attr2 = static_cast<uint16_t>(
|
.attr2 = static_cast<uint16_t>(
|
||||||
(static_cast<uint16_t>(s.tileIdx & ox::onMask<uint16_t>(8)))
|
// double tileIdx if 8 bpp
|
||||||
|
(static_cast<uint16_t>((s.tileIdx * (1 + eightBpp)) & ox::onMask<uint16_t>(8)))
|
||||||
| (static_cast<uint16_t>(s.priority & 0b11) << 10)),
|
| (static_cast<uint16_t>(s.priority & 0b11) << 10)),
|
||||||
.idx = static_cast<uint16_t>(idx),
|
.idx = static_cast<uint16_t>(idx),
|
||||||
});
|
});
|
||||||
|
@ -105,16 +105,18 @@ static ox::Error runTileSheetSetTest(turbine::Context &tctx) {
|
|||||||
core::setBgTile(*cctx, 0, 11, 9, 2);
|
core::setBgTile(*cctx, 0, 11, 9, 2);
|
||||||
core::setBgTile(*cctx, 0, 13, 9, 4);
|
core::setBgTile(*cctx, 0, 13, 9, 4);
|
||||||
core::setSprite(*cctx, 16, {
|
core::setSprite(*cctx, 16, {
|
||||||
.enabled = true,
|
.enabled = true,
|
||||||
.x = 12 * 8,
|
.x = 12 * 8,
|
||||||
.y = 9 * 8,
|
.y = 9 * 8,
|
||||||
.tileIdx = 3,
|
.tileIdx = 3,
|
||||||
|
.bpp = static_cast<unsigned>(set.bpp),
|
||||||
});
|
});
|
||||||
core::setSprite(*cctx, 17, {
|
core::setSprite(*cctx, 17, {
|
||||||
.enabled = true,
|
.enabled = true,
|
||||||
.x = 14 * 8,
|
.x = 14 * 8,
|
||||||
.y = 9 * 8,
|
.y = 9 * 8,
|
||||||
.tileIdx = 5,
|
.tileIdx = 5,
|
||||||
|
.bpp = static_cast<unsigned>(set.bpp),
|
||||||
});
|
});
|
||||||
turbine::setKeyEventHandler(tctx, testKeyEventHandler);
|
turbine::setKeyEventHandler(tctx, testKeyEventHandler);
|
||||||
return turbine::run(tctx);
|
return turbine::run(tctx);
|
||||||
|
Loading…
Reference in New Issue
Block a user