GBA Video: Mode 2 cubic interpolation

This commit is contained in:
Vicki Pfau 2019-05-11 15:50:50 -07:00
parent 8a6ea929d2
commit 68f0176ee4
2 changed files with 72 additions and 18 deletions

View File

@ -58,7 +58,7 @@ struct GBAVideoGLBackground {
int32_t refx;
int32_t refy;
struct GBAVideoGLAffine affine[2];
struct GBAVideoGLAffine affine[4];
};
struct GBAVideoGLRenderer {
@ -98,6 +98,8 @@ struct GBAVideoGLRenderer {
GBAMosaicControl mosaic;
int firstAffine;
int scale;
};

View File

@ -138,11 +138,10 @@ static const char* const _renderMode2 =
"uniform int screenBase;\n"
"uniform int charBase;\n"
"uniform int size;\n"
"uniform ivec2 offset;\n"
"uniform ivec2 oldOffset;\n"
"uniform mat2x2 transform;\n"
"uniform mat2x2 oldTransform;\n"
"uniform int firstD;\n"
"uniform ivec2[4] offset;\n"
"uniform ivec2[4] transform;\n"
"precision highp float;\n"
"precision highp int;\n"
"vec4 fetchTile(ivec2 coord);\n"
@ -162,13 +161,21 @@ static const char* const _renderMode2 =
" color.a = 0.;\n"
" }\n"
" return color;\n"
"}"
"}\n"
"vec2 interpolate(ivec2 arr[4], float x) {\n"
" float x1m = 1. - x;\n"
" return x1m * x1m * x1m * arr[0] +"
" 3 * x1m * x1m * x * arr[1] +"
" 3 * x1m * x * x * arr[2] +"
" x * x * x * arr[3];\n"
"}\n"
"void main() {\n"
" float y = fract(texCoord.y);\n"
" float lin = y / ceil(y);\n"
" vec2 mixedTransform = mix(oldTransform[0], transform[0], lin);\n"
" vec2 mixedOffset = mix(oldOffset, offset, lin);\n"
" float lin = 0.5 - y / ceil(y) * 0.25;\n"
" vec2 mixedTransform = interpolate(transform, lin);\n"
" vec2 mixedOffset = interpolate(offset, lin);\n"
" gl_FragColor = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n"
"}";
@ -192,7 +199,7 @@ static const char* const _composite =
" ivec3 outflags = ivec3(0, 0, 0);\n"
" if (inflags.x < oldFlags.x) {\n"
" outflags = inflags;\n"
" if ((inflags.y & 1) == 1 && (oldFlags.y & 2) == 2) {\n"
" if (inflags.z == 1 && (inflags.y & 1) == 1 && (oldFlags.y & 2) == 2) {\n"
" vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n"
" pix *= blend.x;\n"
" pix += oldpix * blend.y;\n"
@ -369,6 +376,7 @@ void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
glRenderer->paletteDirty = true;
glRenderer->vramDirty = 0xFFFFFF;
glRenderer->firstAffine = -1;
}
void GBAVideoGLRendererWriteVRAM(struct GBAVideoRenderer* renderer, uint32_t address) {
@ -633,6 +641,23 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
if (glRenderer->firstAffine < 0) {
memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[2].affine[2], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[3].affine[2], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
glRenderer->firstAffine = y;
} else if (y - glRenderer->firstAffine == 1) {
memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
}
} else {
glRenderer->firstAffine = -1;
}
unsigned priority;
for (priority = 4; priority--;) {
if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
@ -674,6 +699,10 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
}
if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[3].affine[3], &glRenderer->bg[3].affine[2], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[2].affine[2], &glRenderer->bg[2].affine[1], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[3].affine[2], &glRenderer->bg[3].affine[1], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[2].affine[1], &glRenderer->bg[2].affine[0], sizeof(struct GBAVideoGLAffine));
memcpy(&glRenderer->bg[3].affine[1], &glRenderer->bg[3].affine[0], sizeof(struct GBAVideoGLAffine));
@ -685,7 +714,12 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
}
void GBAVideoGLRendererFinishFrame(struct GBAVideoRenderer* renderer) {
UNUSED(renderer);
struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
glRenderer->firstAffine = -1;
glRenderer->bg[2].affine[0].sx = glRenderer->bg[2].refx;
glRenderer->bg[2].affine[0].sy = glRenderer->bg[2].refy;
glRenderer->bg[3].affine[0].sx = glRenderer->bg[3].refx;
glRenderer->bg[3].affine[0].sy = glRenderer->bg[3].refy;
glFlush();
}
@ -845,14 +879,32 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer,
glUniform1i(3, background->screenBase);
glUniform1i(4, background->charBase);
glUniform1i(5, background->size);
glUniform2i(6, background->affine[0].sx, background->affine[0].sy);
glUniformMatrix2fv(8, 1, GL_FALSE, (GLfloat[]) { background->affine[0].dx, background->affine[0].dy, background->affine[0].dmx, background->affine[0].dmy });
if (renderer->scale > 1) {
glUniform2i(7, background->affine[1].sx, background->affine[1].sy);
glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->affine[1].dx, background->affine[1].dy, background->affine[1].dmx, background->affine[1].dmy });
glUniform2iv(6, 4, (GLint[]) {
background->affine[0].sx, background->affine[0].sy,
background->affine[1].sx, background->affine[1].sy,
background->affine[2].sx, background->affine[2].sy,
background->affine[3].sx, background->affine[3].sy,
});
glUniform2iv(10, 4, (GLint[]) {
background->affine[0].dx, background->affine[0].dy,
background->affine[1].dx, background->affine[1].dy,
background->affine[2].dx, background->affine[2].dy,
background->affine[3].dx, background->affine[3].dy,
});
} else {
glUniform2i(7, background->affine[0].sx, background->affine[0].sy);
glUniformMatrix2fv(9, 1, GL_FALSE, (GLfloat[]) { background->affine[0].dx, background->affine[0].dy, background->affine[0].dmx, background->affine[0].dmy });
glUniform2iv(6, 4, (GLint[]) {
background->affine[0].sx, background->affine[0].sy,
background->affine[0].sx, background->affine[0].sy,
background->affine[0].sx, background->affine[0].sy,
background->affine[0].sx, background->affine[0].sy,
});
glUniform2iv(10, 4, (GLint[]) {
background->affine[0].dx, background->affine[0].dy,
background->affine[0].dx, background->affine[0].dy,
background->affine[0].dx, background->affine[0].dy,
background->affine[0].dx, background->affine[0].dy,
});
}
glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
glEnableVertexAttribArray(0);