X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=source%2Frice_gles%2Fsrc%2FOGLES2FragmentShaders.cpp;fp=source%2Frice_gles%2Fsrc%2FOGLES2FragmentShaders.cpp;h=4c5f06ec3e18bd851b23049c4bab8dba355a7803;hb=d07c171fa694cae985ad7045f9ce2b2f1a5699b4;hp=0000000000000000000000000000000000000000;hpb=ca22e7b76883b946060a6b40bb8709c1981e1cf6;p=mupen64plus-pandora.git diff --git a/source/rice_gles/src/OGLES2FragmentShaders.cpp b/source/rice_gles/src/OGLES2FragmentShaders.cpp new file mode 100644 index 0000000..4c5f06e --- /dev/null +++ b/source/rice_gles/src/OGLES2FragmentShaders.cpp @@ -0,0 +1,822 @@ +/* +Copyright (C) 2003 Rice1964 + +This program 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 program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "OGLDebug.h" +#include "OGLES2FragmentShaders.h" +#include "OGLRender.h" +#include "OGLGraphicsContext.h" +#include "OGLTexture.h" + +#define ALPHA_TEST " if(gl_FragColor.a < AlphaRef) discard; \n" +//#define ALPHA_TEST + + +GLuint vertexProgram = 9999; +const char *vertexShader = +"#version " GLSL_VERSION "\n" +"attribute mediump vec4 aPosition; \n"\ +"attribute lowp vec4 aColor; \n"\ +"attribute lowp vec2 aTexCoord0; \n"\ +"attribute lowp vec2 aTexCoord1; \n"\ +"attribute lowp vec2 aAtlasTransform; \n"\ +" \n"\ +"uniform lowp vec2 FogMinMax; \n"\ +" \n"\ +"varying lowp float vFactor; \n"\ +"varying lowp vec4 vShadeColor; \n"\ +"varying mediump vec2 vTexCoord0; \n"\ +"varying lowp vec2 vTexCoord1; \n"\ +"varying lowp float vFog; \n"\ +" \n"\ +"void main() \n"\ +"{ \n"\ +"gl_Position = aPosition; //gl_Position.z = max(0.0,gl_Position.z); \n"\ +"vShadeColor = aColor; \n"\ +"vTexCoord0 = aTexCoord0; \n"\ +"vTexCoord1 = aTexCoord1; \n"\ +"vFog = clamp((FogMinMax[1] - (gl_Position.z/aPosition.w))/(FogMinMax[1]-FogMinMax[0]),0.0,1.0); \n"\ +" \n"\ +"} \n"\ +" \n"; + +const char *fragmentHeader = +"#define saturate(x) clamp( x, 0.0, 1.0 ) \n"\ +"precision lowp float; \n"\ +"#ifdef NEED_TEX0 \n"\ +"uniform sampler2D uTex0; \n"\ +"#endif \n"\ +" \n"\ +"#ifdef NEED_TEX1 \n"\ +"uniform sampler2D uTex1; \n"\ +"#endif \n"\ +" \n"\ +"uniform vec4 EnvColor; \n"\ +"uniform vec4 PrimColor; \n"\ +"uniform vec4 EnvFrac; \n"\ +"uniform vec4 PrimFrac; \n"\ +"uniform float AlphaRef; \n"\ +"uniform vec4 FogColor; \n"\ +" \n"\ +"varying lowp float vFactor; \n"\ +"varying lowp vec4 vShadeColor; \n"\ +"varying mediump vec2 vTexCoord0; \n"\ +"varying lowp vec2 vTexCoord1; \n"\ +"varying lowp float vFog; \n"\ +" \n"\ +"void main() \n"\ +"{ \n"\ +"vec4 comb,comb2; \n"\ +" \n"\ +"#ifdef NEED_TEX0 \n"\ +"vec4 t0 = texture2D(uTex0,vTexCoord0); \n"\ +"#endif \n"\ +" \n"\ +"#ifdef NEED_TEX1 \n"\ +"vec4 t1 = texture2D(uTex1,vTexCoord1); \n"\ +"#endif \n"; + +const char *fragmentFooter = +" \n"\ +"#ifdef FOG \n"\ +"gl_FragColor.rgb = mix(FogColor.rgb,comb.rgb,vFog * step(0.5,1.0-FogColor.a)); \n"\ +"gl_FragColor.a = comb.a; \n"\ +"#else \n"\ +"gl_FragColor = comb; \n"\ +"#endif \n"\ +" \n"\ +"#ifdef ALPHA_TEST \n"\ +ALPHA_TEST +"#endif \n"\ +" \n"\ +" \n"\ +" \n"\ +" \n"\ +"} \n"; + +//Fragment shader for InitCycleCopy +const char *fragmentCopy = +"#version " GLSL_VERSION "\n"\ +"precision lowp float; \n"\ +"uniform sampler2D uTex0; \n"\ +"uniform float AlphaRef; \n"\ +"varying lowp vec2 vTexCoord0; \n"\ +"void main() \n"\ +"{ \n"\ +" gl_FragColor = texture2D(uTex0,vTexCoord0).bgra; \n"\ +ALPHA_TEST +"}"; + +GLuint copyProgram,copyAlphaLocation; + +//Fragment shader for InitCycleFill +const char *fragmentFill = +"#version " GLSL_VERSION "\n"\ +"precision lowp float; \n" +"uniform vec4 uColor; \n" +"void main() \n" +"{ \n" +" gl_FragColor = uColor; \n" +"}"; + +GLuint fillProgram,fillColorLocation; + +COGLFragmentShaderCombiner::COGLFragmentShaderCombiner(CRender *pRender) +: COGLColorCombiner(pRender) +{ + m_bShaderIsSupported = true; +} +COGLFragmentShaderCombiner::~COGLFragmentShaderCombiner() +{ +} + +bool COGLFragmentShaderCombiner::Initialize(void) +{ + if( !COGLColorCombiner::Initialize() ) + return false; + + COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); +// if( pcontext->IsExtensionSupported("GL_fragment_shader") ) +// { + m_bShaderIsSupported = true; +// } + + return true; +} + +void COGLFragmentShaderCombiner::InitCombinerCycle12(void) +{ +} +void COGLFragmentShaderCombiner::DisableCombiner(void) +{ + COGLColorCombiner::DisableCombiner(); +} + +void COGLFragmentShaderCombiner::InitCombinerCycleCopy(void) +{ + COGLColorCombiner::InitCombinerCycleCopy(); +} + +void COGLFragmentShaderCombiner::InitCombinerCycleFill(void) +{ + COGLColorCombiner::InitCombinerCycleFill(); +} +void COGLFragmentShaderCombiner::InitCombinerBlenderForSimpleTextureDraw(uint32 tile) +{ + COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(tile); +} + +#ifdef DEBUGGER +void COGLFragmentShaderCombiner::DisplaySimpleMuxString(void) +{ + COGLColorCombiner::DisplaySimpleMuxString(); +} +#endif + + + +COGL_FragmentProgramCombiner::COGL_FragmentProgramCombiner(CRender *pRender) +: COGLColorCombiner4(pRender) +{ + delete m_pDecodedMux; + m_pDecodedMux = new DecodedMuxForPixelShader; + m_bFragmentProgramIsSupported = true; + m_AlphaRef = 0.0f; + + //Create shaders for fill and copy + GLint success; + GLuint vs,fs; + copyProgram = glCreateProgram(); + vs = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vs,1,&vertexShader,NULL); + glCompileShader(vs); + + glGetShaderiv(vs,GL_COMPILE_STATUS,&success); + if(!success) + { + char log[1024]; + glGetShaderInfoLog(vs,1024,NULL,log); + printf("%s\n",log); + } + + fs = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fs,1,&fragmentCopy,NULL); + glCompileShader(fs); + + glGetShaderiv(fs,GL_COMPILE_STATUS,&success); + if(!success) + { + char log[1024]; + glGetShaderInfoLog(fs,1024,NULL,log); + printf("%s\n",log); + } + + glAttachShader(copyProgram,vs); + glAttachShader(copyProgram,fs); + + glBindAttribLocation(copyProgram,VS_TEXCOORD0,"aTexCoord0"); + OPENGL_CHECK_ERRORS; + glBindAttribLocation(copyProgram,VS_POSITION,"aPosition"); + OPENGL_CHECK_ERRORS; + + glLinkProgram(copyProgram); + copyAlphaLocation = glGetUniformLocation(copyProgram,"AlphaRef"); + glGetProgramiv(copyProgram,GL_LINK_STATUS,&success); + if(!success) + { + char log[1024]; + glGetProgramInfoLog(copyProgram,1024,NULL,log); + printf("%s\n",log); + } + + glDeleteShader(fs); + + //Fill shader + fs = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fs,1,&fragmentFill,NULL); + glCompileShader(fs); + + glGetShaderiv(fs,GL_COMPILE_STATUS,&success); + if(!success) + { + char log[1024]; + glGetShaderInfoLog(fs,1024,NULL,log); + printf("%s\n",log); + } + + fillProgram = glCreateProgram(); + glAttachShader(fillProgram,vs); + glAttachShader(fillProgram,fs); + + glBindAttribLocation(fillProgram,VS_POSITION,"aPosition"); + OPENGL_CHECK_ERRORS; + + glLinkProgram(fillProgram); + + + fillColorLocation = glGetUniformLocation(fillProgram,"uColor"); + + glDeleteShader(fs); + glDeleteShader(vs); +} +COGL_FragmentProgramCombiner::~COGL_FragmentProgramCombiner() +{ + int size = m_vCompiledShaders.size(); + for (int i=0; iIsExtensionSupported("GL_fragment_program") ) +// { + m_bFragmentProgramIsSupported = true; +// } + + return true; +} + + + +void COGL_FragmentProgramCombiner::DisableCombiner(void) +{ + //glDisable(GL_FRAGMENT_PROGRAM); + //OPENGL_CHECK_ERRORS; + COGLColorCombiner4::DisableCombiner(); +} + +void COGL_FragmentProgramCombiner::InitCombinerCycleCopy(void) +{ + m_pOGLRender->DisableMultiTexture(); + m_pOGLRender->EnableTexUnit(0,TRUE); + glUseProgram(copyProgram); + glUniform1f(copyAlphaLocation,m_AlphaRef); + OPENGL_CHECK_ERRORS; + glEnableVertexAttribArray(VS_POSITION); + OPENGL_CHECK_ERRORS; + glEnableVertexAttribArray(VS_TEXCOORD0); + OPENGL_CHECK_ERRORS; + glDisableVertexAttribArray(VS_COLOR); + OPENGL_CHECK_ERRORS; + glDisableVertexAttribArray(VS_TEXCOORD1); + OPENGL_CHECK_ERRORS; + COGLTexture* pTexture = g_textures[gRSP.curTile].m_pCOGLTexture; + if( pTexture ) + { + m_pOGLRender->BindTexture(pTexture->m_dwTextureName, 0); + m_pOGLRender->SetTexelRepeatFlags(gRSP.curTile); + } +} + +void COGL_FragmentProgramCombiner::InitCombinerCycleFill(void) +{ + glUseProgram(fillProgram); + glUniform4f(fillColorLocation,((gRDP.fillColor>>16)&0xFF)/255.0f,((gRDP.fillColor>>8)&0xFF)/255.0f,((gRDP.fillColor)&0xFF)/255.0f,((gRDP.fillColor>>24)&0xFF)/255.0f); + OPENGL_CHECK_ERRORS; +} + +#ifdef BGR_SHADER +const char *muxToFP_Maps[][2] = { +//color -- alpha +{"vec3(0.0)", "0.0"}, //MUX_0 = 0, +{"vec3(1.0)", "1.0"}, //MUX_1, +{"comb.rgb", "comb.a"}, //MUX_COMBINED, +{"t0.rgb", "t0.a"}, //MUX_TEXEL0, +{"t1.rgb", "t1.a"}, //MUX_TEXEL1, +{"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM, +{"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE, +{"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV, +{"comb.rgb", "comb.a"}, //MUX_COMBALPHA, +{"t0.rgb", "t0.a"}, //MUX_T0_ALPHA, +{"t1.rgb", "t1.a"}, //MUX_T1_ALPHA, +{"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM_ALPHA, +{"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE_ALPHA, +{"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV_ALPHA, +{"EnvFrac.a", "EnvFrac.a"}, //MUX_LODFRAC, +{"PrimFrac.a", "PrimFrac.a"}, //MUX_PRIMLODFRAC, +{"vec3(1.0)", "1.0"}, //MUX_K5, +{"vec3(1.0)", "1.0"}, //MUX_UNK, // Should not be used +}; +#else +const char *muxToFP_Maps[][2] = { +//color -- alpha +{"vec3(0.0)", "0.0"}, //MUX_0 = 0, +{"vec3(1.0)", "1.0"}, //MUX_1, +{"comb.rgb", "comb.a"}, //MUX_COMBINED, +{"t0.bgr", "t0.a"}, //MUX_TEXEL0, +{"t1.bgr", "t1.a"}, //MUX_TEXEL1, +{"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM, +{"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE, +{"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV, +{"comb.rgb", "comb.a"}, //MUX_COMBALPHA, +{"t0.bgr", "t0.a"}, //MUX_T0_ALPHA, +{"t1.bgr", "t1.a"}, //MUX_T1_ALPHA, +{"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM_ALPHA, +{"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE_ALPHA, +{"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV_ALPHA, +{"EnvFrac.a", "EnvFrac.a"}, //MUX_LODFRAC, +{"PrimFrac.a", "PrimFrac.a"}, //MUX_PRIMLODFRAC, +{"vec3(1.0)", "1.0"}, //MUX_K5, +{"vec3(1.0)", "1.0"}, //MUX_UNK, // Should not be used +}; +#endif + + +char oglNewFP[4092]; + +char* MuxToOC(uint8 val) +{ +// For color channel +if( val&MUX_ALPHAREPLICATE ) + return (char*)muxToFP_Maps[val&0x1F][1]; +else + return (char*)muxToFP_Maps[val&0x1F][0]; +} + +char* MuxToOA(uint8 val) +{ +// For alpha channel +return (char*)muxToFP_Maps[val&0x1F][1]; +} + +static void CheckFpVars(uint8 MuxVar, bool &bNeedT0, bool &bNeedT1) +{ + MuxVar &= 0x1f; + if (MuxVar == MUX_TEXEL0 || MuxVar == MUX_T0_ALPHA) + bNeedT0 = true; + if (MuxVar == MUX_TEXEL1 || MuxVar == MUX_T1_ALPHA) + bNeedT1 = true; +} + +void COGL_FragmentProgramCombiner::GenerateProgramStr() +{ + DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux; + + mux.splitType[0] = mux.splitType[1] = mux.splitType[2] = mux.splitType[3] = CM_FMT_TYPE_NOT_CHECKED; + m_pDecodedMux->Reformat(false); + + char tempstr[500], newFPBody[4092]; + bool bNeedT0 = false, bNeedT1 = false, bNeedComb2 = false; + newFPBody[0] = 0; + + for( int cycle=0; cycle<2; cycle++ ) + { + for( int channel=0; channel<2; channel++) + { + char* (*func)(uint8) = channel==0?MuxToOC:MuxToOA; + char *dst = channel==0?(char*)"rgb":(char*)"a"; + N64CombinerType &m = mux.m_n64Combiners[cycle*2+channel]; + switch( mux.splitType[cycle*2+channel] ) + { + case CM_FMT_TYPE_NOT_USED: + tempstr[0] = 0; + break; + case CM_FMT_TYPE_D: + sprintf(tempstr, "comb.%s = %s;\n", dst, func(m.d)); + CheckFpVars(m.d, bNeedT0, bNeedT1); + break; + case CM_FMT_TYPE_A_MOD_C: + sprintf(tempstr, "comb.%s = %s * %s;\n", dst, func(m.a), func(m.c)); + CheckFpVars(m.a, bNeedT0, bNeedT1); + CheckFpVars(m.c, bNeedT0, bNeedT1); + break; + case CM_FMT_TYPE_A_ADD_D: + sprintf(tempstr, "comb.%s = saturate(%s + %s);\n", dst, func(m.a), func(m.d)); + CheckFpVars(m.a, bNeedT0, bNeedT1); + CheckFpVars(m.d, bNeedT0, bNeedT1); + break; + case CM_FMT_TYPE_A_SUB_B: + sprintf(tempstr, "comb.%s = %s - %s;\n", dst, func(m.a), func(m.b)); + CheckFpVars(m.a, bNeedT0, bNeedT1); + CheckFpVars(m.b, bNeedT0, bNeedT1); + break; + case CM_FMT_TYPE_A_MOD_C_ADD_D: + sprintf(tempstr, "comb.%s = saturate(%s * %s + %s);\n", dst, func(m.a), func(m.c),func(m.d)); + CheckFpVars(m.a, bNeedT0, bNeedT1); + CheckFpVars(m.c, bNeedT0, bNeedT1); + CheckFpVars(m.d, bNeedT0, bNeedT1); + break; + case CM_FMT_TYPE_A_LERP_B_C: + //ARB ASM LERP and mix have different parameter ordering. + //sprintf(tempstr, "comb.%s = saturate(mix(%s, %s, %s));\n", dst,func(m.a),func(m.b), func(m.c)); + sprintf(tempstr, "comb.%s = (%s - %s) * %s + %s;\n", dst,func(m.a),func(m.b), func(m.c),func(m.b)); + CheckFpVars(m.a, bNeedT0, bNeedT1); + CheckFpVars(m.b, bNeedT0, bNeedT1); + CheckFpVars(m.c, bNeedT0, bNeedT1); + //sprintf(tempstr, "SUB comb.%s, %s, %s;\nMAD_SAT comb.%s, comb, %s, %s;\n", dst, func(m.a), func(m.b), dst, func(m.c), func(m.b)); + break; + default: + sprintf(tempstr, "comb2.%s = %s - %s;\ncomb.%s = saturate(comb2.%s * %s + %s);\n", dst, func(m.a), func(m.b), dst,dst, func(m.c),func(m.d)); + CheckFpVars(m.a, bNeedT0, bNeedT1); + CheckFpVars(m.b, bNeedT0, bNeedT1); + CheckFpVars(m.c, bNeedT0, bNeedT1); + CheckFpVars(m.d, bNeedT0, bNeedT1); + bNeedComb2 = true; + break; + } + strcat(newFPBody, tempstr); + } + } + + oglNewFP[0] = 0; + if (bNeedT0) + strcat(oglNewFP, "#define NEED_TEX0\n"); + if (bNeedT1) + strcat(oglNewFP, "#define NEED_TEX1\n"); + if(gRDP.bFogEnableInBlender && gRSP.bFogEnabled && options.fogMethod > 0) + strcat(oglNewFP,"#define FOG"); + strcat(oglNewFP, fragmentHeader); + strcat(oglNewFP, newFPBody); + strcat(oglNewFP, fragmentFooter); + +} + +int COGL_FragmentProgramCombiner::ParseDecodedMux() +{ + if( !m_bFragmentProgramIsSupported ) + return COGLColorCombiner4::ParseDecodedMux(); + + OGLShaderCombinerSaveType res; + GLint success; + + if(vertexProgram == 9999) + { + vertexProgram = res.vertexShaderID = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(res.vertexShaderID, 1, &vertexShader,NULL); + OPENGL_CHECK_ERRORS; + glCompileShader(res.vertexShaderID); + OPENGL_CHECK_ERRORS; + } + else + { + res.vertexShaderID = vertexProgram; + } + + + //Create 2 shaders, with and without alphatest + GenerateProgramStr(); + + for(int alphaTest = 0;alphaTest < 2;alphaTest++) + { + res.fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + + char* tmpShader = (char*)malloc(sizeof(char) * 4096); + strcpy(tmpShader,"#version " GLSL_VERSION "\n"); + + if(alphaTest == 1) + { + strcat(tmpShader,"#define ALPHA_TEST\n"); + } + + res.alphaTest = alphaTest == 1; + strcat(tmpShader,oglNewFP); + + glShaderSource(res.fragmentShaderID, 1,(const char**) &tmpShader,NULL); + free(tmpShader); + + + OPENGL_CHECK_ERRORS; + glCompileShader(res.fragmentShaderID); + + glGetShaderiv(res.fragmentShaderID, GL_COMPILE_STATUS, &success); + if (!success) + { + char Log[1024]; + GLint nLength; + glGetShaderInfoLog(res.fragmentShaderID, 1024, &nLength, Log); + printf("Error compiling shader!\n %s",oglNewFP); + printf("%s", Log); + } + + res.programID = glCreateProgram(); + glAttachShader(res.programID,res.vertexShaderID); + glAttachShader(res.programID,res.fragmentShaderID); + + //Bind Attributes + glBindAttribLocation(res.programID,VS_COLOR,"aColor"); + OPENGL_CHECK_ERRORS; + glBindAttribLocation(res.programID,VS_TEXCOORD0,"aTexCoord0"); + OPENGL_CHECK_ERRORS; + glBindAttribLocation(res.programID,VS_TEXCOORD1,"aTexCoord1"); + OPENGL_CHECK_ERRORS; + glBindAttribLocation(res.programID,VS_POSITION,"aPosition"); + OPENGL_CHECK_ERRORS; + + glLinkProgram(res.programID); + OPENGL_CHECK_ERRORS; + + glGetProgramiv(res.programID, GL_LINK_STATUS, &success); + if (!success) + { + char Log[1024]; + GLint nLength; + glGetShaderInfoLog(res.fragmentShaderID, 1024, &nLength, Log); + printf("Error linking program!\n"); + printf("%s\n",Log); + } + + glUseProgram(res.programID); + OPENGL_CHECK_ERRORS; + + //Bind texture samplers + GLint tex0 = glGetUniformLocation(res.programID,"uTex0"); + GLint tex1 = glGetUniformLocation(res.programID,"uTex1"); + + if(tex0 != -1) + glUniform1i(tex0,0); + if(tex1 != -1) + glUniform1i(tex1,1); + + //Bind Uniforms + res.PrimColorLocation = glGetUniformLocation(res.programID,"PrimColor"); + OPENGL_CHECK_ERRORS; + res.EnvColorLocation = glGetUniformLocation(res.programID,"EnvColor"); + OPENGL_CHECK_ERRORS; + res.PrimFracLocation = glGetUniformLocation(res.programID,"PrimFrac"); + OPENGL_CHECK_ERRORS; + res.EnvFracLocation = glGetUniformLocation(res.programID,"EnvFrac"); + OPENGL_CHECK_ERRORS; + res.AlphaRefLocation = glGetUniformLocation(res.programID,"AlphaRef"); + OPENGL_CHECK_ERRORS; + res.FogColorLocation = glGetUniformLocation(res.programID,"FogColor"); + OPENGL_CHECK_ERRORS; + res.FogMinMaxLocation = glGetUniformLocation(res.programID,"FogMinMax"); + OPENGL_CHECK_ERRORS; + + res.dwMux0 = m_pDecodedMux->m_dwMux0; + res.dwMux1 = m_pDecodedMux->m_dwMux1; + res.fogIsUsed = gRDP.bFogEnableInBlender && gRSP.bFogEnabled; + + m_vCompiledShaders.push_back(res); + } + m_lastIndex = m_vCompiledShaders.size()-2; + + return m_lastIndex; +} + +void COGL_FragmentProgramCombiner::GenerateCombinerSetting(int index) +{ + GLuint ID = m_vCompiledShaders[index].programID; + + glUseProgram(ID); + glEnableVertexAttribArray(VS_POSITION); + OPENGL_CHECK_ERRORS; + glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); + OPENGL_CHECK_ERRORS; + + glEnableVertexAttribArray(VS_TEXCOORD0); + OPENGL_CHECK_ERRORS; + glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u)); + OPENGL_CHECK_ERRORS; + + glEnableVertexAttribArray(VS_TEXCOORD1); + OPENGL_CHECK_ERRORS; + glVertexAttribPointer(VS_TEXCOORD1,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[1].u)); + OPENGL_CHECK_ERRORS; + + glEnableVertexAttribArray(VS_COLOR); + OPENGL_CHECK_ERRORS; + glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); + OPENGL_CHECK_ERRORS; +} + +void COGL_FragmentProgramCombiner::GenerateCombinerSettingConstants(int index) +{ + OGLShaderCombinerSaveType prog = m_vCompiledShaders[index]; + + glUseProgram(prog.programID); + float *pf; + if(prog.EnvColorLocation != -1) + { + pf = GetEnvColorfv(); + glUniform4fv(prog.EnvColorLocation,1, pf); + OPENGL_CHECK_ERRORS; + } + + if(prog.PrimColorLocation != -1) + { + pf = GetPrimitiveColorfv(); + glUniform4fv(prog.PrimColorLocation,1, pf); + OPENGL_CHECK_ERRORS; + } + + if(prog.EnvFracLocation != -1) + { + float frac = gRDP.LODFrac / 255.0f; + float tempf[4] = {frac,frac,frac,frac}; + glUniform4fv(prog.EnvFracLocation,1, tempf); + OPENGL_CHECK_ERRORS; + } + + if(prog.PrimFracLocation != -1) + { + float frac2 = gRDP.primLODFrac / 255.0f; + float tempf2[4] = {frac2,frac2,frac2,frac2}; + glUniform4fv(prog.PrimFracLocation,1, tempf2); + OPENGL_CHECK_ERRORS; + } + + //if(prog.FogColorLocation != -1 && prog.FogMinMaxLocation != -1) + //{ + // //Pass fog colour and distance, use 0 alpha if fog disabled + // glUniform4f(prog.FogColorLocation, gRDP.fvFogColor[0],gRDP.fvFogColor[1],gRDP.fvFogColor[2], + // gRSP.bFogEnabled ? gRDP.fvFogColor[0] : 0.0f); + // glUniform2f(prog.FogMinMaxLocation,gRSPfFogMin,gRSPfFogMax); + //} + + if(prog.AlphaRefLocation != -1) + glUniform1f(prog.AlphaRefLocation,m_AlphaRef); + OPENGL_CHECK_ERRORS; +} + +void COGL_FragmentProgramCombiner::UpdateFog(bool bEnable) +{ + if(m_lastIndex < 0 || m_lastIndex >= m_vCompiledShaders.size()) + return; + OGLShaderCombinerSaveType prog = m_vCompiledShaders[m_lastIndex]; + + //if(bEnable) + // DebugMessage(M64MSG_INFO,"Fog Color %x Min %f Max %f",gRDP.fogColor,gRSPfFogMin,gRSPfFogMax); + + if(prog.FogColorLocation != -1 && prog.FogMinMaxLocation != -1) + { + //Pass fog colour and distance, use 0 alpha if fog disabled + glUniform4f(prog.FogColorLocation, gRDP.fvFogColor[0],gRDP.fvFogColor[1],gRDP.fvFogColor[2], + bEnable ? gRDP.fvFogColor[0] : 0.0f); + //glUniform4f(prog.FogColorLocation, 1.0f,0.3f,0.3f,1.0f); + //OPENGL_CHECK_ERRORS; + glUniform2f(prog.FogMinMaxLocation,gRSPfFogMin,gRSPfFogMax); + OPENGL_CHECK_ERRORS; + } +} + +int COGL_FragmentProgramCombiner::FindCompiledMux() +{ +#ifdef DEBUGGER + if( debuggerDropCombiners ) + { + m_vCompiledShaders.clear(); + //m_dwLastMux0 = m_dwLastMux1 = 0; + debuggerDropCombiners = false; + } +#endif + for( uint32 i=0; im_dwMux0 + && m_vCompiledShaders[i].dwMux1 == m_pDecodedMux->m_dwMux1 + && m_vCompiledShaders[i].fogIsUsed == (gRDP.bFogEnableInBlender && gRSP.bFogEnabled) + && m_vCompiledShaders[i].alphaTest == m_AlphaRef > 0.0f) + { + return (int)i; + } + } + + return -1; +} + +////////////////////////////////////////////////////////////////////////// +void COGL_FragmentProgramCombiner::InitCombinerCycle12(void) +{ + if( !m_bFragmentProgramIsSupported ) + { + COGLColorCombiner4::InitCombinerCycle12(); + return; + } + +#ifdef DEBUGGER + if( debuggerDropCombiners ) + { + UpdateCombiner(m_pDecodedMux->m_dwMux0,m_pDecodedMux->m_dwMux1); + m_vCompiledShaders.clear(); + m_dwLastMux0 = m_dwLastMux1 = 0; + debuggerDropCombiners = false; + } +#endif + + m_pOGLRender->EnableMultiTexture(); + + bool combinerIsChanged = false; + + if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 || m_lastIndex < 0 ) + { + combinerIsChanged = true; + m_lastIndex = FindCompiledMux(); + if( m_lastIndex < 0 ) // Can not found + { + m_lastIndex = ParseDecodedMux(); + } + + m_dwLastMux0 = m_pDecodedMux->m_dwMux0; + m_dwLastMux1 = m_pDecodedMux->m_dwMux1; + } + + + GenerateCombinerSettingConstants(m_lastIndex); + if( m_bCycleChanged || combinerIsChanged || gRDP.texturesAreReloaded || gRDP.colorsAreReloaded ) + { + if( m_bCycleChanged || combinerIsChanged ) + { + GenerateCombinerSettingConstants(m_lastIndex); + GenerateCombinerSetting(m_lastIndex); + } + else if( gRDP.colorsAreReloaded ) + { + GenerateCombinerSettingConstants(m_lastIndex); + } + + m_pOGLRender->SetAllTexelRepeatFlag(); + + gRDP.colorsAreReloaded = false; + gRDP.texturesAreReloaded = false; + } + else + { + m_pOGLRender->SetAllTexelRepeatFlag(); + } +} + +#ifdef DEBUGGER +void COGL_FragmentProgramCombiner::DisplaySimpleMuxString(void) +{ + COGLColorCombiner::DisplaySimpleMuxString(); + DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux; + mux.Reformat(false); + GenerateProgramStr(); + //sprintf(oglNewFP, oglFP, + // MuxToOC(mux.aRGB0), MuxToOC(mux.bRGB0), MuxToOC(mux.cRGB0), MuxToOC(mux.dRGB0), + // MuxToOA(mux.aA0), MuxToOA(mux.bA0), MuxToOA(mux.cA0), MuxToOA(mux.dA0), + // MuxToOC(mux.aRGB1), MuxToOC(mux.bRGB1), MuxToOC(mux.cRGB1), MuxToOC(mux.dRGB1), + // MuxToOA(mux.aA1), MuxToOA(mux.bA1), MuxToOA(mux.cA1), MuxToOA(mux.dA1) + // ); + + TRACE0("OGL Fragment Program:"); + TRACE0(oglNewFP); +} +#endif +