From 35ae54b33688c72382d107810c77e0349736351a Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Tue, 2 Aug 2022 01:24:37 -0500 Subject: [PATCH] [nostalgia/core] Add ability to set a BG's CBB --- src/nostalgia/core/context.hpp | 11 ++- src/nostalgia/core/gba/addresses.hpp | 101 +++++++++++-------- src/nostalgia/core/gba/gfx.cpp | 109 ++++++++++----------- src/nostalgia/core/gba/gfx.hpp | 2 +- src/nostalgia/core/gba/irq.arm.cpp | 4 +- src/nostalgia/core/gba/registers.hpp | 70 +++++++++++++ src/nostalgia/core/gfx.hpp | 10 +- src/nostalgia/core/userland/gfx.cpp | 7 +- src/nostalgia/core/userland/gfx.hpp | 2 +- src/nostalgia/core/userland/gfx_opengl.cpp | 78 ++++++++------- 10 files changed, 247 insertions(+), 147 deletions(-) create mode 100644 src/nostalgia/core/gba/registers.hpp diff --git a/src/nostalgia/core/context.hpp b/src/nostalgia/core/context.hpp index a41e5b99..550fb5db 100644 --- a/src/nostalgia/core/context.hpp +++ b/src/nostalgia/core/context.hpp @@ -38,6 +38,10 @@ class ClipboardObject: public BaseClipboardObject { class Drawer; +struct BgCbbData { + unsigned bpp = 4; +}; + // User Input Output class Context { friend constexpr void setApplicationData(Context *ctx, void *applicationData) noexcept; @@ -51,7 +55,7 @@ class Context { friend int getScreenWidth(Context *ctx) noexcept; friend ox::Error initGfx(Context *ctx) noexcept; friend ox::Error loadBgTileSheet(Context *ctx, - int section, + unsigned cbb, const ox::FileAddress &tilesheetPath, const ox::FileAddress &palettePath) noexcept; friend ox::Error run(Context *ctx) noexcept; @@ -60,16 +64,17 @@ class Context { friend ox::String getClipboardText(Context *ctx) noexcept; friend uint64_t ticksMs(Context *ctx) noexcept; friend uint8_t bgStatus(Context *ctx) noexcept; - friend void clearTileLayer(Context *ctx, int layer) noexcept; + friend void clearTileLayer(Context *ctx, unsigned bgIdx) noexcept; friend void draw(Context *ctx) noexcept; friend void focusWindow(Context *ctx) noexcept; + friend void setBgCbb(Context *ctx, unsigned bgIdx, unsigned cbb) noexcept; friend void setBgStatus(Context *ctx, uint32_t status) noexcept; friend void setBgStatus(Context *ctx, unsigned bg, bool status) noexcept; friend void setClipboardText(Context *ctx, const ox::String &text) noexcept; friend void setUpdateHandler(Context *ctx, UpdateHandler h) noexcept; friend constexpr void setKeyEventHandler(Context *ctx, KeyEventHandler h) noexcept; friend constexpr KeyEventHandler keyEventHandler(Context *ctx) noexcept; - friend void setTile(Context *ctx, int layer, int column, int row, uint8_t tile) noexcept; + friend void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept; friend void setWindowTitle(Context *ctx, const char *title) noexcept; public: diff --git a/src/nostalgia/core/gba/addresses.hpp b/src/nostalgia/core/gba/addresses.hpp index 3be1cad7..02d66d2c 100644 --- a/src/nostalgia/core/gba/addresses.hpp +++ b/src/nostalgia/core/gba/addresses.hpp @@ -4,87 +4,104 @@ #pragma once +#include #include ///////////////////////////////////////////////////////////////// // Interrupt Handler using interrupt_handler = void (*)(); -#define REG_ISR *reinterpret_cast(0x03007FFC) -#define REG_IE *reinterpret_cast(0x04000200) -#define REG_IF *reinterpret_cast(0x04000202) -#define REG_IME *reinterpret_cast(0x04000208) +#define REG_ISR *reinterpret_cast(0x0300'7FFC) +#define REG_IE *reinterpret_cast(0x0400'0200) +#define REG_IF *reinterpret_cast(0x0400'0202) +#define REG_IME *reinterpret_cast(0x0400'0208) ///////////////////////////////////////////////////////////////// // Display Registers -#define REG_DISPCTL *reinterpret_cast(0x04000000) -#define REG_DISPSTAT *reinterpret_cast(0x04000004) -#define REG_VCOUNT *reinterpret_cast(0x04000006) +#define REG_DISPCTL *reinterpret_cast(0x0400'0000) +#define REG_DISPSTAT *reinterpret_cast(0x0400'0004) +#define REG_VCOUNT *reinterpret_cast(0x0400'0006) ///////////////////////////////////////////////////////////////// // Timers -#define REG_TIMER0 *reinterpret_cast(0x04000100) -#define REG_TIMER0CTL *reinterpret_cast(0x04000102) +#define REG_TIMER0 *reinterpret_cast(0x0400'0100) +#define REG_TIMER0CTL *reinterpret_cast(0x0400'0102) -#define REG_TIMER1 *reinterpret_cast(0x04000104) -#define REG_TIMER1CTL *reinterpret_cast(0x04000106) +#define REG_TIMER1 *reinterpret_cast(0x0400'0104) +#define REG_TIMER1CTL *reinterpret_cast(0x0400'0106) -#define REG_TIMER2 *reinterpret_cast(0x04000108) -#define REG_TIMER2CTL *reinterpret_cast(0x0400010a) +#define REG_TIMER2 *reinterpret_cast(0x0400'0108) +#define REG_TIMER2CTL *reinterpret_cast(0x0400'010a) -#define REG_TIMER3 *reinterpret_cast(0x0400010c) -#define REG_TIMER3CTL *reinterpret_cast(0x0400010e) +#define REG_TIMER3 *reinterpret_cast(0x0400'010c) +#define REG_TIMER3CTL *reinterpret_cast(0x0400'010e) ///////////////////////////////////////////////////////////////// // background registers // background control registers -#define REG_BG0CTL *reinterpret_cast(0x04000008) -#define REG_BG1CTL *reinterpret_cast(0x0400000a) -#define REG_BG2CTL *reinterpret_cast(0x0400000c) -#define REG_BG3CTL *reinterpret_cast(0x0400000e) +using BgCtl = uint16_t; +#define REG_BG0CTL *reinterpret_cast(0x0400'0008) +#define REG_BG1CTL *reinterpret_cast(0x0400'000a) +#define REG_BG2CTL *reinterpret_cast(0x0400'000c) +#define REG_BG3CTL *reinterpret_cast(0x0400'000e) + +[[nodiscard]] +inline auto ®BgCtl(auto bgIdx) noexcept { + return *reinterpret_cast(0x0400'0008 + 2 * bgIdx); +} // background horizontal scrolling registers -#define REG_BG0HOFS *reinterpret_cast(0x04000010) -#define REG_BG1HOFS *reinterpret_cast(0x04000014) -#define REG_BG2HOFS *reinterpret_cast(0x04000018) -#define REG_BG3HOFS *reinterpret_cast(0x0400001c) +#define REG_BG0HOFS *reinterpret_cast(0x0400'0010) +#define REG_BG1HOFS *reinterpret_cast(0x0400'0014) +#define REG_BG2HOFS *reinterpret_cast(0x0400'0018) +#define REG_BG3HOFS *reinterpret_cast(0x0400'001c) + +[[nodiscard]] +inline volatile auto ®BgHofs(auto bgIdx) noexcept { + return *reinterpret_cast(0x0400'0010 + 4 * bgIdx); +} // background vertical scrolling registers -#define REG_BG0VOFS *reinterpret_cast(0x04000012) -#define REG_BG1VOFS *reinterpret_cast(0x04000016) -#define REG_BG2VOFS *reinterpret_cast(0x0400001a) -#define REG_BG3VOFS *reinterpret_cast(0x0400001e) +#define REG_BG0VOFS *reinterpret_cast(0x0400'0012) +#define REG_BG1VOFS *reinterpret_cast(0x0400'0016) +#define REG_BG2VOFS *reinterpret_cast(0x0400'001a) +#define REG_BG3VOFS *reinterpret_cast(0x0400'001e) + +[[nodiscard]] +inline volatile auto ®BgVofs(auto bgIdx) noexcept { + return *reinterpret_cast(0x0400'0012 + 4 * bgIdx); +} ///////////////////////////////////////////////////////////////// // User Input -#define REG_GAMEPAD *reinterpret_cast(0x04000130) +#define REG_GAMEPAD *reinterpret_cast(0x0400'0130) ///////////////////////////////////////////////////////////////// // Memory Addresses -#define MEM_EWRAM_BEGIN reinterpret_cast(0x02000000) -#define MEM_EWRAM_END reinterpret_cast(0x0203FFFF) +#define MEM_EWRAM_BEGIN reinterpret_cast(0x0200'0000) +#define MEM_EWRAM_END reinterpret_cast(0x0203'FFFF) -#define MEM_IWRAM_BEGIN reinterpret_cast(0x03000000) -#define MEM_IWRAM_END reinterpret_cast(0x03007FFF) +#define MEM_IWRAM_BEGIN reinterpret_cast(0x0300'0000) +#define MEM_IWRAM_END reinterpret_cast(0x0300'7FFF) -#define REG_BLNDCTL *reinterpret_cast(0x04000050) +#define REG_BLNDCTL *reinterpret_cast(0x0400'0050) -#define MEM_BG_PALETTE reinterpret_cast(0x05000000) -#define MEM_SPRITE_PALETTE reinterpret_cast(0x05000200) +#define MEM_BG_PALETTE reinterpret_cast(0x0500'0000) +#define MEM_SPRITE_PALETTE reinterpret_cast(0x0500'0200) -typedef uint16_t BgMapTile[1024]; -#define MEM_BG_TILES reinterpret_cast(0x06000000) -#define MEM_BG_MAP reinterpret_cast(0x0600e000) +using BgMapTile = ox::Array; +#define MEM_BG_TILES reinterpret_cast(0x0600'0000) +#define MEM_BG_MAP reinterpret_cast(0x0600'e000) -#define MEM_SPRITE_TILES reinterpret_cast(0x06010000) -#define MEM_OAM reinterpret_cast(0x07000000) +#define MEM_SPRITE_TILES reinterpret_cast(0x0601'0000) +#define MEM_OAM reinterpret_cast(0x0700'0000) -#define MEM_ROM reinterpret_cast(0x08000000) +#define MEM_ROM reinterpret_cast(0x0800'0000) -#define MEM_SRAM reinterpret_cast(0x0e000000) +#define MEM_SRAM reinterpret_cast(0x0e00'0000) #define MEM_SRAM_SIZE 65535 diff --git a/src/nostalgia/core/gba/gfx.cpp b/src/nostalgia/core/gba/gfx.cpp index ea6aa51d..2561e5a2 100644 --- a/src/nostalgia/core/gba/gfx.cpp +++ b/src/nostalgia/core/gba/gfx.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -12,9 +13,12 @@ #include "bios.hpp" #include "gfx.hpp" #include "irq.hpp" +#include "registers.hpp" namespace nostalgia::core { +ox::Array 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 auto *t) noexcept { io->template setTypeInfo(); - 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 auto *t) constexpr ox::Error model(auto *io, ox::CommonPtrWith auto *t) noexcept { io->template setTypeInfo(); - 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(*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 = ®_BG0CTL; bgCtl <= ®_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(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(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(MEM_SPRITE_TILES)[section * 512]; + target.pal.palette = &MEM_SPRITE_PALETTE[cbb]; + target.tileMap = &reinterpret_cast(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(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]] diff --git a/src/nostalgia/core/gba/gfx.hpp b/src/nostalgia/core/gba/gfx.hpp index cae06621..54b9ca08 100644 --- a/src/nostalgia/core/gba/gfx.hpp +++ b/src/nostalgia/core/gba/gfx.hpp @@ -38,6 +38,6 @@ struct OX_ALIGN8 GbaSpriteAttrUpdate { }; extern volatile uint16_t g_spriteUpdates; -extern GbaSpriteAttrUpdate g_spriteBuffer[config::GbaSpriteBufferLen]; +extern ox::Array g_spriteBuffer; } diff --git a/src/nostalgia/core/gba/irq.arm.cpp b/src/nostalgia/core/gba/irq.arm.cpp index 27485c75..57e937a5 100644 --- a/src/nostalgia/core/gba/irq.arm.cpp +++ b/src/nostalgia/core/gba/irq.arm.cpp @@ -5,8 +5,6 @@ // NOTE: this file is compiled as ARM and not THUMB, so don't but too much in // here -#include - #include "addresses.hpp" #include "core.hpp" #include "gfx.hpp" @@ -15,7 +13,7 @@ namespace nostalgia::core { volatile uint16_t g_spriteUpdates = 0; -GbaSpriteAttrUpdate g_spriteBuffer[config::GbaSpriteBufferLen]; +ox::Array g_spriteBuffer; volatile gba_timer_t g_timerMs = 0; diff --git a/src/nostalgia/core/gba/registers.hpp b/src/nostalgia/core/gba/registers.hpp new file mode 100644 index 00000000..0fb30426 --- /dev/null +++ b/src/nostalgia/core/gba/registers.hpp @@ -0,0 +1,70 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include "addresses.hpp" + +namespace nostalgia::core { + +inline auto bgSetSbb(volatile BgCtl *bgCtl, unsigned sbb) noexcept { + *bgCtl = (*bgCtl & ~0b11111'0000'0000u) | (sbb << 8); +} + +[[nodiscard]] +constexpr unsigned bgPri(BgCtl bgCtl) noexcept { + return bgCtl & 1; +} + +[[nodiscard]] +inline auto bgPri(const volatile BgCtl *bgCtl) noexcept { + return bgPri(*bgCtl); +} + +inline auto bgSetPri(volatile BgCtl *bgCtl, unsigned pri) noexcept { + pri = pri & 0b1; + *bgCtl = (*bgCtl & ~0b1u) | (pri << 0); +} + +[[nodiscard]] +constexpr unsigned bgBpp(BgCtl bgCtl) noexcept { + return ((bgCtl >> 7) & 1) ? 8 : 4; +} + +[[nodiscard]] +inline auto bgBpp(const volatile BgCtl *bgCtl) noexcept { + return bgBpp(*bgCtl); +} + +inline auto bgSetBpp(volatile BgCtl *bgCtl, unsigned bpp) noexcept { + constexpr auto Bpp8 = 1 << 7; + if (bpp == 4) { + *bgCtl = *bgCtl | ((*bgCtl | Bpp8) ^ Bpp8); // set to use 4 bits per pixel + } else { + *bgCtl = *bgCtl | Bpp8; // set to use 8 bits per pixel + } +} + +[[nodiscard]] +constexpr auto bgCbb(BgCtl bgCtl) noexcept { + return (bgCtl >> 2) & 0b11u; +} + +[[nodiscard]] +inline auto bgCbb(const volatile BgCtl *bgCtl) noexcept { + return bgCbb(*bgCtl); +} + +inline auto bgSetCbb(volatile BgCtl *bgCtl, unsigned cbb) noexcept { + cbb = cbb & 0b11; + *bgCtl = (*bgCtl & ~0b1100u) | (cbb << 2); +} + +constexpr void iterateBgCtl(auto cb) noexcept { + for (auto bgCtl = ®_BG0CTL; bgCtl <= ®_BG3CTL; bgCtl += 2) { + cb(bgCtl); + } +} + +} diff --git a/src/nostalgia/core/gfx.hpp b/src/nostalgia/core/gfx.hpp index 5c0f9359..5fb9d2a9 100644 --- a/src/nostalgia/core/gfx.hpp +++ b/src/nostalgia/core/gfx.hpp @@ -497,21 +497,23 @@ void setBgStatus(Context *ctx, unsigned bg, bool status) noexcept; ox::Error initConsole(Context *ctx) noexcept; +void setBgCbb(Context *ctx, unsigned bgIdx, unsigned cbb) noexcept; + /** * @param section describes which section of the selected TileSheetSpace to use (e.g. MEM_PALLETE_BG[section]) */ -ox::Error loadBgTileSheet(Context *ctx, int section, const ox::FileAddress &tilesheet, const ox::FileAddress &palette = nullptr) noexcept; +ox::Error loadBgTileSheet(Context *ctx, unsigned cbb, const ox::FileAddress &tilesheet, const ox::FileAddress &palette = nullptr) noexcept; ox::Error loadSpriteTileSheet(Context *ctx, - int section, + unsigned section, const ox::FileAddress &tilesheetAddr, const ox::FileAddress &paletteAddr) noexcept; void puts(Context *ctx, int column, int row, const char *str) noexcept; -void setTile(Context *ctx, int layer, int column, int row, uint8_t tile) noexcept; +void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept; -void clearTileLayer(Context *ctx, int layer) noexcept; +void clearTileLayer(Context *ctx, unsigned bgIdx) noexcept; void hideSprite(Context *ctx, unsigned) noexcept; diff --git a/src/nostalgia/core/userland/gfx.cpp b/src/nostalgia/core/userland/gfx.cpp index 9dada4c5..e75d87dd 100644 --- a/src/nostalgia/core/userland/gfx.cpp +++ b/src/nostalgia/core/userland/gfx.cpp @@ -13,18 +13,19 @@ ox::Error initConsole(Context *ctx) noexcept { constexpr auto TilesheetAddr = "/TileSheets/Charset.ng"; constexpr auto PaletteAddr = "/Palettes/Charset.npal"; setBgStatus(ctx, 0b0001); + setBgCbb(ctx, 0, 0); return loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr); } ox::Error loadSpriteTileSheet(Context*, - int, + unsigned, const ox::FileAddress&, const ox::FileAddress&) noexcept { return OxError(0); } ox::Error loadBgTileSheet(Context *ctx, - int section, + unsigned cbb, const ox::FileAddress &tilesheetPath, const ox::FileAddress &palettePath) noexcept { oxRequire(tilesheet, readObj(ctx, tilesheetPath)); @@ -46,7 +47,7 @@ ox::Error loadBgTileSheet(Context *ctx, pixels[i * 2 + 1] = toColor32(palette->colors[tilesheet->pixels[i] >> 4]); } } - renderer::loadBgTexture(ctx->rendererData(), section, pixels.data(), width, height); + renderer::loadBgTexture(ctx->rendererData(), cbb, pixels.data(), width, height); return OxError(0); } diff --git a/src/nostalgia/core/userland/gfx.hpp b/src/nostalgia/core/userland/gfx.hpp index 8a30f99f..6e3831c1 100644 --- a/src/nostalgia/core/userland/gfx.hpp +++ b/src/nostalgia/core/userland/gfx.hpp @@ -14,6 +14,6 @@ ox::Error init(Context *ctx, void **rendererData) noexcept; void shutdown(Context *ctx, void *rendererData) noexcept; -void loadBgTexture(void *rendererData, int section, void *pixels, int w, int h) noexcept; +void loadBgTexture(void *rendererData, unsigned cbb, void *pixels, int w, int h) noexcept; } diff --git a/src/nostalgia/core/userland/gfx_opengl.cpp b/src/nostalgia/core/userland/gfx_opengl.cpp index b9188baf..9d1853c5 100644 --- a/src/nostalgia/core/userland/gfx_opengl.cpp +++ b/src/nostalgia/core/userland/gfx_opengl.cpp @@ -22,25 +22,30 @@ namespace renderer { constexpr auto TileRows = 128; constexpr auto TileColumns = 128; constexpr auto TileCount = TileRows * TileColumns; -constexpr auto BgVertexVboRows = 4; -constexpr auto BgVertexVboRowLength = 4; -constexpr auto BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength; -constexpr auto BgVertexEboLength = 6; +constexpr unsigned BgVertexVboRows = 4; +constexpr unsigned BgVertexVboRowLength = 4; +constexpr unsigned BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength; +constexpr unsigned BgVertexEboLength = 6; -struct Background: public glutils::BufferSet { - bool enabled = false; +struct CBB: public glutils::BufferSet { bool updated = false; - Background() noexcept { + CBB() noexcept { vertices.resize(TileCount * BgVertexVboLength); elements.resize(TileCount * BgVertexEboLength); } }; +struct Background { + bool enabled = false; + unsigned cbbIdx = 0; +}; + struct GlImplData { glutils::GLProgram bgShader; int64_t prevFpsCheckTime = 0; uint64_t draws = 0; + ox::Array cbbs; ox::Array backgrounds; }; @@ -80,18 +85,18 @@ setTileBufferObject(Context *ctx, unsigned vi, float x, float y, int textureRow, y *= -ymod; x -= 1.0f; y += 1.0f - ymod; - const float vertices[BgVertexVboLength] = { + const ox::Array vertices { x, y, 0, static_cast(textureRow + 1), // bottom left x + xmod, y, 1, static_cast(textureRow + 1), // bottom right x + xmod, y + ymod, 1, static_cast(textureRow + 0), // top right x, y + ymod, 0, static_cast(textureRow + 0), // top left }; - memcpy(vbo, vertices, sizeof(vertices)); - const GLuint elms[BgVertexEboLength] = { + memcpy(vbo, vertices.data(), sizeof(vertices)); + const ox::Array elms { vi + 0, vi + 1, vi + 2, vi + 2, vi + 3, vi + 0, }; - memcpy(ebo, elms, sizeof(elms)); + memcpy(ebo, elms.data(), sizeof(elms)); } static void initBackgroundBufferObjects(Context *ctx, glutils::BufferSet *bg) noexcept { @@ -157,16 +162,14 @@ static void tickFps(GlImplData *id) noexcept { } } -static void drawBackground(Background *bg) noexcept { - if (bg->enabled) { - glBindVertexArray(bg->vao); - if (bg->updated) { - bg->updated = false; - glutils::sendVbo(*bg); - } - glBindTexture(GL_TEXTURE_2D, bg->tex); - glDrawElements(GL_TRIANGLES, static_cast(bg->elements.size()), GL_UNSIGNED_INT, nullptr); +static void drawBackground(CBB *cbb) noexcept { + glBindVertexArray(cbb->vao); + if (cbb->updated) { + cbb->updated = false; + glutils::sendVbo(*cbb); } + glBindTexture(GL_TEXTURE_2D, cbb->tex); + glDrawElements(GL_TRIANGLES, static_cast(cbb->elements.size()), GL_UNSIGNED_INT, nullptr); } static void drawBackgrounds(GlImplData *id) noexcept { @@ -174,8 +177,11 @@ static void drawBackgrounds(GlImplData *id) noexcept { glUseProgram(id->bgShader); const auto uniformTileHeight = static_cast(glGetUniformLocation(id->bgShader, "vTileHeight")); for (auto &bg : id->backgrounds) { - glUniform1f(uniformTileHeight, 1.0f / static_cast(bg.tex.height / 8)); - drawBackground(&bg); + if (bg.enabled) { + auto &cbb = id->cbbs[bg.cbbIdx]; + glUniform1f(uniformTileHeight, 1.0f / static_cast(cbb.tex.height / 8)); + drawBackground(&cbb); + } } } @@ -186,7 +192,7 @@ ox::Error init(Context *ctx, void **rendererData) noexcept { const auto id = new GlImplData; *rendererData = id; id->bgShader = std::move(bgShader); - for (auto &bg : id->backgrounds) { + for (auto &bg : id->cbbs) { initBackgroundBufferset(ctx, id->bgShader, &bg); } ImGui_ImplOpenGL3_Init(glutils::GlslVersion); @@ -198,19 +204,25 @@ void shutdown(Context*, void *rendererData) noexcept { ox::safeDelete(id); } -void loadBgTexture(void *rendererData, int section, void *pixels, int w, int h) noexcept { - oxTracef("nostalgia::core::gfx::gl", "loadBgTexture: { section: {}, w: {}, h: {} }", section, w, h); +void loadBgTexture(void *rendererData, unsigned cbbIdx, void *pixels, int w, int h) noexcept { + oxTracef("nostalgia::core::gfx::gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbbIdx, w, h); const auto id = static_cast(rendererData); - auto &tex = id->backgrounds[static_cast(section)].tex; + auto &tex = id->cbbs[cbbIdx].tex; tex = loadTexture(w, h, pixels); } } +void setBgCbb(Context *ctx, unsigned bgIdx, unsigned cbbIdx) noexcept { + const auto id = ctx->rendererData(); + auto &bg = id->backgrounds[bgIdx]; + bg.cbbIdx = cbbIdx; +} + uint8_t bgStatus(Context *ctx) noexcept { const auto id = ctx->rendererData(); uint8_t out = 0; - for (unsigned i = 0; i < id->backgrounds.size(); ++i) { + for (unsigned i = 0; i < id->cbbs.size(); ++i) { out |= id->backgrounds[i].enabled << i; } return out; @@ -218,7 +230,7 @@ uint8_t bgStatus(Context *ctx) noexcept { void setBgStatus(Context *ctx, uint32_t status) noexcept { const auto id = ctx->rendererData(); - for (unsigned i = 0; i < id->backgrounds.size(); ++i) { + for (unsigned i = 0; i < id->cbbs.size(); ++i) { id->backgrounds[i].enabled = (status >> i) & 1; } } @@ -256,9 +268,9 @@ void draw(Context *ctx) noexcept { } } -void clearTileLayer(Context *ctx, int layer) noexcept { +void clearTileLayer(Context *ctx, unsigned bgIdx) noexcept { const auto id = ctx->rendererData(); - auto &bg = id->backgrounds[static_cast(layer)]; + auto &bg = id->cbbs[static_cast(bgIdx)]; initBackgroundBufferObjects(ctx, &bg); bg.updated = true; } @@ -276,13 +288,13 @@ void setSprite(Context*, unsigned) noexcept { } -void setTile(Context *ctx, int layer, int column, int row, uint8_t tile) noexcept { +void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept { const auto id = ctx->rendererData(); - const auto z = static_cast(layer); + const auto z = static_cast(bgIdx); const auto y = static_cast(row); const auto x = static_cast(column); const auto i = renderer::bgVertexRow(x, y); - auto &bg = id->backgrounds[z]; + auto &bg = id->cbbs[z]; auto vbo = &bg.vertices[i * renderer::BgVertexVboLength]; auto ebo = &bg.elements[i * renderer::BgVertexEboLength]; renderer::setTileBufferObject(ctx, i * renderer::BgVertexVboRows,