diff --git a/src/nostalgia/modules/core/src/opengl/gfx.cpp b/src/nostalgia/modules/core/src/opengl/gfx.cpp index 5931c02c..eccd1eb9 100644 --- a/src/nostalgia/modules/core/src/opengl/gfx.cpp +++ b/src/nostalgia/modules/core/src/opengl/gfx.cpp @@ -20,6 +20,7 @@ namespace nostalgia::core { constexpr auto Scale = 1; +constexpr auto PriorityScale = 0.01f; namespace renderer { @@ -32,16 +33,19 @@ void Drawer::draw(turbine::Context &tctx) noexcept { constexpr ox::CStringView bgvshadTmpl = R"glsl( {} in vec2 vTexCoord; - in vec2 vPosition; + in vec3 vPosition; in float vTileIdx; out vec2 fTexCoord; uniform float vXScale; uniform float vTileHeight; + uniform float vBgIdx; void main() { float xScaleInvert = 1.0 - vXScale; gl_Position = vec4( - vPosition.x * vXScale - xScaleInvert, vPosition.y, - 0.5, 1.0); + vPosition.x * vXScale - xScaleInvert, + vPosition.y, + vPosition.z - 0.001 * vBgIdx, + 1.0); fTexCoord = vec2( vTexCoord.x, vTexCoord.y * vTileHeight + vTileIdx * vTileHeight); @@ -55,10 +59,11 @@ constexpr ox::CStringView bgfshadTmpl = R"glsl( uniform vec2 fSrcImgSz; uniform vec4 fPalette[256]; void main() { - vec2 pixelSz = vec2(1, 1) / fSrcImgSz; - vec2 pixelCoord = floor(fTexCoord / pixelSz) * pixelSz; outColor = fPalette[int(texture(image, fTexCoord).rgb.r * 256)]; //outColor = vec4(0.0, 0.7, 1.0, 1.0); + if (outColor.a == 0) { + discard; + } })glsl"; constexpr ox::CStringView spritevshadTmpl = R"glsl( @@ -72,8 +77,11 @@ constexpr ox::CStringView spritevshadTmpl = R"glsl( void main() { float xScaleInvert = 1.0 - vXScale; gl_Position = vec4( - vPosition.x * vXScale - xScaleInvert, vPosition.y, - vPosition.z, 1.0) * vEnabled; + vPosition.x * vXScale - xScaleInvert, + vPosition.y, + // offset to ensure sprites draw on top of BGs by default + vPosition.z - 0.004, + 1.0) * vEnabled; fTexCoord = vTexCoord * vec2(1, vTileHeight); })glsl"; @@ -85,10 +93,11 @@ constexpr ox::CStringView spritefshadTmpl = R"glsl( uniform vec2 fSrcImgSz; uniform vec4 fPalette[256]; void main() { - vec2 pixelSz = vec2(1, 1) / fSrcImgSz; - vec2 pixelCoord = floor(fTexCoord / pixelSz) * pixelSz; outColor = fPalette[int(texture(image, fTexCoord).rgb.r * 256)]; //outColor = vec4(0.0, 0.7, 1.0, 1.0); + if (outColor.a == 0) { + discard; + } })glsl";; [[nodiscard]] @@ -113,7 +122,7 @@ static void setSpriteBufferObject( y *= -ymod; x -= 1.f; y += 1.f - ymod; - auto const prif = static_cast(priority) * 0.01f; + auto const prif = static_cast(priority) * PriorityScale; auto const textureRowf = static_cast(textureRow); float const L = flipX ? 1 : 0; float const R = flipX ? 0 : 1; @@ -137,6 +146,7 @@ static void setTileBufferObject( float x, float y, float textureTileIdx, + float priority, float *vbo, GLuint *ebo) noexcept { // don't worry, this memcpy gets optimized to something much more ideal @@ -146,11 +156,12 @@ static void setTileBufferObject( y *= -ymod; x -= 1.0f; y += 1.0f - ymod; + auto const prif = priority * PriorityScale; ox::Array const vertices { - x, y, 0, 1, textureTileIdx, // bottom left - x + xmod, y, 1, 1, textureTileIdx, // bottom right - x + xmod, y + ymod, 1, 0, textureTileIdx, // top right - x, y + ymod, 0, 0, textureTileIdx, // top left + 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 }; memcpy(vbo, vertices.data(), sizeof(vertices)); ox::Array const elms { @@ -168,17 +179,18 @@ static void initSpriteBufferObjects(glutils::BufferSet &bs) noexcept { } } -static void initBackgroundBufferObjects(glutils::BufferSet &bg) noexcept { +static void initBackgroundBufferObjects(glutils::BufferSet &bs, float priority) noexcept { for (auto x = 0u; x < TileColumns; ++x) { for (auto y = 0u; y < TileRows; ++y) { const auto i = bgVertexRow(x, y); - auto vbo = &bg.vertices[i * static_cast(BgVertexVboLength)]; - auto ebo = &bg.elements[i * static_cast(BgVertexEboLength)]; + auto vbo = &bs.vertices[i * static_cast(BgVertexVboLength)]; + auto ebo = &bs.elements[i * static_cast(BgVertexEboLength)]; setTileBufferObject( static_cast(i * BgVertexVboRows), static_cast(x), static_cast(y), 0, + priority, vbo, ebo); } @@ -216,30 +228,31 @@ static void initSpritesBufferset(Context &ctx) noexcept { static void initBackgroundBufferset( GLuint shader, - glutils::BufferSet &bg) noexcept { + glutils::BufferSet &bs, + float priority) noexcept { // vao - bg.vao = glutils::generateVertexArrayObject(); - glBindVertexArray(bg.vao); + bs.vao = glutils::generateVertexArrayObject(); + glBindVertexArray(bs.vao); // vbo & ebo - bg.vbo = glutils::generateBuffer(); - bg.ebo = glutils::generateBuffer(); - initBackgroundBufferObjects(bg); - glutils::sendVbo(bg); - glutils::sendEbo(bg); + bs.vbo = glutils::generateBuffer(); + bs.ebo = glutils::generateBuffer(); + initBackgroundBufferObjects(bs, priority); + glutils::sendVbo(bs); + glutils::sendEbo(bs); // vbo layout auto const posAttr = static_cast(glGetAttribLocation(shader, "vPosition")); glEnableVertexAttribArray(posAttr); - glVertexAttribPointer(posAttr, 2, GL_FLOAT, GL_FALSE, BgVertexVboRowLength * sizeof(float), nullptr); + glVertexAttribPointer(posAttr, 3, GL_FLOAT, GL_FALSE, BgVertexVboRowLength * sizeof(float), nullptr); auto const texCoordAttr = static_cast(glGetAttribLocation(shader, "vTexCoord")); glEnableVertexAttribArray(texCoordAttr); glVertexAttribPointer( texCoordAttr, 2, GL_FLOAT, GL_FALSE, BgVertexVboRowLength * sizeof(float), - std::bit_cast(uintptr_t{2 * sizeof(float)})); + std::bit_cast(uintptr_t{3 * sizeof(float)})); auto const heightMultAttr = static_cast(glGetAttribLocation(shader, "vTileIdx")); glEnableVertexAttribArray(heightMultAttr); glVertexAttribPointer( heightMultAttr, 1, GL_FLOAT, GL_FALSE, BgVertexVboRowLength * sizeof(float), - std::bit_cast(uintptr_t{4 * sizeof(float)})); + std::bit_cast(uintptr_t{5 * sizeof(float)})); } static glutils::GLTexture createTexture( @@ -279,10 +292,12 @@ static void drawBackgrounds( const auto uniformSrcImgSz = glGetUniformLocation(ctx.bgShader, "fSrcImgSz"); const auto uniformXScale = static_cast(glGetUniformLocation(ctx.bgShader, "vXScale")); const auto uniformTileHeight = static_cast(glGetUniformLocation(ctx.bgShader, "vTileHeight")); + const auto uniformBgIdx = static_cast(glGetUniformLocation(ctx.bgShader, "vBgIdx")); const auto [wi, hi] = renderSz; const auto wf = static_cast(wi); const auto hf = static_cast(hi); glUniform1f(uniformXScale, hf / wf); + auto bgIdx = 0.f; for (const auto &bg : ctx.backgrounds) { if (bg.enabled) { auto &cbb = ctx.cbbs[bg.cbbIdx]; @@ -292,7 +307,9 @@ static void drawBackgrounds( uniformSrcImgSz, static_cast(cbb.tex.width), static_cast(cbb.tex.height)); + glUniform1f(uniformBgIdx, bgIdx); drawBackground(cbb); + ++bgIdx; } } } @@ -323,7 +340,7 @@ static void drawSprites(Context &ctx, ox::Size const&renderSz) noexcept { static void loadPalette( GLuint shaderPgrm, Palette const&pal, - bool firstIsTransparent = false) noexcept { + bool firstIsTransparent) noexcept { static constexpr std::size_t ColorCnt = 256; ox::Array palette{}; for (auto i = 0u; const auto c : pal.colors) { @@ -341,7 +358,7 @@ static void loadPalette( } static void loadBgPalette(Context &ctx, Palette const&pal) noexcept { - loadPalette(ctx.bgShader, pal); + loadPalette(ctx.bgShader, pal, true); } static void loadSpritePalette(Context &ctx, Palette const&pal) noexcept { @@ -456,8 +473,8 @@ ox::Error initGfx( oxReturnError(glutils::buildShaderProgram(bgVshad, bgFshad).moveTo(ctx.bgShader)); oxReturnError( glutils::buildShaderProgram(spriteVshad, spriteFshad).moveTo(ctx.spriteShader)); - for (auto &bg : ctx.cbbs) { - initBackgroundBufferset(ctx.bgShader, bg); + for (auto &cbb : ctx.cbbs) { + initBackgroundBufferset(ctx.bgShader, cbb, 0); } renderer::initSpritesBufferset(ctx); if (initParams.glInstallDrawer) { @@ -562,6 +579,11 @@ void setBgCbb(Context &ctx, uint_t bgIdx, uint_t cbbIdx) noexcept { bg.cbbIdx = cbbIdx; } +void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept { + auto &bg = ctx.backgrounds[bgIdx]; + bg.priority = static_cast(priority & 0b11); +} + uint8_t bgStatus(Context &ctx) noexcept { uint8_t out = 0; for (uint_t i = 0; i < ctx.cbbs.size(); ++i) { @@ -586,9 +608,11 @@ void setBgStatus(Context &ctx, uint_t bg, bool status) noexcept { void clearTileLayer(Context &ctx, uint_t bgIdx) noexcept { - auto &bg = ctx.cbbs[static_cast(bgIdx)]; - initBackgroundBufferObjects(bg); - bg.updated = true; + auto &cbb = ctx.cbbs[static_cast(bgIdx)]; + initBackgroundBufferObjects(cbb, 0); + cbb.updated = true; + auto &bg = ctx.backgrounds[static_cast(bgIdx)]; + bg.priority = 0; } void hideSprite(Context &ctx, uint_t idx) noexcept { @@ -623,17 +647,19 @@ void setTile( const auto y = static_cast(row); const auto x = static_cast(column); const auto i = renderer::bgVertexRow(x, y); - auto &bg = ctx.cbbs[z]; - const auto vbo = &bg.vertices[i * renderer::BgVertexVboLength]; - const auto ebo = &bg.elements[i * renderer::BgVertexEboLength]; + auto &cbb = ctx.cbbs[z]; + const auto vbo = &cbb.vertices[i * renderer::BgVertexVboLength]; + const auto ebo = &cbb.elements[i * renderer::BgVertexEboLength]; + auto &bg = ctx.backgrounds[bgIdx]; renderer::setTileBufferObject( static_cast(i * renderer::BgVertexVboRows), static_cast(x), static_cast(y), static_cast(tile), + bg.priority, vbo, ebo); - bg.updated = true; + cbb.updated = true; } namespace gl { diff --git a/src/nostalgia/modules/core/src/opengl/gfx.hpp b/src/nostalgia/modules/core/src/opengl/gfx.hpp index 37c363d2..48a4c6d4 100644 --- a/src/nostalgia/modules/core/src/opengl/gfx.hpp +++ b/src/nostalgia/modules/core/src/opengl/gfx.hpp @@ -19,7 +19,7 @@ constexpr uint64_t TileColumns = 128; constexpr uint64_t TileCount = TileRows * TileColumns; constexpr uint64_t SpriteCount = 128; constexpr uint64_t BgVertexVboRows = 4; -constexpr uint64_t BgVertexVboRowLength = 5; +constexpr uint64_t BgVertexVboRowLength = 6; constexpr uint64_t BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength; constexpr uint64_t BgVertexEboLength = 6; constexpr uint64_t SpriteVertexVboRows = 4; @@ -45,6 +45,7 @@ struct SpriteBlockset: public glutils::BufferSet { }; struct Background { + float priority = 0; bool enabled = false; unsigned cbbIdx = 0; };