GBA Video: Batch affine modifications
@@ -62,7 +62,7 @@ uint16_t y;
int32_t refx; int32_t refy; - struct GBAVideoGLAffine affine[4]; + struct GBAVideoGLAffine affine; }; enum {@@ -79,6 +79,8 @@ GBA_GL_TEX_OBJ_FLAGS,
GBA_GL_TEX_BACKDROP_COLOR, GBA_GL_TEX_BACKDROP_FLAGS, GBA_GL_TEX_WINDOW, + GBA_GL_TEX_AFFINE_2, + GBA_GL_TEX_AFFINE_3, GBA_GL_TEX_MAX };@@ -94,7 +96,6 @@ GBA_GL_BG_SIZE,
GBA_GL_BG_OFFSET, GBA_GL_BG_INFLAGS, GBA_GL_BG_TRANSFORM, - GBA_GL_BG_RANGE, GBA_GL_BG_MOSAIC, GBA_GL_OBJ_VRAM = 2,@@ -130,6 +131,7 @@
uint32_t* temporaryBuffer; struct GBAVideoGLBackground bg[4]; + struct GBAVideoGLAffine affine[2][GBA_VIDEO_VERTICAL_PIXELS]; int oamMax; bool oamDirty;
@@ -181,7 +181,6 @@ { "size", GBA_GL_BG_SIZE, },
{ "inflags", GBA_GL_BG_INFLAGS, }, { "offset", GBA_GL_BG_OFFSET, }, { "transform", GBA_GL_BG_TRANSFORM, }, - { "range", GBA_GL_BG_RANGE, }, { "mosaic", GBA_GL_BG_MOSAIC, }, { 0 } };@@ -193,6 +192,25 @@ " 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 loadAffine(int y, out ivec2 mat[4], out ivec2 aff[4]) {\n" + " mat[2] = texelFetch(transform, ivec2(0, y), 0).xz;\n" + " ivec4 splitOffset[4];\n" + " splitOffset[2] = texelFetch(transform, ivec2(1, y), 0);\n" + + " mat[0] = texelFetch(transform, ivec2(0, y - 2), 0).xz;\n" + " mat[1] = texelFetch(transform, ivec2(0, y - 1), 0).xz;\n" + " mat[3] = texelFetch(transform, ivec2(0, y + 1), 0).xz;\n" + + " splitOffset[0] = texelFetch(transform, ivec2(1, y - 2), 0);\n" + " splitOffset[1] = texelFetch(transform, ivec2(1, y - 1), 0);\n" + " splitOffset[3] = texelFetch(transform, ivec2(1, y + 1), 0);\n" + + " aff[0] = (splitOffset[0].xz & 0xFFFF) + (splitOffset[0].yw << 16);\n" + " aff[1] = (splitOffset[1].xz & 0xFFFF) + (splitOffset[1].yw << 16);\n" + " aff[2] = (splitOffset[2].xz & 0xFFFF) + (splitOffset[2].yw << 16);\n" + " aff[3] = (splitOffset[3].xz & 0xFFFF) + (splitOffset[3].yw << 16);\n" "}\n"; static const char* const _renderMode2 =@@ -203,9 +221,7 @@ "uniform int screenBase;\n"
"uniform int charBase;\n" "uniform int size;\n" "uniform ivec4 inflags;\n" - "uniform ivec2[4] offset;\n" - "uniform ivec2[4] transform;\n" - "uniform vec2 range;\n" + "uniform isampler2D transform;\n" "uniform ivec2 mosaic;\n" "out vec4 color;\n" "out vec4 flags;\n"@@ -215,6 +231,7 @@ "precision highp int;\n"
"vec4 fetchTile(ivec2 coord);\n" "vec2 interpolate(ivec2 arr[4], float x);\n" + "void loadAffine(int y, out ivec2 mat[4], out ivec2 aff[4]);\n" "vec4 renderTile(ivec2 coord) {\n" " int map = (coord.x >> 11) + (((coord.y >> 7) & 0x7F0) << size);\n"@@ -234,6 +251,9 @@ " return color;\n"
"}\n" "void main() {\n" + " ivec2 mat[4];\n" + " ivec2 offset[4];\n" + " loadAffine(int(texCoord.y), mat, offset);\n" " vec2 coord = texCoord;\n" " if (mosaic.x > 1) {\n" " coord.x -= mod(coord.x, mosaic.x);\n"@@ -241,9 +261,9 @@ " }\n"
" if (mosaic.y > 1) {\n" " coord.y -= mod(coord.y, mosaic.y);\n" " }\n" - " float y = coord.y - range.x;\n" - " float lin = 0.5 - y / range.y * 0.25;\n" - " vec2 mixedTransform = interpolate(transform, lin);\n" + " float y = fract(coord.y);\n" + " float lin = 0.5 + y * 0.25;\n" + " vec2 mixedTransform = interpolate(mat, lin);\n" " vec2 mixedOffset = interpolate(offset, lin);\n" " color = fetchTile(ivec2(mixedTransform * coord.x + mixedOffset));\n" " flags = inflags / flagCoeff;\n"@@ -258,7 +278,6 @@ { "size", GBA_GL_BG_SIZE, },
{ "inflags", GBA_GL_BG_INFLAGS, }, { "offset", GBA_GL_BG_OFFSET, }, { "transform", GBA_GL_BG_TRANSFORM, }, - { "range", GBA_GL_BG_RANGE, }, { "mosaic", GBA_GL_BG_MOSAIC, }, { 0 } };@@ -269,9 +288,7 @@ "uniform sampler2D vram;\n"
"uniform int charBase;\n" "uniform ivec2 size;\n" "uniform ivec4 inflags;\n" - "uniform ivec2[4] offset;\n" - "uniform ivec2[4] transform;\n" - "uniform vec2 range;\n" + "uniform isampler2D transform;\n" "uniform ivec2 mosaic;\n" "out vec4 color;\n" "out vec4 flags;\n"@@ -280,8 +297,12 @@ "precision highp float;\n"
"precision highp int;\n" "vec2 interpolate(ivec2 arr[4], float x);\n" + "void loadAffine(int y, out ivec2 mat[4], out ivec2 aff[4]);\n" "void main() {\n" + " ivec2 mat[4];\n" + " ivec2 offset[4];\n" + " loadAffine(int(texCoord.y), mat, offset);\n" " vec2 incoord = texCoord;\n" " if (mosaic.x > 1) {\n" " incoord.x -= mod(incoord.x, mosaic.x);\n"@@ -289,9 +310,9 @@ " }\n"
" if (mosaic.y > 1) {\n" " incoord.y -= mod(incoord.y, mosaic.y);\n" " }\n" - " float y = incoord.y - range.x;\n" - " float lin = 0.5 - y / range.y * 0.25;\n" - " vec2 mixedTransform = interpolate(transform, lin);\n" + " float y = fract(incoord.y);\n" + " float lin = 0.5 + y * 0.25;\n" + " vec2 mixedTransform = interpolate(mat, lin);\n" " vec2 mixedOffset = interpolate(offset, lin);\n" " ivec2 coord = ivec2(mixedTransform * incoord.x + mixedOffset);\n" " if (coord.x < 0 || coord.x >= (size.x << 8)) {\n"@@ -317,7 +338,6 @@ { "size", GBA_GL_BG_SIZE, },
{ "inflags", GBA_GL_BG_INFLAGS, }, { "offset", GBA_GL_BG_OFFSET, }, { "transform", GBA_GL_BG_TRANSFORM, }, - { "range", GBA_GL_BG_RANGE, }, { "mosaic", GBA_GL_BG_MOSAIC, }, { 0 } };@@ -329,9 +349,7 @@ "uniform sampler2D palette;\n"
"uniform int charBase;\n" "uniform ivec2 size;\n" "uniform ivec4 inflags;\n" - "uniform ivec2[4] offset;\n" - "uniform ivec2[4] transform;\n" - "uniform vec2 range;\n" + "uniform isampler2D transform;\n" "uniform ivec2 mosaic;\n" "out vec4 color;\n" "out vec4 flags;\n"@@ -340,8 +358,12 @@ "precision highp float;\n"
"precision highp int;\n" "vec2 interpolate(ivec2 arr[4], float x);\n" + "void loadAffine(int y, out ivec2 mat[4], out ivec2 aff[4]);\n" "void main() {\n" + " ivec2 mat[4];\n" + " ivec2 offset[4];\n" + " loadAffine(int(texCoord.y), mat, offset);\n" " vec2 incoord = texCoord;\n" " if (mosaic.x > 1) {\n" " incoord.x -= mod(incoord.x, mosaic.x);\n"@@ -349,9 +371,9 @@ " }\n"
" if (mosaic.y > 1) {\n" " incoord.y -= mod(incoord.y, mosaic.y);\n" " }\n" - " float y = incoord.y - range.x;\n" - " float lin = 0.5 - y / range.y * 0.25;\n" - " vec2 mixedTransform = interpolate(transform, lin);\n" + " float y = fract(incoord.y);\n" + " float lin = 0.5 + y * 0.25;\n" + " vec2 mixedTransform = interpolate(mat, lin);\n" " vec2 mixedOffset = interpolate(offset, lin);\n" " ivec2 coord = ivec2(mixedTransform * incoord.x + mixedOffset);\n" " if (coord.x < 0 || coord.x >= (size.x << 8)) {\n"@@ -615,6 +637,19 @@ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0); + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_AFFINE_2]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16I, 2, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGBA_INTEGER, GL_SHORT, NULL); + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_AFFINE_3]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16I, 2, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGBA_INTEGER, GL_SHORT, NULL); + glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]); _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale); _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], GL_RGBA, GL_COLOR_ATTACHMENT1, glRenderer->scale);@@ -654,12 +689,12 @@ bg->x = 0;
bg->y = 0; bg->refx = 0; bg->refy = 0; - bg->affine[0].dx = 256; - bg->affine[0].dmx = 0; - bg->affine[0].dy = 0; - bg->affine[0].dmy = 256; - bg->affine[0].sx = 0; - bg->affine[0].sy = 0; + bg->affine.dx = 256; + bg->affine.dmx = 0; + bg->affine.dy = 0; + bg->affine.dmy = 256; + bg->affine.sx = 0; + bg->affine.sy = 0; glGenFramebuffers(1, &bg->fbo); glGenTextures(1, &bg->tex); glGenTextures(1, &bg->flags);@@ -796,7 +831,7 @@ if (renderer->cache) {
GBAVideoCacheWriteVideoRegister(renderer->cache, address, value); } - glRenderer->regsDirty |= 1ULL << (address >> 1); + bool dirty = true; switch (address) { case REG_DISPCNT: value &= 0xFFF7;@@ -815,6 +850,70 @@ case REG_BG3HOFS:
case REG_BG3VOFS: value &= 0x01FF; break; + case REG_BG2PA: + glRenderer->bg[2].affine.dx = value; + dirty = false; + break; + case REG_BG2PB: + glRenderer->bg[2].affine.dmx = value; + dirty = false; + break; + case REG_BG2PC: + glRenderer->bg[2].affine.dy = value; + dirty = false; + break; + case REG_BG2PD: + glRenderer->bg[2].affine.dmy = value; + dirty = false; + break; + case REG_BG2X_LO: + GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value); + dirty = false; + break; + case REG_BG2X_HI: + GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value); + dirty = false; + break; + case REG_BG2Y_LO: + GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value); + dirty = false; + break; + case REG_BG2Y_HI: + GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value); + dirty = false; + break; + case REG_BG3PA: + glRenderer->bg[3].affine.dx = value; + dirty = false; + break; + case REG_BG3PB: + glRenderer->bg[3].affine.dmx = value; + dirty = false; + break; + case REG_BG3PC: + glRenderer->bg[3].affine.dy = value; + dirty = false; + break; + case REG_BG3PD: + glRenderer->bg[3].affine.dmy = value; + dirty = false; + break; + case REG_BG3X_LO: + GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value); + dirty = false; + break; + case REG_BG3X_HI: + GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value); + dirty = false; + break; + case REG_BG3Y_LO: + GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value); + dirty = false; + break; + case REG_BG3Y_HI: + GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value); + dirty = false; + break; case REG_BLDALPHA: value &= 0x1F1F; break;@@ -833,7 +932,14 @@ break;
default: break; } - glRenderer->shadowRegs[address >> 1] = value; + if (glRenderer->shadowRegs[address >> 1] == value) { + dirty = false; + } else { + glRenderer->shadowRegs[address >> 1] = value; + } + if (dirty) { + glRenderer->regsDirty |= 1ULL << (address >> 1); + } return value; }@@ -879,54 +985,6 @@ break;
case REG_BG3VOFS: glRenderer->bg[3].y = value; break; - case REG_BG2PA: - glRenderer->bg[2].affine[0].dx = value; - break; - case REG_BG2PB: - glRenderer->bg[2].affine[0].dmx = value; - break; - case REG_BG2PC: - glRenderer->bg[2].affine[0].dy = value; - break; - case REG_BG2PD: - glRenderer->bg[2].affine[0].dmy = value; - break; - case REG_BG2X_LO: - GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[2], value); - break; - case REG_BG2X_HI: - GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[2], value); - break; - case REG_BG2Y_LO: - GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[2], value); - break; - case REG_BG2Y_HI: - GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[2], value); - break; - case REG_BG3PA: - glRenderer->bg[3].affine[0].dx = value; - break; - case REG_BG3PB: - glRenderer->bg[3].affine[0].dmx = value; - break; - case REG_BG3PC: - glRenderer->bg[3].affine[0].dy = value; - break; - case REG_BG3PD: - glRenderer->bg[3].affine[0].dmy = value; - break; - case REG_BG3X_LO: - GBAVideoGLRendererWriteBGX_LO(&glRenderer->bg[3], value); - break; - case REG_BG3X_HI: - GBAVideoGLRendererWriteBGX_HI(&glRenderer->bg[3], value); - break; - case REG_BG3Y_LO: - GBAVideoGLRendererWriteBGY_LO(&glRenderer->bg[3], value); - break; - case REG_BG3Y_HI: - GBAVideoGLRendererWriteBGY_HI(&glRenderer->bg[3], value); - break; case REG_BLDCNT: GBAVideoGLRendererWriteBLDCNT(glRenderer, value); value &= 0x3FFF;@@ -1016,14 +1074,10 @@
void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + memcpy(&glRenderer->affine[0][y], &glRenderer->bg[2].affine, sizeof(struct GBAVideoGLAffine)); + memcpy(&glRenderer->affine[1][y], &glRenderer->bg[3].affine, sizeof(struct GBAVideoGLAffine)); 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 {@@ -1038,6 +1092,9 @@ }
if (glRenderer->firstY < 0) { glRenderer->firstY = y; } + + memcpy(&glRenderer->winN[0].h[1], &glRenderer->winN[0].h[0], sizeof(struct GBAVideoWindowRegion)); + memcpy(&glRenderer->winN[1].h[1], &glRenderer->winN[1].h[0], sizeof(struct GBAVideoWindowRegion)); int i; for (i = 0; i < 0x30; ++i) {@@ -1095,25 +1152,20 @@ }
} 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)); - - glRenderer->bg[2].affine[0].sx += glRenderer->bg[2].affine[0].dmx; - glRenderer->bg[2].affine[0].sy += glRenderer->bg[2].affine[0].dmy; - glRenderer->bg[3].affine[0].sx += glRenderer->bg[3].affine[0].dmx; - glRenderer->bg[3].affine[0].sy += glRenderer->bg[3].affine[0].dmy; - glRenderer->regsDirty |= 1ULL << 0x30; + glRenderer->bg[2].affine.sx += glRenderer->bg[2].affine.dmx; + glRenderer->bg[2].affine.sy += glRenderer->bg[2].affine.dmy; + glRenderer->bg[3].affine.sx += glRenderer->bg[3].affine.dmx; + glRenderer->bg[3].affine.sy += glRenderer->bg[3].affine.dmy; } - - memcpy(&glRenderer->winN[0].h[1], &glRenderer->winN[0].h[0], sizeof(struct GBAVideoWindowRegion)); - memcpy(&glRenderer->winN[1].h[1], &glRenderer->winN[1].h[0], sizeof(struct GBAVideoWindowRegion)); } void _drawScanlines(struct GBAVideoGLRenderer* glRenderer, int y) { + if (glRenderer->firstAffine >= 0) { + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_AFFINE_2]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16I, 2, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGBA_INTEGER, GL_SHORT, glRenderer->affine[0]); + glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_AFFINE_3]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16I, 2, GBA_VIDEO_VERTICAL_PIXELS, 0, GL_RGBA_INTEGER, GL_SHORT, glRenderer->affine[1]); + } glEnable(GL_SCISSOR_TEST); uint32_t backdrop = M_RGB5_TO_RGB8(glRenderer->d.palette[0]);@@ -1187,10 +1239,10 @@ _finalizeLayers(glRenderer);
glBindVertexArray(0); glRenderer->firstAffine = -1; glRenderer->firstY = -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; + glRenderer->bg[2].affine.sx = glRenderer->bg[2].refx; + glRenderer->bg[2].affine.sy = glRenderer->bg[2].refy; + glRenderer->bg[3].affine.sx = glRenderer->bg[3].refx; + glRenderer->bg[3].affine.sy = glRenderer->bg[3].refy; } void GBAVideoGLRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels) {@@ -1245,26 +1297,26 @@ }
static void GBAVideoGLRendererWriteBGX_LO(struct GBAVideoGLBackground* bg, uint16_t value) { bg->refx = (bg->refx & 0xFFFF0000) | value; - bg->affine[0].sx = bg->refx; + bg->affine.sx = bg->refx; } static void GBAVideoGLRendererWriteBGX_HI(struct GBAVideoGLBackground* bg, uint16_t value) { bg->refx = (bg->refx & 0x0000FFFF) | (value << 16); bg->refx <<= 4; bg->refx >>= 4; - bg->affine[0].sx = bg->refx; + bg->affine.sx = bg->refx; } static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint16_t value) { bg->refy = (bg->refy & 0xFFFF0000) | value; - bg->affine[0].sy = bg->refy; + bg->affine.sy = bg->refy; } static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value) { bg->refy = (bg->refy & 0x0000FFFF) | (value << 16); bg->refy <<= 4; bg->refy >>= 4; - bg->affine[0].sy = bg->refy; + bg->affine.sy = bg->refy; } static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value) {@@ -1480,64 +1532,12 @@ glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
} void _prepareTransform(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, const GLuint* uniforms, int y) { - int reverse = 0; - int forward = 1; - if (renderer->scale > 1) { - switch (y - renderer->firstAffine) { - case 0: - case 1: - case 2: - case 3: - return; - case 4: - forward = 2; - reverse = 4; - break; - case 5: - forward = 2; - reverse = 3; - break; - case 6: - forward = 2; - reverse = 2; - break; - case 7: - forward = 2; - reverse = 1; - break; - } - } + glScissor(0, renderer->firstY * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale * (y - renderer->firstY + 1)); + glUniform2i(uniforms[GBA_GL_VS_LOC], y - renderer->firstY + 1, renderer->firstY); - glScissor(0, (y - reverse) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, renderer->scale * forward); - glUniform2i(uniforms[GBA_GL_VS_LOC], forward, y - reverse); - glUniform2f(uniforms[GBA_GL_BG_RANGE], y - 1, 1); - if (renderer->scale > 1) { - glUniform2iv(uniforms[GBA_GL_BG_OFFSET], 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(uniforms[GBA_GL_BG_TRANSFORM], 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 { - glUniform2iv(uniforms[GBA_GL_BG_OFFSET], 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(uniforms[GBA_GL_BG_TRANSFORM], 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, - }); - } + glActiveTexture(GL_TEXTURE0 + 2); + glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_AFFINE_2 + background->index - 2]); + glUniform1i(uniforms[GBA_GL_BG_TRANSFORM], 2); _prepareBackground(renderer, background, uniforms); }