[nostalgia/core] Make load TileSheet functions take CompactTileSheet, in addition to FileAddresses
This commit is contained in:
parent
0dfa7c30e6
commit
f82db6905c
@ -11,6 +11,7 @@
|
||||
|
||||
#include "context.hpp"
|
||||
#include "palette.hpp"
|
||||
#include "tilesheet.hpp"
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
@ -134,12 +135,23 @@ ox::Error loadBgTileSheet(
|
||||
unsigned cbb,
|
||||
TileSheetSet const&set) noexcept;
|
||||
|
||||
ox::Error loadBgTileSheet(
|
||||
Context &ctx,
|
||||
unsigned cbb,
|
||||
CompactTileSheet const&ts,
|
||||
ox::Optional<unsigned> const&paletteBank) noexcept;
|
||||
|
||||
ox::Error loadBgTileSheet(
|
||||
Context &ctx,
|
||||
unsigned cbb,
|
||||
ox::FileAddress const&tilesheetAddr,
|
||||
ox::Optional<unsigned> const&paletteBank = {}) noexcept;
|
||||
|
||||
ox::Error loadSpriteTileSheet(
|
||||
Context &ctx,
|
||||
CompactTileSheet const&ts,
|
||||
bool loadDefaultPalette) noexcept;
|
||||
|
||||
ox::Error loadSpriteTileSheet(
|
||||
Context &ctx,
|
||||
ox::FileAddress const&tilesheetAddr,
|
||||
|
@ -296,9 +296,10 @@ using TileSheetV4 = TileSheet;
|
||||
struct CompactTileSheetV1 {
|
||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.CompactTileSheet";
|
||||
static constexpr auto TypeVersion = 1;
|
||||
static constexpr auto Preloadable = true;
|
||||
int8_t bpp = 0;
|
||||
ox::FileAddress defaultPalette;
|
||||
ox::Vector<uint8_t> pixels = {};
|
||||
ox::Vector<uint8_t> pixels;
|
||||
};
|
||||
|
||||
using CompactTileSheet = CompactTileSheetV1;
|
||||
|
@ -24,104 +24,6 @@ namespace nostalgia::core {
|
||||
|
||||
constexpr auto SpriteCount = 128;
|
||||
|
||||
struct GbaTileMapTarget {
|
||||
static constexpr auto TypeName = CompactTileSheet::TypeName;
|
||||
static constexpr auto TypeVersion = CompactTileSheet::TypeVersion;
|
||||
unsigned &bpp;
|
||||
ox::FileAddress defaultPalette;
|
||||
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;
|
||||
TileSheetSetEntry const*setEntry = nullptr;
|
||||
};
|
||||
|
||||
[[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 {
|
||||
oxReturnError(io->template setTypeInfo<CompactTileSheet>());
|
||||
oxReturnError(io->field("bpp", &t->bpp));
|
||||
oxReturnError(io->field("defaultPalette", &t->defaultPalette));
|
||||
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->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.
|
||||
size_t sectionIdx = 0;
|
||||
if (t->targetBpp == t->bpp) {
|
||||
uint16_t intermediate = 0;
|
||||
size_t const fourBpp = t->bpp == 4;
|
||||
const auto handleTileMap = [t, &intermediate, §ionIdx, fourBpp]
|
||||
(std::size_t i, uint8_t const*tile) {
|
||||
auto const tileIdx = static_cast<int>((i * (2 * fourBpp)) / PixelsPerTile);
|
||||
if (!loadPixel(*t->setEntry, sectionIdx, tileIdx)) {
|
||||
return ox::Error{};
|
||||
}
|
||||
if (i & 1) { // i is odd
|
||||
intermediate |= static_cast<uint16_t>(*tile) << 8;
|
||||
t->tileMap[t->tileWriteIdx] = 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, §ionIdx](std::size_t i, uint8_t const*tile) {
|
||||
auto constexpr BytesPerTile4Bpp = 32;
|
||||
auto const tileIdx = static_cast<int>(i / 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<uint16_t>(px1 | (px2 << 8));
|
||||
++t->tileWriteIdx;
|
||||
return ox::Error{};
|
||||
};
|
||||
out = io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
||||
}
|
||||
} else {
|
||||
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<uint16_t>(*tile) << 8;
|
||||
t->tileMap[i / 2] = intermediate;
|
||||
} 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 {
|
||||
for (auto bgCtl = ®_BG0CTL; bgCtl <= ®_BG3CTL; bgCtl += 2) {
|
||||
teagba::bgSetSbb(*bgCtl, 28);
|
||||
@ -181,21 +83,48 @@ static ox::Error loadTileSheetSet(
|
||||
Context &ctx,
|
||||
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));
|
||||
unsigned tilesheetBpp{};
|
||||
GbaTileMapTarget target{
|
||||
.bpp = tilesheetBpp,
|
||||
.defaultPalette = {},
|
||||
.tileMap = tileMapTargetMem + tileWriteIdx,
|
||||
.targetBpp = static_cast<unsigned>(set.bpp),
|
||||
.setEntry = &entry,
|
||||
};
|
||||
oxReturnError(ox::readMC({ts, static_cast<std::size_t>(tsStat.size)}, target));
|
||||
tileWriteIdx += target.tileWriteIdx;
|
||||
oxRequire(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), entry.tilesheet));
|
||||
if (set.bpp != ts->bpp && ts->bpp == 8) {
|
||||
return OxError(1, "cannot load an 8 BPP tilesheet into a 4 BPP CBB");
|
||||
}
|
||||
for (auto const&s : entry.sections) {
|
||||
auto const cnt = (static_cast<size_t>(s.tiles) * PixelsPerTile) / (1 + (set.bpp == 4));
|
||||
for (size_t i = 0; i < cnt; ++i) {
|
||||
auto const srcIdx = static_cast<size_t>(s.begin) + i * 2;
|
||||
auto const v = static_cast<uint16_t>(
|
||||
static_cast<uint16_t>(ts->pixels[srcIdx]) |
|
||||
(static_cast<uint16_t>(ts->pixels[srcIdx + 1]) << 8));
|
||||
tileMapTargetMem[tileWriteIdx + i] = v;
|
||||
}
|
||||
tileWriteIdx += cnt;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error loadBgTileSheet(
|
||||
Context &ctx,
|
||||
unsigned cbb,
|
||||
CompactTileSheet const&ts,
|
||||
ox::Optional<unsigned> const&paletteBank) noexcept {
|
||||
auto const cnt = (ts.pixels.size() * PixelsPerTile) / (1 + (ts.bpp == 4));
|
||||
for (size_t i = 0; i < cnt; ++i) {
|
||||
auto const srcIdx = i * 2;
|
||||
auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
|
||||
auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);
|
||||
MEM_BG_TILES[cbb][i] = static_cast<uint16_t>(p1 | (p2 << 8));
|
||||
}
|
||||
// update bpp of all bgs with the updated cbb
|
||||
auto const bpp = ctx.cbbData[cbb].bpp;
|
||||
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
|
||||
if (teagba::bgCbb(bgCtl) == cbb) {
|
||||
teagba::bgSetBpp(bgCtl, bpp);
|
||||
}
|
||||
});
|
||||
if (paletteBank.has_value() && ts.defaultPalette) {
|
||||
oxReturnError(loadBgPalette(ctx, *paletteBank, ts.defaultPalette));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@ -205,26 +134,8 @@ ox::Error loadBgTileSheet(
|
||||
unsigned cbb,
|
||||
ox::FileAddress const&tilesheetAddr,
|
||||
ox::Optional<unsigned> const&paletteBank) noexcept {
|
||||
auto &rom = ctx.rom();
|
||||
oxRequire(tsStat, rom.stat(tilesheetAddr));
|
||||
oxRequire(ts, rom.directAccess(tilesheetAddr));
|
||||
GbaTileMapTarget target{
|
||||
.bpp = ctx.cbbData[cbb].bpp,
|
||||
.defaultPalette = {},
|
||||
.tileMap = MEM_BG_TILES[cbb].data(),
|
||||
};
|
||||
oxReturnError(ox::readMC({ts, static_cast<std::size_t>(tsStat.size)}, target));
|
||||
// update bpp of all bgs with the updated cbb
|
||||
const auto bpp = ctx.cbbData[cbb].bpp;
|
||||
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
|
||||
if (teagba::bgCbb(bgCtl) == cbb) {
|
||||
teagba::bgSetBpp(bgCtl, bpp);
|
||||
}
|
||||
});
|
||||
if (paletteBank.has_value() && target.defaultPalette) {
|
||||
oxReturnError(loadBgPalette(ctx, *paletteBank, target.defaultPalette));
|
||||
}
|
||||
return {};
|
||||
oxRequire(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
|
||||
return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
|
||||
}
|
||||
|
||||
ox::Error loadBgTileSheet(
|
||||
@ -252,25 +163,28 @@ static void setSpritesBpp(unsigned const bpp) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
ox::Error loadSpriteTileSheet(
|
||||
Context &ctx,
|
||||
CompactTileSheet const&ts,
|
||||
bool loadDefaultPalette) noexcept {
|
||||
for (size_t i = 0; i < ts.pixels.size(); i += 2) {
|
||||
uint16_t v = ts.pixels[i];
|
||||
v |= static_cast<uint16_t>(ts.pixels[i + 1] << 8);
|
||||
MEM_SPRITE_TILES[i] = v;
|
||||
}
|
||||
if (loadDefaultPalette && ts.defaultPalette) {
|
||||
oxReturnError(loadSpritePalette(ctx, ts.defaultPalette));
|
||||
}
|
||||
setSpritesBpp(static_cast<unsigned>(ts.bpp));
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error loadSpriteTileSheet(
|
||||
Context &ctx,
|
||||
ox::FileAddress const&tilesheetAddr,
|
||||
bool loadDefaultPalette) noexcept {
|
||||
auto &rom = ctx.rom();
|
||||
oxRequire(tsStat, rom.stat(tilesheetAddr));
|
||||
oxRequire(ts, rom.directAccess(tilesheetAddr));
|
||||
unsigned bpp{};
|
||||
GbaTileMapTarget target{
|
||||
.bpp = bpp,
|
||||
.defaultPalette = {},
|
||||
.tileMap = MEM_SPRITE_TILES,
|
||||
};
|
||||
oxReturnError(ox::readMC({ts, static_cast<std::size_t>(tsStat.size)}, target));
|
||||
if (loadDefaultPalette && target.defaultPalette) {
|
||||
oxReturnError(loadSpritePalette(ctx, target.defaultPalette));
|
||||
}
|
||||
setSpritesBpp(bpp);
|
||||
return {};
|
||||
oxRequire(ts, keel::readObj<CompactTileSheet>(keelCtx(ctx), tilesheetAddr));
|
||||
return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette);
|
||||
}
|
||||
|
||||
ox::Error loadSpriteTileSheet(
|
||||
|
@ -572,20 +572,28 @@ static ox::Result<TileSheetData> buildSetTsd(
|
||||
return setTsd;
|
||||
}
|
||||
|
||||
ox::Error loadBgTileSheet(
|
||||
Context &ctx,
|
||||
uint_t cbb,
|
||||
CompactTileSheet const&ts,
|
||||
ox::Optional<unsigned> const&paletteBank) noexcept {
|
||||
oxRequire(tsd, normalizeTileSheet(ts));
|
||||
oxTracef("nostalgia.core.gfx.gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbb, tsd.width, tsd.height);
|
||||
ctx.cbbs[cbb].tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data());
|
||||
if (paletteBank.has_value() && ts.defaultPalette) {
|
||||
oxReturnError(loadBgPalette(ctx, *paletteBank, ts.defaultPalette));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error loadBgTileSheet(
|
||||
Context &ctx,
|
||||
uint_t cbb,
|
||||
ox::FileAddress const&tilesheetAddr,
|
||||
ox::Optional<unsigned> const&paletteBank) noexcept {
|
||||
auto &kctx = keelCtx(ctx.turbineCtx);
|
||||
oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, tilesheetAddr));
|
||||
oxRequire(tsd, normalizeTileSheet(*tilesheet));
|
||||
oxTracef("nostalgia.core.gfx.gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbb, tsd.width, tsd.height);
|
||||
ctx.cbbs[cbb].tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data());
|
||||
if (paletteBank.has_value() && tilesheet->defaultPalette) {
|
||||
oxReturnError(loadBgPalette(ctx, *paletteBank, tilesheet->defaultPalette));
|
||||
}
|
||||
return {};
|
||||
oxRequire(ts, readObj<CompactTileSheet>(kctx, tilesheetAddr));
|
||||
return loadBgTileSheet(ctx, cbb, *ts, paletteBank);
|
||||
}
|
||||
|
||||
ox::Error loadBgTileSheet(
|
||||
@ -599,19 +607,26 @@ ox::Error loadBgTileSheet(
|
||||
|
||||
ox::Error loadSpriteTileSheet(
|
||||
Context &ctx,
|
||||
ox::FileAddress const&tilesheetAddr,
|
||||
CompactTileSheet const&ts,
|
||||
bool loadDefaultPalette) noexcept {
|
||||
auto &kctx = keelCtx(ctx.turbineCtx);
|
||||
oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, tilesheetAddr));
|
||||
oxRequire(tsd, normalizeTileSheet(*tilesheet));
|
||||
oxRequire(tsd, normalizeTileSheet(ts));
|
||||
oxTracef("nostalgia.core.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", tsd.width, tsd.height);
|
||||
ctx.spriteBlocks.tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data());
|
||||
if (loadDefaultPalette) {
|
||||
oxReturnError(loadSpritePalette(ctx, tilesheet->defaultPalette));
|
||||
oxReturnError(loadSpritePalette(ctx, ts.defaultPalette));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error loadSpriteTileSheet(
|
||||
Context &ctx,
|
||||
ox::FileAddress const&tilesheetAddr,
|
||||
bool loadDefaultPalette) noexcept {
|
||||
auto &kctx = keelCtx(ctx.turbineCtx);
|
||||
oxRequire(ts, readObj<CompactTileSheet>(kctx, tilesheetAddr));
|
||||
return loadSpriteTileSheet(ctx, *ts, loadDefaultPalette);
|
||||
}
|
||||
|
||||
ox::Error loadSpriteTileSheet(
|
||||
Context &ctx,
|
||||
TileSheetSet const&set) noexcept {
|
||||
|
Loading…
Reference in New Issue
Block a user