[nostalgia/core] Add support for specifying palette banks
Some checks failed
Build / build (push) Failing after 40s

This commit is contained in:
Gary Talent 2023-12-26 11:54:31 -06:00
parent e941781f21
commit ffdc0ddb97
8 changed files with 86 additions and 35 deletions

View File

@ -43,6 +43,22 @@ oxModelBegin(Sprite)
oxModelField(priority)
oxModelEnd()
struct BgTile {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.BgTile";
static constexpr auto TypeVersion = 1;
unsigned tileIdx = 0;
unsigned palBank = 0;
unsigned horizontalFlip = false;
unsigned verticalFlip = false;
};
oxModelBegin(BgTile)
oxModelField(tileIdx)
oxModelField(palBank)
oxModelField(horizontalFlip)
oxModelField(verticalFlip)
oxModelEnd()
struct TileSheetSetEntrySection {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheetSetEntrySection";
static constexpr auto TypeVersion = 1;
@ -86,6 +102,7 @@ oxModelEnd()
ox::Error loadBgPalette(
Context &ctx,
size_t palBank,
ox::FileAddress const&paletteAddr) noexcept;
ox::Error loadSpritePalette(
@ -101,7 +118,7 @@ ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
ox::FileAddress const&tilesheetAddr,
bool loadDefaultPalette = false) noexcept;
ox::Optional<unsigned> const&paletteBank = {}) noexcept;
ox::Error loadSpriteTileSheet(
Context &ctx,
@ -112,7 +129,9 @@ ox::Error loadSpriteTileSheet(
Context &ctx,
TileSheetSet const&set) noexcept;
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, uint8_t tile) noexcept;
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, unsigned tile, unsigned palBank = 0) noexcept;
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, BgTile const&tile) noexcept;
void clearBg(Context &ctx, uint_t bgIdx) noexcept;

View File

@ -158,9 +158,10 @@ ox::Error initGfx(Context&, InitParams const&) noexcept {
ox::Error loadBgPalette(
Context &ctx,
size_t palBank,
ox::FileAddress const&paletteAddr) noexcept {
auto &rom = ctx.rom();
GbaPaletteTarget const palTarget{.palette = MEM_BG_PALETTE};
GbaPaletteTarget const palTarget{.palette = MEM_BG_PALETTE + palBank * 16};
oxRequire(palStat, rom.stat(paletteAddr));
oxRequire(pal, rom.directAccess(paletteAddr));
oxReturnError(ox::readMC(pal, static_cast<std::size_t>(palStat.size), &palTarget));
@ -205,7 +206,7 @@ ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
ox::FileAddress const&tilesheetAddr,
bool loadDefaultPalette) noexcept {
ox::Optional<unsigned> const&paletteBank) noexcept {
auto &rom = ctx.rom();
oxRequire(tsStat, rom.stat(tilesheetAddr));
oxRequire(ts, rom.directAccess(tilesheetAddr));
@ -222,8 +223,8 @@ ox::Error loadBgTileSheet(
teagba::bgSetBpp(bgCtl, bpp);
}
});
if (loadDefaultPalette && target.defaultPalette) {
oxReturnError(loadBgPalette(ctx, target.defaultPalette));
if (paletteBank.has_value() && target.defaultPalette) {
oxReturnError(loadBgPalette(ctx, *paletteBank, target.defaultPalette));
}
return {};
}
@ -283,9 +284,14 @@ ox::Error loadSpriteTileSheet(
return {};
}
void setBgTile(Context&, uint_t bgIdx, int column, int row, uint8_t tile) noexcept {
const auto tileIdx = static_cast<std::size_t>(row * GbaTileColumns + column);
MEM_BG_MAP[bgIdx][tileIdx] = tile;
void setBgTile(Context&, uint_t bgIdx, int column, int row, BgTile const&tile) noexcept {
auto const tileIdx = static_cast<std::size_t>(row * GbaTileColumns + column);
// see Tonc 9.3
MEM_BG_MAP[bgIdx][tileIdx] =
static_cast<uint16_t>(tile.tileIdx & 0b1'1111'1111) |
static_cast<uint16_t>(tile.horizontalFlip << 0xa) |
static_cast<uint16_t>(tile.verticalFlip << 0xb) |
static_cast<uint16_t>(tile.palBank << 0xc);
}
void clearBg(Context&, uint_t bgIdx) noexcept {

View File

@ -137,13 +137,20 @@ constexpr ox::Array<char, 128> charMap = {
50, // ~
};
void setBgTile(Context &ctx, uint_t bgIdx, int column, int row, unsigned tile, unsigned palBank) noexcept {
setBgTile(ctx, bgIdx, column, row, {
.tileIdx = tile,
.palBank = palBank,
});
}
ox::Error initConsole(Context &ctx) noexcept {
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
setBgStatus(ctx, 0b0001);
setBgCbb(ctx, 0, 0);
oxReturnError(loadBgTileSheet(ctx, 0, TilesheetAddr));
return loadBgPalette(ctx, PaletteAddr);
return loadBgPalette(ctx, 0, PaletteAddr);
}
void puts(

View File

@ -24,6 +24,7 @@ class Context {
ox::Array<renderer::CBB, 4> cbbs;
renderer::SpriteBlockset spriteBlocks;
ox::Array<Sprite, 128> spriteStates;
ox::Array<GLfloat, 1024> bgPalette;
ox::Array<renderer::Background, 4> backgrounds;
renderer::Drawer drawer;
uint_t spriteCount = 0;

View File

@ -35,7 +35,9 @@ constexpr ox::CStringView bgvshadTmpl = R"glsl(
in vec2 vTexCoord;
in vec3 vPosition;
in float vTileIdx;
in float vPalOffset;
out vec2 fTexCoord;
out float fPalOffset;
uniform float vXScale;
uniform float vTileHeight;
uniform float vBgIdx;
@ -49,17 +51,19 @@ constexpr ox::CStringView bgvshadTmpl = R"glsl(
fTexCoord = vec2(
vTexCoord.x,
vTexCoord.y * vTileHeight + vTileIdx * vTileHeight);
fPalOffset = vPalOffset;
})glsl";
constexpr ox::CStringView bgfshadTmpl = R"glsl(
{}
out vec4 outColor;
in float fPalOffset;
in vec2 fTexCoord;
uniform sampler2D image;
uniform vec2 fSrcImgSz;
uniform vec4 fPalette[256];
void main() {
outColor = fPalette[int(texture(image, fTexCoord).rgb.r * 256)];
outColor = fPalette[int(texture(image, fTexCoord).rgb.r * 256) + int(fPalOffset)];
//outColor = vec4(0.0, 0.7, 1.0, 1.0);
if (outColor.a == 0) {
discard;
@ -147,6 +151,7 @@ static void setTileBufferObject(
float y,
float textureTileIdx,
float priority,
float palOffset,
float *vbo,
GLuint *ebo) noexcept {
// don't worry, this memcpy gets optimized to something much more ideal
@ -158,10 +163,10 @@ static void setTileBufferObject(
y += 1.0f - ymod;
auto const prif = priority * PriorityScale;
ox::Array<float, BgVertexVboLength> const vertices {
x, y, prif, 0, 1, textureTileIdx, // bottom left
x + xmod, y, prif, 1, 1, textureTileIdx, // bottom right
x + xmod, y + ymod, prif, 1, 0, textureTileIdx, // top right
x, y + ymod, prif, 0, 0, textureTileIdx, // top left
x, y, prif, 0, 1, textureTileIdx, palOffset, // bottom left
x + xmod, y, prif, 1, 1, textureTileIdx, palOffset, // bottom right
x + xmod, y + ymod, prif, 1, 0, textureTileIdx, palOffset, // top right
x, y + ymod, prif, 0, 0, textureTileIdx, palOffset, // top left
};
memcpy(vbo, vertices.data(), sizeof(vertices));
ox::Array<GLuint, BgVertexEboLength> const elms {
@ -191,6 +196,7 @@ static void initBackgroundBufferObjects(glutils::BufferSet &bs) noexcept {
static_cast<float>(y),
0,
0,
0,
vbo,
ebo);
}
@ -252,6 +258,11 @@ static void initBackgroundBufferset(
glVertexAttribPointer(
heightMultAttr, 1, GL_FLOAT, GL_FALSE, BgVertexVboRowLength * sizeof(float),
std::bit_cast<void*>(uintptr_t{5 * sizeof(float)}));
auto const palBankAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vPalOffset"));
glEnableVertexAttribArray(palBankAttr);
glVertexAttribPointer(
palBankAttr, 1, GL_FLOAT, GL_FALSE, BgVertexVboRowLength * sizeof(float),
std::bit_cast<void*>(uintptr_t{6 * sizeof(float)}));
}
static glutils::GLTexture createTexture(
@ -337,18 +348,19 @@ static void drawSprites(Context &ctx, ox::Size const&renderSz) noexcept {
}
static void loadPalette(
ox::Array<GLfloat, 1024> &palette,
size_t palOffset,
GLuint shaderPgrm,
Palette const&pal) noexcept {
static constexpr std::size_t ColorCnt = 256;
ox::Array<GLfloat, ColorCnt * 4> palette{};
for (auto i = 0u; const auto c : pal.colors) {
for (auto i = palOffset; auto const c : pal.colors) {
palette[i++] = redf(c);
palette[i++] = greenf(c);
palette[i++] = bluef(c);
palette[i++] = 255;
}
// make first color transparent
palette[3] = 0;
palette[palOffset + 3] = 0;
glUseProgram(shaderPgrm);
const auto uniformPalette = static_cast<GLint>(glGetUniformLocation(shaderPgrm, "fPalette"));
glUniform4fv(uniformPalette, ColorCnt, palette.data());
@ -488,10 +500,11 @@ static ox::Result<TileSheetData> normalizeTileSheet(
ox::Error loadBgPalette(
Context &ctx,
size_t palBank,
ox::FileAddress const&paletteAddr) noexcept {
auto &kctx = keelCtx(ctx.turbineCtx);
oxRequire(palette, readObj<Palette>(kctx, paletteAddr));
renderer::loadPalette(ctx.bgShader, *palette);
renderer::loadPalette(ctx.bgPalette, palBank * 16 * 4, ctx.bgShader, *palette);
return {};
}
@ -500,7 +513,8 @@ ox::Error loadSpritePalette(
ox::FileAddress const&paletteAddr) noexcept {
auto &kctx = keelCtx(ctx.turbineCtx);
oxRequire(palette, readObj<Palette>(kctx, paletteAddr));
renderer::loadPalette(ctx.spriteShader, *palette);
ox::Array<GLfloat, 1024> pal;
renderer::loadPalette(pal, 0, ctx.spriteShader, *palette);
return {};
}
@ -529,14 +543,14 @@ ox::Error loadBgTileSheet(
Context &ctx,
uint_t cbb,
ox::FileAddress const&tilesheetAddr,
bool loadDefaultPalette) noexcept {
ox::Optional<unsigned> const&paletteBank) noexcept {
auto &kctx = keelCtx(ctx.turbineCtx);
oxRequire(tilesheet, readObj<CompactTileSheet>(kctx, tilesheetAddr));
oxRequire(tsd, normalizeTileSheet(*tilesheet));
oxTracef("nostalgia.core.gfx.gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbb, tsd.width, tsd.height);
ctx.cbbs[cbb].tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data());
if (loadDefaultPalette) {
oxReturnError(loadBgPalette(ctx, tilesheet->defaultPalette));
if (paletteBank.has_value() && tilesheet->defaultPalette) {
oxReturnError(loadBgPalette(ctx, *paletteBank, tilesheet->defaultPalette));
}
return {};
}
@ -578,7 +592,8 @@ void setBgTile(
uint_t bgIdx,
int column,
int row,
uint8_t tile) noexcept {
unsigned tile,
unsigned palBank) noexcept {
oxTracef(
"nostalgia.core.gfx.setBgTile",
"bgIdx: {}, column: {}, row: {}, tile: {}",
@ -597,6 +612,7 @@ void setBgTile(
static_cast<float>(y),
static_cast<float>(tile),
bg.priority,
static_cast<float>(palBank * 16),
vbo,
ebo);
cbb.updated = true;

View File

@ -18,7 +18,7 @@ constexpr uint64_t TileRows = 128;
constexpr uint64_t TileColumns = 128;
constexpr uint64_t TileCount = TileRows * TileColumns;
constexpr uint64_t BgVertexVboRows = 4;
constexpr uint64_t BgVertexVboRowLength = 6;
constexpr uint64_t BgVertexVboRowLength = 7;
constexpr uint64_t BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength;
constexpr uint64_t BgVertexEboLength = 6;
constexpr uint64_t SpriteVertexVboRows = 4;

View File

@ -18,7 +18,7 @@ ox::Error Scene::setupDisplay(core::Context &ctx) const noexcept {
}
auto const&palette = m_sceneStatic.palettes[0];
oxReturnError(core::loadBgTileSheet(ctx, 0, m_sceneStatic.tilesheet));
oxReturnError(core::loadBgPalette(ctx, palette));
oxReturnError(core::loadBgPalette(ctx, 0, palette));
// disable all backgrounds
core::setBgStatus(ctx, 0);
for (auto layerNo = 0u; auto const&layer : m_sceneStatic.tileMapIdx) {

View File

@ -96,14 +96,16 @@ static ox::Error runTileSheetSetTest(turbine::Context &tctx) {
{ .tilesheet = ox::StringLiteral("/TileSheets/AB.ng"), .sections{{.begin = 1, .tiles = 1}} },
},
};
constexpr auto bgPalBank = 1;
oxReturnError(core::loadBgTileSheet(*cctx, 0, set));
oxReturnError(core::loadSpriteTileSheet(*cctx, set));
oxReturnError(core::loadBgPalette(*cctx, PaletteAddr));
oxReturnError(core::loadBgPalette(*cctx, bgPalBank, PaletteAddr));
oxReturnError(core::loadBgPalette(*cctx, 0, ox::StringLiteral("/Palettes/Chester.npal")));
oxReturnError(core::loadSpritePalette(*cctx, PaletteAddr));
core::setBgStatus(*cctx, 0, true);
core::setBgTile(*cctx, 0, 10, 9, 1);
core::setBgTile(*cctx, 0, 11, 9, 2);
core::setBgTile(*cctx, 0, 13, 9, 4);
core::setBgTile(*cctx, 0, 10, 9, 1, bgPalBank);
core::setBgTile(*cctx, 0, 11, 9, 2, bgPalBank);
core::setBgTile(*cctx, 0, 13, 9, 4, bgPalBank);
core::setSprite(*cctx, 16, {
.enabled = true,
.x = 12 * 8,