diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 3b29be3c8..5319b300f 100644 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -72,6 +72,8 @@ static void ENDGL() { #include "OGLRender.h" #include "gfx3d.h" +#include "shaders.h" + #ifndef CTASSERT #define CTASSERT(x) typedef char __assert ## y[(x) ? 1 : -1] #endif @@ -97,6 +99,7 @@ static bool wireframe=false, alpha31=false; static unsigned int polyID=0; static unsigned int depthFuncMode=0; static unsigned int envMode=0; +static unsigned int lastEnvMode=0; static unsigned int cullingMask=0; static bool alphaDepthWrite; static unsigned int lightMask=0; @@ -104,10 +107,13 @@ static bool isTranslucent; //------------------------------------------------------------ -#ifdef _WIN32 - #define OGLEXT(x,y) x y = 0; + +#ifdef _WIN32 #define INITOGLEXT(x,y) y = (x)wglGetProcAddress(#y); +#else +#define INITOGLEXT(x,y) y = (x)glXGetProcAddress(#y); +#endif OGLEXT(PFNGLCREATESHADERPROC,glCreateShader) //zero: i dont understand this at all. my glext.h has the wrong thing declared here... so I have to do it myself @@ -118,14 +124,16 @@ OGLEXT(PFNGLCREATEPROGRAMPROC,glCreateProgram) OGLEXT(PFNGLATTACHSHADERPROC,glAttachShader) OGLEXT(PFNGLLINKPROGRAMPROC,glLinkProgram) OGLEXT(PFNGLUSEPROGRAMPROC,glUseProgram) +OGLEXT(PFNGLGETSHADERIVPROC,glGetShaderiv) OGLEXT(PFNGLGETSHADERINFOLOGPROC,glGetShaderInfoLog) +OGLEXT(PFNGLDELETESHADERPROC,glDeleteShader) +OGLEXT(PFNGLGETPROGRAMIVPROC,glGetProgramiv) +OGLEXT(PFNGLGETPROGRAMINFOLOGPROC,glGetProgramInfoLog) +OGLEXT(PFNGLVALIDATEPROGRAMPROC,glValidateProgram) OGLEXT(PFNGLBLENDFUNCSEPARATEEXTPROC,glBlendFuncSeparateEXT) - -#else - -#define INITOGLEXT(x,y) y = 0; - -#endif +OGLEXT(PFNGLGETUNIFORMLOCATIONPROC,glGetUniformLocation) +OGLEXT(PFNGLUNIFORM1IPROC,glUniform1i) +OGLEXT(PFNGLACTIVETEXTUREPROC,glActiveTexture) //opengl state caching: @@ -148,6 +156,7 @@ static void xglPolygonMode(GLenum face,GLenum mode) { } } +#if 0 #ifdef _WIN32 static void xglUseProgram(GLuint program) { if(!glUseProgram) return; @@ -163,6 +172,7 @@ static void xglUseProgram(GLuint program) { } #endif #endif +#endif static void xglDepthMask (GLboolean flag) { static GLboolean oldflag = -1; @@ -237,7 +247,104 @@ u32 texcache_stop; GLenum oglTempTextureID[MAX_TEXTURE]; GLenum oglToonTableTextureID; -u32 toonShader, toonProgram; + +#define NOSHADERS(i) { hasShaders = false; INFO("Shaders aren't supported on your system, using fixed pipeline\n(failed shader init at step %i)\n", i); return; } + +#define SHADER_COMPCHECK(s) { \ + GLint status = GL_TRUE; \ + glGetShaderiv(s, GL_COMPILE_STATUS, &status); \ + if(status != GL_TRUE) \ + { \ + GLint logSize; \ + GLchar *log; \ + glGetShaderiv(s, GL_INFO_LOG_LENGTH, &logSize); \ + log = new GLchar[logSize]; \ + glGetShaderInfoLog(s, logSize, &logSize, log); \ + INFO("SEVERE : FAILED TO COMPILE GL SHADER : %s\n", log); \ + delete log; \ + if(s)glDeleteShader(s); \ + NOSHADERS(3); \ + } \ +} + +#define PROGRAM_COMPCHECK(p, s1, s2) { \ + GLint status = GL_TRUE; \ + glGetProgramiv(p, GL_LINK_STATUS, &status); \ + if(status != GL_TRUE) \ + { \ + GLint logSize; \ + GLchar *log; \ + glGetProgramiv(p, GL_INFO_LOG_LENGTH, &logSize); \ + log = new GLchar[logSize]; \ + glGetProgramInfoLog(p, logSize, &logSize, log); \ + INFO("SEVERE : FAILED TO LINK GL SHADER PROGRAM : %s\n", log); \ + delete log; \ + if(s1)glDeleteShader(s1); \ + if(s2)glDeleteShader(s2); \ + NOSHADERS(5); \ + } \ +} + +bool hasShaders = false; + +/* Vertex shader */ +GLuint vertexShaderID; +/* Fragment shader */ +GLuint fragmentShaderID; +/* Shader program */ +GLuint shaderProgram; + +static GLuint hasTexLoc; +static GLuint texBlendLoc; + +/* Shaders init */ + +void createShaders() +{ + hasShaders = true; + + if (!glCreateShader || + !glShaderSource || + !glCompileShader || + !glCreateProgram || + !glAttachShader || + !glLinkProgram || + !glUseProgram || + !glGetShaderInfoLog) + NOSHADERS(1); + + vertexShaderID = glCreateShader(GL_VERTEX_SHADER); + if(!vertexShaderID) + NOSHADERS(2); + + glShaderSource(vertexShaderID, 1, (GLchar**)&vertexShader, NULL); + glCompileShader(vertexShaderID); + SHADER_COMPCHECK(vertexShaderID); + + fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + if(!fragmentShaderID) + NOSHADERS(2); + + glShaderSource(fragmentShaderID, 1, (GLchar**)&fragmentShader, NULL); + glCompileShader(fragmentShaderID); + SHADER_COMPCHECK(fragmentShaderID); + + shaderProgram = glCreateProgram(); + if(!shaderProgram) + NOSHADERS(4); + + glAttachShader(shaderProgram, vertexShaderID); + glAttachShader(shaderProgram, fragmentShaderID); + + glLinkProgram(shaderProgram); + PROGRAM_COMPCHECK(shaderProgram, vertexShaderID, fragmentShaderID); + + glValidateProgram(shaderProgram); + glUseProgram(shaderProgram); + + INFO("Successfully created OpenGL shaders.\n"); +} + //================================================= @@ -260,6 +367,8 @@ static void Reset() static char Init(void) { + GLuint loc; + if(!oglrender_init) return 0; if(!oglrender_init()) @@ -272,6 +381,7 @@ static char Init(void) xglEnable (GL_NORMALIZE); xglEnable (GL_DEPTH_TEST); + glEnable (GL_TEXTURE_1D); glEnable (GL_TEXTURE_2D); glAlphaFunc (GL_GREATER, 0); @@ -285,7 +395,6 @@ static char Init(void) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - #ifdef _WIN32 INITOGLEXT(PFNGLCREATESHADERPROC,glCreateShader) INITOGLEXT(X_PFNGLGETSHADERSOURCEPROC,glShaderSource) INITOGLEXT(PFNGLCOMPILESHADERPROC,glCompileShader) @@ -293,8 +402,33 @@ static char Init(void) INITOGLEXT(PFNGLATTACHSHADERPROC,glAttachShader) INITOGLEXT(PFNGLLINKPROGRAMPROC,glLinkProgram) INITOGLEXT(PFNGLUSEPROGRAMPROC,glUseProgram) + INITOGLEXT(PFNGLGETSHADERIVPROC,glGetShaderiv) INITOGLEXT(PFNGLGETSHADERINFOLOGPROC,glGetShaderInfoLog) + INITOGLEXT(PFNGLDELETESHADERPROC,glDeleteShader) + INITOGLEXT(PFNGLGETPROGRAMIVPROC,glGetProgramiv) + INITOGLEXT(PFNGLGETPROGRAMINFOLOGPROC,glGetProgramInfoLog) + INITOGLEXT(PFNGLVALIDATEPROGRAMPROC,glValidateProgram) INITOGLEXT(PFNGLBLENDFUNCSEPARATEEXTPROC,glBlendFuncSeparateEXT) + INITOGLEXT(PFNGLGETUNIFORMLOCATIONPROC,glGetUniformLocation) + INITOGLEXT(PFNGLUNIFORM1IPROC,glUniform1i) + INITOGLEXT(PFNGLACTIVETEXTUREPROC,glActiveTexture) + + /* Create the shaders */ + createShaders(); + + /* Assign the texture units : 0 for main textures, 1 for toon table */ + /* Also init the locations for some variables in the shaders */ + if(hasShaders) + { + loc = glGetUniformLocation(shaderProgram, "tex2d"); + glUniform1i(loc, 0); + + loc = glGetUniformLocation(shaderProgram, "toonTable"); + glUniform1i(loc, 1); + + hasTexLoc = glGetUniformLocation(shaderProgram, "hasTexture"); + texBlendLoc = glGetUniformLocation(shaderProgram, "texBlending"); + } //we want to use alpha destination blending so we can track the last-rendered alpha value if(glBlendFuncSeparateEXT) @@ -302,51 +436,17 @@ static char Init(void) glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_DST_ALPHA); } - if(glCreateShader && glShaderSource && glCompileShader && glCreateProgram && glAttachShader && glLinkProgram && glUseProgram && glGetShaderInfoLog) - { - { - glGenTextures (1, &oglToonTableTextureID); - glBindTexture(GL_TEXTURE_1D,oglToonTableTextureID); - glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); //clamp so that we dont run off the edges due to 1.0 -> [0,31] math - //do we need to init the toon table? - } - { - char buf[10000]; - const char* toonShaderSource[] = {"\ - uniform sampler2D tex2; \ - uniform sampler1D tex1; \ - void main() {\ - gl_FragColor = gl_Color; \ - gl_FragColor = texture1D(tex1,gl_FragColor.r/32*31); \ - gl_FragColor *= texture2D(tex2,gl_TexCoord[0].st); \ - }\ - "}; + glGenTextures (1, &oglToonTableTextureID); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_1D, oglToonTableTextureID); + glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); //clamp so that we dont run off the edges due to 1.0 -> [0,31] math - //TODO - this should modulate or add depending on whether we are in highlight or toon mode - - toonShader = glCreateShader(GL_FRAGMENT_SHADER); - toonProgram = glCreateProgram(); - glShaderSource(toonShader, 1, (GLchar**)toonShaderSource, 0); - glCompileShader(toonShader); - glGetShaderInfoLog(toonShader,10000,0,buf); - - glAttachShader(toonProgram,toonShader); - glLinkProgram(toonProgram); - - toonShader = 0; - } - } - #endif - -#ifdef _WIN32 if(!glBlendFuncSeparateEXT) -#endif clearAlpha = 1; -#ifdef _WIN32 - else clearAlpha = 0; -#endif + else + clearAlpha = 0; ENDGL(); @@ -463,6 +563,7 @@ static void DebugDumpTexture(int which) //================================================================================ static int lastTexture = -1; +static bool hasTexture = false; static void setTexture(unsigned int format, unsigned int texpal) { int palSize[7]={32,4,16,256,0,8,32768}; @@ -486,14 +587,22 @@ static void setTexture(unsigned int format, unsigned int texpal) if (format==0) { texcache_count=-1; + if(hasShaders && hasTexture) { glUniform1i(hasTexLoc, 0); hasTexture = false; } return; } if (textureMode==0) { texcache_count=-1; + if(hasShaders && hasTexture) { glUniform1i(hasTexLoc, 0); hasTexture = false; } return; } + if(hasShaders) + { + if(!hasTexture) { glUniform1i(hasTexLoc, 1); hasTexture = true; } + glActiveTexture(GL_TEXTURE0); + } + txt_slot_current=(format>>14)&0x03; adr=(unsigned char *)(ARM9Mem.textureSlotAddr[txt_slot_current]+((format&0x3FFF)<<3)); @@ -801,7 +910,7 @@ static void setTexture(unsigned int format, unsigned int texpal) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (BIT16(texcache[i].frm) ? (BIT18(texcache[i].frm)?GL_MIRRORED_REPEAT:GL_REPEAT) : GL_CLAMP)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (BIT17(texcache[i].frm) ? (BIT18(texcache[i].frm)?GL_MIRRORED_REPEAT:GL_REPEAT) : GL_CLAMP)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (BIT17(texcache[i].frm) ? (BIT19(texcache[i].frm)?GL_MIRRORED_REPEAT:GL_REPEAT) : GL_CLAMP)); } @@ -880,14 +989,16 @@ static void BeginRenderPoly() glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texEnv[envMode]); - //handle toon rendering - #ifdef _WIN32 - if(glUseProgram) { - if(envMode == 2) { - xglUseProgram(toonProgram); - } else xglUseProgram(0); + if(hasShaders) + { + if(envMode != lastEnvMode) + { + lastEnvMode = envMode; + + int _envModes[4] = {0, 1, (2 + gfx3d.shading), 0}; + glUniform1i(texBlendLoc, _envModes[envMode]); + } } - #endif xglDepthMask(enableDepthWrite?GL_TRUE:GL_FALSE); } @@ -945,7 +1056,12 @@ static void Render() Control(); - glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx3d.rgbToonTable); + if(hasShaders) + { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_1D, oglToonTableTextureID); + glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx3d.rgbToonTable); + } xglDepthMask(GL_TRUE); diff --git a/desmume/src/gfx3d.h b/desmume/src/gfx3d.h index 52bcab99b..85f1f1278 100644 --- a/desmume/src/gfx3d.h +++ b/desmume/src/gfx3d.h @@ -91,7 +91,7 @@ struct GFX3D BOOL enableTexturing, enableAlphaTest, enableAlphaBlending, enableAntialiasing, enableEdgeMarking; static const u32 TOON = 0; - static const u32 HIGHLIGHT = 0; + static const u32 HIGHLIGHT = 1; u32 shading; POLYLIST* polylist; diff --git a/desmume/src/shaders.h b/desmume/src/shaders.h new file mode 100644 index 000000000..a08df5b10 --- /dev/null +++ b/desmume/src/shaders.h @@ -0,0 +1,78 @@ +/* Predefined OpenGL shaders */ + +/* Vertex shader */ +const char *vertexShader = {"\ + void main() \n\ + { \n\ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n\ + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; \n\ + gl_FrontColor = gl_Color; \n\ + } \n\ +"}; + +/* Fragment shader */ +const char *fragmentShader = {"\ + uniform sampler1D toonTable; \n\ + uniform sampler2D tex2d; \n\ + uniform int hasTexture; \n\ + uniform int texBlending; \n\ + \n\ + vec4 float_to_6bit(in vec4 color) \n\ + { \n\ + vec4 ret = color * 31;\n\ + \n\ + if(ret.r > 0) ret.r = (ret.r * 2) + 1; \n\ + if(ret.g > 0) ret.g = (ret.g * 2) + 1; \n\ + if(ret.b > 0) ret.b = (ret.b * 2) + 1; \n\ + if(ret.a > 0) ret.a = (ret.a * 2) + 1; \n\ + \n\ + return ret; \n\ + } \n\ + \n\ + void main() \n\ + { \n\ + vec4 vtxColor = float_to_6bit(gl_Color); \n\ + vec4 texColor = float_to_6bit(texture2D(tex2d, gl_TexCoord[0].st)); \n\ + vec3 toonColor = vec3(float_to_6bit(vec4(texture1D(toonTable, gl_Color.r).rgb, 0.0))); \n\ + vec4 fragColor = vec4(0.0, 0.0, 0.0, 0.0); \n\ + \n\ + if(hasTexture == 0) \n\ + { \n\ + texColor = vec4(63.0, 63.0, 63.0, 63.0); \n\ + } \n\ + \n\ + if(texBlending == 0) \n\ + { \n\ + fragColor = ((texColor + 1) * (vtxColor + 1) - 1) / 64; \n\ + } \n\ + else if(texBlending == 1) \n\ + { \n\ + if(texColor.a == 0.0 || hasTexture == 0) \n\ + { \n\ + fragColor.rgb = vtxColor.rgb; \n\ + } \n\ + else if(texColor.a == 63.0) \n\ + { \n\ + fragColor.rgb = texColor.rgb; \n\ + } \n\ + else \n\ + { \n\ + fragColor.rgb = ((texColor.rgb * texColor.a) + (vtxColor.rgb * (63.0 - texColor.a))) / 64; \n\ + } \n\ + \n\ + fragColor.a = vtxColor.a; \n\ + } \n\ + else if(texBlending == 2) \n\ + { \n\ + fragColor.rgb = ((texColor.rgb + 1) * (toonColor + 1) - 1) / 64; \n\ + fragColor.a = ((texColor.a + 1) * (vtxColor.a + 1) - 1) / 64; \n\ + } \n\ + else if(texBlending == 3) \n\ + { \n\ + fragColor.rgb = min((((texColor.rgb + 1) * (toonColor + 1) - 1) / 64) + toonColor, 63.0); \n\ + fragColor.a = ((texColor.a + 1) * (vtxColor.a + 1) - 1) / 64; \n\ + } \n\ + \n\ + gl_FragColor = ((fragColor - 1) / 2) / 31; \n\ + } \n\ +"};