mirror of https://github.com/mgba-emu/mgba.git
GBA Video: Emulate sprite cycle limits in OpenGL renderer (fixes #1635)
This commit is contained in:
parent
e83a371e50
commit
e11dc3fad0
1
CHANGES
1
CHANGES
|
@ -46,6 +46,7 @@ Emulation fixes:
|
|||
- GBA Video: Don't draw sprites using unmapped VRAM in GL renderer (fixes mgba.io/i/1865)
|
||||
- GBA Video: Implement green swap (fixes mgba.io/i/1609)
|
||||
- GBA Video: Fix rare regression blending semitransparent sprites (fixes mgba.io/i/1876)
|
||||
- GBA Video: Emulate sprite cycle limits in OpenGL renderer (fixes mgba.io/i/1635)
|
||||
- SM83: Emulate HALT bug
|
||||
Other fixes:
|
||||
- 3DS: Redo video sync to be more precise
|
||||
|
|
|
@ -109,6 +109,7 @@ enum {
|
|||
GBA_GL_OBJ_DIMS,
|
||||
GBA_GL_OBJ_OBJWIN,
|
||||
GBA_GL_OBJ_MOSAIC,
|
||||
GBA_GL_OBJ_CYCLES,
|
||||
|
||||
GBA_GL_WIN_DISPCNT = 2,
|
||||
GBA_GL_WIN_BLEND,
|
||||
|
@ -123,7 +124,7 @@ enum {
|
|||
GBA_GL_FINALIZE_BACKDROP,
|
||||
GBA_GL_FINALIZE_BACKDROPFLAGS,
|
||||
|
||||
GBA_GL_UNIFORM_MAX = 12
|
||||
GBA_GL_UNIFORM_MAX = 14
|
||||
};
|
||||
|
||||
struct GBAVideoGLShader {
|
||||
|
@ -183,6 +184,7 @@ struct GBAVideoGLRenderer {
|
|||
} winN[2];
|
||||
|
||||
GLint winNHistory[2][GBA_VIDEO_VERTICAL_PIXELS * 4];
|
||||
GLint spriteCycles[GBA_VIDEO_VERTICAL_PIXELS];
|
||||
|
||||
GBAWindowControl winout;
|
||||
GBAWindowControl objwin;
|
||||
|
@ -200,4 +202,4 @@ void GBAVideoGLRendererSetScale(struct GBAVideoGLRenderer* renderer, int scale);
|
|||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -413,6 +413,7 @@ static const struct GBAVideoGLUniform _uniformsObj[] = {
|
|||
{ "dims", GBA_GL_OBJ_DIMS, },
|
||||
{ "objwin", GBA_GL_OBJ_OBJWIN, },
|
||||
{ "mosaic", GBA_GL_OBJ_MOSAIC, },
|
||||
{ "cyclesRemaining", GBA_GL_OBJ_CYCLES, },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -428,6 +429,7 @@ static const char* const _renderObj =
|
|||
"uniform ivec4 dims;\n"
|
||||
"uniform ivec4 objwin;\n"
|
||||
"uniform ivec4 mosaic;\n"
|
||||
"uniform int cyclesRemaining[160];\n"
|
||||
"OUT(0) out vec4 color;\n"
|
||||
"OUT(1) out ivec4 flags;\n"
|
||||
"OUT(2) out ivec4 window;\n"
|
||||
|
@ -443,6 +445,9 @@ static const char* const _renderObj =
|
|||
" int x = dims.z - int(incoord.x) - 1;\n"
|
||||
" incoord.x = float(clamp(dims.z - x + (mosaic.z + x) % -mosaic.x - 1, 0, dims.z - 1));\n"
|
||||
" }\n"
|
||||
" if (cyclesRemaining[int(incoord.y) + mosaic.w] <= 0) {\n"
|
||||
" discard;\n"
|
||||
" }\n"
|
||||
" if (mosaic.y > 1) {\n"
|
||||
" int y = int(incoord.y);\n"
|
||||
" incoord.y = float(clamp(y - (mosaic.w + y) % mosaic.y, 0, dims.w - 1));\n"
|
||||
|
@ -1383,6 +1388,11 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
|
|||
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
int spriteCyclesRemaining = GBARegisterDISPCNTIsHblankIntervalFree(glRenderer->dispcnt) ? OBJ_HBLANK_FREE_LENGTH : OBJ_LENGTH;
|
||||
for (i = 0; i < GBA_VIDEO_VERTICAL_PIXELS; ++i) {
|
||||
glRenderer->spriteCycles[i] = spriteCyclesRemaining;
|
||||
}
|
||||
}
|
||||
|
||||
if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
|
||||
|
@ -1428,6 +1438,24 @@ void _drawScanlines(struct GBAVideoGLRenderer* glRenderer, int y) {
|
|||
}
|
||||
|
||||
GBAVideoGLRendererDrawSprite(glRenderer, &sprite->obj, y, sprite->y);
|
||||
|
||||
int startY = sprite->y;
|
||||
int endY = sprite->endY;
|
||||
|
||||
if (endY >= 256) {
|
||||
startY -= 256;
|
||||
endY -= 256;
|
||||
}
|
||||
if (startY < glRenderer->firstY) {
|
||||
startY = glRenderer->firstY;
|
||||
}
|
||||
if (endY > y) {
|
||||
endY = y;
|
||||
}
|
||||
int j;
|
||||
for (j = startY; j <= endY; ++j) {
|
||||
glRenderer->spriteCycles[j] -= sprite->cycles;
|
||||
}
|
||||
}
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
@ -1668,6 +1696,7 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB
|
|||
glUniform4i(uniforms[GBA_GL_OBJ_INFLAGS], GBAObjAttributesCGetPriority(sprite->c),
|
||||
(renderer->target1Obj || GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT) | (renderer->target2Obj * 2) | (renderer->blendEffect * 4),
|
||||
renderer->blda, GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_SEMITRANSPARENT);
|
||||
glUniform1iv(uniforms[GBA_GL_OBJ_CYCLES], GBA_VIDEO_VERTICAL_PIXELS, renderer->spriteCycles);
|
||||
if (GBAObjAttributesAIsTransformed(sprite->a)) {
|
||||
struct GBAOAMMatrix mat;
|
||||
LOAD_16(mat.a, 0, &renderer->d.oam->mat[GBAObjAttributesBGetMatIndex(sprite->b)].a);
|
||||
|
@ -1705,7 +1734,7 @@ void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GB
|
|||
}
|
||||
glUniform4i(uniforms[GBA_GL_OBJ_MOSAIC], mosaicH, GBAMosaicControlGetObjV(renderer->mosaic) + 1, x, spriteY);
|
||||
} else {
|
||||
glUniform4i(uniforms[GBA_GL_OBJ_MOSAIC], 0, 0, 0, 0);
|
||||
glUniform4i(uniforms[GBA_GL_OBJ_MOSAIC], 0, 0, x, spriteY);
|
||||
}
|
||||
glStencilFunc(GL_ALWAYS, 1, 1);
|
||||
if (GBAObjAttributesAGetMode(sprite->a) != OBJ_MODE_OBJWIN || GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt)) {
|
||||
|
|
Loading…
Reference in New Issue