[nostalgia/core] Add support for specifying palette banks
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Build / build (push) Failing after 40s
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Build / build (push) Failing after 40s
				
			This commit is contained in:
		| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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( | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user