[nostalgia/core] Get TileSheetSet working

This commit is contained in:
2023-12-22 22:38:46 -06:00
parent ef6e3af735
commit fcf6f00797
8 changed files with 196 additions and 47 deletions

View File

@@ -41,6 +41,7 @@ struct GbaTileMapTarget {
// and only exist to communicate with the loading process
size_t tileWriteIdx = 0;
unsigned targetBpp = 0;
TileSheetSetEntry const*setEntry = nullptr;
};
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> auto *t) noexcept {
@@ -63,7 +64,6 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t)
oxReturnError(io->template setTypeInfo<CompactTileSheet>());
oxReturnError(io->field("bpp", &t->bpp));
oxReturnError(io->field("defaultPalette", &t->defaultPalette));
uint16_t intermediate = 0;
if (t->targetBpp == 0) {
t->targetBpp = t->bpp;
}
@@ -71,32 +71,75 @@ 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");
}
ox::Error out{};
if (t->targetBpp == t->bpp) {
const auto handleTileMap = [t, &intermediate](std::size_t i, uint8_t const*tile) {
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<uint64_t, 4>)
// so this can be done with a single bitmap look up.
if (t->targetBpp == t->bpp) {
TileSheetSetEntrySection const*section = &t->setEntry->sections[0];
size_t sectionIdx = 1;
size_t writeIt = 0;
size_t const fourBpp = t->bpp == 4;
const auto handleTileMap = [t, &intermediate, &section, &sectionIdx, &writeIt, fourBpp]
(std::size_t i, uint8_t const *tile) {
if (!section) {
return ox::Error{};
}
auto const tileIdx = static_cast<int>((i * (2 * fourBpp)) / PixelsPerTile);
if (tileIdx < section->begin) {
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
intermediate |= static_cast<uint16_t>(*tile) << 8;
t->tileMap[writeIt / 2] = intermediate;
++t->tileWriteIdx;
} else { // writeIt is even
intermediate = *tile & 0x00ff;
}
++writeIt;
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);
}
} else {
const auto handleTileMap = [t, &intermediate](std::size_t i, const uint8_t *tile) {
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{};
return OxError(0);
};
out = io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
}
@@ -150,6 +193,7 @@ static ox::Error loadTileSheetSet(
.bpp = bpp,
.defaultPalette = {},
.tileMap = tileMapTargetMem + tileWriteIdx,
.setEntry = &entry,
};
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
tileWriteIdx += target.tileWriteIdx;