desmume/desmume/src/OGLRender_3_2.cpp

1048 lines
39 KiB
C++

/*
Copyright (C) 2006 yopyop
Copyright (C) 2006-2007 shash
Copyright (C) 2008-2015 DeSmuME team
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#include "OGLRender_3_2.h"
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "gfx3d.h"
#include "NDSSystem.h"
#include "texcache.h"
//------------------------------------------------------------
// Basic Functions
OGLEXT(PFNGLGETSTRINGIPROC, glGetStringi) // Core in v3.0
// Shaders
OGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation) // Core in v3.0
// FBO
OGLEXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) // Core in v3.0
OGLEXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) // Core in v3.0
OGLEXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) // Core in v3.0
OGLEXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) // Core in v3.0
OGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) // Core in v3.0
OGLEXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) // Core in v3.0
OGLEXT(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer) // Core in v3.0
OGLEXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) // Core in v3.0
OGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Core in v3.0
OGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Core in v3.0
OGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Core in v3.0
OGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Core in v3.0
void OGLLoadEntryPoints_3_2()
{
// Basic Functions
INITOGLEXT(PFNGLGETSTRINGIPROC, glGetStringi)
// Shaders
INITOGLEXT(PFNGLBINDFRAGDATALOCATIONPROC, glBindFragDataLocation)
// FBO
INITOGLEXT(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers) // Promote to core version
INITOGLEXT(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer) // Promote to core version
INITOGLEXT(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer) // Promote to core version
INITOGLEXT(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D) // Promote to core version
INITOGLEXT(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus) // Promote to core version
INITOGLEXT(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers) // Promote to core version
INITOGLEXT(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer) // Promote to core version
INITOGLEXT(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers) // Promote to core version
INITOGLEXT(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer) // Promote to core version
INITOGLEXT(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage) // Promote to core version
INITOGLEXT(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample) // Promote to core version
INITOGLEXT(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers) // Promote to core version
}
// Vertex shader for geometry, GLSL 1.50
static const char *GeometryVtxShader_150 = {"\
#version 150 \n\
\n\
in vec4 inPosition; \n\
in vec2 inTexCoord0; \n\
in vec3 inColor; \n\
\n\
uniform float polyAlpha; \n\
uniform vec2 polyTexScale; \n\
\n\
out vec4 vtxPosition; \n\
out vec2 vtxTexCoord; \n\
out vec4 vtxColor; \n\
\n\
void main() \n\
{ \n\
mat2 texScaleMtx = mat2( vec2(polyTexScale.x, 0.0), \n\
vec2( 0.0, polyTexScale.y)); \n\
\n\
vtxPosition = inPosition; \n\
vtxTexCoord = texScaleMtx * inTexCoord0; \n\
vtxColor = vec4(inColor * 4.0, polyAlpha); \n\
\n\
gl_Position = vtxPosition; \n\
} \n\
"};
// Fragment shader for geometry, GLSL 1.50
static const char *GeometryFragShader_150 = {"\
#version 150 \n\
\n\
in vec4 vtxPosition; \n\
in vec2 vtxTexCoord; \n\
in vec4 vtxColor; \n\
\n\
uniform sampler2D texRenderObject; \n\
uniform sampler1D texToonTable; \n\
\n\
uniform int stateToonShadingMode; \n\
uniform bool stateEnableAlphaTest; \n\
uniform bool stateEnableAntialiasing;\n\
uniform bool stateEnableEdgeMarking;\n\
uniform bool stateEnableFogAlphaOnly;\n\
uniform bool stateUseWDepth; \n\
uniform float stateAlphaTestRef; \n\
\n\
uniform int polyMode; \n\
uniform bool polyEnableDepthWrite;\n\
uniform bool polySetNewDepthForTranslucent;\n\
uniform int polyID; \n\
\n\
uniform bool polyEnableTexture; \n\
uniform bool polyEnableFog;\n\
\n\
out vec4 outFragColor;\n\
out vec4 outFragDepth;\n\
out vec4 outPolyID;\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\
vec4 newFragColor = mainTexColor * vtxColor; \n\
\n\
if(polyMode == 1) \n\
{ \n\
newFragColor.rgb = (polyEnableTexture) ? mix(vtxColor.rgb, mainTexColor.rgb, mainTexColor.a) : vtxColor.rgb; \n\
newFragColor.a = vtxColor.a; \n\
} \n\
else if(polyMode == 2) \n\
{ \n\
vec3 toonColor = vec3(texture(texToonTable, vtxColor.r).rgb); \n\
newFragColor.rgb = (stateToonShadingMode == 0) ? mainTexColor.rgb * toonColor.rgb : min((mainTexColor.rgb * vtxColor.rgb) + toonColor.rgb, 1.0); \n\
} \n\
else if(polyMode == 3) \n\
{ \n\
if (polyID != 0) \n\
{ \n\
newFragColor = vtxColor; \n\
} \n\
} \n\
\n\
if (newFragColor.a == 0.0 || (stateEnableAlphaTest && newFragColor.a < stateAlphaTestRef)) \n\
{ \n\
discard; \n\
} \n\
\n\
float vertW = (vtxPosition.w == 0.0) ? 0.00000001 : vtxPosition.w; \n\
float newFragDepth = (stateUseWDepth) ? vtxPosition.w/4096.0 : clamp((vtxPosition.z/vertW) * 0.5 + 0.5, 0.0, 1.0); \n\
\n\
outFragColor = newFragColor;\n\
outFogAttributes = vec4( float(polyEnableFog), float(stateEnableFogAlphaOnly), 0.0, 1.0);\n\
if (newFragColor.a > 0.999) outPolyID = vec4(float(polyID)/63.0, float(stateEnableAntialiasing), 0.0, 1.0);\n\
if (polyEnableDepthWrite && (newFragColor.a > 0.999 || polySetNewDepthForTranslucent)) outFragDepth = vec4( packVec3FromFloat(newFragDepth), 1.0);\n\
gl_FragDepth = newFragDepth;\n\
} \n\
"};
// Vertex shader for applying edge marking, GLSL 1.50
static const char *EdgeMarkVtxShader_150 = {"\
#version 150\n\
\n\
in vec2 inPosition;\n\
in vec2 inTexCoord0;\n\
uniform vec2 framebufferSize;\n\
out vec2 texCoord[5];\n\
\n\
void main()\n\
{\n\
vec2 texInvScale = vec2(1.0/framebufferSize.x, 1.0/framebufferSize.y);\n\
\n\
texCoord[0] = inTexCoord0; // Center\n\
texCoord[1] = inTexCoord0 + (vec2( 1.0, 0.0) * texInvScale); // Right\n\
texCoord[2] = inTexCoord0 + (vec2( 0.0, 1.0) * texInvScale); // Down\n\
texCoord[3] = inTexCoord0 + (vec2(-1.0, 0.0) * texInvScale); // Left\n\
texCoord[4] = inTexCoord0 + (vec2( 0.0,-1.0) * texInvScale); // Up\n\
\n\
gl_Position = vec4(inPosition, 0.0, 1.0);\n\
}\n\
"};
// Fragment shader for applying edge marking, GLSL 1.50
static const char *EdgeMarkFragShader_150 = {"\
#version 150\n\
\n\
in vec2 texCoord[5];\n\
\n\
uniform sampler2D texInFragColor;\n\
uniform sampler2D texInFragDepth;\n\
uniform sampler2D texInPolyID;\n\
uniform vec4 stateEdgeColor[8];\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[0]);\n\
float inFragDepth = unpackFloatFromVec3(texture(texInFragDepth, texCoord[0]).rgb);\n\
\n\
vec4 inPolyIDAttributes[5];\n\
inPolyIDAttributes[0] = texture(texInPolyID, texCoord[0]);\n\
inPolyIDAttributes[1] = texture(texInPolyID, texCoord[1]);\n\
inPolyIDAttributes[2] = texture(texInPolyID, texCoord[2]);\n\
inPolyIDAttributes[3] = texture(texInPolyID, texCoord[3]);\n\
inPolyIDAttributes[4] = texture(texInPolyID, texCoord[4]);\n\
\n\
int polyID[5];\n\
polyID[0] = int((inPolyIDAttributes[0].r * 63.0) + 0.5);\n\
polyID[1] = int((inPolyIDAttributes[1].r * 63.0) + 0.5);\n\
polyID[2] = int((inPolyIDAttributes[2].r * 63.0) + 0.5);\n\
polyID[3] = int((inPolyIDAttributes[3].r * 63.0) + 0.5);\n\
polyID[4] = int((inPolyIDAttributes[4].r * 63.0) + 0.5);\n\
\n\
bool antialias[5];\n\
antialias[0] = bool(inPolyIDAttributes[0].g);\n\
antialias[1] = bool(inPolyIDAttributes[1].g);\n\
antialias[2] = bool(inPolyIDAttributes[2].g);\n\
antialias[3] = bool(inPolyIDAttributes[3].g);\n\
antialias[4] = bool(inPolyIDAttributes[4].g);\n\
\n\
float depth[5];\n\
depth[0] = unpackFloatFromVec3(texture(texInFragDepth, texCoord[0]).rgb);\n\
depth[1] = unpackFloatFromVec3(texture(texInFragDepth, texCoord[1]).rgb);\n\
depth[2] = unpackFloatFromVec3(texture(texInFragDepth, texCoord[2]).rgb);\n\
depth[3] = unpackFloatFromVec3(texture(texInFragDepth, texCoord[3]).rgb);\n\
depth[4] = unpackFloatFromVec3(texture(texInFragDepth, texCoord[4]).rgb);\n\
\n\
vec4 edgeColor = stateEdgeColor[polyID[0]/8];\n\
bool doEdgeMark = false;\n\
bool doAntialias = false;\n\
\n\
for (int i = 1; i < 5; i++)\n\
{\n\
if (polyID[0] != polyID[i] && depth[0] >= depth[i])\n\
{\n\
doEdgeMark = true;\n\
edgeColor = stateEdgeColor[polyID[i]/8];\n\
doAntialias = antialias[i];\n\
break;\n\
}\n\
}\n\
\n\
outFragColor = (doEdgeMark) ? ((doAntialias) ? mix(edgeColor, inFragColor, 0.4) : edgeColor) : inFragColor;\n\
}\n\
"};
// Vertex shader for applying fog, GLSL 1.50
static const char *FogVtxShader_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 texInFragDepth;\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(texInFragDepth, 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))
{
*rendererPtr = new OpenGLRenderer_3_2;
(*rendererPtr)->SetVersion(3, 2, 0);
}
}
OpenGLRenderer_3_2::~OpenGLRenderer_3_2()
{
glFinish();
DestroyVAOs();
DestroyFBOs();
DestroyMultisampledFBO();
}
Render3DError OpenGLRenderer_3_2::InitExtensions()
{
Render3DError error = OGLERROR_NOERR;
// Get OpenGL extensions
std::set<std::string> oglExtensionSet;
this->GetExtensionSet(&oglExtensionSet);
// Initialize OpenGL
this->InitTables();
// Load and create shaders. Return on any error, since v3.2 Core Profile makes shaders mandatory.
this->isShaderSupported = true;
std::string vertexShaderProgram;
std::string fragmentShaderProgram;
error = this->LoadGeometryShaders(vertexShaderProgram, fragmentShaderProgram);
if (error != OGLERROR_NOERR)
{
this->isShaderSupported = false;
return error;
}
error = this->InitGeometryProgram(vertexShaderProgram, fragmentShaderProgram);
if (error != OGLERROR_NOERR)
{
this->isShaderSupported = false;
return error;
}
std::string edgeMarkVtxShaderString = std::string(EdgeMarkVtxShader_150);
std::string edgeMarkFragShaderString = std::string(EdgeMarkFragShader_150);
std::string fogVtxShaderString = std::string(FogVtxShader_150);
std::string fogFragShaderString = std::string(FogFragShader_150);
error = this->InitPostprocessingPrograms(edgeMarkVtxShaderString, edgeMarkFragShaderString, fogVtxShaderString, fogFragShaderString);
if (error != OGLERROR_NOERR)
{
this->DestroyGeometryProgram();
this->isShaderSupported = false;
return error;
}
this->isVBOSupported = true;
this->CreateVBOs();
this->isPBOSupported = true;
this->CreatePBOs();
this->isVAOSupported = true;
this->CreateVAOs();
// Load and create FBOs. Return on any error, since v3.2 Core Profile makes FBOs mandatory.
this->isFBOSupported = true;
error = this->CreateFBOs();
if (error != OGLERROR_NOERR)
{
this->isFBOSupported = false;
return error;
}
this->isMultisampledFBOSupported = true;
error = this->CreateMultisampledFBO();
if (error != OGLERROR_NOERR)
{
this->isMultisampledFBOSupported = false;
if (error == OGLERROR_FBO_CREATE_ERROR)
{
// Return on OGLERROR_FBO_CREATE_ERROR, since a v3.0 driver should be able to
// support FBOs.
return error;
}
}
this->InitTextures();
this->InitFinalRenderStates(&oglExtensionSet); // This must be done last
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_3_2::InitEdgeMarkProgramBindings()
{
OGLRenderRef &OGLRef = *this->ref;
glBindAttribLocation(OGLRef.programEdgeMarkID, OGLVertexAttributeID_Position, "inPosition");
glBindAttribLocation(OGLRef.programEdgeMarkID, OGLVertexAttributeID_TexCoord0, "inTexCoord0");
glBindFragDataLocation(OGLRef.programEdgeMarkID, 0, "outFragColor");
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_3_2::InitFogProgramBindings()
{
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;
// Set up FBO render targets
glGenTextures(1, &OGLRef.texGColorID);
glGenTextures(1, &OGLRef.texGDepthID);
glGenTextures(1, &OGLRef.texGPolyID);
glGenTextures(1, &OGLRef.texGFogAttrID);
glGenTextures(1, &OGLRef.texGDepthStencilID);
glGenTextures(1, &OGLRef.texPostprocessEdgeMarkID);
glGenTextures(1, &OGLRef.texPostprocessFogID);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID);
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, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthID);
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, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGPolyID);
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, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGFogAttrID);
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, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessEdgeMarkID);
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, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessFogID);
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, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
// Set up FBOs
glGenFramebuffers(1, &OGLRef.fboRenderID);
glGenFramebuffers(1, &OGLRef.fboPostprocessID);
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OGLRef.texGColorID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, OGLRef.texGDepthID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, OGLRef.texGPolyID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, OGLRef.texGFogAttrID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &OGLRef.fboRenderID);
glDeleteFramebuffers(1, &OGLRef.fboPostprocessID);
glDeleteTextures(1, &OGLRef.texGColorID);
glDeleteTextures(1, &OGLRef.texGDepthID);
glDeleteTextures(1, &OGLRef.texGPolyID);
glDeleteTextures(1, &OGLRef.texGFogAttrID);
glDeleteTextures(1, &OGLRef.texGDepthStencilID);
glDeleteTextures(1, &OGLRef.texPostprocessEdgeMarkID);
glDeleteTextures(1, &OGLRef.texPostprocessFogID);
OGLRef.fboRenderID = 0;
OGLRef.fboPostprocessID = 0;
return OGLERROR_FBO_CREATE_ERROR;
}
glDrawBuffers(4, RenderDrawList);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboPostprocessID);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OGLRef.texPostprocessEdgeMarkID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, OGLRef.texPostprocessFogID, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &OGLRef.fboRenderID);
glDeleteFramebuffers(1, &OGLRef.fboPostprocessID);
glDeleteTextures(1, &OGLRef.texGColorID);
glDeleteTextures(1, &OGLRef.texGDepthID);
glDeleteTextures(1, &OGLRef.texGPolyID);
glDeleteTextures(1, &OGLRef.texGFogAttrID);
glDeleteTextures(1, &OGLRef.texGDepthStencilID);
glDeleteTextures(1, &OGLRef.texPostprocessEdgeMarkID);
glDeleteTextures(1, &OGLRef.texPostprocessFogID);
OGLRef.fboRenderID = 0;
OGLRef.fboPostprocessID = 0;
return OGLERROR_FBO_CREATE_ERROR;
}
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
OGLRef.selectedRenderingFBO = OGLRef.fboRenderID;
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.selectedRenderingFBO);
INFO("OpenGL: Successfully created FBOs.\n");
return OGLERROR_NOERR;
}
void OpenGLRenderer_3_2::DestroyFBOs()
{
if (!this->isFBOSupported)
{
return;
}
OGLRenderRef &OGLRef = *this->ref;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &OGLRef.fboRenderID);
glDeleteFramebuffers(1, &OGLRef.fboPostprocessID);
glDeleteTextures(1, &OGLRef.texGColorID);
glDeleteTextures(1, &OGLRef.texGDepthID);
glDeleteTextures(1, &OGLRef.texGPolyID);
glDeleteTextures(1, &OGLRef.texGFogAttrID);
glDeleteTextures(1, &OGLRef.texGDepthStencilID);
glDeleteTextures(1, &OGLRef.texPostprocessEdgeMarkID);
glDeleteTextures(1, &OGLRef.texPostprocessFogID);
OGLRef.fboRenderID = 0;
OGLRef.fboPostprocessID = 0;
this->isFBOSupported = false;
}
Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO()
{
// Check the maximum number of samples that the GPU supports and use that.
// Since our target resolution is only 256x192 pixels, using the most samples
// possible is the best thing to do.
GLint maxSamples = 0;
glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
if (maxSamples < 2)
{
INFO("OpenGL: GPU does not support at least 2x multisampled FBOs. Multisample antialiasing will be disabled.\n");
return OGLERROR_FEATURE_UNSUPPORTED;
}
else if (maxSamples > OGLRENDER_MAX_MULTISAMPLES)
{
maxSamples = OGLRENDER_MAX_MULTISAMPLES;
}
OGLRenderRef &OGLRef = *this->ref;
// Set up FBO render targets
glGenRenderbuffers(1, &OGLRef.rboMSGColorID);
glGenRenderbuffers(1, &OGLRef.rboMSGDepthID);
glGenRenderbuffers(1, &OGLRef.rboMSGPolyID);
glGenRenderbuffers(1, &OGLRef.rboMSGFogAttrID);
glGenRenderbuffers(1, &OGLRef.rboMSGDepthStencilID);
glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGColorID);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamples, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthID);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamples, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGPolyID);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamples, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamples, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamples, GL_DEPTH24_STENCIL8, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT);
// Set up multisampled rendering FBO
glGenFramebuffers(1, &OGLRef.fboMSIntermediateRenderID);
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderID);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, OGLRef.rboMSGColorID);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, OGLRef.rboMSGDepthID);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER, OGLRef.rboMSGPolyID);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
INFO("OpenGL: Failed to create multisampled FBO. Multisample antialiasing will be disabled.\n");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &OGLRef.fboMSIntermediateRenderID);
glDeleteRenderbuffers(1, &OGLRef.rboMSGColorID);
glDeleteRenderbuffers(1, &OGLRef.rboMSGDepthID);
glDeleteRenderbuffers(1, &OGLRef.rboMSGPolyID);
glDeleteRenderbuffers(1, &OGLRef.rboMSGFogAttrID);
glDeleteRenderbuffers(1, &OGLRef.rboMSGDepthStencilID);
OGLRef.fboMSIntermediateRenderID = 0;
return OGLERROR_FBO_CREATE_ERROR;
}
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID);
INFO("OpenGL: Successfully created multisampled FBO.\n");
return OGLERROR_NOERR;
}
void OpenGLRenderer_3_2::DestroyMultisampledFBO()
{
if (!this->isMultisampledFBOSupported)
{
return;
}
OGLRenderRef &OGLRef = *this->ref;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &OGLRef.fboMSIntermediateRenderID);
glDeleteRenderbuffers(1, &OGLRef.rboMSGColorID);
glDeleteRenderbuffers(1, &OGLRef.rboMSGDepthID);
glDeleteRenderbuffers(1, &OGLRef.rboMSGPolyID);
glDeleteRenderbuffers(1, &OGLRef.rboMSGFogAttrID);
glDeleteRenderbuffers(1, &OGLRef.rboMSGDepthStencilID);
OGLRef.fboMSIntermediateRenderID = 0;
this->isMultisampledFBOSupported = false;
}
Render3DError OpenGLRenderer_3_2::CreateVAOs()
{
OGLRenderRef &OGLRef = *this->ref;
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;
}
void OpenGLRenderer_3_2::DestroyVAOs()
{
if (!this->isVAOSupported)
{
return;
}
OGLRenderRef &OGLRef = *this->ref;
glBindVertexArray(0);
glDeleteVertexArrays(1, &OGLRef.vaoGeometryStatesID);
glDeleteVertexArrays(1, &OGLRef.vaoPostprocessStatesID);
this->isVAOSupported = false;
}
Render3DError OpenGLRenderer_3_2::LoadGeometryShaders(std::string &outVertexShaderProgram, std::string &outFragmentShaderProgram)
{
outVertexShaderProgram.clear();
outFragmentShaderProgram.clear();
outVertexShaderProgram = std::string(GeometryVtxShader_150);
outFragmentShaderProgram = std::string(GeometryFragShader_150);
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_3_2::InitGeometryProgramBindings()
{
OGLRenderRef &OGLRef = *this->ref;
glBindAttribLocation(OGLRef.programGeometryID, OGLVertexAttributeID_Position, "inPosition");
glBindAttribLocation(OGLRef.programGeometryID, OGLVertexAttributeID_TexCoord0, "inTexCoord0");
glBindAttribLocation(OGLRef.programGeometryID, OGLVertexAttributeID_Color, "inColor");
glBindFragDataLocation(OGLRef.programGeometryID, 0, "outFragColor");
glBindFragDataLocation(OGLRef.programGeometryID, 1, "outFragDepth");
glBindFragDataLocation(OGLRef.programGeometryID, 2, "outPolyID");
glBindFragDataLocation(OGLRef.programGeometryID, 3, "outFogAttributes");
return OGLERROR_NOERR;
}
void OpenGLRenderer_3_2::GetExtensionSet(std::set<std::string> *oglExtensionSet)
{
GLint extensionCount = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount);
for (size_t i = 0; i < extensionCount; i++)
{
std::string extensionName = std::string((const char *)glGetStringi(GL_EXTENSIONS, i));
oglExtensionSet->insert(extensionName);
}
}
Render3DError OpenGLRenderer_3_2::EnableVertexAttributes(const VERTLIST *vertList, const GLushort *indexBuffer, const size_t vertIndexCount)
{
OGLRenderRef &OGLRef = *this->ref;
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);
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_3_2::DisableVertexAttributes()
{
glBindVertexArray(0);
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_3_2::SelectRenderingFramebuffer()
{
OGLRenderRef &OGLRef = *this->ref;
OGLRef.selectedRenderingFBO = (CommonSettings.GFX3D_Renderer_Multisample) ? OGLRef.fboMSIntermediateRenderID : OGLRef.fboRenderID;
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.selectedRenderingFBO);
glDrawBuffers(4, RenderDrawList);
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_3_2::DownsampleFBO()
{
OGLRenderRef &OGLRef = *this->ref;
if (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID)
{
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);
// 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 polygon ID 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);
// Blit the fog buffer
glReadBuffer(GL_COLOR_ATTACHMENT3);
glDrawBuffer(GL_COLOR_ATTACHMENT3);
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(4, RenderDrawList);
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID);
}
return OGLERROR_NOERR;
}
Render3DError OpenGLRenderer_3_2::RenderEdgeMarking(const u16 *colorTable)
{
OGLRenderRef &OGLRef = *this->ref;
const GLfloat oglColor[4*8] = {divide5bitBy31_LUT[(colorTable[0] ) & 0x001F],
divide5bitBy31_LUT[(colorTable[0] >> 5) & 0x001F],
divide5bitBy31_LUT[(colorTable[0] >> 10) & 0x001F],
1.0f,
divide5bitBy31_LUT[(colorTable[1] ) & 0x001F],
divide5bitBy31_LUT[(colorTable[1] >> 5) & 0x001F],
divide5bitBy31_LUT[(colorTable[1] >> 10) & 0x001F],
1.0f,
divide5bitBy31_LUT[(colorTable[2] ) & 0x001F],
divide5bitBy31_LUT[(colorTable[2] >> 5) & 0x001F],
divide5bitBy31_LUT[(colorTable[2] >> 10) & 0x001F],
1.0f,
divide5bitBy31_LUT[(colorTable[3] ) & 0x001F],
divide5bitBy31_LUT[(colorTable[3] >> 5) & 0x001F],
divide5bitBy31_LUT[(colorTable[3] >> 10) & 0x001F],
1.0f,
divide5bitBy31_LUT[(colorTable[4] ) & 0x001F],
divide5bitBy31_LUT[(colorTable[4] >> 5) & 0x001F],
divide5bitBy31_LUT[(colorTable[4] >> 10) & 0x001F],
1.0f,
divide5bitBy31_LUT[(colorTable[5] ) & 0x001F],
divide5bitBy31_LUT[(colorTable[5] >> 5) & 0x001F],
divide5bitBy31_LUT[(colorTable[5] >> 10) & 0x001F],
1.0f,
divide5bitBy31_LUT[(colorTable[6] ) & 0x001F],
divide5bitBy31_LUT[(colorTable[6] >> 5) & 0x001F],
divide5bitBy31_LUT[(colorTable[6] >> 10) & 0x001F],
1.0f,
divide5bitBy31_LUT[(colorTable[7] ) & 0x001F],
divide5bitBy31_LUT[(colorTable[7] >> 5) & 0x001F],
divide5bitBy31_LUT[(colorTable[7] >> 10) & 0x001F],
1.0f};
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboPostprocessID);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glUseProgram(OGLRef.programEdgeMarkID);
glUniform1i(OGLRef.uniformTexGColor_EdgeMark, OGLTextureUnitID_GColor);
glUniform1i(OGLRef.uniformTexGDepth_EdgeMark, OGLTextureUnitID_GDepth);
glUniform1i(OGLRef.uniformTexGPolyID_EdgeMark, OGLTextureUnitID_GPolyID);
glUniform2f(OGLRef.uniformFramebufferSize, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT);
glUniform4fv(OGLRef.uniformStateEdgeColor, 8, oglColor);
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_GPolyID);
glBindTexture(GL_TEXTURE_2D, OGLRef.texGPolyID);
glActiveTexture(GL_TEXTURE0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
this->didRenderEdgeMark = true;
return RENDER3DERROR_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);
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glReadBuffer(GL_COLOR_ATTACHMENT1);
glUseProgram(OGLRef.programFogID);
glUniform1i(OGLRef.uniformTexGColor_Fog, OGLTextureUnitID_GColor);
glUniform1i(OGLRef.uniformTexGDepth_Fog, OGLTextureUnitID_GDepth);
glUniform1i(OGLRef.uniformTexGFog_Fog, 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, (this->didRenderEdgeMark) ? OGLRef.texPostprocessEdgeMarkID : 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;
this->UploadClearImage(colorBuffer, depthStencilBuffer, fogBuffer);
if (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID)
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, OGLRef.fboRenderID);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderID);
// 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_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
// 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 polygon ID 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);
// Blit the fog buffer
glReadBuffer(GL_COLOR_ATTACHMENT3);
glDrawBuffer(GL_COLOR_ATTACHMENT3);
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(4, RenderDrawList);
glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderID);
}
return OGLERROR_NOERR;
}