[nostalgia/core] Add ability to set a BG's CBB
This commit is contained in:
parent
c6ba893583
commit
35ae54b336
@ -38,6 +38,10 @@ class ClipboardObject: public BaseClipboardObject {
|
|||||||
|
|
||||||
class Drawer;
|
class Drawer;
|
||||||
|
|
||||||
|
struct BgCbbData {
|
||||||
|
unsigned bpp = 4;
|
||||||
|
};
|
||||||
|
|
||||||
// User Input Output
|
// User Input Output
|
||||||
class Context {
|
class Context {
|
||||||
friend constexpr void setApplicationData(Context *ctx, void *applicationData) noexcept;
|
friend constexpr void setApplicationData(Context *ctx, void *applicationData) noexcept;
|
||||||
@ -51,7 +55,7 @@ class Context {
|
|||||||
friend int getScreenWidth(Context *ctx) noexcept;
|
friend int getScreenWidth(Context *ctx) noexcept;
|
||||||
friend ox::Error initGfx(Context *ctx) noexcept;
|
friend ox::Error initGfx(Context *ctx) noexcept;
|
||||||
friend ox::Error loadBgTileSheet(Context *ctx,
|
friend ox::Error loadBgTileSheet(Context *ctx,
|
||||||
int section,
|
unsigned cbb,
|
||||||
const ox::FileAddress &tilesheetPath,
|
const ox::FileAddress &tilesheetPath,
|
||||||
const ox::FileAddress &palettePath) noexcept;
|
const ox::FileAddress &palettePath) noexcept;
|
||||||
friend ox::Error run(Context *ctx) noexcept;
|
friend ox::Error run(Context *ctx) noexcept;
|
||||||
@ -60,16 +64,17 @@ class Context {
|
|||||||
friend ox::String getClipboardText(Context *ctx) noexcept;
|
friend ox::String getClipboardText(Context *ctx) noexcept;
|
||||||
friend uint64_t ticksMs(Context *ctx) noexcept;
|
friend uint64_t ticksMs(Context *ctx) noexcept;
|
||||||
friend uint8_t bgStatus(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 draw(Context *ctx) noexcept;
|
||||||
friend void focusWindow(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, uint32_t status) noexcept;
|
||||||
friend void setBgStatus(Context *ctx, unsigned bg, bool status) noexcept;
|
friend void setBgStatus(Context *ctx, unsigned bg, bool status) noexcept;
|
||||||
friend void setClipboardText(Context *ctx, const ox::String &text) noexcept;
|
friend void setClipboardText(Context *ctx, const ox::String &text) noexcept;
|
||||||
friend void setUpdateHandler(Context *ctx, UpdateHandler h) noexcept;
|
friend void setUpdateHandler(Context *ctx, UpdateHandler h) noexcept;
|
||||||
friend constexpr void setKeyEventHandler(Context *ctx, KeyEventHandler h) noexcept;
|
friend constexpr void setKeyEventHandler(Context *ctx, KeyEventHandler h) noexcept;
|
||||||
friend constexpr KeyEventHandler keyEventHandler(Context *ctx) 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;
|
friend void setWindowTitle(Context *ctx, const char *title) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -4,87 +4,104 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <ox/std/array.hpp>
|
||||||
#include <ox/std/types.hpp>
|
#include <ox/std/types.hpp>
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
// Interrupt Handler
|
// Interrupt Handler
|
||||||
|
|
||||||
using interrupt_handler = void (*)();
|
using interrupt_handler = void (*)();
|
||||||
#define REG_ISR *reinterpret_cast<interrupt_handler*>(0x03007FFC)
|
#define REG_ISR *reinterpret_cast<interrupt_handler*>(0x0300'7FFC)
|
||||||
#define REG_IE *reinterpret_cast<volatile uint16_t*>(0x04000200)
|
#define REG_IE *reinterpret_cast<volatile uint16_t*>(0x0400'0200)
|
||||||
#define REG_IF *reinterpret_cast<volatile uint16_t*>(0x04000202)
|
#define REG_IF *reinterpret_cast<volatile uint16_t*>(0x0400'0202)
|
||||||
#define REG_IME *reinterpret_cast<volatile uint16_t*>(0x04000208)
|
#define REG_IME *reinterpret_cast<volatile uint16_t*>(0x0400'0208)
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
// Display Registers
|
// Display Registers
|
||||||
|
|
||||||
#define REG_DISPCTL *reinterpret_cast<volatile uint32_t*>(0x04000000)
|
#define REG_DISPCTL *reinterpret_cast<volatile uint32_t*>(0x0400'0000)
|
||||||
#define REG_DISPSTAT *reinterpret_cast<volatile uint32_t*>(0x04000004)
|
#define REG_DISPSTAT *reinterpret_cast<volatile uint32_t*>(0x0400'0004)
|
||||||
#define REG_VCOUNT *reinterpret_cast<volatile uint32_t*>(0x04000006)
|
#define REG_VCOUNT *reinterpret_cast<volatile uint32_t*>(0x0400'0006)
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
// Timers
|
// Timers
|
||||||
|
|
||||||
#define REG_TIMER0 *reinterpret_cast<volatile uint16_t*>(0x04000100)
|
#define REG_TIMER0 *reinterpret_cast<volatile uint16_t*>(0x0400'0100)
|
||||||
#define REG_TIMER0CTL *reinterpret_cast<volatile uint16_t*>(0x04000102)
|
#define REG_TIMER0CTL *reinterpret_cast<volatile uint16_t*>(0x0400'0102)
|
||||||
|
|
||||||
#define REG_TIMER1 *reinterpret_cast<volatile uint16_t*>(0x04000104)
|
#define REG_TIMER1 *reinterpret_cast<volatile uint16_t*>(0x0400'0104)
|
||||||
#define REG_TIMER1CTL *reinterpret_cast<volatile uint16_t*>(0x04000106)
|
#define REG_TIMER1CTL *reinterpret_cast<volatile uint16_t*>(0x0400'0106)
|
||||||
|
|
||||||
#define REG_TIMER2 *reinterpret_cast<volatile uint16_t*>(0x04000108)
|
#define REG_TIMER2 *reinterpret_cast<volatile uint16_t*>(0x0400'0108)
|
||||||
#define REG_TIMER2CTL *reinterpret_cast<volatile uint16_t*>(0x0400010a)
|
#define REG_TIMER2CTL *reinterpret_cast<volatile uint16_t*>(0x0400'010a)
|
||||||
|
|
||||||
#define REG_TIMER3 *reinterpret_cast<volatile uint16_t*>(0x0400010c)
|
#define REG_TIMER3 *reinterpret_cast<volatile uint16_t*>(0x0400'010c)
|
||||||
#define REG_TIMER3CTL *reinterpret_cast<volatile uint16_t*>(0x0400010e)
|
#define REG_TIMER3CTL *reinterpret_cast<volatile uint16_t*>(0x0400'010e)
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
// background registers
|
// background registers
|
||||||
|
|
||||||
// background control registers
|
// background control registers
|
||||||
#define REG_BG0CTL *reinterpret_cast<volatile uint16_t*>(0x04000008)
|
using BgCtl = uint16_t;
|
||||||
#define REG_BG1CTL *reinterpret_cast<volatile uint16_t*>(0x0400000a)
|
#define REG_BG0CTL *reinterpret_cast<volatile BgCtl*>(0x0400'0008)
|
||||||
#define REG_BG2CTL *reinterpret_cast<volatile uint16_t*>(0x0400000c)
|
#define REG_BG1CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000a)
|
||||||
#define REG_BG3CTL *reinterpret_cast<volatile uint16_t*>(0x0400000e)
|
#define REG_BG2CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000c)
|
||||||
|
#define REG_BG3CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000e)
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline auto ®BgCtl(auto bgIdx) noexcept {
|
||||||
|
return *reinterpret_cast<volatile BgCtl*>(0x0400'0008 + 2 * bgIdx);
|
||||||
|
}
|
||||||
|
|
||||||
// background horizontal scrolling registers
|
// background horizontal scrolling registers
|
||||||
#define REG_BG0HOFS *reinterpret_cast<volatile uint32_t*>(0x04000010)
|
#define REG_BG0HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0010)
|
||||||
#define REG_BG1HOFS *reinterpret_cast<volatile uint32_t*>(0x04000014)
|
#define REG_BG1HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0014)
|
||||||
#define REG_BG2HOFS *reinterpret_cast<volatile uint32_t*>(0x04000018)
|
#define REG_BG2HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0018)
|
||||||
#define REG_BG3HOFS *reinterpret_cast<volatile uint32_t*>(0x0400001c)
|
#define REG_BG3HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001c)
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline volatile auto ®BgHofs(auto bgIdx) noexcept {
|
||||||
|
return *reinterpret_cast<volatile uint32_t*>(0x0400'0010 + 4 * bgIdx);
|
||||||
|
}
|
||||||
|
|
||||||
// background vertical scrolling registers
|
// background vertical scrolling registers
|
||||||
#define REG_BG0VOFS *reinterpret_cast<volatile uint32_t*>(0x04000012)
|
#define REG_BG0VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0012)
|
||||||
#define REG_BG1VOFS *reinterpret_cast<volatile uint32_t*>(0x04000016)
|
#define REG_BG1VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0016)
|
||||||
#define REG_BG2VOFS *reinterpret_cast<volatile uint32_t*>(0x0400001a)
|
#define REG_BG2VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001a)
|
||||||
#define REG_BG3VOFS *reinterpret_cast<volatile uint32_t*>(0x0400001e)
|
#define REG_BG3VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001e)
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline volatile auto ®BgVofs(auto bgIdx) noexcept {
|
||||||
|
return *reinterpret_cast<volatile uint32_t*>(0x0400'0012 + 4 * bgIdx);
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
// User Input
|
// User Input
|
||||||
|
|
||||||
#define REG_GAMEPAD *reinterpret_cast<volatile uint16_t*>(0x04000130)
|
#define REG_GAMEPAD *reinterpret_cast<volatile uint16_t*>(0x0400'0130)
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
// Memory Addresses
|
// Memory Addresses
|
||||||
|
|
||||||
#define MEM_EWRAM_BEGIN reinterpret_cast<uint8_t*>(0x02000000)
|
#define MEM_EWRAM_BEGIN reinterpret_cast<uint8_t*>(0x0200'0000)
|
||||||
#define MEM_EWRAM_END reinterpret_cast<uint8_t*>(0x0203FFFF)
|
#define MEM_EWRAM_END reinterpret_cast<uint8_t*>(0x0203'FFFF)
|
||||||
|
|
||||||
#define MEM_IWRAM_BEGIN reinterpret_cast<uint8_t*>(0x03000000)
|
#define MEM_IWRAM_BEGIN reinterpret_cast<uint8_t*>(0x0300'0000)
|
||||||
#define MEM_IWRAM_END reinterpret_cast<uint8_t*>(0x03007FFF)
|
#define MEM_IWRAM_END reinterpret_cast<uint8_t*>(0x0300'7FFF)
|
||||||
|
|
||||||
#define REG_BLNDCTL *reinterpret_cast<uint16_t*>(0x04000050)
|
#define REG_BLNDCTL *reinterpret_cast<uint16_t*>(0x0400'0050)
|
||||||
|
|
||||||
#define MEM_BG_PALETTE reinterpret_cast<uint16_t*>(0x05000000)
|
#define MEM_BG_PALETTE reinterpret_cast<uint16_t*>(0x0500'0000)
|
||||||
#define MEM_SPRITE_PALETTE reinterpret_cast<uint16_t*>(0x05000200)
|
#define MEM_SPRITE_PALETTE reinterpret_cast<uint16_t*>(0x0500'0200)
|
||||||
|
|
||||||
typedef uint16_t BgMapTile[1024];
|
using BgMapTile = ox::Array<uint16_t, 8192>;
|
||||||
#define MEM_BG_TILES reinterpret_cast<BgMapTile*>(0x06000000)
|
#define MEM_BG_TILES reinterpret_cast<BgMapTile*>(0x0600'0000)
|
||||||
#define MEM_BG_MAP reinterpret_cast<BgMapTile*>(0x0600e000)
|
#define MEM_BG_MAP reinterpret_cast<BgMapTile*>(0x0600'e000)
|
||||||
|
|
||||||
#define MEM_SPRITE_TILES reinterpret_cast<uint16_t*>(0x06010000)
|
#define MEM_SPRITE_TILES reinterpret_cast<uint16_t*>(0x0601'0000)
|
||||||
#define MEM_OAM reinterpret_cast<uint64_t*>(0x07000000)
|
#define MEM_OAM reinterpret_cast<uint64_t*>(0x0700'0000)
|
||||||
|
|
||||||
#define MEM_ROM reinterpret_cast<char*>(0x08000000)
|
#define MEM_ROM reinterpret_cast<char*>(0x0800'0000)
|
||||||
|
|
||||||
#define MEM_SRAM reinterpret_cast<char*>(0x0e000000)
|
#define MEM_SRAM reinterpret_cast<char*>(0x0e00'0000)
|
||||||
#define MEM_SRAM_SIZE 65535
|
#define MEM_SRAM_SIZE 65535
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <ox/fs/fs.hpp>
|
#include <ox/fs/fs.hpp>
|
||||||
#include <ox/mc/mc.hpp>
|
#include <ox/mc/mc.hpp>
|
||||||
|
#include <ox/std/array.hpp>
|
||||||
|
|
||||||
#include <nostalgia/core/media.hpp>
|
#include <nostalgia/core/media.hpp>
|
||||||
#include <nostalgia/core/gfx.hpp>
|
#include <nostalgia/core/gfx.hpp>
|
||||||
@ -12,9 +13,12 @@
|
|||||||
#include "bios.hpp"
|
#include "bios.hpp"
|
||||||
#include "gfx.hpp"
|
#include "gfx.hpp"
|
||||||
#include "irq.hpp"
|
#include "irq.hpp"
|
||||||
|
#include "registers.hpp"
|
||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
ox::Array<BgCbbData, 4> g_cbbData;
|
||||||
|
|
||||||
constexpr auto GbaTileColumns = 32;
|
constexpr auto GbaTileColumns = 32;
|
||||||
constexpr auto GbaTileRows = 32;
|
constexpr auto GbaTileRows = 32;
|
||||||
|
|
||||||
@ -31,7 +35,7 @@ struct GbaPaletteTarget {
|
|||||||
struct GbaTileMapTarget {
|
struct GbaTileMapTarget {
|
||||||
static constexpr auto TypeName = CompactTileSheet::TypeName;
|
static constexpr auto TypeName = CompactTileSheet::TypeName;
|
||||||
static constexpr auto TypeVersion = CompactTileSheet::TypeVersion;
|
static constexpr auto TypeVersion = CompactTileSheet::TypeVersion;
|
||||||
volatile uint16_t *bgCtl = nullptr;
|
BgCbbData *cbbData = nullptr;
|
||||||
ox::FileAddress defaultPalette;
|
ox::FileAddress defaultPalette;
|
||||||
GbaPaletteTarget pal;
|
GbaPaletteTarget pal;
|
||||||
volatile uint16_t *tileMap = nullptr;
|
volatile uint16_t *tileMap = nullptr;
|
||||||
@ -39,7 +43,7 @@ struct GbaTileMapTarget {
|
|||||||
|
|
||||||
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> auto *t) noexcept {
|
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaPaletteTarget> auto *t) noexcept {
|
||||||
io->template setTypeInfo<Palette>();
|
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;
|
t->palette[i] = *c;
|
||||||
return OxError(0);
|
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 {
|
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t) noexcept {
|
||||||
io->template setTypeInfo<CompactTileSheet>();
|
io->template setTypeInfo<CompactTileSheet>();
|
||||||
uint8_t bpp;
|
oxReturnError(io->field("bpp", &t->cbbData->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("defaultPalette", &t->defaultPalette));
|
oxReturnError(io->field("defaultPalette", &t->defaultPalette));
|
||||||
uint16_t intermediate = 0;
|
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
|
if (i & 1) { // i is odd
|
||||||
intermediate |= static_cast<uint16_t>(*tile) << 8;
|
intermediate |= static_cast<uint16_t>(*tile) << 8;
|
||||||
t->tileMap[i / 2] = intermediate;
|
t->tileMap[i / 2] = intermediate;
|
||||||
@ -81,11 +75,14 @@ ox::Error initGfx(Context*) noexcept {
|
|||||||
REG_DISPSTAT = REG_DISPSTAT | DispStat_irq_vblank;
|
REG_DISPSTAT = REG_DISPSTAT | DispStat_irq_vblank;
|
||||||
// enable vblank interrupt
|
// enable vblank interrupt
|
||||||
REG_IE = REG_IE | Int_vblank;
|
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 {
|
ox::Error shutdownGfx(Context*) noexcept {
|
||||||
return OxError(0);
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void setWindowTitle(Context*, const char*) noexcept {
|
void setWindowTitle(Context*, const char*) noexcept {
|
||||||
@ -111,8 +108,8 @@ uint8_t bgStatus(Context*) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setBgStatus(Context*, uint32_t status) noexcept {
|
void setBgStatus(Context*, uint32_t status) noexcept {
|
||||||
constexpr auto Bg0Status = 8;
|
constexpr auto BgStatus = 8;
|
||||||
REG_DISPCTL = (REG_DISPCTL & ~0b111100000000u) | status << Bg0Status;
|
REG_DISPCTL = (REG_DISPCTL & ~0b111100000000u) | status << BgStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bgStatus(Context*, unsigned bg) noexcept {
|
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);
|
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.
|
// Do NOT rely on Context in the GBA version of this function.
|
||||||
ox::Error initConsole(Context *ctx) noexcept {
|
ox::Error initConsole(Context *ctx) noexcept {
|
||||||
constexpr auto TilesheetAddr = "/TileSheets/Charset.ng";
|
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);
|
auto romFs = new (ox_alloca(sizeof(ox::FileSystem32))) ox::FileSystem32(fs);
|
||||||
new (&ctx->rom) ox::UniquePtr<ox::FileSystem>(romFs);
|
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,
|
ox::Error loadBgTileSheet(Context *ctx,
|
||||||
int section,
|
unsigned cbb,
|
||||||
const ox::FileAddress &tilesheetAddr,
|
const ox::FileAddress &tilesheetAddr,
|
||||||
const ox::FileAddress &paletteAddr) noexcept {
|
const ox::FileAddress &paletteAddr) noexcept {
|
||||||
oxRequire(tsStat, ctx->rom->stat(tilesheetAddr));
|
oxRequire(tsStat, ctx->rom->stat(tilesheetAddr));
|
||||||
oxRequire(ts, ctx->rom->directAccess(tilesheetAddr));
|
oxRequire(ts, ctx->rom->directAccess(tilesheetAddr));
|
||||||
GbaTileMapTarget target;
|
GbaTileMapTarget target;
|
||||||
target.pal.palette = &MEM_BG_PALETTE[section];
|
target.pal.palette = MEM_BG_PALETTE;
|
||||||
target.bgCtl = &bgCtl(section);
|
target.cbbData = &g_cbbData[cbb];
|
||||||
target.tileMap = &reinterpret_cast<uint16_t*>(MEM_BG_TILES)[section * 512];
|
target.tileMap = MEM_BG_TILES[cbb].data();
|
||||||
oxReturnError(ox::readMC(ts, tsStat.size, &target));
|
oxReturnError(ox::readMC(ts, tsStat.size, &target));
|
||||||
// load external palette if available
|
// load external palette if available
|
||||||
if (paletteAddr) {
|
if (paletteAddr) {
|
||||||
@ -174,20 +163,25 @@ ox::Error loadBgTileSheet(Context *ctx,
|
|||||||
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
|
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
|
||||||
oxReturnError(ox::readMC(pal, palStat.size, &target.pal));
|
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,
|
ox::Error loadSpriteTileSheet(Context *ctx,
|
||||||
int section,
|
unsigned cbb,
|
||||||
const ox::FileAddress &tilesheetAddr,
|
const ox::FileAddress &tilesheetAddr,
|
||||||
const ox::FileAddress &paletteAddr) noexcept {
|
const ox::FileAddress &paletteAddr) noexcept {
|
||||||
oxRequire(tsStat, ctx->rom->stat(tilesheetAddr));
|
oxRequire(tsStat, ctx->rom->stat(tilesheetAddr));
|
||||||
oxRequire(ts, ctx->rom->directAccess(tilesheetAddr));
|
oxRequire(ts, ctx->rom->directAccess(tilesheetAddr));
|
||||||
GbaTileMapTarget target;
|
GbaTileMapTarget target;
|
||||||
target.pal.palette = &MEM_SPRITE_PALETTE[section];
|
target.pal.palette = &MEM_SPRITE_PALETTE[cbb];
|
||||||
// Is this needed? Should this be written to an equivalent sprite value?
|
target.tileMap = &reinterpret_cast<uint16_t*>(MEM_SPRITE_TILES)[cbb * 512];
|
||||||
// target.bgCtl = &bgCtl(section);
|
|
||||||
target.tileMap = &reinterpret_cast<uint16_t*>(MEM_SPRITE_TILES)[section * 512];
|
|
||||||
oxReturnError(ox::readMC(ts, tsStat.size, &target));
|
oxReturnError(ox::readMC(ts, tsStat.size, &target));
|
||||||
// load external palette if available
|
// load external palette if available
|
||||||
if (paletteAddr) {
|
if (paletteAddr) {
|
||||||
@ -195,25 +189,25 @@ ox::Error loadSpriteTileSheet(Context *ctx,
|
|||||||
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
|
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
|
||||||
oxReturnError(ox::readMC(pal, palStat.size, &target.pal));
|
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;
|
GbaPaletteTarget target;
|
||||||
target.palette = &MEM_BG_PALETTE[section];
|
target.palette = MEM_BG_PALETTE;
|
||||||
oxRequire(palStat, ctx->rom->stat(paletteAddr));
|
oxRequire(palStat, ctx->rom->stat(paletteAddr));
|
||||||
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
|
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
|
||||||
oxReturnError(ox::readMC(pal, palStat.size, &target));
|
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;
|
GbaPaletteTarget target;
|
||||||
target.palette = &MEM_SPRITE_PALETTE[section];
|
target.palette = &MEM_SPRITE_PALETTE[cbb];
|
||||||
oxRequire(palStat, ctx->rom->stat(paletteAddr));
|
oxRequire(palStat, ctx->rom->stat(paletteAddr));
|
||||||
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
|
oxRequire(pal, ctx->rom->directAccess(paletteAddr));
|
||||||
oxReturnError(ox::readMC(pal, palStat.size, &target));
|
oxReturnError(ox::readMC(pal, palStat.size, &target));
|
||||||
return OxError(0);
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do NOT use Context in the GBA version of this function.
|
// 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 {
|
void setTile(Context*, unsigned bgIdx, int column, int row, uint8_t tile) noexcept {
|
||||||
MEM_BG_MAP[layer][row * GbaTileColumns + column] = tile;
|
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.
|
// Do NOT use Context in the GBA version of this function.
|
||||||
void clearTileLayer(Context*, int layer) noexcept {
|
void clearTileLayer(Context*, unsigned bgIdx) noexcept {
|
||||||
memset(&MEM_BG_MAP[layer], 0, GbaTileRows * GbaTileColumns);
|
memset(MEM_BG_MAP[bgIdx].data(), 0, GbaTileRows * GbaTileColumns);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
|
@ -38,6 +38,6 @@ struct OX_ALIGN8 GbaSpriteAttrUpdate {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern volatile uint16_t g_spriteUpdates;
|
extern volatile uint16_t g_spriteUpdates;
|
||||||
extern GbaSpriteAttrUpdate g_spriteBuffer[config::GbaSpriteBufferLen];
|
extern ox::Array<GbaSpriteAttrUpdate, config::GbaSpriteBufferLen> g_spriteBuffer;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
// NOTE: this file is compiled as ARM and not THUMB, so don't but too much in
|
// NOTE: this file is compiled as ARM and not THUMB, so don't but too much in
|
||||||
// here
|
// here
|
||||||
|
|
||||||
#include <ox/std/bit.hpp>
|
|
||||||
|
|
||||||
#include "addresses.hpp"
|
#include "addresses.hpp"
|
||||||
#include "core.hpp"
|
#include "core.hpp"
|
||||||
#include "gfx.hpp"
|
#include "gfx.hpp"
|
||||||
@ -15,7 +13,7 @@
|
|||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
volatile uint16_t g_spriteUpdates = 0;
|
volatile uint16_t g_spriteUpdates = 0;
|
||||||
GbaSpriteAttrUpdate g_spriteBuffer[config::GbaSpriteBufferLen];
|
ox::Array<GbaSpriteAttrUpdate, config::GbaSpriteBufferLen> g_spriteBuffer;
|
||||||
|
|
||||||
volatile gba_timer_t g_timerMs = 0;
|
volatile gba_timer_t g_timerMs = 0;
|
||||||
|
|
||||||
|
70
src/nostalgia/core/gba/registers.hpp
Normal file
70
src/nostalgia/core/gba/registers.hpp
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -497,21 +497,23 @@ void setBgStatus(Context *ctx, unsigned bg, bool status) noexcept;
|
|||||||
|
|
||||||
ox::Error initConsole(Context *ctx) 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])
|
* @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,
|
ox::Error loadSpriteTileSheet(Context *ctx,
|
||||||
int section,
|
unsigned section,
|
||||||
const ox::FileAddress &tilesheetAddr,
|
const ox::FileAddress &tilesheetAddr,
|
||||||
const ox::FileAddress &paletteAddr) noexcept;
|
const ox::FileAddress &paletteAddr) noexcept;
|
||||||
|
|
||||||
void puts(Context *ctx, int column, int row, const char *str) 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;
|
void hideSprite(Context *ctx, unsigned) noexcept;
|
||||||
|
|
||||||
|
@ -13,18 +13,19 @@ ox::Error initConsole(Context *ctx) noexcept {
|
|||||||
constexpr auto TilesheetAddr = "/TileSheets/Charset.ng";
|
constexpr auto TilesheetAddr = "/TileSheets/Charset.ng";
|
||||||
constexpr auto PaletteAddr = "/Palettes/Charset.npal";
|
constexpr auto PaletteAddr = "/Palettes/Charset.npal";
|
||||||
setBgStatus(ctx, 0b0001);
|
setBgStatus(ctx, 0b0001);
|
||||||
|
setBgCbb(ctx, 0, 0);
|
||||||
return loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr);
|
return loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error loadSpriteTileSheet(Context*,
|
ox::Error loadSpriteTileSheet(Context*,
|
||||||
int,
|
unsigned,
|
||||||
const ox::FileAddress&,
|
const ox::FileAddress&,
|
||||||
const ox::FileAddress&) noexcept {
|
const ox::FileAddress&) noexcept {
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error loadBgTileSheet(Context *ctx,
|
ox::Error loadBgTileSheet(Context *ctx,
|
||||||
int section,
|
unsigned cbb,
|
||||||
const ox::FileAddress &tilesheetPath,
|
const ox::FileAddress &tilesheetPath,
|
||||||
const ox::FileAddress &palettePath) noexcept {
|
const ox::FileAddress &palettePath) noexcept {
|
||||||
oxRequire(tilesheet, readObj<CompactTileSheet>(ctx, tilesheetPath));
|
oxRequire(tilesheet, readObj<CompactTileSheet>(ctx, tilesheetPath));
|
||||||
@ -46,7 +47,7 @@ ox::Error loadBgTileSheet(Context *ctx,
|
|||||||
pixels[i * 2 + 1] = toColor32(palette->colors[tilesheet->pixels[i] >> 4]);
|
pixels[i * 2 + 1] = toColor32(palette->colors[tilesheet->pixels[i] >> 4]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
renderer::loadBgTexture(ctx->rendererData<void>(), section, pixels.data(), width, height);
|
renderer::loadBgTexture(ctx->rendererData<void>(), cbb, pixels.data(), width, height);
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,6 @@ ox::Error init(Context *ctx, void **rendererData) noexcept;
|
|||||||
|
|
||||||
void shutdown(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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,25 +22,30 @@ namespace renderer {
|
|||||||
constexpr auto TileRows = 128;
|
constexpr auto TileRows = 128;
|
||||||
constexpr auto TileColumns = 128;
|
constexpr auto TileColumns = 128;
|
||||||
constexpr auto TileCount = TileRows * TileColumns;
|
constexpr auto TileCount = TileRows * TileColumns;
|
||||||
constexpr auto BgVertexVboRows = 4;
|
constexpr unsigned BgVertexVboRows = 4;
|
||||||
constexpr auto BgVertexVboRowLength = 4;
|
constexpr unsigned BgVertexVboRowLength = 4;
|
||||||
constexpr auto BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength;
|
constexpr unsigned BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength;
|
||||||
constexpr auto BgVertexEboLength = 6;
|
constexpr unsigned BgVertexEboLength = 6;
|
||||||
|
|
||||||
struct Background: public glutils::BufferSet {
|
struct CBB: public glutils::BufferSet {
|
||||||
bool enabled = false;
|
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
|
|
||||||
Background() noexcept {
|
CBB() noexcept {
|
||||||
vertices.resize(TileCount * BgVertexVboLength);
|
vertices.resize(TileCount * BgVertexVboLength);
|
||||||
elements.resize(TileCount * BgVertexEboLength);
|
elements.resize(TileCount * BgVertexEboLength);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Background {
|
||||||
|
bool enabled = false;
|
||||||
|
unsigned cbbIdx = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct GlImplData {
|
struct GlImplData {
|
||||||
glutils::GLProgram bgShader;
|
glutils::GLProgram bgShader;
|
||||||
int64_t prevFpsCheckTime = 0;
|
int64_t prevFpsCheckTime = 0;
|
||||||
uint64_t draws = 0;
|
uint64_t draws = 0;
|
||||||
|
ox::Array<CBB, 4> cbbs;
|
||||||
ox::Array<Background, 4> backgrounds;
|
ox::Array<Background, 4> backgrounds;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,18 +85,18 @@ setTileBufferObject(Context *ctx, unsigned vi, float x, float y, int textureRow,
|
|||||||
y *= -ymod;
|
y *= -ymod;
|
||||||
x -= 1.0f;
|
x -= 1.0f;
|
||||||
y += 1.0f - ymod;
|
y += 1.0f - ymod;
|
||||||
const float vertices[BgVertexVboLength] = {
|
const ox::Array<float, BgVertexVboLength> vertices {
|
||||||
x, y, 0, static_cast<float>(textureRow + 1), // bottom left
|
x, y, 0, static_cast<float>(textureRow + 1), // bottom left
|
||||||
x + xmod, y, 1, static_cast<float>(textureRow + 1), // bottom right
|
x + xmod, y, 1, static_cast<float>(textureRow + 1), // bottom right
|
||||||
x + xmod, y + ymod, 1, static_cast<float>(textureRow + 0), // top right
|
x + xmod, y + ymod, 1, static_cast<float>(textureRow + 0), // top right
|
||||||
x, y + ymod, 0, static_cast<float>(textureRow + 0), // top left
|
x, y + ymod, 0, static_cast<float>(textureRow + 0), // top left
|
||||||
};
|
};
|
||||||
memcpy(vbo, vertices, sizeof(vertices));
|
memcpy(vbo, vertices.data(), sizeof(vertices));
|
||||||
const GLuint elms[BgVertexEboLength] = {
|
const ox::Array<GLuint, BgVertexEboLength> elms {
|
||||||
vi + 0, vi + 1, vi + 2,
|
vi + 0, vi + 1, vi + 2,
|
||||||
vi + 2, vi + 3, vi + 0,
|
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 {
|
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 {
|
static void drawBackground(CBB *cbb) noexcept {
|
||||||
if (bg->enabled) {
|
glBindVertexArray(cbb->vao);
|
||||||
glBindVertexArray(bg->vao);
|
if (cbb->updated) {
|
||||||
if (bg->updated) {
|
cbb->updated = false;
|
||||||
bg->updated = false;
|
glutils::sendVbo(*cbb);
|
||||||
glutils::sendVbo(*bg);
|
|
||||||
}
|
|
||||||
glBindTexture(GL_TEXTURE_2D, bg->tex);
|
|
||||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(bg->elements.size()), GL_UNSIGNED_INT, nullptr);
|
|
||||||
}
|
}
|
||||||
|
glBindTexture(GL_TEXTURE_2D, cbb->tex);
|
||||||
|
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(cbb->elements.size()), GL_UNSIGNED_INT, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drawBackgrounds(GlImplData *id) noexcept {
|
static void drawBackgrounds(GlImplData *id) noexcept {
|
||||||
@ -174,8 +177,11 @@ static void drawBackgrounds(GlImplData *id) noexcept {
|
|||||||
glUseProgram(id->bgShader);
|
glUseProgram(id->bgShader);
|
||||||
const auto uniformTileHeight = static_cast<GLint>(glGetUniformLocation(id->bgShader, "vTileHeight"));
|
const auto uniformTileHeight = static_cast<GLint>(glGetUniformLocation(id->bgShader, "vTileHeight"));
|
||||||
for (auto &bg : id->backgrounds) {
|
for (auto &bg : id->backgrounds) {
|
||||||
glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(bg.tex.height / 8));
|
if (bg.enabled) {
|
||||||
drawBackground(&bg);
|
auto &cbb = id->cbbs[bg.cbbIdx];
|
||||||
|
glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(cbb.tex.height / 8));
|
||||||
|
drawBackground(&cbb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +192,7 @@ ox::Error init(Context *ctx, void **rendererData) noexcept {
|
|||||||
const auto id = new GlImplData;
|
const auto id = new GlImplData;
|
||||||
*rendererData = id;
|
*rendererData = id;
|
||||||
id->bgShader = std::move(bgShader);
|
id->bgShader = std::move(bgShader);
|
||||||
for (auto &bg : id->backgrounds) {
|
for (auto &bg : id->cbbs) {
|
||||||
initBackgroundBufferset(ctx, id->bgShader, &bg);
|
initBackgroundBufferset(ctx, id->bgShader, &bg);
|
||||||
}
|
}
|
||||||
ImGui_ImplOpenGL3_Init(glutils::GlslVersion);
|
ImGui_ImplOpenGL3_Init(glutils::GlslVersion);
|
||||||
@ -198,19 +204,25 @@ void shutdown(Context*, void *rendererData) noexcept {
|
|||||||
ox::safeDelete(id);
|
ox::safeDelete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadBgTexture(void *rendererData, int section, void *pixels, int w, int h) noexcept {
|
void loadBgTexture(void *rendererData, unsigned cbbIdx, void *pixels, int w, int h) noexcept {
|
||||||
oxTracef("nostalgia::core::gfx::gl", "loadBgTexture: { section: {}, w: {}, h: {} }", section, w, h);
|
oxTracef("nostalgia::core::gfx::gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbbIdx, w, h);
|
||||||
const auto id = static_cast<GlImplData*>(rendererData);
|
const auto id = static_cast<GlImplData*>(rendererData);
|
||||||
auto &tex = id->backgrounds[static_cast<std::size_t>(section)].tex;
|
auto &tex = id->cbbs[cbbIdx].tex;
|
||||||
tex = loadTexture(w, h, pixels);
|
tex = loadTexture(w, h, pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBgCbb(Context *ctx, unsigned bgIdx, unsigned cbbIdx) noexcept {
|
||||||
|
const auto id = ctx->rendererData<renderer::GlImplData>();
|
||||||
|
auto &bg = id->backgrounds[bgIdx];
|
||||||
|
bg.cbbIdx = cbbIdx;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t bgStatus(Context *ctx) noexcept {
|
uint8_t bgStatus(Context *ctx) noexcept {
|
||||||
const auto id = ctx->rendererData<renderer::GlImplData>();
|
const auto id = ctx->rendererData<renderer::GlImplData>();
|
||||||
uint8_t out = 0;
|
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;
|
out |= id->backgrounds[i].enabled << i;
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
@ -218,7 +230,7 @@ uint8_t bgStatus(Context *ctx) noexcept {
|
|||||||
|
|
||||||
void setBgStatus(Context *ctx, uint32_t status) noexcept {
|
void setBgStatus(Context *ctx, uint32_t status) noexcept {
|
||||||
const auto id = ctx->rendererData<renderer::GlImplData>();
|
const auto id = ctx->rendererData<renderer::GlImplData>();
|
||||||
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;
|
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<renderer::GlImplData>();
|
const auto id = ctx->rendererData<renderer::GlImplData>();
|
||||||
auto &bg = id->backgrounds[static_cast<std::size_t>(layer)];
|
auto &bg = id->cbbs[static_cast<std::size_t>(bgIdx)];
|
||||||
initBackgroundBufferObjects(ctx, &bg);
|
initBackgroundBufferObjects(ctx, &bg);
|
||||||
bg.updated = true;
|
bg.updated = true;
|
||||||
}
|
}
|
||||||
@ -276,13 +288,13 @@ void setSprite(Context*,
|
|||||||
unsigned) noexcept {
|
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<renderer::GlImplData>();
|
const auto id = ctx->rendererData<renderer::GlImplData>();
|
||||||
const auto z = static_cast<unsigned>(layer);
|
const auto z = static_cast<unsigned>(bgIdx);
|
||||||
const auto y = static_cast<unsigned>(row);
|
const auto y = static_cast<unsigned>(row);
|
||||||
const auto x = static_cast<unsigned>(column);
|
const auto x = static_cast<unsigned>(column);
|
||||||
const auto i = renderer::bgVertexRow(x, y);
|
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 vbo = &bg.vertices[i * renderer::BgVertexVboLength];
|
||||||
auto ebo = &bg.elements[i * renderer::BgVertexEboLength];
|
auto ebo = &bg.elements[i * renderer::BgVertexEboLength];
|
||||||
renderer::setTileBufferObject(ctx, i * renderer::BgVertexVboRows,
|
renderer::setTileBufferObject(ctx, i * renderer::BgVertexVboRows,
|
||||||
|
Loading…
Reference in New Issue
Block a user