[nostalgia/core] Cleanup graphics API

This commit is contained in:
2023-12-21 21:18:31 -06:00
parent 8395128efa
commit d29118d783
8 changed files with 268 additions and 288 deletions

View File

@@ -8,10 +8,15 @@
namespace nostalgia::core {
struct BgCbbData {
unsigned bpp = 4;
};
class Context {
public:
turbine::Context &turbineCtx;
ox::Array<BgCbbData, 4> cbbData;
explicit Context(turbine::Context &tctx) noexcept;
Context(Context &other) noexcept = delete;

View File

@@ -10,7 +10,6 @@
#include <teagba/gfx.hpp>
#include <teagba/registers.hpp>
#include <keel/media.hpp>
#include <turbine/turbine.hpp>
#include <nostalgia/core/color.hpp>
@@ -22,11 +21,6 @@
namespace nostalgia::core {
struct BgCbbData {
unsigned bpp = 4;
};
static ox::Array<BgCbbData, 4> g_cbbData;
constexpr auto GbaTileColumns = 32;
constexpr auto GbaTileRows = 32;
@@ -41,17 +35,23 @@ struct GbaTileMapTarget {
static constexpr auto TypeVersion = CompactTileSheet::TypeVersion;
BgCbbData *cbbData = nullptr;
ox::FileAddress defaultPalette;
GbaPaletteTarget pal;
volatile uint16_t *tileMap = nullptr;
};
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> auto *t) noexcept {
oxReturnError(io->template setTypeInfo<Palette>());
const auto colorHandler = [t](std::size_t i, const Color16 *c) {
t->palette[i] = *c;
return OxError(0);
};
return io->template field<Color16, decltype(colorHandler)>("colors", colorHandler);
if (t->palette) {
const auto colorHandler = [t](std::size_t i, const Color16 *c) {
t->palette[i] = *c;
return ox::Error{};
};
return io->template field<Color16, decltype(colorHandler)>("colors", colorHandler);
} else {
constexpr auto colorHandler = [](std::size_t, const Color16*) {
return ox::Error{};
};
return io->template field<Color16, decltype(colorHandler)>("colors", colorHandler);
}
}
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t) noexcept {
@@ -73,11 +73,87 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t)
ox::Error initGfx(Context&, InitParams const&) noexcept {
for (auto bgCtl = &REG_BG0CTL; bgCtl <= &REG_BG3CTL; bgCtl += 2) {
teagba::bgSetSbb(bgCtl, 28);
teagba::bgSetSbb(*bgCtl, 28);
}
return {};
}
ox::Error loadBgPalette(
Context &ctx,
ox::FileAddress const&paletteAddr) noexcept {
auto &rom = ctx.rom();
GbaPaletteTarget const palTarget{.palette = MEM_BG_PALETTE};
oxRequire(palStat, rom.stat(paletteAddr));
oxRequire(pal, rom.directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &palTarget));
return {};
}
ox::Error loadSpritePalette(
Context &ctx,
ox::FileAddress const&paletteAddr) noexcept {
auto &rom = ctx.rom();
GbaPaletteTarget const palTarget{.palette = MEM_SPRITE_PALETTE};
oxRequire(palStat, rom.stat(paletteAddr));
oxRequire(pal, rom.directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &palTarget));
return {};
}
ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
ox::FileAddress const&tilesheetAddr,
bool loadDefaultPalette) noexcept {
auto &rom = ctx.rom();
oxRequire(tsStat, rom.stat(tilesheetAddr));
oxRequire(ts, rom.directAccess(tilesheetAddr));
GbaTileMapTarget target{
.cbbData = &ctx.cbbData[cbb],
.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 (loadDefaultPalette && target.defaultPalette) {
oxReturnError(loadBgPalette(ctx, target.defaultPalette));
}
return {};
}
ox::Error loadSpriteTileSheet(
Context &ctx,
ox::FileAddress const&tilesheetAddr,
bool loadDefaultPalette) noexcept {
auto &rom = ctx.rom();
oxRequire(tsStat, ctx.rom().stat(tilesheetAddr));
oxRequire(ts, rom.directAccess(tilesheetAddr));
GbaTileMapTarget target{
.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));
}
return {};
}
void setBgTile(Context&, uint_t bgIdx, int column, int row, uint8_t tile) noexcept {
const auto tileIdx = static_cast<std::size_t>(row * GbaTileColumns + column);
MEM_BG_MAP[bgIdx][tileIdx] = tile;
}
void clearBg(Context&, uint_t bgIdx) noexcept {
memset(MEM_BG_MAP[bgIdx].data(), 0, GbaTileRows * GbaTileColumns);
}
uint8_t bgStatus(Context&) noexcept {
return (REG_DISPCTL >> 8u) & 0b1111u;
}
@@ -97,11 +173,11 @@ void setBgStatus(Context&, unsigned bg, bool status) noexcept {
REG_DISPCTL = REG_DISPCTL | ((REG_DISPCTL & ~mask) | mask);
}
void setBgCbb(Context&, unsigned bgIdx, unsigned cbb) noexcept {
void setBgCbb(Context &ctx, unsigned bgIdx, unsigned cbb) noexcept {
auto &bgCtl = regBgCtl(bgIdx);
const auto &cbbData = g_cbbData[cbb];
teagba::bgSetBpp(&bgCtl, cbbData.bpp);
teagba::bgSetCbb(&bgCtl, cbb);
const auto &cbbData = ctx.cbbData[cbb];
teagba::bgSetBpp(bgCtl, cbbData.bpp);
teagba::bgSetCbb(bgCtl, cbb);
}
void setBgPriority(Context&, uint_t bgIdx, uint_t priority) noexcept {
@@ -109,111 +185,6 @@ void setBgPriority(Context&, uint_t bgIdx, uint_t priority) noexcept {
bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11);
}
static ox::Error loadBgTileSheet(
ox::MemFS const&rom,
unsigned cbb,
ox::FileAddress const&tilesheetAddr,
ox::FileAddress const&paletteAddr) noexcept {
oxRequire(tsStat, rom.stat(tilesheetAddr));
oxRequire(ts, rom.directAccess(tilesheetAddr));
GbaTileMapTarget target;
target.pal.palette = MEM_BG_PALETTE;
target.cbbData = &g_cbbData[cbb];
target.tileMap = MEM_BG_TILES[cbb].data();
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
// load external palette if available
if (paletteAddr) {
oxRequire(palStat, rom.stat(paletteAddr));
oxRequire(pal, rom.directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target.pal));
}
// update bpp of all bgs with the updated cbb
const auto bpp = g_cbbData[cbb].bpp;
teagba::iterateBgCtl([bpp, cbb](auto bgCtl) {
if (teagba::bgCbb(bgCtl) == cbb) {
teagba::bgSetBpp(bgCtl, bpp);
}
});
return {};
}
ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
ox::FileAddress const&tilesheetAddr,
ox::FileAddress const&paletteAddr) noexcept {
auto &rom = ctx.rom();
return loadBgTileSheet(rom, cbb, tilesheetAddr, paletteAddr);
}
ox::Error loadSpriteTileSheet(
Context &ctx,
ox::FileAddress const&tilesheetAddr,
ox::FileAddress const&paletteAddr) noexcept {
auto &rom = ctx.rom();
oxRequire(tsStat, ctx.rom().stat(tilesheetAddr));
oxRequire(ts, rom.directAccess(tilesheetAddr));
GbaTileMapTarget target;
target.pal.palette = MEM_SPRITE_PALETTE;
target.tileMap = MEM_SPRITE_TILES;
oxReturnError(ox::readMC(ts, static_cast<std::size_t>(tsStat.size), &target));
// load external palette if available
if (paletteAddr) {
oxRequire(palStat, ctx.rom().stat(paletteAddr));
oxRequire(pal, rom.directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target.pal));
}
return {};
}
ox::Error loadBgPalette(Context &ctx, unsigned, ox::FileAddress const&paletteAddr) noexcept {
auto &rom = ctx.rom();
GbaPaletteTarget target;
target.palette = MEM_BG_PALETTE;
oxRequire(palStat, ctx.rom().stat(paletteAddr));
oxRequire(pal, rom.directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target));
return {};
}
ox::Error loadSpritePalette(Context &ctx, unsigned cbb, ox::FileAddress const&paletteAddr) noexcept {
auto &rom = ctx.rom();
GbaPaletteTarget target;
target.palette = &MEM_SPRITE_PALETTE[cbb];
oxRequire(palStat, rom.stat(paletteAddr));
oxRequire(pal, rom.directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target));
return {};
}
ox::Error initConsole(Context &ctx) noexcept {
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
setBgStatus(ctx, 0b0001);
oxReturnError(loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr));
setBgCbb(ctx, 0, 0);
return {};
}
void puts(Context &ctx, int column, int row, ox::CRStringView str) noexcept {
const auto col = static_cast<unsigned>(column);
for (auto i = 0u; i < str.bytes(); i++) {
const auto c = charMap[static_cast<std::size_t>(str[i])];
setTile(ctx, 0, static_cast<int>(col + i), row, static_cast<uint8_t>(c));
}
}
void setTile(Context&, unsigned bgIdx, int column, int row, uint8_t tile) noexcept {
const auto tileIdx = static_cast<std::size_t>(row * GbaTileColumns + column);
MEM_BG_MAP[bgIdx][tileIdx] = tile;
}
// Do NOT use Context in the GBA version of this function.
void clearTileLayer(Context&, unsigned bgIdx) noexcept {
memset(MEM_BG_MAP[bgIdx].data(), 0, GbaTileRows * GbaTileColumns);
}
[[maybe_unused]]
void hideSprite(Context&, unsigned idx) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
teagba::addSpriteUpdate({
@@ -222,7 +193,6 @@ void hideSprite(Context&, unsigned idx) noexcept {
});
}
[[maybe_unused]]
void showSprite(Context&, unsigned idx) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
teagba::addSpriteUpdate({
@@ -249,4 +219,8 @@ void setSprite(Context&, uint_t idx, Sprite const&s) noexcept {
});
}
uint_t spriteCount(Context&) noexcept {
return 128;
}
}

View File

@@ -31,7 +31,7 @@ void panic(const char *file, int line, const char *panicMsg, ox::Error const&err
oxIgnoreError(initGfx(*ctx, {}));
oxIgnoreError(initConsole(*ctx));
setBgStatus(*ctx, 0, true);
clearTileLayer(*ctx, 0);
clearBg(*ctx, 0);
ox::BString<23> serr = "Error code: ";
serr += static_cast<int64_t>(err);
puts(*ctx, 32 + 1, 1, "SADNESS...");