[nostalgia/core] Fix OpenGL sprites, add priority
This commit is contained in:
parent
2b8dbb88b2
commit
59016ee894
@ -16,23 +16,26 @@ namespace nostalgia::core {
|
|||||||
extern ox::Array<char, 128> charMap;
|
extern ox::Array<char, 128> charMap;
|
||||||
|
|
||||||
struct Sprite {
|
struct Sprite {
|
||||||
unsigned idx = 0;
|
bool enabled = false;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
unsigned tileIdx = 0;
|
unsigned tileIdx = 0;
|
||||||
unsigned spriteShape = 0;
|
unsigned spriteShape = 0;
|
||||||
unsigned spriteSize = 0;
|
unsigned spriteSize = 0;
|
||||||
unsigned flipX = 0;
|
unsigned flipX = 0;
|
||||||
|
unsigned priority = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
oxModelBegin(Sprite)
|
oxModelBegin(Sprite)
|
||||||
oxModelField(idx)
|
oxModelField(idx)
|
||||||
oxModelField(x)
|
oxModelField(x)
|
||||||
oxModelField(y)
|
oxModelField(y)
|
||||||
|
oxModelField(enabled)
|
||||||
oxModelField(tileIdx)
|
oxModelField(tileIdx)
|
||||||
oxModelField(spriteShape)
|
oxModelField(spriteShape)
|
||||||
oxModelField(spriteSize)
|
oxModelField(spriteSize)
|
||||||
oxModelField(flipX)
|
oxModelField(flipX)
|
||||||
|
oxModelField(priority)
|
||||||
oxModelEnd()
|
oxModelEnd()
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@ -70,10 +73,9 @@ void clearTileLayer(Context &ctx, unsigned bgIdx) noexcept;
|
|||||||
|
|
||||||
void hideSprite(Context &ctx, unsigned) noexcept;
|
void hideSprite(Context &ctx, unsigned) noexcept;
|
||||||
|
|
||||||
void setSprite(Context &ctx, unsigned idx, int x, int y, unsigned tileIdx,
|
void showSprite(Context &ctx, unsigned) noexcept;
|
||||||
unsigned spriteShape = 0, unsigned spriteSize = 0, unsigned flipX = 0) noexcept;
|
|
||||||
|
|
||||||
void setSprite(Context &ctx, Sprite const&s) noexcept;
|
void setSprite(Context &c, uint_t idx, Sprite const&s) noexcept;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,32 +216,37 @@ void clearTileLayer(Context&, unsigned bgIdx) noexcept {
|
|||||||
void hideSprite(Context&, unsigned idx) noexcept {
|
void hideSprite(Context&, unsigned idx) noexcept {
|
||||||
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||||
teagba::GbaSpriteAttrUpdate oa;
|
teagba::GbaSpriteAttrUpdate oa;
|
||||||
oa.attr0 = 2 << 8;
|
oa.attr0 = uint16_t{0b11 << 8};
|
||||||
oa.idx = static_cast<uint16_t>(idx);
|
oa.idx = static_cast<uint16_t>(idx);
|
||||||
teagba::addSpriteUpdate(oa);
|
teagba::addSpriteUpdate(oa);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSprite(Context&,
|
[[maybe_unused]]
|
||||||
unsigned idx,
|
void showSprite(Context&, unsigned idx) noexcept {
|
||||||
int x,
|
|
||||||
int y,
|
|
||||||
unsigned tileIdx,
|
|
||||||
unsigned spriteShape,
|
|
||||||
unsigned spriteSize,
|
|
||||||
unsigned flipX) noexcept {
|
|
||||||
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||||
teagba::GbaSpriteAttrUpdate oa;
|
teagba::GbaSpriteAttrUpdate oa;
|
||||||
oa.attr0 = static_cast<uint16_t>(
|
oa.attr0 &= uint16_t{0b1111'1100'1111'1111};
|
||||||
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);
|
oa.idx = static_cast<uint16_t>(idx);
|
||||||
teagba::addSpriteUpdate(oa);
|
teagba::addSpriteUpdate(oa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setSprite(Context&, uint_t idx, Sprite const&s) noexcept {
|
||||||
|
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||||
|
teagba::GbaSpriteAttrUpdate const oa{
|
||||||
|
.attr0 = static_cast<uint16_t>(
|
||||||
|
(static_cast<uint16_t>(s.y & ox::onMask<uint8_t>(0b111'1111)))
|
||||||
|
| (static_cast<uint16_t>(1) << 10) // enable alpha
|
||||||
|
| (static_cast<uint16_t>(s.spriteShape) << 14)),
|
||||||
|
.attr1 = static_cast<uint16_t>(
|
||||||
|
(static_cast<uint16_t>(s.x) & ox::onMask<uint8_t>(8))
|
||||||
|
| (static_cast<uint16_t>(s.flipX) << 12)
|
||||||
|
| (static_cast<uint16_t>(s.spriteSize) << 14)),
|
||||||
|
.attr2 = static_cast<uint16_t>(
|
||||||
|
(static_cast<uint16_t>(s.tileIdx & ox::onMask<uint16_t>(8)))
|
||||||
|
| (static_cast<uint16_t>(s.priority & 0b11) << 10)),
|
||||||
|
.idx = static_cast<uint16_t>(idx),
|
||||||
|
};
|
||||||
|
teagba::addSpriteUpdate(oa);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -137,8 +137,4 @@ ox::Array<char, 128> charMap = {
|
|||||||
50, // ~
|
50, // ~
|
||||||
};
|
};
|
||||||
|
|
||||||
void setSprite(Context &c, Sprite const&s) noexcept {
|
|
||||||
setSprite(c, s.idx, s.x, s.y, s.tileIdx, s.spriteShape, s.spriteSize, s.flipX);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,10 @@ class Context {
|
|||||||
ox::Array<renderer::Background, 4> backgrounds;
|
ox::Array<renderer::Background, 4> backgrounds;
|
||||||
renderer::Drawer drawer;
|
renderer::Drawer drawer;
|
||||||
explicit Context(turbine::Context &tctx) noexcept;
|
explicit Context(turbine::Context &tctx) noexcept;
|
||||||
|
Context(Context const&) = delete;
|
||||||
|
Context(Context&&) = delete;
|
||||||
|
Context &operator=(Context const&) = delete;
|
||||||
|
Context &operator=(Context&&) = delete;
|
||||||
~Context() noexcept;
|
~Context() noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ void Drawer::draw(turbine::Context &tctx) noexcept {
|
|||||||
core::gl::draw(m_ctx, turbine::getScreenSize(tctx));
|
core::gl::draw(m_ctx, turbine::getScreenSize(tctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ox::StringView bgvshadTmpl = R"glsl(
|
constexpr ox::CStringView bgvshadTmpl = R"glsl(
|
||||||
{}
|
{}
|
||||||
in vec2 vTexCoord;
|
in vec2 vTexCoord;
|
||||||
in vec2 vPosition;
|
in vec2 vPosition;
|
||||||
@ -41,13 +41,13 @@ constexpr ox::StringView bgvshadTmpl = R"glsl(
|
|||||||
float xScaleInvert = 1.0 - vXScale;
|
float xScaleInvert = 1.0 - vXScale;
|
||||||
gl_Position = vec4(
|
gl_Position = vec4(
|
||||||
vPosition.x * vXScale - xScaleInvert, vPosition.y,
|
vPosition.x * vXScale - xScaleInvert, vPosition.y,
|
||||||
0.0, 1.0);
|
0.5, 1.0);
|
||||||
fTexCoord = vec2(
|
fTexCoord = vec2(
|
||||||
vTexCoord.x,
|
vTexCoord.x,
|
||||||
vTexCoord.y * vTileHeight + vTileIdx * vTileHeight);
|
vTexCoord.y * vTileHeight + vTileIdx * vTileHeight);
|
||||||
})glsl";
|
})glsl";
|
||||||
|
|
||||||
constexpr ox::StringView bgfshadTmpl = R"glsl(
|
constexpr ox::CStringView bgfshadTmpl = R"glsl(
|
||||||
{}
|
{}
|
||||||
out vec4 outColor;
|
out vec4 outColor;
|
||||||
in vec2 fTexCoord;
|
in vec2 fTexCoord;
|
||||||
@ -55,17 +55,17 @@ constexpr ox::StringView bgfshadTmpl = R"glsl(
|
|||||||
uniform vec2 fSrcImgSz;
|
uniform vec2 fSrcImgSz;
|
||||||
uniform vec4 fPalette[256];
|
uniform vec4 fPalette[256];
|
||||||
void main() {
|
void main() {
|
||||||
vec2 pixelSz = vec2(1, 1) / (fSrcImgSz);
|
vec2 pixelSz = vec2(1, 1) / fSrcImgSz;
|
||||||
vec2 pixelCoord = floor(fTexCoord / pixelSz) * pixelSz;
|
vec2 pixelCoord = floor(fTexCoord / pixelSz) * pixelSz;
|
||||||
outColor = fPalette[int(texture(image, fTexCoord).rgb.r * 256)];
|
outColor = fPalette[int(texture(image, fTexCoord).rgb.r * 256)];
|
||||||
//outColor = vec4(0.0, 0.7, 1.0, 1.0);
|
//outColor = vec4(0.0, 0.7, 1.0, 1.0);
|
||||||
})glsl";
|
})glsl";
|
||||||
|
|
||||||
constexpr ox::StringView spritevshadTmpl = R"glsl(
|
constexpr ox::CStringView spritevshadTmpl = R"glsl(
|
||||||
{}
|
{}
|
||||||
in float vEnabled;
|
in float vEnabled;
|
||||||
|
in vec3 vPosition;
|
||||||
in vec2 vTexCoord;
|
in vec2 vTexCoord;
|
||||||
in vec2 vPosition;
|
|
||||||
out vec2 fTexCoord;
|
out vec2 fTexCoord;
|
||||||
uniform float vXScale;
|
uniform float vXScale;
|
||||||
uniform float vTileHeight;
|
uniform float vTileHeight;
|
||||||
@ -73,11 +73,23 @@ constexpr ox::StringView spritevshadTmpl = R"glsl(
|
|||||||
float xScaleInvert = 1.0 - vXScale;
|
float xScaleInvert = 1.0 - vXScale;
|
||||||
gl_Position = vec4(
|
gl_Position = vec4(
|
||||||
vPosition.x * vXScale - xScaleInvert, vPosition.y,
|
vPosition.x * vXScale - xScaleInvert, vPosition.y,
|
||||||
0.0, 1.0);
|
vPosition.z, 1.0);
|
||||||
fTexCoord = vTexCoord * vec2(1, vTileHeight) * vec2(vEnabled, vEnabled);
|
fTexCoord = vTexCoord * vec2(1, vTileHeight) * vec2(vEnabled, vEnabled);
|
||||||
})glsl";
|
})glsl";
|
||||||
|
|
||||||
constexpr ox::StringView spritefshadTmpl = bgfshadTmpl;
|
constexpr ox::CStringView spritefshadTmpl = R"glsl(
|
||||||
|
{}
|
||||||
|
out vec4 outColor;
|
||||||
|
in vec2 fTexCoord;
|
||||||
|
uniform sampler2D image;
|
||||||
|
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);
|
||||||
|
})glsl";;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static constexpr auto bgVertexRow(uint_t x, uint_t y) noexcept {
|
static constexpr auto bgVertexRow(uint_t x, uint_t y) noexcept {
|
||||||
@ -91,6 +103,7 @@ static void setSpriteBufferObject(
|
|||||||
float y,
|
float y,
|
||||||
uint_t textureRow,
|
uint_t textureRow,
|
||||||
uint_t flipX,
|
uint_t flipX,
|
||||||
|
uint_t priority,
|
||||||
float *vbo,
|
float *vbo,
|
||||||
GLuint *ebo) noexcept {
|
GLuint *ebo) noexcept {
|
||||||
// don't worry, this memcpy gets optimized to something much more ideal
|
// don't worry, this memcpy gets optimized to something much more ideal
|
||||||
@ -100,17 +113,19 @@ static void setSpriteBufferObject(
|
|||||||
y *= -ymod;
|
y *= -ymod;
|
||||||
x -= 1.f;
|
x -= 1.f;
|
||||||
y += 1.f - ymod;
|
y += 1.f - ymod;
|
||||||
const auto textureRowf = static_cast<float>(textureRow);
|
auto const prif = static_cast<float>(priority) * 0.1f;
|
||||||
const float L = flipX ? 1 : 0;
|
auto const textureRowf = static_cast<float>(textureRow);
|
||||||
const float R = flipX ? 0 : 1;
|
float const L = flipX ? 1 : 0;
|
||||||
const ox::Array<float, SpriteVertexVboLength> vertices {
|
float const R = flipX ? 0 : 1;
|
||||||
enabled, x, y, L, textureRowf + 1, // bottom left
|
ox::Array<float, SpriteVertexVboLength> const vertices {
|
||||||
enabled, x + xmod, y, R, textureRowf + 1, // bottom right
|
// vEnabled| vPosition | vTexCoord
|
||||||
enabled, x + xmod, y + ymod, R, textureRowf + 0, // top right
|
enabled, x, y, prif, L, textureRowf + 1, // bottom left
|
||||||
enabled, x, y + ymod, L, textureRowf + 0, // top left
|
enabled, x + xmod, y, prif, R, textureRowf + 1, // bottom right
|
||||||
|
enabled, x + xmod, y + ymod, prif, R, textureRowf + 0, // top right
|
||||||
|
enabled, x, y + ymod, prif, L, textureRowf + 0, // top left
|
||||||
};
|
};
|
||||||
memcpy(vbo, vertices.data(), sizeof(vertices));
|
memcpy(vbo, vertices.data(), sizeof(vertices));
|
||||||
const ox::Array<GLuint, SpriteVertexEboLength> elms {
|
ox::Array<GLuint, SpriteVertexEboLength> const 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,
|
||||||
};
|
};
|
||||||
@ -149,7 +164,7 @@ static void initSpriteBufferObjects(glutils::BufferSet &bs) noexcept {
|
|||||||
for (auto i = 0u; i < SpriteCount; ++i) {
|
for (auto i = 0u; i < SpriteCount; ++i) {
|
||||||
auto vbo = &bs.vertices[i * static_cast<std::size_t>(SpriteVertexVboLength)];
|
auto vbo = &bs.vertices[i * static_cast<std::size_t>(SpriteVertexVboLength)];
|
||||||
auto ebo = &bs.elements[i * static_cast<std::size_t>(SpriteVertexEboLength)];
|
auto ebo = &bs.elements[i * static_cast<std::size_t>(SpriteVertexEboLength)];
|
||||||
setSpriteBufferObject(i * SpriteVertexVboRows, 0, 0, 0, 0, false, vbo, ebo);
|
setSpriteBufferObject(i * SpriteVertexVboRows * BlocksPerSprite, 0, 0, 0, 0, false, 0, vbo, ebo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +185,9 @@ static void initBackgroundBufferObjects(glutils::BufferSet &bg) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initSpritesBufferset(GLuint shader, glutils::BufferSet &bs) noexcept {
|
static void initSpritesBufferset(Context &ctx) noexcept {
|
||||||
|
auto const shader = ctx.spriteShader.id;
|
||||||
|
auto &bs = ctx.spriteBlocks;
|
||||||
// vao
|
// vao
|
||||||
bs.vao = glutils::generateVertexArrayObject();
|
bs.vao = glutils::generateVertexArrayObject();
|
||||||
glBindVertexArray(bs.vao);
|
glBindVertexArray(bs.vao);
|
||||||
@ -181,17 +198,20 @@ static void initSpritesBufferset(GLuint shader, glutils::BufferSet &bs) noexcept
|
|||||||
glutils::sendVbo(bs);
|
glutils::sendVbo(bs);
|
||||||
glutils::sendEbo(bs);
|
glutils::sendEbo(bs);
|
||||||
// vbo layout
|
// vbo layout
|
||||||
|
// in float vEnabled;
|
||||||
auto const enabledAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vEnabled"));
|
auto const enabledAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vEnabled"));
|
||||||
glEnableVertexAttribArray(enabledAttr);
|
glEnableVertexAttribArray(enabledAttr);
|
||||||
glVertexAttribPointer(enabledAttr, 1, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float), nullptr);
|
glVertexAttribPointer(enabledAttr, 1, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float), nullptr);
|
||||||
|
// in vec3 vPosition;
|
||||||
auto const posAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vPosition"));
|
auto const posAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vPosition"));
|
||||||
glEnableVertexAttribArray(posAttr);
|
glEnableVertexAttribArray(posAttr);
|
||||||
glVertexAttribPointer(posAttr, 2, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float),
|
glVertexAttribPointer(posAttr, 3, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float),
|
||||||
std::bit_cast<void*>(uintptr_t{1 * sizeof(float)}));
|
std::bit_cast<void*>(uintptr_t{1 * sizeof(float)}));
|
||||||
|
// in vec2 vTexCoord;
|
||||||
auto const texCoordAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vTexCoord"));
|
auto const texCoordAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vTexCoord"));
|
||||||
glEnableVertexAttribArray(texCoordAttr);
|
glEnableVertexAttribArray(texCoordAttr);
|
||||||
glVertexAttribPointer(texCoordAttr, 2, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float),
|
glVertexAttribPointer(texCoordAttr, 2, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float),
|
||||||
std::bit_cast<void*>(uintptr_t{3 * sizeof(float)}));
|
std::bit_cast<void*>(uintptr_t{4 * sizeof(float)}));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initBackgroundBufferset(
|
static void initBackgroundBufferset(
|
||||||
@ -347,11 +367,86 @@ static void loadSpriteTexture(
|
|||||||
ctx.spriteBlocks.tex = createTexture(w, h, pixels);
|
ctx.spriteBlocks.tex = createTexture(w, h, pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setSprite(
|
||||||
|
Context &ctx,
|
||||||
|
uint_t const idx,
|
||||||
|
Sprite const&s) noexcept {
|
||||||
|
// Tonc Table 8.4
|
||||||
|
static constexpr ox::Array<ox::Vec<uint_t>, 12> dimensions{
|
||||||
|
// col 0
|
||||||
|
{1, 1}, // 0, 0
|
||||||
|
{2, 2}, // 0, 1
|
||||||
|
{4, 4}, // 0, 2
|
||||||
|
{8, 8}, // 0, 3
|
||||||
|
// col 1
|
||||||
|
{2, 1}, // 1, 0
|
||||||
|
{4, 1}, // 1, 1
|
||||||
|
{4, 2}, // 1, 2
|
||||||
|
{8, 4}, // 1, 3
|
||||||
|
// col 2
|
||||||
|
{1, 1}, // 2, 0
|
||||||
|
{1, 4}, // 2, 1
|
||||||
|
{2, 4}, // 2, 2
|
||||||
|
{4, 8}, // 2, 3
|
||||||
|
};
|
||||||
|
oxAssert(idx < ctx.spriteStates.size(), "overflow");
|
||||||
|
auto const dim = dimensions[(s.spriteShape << 2) | s.spriteSize];
|
||||||
|
auto const uX = static_cast<int>(s.x) % 255;
|
||||||
|
auto const uY = static_cast<int>(s.y + 8) % 255 - 8;
|
||||||
|
oxAssert(1 < ctx.spriteBlocks.vertices.size(), "vbo overflow");
|
||||||
|
oxAssert(1 < ctx.spriteBlocks.elements.size(), "ebo overflow");
|
||||||
|
constexpr auto spriteVboSz = renderer::BlocksPerSprite * renderer::SpriteVertexVboLength;
|
||||||
|
constexpr auto spriteEboSz = renderer::BlocksPerSprite * renderer::SpriteVertexEboLength;
|
||||||
|
auto const vboBase = spriteVboSz * idx;
|
||||||
|
auto const eboBase = spriteEboSz * idx;
|
||||||
|
auto i = 0u;
|
||||||
|
const auto set = [&](int xIt, int yIt, bool enabled) {
|
||||||
|
auto const fX = static_cast<float>(uX + xIt * 8) / 8;
|
||||||
|
auto const fY = static_cast<float>(uY + yIt * 8) / 8;
|
||||||
|
auto const vboIdx = vboBase + renderer::SpriteVertexVboLength * i;
|
||||||
|
auto const eboIdx = eboBase + renderer::SpriteVertexEboLength * i;
|
||||||
|
oxAssert(vboIdx < ctx.spriteBlocks.vertices.size(), "vbo overflow");
|
||||||
|
oxAssert(eboIdx < ctx.spriteBlocks.elements.size(), "ebo overflow");
|
||||||
|
auto const vbo = &ctx.spriteBlocks.vertices[vboIdx];
|
||||||
|
auto const ebo = &ctx.spriteBlocks.elements[eboIdx];
|
||||||
|
renderer::setSpriteBufferObject(
|
||||||
|
static_cast<uint_t>(vboIdx),
|
||||||
|
enabled,
|
||||||
|
fX,
|
||||||
|
fY,
|
||||||
|
s.tileIdx + i,
|
||||||
|
s.flipX,
|
||||||
|
s.priority,
|
||||||
|
vbo,
|
||||||
|
ebo);
|
||||||
|
++i;
|
||||||
|
};
|
||||||
|
if (!s.flipX) {
|
||||||
|
for (auto yIt = 0; yIt < static_cast<int>(dim.y); ++yIt) {
|
||||||
|
for (auto xIt = 0u; xIt < dim.x; ++xIt) {
|
||||||
|
set(static_cast<int>(xIt), static_cast<int>(yIt), s.enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (auto yIt = 0u; yIt < dim.y; ++yIt) {
|
||||||
|
for (auto xIt = dim.x - 1; xIt < ~0u; --xIt) {
|
||||||
|
set(static_cast<int>(xIt), static_cast<int>(yIt), s.enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear remaining blocks in the sprite
|
||||||
|
for (; i < BlocksPerSprite; ++i) {
|
||||||
|
set(0, 0, false);
|
||||||
|
}
|
||||||
|
ctx.spriteBlocks.updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error initGfx(
|
ox::Error initGfx(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
InitParams const&initParams) noexcept {
|
InitParams const&initParams) noexcept {
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
const auto bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion);
|
const auto bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion);
|
||||||
@ -364,7 +459,7 @@ ox::Error initGfx(
|
|||||||
for (auto &bg : ctx.cbbs) {
|
for (auto &bg : ctx.cbbs) {
|
||||||
initBackgroundBufferset(ctx.bgShader, bg);
|
initBackgroundBufferset(ctx.bgShader, bg);
|
||||||
}
|
}
|
||||||
initSpritesBufferset(ctx.spriteShader, ctx.spriteBlocks);
|
renderer::initSpritesBufferset(ctx);
|
||||||
if (initParams.glInstallDrawer) {
|
if (initParams.glInstallDrawer) {
|
||||||
turbine::gl::addDrawer(ctx.turbineCtx, &ctx.drawer);
|
turbine::gl::addDrawer(ctx.turbineCtx, &ctx.drawer);
|
||||||
}
|
}
|
||||||
@ -497,77 +592,21 @@ void clearTileLayer(Context &ctx, uint_t bgIdx) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void hideSprite(Context &ctx, uint_t idx) noexcept {
|
void hideSprite(Context &ctx, uint_t idx) noexcept {
|
||||||
auto vbo = &ctx.spriteBlocks.vertices[idx * renderer::SpriteVertexVboLength];
|
auto &s = ctx.spriteStates[idx];
|
||||||
auto ebo = &ctx.spriteBlocks.elements[idx * renderer::SpriteVertexEboLength];
|
s.enabled = false;
|
||||||
renderer::setSpriteBufferObject(
|
renderer::setSprite(ctx, idx, s);
|
||||||
idx * renderer::SpriteVertexVboRows, 0, 0, 0, 0, false, vbo, ebo);
|
|
||||||
ctx.spriteBlocks.updated = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSprite(
|
void showSprite(Context &ctx, uint_t idx) noexcept {
|
||||||
Context &ctx,
|
auto &s = ctx.spriteStates[idx];
|
||||||
uint_t idx,
|
s.enabled = true;
|
||||||
int x,
|
renderer::setSprite(ctx, idx, s);
|
||||||
int y,
|
}
|
||||||
uint_t tileIdx,
|
|
||||||
uint_t spriteShape,
|
void setSprite(Context &ctx, uint_t idx, Sprite const&sprite) noexcept {
|
||||||
uint_t spriteSize,
|
auto &s = ctx.spriteStates[idx];
|
||||||
uint_t flipX) noexcept {
|
s = sprite;
|
||||||
//oxTracef("nostalgia::core::gfx::gl", "setSprite(ctx, {}, {}, {}, {}, {}, {}, {})",
|
renderer::setSprite(ctx, idx, s);
|
||||||
// idx, x, y, tileIdx, spriteShape, spriteSize, flipX);
|
|
||||||
// Tonc Table 8.4
|
|
||||||
static constexpr ox::Array<ox::Vec<uint_t>, 12> dimensions{
|
|
||||||
// col 0
|
|
||||||
{1, 1}, // 0, 0
|
|
||||||
{2, 2}, // 0, 1
|
|
||||||
{4, 4}, // 0, 2
|
|
||||||
{8, 8}, // 0, 3
|
|
||||||
// col 1
|
|
||||||
{2, 1}, // 1, 0
|
|
||||||
{4, 1}, // 1, 1
|
|
||||||
{4, 2}, // 1, 2
|
|
||||||
{8, 4}, // 1, 3
|
|
||||||
// col 2
|
|
||||||
{1, 1}, // 2, 0
|
|
||||||
{1, 4}, // 2, 1
|
|
||||||
{2, 4}, // 2, 2
|
|
||||||
{4, 8}, // 2, 3
|
|
||||||
};
|
|
||||||
const auto dim = dimensions[(spriteShape << 2) | spriteSize];
|
|
||||||
const auto uX = static_cast<int>(x) % 255;
|
|
||||||
const auto uY = static_cast<int>(y + 8) % 255 - 8;
|
|
||||||
auto i = 0u;
|
|
||||||
const auto set = [&](int xIt, int yIt) {
|
|
||||||
const auto fX = static_cast<float>(uX + xIt * 8) / 8;
|
|
||||||
const auto fY = static_cast<float>(uY + yIt * 8) / 8;
|
|
||||||
const auto cidx = idx + i;
|
|
||||||
auto vbo = &ctx.spriteBlocks.vertices[cidx * renderer::SpriteVertexVboLength];
|
|
||||||
auto ebo = &ctx.spriteBlocks.elements[cidx * renderer::SpriteVertexEboLength];
|
|
||||||
renderer::setSpriteBufferObject(
|
|
||||||
cidx * renderer::SpriteVertexVboRows,
|
|
||||||
1,
|
|
||||||
fX,
|
|
||||||
fY,
|
|
||||||
tileIdx + i,
|
|
||||||
flipX,
|
|
||||||
vbo,
|
|
||||||
ebo);
|
|
||||||
++i;
|
|
||||||
};
|
|
||||||
if (!flipX) {
|
|
||||||
for (auto yIt = 0; yIt < static_cast<int>(dim.y); ++yIt) {
|
|
||||||
for (auto xIt = 0u; xIt < dim.x; ++xIt) {
|
|
||||||
set(static_cast<int>(xIt), static_cast<int>(yIt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (auto yIt = 0u; yIt < dim.y; ++yIt) {
|
|
||||||
for (auto xIt = dim.x - 1; xIt < ~0u; --xIt) {
|
|
||||||
set(static_cast<int>(xIt), static_cast<int>(yIt));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.spriteBlocks.updated = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTile(
|
void setTile(
|
||||||
@ -605,7 +644,8 @@ ox::Size drawSize(int scale) noexcept {
|
|||||||
|
|
||||||
void draw(core::Context &ctx, ox::Size const&renderSz) noexcept {
|
void draw(core::Context &ctx, ox::Size const&renderSz) noexcept {
|
||||||
glViewport(0, 0, renderSz.width, renderSz.height);
|
glViewport(0, 0, renderSz.width, renderSz.height);
|
||||||
glutils::clearScreen();
|
glClearColor(0, 0, 0, 1);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
renderer::drawBackgrounds(ctx, renderSz);
|
renderer::drawBackgrounds(ctx, renderSz);
|
||||||
if (ctx.spriteBlocks.tex) {
|
if (ctx.spriteBlocks.tex) {
|
||||||
renderer::drawSprites(ctx, renderSz);
|
renderer::drawSprites(ctx, renderSz);
|
||||||
|
@ -22,10 +22,11 @@ constexpr uint64_t BgVertexVboRows = 4;
|
|||||||
constexpr uint64_t BgVertexVboRowLength = 5;
|
constexpr uint64_t BgVertexVboRowLength = 5;
|
||||||
constexpr uint64_t BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength;
|
constexpr uint64_t BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength;
|
||||||
constexpr uint64_t BgVertexEboLength = 6;
|
constexpr uint64_t BgVertexEboLength = 6;
|
||||||
constexpr uint64_t SpriteVertexVboRows = 256;
|
constexpr uint64_t SpriteVertexVboRows = 4;
|
||||||
constexpr uint64_t SpriteVertexVboRowLength = 5;
|
constexpr uint64_t SpriteVertexVboRowLength = 6;
|
||||||
constexpr uint64_t SpriteVertexVboLength = SpriteVertexVboRows * SpriteVertexVboRowLength;
|
constexpr uint64_t SpriteVertexVboLength = SpriteVertexVboRows * SpriteVertexVboRowLength;
|
||||||
constexpr uint64_t SpriteVertexEboLength = 6;
|
constexpr uint64_t SpriteVertexEboLength = 6;
|
||||||
|
constexpr uint64_t BlocksPerSprite = 64;
|
||||||
|
|
||||||
struct CBB: public glutils::BufferSet {
|
struct CBB: public glutils::BufferSet {
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
@ -38,8 +39,8 @@ struct CBB: public glutils::BufferSet {
|
|||||||
struct SpriteBlockset: public glutils::BufferSet {
|
struct SpriteBlockset: public glutils::BufferSet {
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
constexpr SpriteBlockset() noexcept {
|
constexpr SpriteBlockset() noexcept {
|
||||||
vertices.resize(SpriteCount * SpriteVertexVboLength);
|
vertices.resize(SpriteCount * SpriteVertexVboLength * BlocksPerSprite);
|
||||||
elements.resize(SpriteCount * SpriteVertexEboLength);
|
elements.resize(SpriteCount * SpriteVertexEboLength * BlocksPerSprite);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,10 +49,6 @@ struct Background {
|
|||||||
unsigned cbbIdx = 0;
|
unsigned cbbIdx = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Sprite {
|
|
||||||
bool enabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Drawer: public turbine::gl::Drawer {
|
class Drawer: public turbine::gl::Drawer {
|
||||||
private:
|
private:
|
||||||
Context &m_ctx;
|
Context &m_ctx;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user