diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 739155db8..bc0002d02 100644 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -41,14 +41,18 @@ static OpenGLRenderer *_OGLRenderer = NULL; // Lookup Tables static CACHE_ALIGN GLfloat material_8bit_to_float[256] = {0}; -static CACHE_ALIGN const GLfloat divide5bitBy31_LUT[32] = {0.0, 0.03225806451613, 0.06451612903226, 0.09677419354839, - 0.1290322580645, 0.1612903225806, 0.1935483870968, 0.2258064516129, - 0.258064516129, 0.2903225806452, 0.3225806451613, 0.3548387096774, - 0.3870967741935, 0.4193548387097, 0.4516129032258, 0.4838709677419, - 0.5161290322581, 0.5483870967742, 0.5806451612903, 0.6129032258065, - 0.6451612903226, 0.6774193548387, 0.7096774193548, 0.741935483871, - 0.7741935483871, 0.8064516129032, 0.8387096774194, 0.8709677419355, - 0.9032258064516, 0.9354838709677, 0.9677419354839, 1.0}; +CACHE_ALIGN const GLfloat divide5bitBy31_LUT[32] = {0.0, 0.03225806451613, 0.06451612903226, 0.09677419354839, + 0.1290322580645, 0.1612903225806, 0.1935483870968, 0.2258064516129, + 0.2580645161290, 0.2903225806452, 0.3225806451613, 0.3548387096774, + 0.3870967741935, 0.4193548387097, 0.4516129032258, 0.4838709677419, + 0.5161290322581, 0.5483870967742, 0.5806451612903, 0.6129032258065, + 0.6451612903226, 0.6774193548387, 0.7096774193548, 0.7419354838710, + 0.7741935483871, 0.8064516129032, 0.8387096774194, 0.8709677419355, + 0.9032258064516, 0.9354838709677, 0.9677419354839, 1.0}; + +const GLfloat PostprocessVtxBuffer[16] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; +const GLubyte PostprocessElementBuffer[6] = {0, 1, 2, 2, 3, 0}; const GLenum RenderDrawList[3] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT}; @@ -279,6 +283,13 @@ static const char *fragmentShader_100 = {"\ uniform bool polyEnableTexture; \n\ uniform bool polyEnableFog;\n\ \n\ + vec3 packVec3FromFloat(const float value)\n\ + {\n\ + float expandedValue = value * 16777215.0;\n\ + vec3 packedValue = vec3( fract(expandedValue/256.0), fract(((expandedValue/256.0) - fract(expandedValue/256.0)) / 256.0), fract(((expandedValue/65536.0) - fract(expandedValue/65536.0)) / 256.0) );\n\ + return packedValue;\n\ + }\n\ + \n\ void main() \n\ { \n\ vec4 mainTexColor = (polyEnableTexture) ? texture2D(texRenderObject, vtxTexCoord) : vec4(1.0, 1.0, 1.0, 1.0); \n\ @@ -311,12 +322,80 @@ static const char *fragmentShader_100 = {"\ float newFragDepth = (stateUseWDepth) ? vtxPosition.w/4096.0 : clamp((vtxPosition.z/vertW) * 0.5 + 0.5, 0.0, 1.0); \n\ \n\ gl_FragData[0] = newFragColor;\n\ - gl_FragData[1] = vec4( vec3(newFragDepth), 1.0);\n\ + gl_FragData[1] = vec4( packVec3FromFloat(newFragDepth), 1.0);\n\ gl_FragData[2] = vec4( float(polyEnableFog), float(stateEnableFogAlphaOnly), 0.0, 1.0);\n\ gl_FragDepth = newFragDepth;\n\ } \n\ "}; +// Vertex shader for post-processing, GLSL 1.00 +static const char *PostprocessVertShader_100 = {"\ + attribute vec2 inPosition;\n\ + attribute vec2 inTexCoord0;\n\ + varying vec2 texCoord;\n\ + \n\ + void main() \n\ + { \n\ + texCoord = inTexCoord0; \n\ + gl_Position = vec4(inPosition, 0.0, 1.0);\n\ + }\n\ +"}; + +// Fragment shader for applying fog, GLSL 1.00 +static const char *FogFragShader_100 = {"\ + varying vec2 texCoord;\n\ + \n\ + uniform sampler2D texInFragColor;\n\ + uniform sampler2D texInFragDepthOnly;\n\ + uniform sampler2D texInFogAttributes;\n\ + uniform vec4 stateFogColor;\n\ + uniform float stateFogDensity[32];\n\ + uniform float stateFogOffset;\n\ + uniform float stateFogStep;\n\ + \n\ + float unpackFloatFromVec3(const vec3 value)\n\ + {\n\ + const vec3 unpackRatio = vec3(256.0, 65536.0, 16777216.0);\n\ + return (dot(value, unpackRatio) / 16777215.0);\n\ + }\n\ + \n\ + void main()\n\ + {\n\ + vec4 inFragColor = texture2D(texInFragColor, texCoord);\n\ + float inFragDepth = unpackFloatFromVec3(texture2D(texInFragDepthOnly, texCoord).rgb);\n\ + vec4 inFogAttributes = texture2D(texInFogAttributes, texCoord);\n\ + \n\ + bool polyEnableFog = bool(inFogAttributes.r);\n\ + bool stateEnableFogAlphaOnly = bool(inFogAttributes.g) ;\n\ + \n\ + float fogMixWeight = 0.0;\n\ + if (inFragDepth <= min(stateFogOffset + stateFogStep, 1.0))\n\ + {\n\ + fogMixWeight = stateFogDensity[0];\n\ + }\n\ + else if (inFragDepth >= min(stateFogOffset + (stateFogStep*32.0), 1.0))\n\ + {\n\ + fogMixWeight = stateFogDensity[31];\n\ + }\n\ + else\n\ + {\n\ + for (int i = 1; i < 32; i++)\n\ + {\n\ + float currentFogStep = min(stateFogOffset + (stateFogStep * float(i+1)), 1.0);\n\ + if (inFragDepth <= currentFogStep)\n\ + {\n\ + float previousFogStep = min(stateFogOffset + (stateFogStep * float(i)), 1.0);\n\ + fogMixWeight = mix(stateFogDensity[i-1], stateFogDensity[i], (inFragDepth - previousFogStep) / (currentFogStep - previousFogStep));\n\ + break;\n\ + }\n\ + }\n\ + }\n\ + \n\ + vec4 newFoggedColor = mix(inFragColor, stateFogColor, fogMixWeight);\n\ + gl_FragData[0] = (polyEnableFog) ? ((stateEnableFogAlphaOnly) ? vec4(inFragColor.rgb, newFoggedColor.a) : newFoggedColor) : inFragColor;\n\ + }\n\ +"}; + FORCEINLINE u32 BGRA8888_32_To_RGBA6665_32(const u32 srcPix) { const u32 dstPix = (srcPix >> 2) & 0x3F3F3F3F; @@ -781,7 +860,6 @@ OpenGLRenderer_1_2::OpenGLRenderer_1_2() ref->fboRenderID = 0; ref->fboMSIntermediateRenderID = 0; ref->fboPostprocessID = 0; - ref->fboOutputID = 0; ref->selectedRenderingFBO = 0; } @@ -800,7 +878,8 @@ OpenGLRenderer_1_2::~OpenGLRenderer_1_2() delete[] ref->color4fBuffer; ref->color4fBuffer = NULL; - DestroyShaders(); + DestroyGeometryProgram(); + DestroyPostprocessingProgram(); DestroyVAOs(); DestroyVBOs(); DestroyPBOs(); @@ -846,22 +925,22 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() std::string vertexShaderProgram; std::string fragmentShaderProgram; - error = this->LoadShaderPrograms(&vertexShaderProgram, &fragmentShaderProgram); + error = this->LoadGeometryShaders(vertexShaderProgram, fragmentShaderProgram); if (error == OGLERROR_NOERR) { - error = this->CreateShaders(&vertexShaderProgram, &fragmentShaderProgram); + error = this->InitGeometryProgram(vertexShaderProgram, fragmentShaderProgram); if (error != OGLERROR_NOERR) { this->isShaderSupported = false; - - if (error == OGLERROR_SHADER_CREATE_ERROR) - { - return error; - } } - else + + std::string postprocessVtxShaderString = std::string(PostprocessVertShader_100); + std::string postprocessFogFragShaderString = std::string(FogFragShader_100); + error = this->InitPostprocessingProgram(postprocessVtxShaderString, postprocessFogFragShaderString); + if (error != OGLERROR_NOERR) { - this->CreateToonTable(); + this->DestroyGeometryProgram(); + this->isShaderSupported = false; } } else @@ -941,13 +1020,21 @@ Render3DError OpenGLRenderer_1_2::CreateVBOs() OGLRenderRef &OGLRef = *this->ref; glGenBuffersARB(1, &OGLRef.vboGeometryVtxID); + glGenBuffersARB(1, &OGLRef.iboGeometryIndexID); + glGenBuffersARB(1, &OGLRef.vboPostprocessVtxID); + glGenBuffersARB(1, &OGLRef.iboPostprocessIndexID); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); glBufferDataARB(GL_ARRAY_BUFFER_ARB, VERTLIST_SIZE * sizeof(VERT), NULL, GL_STREAM_DRAW_ARB); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - - glGenBuffersARB(1, &OGLRef.iboGeometryIndexID); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRENDER_VERT_INDEX_BUFFER_COUNT * sizeof(GLushort), NULL, GL_STREAM_DRAW_ARB); + + glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboPostprocessVtxID); + glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(PostprocessVtxBuffer), PostprocessVtxBuffer, GL_STATIC_DRAW_ARB); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboPostprocessIndexID); + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(PostprocessElementBuffer), PostprocessElementBuffer, GL_STATIC_DRAW_ARB); + + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); return OGLERROR_NOERR; @@ -963,10 +1050,12 @@ void OpenGLRenderer_1_2::DestroyVBOs() OGLRenderRef &OGLRef = *this->ref; glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glDeleteBuffersARB(1, &OGLRef.vboGeometryVtxID); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + + glDeleteBuffersARB(1, &OGLRef.vboGeometryVtxID); glDeleteBuffersARB(1, &OGLRef.iboGeometryIndexID); + glDeleteBuffersARB(1, &OGLRef.vboPostprocessVtxID); + glDeleteBuffersARB(1, &OGLRef.iboPostprocessIndexID); this->isVBOSupported = false; } @@ -998,18 +1087,18 @@ void OpenGLRenderer_1_2::DestroyPBOs() this->isPBOSupported = false; } -Render3DError OpenGLRenderer_1_2::LoadShaderPrograms(std::string *outVertexShaderProgram, std::string *outFragmentShaderProgram) +Render3DError OpenGLRenderer_1_2::LoadGeometryShaders(std::string &outVertexShaderProgram, std::string &outFragmentShaderProgram) { - outVertexShaderProgram->clear(); - outFragmentShaderProgram->clear(); + outVertexShaderProgram.clear(); + outFragmentShaderProgram.clear(); - *outVertexShaderProgram += std::string(vertexShader_100); - *outFragmentShaderProgram += std::string(fragmentShader_100); + outVertexShaderProgram += std::string(vertexShader_100); + outFragmentShaderProgram += std::string(fragmentShader_100); return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_1_2::SetupShaderIO() +Render3DError OpenGLRenderer_1_2::InitGeometryProgramBindings() { OGLRenderRef &OGLRef = *this->ref; @@ -1020,7 +1109,7 @@ Render3DError OpenGLRenderer_1_2::SetupShaderIO() return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_1_2::CreateShaders(const std::string *vertexShaderProgram, const std::string *fragmentShaderProgram) +Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const std::string &vertexShaderProgram, const std::string &fragmentShaderProgram) { OGLRenderRef &OGLRef = *this->ref; @@ -1031,7 +1120,7 @@ Render3DError OpenGLRenderer_1_2::CreateShaders(const std::string *vertexShaderP return OGLERROR_SHADER_CREATE_ERROR; } - const char *vertexShaderProgramChar = vertexShaderProgram->c_str(); + const char *vertexShaderProgramChar = vertexShaderProgram.c_str(); glShaderSource(OGLRef.vertexGeometryShaderID, 1, (const GLchar **)&vertexShaderProgramChar, NULL); glCompileShader(OGLRef.vertexGeometryShaderID); if (!this->ValidateShaderCompile(OGLRef.vertexGeometryShaderID)) @@ -1049,7 +1138,7 @@ Render3DError OpenGLRenderer_1_2::CreateShaders(const std::string *vertexShaderP return OGLERROR_SHADER_CREATE_ERROR; } - const char *fragmentShaderProgramChar = fragmentShaderProgram->c_str(); + const char *fragmentShaderProgramChar = fragmentShaderProgram.c_str(); glShaderSource(OGLRef.fragmentGeometryShaderID, 1, (const GLchar **)&fragmentShaderProgramChar, NULL); glCompileShader(OGLRef.fragmentGeometryShaderID); if (!this->ValidateShaderCompile(OGLRef.fragmentGeometryShaderID)) @@ -1072,7 +1161,7 @@ Render3DError OpenGLRenderer_1_2::CreateShaders(const std::string *vertexShaderP glAttachShader(OGLRef.programGeometryID, OGLRef.vertexGeometryShaderID); glAttachShader(OGLRef.programGeometryID, OGLRef.fragmentGeometryShaderID); - this->SetupShaderIO(); + this->InitGeometryProgramBindings(); glLinkProgram(OGLRef.programGeometryID); if (!this->ValidateShaderProgramLink(OGLRef.programGeometryID)) @@ -1110,15 +1199,14 @@ Render3DError OpenGLRenderer_1_2::CreateShaders(const std::string *vertexShaderP OGLRef.uniformPolyEnableTexture = glGetUniformLocation(OGLRef.programGeometryID, "polyEnableTexture"); OGLRef.uniformPolyEnableFog = glGetUniformLocation(OGLRef.programGeometryID, "polyEnableFog"); - glUniform1i(OGLRef.uniformTexRenderObject, 0); - glUniform1i(OGLRef.uniformTexToonTable, OGLTextureUnitID_ToonTable); - INFO("OpenGL: Successfully created shaders.\n"); + this->CreateToonTable(); + return OGLERROR_NOERR; } -void OpenGLRenderer_1_2::DestroyShaders() +void OpenGLRenderer_1_2::DestroyGeometryProgram() { if(!this->isShaderSupported) { @@ -1145,34 +1233,48 @@ Render3DError OpenGLRenderer_1_2::CreateVAOs() { OGLRenderRef &OGLRef = *this->ref; - glGenVertexArrays(1, &OGLRef.vaoMainStatesID); - glBindVertexArray(OGLRef.vaoMainStatesID); + glGenVertexArrays(1, &OGLRef.vaoGeometryStatesID); + glGenVertexArrays(1, &OGLRef.vaoPostprocessStatesID); + glBindVertexArray(OGLRef.vaoGeometryStatesID); glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); glEnableVertexAttribArray(OGLVertexAttributeID_Position); glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); glEnableVertexAttribArray(OGLVertexAttributeID_Color); - glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, coord)); glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, texcoord)); glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERT), (const GLvoid *)offsetof(VERT, color)); glBindVertexArray(0); + glBindVertexArray(OGLRef.vaoPostprocessStatesID); + glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboPostprocessVtxID); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboPostprocessIndexID); + + glEnableVertexAttribArray(OGLVertexAttributeID_Position); + glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); + glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_FLOAT, GL_FALSE, 0, 0); + glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(sizeof(GLfloat) * 8)); + + glBindVertexArray(0); + return OGLERROR_NOERR; } void OpenGLRenderer_1_2::DestroyVAOs() { + OGLRenderRef &OGLRef = *this->ref; + if (!this->isVAOSupported) { return; } glBindVertexArray(0); - glDeleteVertexArrays(1, &this->ref->vaoMainStatesID); + glDeleteVertexArrays(1, &OGLRef.vaoGeometryStatesID); + glDeleteVertexArrays(1, &OGLRef.vaoPostprocessStatesID); this->isVAOSupported = false; } @@ -1279,7 +1381,6 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); - OGLRef.fboOutputID = OGLRef.fboPostprocessID; OGLRef.selectedRenderingFBO = OGLRef.fboRenderID; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO); INFO("OpenGL: Successfully created FBOs.\n"); @@ -1307,7 +1408,6 @@ void OpenGLRenderer_1_2::DestroyFBOs() OGLRef.fboRenderID = 0; OGLRef.fboPostprocessID = 0; - OGLRef.fboOutputID = 0; this->isFBOSupported = false; } @@ -1371,7 +1471,7 @@ Render3DError OpenGLRenderer_1_2::CreateMultisampledFBO() return OGLERROR_FBO_CREATE_ERROR; } - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboOutputID); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); INFO("OpenGL: Successfully created multisampled FBO.\n"); return OGLERROR_NOERR; @@ -1461,6 +1561,21 @@ Render3DError OpenGLRenderer_1_2::InitTables() return OGLERROR_NOERR; } +Render3DError OpenGLRenderer_1_2::InitPostprocessingProgram(const std::string &vtxShader, const std::string &fragShader) +{ + return OGLERROR_FEATURE_UNSUPPORTED; +} + +Render3DError OpenGLRenderer_1_2::InitPostprocessingProgramBindings() +{ + return OGLERROR_FEATURE_UNSUPPORTED; +} + +Render3DError OpenGLRenderer_1_2::DestroyPostprocessingProgram() +{ + return OGLERROR_FEATURE_UNSUPPORTED; +} + Render3DError OpenGLRenderer_1_2::CreateToonTable() { OGLRenderRef &OGLRef = *this->ref; @@ -1648,7 +1763,10 @@ Render3DError OpenGLRenderer_1_2::EnableVertexAttributes(const VERTLIST *vertLis if (this->isVAOSupported) { - glBindVertexArray(OGLRef.vaoMainStatesID); + glBindVertexArray(OGLRef.vaoGeometryStatesID); + glBindBuffer(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(VERT) * vertList->count, vertList); glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, vertIndexCount * sizeof(GLushort), indexBuffer); } @@ -1757,12 +1875,30 @@ Render3DError OpenGLRenderer_1_2::DownsampleFBO() { OGLRenderRef &OGLRef = *this->ref; - if (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID) + if (this->isMultisampledFBOSupported && OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID) { - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboOutputID); + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboMSIntermediateRenderID); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboRenderID); + + // Blit the color buffer + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glBlitFramebufferEXT(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboOutputID); + + // Blit the working depth buffer + glReadBuffer(GL_COLOR_ATTACHMENT1_EXT); + glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT); + glBlitFramebufferEXT(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // Blit the fog buffer + glReadBuffer(GL_COLOR_ATTACHMENT2_EXT); + glDrawBuffer(GL_COLOR_ATTACHMENT2_EXT); + glBlitFramebufferEXT(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // Reset framebuffer targets + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + glDrawBuffers(3, RenderDrawList); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); } return OGLERROR_NOERR; @@ -1804,6 +1940,7 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State *renderState) if (this->isShaderSupported) { + glUseProgram(OGLRef.programGeometryID); glUniform1i(OGLRef.uniformStateToonShadingMode, renderState->shading); glUniform1i(OGLRef.uniformStateEnableAlphaTest, (renderState->enableAlphaTest) ? GL_TRUE : GL_FALSE); glUniform1i(OGLRef.uniformStateEnableAntialiasing, (renderState->enableAntialiasing) ? GL_TRUE : GL_FALSE); @@ -1811,6 +1948,11 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State *renderState) glUniform1i(OGLRef.uniformStateEnableFogAlphaOnly, (renderState->enableFogAlphaOnly) ? GL_TRUE : GL_FALSE); glUniform1i(OGLRef.uniformStateUseWDepth, (renderState->wbuffer) ? GL_TRUE : GL_FALSE); glUniform1f(OGLRef.uniformStateAlphaTestRef, divide5bitBy31_LUT[renderState->alphaTestRef]); + glUniform1i(OGLRef.uniformTexRenderObject, 0); + glUniform1i(OGLRef.uniformTexToonTable, OGLTextureUnitID_ToonTable); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_STENCIL_TEST); } else { @@ -1976,7 +2118,7 @@ Render3DError OpenGLRenderer_1_2::ClearUsingImage(const u16 *__restrict colorBuf this->UploadClearImage(colorBuffer, depthStencilBuffer, fogBuffer); - if (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID) + if (this->isMultisampledFBOSupported && OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID) { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboRenderID); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboMSIntermediateRenderID); @@ -2025,7 +2167,7 @@ Render3DError OpenGLRenderer_1_2::ClearUsingValues(const u8 r, const u8 g, const glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT); // texGDepthID - glClearColor((GLfloat)clearDepth / (GLfloat)0x00FFFFFF, 0.0, 0.0, 1.0); + glClearColor((GLfloat)(clearDepth & 0x000000FF)/255.0f, (GLfloat)((clearDepth >> 8) & 0x000000FF)/255.0f, (GLfloat)((clearDepth >> 16) & 0x000000FF)/255.0f, 1.0); glClear(GL_COLOR_BUFFER_BIT); glDrawBuffer(GL_COLOR_ATTACHMENT2_EXT); // texGFogAttrID @@ -2054,6 +2196,8 @@ Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY *thePoly) if (this->isShaderSupported) { glUniform1i(OGLRef.uniformPolyMode, attr.polygonMode); + glUniform1i(OGLRef.uniformPolySetNewDepthForTranslucent, (attr.enableAlphaDepthWrite) ? GL_TRUE : GL_FALSE); + glUniform1i(OGLRef.uniformPolyEnableFog, (attr.enableRenderFog) ? GL_TRUE : GL_FALSE); glUniform1f(OGLRef.uniformPolyAlpha, (!attr.isWireframe && attr.isTranslucent) ? divide5bitBy31_LUT[attr.alpha] : 1.0f); glUniform1i(OGLRef.uniformPolyID, attr.polygonID); } @@ -2243,17 +2387,23 @@ Render3DError OpenGLRenderer_1_2::Reset() if(this->isShaderSupported) { + glUseProgram(OGLRef.programGeometryID); glUniform1i(OGLRef.uniformStateToonShadingMode, 0); glUniform1i(OGLRef.uniformStateEnableAlphaTest, GL_TRUE); + glUniform1i(OGLRef.uniformStateEnableAntialiasing, GL_FALSE); + glUniform1i(OGLRef.uniformStateEnableEdgeMarking, GL_TRUE); + glUniform1i(OGLRef.uniformStateEnableFogAlphaOnly, GL_FALSE); glUniform1i(OGLRef.uniformStateUseWDepth, GL_FALSE); glUniform1f(OGLRef.uniformStateAlphaTestRef, 0.0f); glUniform2f(OGLRef.uniformPolyTexScale, 1.0f, 1.0f); glUniform1i(OGLRef.uniformPolyMode, 0); + glUniform1i(OGLRef.uniformPolySetNewDepthForTranslucent, GL_TRUE); glUniform1f(OGLRef.uniformPolyAlpha, 1.0f); glUniform1i(OGLRef.uniformPolyID, 0); glUniform1i(OGLRef.uniformPolyEnableTexture, GL_TRUE); + glUniform1i(OGLRef.uniformPolyEnableFog, GL_FALSE); } else { @@ -2400,13 +2550,21 @@ Render3DError OpenGLRenderer_1_5::CreateVBOs() OGLRenderRef &OGLRef = *this->ref; glGenBuffers(1, &OGLRef.vboGeometryVtxID); + glGenBuffers(1, &OGLRef.iboGeometryIndexID); + glGenBuffers(1, &OGLRef.vboPostprocessVtxID); + glGenBuffers(1, &OGLRef.iboPostprocessIndexID); + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); glBufferData(GL_ARRAY_BUFFER, VERTLIST_SIZE * sizeof(VERT), NULL, GL_STREAM_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glGenBuffers(1, &OGLRef.iboGeometryIndexID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, OGLRENDER_VERT_INDEX_BUFFER_COUNT * sizeof(GLushort), NULL, GL_STREAM_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID); + glBufferData(GL_ARRAY_BUFFER, sizeof(PostprocessVtxBuffer), PostprocessVtxBuffer, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(PostprocessElementBuffer), PostprocessElementBuffer, GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); return OGLERROR_NOERR; @@ -2422,10 +2580,12 @@ void OpenGLRenderer_1_5::DestroyVBOs() OGLRenderRef &OGLRef = *this->ref; glBindBuffer(GL_ARRAY_BUFFER, 0); - glDeleteBuffers(1, &OGLRef.vboGeometryVtxID); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + glDeleteBuffers(1, &OGLRef.vboGeometryVtxID); glDeleteBuffers(1, &OGLRef.iboGeometryIndexID); + glDeleteBuffers(1, &OGLRef.vboPostprocessVtxID); + glDeleteBuffers(1, &OGLRef.iboPostprocessIndexID); this->isVBOSupported = false; } @@ -2463,22 +2623,33 @@ Render3DError OpenGLRenderer_1_5::CreateVAOs() { OGLRenderRef &OGLRef = *this->ref; - glGenVertexArrays(1, &OGLRef.vaoMainStatesID); - glBindVertexArray(OGLRef.vaoMainStatesID); + glGenVertexArrays(1, &OGLRef.vaoGeometryStatesID); + glGenVertexArrays(1, &OGLRef.vaoPostprocessStatesID); + glBindVertexArray(OGLRef.vaoGeometryStatesID); glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); glEnableVertexAttribArray(OGLVertexAttributeID_Position); glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); glEnableVertexAttribArray(OGLVertexAttributeID_Color); - glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, coord)); glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, texcoord)); glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERT), (const GLvoid *)offsetof(VERT, color)); glBindVertexArray(0); + glBindVertexArray(OGLRef.vaoPostprocessStatesID); + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID); + + glEnableVertexAttribArray(OGLVertexAttributeID_Position); + glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); + glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_FLOAT, GL_FALSE, 0, 0); + glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(sizeof(GLfloat) * 8)); + + glBindVertexArray(0); + return OGLERROR_NOERR; } @@ -2488,7 +2659,10 @@ Render3DError OpenGLRenderer_1_5::EnableVertexAttributes(const VERTLIST *vertLis if (this->isVAOSupported) { - glBindVertexArray(OGLRef.vaoMainStatesID); + glBindVertexArray(OGLRef.vaoGeometryStatesID); + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VERT) * vertList->count, vertList); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, vertIndexCount * sizeof(GLushort), indexBuffer); } @@ -2628,21 +2802,28 @@ Render3DError OpenGLRenderer_2_0::InitExtensions() std::string vertexShaderProgram; std::string fragmentShaderProgram; - error = this->LoadShaderPrograms(&vertexShaderProgram, &fragmentShaderProgram); + error = this->LoadGeometryShaders(vertexShaderProgram, fragmentShaderProgram); if (error != OGLERROR_NOERR) { this->isShaderSupported = false; return error; } - error = this->CreateShaders(&vertexShaderProgram, &fragmentShaderProgram); + error = this->InitGeometryProgram(vertexShaderProgram, fragmentShaderProgram); if (error != OGLERROR_NOERR) { this->isShaderSupported = false; return error; } - this->CreateToonTable(); + std::string postprocessVtxShaderString = std::string(PostprocessVertShader_100); + std::string postprocessFogFragShaderString = std::string(FogFragShader_100); + error = this->InitPostprocessingProgram(postprocessVtxShaderString, postprocessFogFragShaderString); + if (error != OGLERROR_NOERR) + { + this->DestroyGeometryProgram(); + this->isShaderSupported = false; + } this->isVBOSupported = true; this->CreateVBOs(); @@ -2726,6 +2907,125 @@ Render3DError OpenGLRenderer_2_0::InitFinalRenderStates(const std::setref; + + OGLRef.vertexPostprocessShaderID = glCreateShader(GL_VERTEX_SHADER); + if(!OGLRef.vertexPostprocessShaderID) + { + INFO("OpenGL: Failed to create the postprocess vertex shader.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + const char *vtxShaderCStr = vtxShader.c_str(); + glShaderSource(OGLRef.vertexPostprocessShaderID, 1, (const GLchar **)&vtxShaderCStr, NULL); + glCompileShader(OGLRef.vertexPostprocessShaderID); + if (!this->ValidateShaderCompile(OGLRef.vertexPostprocessShaderID)) + { + glDeleteShader(OGLRef.vertexPostprocessShaderID); + INFO("OpenGL: Failed to compile the postprocess vertex shader.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + OGLRef.fragmentFogShaderID = glCreateShader(GL_FRAGMENT_SHADER); + if(!OGLRef.fragmentFogShaderID) + { + glDeleteShader(OGLRef.vertexPostprocessShaderID); + INFO("OpenGL: Failed to create the fog fragment shader.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + const char *fragShaderCStr = fragShader.c_str(); + glShaderSource(OGLRef.fragmentFogShaderID, 1, (const GLchar **)&fragShaderCStr, NULL); + glCompileShader(OGLRef.fragmentFogShaderID); + if (!this->ValidateShaderCompile(OGLRef.fragmentFogShaderID)) + { + glDeleteShader(OGLRef.vertexPostprocessShaderID); + glDeleteShader(OGLRef.fragmentFogShaderID); + INFO("OpenGL: Failed to compile the fog fragment shader.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + OGLRef.programFogID = glCreateProgram(); + if(!OGLRef.programFogID) + { + glDeleteShader(OGLRef.vertexPostprocessShaderID); + glDeleteShader(OGLRef.fragmentFogShaderID); + INFO("OpenGL: Failed to create the fog shader program.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + glAttachShader(OGLRef.programFogID, OGLRef.vertexPostprocessShaderID); + glAttachShader(OGLRef.programFogID, OGLRef.fragmentFogShaderID); + + error = this->InitPostprocessingProgramBindings(); + if (error != OGLERROR_NOERR) + { + glDetachShader(OGLRef.programFogID, OGLRef.vertexPostprocessShaderID); + glDetachShader(OGLRef.programFogID, OGLRef.fragmentFogShaderID); + glDeleteProgram(OGLRef.programFogID); + glDeleteShader(OGLRef.vertexPostprocessShaderID); + glDeleteShader(OGLRef.fragmentFogShaderID); + INFO("OpenGL: Failed to make the fog shader bindings.\n"); + return error; + } + + glLinkProgram(OGLRef.programFogID); + if (!this->ValidateShaderProgramLink(OGLRef.programFogID)) + { + glDetachShader(OGLRef.programFogID, OGLRef.vertexPostprocessShaderID); + glDetachShader(OGLRef.programFogID, OGLRef.fragmentFogShaderID); + glDeleteProgram(OGLRef.programFogID); + glDeleteShader(OGLRef.vertexPostprocessShaderID); + glDeleteShader(OGLRef.fragmentFogShaderID); + INFO("OpenGL: Failed to link the fog shader program.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + glValidateProgram(OGLRef.programFogID); + glUseProgram(OGLRef.programFogID); + + // Set up shader uniforms + OGLRef.uniformTexGColor = glGetUniformLocation(OGLRef.programFogID, "texInFragColor"); + OGLRef.uniformTexGDepth = glGetUniformLocation(OGLRef.programFogID, "texInFragDepthOnly"); + OGLRef.uniformTexGFog = glGetUniformLocation(OGLRef.programFogID, "texInFogAttributes"); + + OGLRef.uniformStateFogColor = glGetUniformLocation(OGLRef.programFogID, "stateFogColor"); + OGLRef.uniformStateFogDensity = glGetUniformLocation(OGLRef.programFogID, "stateFogDensity"); + OGLRef.uniformStateFogOffset = glGetUniformLocation(OGLRef.programFogID, "stateFogOffset"); + OGLRef.uniformStateFogStep = glGetUniformLocation(OGLRef.programFogID, "stateFogStep"); + + glUseProgram(OGLRef.programGeometryID); + INFO("OpenGL: Successfully created postprocess shaders.\n"); + + return OGLERROR_NOERR; +} + +Render3DError OpenGLRenderer_2_0::InitPostprocessingProgramBindings() +{ + OGLRenderRef &OGLRef = *this->ref; + glBindAttribLocation(OGLRef.programFogID, OGLVertexAttributeID_Position, "inPosition"); + glBindAttribLocation(OGLRef.programFogID, OGLVertexAttributeID_TexCoord0, "inTexCoord0"); + + return OGLERROR_NOERR; +} + +Render3DError OpenGLRenderer_2_0::DestroyPostprocessingProgram() +{ + OGLRenderRef &OGLRef = *this->ref; + + glUseProgram(0); + glDetachShader(OGLRef.programFogID, OGLRef.vertexPostprocessShaderID); + glDetachShader(OGLRef.programFogID, OGLRef.fragmentFogShaderID); + glDeleteProgram(OGLRef.programFogID); + glDeleteShader(OGLRef.fragmentFogShaderID); + glDeleteShader(OGLRef.vertexPostprocessShaderID); + + return OGLERROR_NOERR; +} + Render3DError OpenGLRenderer_2_0::SetupVertices(const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList, GLushort *outIndexBuffer, size_t *outIndexCount) { const size_t polyCount = polyList->count; @@ -2770,7 +3070,10 @@ Render3DError OpenGLRenderer_2_0::EnableVertexAttributes(const VERTLIST *vertLis if (this->isVAOSupported) { - glBindVertexArray(OGLRef.vaoMainStatesID); + glBindVertexArray(OGLRef.vaoGeometryStatesID); + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VERT) * vertList->count, vertList); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, vertIndexCount * sizeof(GLushort), indexBuffer); } @@ -2820,6 +3123,7 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State *renderState) this->SelectRenderingFramebuffer(); + glUseProgram(OGLRef.programGeometryID); glUniform1i(OGLRef.uniformStateToonShadingMode, renderState->shading); glUniform1i(OGLRef.uniformStateEnableAlphaTest, (renderState->enableAlphaTest) ? GL_TRUE : GL_FALSE); glUniform1i(OGLRef.uniformStateEnableAntialiasing, (renderState->enableAntialiasing) ? GL_TRUE : GL_FALSE); @@ -2827,6 +3131,11 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State *renderState) glUniform1i(OGLRef.uniformStateEnableFogAlphaOnly, (renderState->enableFogAlphaOnly) ? GL_TRUE : GL_FALSE); glUniform1i(OGLRef.uniformStateUseWDepth, (renderState->wbuffer) ? GL_TRUE : GL_FALSE); glUniform1f(OGLRef.uniformStateAlphaTestRef, divide5bitBy31_LUT[renderState->alphaTestRef]); + glUniform1i(OGLRef.uniformTexRenderObject, 0); + glUniform1i(OGLRef.uniformTexToonTable, OGLTextureUnitID_ToonTable); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_STENCIL_TEST); if(renderState->enableAlphaBlending) { @@ -2842,14 +3151,93 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State *renderState) return OGLERROR_NOERR; } +Render3DError OpenGLRenderer_2_0::RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift) +{ + OGLRenderRef &OGLRef = *this->ref; + static GLfloat oglDensityTable[32]; + + if (!this->isFBOSupported) + { + return OGLERROR_FEATURE_UNSUPPORTED; + } + + for (size_t i = 0; i < 32; i++) + { + oglDensityTable[i] = (densityTable[i] == 127) ? 1.0f : (GLfloat)densityTable[i] / 128.0f; + } + + const GLfloat oglColor[4] = {divide5bitBy31_LUT[(color ) & 0x0000001F], + divide5bitBy31_LUT[(color >> 5) & 0x0000001F], + divide5bitBy31_LUT[(color >> 10) & 0x0000001F], + divide5bitBy31_LUT[(color >> 16) & 0x0000001F]}; + + const GLfloat oglOffset = (GLfloat)offset / 32767.0f; + const GLfloat oglFogStep = (GLfloat)(0x0400 >> shift) / 32767.0f; + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboPostprocessID); + glUseProgram(OGLRef.programFogID); + glUniform1i(OGLRef.uniformTexGColor, OGLTextureUnitID_GColor); + glUniform1i(OGLRef.uniformTexGDepth, OGLTextureUnitID_GDepth); + glUniform1i(OGLRef.uniformTexGFog, OGLTextureUnitID_FogAttr); + glUniform4f(OGLRef.uniformStateFogColor, oglColor[0], oglColor[1], oglColor[2], oglColor[3]); + glUniform1f(OGLRef.uniformStateFogOffset, oglOffset); + glUniform1f(OGLRef.uniformStateFogStep, oglFogStep); + glUniform1fv(OGLRef.uniformStateFogDensity, 32, oglDensityTable); + + glViewport(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + glDisable(GL_BLEND); + glDisable(GL_CULL_FACE); + + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID); + + if (this->isVAOSupported) + { + glBindVertexArray(OGLRef.vaoPostprocessStatesID); + } + else + { + glEnableVertexAttribArray(OGLVertexAttributeID_Position); + glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); + glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_FLOAT, GL_FALSE, 0, 0); + glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(sizeof(GLfloat) * 8)); + } + + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GDepth); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthID); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGFogAttrID); + glActiveTexture(GL_TEXTURE0); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); + glBindTexture(GL_TEXTURE_2D, 0); + + if (this->isVAOSupported) + { + glBindVertexArray(0); + } + else + { + glDisableVertexAttribArray(OGLVertexAttributeID_Position); + glDisableVertexAttribArray(OGLVertexAttributeID_TexCoord0); + } + + return OGLERROR_NOERR; +} + Render3DError OpenGLRenderer_2_0::SetupPolygon(const POLY *thePoly) { OGLRenderRef &OGLRef = *this->ref; const PolygonAttributes attr = thePoly->getAttributes(); // Set up polygon attributes - assert(attr.polygonMode != 1); glUniform1i(OGLRef.uniformPolyMode, attr.polygonMode); + glUniform1i(OGLRef.uniformPolySetNewDepthForTranslucent, (attr.enableAlphaDepthWrite) ? GL_TRUE : GL_FALSE); + glUniform1i(OGLRef.uniformPolyEnableFog, (attr.enableRenderFog) ? GL_TRUE : GL_FALSE); glUniform1f(OGLRef.uniformPolyAlpha, (!attr.isWireframe && attr.isTranslucent) ? divide5bitBy31_LUT[attr.alpha] : 1.0f); glUniform1i(OGLRef.uniformPolyID, attr.polygonID); diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index 80a539e7a..1a4e75de4 100644 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -327,7 +327,6 @@ struct OGLRenderRef GLuint fboRenderID; GLuint fboPostprocessID; GLuint fboMSIntermediateRenderID; - GLuint fboOutputID; GLuint selectedRenderingFBO; // Shader states @@ -371,7 +370,7 @@ struct OGLRenderRef GLuint texToonTableID; // VAO - GLuint vaoMainStatesID; + GLuint vaoGeometryStatesID; GLuint vaoPostprocessStatesID; // Textures @@ -395,6 +394,9 @@ extern GPU3DInterface gpu3DglOld; extern GPU3DInterface gpu3Dgl_3_2; extern const GLenum RenderDrawList[3]; +extern CACHE_ALIGN const GLfloat divide5bitBy31_LUT[32]; +extern const GLfloat PostprocessVtxBuffer[16];; +extern const GLubyte PostprocessElementBuffer[6]; //This is called by OGLRender whenever it initializes. //Platforms, please be sure to set this up. @@ -457,16 +459,19 @@ protected: virtual void DestroyFBOs() = 0; virtual Render3DError CreateMultisampledFBO() = 0; virtual void DestroyMultisampledFBO() = 0; - virtual Render3DError CreateShaders(const std::string *vertexShaderProgram, const std::string *fragmentShaderProgram) = 0; - virtual void DestroyShaders() = 0; + virtual Render3DError InitGeometryProgram(const std::string &vertexShaderProgram, const std::string &fragmentShaderProgram) = 0; + virtual void DestroyGeometryProgram() = 0; virtual Render3DError CreateVAOs() = 0; virtual void DestroyVAOs() = 0; virtual Render3DError InitTextures() = 0; virtual Render3DError InitFinalRenderStates(const std::set *oglExtensionSet) = 0; virtual Render3DError InitTables() = 0; + virtual Render3DError InitPostprocessingProgram(const std::string &vtxShader, const std::string &fragShader) = 0; + virtual Render3DError InitPostprocessingProgramBindings() = 0; + virtual Render3DError DestroyPostprocessingProgram() = 0; - virtual Render3DError LoadShaderPrograms(std::string *outVertexShaderProgram, std::string *outFragmentShaderProgram) = 0; - virtual Render3DError SetupShaderIO() = 0; + virtual Render3DError LoadGeometryShaders(std::string &outVertexShaderProgram, std::string &outFragmentShaderProgram) = 0; + virtual Render3DError InitGeometryProgramBindings() = 0; virtual Render3DError CreateToonTable() = 0; virtual Render3DError DestroyToonTable() = 0; virtual Render3DError UploadToonTable(const u16 *toonTableBuffer) = 0; @@ -481,28 +486,11 @@ protected: virtual Render3DError DownsampleFBO() = 0; virtual Render3DError ReadBackPixels() = 0; - // Base rendering methods - virtual Render3DError BeginRender(const GFX3D_State *renderState) = 0; - virtual Render3DError RenderGeometry(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList) = 0; - virtual Render3DError EndRender(const u64 frameCount) = 0; - - virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer) = 0; - - virtual Render3DError ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthStencilBuffer, const bool *__restrict fogBuffer) = 0; - virtual Render3DError ClearUsingValues(const u8 r, const u8 g, const u8 b, const u8 a, const u32 clearDepth, const u8 clearStencil, const bool enableFog) const = 0; - - virtual Render3DError SetupPolygon(const POLY *thePoly) = 0; - virtual Render3DError SetupTexture(const POLY *thePoly, bool enableTexturing) = 0; - virtual Render3DError SetupViewport(const u32 viewportValue) = 0; - public: OpenGLRenderer(); virtual ~OpenGLRenderer() {}; virtual Render3DError InitExtensions() = 0; - virtual Render3DError Reset() = 0; - virtual Render3DError RenderFinish() = 0; - virtual Render3DError DeleteTexture(const TexCacheItem *item) = 0; bool IsExtensionPresent(const std::set *oglExtensionSet, const std::string extensionName) const; @@ -525,16 +513,20 @@ protected: virtual void DestroyFBOs(); virtual Render3DError CreateMultisampledFBO(); virtual void DestroyMultisampledFBO(); - virtual Render3DError CreateShaders(const std::string *vertexShaderProgram, const std::string *fragmentShaderProgram); - virtual void DestroyShaders(); virtual Render3DError CreateVAOs(); virtual void DestroyVAOs(); virtual Render3DError InitTextures(); virtual Render3DError InitFinalRenderStates(const std::set *oglExtensionSet); virtual Render3DError InitTables(); - virtual Render3DError LoadShaderPrograms(std::string *outVertexShaderProgram, std::string *outFragmentShaderProgram); - virtual Render3DError SetupShaderIO(); + virtual Render3DError InitGeometryProgram(const std::string &vertexShaderProgram, const std::string &fragmentShaderProgram); + virtual Render3DError LoadGeometryShaders(std::string &outVertexShaderProgram, std::string &outFragmentShaderProgram); + virtual Render3DError InitGeometryProgramBindings(); + virtual void DestroyGeometryProgram(); + virtual Render3DError InitPostprocessingProgram(const std::string &vtxShader, const std::string &fragShader); + virtual Render3DError InitPostprocessingProgramBindings(); + virtual Render3DError DestroyPostprocessingProgram(); + virtual Render3DError CreateToonTable(); virtual Render3DError DestroyToonTable(); virtual Render3DError UploadToonTable(const u16 *toonTableBuffer); @@ -611,12 +603,16 @@ class OpenGLRenderer_2_0 : public OpenGLRenderer_1_5 protected: virtual Render3DError InitExtensions(); virtual Render3DError InitFinalRenderStates(const std::set *oglExtensionSet); + virtual Render3DError InitPostprocessingProgram(const std::string &vtxShader, const std::string &fragShader); + virtual Render3DError InitPostprocessingProgramBindings(); + virtual Render3DError DestroyPostprocessingProgram(); virtual Render3DError SetupVertices(const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList, GLushort *outIndexBuffer, size_t *outIndexCount); virtual Render3DError EnableVertexAttributes(const VERTLIST *vertList, const GLushort *indexBuffer, const size_t vertIndexCount); virtual Render3DError DisableVertexAttributes(); virtual Render3DError BeginRender(const GFX3D_State *renderState); + virtual Render3DError RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift); virtual Render3DError SetupPolygon(const POLY *thePoly); virtual Render3DError SetupTexture(const POLY *thePoly, bool enableTexturing); diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index ddc051943..9968d9a31 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -72,8 +72,8 @@ void OGLLoadEntryPoints_3_2() INITOGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Promote to core version } -// Vertex Shader GLSL 1.50 -static const char *vertexShader_150 = {"\ +// Vertex shader for geometry, GLSL 1.50 +static const char *GeometryVtxShader_150 = {"\ #version 150 \n\ \n\ in vec4 inPosition; \n\ @@ -100,8 +100,8 @@ static const char *vertexShader_150 = {"\ } \n\ "}; -// Fragment Shader GLSL 1.50 -static const char *fragmentShader_150 = {"\ +// Fragment shader for geometry, GLSL 1.50 +static const char *GeometryFragShader_150 = {"\ #version 150 \n\ \n\ in vec4 vtxPosition; \n\ @@ -130,6 +130,13 @@ static const char *fragmentShader_150 = {"\ out vec4 outFragDepth;\n\ out vec4 outFogAttributes;\n\ \n\ + vec3 packVec3FromFloat(const float value)\n\ + {\n\ + float expandedValue = value * 16777215.0;\n\ + vec3 packedValue = vec3( fract(expandedValue/256.0), fract(((expandedValue/256.0) - fract(expandedValue/256.0)) / 256.0), fract(((expandedValue/65536.0) - fract(expandedValue/65536.0)) / 256.0) );\n\ + return packedValue;\n\ + }\n\ + \n\ void main() \n\ { \n\ vec4 mainTexColor = (polyEnableTexture) ? texture(texRenderObject, vtxTexCoord) : vec4(1.0, 1.0, 1.0, 1.0); \n\ @@ -162,12 +169,86 @@ static const char *fragmentShader_150 = {"\ float newFragDepth = (stateUseWDepth) ? vtxPosition.w/4096.0 : clamp((vtxPosition.z/vertW) * 0.5 + 0.5, 0.0, 1.0); \n\ \n\ outFragColor = newFragColor;\n\ - outFragDepth = vec4( vec3(newFragDepth), 1.0);\n\ + outFragDepth = vec4( packVec3FromFloat(newFragDepth), 1.0);\n\ outFogAttributes = vec4( float(polyEnableFog), float(stateEnableFogAlphaOnly), 0.0, 1.0);\n\ gl_FragDepth = newFragDepth;\n\ } \n\ "}; +// Vertex shader for post-processing, GLSL 1.50 +static const char *PostprocessVtxShader_150 = {"\ + #version 150\n\ + \n\ + in vec2 inPosition;\n\ + in vec2 inTexCoord0;\n\ + out vec2 texCoord;\n\ + \n\ + void main() \n\ + { \n\ + texCoord = inTexCoord0; \n\ + gl_Position = vec4(inPosition, 0.0, 1.0);\n\ + }\n\ +"}; + +// Fragment shader for applying fog, GLSL 1.50 +static const char *FogFragShader_150 = {"\ + #version 150\n\ + \n\ + in vec2 texCoord;\n\ + \n\ + uniform sampler2D texInFragColor;\n\ + uniform sampler2D texInFragDepthOnly;\n\ + uniform sampler2D texInFogAttributes;\n\ + uniform vec4 stateFogColor;\n\ + uniform float stateFogDensity[32];\n\ + uniform float stateFogOffset;\n\ + uniform float stateFogStep;\n\ + \n\ + out vec4 outFragColor;\n\ + \n\ + float unpackFloatFromVec3(const vec3 value)\n\ + {\n\ + const vec3 unpackRatio = vec3(256.0, 65536.0, 16777216.0);\n\ + return (dot(value, unpackRatio) / 16777215.0);\n\ + }\n\ + \n\ + void main()\n\ + {\n\ + vec4 inFragColor = texture(texInFragColor, texCoord);\n\ + float inFragDepth = unpackFloatFromVec3(texture(texInFragDepthOnly, texCoord).rgb);\n\ + vec4 inFogAttributes = texture(texInFogAttributes, texCoord);\n\ + \n\ + bool polyEnableFog = bool(inFogAttributes.r);\n\ + bool stateEnableFogAlphaOnly = bool(inFogAttributes.g) ;\n\ + \n\ + float fogMixWeight = 0.0;\n\ + if (inFragDepth <= min(stateFogOffset + stateFogStep, 1.0))\n\ + {\n\ + fogMixWeight = stateFogDensity[0];\n\ + }\n\ + else if (inFragDepth >= min(stateFogOffset + (stateFogStep*32.0), 1.0))\n\ + {\n\ + fogMixWeight = stateFogDensity[31];\n\ + }\n\ + else\n\ + {\n\ + for (int i = 1; i < 32; i++)\n\ + {\n\ + float currentFogStep = min(stateFogOffset + (stateFogStep * float(i+1)), 1.0);\n\ + if (inFragDepth <= currentFogStep)\n\ + {\n\ + float previousFogStep = min(stateFogOffset + (stateFogStep * float(i)), 1.0);\n\ + fogMixWeight = mix(stateFogDensity[i-1], stateFogDensity[i], (inFragDepth - previousFogStep) / (currentFogStep - previousFogStep));\n\ + break;\n\ + }\n\ + }\n\ + }\n\ + \n\ + vec4 newFoggedColor = mix(inFragColor, stateFogColor, fogMixWeight);\n\ + outFragColor = (polyEnableFog) ? ((stateEnableFogAlphaOnly) ? vec4(inFragColor.rgb, newFoggedColor.a) : newFoggedColor) : inFragColor;\n\ + }\n\ +"}; + void OGLCreateRenderer_3_2(OpenGLRenderer **rendererPtr) { if (IsVersionSupported(3, 2, 0)) @@ -202,21 +283,29 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() std::string vertexShaderProgram; std::string fragmentShaderProgram; - error = this->LoadShaderPrograms(&vertexShaderProgram, &fragmentShaderProgram); + error = this->LoadGeometryShaders(vertexShaderProgram, fragmentShaderProgram); if (error != OGLERROR_NOERR) { this->isShaderSupported = false; return error; } - error = this->CreateShaders(&vertexShaderProgram, &fragmentShaderProgram); + error = this->InitGeometryProgram(vertexShaderProgram, fragmentShaderProgram); if (error != OGLERROR_NOERR) { this->isShaderSupported = false; return error; } - this->CreateToonTable(); + std::string postprocessVtxShaderString = std::string(PostprocessVtxShader_150); + std::string postprocessFogFragShaderString = std::string(FogFragShader_150); + error = this->InitPostprocessingProgram(postprocessVtxShaderString, postprocessFogFragShaderString); + if (error != OGLERROR_NOERR) + { + this->DestroyGeometryProgram(); + this->isShaderSupported = false; + return error; + } this->isVBOSupported = true; this->CreateVBOs(); @@ -256,6 +345,16 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() return OGLERROR_NOERR; } +Render3DError OpenGLRenderer_3_2::InitPostprocessingProgramBindings() +{ + OGLRenderRef &OGLRef = *this->ref; + glBindAttribLocation(OGLRef.programFogID, OGLVertexAttributeID_Position, "inPosition"); + glBindAttribLocation(OGLRef.programFogID, OGLVertexAttributeID_TexCoord0, "inTexCoord0"); + glBindFragDataLocation(OGLRef.programFogID, 0, "outFragColor"); + + return OGLERROR_NOERR; +} + Render3DError OpenGLRenderer_3_2::CreateFBOs() { OGLRenderRef &OGLRef = *this->ref; @@ -330,7 +429,6 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() OGLRef.fboRenderID = 0; OGLRef.fboPostprocessID = 0; - OGLRef.fboOutputID = 0; return OGLERROR_FBO_CREATE_ERROR; } @@ -356,7 +454,6 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() OGLRef.fboRenderID = 0; OGLRef.fboPostprocessID = 0; - OGLRef.fboOutputID = 0; return OGLERROR_FBO_CREATE_ERROR; } @@ -364,7 +461,6 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glDrawBuffer(GL_COLOR_ATTACHMENT0); glReadBuffer(GL_COLOR_ATTACHMENT0); - OGLRef.fboOutputID = OGLRef.fboPostprocessID; OGLRef.selectedRenderingFBO = OGLRef.fboRenderID; glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.selectedRenderingFBO); INFO("OpenGL: Successfully created FBOs.\n"); @@ -392,7 +488,6 @@ void OpenGLRenderer_3_2::DestroyFBOs() OGLRef.fboRenderID = 0; OGLRef.fboPostprocessID = 0; - OGLRef.fboOutputID = 0; this->isFBOSupported = false; } @@ -457,7 +552,7 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO() return OGLERROR_FBO_CREATE_ERROR; } - glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboOutputID); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID); INFO("OpenGL: Successfully created multisampled FBO.\n"); return OGLERROR_NOERR; @@ -488,22 +583,33 @@ Render3DError OpenGLRenderer_3_2::CreateVAOs() { OGLRenderRef &OGLRef = *this->ref; - glGenVertexArrays(1, &OGLRef.vaoMainStatesID); - glBindVertexArray(OGLRef.vaoMainStatesID); + glGenVertexArrays(1, &OGLRef.vaoGeometryStatesID); + glGenVertexArrays(1, &OGLRef.vaoPostprocessStatesID); + glBindVertexArray(OGLRef.vaoGeometryStatesID); glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); glEnableVertexAttribArray(OGLVertexAttributeID_Position); glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); glEnableVertexAttribArray(OGLVertexAttributeID_Color); - glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, coord)); glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, texcoord)); glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(VERT), (const GLvoid *)offsetof(VERT, color)); glBindVertexArray(0); + glBindVertexArray(OGLRef.vaoPostprocessStatesID); + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID); + + glEnableVertexAttribArray(OGLVertexAttributeID_Position); + glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); + glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_FLOAT, GL_FALSE, 0, 0); + glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(sizeof(GLfloat) * 8)); + + glBindVertexArray(0); + return OGLERROR_NOERR; } @@ -514,21 +620,27 @@ void OpenGLRenderer_3_2::DestroyVAOs() return; } + OGLRenderRef &OGLRef = *this->ref; + glBindVertexArray(0); - glDeleteVertexArrays(1, &this->ref->vaoMainStatesID); + glDeleteVertexArrays(1, &OGLRef.vaoGeometryStatesID); + glDeleteVertexArrays(1, &OGLRef.vaoPostprocessStatesID); this->isVAOSupported = false; } -Render3DError OpenGLRenderer_3_2::LoadShaderPrograms(std::string *outVertexShaderProgram, std::string *outFragmentShaderProgram) +Render3DError OpenGLRenderer_3_2::LoadGeometryShaders(std::string &outVertexShaderProgram, std::string &outFragmentShaderProgram) { - *outVertexShaderProgram = std::string(vertexShader_150); - *outFragmentShaderProgram = std::string(fragmentShader_150); + outVertexShaderProgram.clear(); + outFragmentShaderProgram.clear(); + + outVertexShaderProgram = std::string(GeometryVtxShader_150); + outFragmentShaderProgram = std::string(GeometryFragShader_150); return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_3_2::SetupShaderIO() +Render3DError OpenGLRenderer_3_2::InitGeometryProgramBindings() { OGLRenderRef &OGLRef = *this->ref; @@ -558,7 +670,10 @@ Render3DError OpenGLRenderer_3_2::EnableVertexAttributes(const VERTLIST *vertLis { OGLRenderRef &OGLRef = *this->ref; - glBindVertexArray(OGLRef.vaoMainStatesID); + glBindVertexArray(OGLRef.vaoGeometryStatesID); + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboGeometryVtxID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboGeometryIndexID); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VERT) * vertList->count, vertList); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, vertIndexCount * sizeof(GLushort), indexBuffer); @@ -588,15 +703,87 @@ Render3DError OpenGLRenderer_3_2::DownsampleFBO() if (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, OGLRef.selectedRenderingFBO); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboOutputID); + glBindFramebuffer(GL_READ_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderID); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboRenderID); + + // Blit the color buffer + glReadBuffer(GL_COLOR_ATTACHMENT0); + glDrawBuffer(GL_COLOR_ATTACHMENT0); glBlitFramebuffer(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboOutputID); + + // Blit the working depth buffer + glReadBuffer(GL_COLOR_ATTACHMENT1); + glDrawBuffer(GL_COLOR_ATTACHMENT1); + glBlitFramebuffer(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // Blit the fog buffer + glReadBuffer(GL_COLOR_ATTACHMENT2); + glDrawBuffer(GL_COLOR_ATTACHMENT2); + glBlitFramebuffer(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // Reset framebuffer targets + glReadBuffer(GL_COLOR_ATTACHMENT0); + glDrawBuffers(3, RenderDrawList); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID); } return OGLERROR_NOERR; } +Render3DError OpenGLRenderer_3_2::RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift) +{ + OGLRenderRef &OGLRef = *this->ref; + static GLfloat oglDensityTable[32]; + + for (size_t i = 0; i < 32; i++) + { + oglDensityTable[i] = (densityTable[i] == 127) ? 1.0f : (GLfloat)densityTable[i] / 128.0f; + } + + const GLfloat oglColor[4] = {divide5bitBy31_LUT[(color ) & 0x0000001F], + divide5bitBy31_LUT[(color >> 5) & 0x0000001F], + divide5bitBy31_LUT[(color >> 10) & 0x0000001F], + divide5bitBy31_LUT[(color >> 16) & 0x0000001F]}; + + const GLfloat oglOffset = (GLfloat)offset / 32767.0f; + const GLfloat oglFogStep = (GLfloat)(0x0400 >> shift) / 32767.0f; + + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboPostprocessID); + glUseProgram(OGLRef.programFogID); + glUniform1i(OGLRef.uniformTexGColor, OGLTextureUnitID_GColor); + glUniform1i(OGLRef.uniformTexGDepth, OGLTextureUnitID_GDepth); + glUniform1i(OGLRef.uniformTexGFog, OGLTextureUnitID_FogAttr); + glUniform4f(OGLRef.uniformStateFogColor, oglColor[0], oglColor[1], oglColor[2], oglColor[3]); + glUniform1f(OGLRef.uniformStateFogOffset, oglOffset); + glUniform1f(OGLRef.uniformStateFogStep, oglFogStep); + glUniform1fv(OGLRef.uniformStateFogDensity, 32, oglDensityTable); + + glViewport(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + glDisable(GL_BLEND); + glDisable(GL_CULL_FACE); + + glBindBuffer(GL_ARRAY_BUFFER, OGLRef.vboPostprocessVtxID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, OGLRef.iboPostprocessIndexID); + glBindVertexArray(OGLRef.vaoPostprocessStatesID); + + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GDepth); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthID); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGFogAttrID); + glActiveTexture(GL_TEXTURE0); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); + glBindTexture(GL_TEXTURE_2D, 0); + + glBindVertexArray(0); + + return OGLERROR_NOERR; +} + Render3DError OpenGLRenderer_3_2::ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthStencilBuffer, const bool *__restrict fogBuffer) { OGLRenderRef &OGLRef = *this->ref; @@ -626,7 +813,7 @@ Render3DError OpenGLRenderer_3_2::ClearUsingImage(const u16 *__restrict colorBuf // Reset framebuffer targets glReadBuffer(GL_COLOR_ATTACHMENT0); glDrawBuffers(3, RenderDrawList); - glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.selectedRenderingFBO); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderID); } return OGLERROR_NOERR; diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index 7aedf32f3..25f633ffc 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -61,6 +61,7 @@ class OpenGLRenderer_3_2 : public OpenGLRenderer_2_1 { protected: virtual Render3DError InitExtensions(); + virtual Render3DError InitPostprocessingProgramBindings(); virtual Render3DError CreateFBOs(); virtual void DestroyFBOs(); virtual Render3DError CreateMultisampledFBO(); @@ -68,14 +69,15 @@ protected: virtual Render3DError CreateVAOs(); virtual void DestroyVAOs(); - virtual Render3DError LoadShaderPrograms(std::string *outVertexShaderProgram, std::string *outFragmentShaderProgram); - virtual Render3DError SetupShaderIO(); + virtual Render3DError LoadGeometryShaders(std::string &outVertexShaderProgram, std::string &outFragmentShaderProgram); + virtual Render3DError InitGeometryProgramBindings(); virtual void GetExtensionSet(std::set *oglExtensionSet); virtual Render3DError EnableVertexAttributes(const VERTLIST *vertList, const GLushort *indexBuffer, const size_t vertIndexCount); virtual Render3DError DisableVertexAttributes(); virtual Render3DError SelectRenderingFramebuffer(); virtual Render3DError DownsampleFBO(); + virtual Render3DError RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift); virtual Render3DError ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthStencilBuffer, const bool *__restrict fogBuffer); diff --git a/desmume/src/render3D.cpp b/desmume/src/render3D.cpp index 180fc72fe..1ae745b3a 100644 --- a/desmume/src/render3D.cpp +++ b/desmume/src/render3D.cpp @@ -126,6 +126,11 @@ Render3DError Render3D::RenderGeometry(const GFX3D_State *renderState, const VER return RENDER3DERROR_NOERR; } +Render3DError Render3D::RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift) +{ + return RENDER3DERROR_NOERR; +} + Render3DError Render3D::EndRender(const u64 frameCount) { return RENDER3DERROR_NOERR; @@ -246,6 +251,11 @@ Render3DError Render3D::Render(const GFX3D_State *renderState, const VERTLIST *v this->ClearFramebuffer(renderState); this->RenderGeometry(renderState, vertList, polyList, indexList); + + if (renderState->enableFog) + { + this->RenderFog(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0360, renderState->fogColor, renderState->fogOffset, renderState->fogShift); + } this->EndRender(frameCount); diff --git a/desmume/src/render3D.h b/desmume/src/render3D.h index a55ddce49..b4176aba5 100644 --- a/desmume/src/render3D.h +++ b/desmume/src/render3D.h @@ -90,6 +90,7 @@ protected: virtual Render3DError BeginRender(const GFX3D_State *renderState); virtual Render3DError RenderGeometry(const GFX3D_State *renderState, const VERTLIST *vertList, const POLYLIST *polyList, const INDEXLIST *indexList); + virtual Render3DError RenderFog(const u8 *densityTable, const u32 color, const u32 offset, const u8 shift); virtual Render3DError EndRender(const u64 frameCount); virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer);