[nostalgia] Move modules into modules directory
This commit is contained in:
12
src/nostalgia/modules/core/src/gba/CMakeLists.txt
Normal file
12
src/nostalgia/modules/core/src/gba/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
enable_language(CXX ASM)
|
||||
set_source_files_properties(gfx.cpp PROPERTIES COMPILE_FLAGS -marm)
|
||||
target_sources(
|
||||
NostalgiaCore PRIVATE
|
||||
context.cpp
|
||||
gfx.cpp
|
||||
panic.cpp
|
||||
)
|
||||
target_link_libraries(
|
||||
NostalgiaCore PUBLIC
|
||||
TeaGBA
|
||||
)
|
20
src/nostalgia/modules/core/src/gba/context.cpp
Normal file
20
src/nostalgia/modules/core/src/gba/context.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nostalgia/core/gfx.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
ox::Error initGfx(Context *ctx, const InitParams&) noexcept;
|
||||
|
||||
ox::Result<ox::UniquePtr<Context>> init(turbine::Context *tctx, const InitParams ¶ms) noexcept {
|
||||
auto ctx = ox::make_unique<GbaContext>();
|
||||
ctx->turbineCtx = tctx;
|
||||
oxReturnError(initGfx(ctx.get(), params));
|
||||
return ox::UPtr<Context>(ctx.release());
|
||||
}
|
||||
|
||||
}
|
22
src/nostalgia/modules/core/src/gba/context.hpp
Normal file
22
src/nostalgia/modules/core/src/gba/context.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nostalgia/core/context.hpp>
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
struct GbaContext: public core::Context {
|
||||
|
||||
turbine::Context *turbineCtx = nullptr;
|
||||
|
||||
[[nodiscard]]
|
||||
const auto &rom() const noexcept {
|
||||
return *turbineCtx->rom;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
247
src/nostalgia/modules/core/src/gba/gfx.cpp
Normal file
247
src/nostalgia/modules/core/src/gba/gfx.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <ox/fs/fs.hpp>
|
||||
#include <ox/mc/mc.hpp>
|
||||
#include <ox/std/array.hpp>
|
||||
|
||||
#include <teagba/addresses.hpp>
|
||||
#include <teagba/gfx.hpp>
|
||||
#include <teagba/registers.hpp>
|
||||
|
||||
#include <keel/media.hpp>
|
||||
#include <turbine/turbine.hpp>
|
||||
|
||||
#include <nostalgia/core/context.hpp>
|
||||
#include <nostalgia/core/gfx.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
struct BgCbbData {
|
||||
unsigned bpp = 4;
|
||||
};
|
||||
static ox::Array<BgCbbData, 4> g_cbbData;
|
||||
|
||||
constexpr auto GbaTileColumns = 32;
|
||||
constexpr auto GbaTileRows = 32;
|
||||
|
||||
struct GbaPaletteTarget {
|
||||
static constexpr auto TypeName = Palette::TypeName;
|
||||
static constexpr auto TypeVersion = Palette::TypeVersion;
|
||||
volatile uint16_t *palette = nullptr;
|
||||
};
|
||||
|
||||
struct GbaTileMapTarget {
|
||||
static constexpr auto TypeName = CompactTileSheet::TypeName;
|
||||
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);
|
||||
}
|
||||
|
||||
constexpr ox::Error model(auto *io, ox::CommonPtrWith<GbaTileMapTarget> auto *t) noexcept {
|
||||
oxReturnError(io->template setTypeInfo<CompactTileSheet>());
|
||||
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, 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 OxError(0);
|
||||
};
|
||||
return io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
||||
}
|
||||
|
||||
ox::Error initGfx(Context*, const InitParams&) noexcept {
|
||||
for (auto bgCtl = ®_BG0CTL; bgCtl <= ®_BG3CTL; bgCtl += 2) {
|
||||
teagba::bgSetSbb(bgCtl, 28);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void shutdownGfx(Context*) noexcept {
|
||||
}
|
||||
|
||||
uint8_t bgStatus(Context*) noexcept {
|
||||
return (REG_DISPCTL >> 8) & 0b1111;
|
||||
}
|
||||
|
||||
void setBgStatus(Context*, uint32_t status) noexcept {
|
||||
constexpr auto BgStatus = 8;
|
||||
REG_DISPCTL = (REG_DISPCTL & ~0b111100000000u) | status << BgStatus;
|
||||
}
|
||||
|
||||
bool bgStatus(Context*, unsigned bg) noexcept {
|
||||
return (REG_DISPCTL >> (8 + bg)) & 1;
|
||||
}
|
||||
|
||||
void setBgStatus(Context*, unsigned bg, bool status) noexcept {
|
||||
constexpr auto Bg0Status = 8;
|
||||
const auto mask = static_cast<uint32_t>(status) << (Bg0Status + bg);
|
||||
REG_DISPCTL = REG_DISPCTL | ((REG_DISPCTL & ~mask) | mask);
|
||||
}
|
||||
|
||||
// Do NOT rely on Context in the GBA version of this function.
|
||||
ox::Error initConsole(Context *ctx) noexcept {
|
||||
constexpr ox::FileAddress TilesheetAddr("/TileSheets/Charset.ng");
|
||||
constexpr ox::FileAddress PaletteAddr("/Palettes/Charset.npal");
|
||||
setBgStatus(ctx, 0b0001);
|
||||
if (!ctx) {
|
||||
const auto gctx = new(ox_alloca(sizeof(GbaContext))) GbaContext;
|
||||
oxRequire(rom, keel::loadRom());
|
||||
auto romFs = new(ox_alloca(sizeof(ox::FileSystem32)))
|
||||
ox::FileSystem32(ox::FileStore32(rom, 32 * ox::units::MB));
|
||||
oxRequireM(tctx, turbine::init(ox::UPtr<ox::FileSystem>(romFs), ""));
|
||||
gctx->turbineCtx = tctx.release();
|
||||
oxReturnError(loadBgTileSheet(gctx, 0, TilesheetAddr, PaletteAddr));
|
||||
setBgCbb(gctx, 0, 0);
|
||||
return {};
|
||||
} else {
|
||||
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];
|
||||
teagba::bgSetBpp(&bgCtl, cbbData.bpp);
|
||||
teagba::bgSetCbb(&bgCtl, cbb);
|
||||
}
|
||||
|
||||
ox::Error loadBgTileSheet(Context *ctx,
|
||||
unsigned cbb,
|
||||
const ox::FileAddress &tilesheetAddr,
|
||||
const ox::FileAddress &paletteAddr) noexcept {
|
||||
auto &gctx = static_cast<GbaContext&>(*ctx);
|
||||
oxRequire(tsStat, gctx.rom().stat(tilesheetAddr));
|
||||
oxRequire(ts, static_cast<const ox::MemFS&>(gctx.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, gctx.rom().stat(paletteAddr));
|
||||
oxRequire(pal, static_cast<const ox::MemFS&>(gctx.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 loadSpriteTileSheet(Context *ctx,
|
||||
const ox::FileAddress &tilesheetAddr,
|
||||
const ox::FileAddress &paletteAddr) noexcept {
|
||||
auto &gctx = static_cast<GbaContext&>(*ctx);
|
||||
oxRequire(tsStat, gctx.rom().stat(tilesheetAddr));
|
||||
oxRequire(ts, static_cast<const ox::MemFS&>(gctx.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, gctx.rom().stat(paletteAddr));
|
||||
oxRequire(pal, static_cast<const ox::MemFS&>(gctx.rom()).directAccess(paletteAddr));
|
||||
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target.pal));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error loadBgPalette(Context *ctx, unsigned, const ox::FileAddress &paletteAddr) noexcept {
|
||||
auto &gctx = static_cast<GbaContext&>(*ctx);
|
||||
GbaPaletteTarget target;
|
||||
target.palette = MEM_BG_PALETTE;
|
||||
oxRequire(palStat, gctx.rom().stat(paletteAddr));
|
||||
oxRequire(pal, static_cast<const ox::MemFS&>(gctx.rom()).directAccess(paletteAddr));
|
||||
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target));
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error loadSpritePalette(Context *ctx, unsigned cbb, const ox::FileAddress &paletteAddr) noexcept {
|
||||
auto &gctx = static_cast<GbaContext&>(*ctx);
|
||||
GbaPaletteTarget target;
|
||||
target.palette = &MEM_SPRITE_PALETTE[cbb];
|
||||
oxRequire(palStat, gctx.rom().stat(paletteAddr));
|
||||
oxRequire(pal, static_cast<const ox::MemFS&>(gctx.rom()).directAccess(paletteAddr));
|
||||
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &target));
|
||||
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<unsigned>(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::GbaSpriteAttrUpdate oa;
|
||||
oa.attr0 = 2 << 8;
|
||||
oa.idx = static_cast<uint16_t>(idx);
|
||||
teagba::addSpriteUpdate(oa);
|
||||
}
|
||||
|
||||
void setSprite(Context*,
|
||||
unsigned idx,
|
||||
int x,
|
||||
int y,
|
||||
unsigned tileIdx,
|
||||
unsigned spriteShape,
|
||||
unsigned spriteSize,
|
||||
unsigned flipX) noexcept {
|
||||
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||
teagba::GbaSpriteAttrUpdate oa;
|
||||
oa.attr0 = static_cast<uint16_t>(
|
||||
static_cast<uint16_t>(y & ox::onMask<uint8_t>(0b111'1111))
|
||||
| (static_cast<uint16_t>(1) << 10) // enable alpha
|
||||
| (static_cast<uint16_t>(spriteShape) << 14));
|
||||
oa.attr1 = static_cast<uint16_t>(
|
||||
(static_cast<uint16_t>(x) & ox::onMask<uint8_t>(8))
|
||||
| (static_cast<uint16_t>(flipX) << 12)
|
||||
| (static_cast<uint16_t>(spriteSize) << 14));
|
||||
oa.attr2 = static_cast<uint16_t>(tileIdx & ox::onMask<uint16_t>(8));
|
||||
oa.idx = static_cast<uint16_t>(idx);
|
||||
teagba::addSpriteUpdate(oa);
|
||||
}
|
||||
|
||||
}
|
11
src/nostalgia/modules/core/src/gba/gfx.hpp
Normal file
11
src/nostalgia/modules/core/src/gba/gfx.hpp
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nostalgia/core/context.hpp>
|
||||
|
||||
namespace nostalgia::core {
|
||||
ox::Error initGfx(Context *ctx, const InitParams&) noexcept;
|
||||
}
|
47
src/nostalgia/modules/core/src/gba/panic.cpp
Normal file
47
src/nostalgia/modules/core/src/gba/panic.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <nostalgia/core/core.hpp>
|
||||
|
||||
#include <teagba/addresses.hpp>
|
||||
#include <teagba/bios.hpp>
|
||||
#include <teagba/gfx.hpp>
|
||||
|
||||
#include "gfx.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
using namespace nostalgia::core;
|
||||
|
||||
void panic(const char *file, int line, const char *panicMsg, const ox::Error &err) noexcept {
|
||||
oxIgnoreError(initGfx(nullptr, {}));
|
||||
oxIgnoreError(initConsole(nullptr));
|
||||
// enable only BG 0
|
||||
REG_DISPCTL = teagba::DispCtl_Bg0;
|
||||
clearTileLayer(nullptr, 0);
|
||||
ox::BString<23> serr = "Error code: ";
|
||||
serr += static_cast<int64_t>(err);
|
||||
puts(nullptr, 32 + 1, 1, "SADNESS...");
|
||||
puts(nullptr, 32 + 1, 4, "UNEXPECTED STATE:");
|
||||
puts(nullptr, 32 + 2, 6, panicMsg);
|
||||
if (err) {
|
||||
puts(nullptr, 32 + 2, 8, serr);
|
||||
}
|
||||
puts(nullptr, 32 + 1, 15, "PLEASE RESTART THE SYSTEM");
|
||||
// print to terminal if in mGBA
|
||||
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
|
||||
if (err.msg) {
|
||||
oxErrf("\tError Message:\t{}\n", err.msg);
|
||||
}
|
||||
oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
|
||||
if (err.file != nullptr) {
|
||||
oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
|
||||
}
|
||||
// disable all interrupt handling and IntrWait on no interrupts
|
||||
REG_IE = 0;
|
||||
teagba::intrwait(0, 0);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user