[nostalgia/core] Add ability to set a BG's CBB

This commit is contained in:
2022-08-02 01:24:37 -05:00
parent c6ba893583
commit 35ae54b336
10 changed files with 247 additions and 147 deletions
+52 -57
View File
@@ -4,6 +4,7 @@
#include <ox/fs/fs.hpp>
#include <ox/mc/mc.hpp>
#include <ox/std/array.hpp>
#include <nostalgia/core/media.hpp>
#include <nostalgia/core/gfx.hpp>
@@ -12,9 +13,12 @@
#include "bios.hpp"
#include "gfx.hpp"
#include "irq.hpp"
#include "registers.hpp"
namespace nostalgia::core {
ox::Array<BgCbbData, 4> g_cbbData;
constexpr auto GbaTileColumns = 32;
constexpr auto GbaTileRows = 32;
@@ -31,7 +35,7 @@ struct GbaPaletteTarget {
struct GbaTileMapTarget {
static constexpr auto TypeName = CompactTileSheet::TypeName;
static constexpr auto TypeVersion = CompactTileSheet::TypeVersion;
volatile uint16_t *bgCtl = nullptr;
BgCbbData *cbbData = nullptr;
ox::FileAddress defaultPalette;
GbaPaletteTarget pal;
volatile uint16_t *tileMap = nullptr;
@@ -39,7 +43,7 @@ struct GbaTileMapTarget {
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> auto *t) noexcept {
io->template setTypeInfo<Palette>();
const auto colorHandler = [t](std::size_t i, Color16 *c) {
const auto colorHandler = [t](std::size_t i, const Color16 *c) {
t->palette[i] = *c;
return OxError(0);
};
@@ -48,20 +52,10 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> auto *t)
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t) noexcept {
io->template setTypeInfo<CompactTileSheet>();
uint8_t bpp;
oxReturnError(io->field("bpp", &bpp));
constexpr auto Bpp8 = 1 << 7;
if (t->bgCtl) {
*t->bgCtl = (28 << 8) | 1;
if (bpp == 4) {
*t->bgCtl = *t->bgCtl | ((*t->bgCtl | Bpp8) ^ Bpp8); // set to use 4 bits per pixel
} else {
*t->bgCtl = *t->bgCtl | Bpp8; // set to use 8 bits per pixel
}
}
oxReturnError(io->field("bpp", &t->cbbData->bpp));
oxReturnError(io->field("defaultPalette", &t->defaultPalette));
uint16_t intermediate = 0;
const auto handleTileMap = [t, &intermediate](std::size_t i, uint8_t *tile) {
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;
@@ -81,11 +75,14 @@ ox::Error initGfx(Context*) noexcept {
REG_DISPSTAT = REG_DISPSTAT | DispStat_irq_vblank;
// enable vblank interrupt
REG_IE = REG_IE | Int_vblank;
return OxError(0);
for (auto bgCtl = &REG_BG0CTL; bgCtl <= &REG_BG3CTL; bgCtl += 2) {
bgSetSbb(bgCtl, 28);
}
return {};
}
ox::Error shutdownGfx(Context*) noexcept {
return OxError(0);
return {};
}
void setWindowTitle(Context*, const char*) noexcept {
@@ -111,8 +108,8 @@ uint8_t bgStatus(Context*) noexcept {
}
void setBgStatus(Context*, uint32_t status) noexcept {
constexpr auto Bg0Status = 8;
REG_DISPCTL = (REG_DISPCTL & ~0b111100000000u) | status << Bg0Status;
constexpr auto BgStatus = 8;
REG_DISPCTL = (REG_DISPCTL & ~0b111100000000u) | status << BgStatus;
}
bool bgStatus(Context*, unsigned bg) noexcept {
@@ -125,23 +122,6 @@ void setBgStatus(Context*, unsigned bg, bool status) noexcept {
REG_DISPCTL = REG_DISPCTL | ((REG_DISPCTL & ~mask) | mask);
}
[[nodiscard]]
constexpr volatile uint16_t &bgCtl(int bg) noexcept {
switch (bg) {
case 0:
return REG_BG0CTL;
case 1:
return REG_BG1CTL;
case 2:
return REG_BG2CTL;
case 3:
return REG_BG3CTL;
default:
oxPanic(OxError(1), "Looking up non-existent register");
return REG_BG0CTL;
}
}
// Do NOT rely on Context in the GBA version of this function.
ox::Error initConsole(Context *ctx) noexcept {
constexpr auto TilesheetAddr = "/TileSheets/Charset.ng";
@@ -154,19 +134,28 @@ ox::Error initConsole(Context *ctx) noexcept {
auto romFs = new (ox_alloca(sizeof(ox::FileSystem32))) ox::FileSystem32(fs);
new (&ctx->rom) ox::UniquePtr<ox::FileSystem>(romFs);
}
return loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr);
oxReturnError(loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr));
setBgCbb(ctx, 0, 0);
return {};
}
void setBgCbb(Context*, unsigned bgIdx, unsigned cbb) noexcept {
auto &bgCtl = regBgCtl(bgIdx);
const auto &cbbData = g_cbbData[cbb];
bgSetBpp(&bgCtl, cbbData.bpp);
bgSetCbb(&bgCtl, cbb);
}
ox::Error loadBgTileSheet(Context *ctx,
int section,
unsigned cbb,
const ox::FileAddress &tilesheetAddr,
const ox::FileAddress &paletteAddr) noexcept {
oxRequire(tsStat, ctx->rom->stat(tilesheetAddr));
oxRequire(ts, ctx->rom->directAccess(tilesheetAddr));
GbaTileMapTarget target;
target.pal.palette = &MEM_BG_PALETTE[section];
target.bgCtl = &bgCtl(section);
target.tileMap = &reinterpret_cast<uint16_t*>(MEM_BG_TILES)[section * 512];
target.pal.palette = MEM_BG_PALETTE;
target.cbbData = &g_cbbData[cbb];
target.tileMap = MEM_BG_TILES[cbb].data();
oxReturnError(ox::readMC(ts, tsStat.size, &target));
// load external palette if available
if (paletteAddr) {
@@ -174,20 +163,25 @@ ox::Error loadBgTileSheet(Context *ctx,
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, palStat.size, &target.pal));
}
return OxError(0);
// update bpp of all bgs with the updated cbb
const auto bpp = g_cbbData[cbb].bpp;
iterateBgCtl([bpp, cbb](auto bgCtl) {
if (bgCbb(bgCtl) == cbb) {
bgSetBpp(bgCtl, bpp);
}
});
return {};
}
ox::Error loadSpriteTileSheet(Context *ctx,
int section,
unsigned cbb,
const ox::FileAddress &tilesheetAddr,
const ox::FileAddress &paletteAddr) noexcept {
oxRequire(tsStat, ctx->rom->stat(tilesheetAddr));
oxRequire(ts, ctx->rom->directAccess(tilesheetAddr));
GbaTileMapTarget target;
target.pal.palette = &MEM_SPRITE_PALETTE[section];
// Is this needed? Should this be written to an equivalent sprite value?
// target.bgCtl = &bgCtl(section);
target.tileMap = &reinterpret_cast<uint16_t*>(MEM_SPRITE_TILES)[section * 512];
target.pal.palette = &MEM_SPRITE_PALETTE[cbb];
target.tileMap = &reinterpret_cast<uint16_t*>(MEM_SPRITE_TILES)[cbb * 512];
oxReturnError(ox::readMC(ts, tsStat.size, &target));
// load external palette if available
if (paletteAddr) {
@@ -195,25 +189,25 @@ ox::Error loadSpriteTileSheet(Context *ctx,
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, palStat.size, &target.pal));
}
return OxError(0);
return {};
}
ox::Error loadBgPalette(Context *ctx, int section, const ox::FileAddress &paletteAddr) noexcept {
ox::Error loadBgPalette(Context *ctx, unsigned, const ox::FileAddress &paletteAddr) noexcept {
GbaPaletteTarget target;
target.palette = &MEM_BG_PALETTE[section];
target.palette = MEM_BG_PALETTE;
oxRequire(palStat, ctx->rom->stat(paletteAddr));
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, palStat.size, &target));
return OxError(0);
return {};
}
ox::Error loadSpritePalette(Context *ctx, int section, const ox::FileAddress &paletteAddr) noexcept {
ox::Error loadSpritePalette(Context *ctx, unsigned cbb, const ox::FileAddress &paletteAddr) noexcept {
GbaPaletteTarget target;
target.palette = &MEM_SPRITE_PALETTE[section];
target.palette = &MEM_SPRITE_PALETTE[cbb];
oxRequire(palStat, ctx->rom->stat(paletteAddr));
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, palStat.size, &target));
return OxError(0);
return {};
}
// Do NOT use Context in the GBA version of this function.
@@ -223,13 +217,14 @@ void puts(Context *ctx, int column, int row, const char *str) noexcept {
}
}
void setTile(Context*, int layer, int column, int row, uint8_t tile) noexcept {
MEM_BG_MAP[layer][row * GbaTileColumns + column] = tile;
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*, int layer) noexcept {
memset(&MEM_BG_MAP[layer], 0, GbaTileRows * GbaTileColumns);
void clearTileLayer(Context*, unsigned bgIdx) noexcept {
memset(MEM_BG_MAP[bgIdx].data(), 0, GbaTileRows * GbaTileColumns);
}
[[maybe_unused]]