|
|
|
@ -30,12 +30,15 @@ static void GBAVideoGLRendererWriteBGY_LO(struct GBAVideoGLBackground* bg, uint1
|
|
|
|
|
static void GBAVideoGLRendererWriteBGY_HI(struct GBAVideoGLBackground* bg, uint16_t value);
|
|
|
|
|
static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, uint16_t value);
|
|
|
|
|
|
|
|
|
|
static void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY);
|
|
|
|
|
static void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
|
|
|
|
|
static void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
|
|
|
|
|
static void GBAVideoGLRendererDrawBackgroundMode3(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
|
|
|
|
|
static void GBAVideoGLRendererDrawBackgroundMode4(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
|
|
|
|
|
static void GBAVideoGLRendererDrawBackgroundMode5(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y);
|
|
|
|
|
|
|
|
|
|
static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, int y, int priority, int flags);
|
|
|
|
|
|
|
|
|
|
#define TEST_LAYER_ENABLED(X) !renderer->disableBG[X] && glRenderer->bg[X].enabled == 4 && glRenderer->bg[X].priority == priority
|
|
|
|
|
|
|
|
|
|
static const GLchar* const _gl3Header =
|
|
|
|
@ -44,13 +47,13 @@ static const GLchar* const _gl3Header =
|
|
|
|
|
static const char* const _vertexShader =
|
|
|
|
|
"attribute vec2 position;\n"
|
|
|
|
|
"uniform ivec2 loc;\n"
|
|
|
|
|
"const ivec2 maxPos = ivec2(240, 160);\n"
|
|
|
|
|
"uniform ivec2 maxPos;\n"
|
|
|
|
|
"varying vec2 texCoord;\n"
|
|
|
|
|
|
|
|
|
|
"void main() {\n"
|
|
|
|
|
" vec2 local = (position * loc.x + vec2(0, loc.y)) / vec2(1., maxPos.y);\n"
|
|
|
|
|
" gl_Position = vec4(local * 2. - 1., 0., 1.);\n"
|
|
|
|
|
" texCoord = local * maxPos.xy;\n"
|
|
|
|
|
" vec2 local = vec2(position.x, float(position.y * loc.x + loc.y) / abs(maxPos.y));\n"
|
|
|
|
|
" gl_Position = vec4((local * 2. - 1.) * sign(maxPos), 0., 1.);\n"
|
|
|
|
|
" texCoord = local * abs(maxPos);\n"
|
|
|
|
|
"}";
|
|
|
|
|
|
|
|
|
|
static const char* const _renderTile16 =
|
|
|
|
@ -60,10 +63,9 @@ static const char* const _renderTile16 =
|
|
|
|
|
" int entry = int(halfrow[3 - (localCoord.x & 3)] * 15.9);\n"
|
|
|
|
|
" vec4 color = texelFetch(palette, ivec2(entry, paletteId), 0);\n"
|
|
|
|
|
" if (entry == 0) {\n"
|
|
|
|
|
" color.a = 0;\n"
|
|
|
|
|
" } else {\n"
|
|
|
|
|
" color.a = 1;\n"
|
|
|
|
|
" discard;\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" color.a = 1;\n"
|
|
|
|
|
" return color;\n"
|
|
|
|
|
"}";
|
|
|
|
|
|
|
|
|
@ -74,11 +76,10 @@ static const char* const _renderTile256 =
|
|
|
|
|
" int entry = int(halfrow[3 - 2 * (localCoord.x & 1)] * 15.9);\n"
|
|
|
|
|
" int pal2 = int(halfrow[2 - 2 * (localCoord.x & 1)] * 15.9);\n"
|
|
|
|
|
" vec4 color = texelFetch(palette, ivec2(entry, pal2 + (paletteId & 16)), 0);\n"
|
|
|
|
|
" if (pal2 > 0 || entry > 0) {\n"
|
|
|
|
|
" color.a = 1.;\n"
|
|
|
|
|
" } else {\n"
|
|
|
|
|
" color.a = 0.;\n"
|
|
|
|
|
" if (pal2 + entry == 0) {\n"
|
|
|
|
|
" discard;\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" color.a = 1.;\n"
|
|
|
|
|
" return color;\n"
|
|
|
|
|
"}";
|
|
|
|
|
|
|
|
|
@ -179,6 +180,26 @@ static const char* const _renderMode2 =
|
|
|
|
|
" gl_FragColor = fetchTile(ivec2(mixedTransform * texCoord.x + mixedOffset));\n"
|
|
|
|
|
"}";
|
|
|
|
|
|
|
|
|
|
static const char* const _renderObjNoTransform =
|
|
|
|
|
"varying vec2 texCoord;\n"
|
|
|
|
|
"uniform sampler2D vram;\n"
|
|
|
|
|
"uniform sampler2D palette;\n"
|
|
|
|
|
"uniform int charBase;\n"
|
|
|
|
|
"uniform int stride;\n"
|
|
|
|
|
"uniform int localPalette;\n"
|
|
|
|
|
"uniform ivec3 inflags;\n"
|
|
|
|
|
"out vec4 color;\n"
|
|
|
|
|
"out vec3 flags;\n"
|
|
|
|
|
"const vec3 flagCoeff = vec3(32., 8., 4.);\n"
|
|
|
|
|
|
|
|
|
|
"vec4 renderTile(int tile, int paletteId, ivec2 localCoord);\n"
|
|
|
|
|
|
|
|
|
|
"void main() {\n"
|
|
|
|
|
" ivec2 coord = ivec2(texCoord);\n"
|
|
|
|
|
" color = renderTile((coord.x >> 3) + (coord.y >> 3) * stride, 16 + localPalette, coord & 7);\n"
|
|
|
|
|
" flags = inflags / flagCoeff;\n"
|
|
|
|
|
"}";
|
|
|
|
|
|
|
|
|
|
static const char* const _composite =
|
|
|
|
|
"varying vec2 texCoord;\n"
|
|
|
|
|
"uniform ivec3 inflags;\n"
|
|
|
|
@ -186,20 +207,21 @@ static const char* const _composite =
|
|
|
|
|
"uniform vec3 blend;\n"
|
|
|
|
|
"uniform sampler2D layer;\n"
|
|
|
|
|
"uniform sampler2D oldLayer;\n"
|
|
|
|
|
"uniform sampler2D buffer;\n"
|
|
|
|
|
"uniform sampler2D oldFlags;\n"
|
|
|
|
|
"out vec4 color;\n"
|
|
|
|
|
"out vec3 flags;\n"
|
|
|
|
|
"const vec3 flagCoeff = vec3(32., 8., 4.);\n"
|
|
|
|
|
|
|
|
|
|
"void main() {\n"
|
|
|
|
|
" vec4 pix = texelFetch(layer, ivec2(texCoord * scale), 0);\n"
|
|
|
|
|
" if (pix.a == 0) {\n"
|
|
|
|
|
" discard;\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" ivec3 oldFlags = ivec3(texelFetch(buffer, ivec2(texCoord * scale), 0).xyz * vec3(32., 4., 1.));\n"
|
|
|
|
|
" ivec3 oflags = ivec3(texelFetch(oldFlags, ivec2(texCoord * scale), 0).xyz * flagCoeff);\n"
|
|
|
|
|
" ivec3 outflags = ivec3(0, 0, 0);\n"
|
|
|
|
|
" if (inflags.x < oldFlags.x) {\n"
|
|
|
|
|
" if (inflags.x < oflags.x) {\n"
|
|
|
|
|
" outflags = inflags;\n"
|
|
|
|
|
" if (inflags.z == 1 && (inflags.y & 1) == 1 && (oldFlags.y & 2) == 2) {\n"
|
|
|
|
|
" if (inflags.z == 1 && (inflags.y & 1) == 1 && (oflags.y & 2) == 2) {\n"
|
|
|
|
|
" vec4 oldpix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n"
|
|
|
|
|
" pix *= blend.x;\n"
|
|
|
|
|
" pix += oldpix * blend.y;\n"
|
|
|
|
@ -208,7 +230,7 @@ static const char* const _composite =
|
|
|
|
|
" pix = texelFetch(oldLayer, ivec2(texCoord * scale), 0);\n"
|
|
|
|
|
" }\n"
|
|
|
|
|
" color = pix;\n"
|
|
|
|
|
" flags = outflags / vec3(32., 4., 1.);\n"
|
|
|
|
|
" flags = outflags / flagCoeff;\n"
|
|
|
|
|
"}";
|
|
|
|
|
|
|
|
|
|
static const GLint _vertices[] = {
|
|
|
|
@ -240,7 +262,7 @@ void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) {
|
|
|
|
|
renderer->scale = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _compileBackground(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) {
|
|
|
|
|
void _compileShader(struct GBAVideoGLRenderer* glRenderer, GLuint program, const char** shaderBuffer, int shaderBufferLines, GLuint vs, char* log) {
|
|
|
|
|
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
|
|
|
|
|
glAttachShader(program, vs);
|
|
|
|
|
glAttachShader(program, fs);
|
|
|
|
@ -279,7 +301,24 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]);
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR]);
|
|
|
|
|
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_RGBA, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], 0);
|
|
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS]);
|
|
|
|
|
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_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], 0);
|
|
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, glRenderer->outputTex);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
@ -288,13 +327,13 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glRenderer->outputTex, 0);
|
|
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, glRenderer->layers[2]);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]);
|
|
|
|
|
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_RGB, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, GBA_VIDEO_VERTICAL_PIXELS * glRenderer->scale, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[2], 0);
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, glRenderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS], 0);
|
|
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
|
|
|
|
|
@ -315,7 +354,10 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glRenderer->compositeProgram = glCreateProgram();
|
|
|
|
|
glRenderer->objProgram = glCreateProgram();
|
|
|
|
|
glRenderer->objProgram[0] = glCreateProgram();
|
|
|
|
|
glRenderer->objProgram[1] = glCreateProgram();
|
|
|
|
|
glRenderer->objProgram[2] = glCreateProgram();
|
|
|
|
|
glRenderer->objProgram[3] = glCreateProgram();
|
|
|
|
|
glRenderer->bgProgram[0] = glCreateProgram();
|
|
|
|
|
glRenderer->bgProgram[1] = glCreateProgram();
|
|
|
|
|
glRenderer->bgProgram[2] = glCreateProgram();
|
|
|
|
@ -339,21 +381,26 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
|
|
|
|
|
shaderBuffer[1] = _renderMode0;
|
|
|
|
|
|
|
|
|
|
shaderBuffer[2] = _renderTile16;
|
|
|
|
|
_compileBackground(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log);
|
|
|
|
|
_compileShader(glRenderer, glRenderer->bgProgram[0], shaderBuffer, 3, vs, log);
|
|
|
|
|
|
|
|
|
|
shaderBuffer[2] = _renderTile256;
|
|
|
|
|
_compileBackground(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log);
|
|
|
|
|
_compileShader(glRenderer, glRenderer->bgProgram[1], shaderBuffer, 3, vs, log);
|
|
|
|
|
|
|
|
|
|
shaderBuffer[1] = _renderMode2;
|
|
|
|
|
|
|
|
|
|
shaderBuffer[2] = _fetchTileOverflow;
|
|
|
|
|
_compileBackground(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log);
|
|
|
|
|
_compileShader(glRenderer, glRenderer->bgProgram[2], shaderBuffer, 3, vs, log);
|
|
|
|
|
|
|
|
|
|
shaderBuffer[2] = _fetchTileNoOverflow;
|
|
|
|
|
_compileBackground(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log);
|
|
|
|
|
_compileShader(glRenderer, glRenderer->bgProgram[3], shaderBuffer, 3, vs, log);
|
|
|
|
|
|
|
|
|
|
shaderBuffer[1] = _renderObjNoTransform;
|
|
|
|
|
|
|
|
|
|
shaderBuffer[2] = _renderTile16;
|
|
|
|
|
_compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log);
|
|
|
|
|
|
|
|
|
|
shaderBuffer[1] = _composite;
|
|
|
|
|
_compileBackground(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log);
|
|
|
|
|
_compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log);
|
|
|
|
|
glBindFragDataLocation(glRenderer->compositeProgram, 0, "color");
|
|
|
|
|
glBindFragDataLocation(glRenderer->compositeProgram, 1, "flags");
|
|
|
|
|
|
|
|
|
@ -369,6 +416,19 @@ void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) {
|
|
|
|
|
glDeleteTextures(1, &glRenderer->paletteTex);
|
|
|
|
|
glDeleteTextures(1, &glRenderer->vramTex);
|
|
|
|
|
glDeleteTextures(1, &glRenderer->oamTex);
|
|
|
|
|
|
|
|
|
|
glDeleteProgram(glRenderer->bgProgram[0]);
|
|
|
|
|
glDeleteProgram(glRenderer->bgProgram[1]);
|
|
|
|
|
glDeleteProgram(glRenderer->bgProgram[2]);
|
|
|
|
|
glDeleteProgram(glRenderer->bgProgram[3]);
|
|
|
|
|
glDeleteProgram(glRenderer->bgProgram[4]);
|
|
|
|
|
glDeleteProgram(glRenderer->bgProgram[5]);
|
|
|
|
|
glDeleteProgram(glRenderer->bgProgram[6]);
|
|
|
|
|
glDeleteProgram(glRenderer->objProgram[0]);
|
|
|
|
|
glDeleteProgram(glRenderer->objProgram[1]);
|
|
|
|
|
glDeleteProgram(glRenderer->objProgram[2]);
|
|
|
|
|
glDeleteProgram(glRenderer->objProgram[3]);
|
|
|
|
|
glDeleteProgram(glRenderer->compositeProgram);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) {
|
|
|
|
@ -610,11 +670,6 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette);
|
|
|
|
|
glRenderer->paletteDirty = false;
|
|
|
|
|
}
|
|
|
|
|
if (glRenderer->oamDirty) {
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam);
|
|
|
|
|
glRenderer->oamDirty = false;
|
|
|
|
|
}
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < 24; ++i) {
|
|
|
|
|
if (!(glRenderer->vramDirty & (1 << i))) {
|
|
|
|
@ -628,16 +683,25 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
|
|
|
|
|
|
|
|
|
|
uint32_t backdrop = M_RGB5_TO_RGB8(renderer->palette[0]);
|
|
|
|
|
glClearColor(((backdrop >> 16) & 0xFF) / 256., ((backdrop >> 8) & 0xFF) / 256., (backdrop & 0xFF) / 256., 0.f);
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[1]);
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]);
|
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
|
glScissor(0, y * glRenderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, glRenderer->scale);
|
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
|
if (y == 0) {
|
|
|
|
|
glDrawBuffer(GL_COLOR_ATTACHMENT1);
|
|
|
|
|
glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 4.f, 0, 1);
|
|
|
|
|
glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2)) / 8.f, 0, 1);
|
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
|
|
|
|
|
|
|
|
|
glClearColor(0, 0, 0, 0);
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
|
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 4; ++i) {
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);
|
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
|
|
|
|
|
@ -658,6 +722,27 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
|
|
|
|
|
glRenderer->firstAffine = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
|
int spriteLayers = 0;
|
|
|
|
|
if (GBARegisterDISPCNTIsObjEnable(glRenderer->dispcnt) && !glRenderer->d.disableOBJ) {
|
|
|
|
|
if (glRenderer->oamDirty) {
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, glRenderer->oamTex);
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, 4, 128, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, glRenderer->d.oam);
|
|
|
|
|
glRenderer->oamMax = GBAVideoRendererCleanOAM(glRenderer->d.oam->obj, glRenderer->sprites, 0);
|
|
|
|
|
glRenderer->oamDirty = false;
|
|
|
|
|
}
|
|
|
|
|
int i;
|
|
|
|
|
for (i = glRenderer->oamMax; i--;) {
|
|
|
|
|
struct GBAVideoRendererSprite* sprite = &glRenderer->sprites[i];
|
|
|
|
|
if ((y < sprite->y && (sprite->endY - 256 < 0 || y >= sprite->endY - 256)) || y >= sprite->endY) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GBAVideoGLRendererDrawSprite(glRenderer, &sprite->obj, y, sprite->y);
|
|
|
|
|
spriteLayers |= 1 << GBAObjAttributesCGetPriority(sprite->obj.c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned priority;
|
|
|
|
|
for (priority = 4; priority--;) {
|
|
|
|
|
if (TEST_LAYER_ENABLED(0) && GBARegisterDISPCNTGetMode(glRenderer->dispcnt) < 2) {
|
|
|
|
@ -697,6 +782,7 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_compositeLayer(glRenderer, glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], y, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (GBARegisterDISPCNTGetMode(glRenderer->dispcnt) != 0) {
|
|
|
|
|
memcpy(&glRenderer->bg[2].affine[3], &glRenderer->bg[2].affine[2], sizeof(struct GBAVideoGLAffine));
|
|
|
|
@ -804,34 +890,72 @@ static void GBAVideoGLRendererWriteBLDCNT(struct GBAVideoGLRenderer* renderer, u
|
|
|
|
|
renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void _compositeLayer(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y, int flags) {
|
|
|
|
|
static void _compositeLayer(struct GBAVideoGLRenderer* renderer, GLuint tex, int y, int priority, int flags) {
|
|
|
|
|
if ((y & 0x1F) != 0x1F) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[1]);
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_COMPOSITE]);
|
|
|
|
|
glViewport(0, 0, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, GBA_VIDEO_VERTICAL_PIXELS * renderer->scale);
|
|
|
|
|
glScissor(0, (y * renderer->scale) % (0x20 * renderer->scale), GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale);
|
|
|
|
|
glScissor(0, (y & ~0x1F) * renderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * renderer->scale, 0x20 * renderer->scale);
|
|
|
|
|
glUseProgram(renderer->compositeProgram);
|
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, background->tex);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex);
|
|
|
|
|
glActiveTexture(GL_TEXTURE0 + 1);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, renderer->outputTex);
|
|
|
|
|
glActiveTexture(GL_TEXTURE0 + 2);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, renderer->layers[2]);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, renderer->layers[GBA_GL_TEX_COMPOSITE_FLAGS]);
|
|
|
|
|
glUniform2i(0, 0x20, y & ~0x1F);
|
|
|
|
|
glUniform3i(1, (background->priority << 3) + (background->index << 1) + 1, flags, renderer->blendEffect);
|
|
|
|
|
glUniform1i(2, renderer->scale);
|
|
|
|
|
glUniform3f(3, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f);
|
|
|
|
|
glUniform1i(4, 0);
|
|
|
|
|
glUniform1i(5, 1);
|
|
|
|
|
glUniform1i(6, 2);
|
|
|
|
|
glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
|
|
|
|
|
glUniform3i(2, priority, flags, renderer->blendEffect);
|
|
|
|
|
glUniform1i(3, renderer->scale);
|
|
|
|
|
glUniform3f(4, renderer->blda / 16.f, renderer->bldb / 16.f, renderer->bldy / 16.f);
|
|
|
|
|
glUniform1i(5, 0);
|
|
|
|
|
glUniform1i(6, 1);
|
|
|
|
|
glUniform1i(7, 2);
|
|
|
|
|
glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
|
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
|
glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GBAVideoGLRendererDrawSprite(struct GBAVideoGLRenderer* renderer, struct GBAObj* sprite, int y, int spriteY) {
|
|
|
|
|
int width = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][0];
|
|
|
|
|
int height = GBAVideoObjSizes[GBAObjAttributesAGetShape(sprite->a) * 4 + GBAObjAttributesBGetSize(sprite->b)][1];
|
|
|
|
|
int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23;
|
|
|
|
|
x >>= 23;
|
|
|
|
|
|
|
|
|
|
int align = GBAObjAttributesAIs256Color(sprite->a) && !GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt);
|
|
|
|
|
unsigned charBase = (BASE_TILE >> 1) + (GBAObjAttributesCGetTile(sprite->c) & ~align) * 0x10;
|
|
|
|
|
int stride = GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt) ? (width >> 3) : (0x10 >> !GBAObjAttributesAIs256Color(sprite->a));
|
|
|
|
|
|
|
|
|
|
if (spriteY + height >= 256) {
|
|
|
|
|
spriteY -= 256;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, renderer->fbo[GBA_GL_FBO_OBJ]);
|
|
|
|
|
glViewport(x * renderer->scale, spriteY * renderer->scale, width * renderer->scale, height * renderer->scale);
|
|
|
|
|
glScissor(x * renderer->scale, y * renderer->scale, width * renderer->scale, renderer->scale);
|
|
|
|
|
glUseProgram(renderer->objProgram[0]);
|
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, renderer->vramTex);
|
|
|
|
|
glActiveTexture(GL_TEXTURE0 + 1);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
|
|
|
|
|
glUniform2i(0, 1, y - spriteY);
|
|
|
|
|
glUniform2i(1, GBAObjAttributesBIsHFlip(sprite->b) ? -width : width, height);
|
|
|
|
|
glUniform1i(2, 0);
|
|
|
|
|
glUniform1i(3, 1);
|
|
|
|
|
glUniform1i(4, charBase);
|
|
|
|
|
glUniform1i(5, stride);
|
|
|
|
|
glUniform1i(6, GBAObjAttributesCGetPalette(sprite->c));
|
|
|
|
|
glUniform3i(7, GBAObjAttributesCGetPriority(sprite->c) << 3, 0, 0);
|
|
|
|
|
glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
|
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
|
glDrawBuffers(2, (GLenum[]) { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 });
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });}
|
|
|
|
|
|
|
|
|
|
void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
|
|
|
|
|
int inY = y + background->y;
|
|
|
|
|
int yBase = inY & 0xFF;
|
|
|
|
@ -849,19 +973,18 @@ void GBAVideoGLRendererDrawBackgroundMode0(struct GBAVideoGLRenderer* renderer,
|
|
|
|
|
glActiveTexture(GL_TEXTURE0 + 1);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
|
|
|
|
|
glUniform2i(0, 1, y);
|
|
|
|
|
glUniform1i(1, 0);
|
|
|
|
|
glUniform1i(2, 1);
|
|
|
|
|
glUniform1i(3, background->screenBase);
|
|
|
|
|
glUniform1i(4, background->charBase);
|
|
|
|
|
glUniform1i(5, background->size);
|
|
|
|
|
glUniform2i(6, background->x, yBase - y);
|
|
|
|
|
glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
|
|
|
|
|
glUniform1i(2, 0);
|
|
|
|
|
glUniform1i(3, 1);
|
|
|
|
|
glUniform1i(4, background->screenBase);
|
|
|
|
|
glUniform1i(5, background->charBase);
|
|
|
|
|
glUniform1i(6, background->size);
|
|
|
|
|
glUniform2i(7, background->x, yBase - y);
|
|
|
|
|
glVertexAttribPointer(0, 2, GL_INT, GL_FALSE, 0, _vertices);
|
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
|
|
|
|
_compositeLayer(renderer, background, y, background->target1 | (background->target2 * 2));
|
|
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
|
_compositeLayer(renderer, background->tex, y, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer, struct GBAVideoGLBackground* background, int y) {
|
|
|
|
@ -874,32 +997,33 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer,
|
|
|
|
|
glActiveTexture(GL_TEXTURE0 + 1);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, renderer->paletteTex);
|
|
|
|
|
glUniform2i(0, 1, y);
|
|
|
|
|
glUniform1i(1, 0);
|
|
|
|
|
glUniform1i(2, 1);
|
|
|
|
|
glUniform1i(3, background->screenBase);
|
|
|
|
|
glUniform1i(4, background->charBase);
|
|
|
|
|
glUniform1i(5, background->size);
|
|
|
|
|
glUniform2i(1, GBA_VIDEO_HORIZONTAL_PIXELS, GBA_VIDEO_VERTICAL_PIXELS);
|
|
|
|
|
glUniform1i(2, 0);
|
|
|
|
|
glUniform1i(3, 1);
|
|
|
|
|
glUniform1i(4, background->screenBase);
|
|
|
|
|
glUniform1i(5, background->charBase);
|
|
|
|
|
glUniform1i(6, background->size);
|
|
|
|
|
if (renderer->scale > 1) {
|
|
|
|
|
glUniform2iv(6, 4, (GLint[]) {
|
|
|
|
|
glUniform2iv(7, 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[]) {
|
|
|
|
|
glUniform2iv(11, 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(6, 4, (GLint[]) {
|
|
|
|
|
glUniform2iv(7, 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[]) {
|
|
|
|
|
glUniform2iv(11, 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,
|
|
|
|
@ -910,7 +1034,5 @@ void GBAVideoGLRendererDrawBackgroundMode2(struct GBAVideoGLRenderer* renderer,
|
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
|
|
|
|
_compositeLayer(renderer, background, y, background->target1 | (background->target2 * 2));
|
|
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
|
_compositeLayer(renderer, background->tex, y, (background->priority << 3) + (background->index << 1) + 1, background->target1 | (background->target2 * 2));
|
|
|
|
|
}
|