| 1 | /* |
| 2 | Copyright (C) 2003 Rice1964 |
| 3 | |
| 4 | This program is free software; you can redistribute it and/or |
| 5 | modify it under the terms of the GNU General Public License |
| 6 | as published by the Free Software Foundation; either version 2 |
| 7 | of the License, or (at your option) any later version. |
| 8 | |
| 9 | This program is distributed in the hope that it will be useful, |
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License |
| 15 | along with this program; if not, write to the Free Software |
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 17 | */ |
| 18 | |
| 19 | #include "OGLDebug.h" |
| 20 | #include "OGLES2FragmentShaders.h" |
| 21 | #include "OGLRender.h" |
| 22 | #include "OGLGraphicsContext.h" |
| 23 | #include "OGLTexture.h" |
| 24 | |
| 25 | #define ALPHA_TEST " if(gl_FragColor.a < AlphaRef) discard; \n" |
| 26 | //#define ALPHA_TEST |
| 27 | #define ENABLE true |
| 28 | #define DISABLE false |
| 29 | |
| 30 | GLuint vertexProgram = 9999; |
| 31 | const char *vertexShader = |
| 32 | "#version " GLSL_VERSION "\n" |
| 33 | "attribute mediump vec4 aPosition; \n"\ |
| 34 | "attribute lowp vec4 aColor; \n"\ |
| 35 | "attribute lowp vec2 aTexCoord0; \n"\ |
| 36 | "attribute lowp vec2 aTexCoord1; \n"\ |
| 37 | "attribute lowp vec2 aAtlasTransform; \n"\ |
| 38 | "attribute mediump float aFogCoord; \n"\ |
| 39 | " \n"\ |
| 40 | "uniform vec2 FogMinMax; \n"\ |
| 41 | " \n"\ |
| 42 | "varying lowp float vFactor; \n"\ |
| 43 | "varying lowp vec4 vShadeColor; \n"\ |
| 44 | "varying mediump vec2 vTexCoord0; \n"\ |
| 45 | "varying lowp vec2 vTexCoord1; \n"\ |
| 46 | "varying lowp float vFog; \n"\ |
| 47 | " \n"\ |
| 48 | "void main() \n"\ |
| 49 | "{ \n"\ |
| 50 | "gl_Position = aPosition; //gl_Position.z = max(0.0,gl_Position.z); \n"\ |
| 51 | "vShadeColor = aColor; \n"\ |
| 52 | "vTexCoord0 = aTexCoord0; \n"\ |
| 53 | "vTexCoord1 = aTexCoord1; \n"\ |
| 54 | "vFog = (FogMinMax[1] - aFogCoord) / (FogMinMax[1] - FogMinMax[0]); \n"\ |
| 55 | " \n"\ |
| 56 | "vFog = clamp(vFog, 0.0, 1.0); \n"\ |
| 57 | "} \n"\ |
| 58 | " \n"; |
| 59 | |
| 60 | const char *fragmentHeader = |
| 61 | "#define saturate(x) clamp( x, 0.0, 1.0 ) \n"\ |
| 62 | "precision lowp float; \n"\ |
| 63 | "#ifdef NEED_TEX0 \n"\ |
| 64 | "uniform sampler2D uTex0; \n"\ |
| 65 | "#endif \n"\ |
| 66 | " \n"\ |
| 67 | "#ifdef NEED_TEX1 \n"\ |
| 68 | "uniform sampler2D uTex1; \n"\ |
| 69 | "#endif \n"\ |
| 70 | " \n"\ |
| 71 | "uniform vec4 EnvColor; \n"\ |
| 72 | "uniform vec4 PrimColor; \n"\ |
| 73 | "uniform vec4 EnvFrac; \n"\ |
| 74 | "uniform vec4 PrimFrac; \n"\ |
| 75 | "uniform float AlphaRef; \n"\ |
| 76 | "uniform vec4 FogColor; \n"\ |
| 77 | " \n"\ |
| 78 | "varying lowp vec4 vShadeColor; \n"\ |
| 79 | "varying mediump vec2 vTexCoord0; \n"\ |
| 80 | "varying lowp vec2 vTexCoord1; \n"\ |
| 81 | "varying lowp float vFog; \n"\ |
| 82 | " \n"\ |
| 83 | "void main() \n"\ |
| 84 | "{ \n"\ |
| 85 | "vec4 comb,comb2; \n"\ |
| 86 | " \n"\ |
| 87 | "#ifdef NEED_TEX0 \n"\ |
| 88 | "vec4 t0 = texture2D(uTex0,vTexCoord0); \n"\ |
| 89 | "#endif \n"\ |
| 90 | " \n"\ |
| 91 | "#ifdef NEED_TEX1 \n"\ |
| 92 | "vec4 t1 = texture2D(uTex1,vTexCoord1); \n"\ |
| 93 | "#endif \n"; |
| 94 | |
| 95 | const char *fragmentFooter = |
| 96 | " \n"\ |
| 97 | "#ifdef FOG \n"\ |
| 98 | "gl_FragColor.rgb = mix(FogColor.rgb,comb.rgb,vFog); \n"\ |
| 99 | "gl_FragColor.a = comb.a; \n"\ |
| 100 | "#else \n"\ |
| 101 | "gl_FragColor = comb; \n"\ |
| 102 | "#endif \n"\ |
| 103 | " \n"\ |
| 104 | "#ifdef ALPHA_TEST \n"\ |
| 105 | ALPHA_TEST |
| 106 | "#endif \n"\ |
| 107 | "} \n"; |
| 108 | |
| 109 | //Fragment shader for InitCycleCopy |
| 110 | const char *fragmentCopy = |
| 111 | "#version " GLSL_VERSION "\n"\ |
| 112 | "precision lowp float; \n"\ |
| 113 | "uniform sampler2D uTex0; \n"\ |
| 114 | "uniform float AlphaRef; \n"\ |
| 115 | "varying lowp vec2 vTexCoord0; \n"\ |
| 116 | "void main() \n"\ |
| 117 | "{ \n"\ |
| 118 | " gl_FragColor = texture2D(uTex0,vTexCoord0).bgra; \n"\ |
| 119 | ALPHA_TEST |
| 120 | "}"; |
| 121 | |
| 122 | GLuint copyProgram,copyAlphaLocation; |
| 123 | |
| 124 | //Fragment shader for InitCycleFill |
| 125 | const char *fragmentFill = |
| 126 | "#version " GLSL_VERSION "\n"\ |
| 127 | "precision lowp float; \n" |
| 128 | "uniform vec4 uColor; \n" |
| 129 | "void main() \n" |
| 130 | "{ \n" |
| 131 | " gl_FragColor = uColor; \n" |
| 132 | "}"; |
| 133 | |
| 134 | GLuint fillProgram,fillColorLocation; |
| 135 | |
| 136 | COGLFragmentShaderCombiner::COGLFragmentShaderCombiner(CRender *pRender) |
| 137 | : COGLColorCombiner(pRender) |
| 138 | { |
| 139 | m_bShaderIsSupported = true; |
| 140 | } |
| 141 | COGLFragmentShaderCombiner::~COGLFragmentShaderCombiner() |
| 142 | { |
| 143 | } |
| 144 | |
| 145 | bool COGLFragmentShaderCombiner::Initialize(void) |
| 146 | { |
| 147 | if( !COGLColorCombiner::Initialize() ) |
| 148 | return false; |
| 149 | |
| 150 | // COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); |
| 151 | // if( pcontext->IsExtensionSupported("GL_fragment_shader") ) |
| 152 | // { |
| 153 | m_bShaderIsSupported = true; |
| 154 | // } |
| 155 | |
| 156 | return true; |
| 157 | } |
| 158 | |
| 159 | void COGLFragmentShaderCombiner::InitCombinerCycle12(void) |
| 160 | { |
| 161 | } |
| 162 | void COGLFragmentShaderCombiner::DisableCombiner(void) |
| 163 | { |
| 164 | COGLColorCombiner::DisableCombiner(); |
| 165 | } |
| 166 | |
| 167 | void COGLFragmentShaderCombiner::InitCombinerCycleCopy(void) |
| 168 | { |
| 169 | COGLColorCombiner::InitCombinerCycleCopy(); |
| 170 | } |
| 171 | |
| 172 | void COGLFragmentShaderCombiner::InitCombinerCycleFill(void) |
| 173 | { |
| 174 | COGLColorCombiner::InitCombinerCycleFill(); |
| 175 | } |
| 176 | void COGLFragmentShaderCombiner::InitCombinerBlenderForSimpleTextureDraw(uint32 tile) |
| 177 | { |
| 178 | COGLColorCombiner::InitCombinerBlenderForSimpleTextureDraw(tile); |
| 179 | } |
| 180 | |
| 181 | #ifdef DEBUGGER |
| 182 | void COGLFragmentShaderCombiner::DisplaySimpleMuxString(void) |
| 183 | { |
| 184 | COGLColorCombiner::DisplaySimpleMuxString(); |
| 185 | } |
| 186 | #endif |
| 187 | |
| 188 | |
| 189 | |
| 190 | COGL_FragmentProgramCombiner::COGL_FragmentProgramCombiner(CRender *pRender) |
| 191 | : COGLColorCombiner4(pRender) |
| 192 | { |
| 193 | delete m_pDecodedMux; |
| 194 | m_pDecodedMux = new DecodedMuxForPixelShader; |
| 195 | m_bFragmentProgramIsSupported = true; |
| 196 | m_AlphaRef = 0.0f; |
| 197 | bAlphaTestState = false; |
| 198 | bAlphaTestPreviousState = false; |
| 199 | bFogState = false; |
| 200 | bFogPreviousState = false; |
| 201 | |
| 202 | //Create shaders for fill and copy |
| 203 | GLint success; |
| 204 | GLuint vs,fs; |
| 205 | copyProgram = glCreateProgram(); |
| 206 | vs = glCreateShader(GL_VERTEX_SHADER); |
| 207 | glShaderSource(vs,1,&vertexShader,NULL); |
| 208 | glCompileShader(vs); |
| 209 | |
| 210 | glGetShaderiv(vs,GL_COMPILE_STATUS,&success); |
| 211 | if(!success) |
| 212 | { |
| 213 | char log[1024]; |
| 214 | glGetShaderInfoLog(vs,1024,NULL,log); |
| 215 | printf("%s\n",log); |
| 216 | } |
| 217 | |
| 218 | fs = glCreateShader(GL_FRAGMENT_SHADER); |
| 219 | glShaderSource(fs,1,&fragmentCopy,NULL); |
| 220 | glCompileShader(fs); |
| 221 | |
| 222 | glGetShaderiv(fs,GL_COMPILE_STATUS,&success); |
| 223 | if(!success) |
| 224 | { |
| 225 | char log[1024]; |
| 226 | glGetShaderInfoLog(fs,1024,NULL,log); |
| 227 | printf("%s\n",log); |
| 228 | } |
| 229 | |
| 230 | glAttachShader(copyProgram,vs); |
| 231 | glAttachShader(copyProgram,fs); |
| 232 | |
| 233 | glBindAttribLocation(copyProgram,VS_TEXCOORD0,"aTexCoord0"); |
| 234 | OPENGL_CHECK_ERRORS; |
| 235 | glBindAttribLocation(copyProgram,VS_POSITION,"aPosition"); |
| 236 | OPENGL_CHECK_ERRORS; |
| 237 | |
| 238 | glLinkProgram(copyProgram); |
| 239 | copyAlphaLocation = glGetUniformLocation(copyProgram,"AlphaRef"); |
| 240 | glGetProgramiv(copyProgram,GL_LINK_STATUS,&success); |
| 241 | if(!success) |
| 242 | { |
| 243 | char log[1024]; |
| 244 | glGetProgramInfoLog(copyProgram,1024,NULL,log); |
| 245 | printf("%s\n",log); |
| 246 | } |
| 247 | |
| 248 | glDeleteShader(fs); |
| 249 | |
| 250 | //Fill shader |
| 251 | fs = glCreateShader(GL_FRAGMENT_SHADER); |
| 252 | glShaderSource(fs,1,&fragmentFill,NULL); |
| 253 | glCompileShader(fs); |
| 254 | |
| 255 | glGetShaderiv(fs,GL_COMPILE_STATUS,&success); |
| 256 | if(!success) |
| 257 | { |
| 258 | char log[1024]; |
| 259 | glGetShaderInfoLog(fs,1024,NULL,log); |
| 260 | printf("%s\n",log); |
| 261 | } |
| 262 | |
| 263 | fillProgram = glCreateProgram(); |
| 264 | glAttachShader(fillProgram,vs); |
| 265 | glAttachShader(fillProgram,fs); |
| 266 | |
| 267 | glBindAttribLocation(fillProgram,VS_POSITION,"aPosition"); |
| 268 | OPENGL_CHECK_ERRORS; |
| 269 | |
| 270 | glLinkProgram(fillProgram); |
| 271 | |
| 272 | |
| 273 | fillColorLocation = glGetUniformLocation(fillProgram,"uColor"); |
| 274 | |
| 275 | glDeleteShader(fs); |
| 276 | glDeleteShader(vs); |
| 277 | } |
| 278 | COGL_FragmentProgramCombiner::~COGL_FragmentProgramCombiner() |
| 279 | { |
| 280 | int size = m_vCompiledShaders.size(); |
| 281 | for (int i=0; i<size; i++) |
| 282 | { |
| 283 | GLuint ID = m_vCompiledShaders[i].programID; |
| 284 | glDeleteProgram(ID); |
| 285 | |
| 286 | OPENGL_CHECK_ERRORS; |
| 287 | m_vCompiledShaders[i].programID = 0; |
| 288 | } |
| 289 | |
| 290 | m_vCompiledShaders.clear(); |
| 291 | } |
| 292 | |
| 293 | bool COGL_FragmentProgramCombiner::Initialize(void) |
| 294 | { |
| 295 | if( !COGLColorCombiner4::Initialize() ) |
| 296 | return false; |
| 297 | |
| 298 | // COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); |
| 299 | // if( pcontext->IsExtensionSupported("GL_fragment_program") ) |
| 300 | // { |
| 301 | m_bFragmentProgramIsSupported = true; |
| 302 | // } |
| 303 | |
| 304 | return true; |
| 305 | } |
| 306 | |
| 307 | |
| 308 | |
| 309 | void COGL_FragmentProgramCombiner::UseProgram(GLuint program) |
| 310 | { |
| 311 | if (program != currentProgram) { |
| 312 | glUseProgram(program); |
| 313 | currentProgram = program; |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | void COGL_FragmentProgramCombiner::DisableCombiner(void) |
| 318 | { |
| 319 | //glDisable(GL_FRAGMENT_PROGRAM); |
| 320 | //OPENGL_CHECK_ERRORS; |
| 321 | COGLColorCombiner4::DisableCombiner(); |
| 322 | } |
| 323 | |
| 324 | void COGL_FragmentProgramCombiner::InitCombinerCycleCopy(void) |
| 325 | { |
| 326 | m_pOGLRender->DisableMultiTexture(); |
| 327 | m_pOGLRender->EnableTexUnit(0,TRUE); |
| 328 | UseProgram(copyProgram); |
| 329 | glUniform1f(copyAlphaLocation,m_AlphaRef); |
| 330 | OPENGL_CHECK_ERRORS; |
| 331 | glEnableVertexAttribArray(VS_POSITION); |
| 332 | OPENGL_CHECK_ERRORS; |
| 333 | glEnableVertexAttribArray(VS_TEXCOORD0); |
| 334 | OPENGL_CHECK_ERRORS; |
| 335 | glDisableVertexAttribArray(VS_COLOR); |
| 336 | OPENGL_CHECK_ERRORS; |
| 337 | glDisableVertexAttribArray(VS_TEXCOORD1); |
| 338 | OPENGL_CHECK_ERRORS; |
| 339 | glDisableVertexAttribArray(VS_FOG); |
| 340 | OPENGL_CHECK_ERRORS; |
| 341 | COGLTexture* pTexture = g_textures[gRSP.curTile].m_pCOGLTexture; |
| 342 | if( pTexture ) |
| 343 | { |
| 344 | m_pOGLRender->BindTexture(pTexture->m_dwTextureName, 0); |
| 345 | m_pOGLRender->SetTexelRepeatFlags(gRSP.curTile); |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | void COGL_FragmentProgramCombiner::InitCombinerCycleFill(void) |
| 350 | { |
| 351 | UseProgram(fillProgram); |
| 352 | 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); |
| 353 | OPENGL_CHECK_ERRORS; |
| 354 | } |
| 355 | |
| 356 | #ifdef BGR_SHADER |
| 357 | const char *muxToFP_Maps[][2] = { |
| 358 | //color -- alpha |
| 359 | {"vec3(0.0)", "0.0"}, //MUX_0 = 0, |
| 360 | {"vec3(1.0)", "1.0"}, //MUX_1, |
| 361 | {"comb.rgb", "comb.a"}, //MUX_COMBINED, |
| 362 | {"t0.rgb", "t0.a"}, //MUX_TEXEL0, |
| 363 | {"t1.rgb", "t1.a"}, //MUX_TEXEL1, |
| 364 | {"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM, |
| 365 | {"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE, |
| 366 | {"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV, |
| 367 | {"comb.rgb", "comb.a"}, //MUX_COMBALPHA, |
| 368 | {"t0.rgb", "t0.a"}, //MUX_T0_ALPHA, |
| 369 | {"t1.rgb", "t1.a"}, //MUX_T1_ALPHA, |
| 370 | {"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM_ALPHA, |
| 371 | {"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE_ALPHA, |
| 372 | {"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV_ALPHA, |
| 373 | {"EnvFrac.a", "EnvFrac.a"}, //MUX_LODFRAC, |
| 374 | {"PrimFrac.a", "PrimFrac.a"}, //MUX_PRIMLODFRAC, |
| 375 | {"vec3(1.0)", "1.0"}, //MUX_K5, |
| 376 | {"vec3(1.0)", "1.0"}, //MUX_UNK, // Should not be used |
| 377 | }; |
| 378 | #else |
| 379 | const char *muxToFP_Maps[][2] = { |
| 380 | //color -- alpha |
| 381 | {"vec3(0.0)", "0.0"}, //MUX_0 = 0, |
| 382 | {"vec3(1.0)", "1.0"}, //MUX_1, |
| 383 | {"comb.rgb", "comb.a"}, //MUX_COMBINED, |
| 384 | {"t0.bgr", "t0.a"}, //MUX_TEXEL0, |
| 385 | {"t1.bgr", "t1.a"}, //MUX_TEXEL1, |
| 386 | {"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM, |
| 387 | {"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE, |
| 388 | {"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV, |
| 389 | {"comb.rgb", "comb.a"}, //MUX_COMBALPHA, |
| 390 | {"t0.bgr", "t0.a"}, //MUX_T0_ALPHA, |
| 391 | {"t1.bgr", "t1.a"}, //MUX_T1_ALPHA, |
| 392 | {"PrimColor.rgb", "PrimColor.a"}, //MUX_PRIM_ALPHA, |
| 393 | {"vShadeColor.rgb", "vShadeColor.a"}, //MUX_SHADE_ALPHA, |
| 394 | {"EnvColor.rgb", "EnvColor.a"}, //MUX_ENV_ALPHA, |
| 395 | {"EnvFrac.a", "EnvFrac.a"}, //MUX_LODFRAC, |
| 396 | {"PrimFrac.a", "PrimFrac.a"}, //MUX_PRIMLODFRAC, |
| 397 | {"vec3(1.0)", "1.0"}, //MUX_K5, |
| 398 | {"vec3(1.0)", "1.0"}, //MUX_UNK, // Should not be used |
| 399 | }; |
| 400 | #endif |
| 401 | |
| 402 | |
| 403 | char oglNewFP[4092]; |
| 404 | |
| 405 | char* MuxToOC(uint8 val) |
| 406 | { |
| 407 | // For color channel |
| 408 | if( val&MUX_ALPHAREPLICATE ) |
| 409 | return (char*)muxToFP_Maps[val&0x1F][1]; |
| 410 | else |
| 411 | return (char*)muxToFP_Maps[val&0x1F][0]; |
| 412 | } |
| 413 | |
| 414 | char* MuxToOA(uint8 val) |
| 415 | { |
| 416 | // For alpha channel |
| 417 | return (char*)muxToFP_Maps[val&0x1F][1]; |
| 418 | } |
| 419 | |
| 420 | static void CheckFpVars(uint8 MuxVar, bool &bNeedT0, bool &bNeedT1) |
| 421 | { |
| 422 | MuxVar &= 0x1f; |
| 423 | if (MuxVar == MUX_TEXEL0 || MuxVar == MUX_T0_ALPHA) |
| 424 | bNeedT0 = true; |
| 425 | if (MuxVar == MUX_TEXEL1 || MuxVar == MUX_T1_ALPHA) |
| 426 | bNeedT1 = true; |
| 427 | } |
| 428 | |
| 429 | void COGL_FragmentProgramCombiner::GenerateProgramStr() |
| 430 | { |
| 431 | DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux; |
| 432 | |
| 433 | mux.splitType[0] = mux.splitType[1] = mux.splitType[2] = mux.splitType[3] = CM_FMT_TYPE_NOT_CHECKED; |
| 434 | m_pDecodedMux->Reformat(false); |
| 435 | |
| 436 | char tempstr[500], newFPBody[4092]; |
| 437 | bool bNeedT0 = false, bNeedT1 = false, bNeedComb2 = false; |
| 438 | newFPBody[0] = 0; |
| 439 | |
| 440 | for( int cycle=0; cycle<2; cycle++ ) |
| 441 | { |
| 442 | for( int channel=0; channel<2; channel++) |
| 443 | { |
| 444 | char* (*func)(uint8) = channel==0?MuxToOC:MuxToOA; |
| 445 | char *dst = channel==0?(char*)"rgb":(char*)"a"; |
| 446 | N64CombinerType &m = mux.m_n64Combiners[cycle*2+channel]; |
| 447 | switch( mux.splitType[cycle*2+channel] ) |
| 448 | { |
| 449 | case CM_FMT_TYPE_NOT_USED: |
| 450 | tempstr[0] = 0; |
| 451 | break; |
| 452 | case CM_FMT_TYPE_D: |
| 453 | sprintf(tempstr, "comb.%s = %s;\n", dst, func(m.d)); |
| 454 | CheckFpVars(m.d, bNeedT0, bNeedT1); |
| 455 | break; |
| 456 | case CM_FMT_TYPE_A_MOD_C: |
| 457 | sprintf(tempstr, "comb.%s = %s * %s;\n", dst, func(m.a), func(m.c)); |
| 458 | CheckFpVars(m.a, bNeedT0, bNeedT1); |
| 459 | CheckFpVars(m.c, bNeedT0, bNeedT1); |
| 460 | break; |
| 461 | case CM_FMT_TYPE_A_ADD_D: |
| 462 | sprintf(tempstr, "comb.%s = saturate(%s + %s);\n", dst, func(m.a), func(m.d)); |
| 463 | CheckFpVars(m.a, bNeedT0, bNeedT1); |
| 464 | CheckFpVars(m.d, bNeedT0, bNeedT1); |
| 465 | break; |
| 466 | case CM_FMT_TYPE_A_SUB_B: |
| 467 | sprintf(tempstr, "comb.%s = %s - %s;\n", dst, func(m.a), func(m.b)); |
| 468 | CheckFpVars(m.a, bNeedT0, bNeedT1); |
| 469 | CheckFpVars(m.b, bNeedT0, bNeedT1); |
| 470 | break; |
| 471 | case CM_FMT_TYPE_A_MOD_C_ADD_D: |
| 472 | sprintf(tempstr, "comb.%s = saturate(%s * %s + %s);\n", dst, func(m.a), func(m.c),func(m.d)); |
| 473 | CheckFpVars(m.a, bNeedT0, bNeedT1); |
| 474 | CheckFpVars(m.c, bNeedT0, bNeedT1); |
| 475 | CheckFpVars(m.d, bNeedT0, bNeedT1); |
| 476 | break; |
| 477 | case CM_FMT_TYPE_A_LERP_B_C: |
| 478 | //ARB ASM LERP and mix have different parameter ordering. |
| 479 | //sprintf(tempstr, "comb.%s = saturate(mix(%s, %s, %s));\n", dst,func(m.a),func(m.b), func(m.c)); |
| 480 | sprintf(tempstr, "comb.%s = (%s - %s) * %s + %s;\n", dst,func(m.a),func(m.b), func(m.c),func(m.b)); |
| 481 | CheckFpVars(m.a, bNeedT0, bNeedT1); |
| 482 | CheckFpVars(m.b, bNeedT0, bNeedT1); |
| 483 | CheckFpVars(m.c, bNeedT0, bNeedT1); |
| 484 | //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)); |
| 485 | break; |
| 486 | default: |
| 487 | 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)); |
| 488 | CheckFpVars(m.a, bNeedT0, bNeedT1); |
| 489 | CheckFpVars(m.b, bNeedT0, bNeedT1); |
| 490 | CheckFpVars(m.c, bNeedT0, bNeedT1); |
| 491 | CheckFpVars(m.d, bNeedT0, bNeedT1); |
| 492 | bNeedComb2 = true; |
| 493 | break; |
| 494 | } |
| 495 | strcat(newFPBody, tempstr); |
| 496 | } |
| 497 | } |
| 498 | |
| 499 | oglNewFP[0] = 0; |
| 500 | if (bNeedT0) |
| 501 | strcat(oglNewFP, "#define NEED_TEX0\n"); |
| 502 | if (bNeedT1) |
| 503 | strcat(oglNewFP, "#define NEED_TEX1\n"); |
| 504 | strcat(oglNewFP, fragmentHeader); |
| 505 | strcat(oglNewFP, newFPBody); |
| 506 | strcat(oglNewFP, fragmentFooter); |
| 507 | |
| 508 | } |
| 509 | |
| 510 | int COGL_FragmentProgramCombiner::ParseDecodedMux() |
| 511 | { |
| 512 | if( !m_bFragmentProgramIsSupported ) |
| 513 | return COGLColorCombiner4::ParseDecodedMux(); |
| 514 | |
| 515 | OGLShaderCombinerSaveType res; |
| 516 | GLint success; |
| 517 | |
| 518 | if(vertexProgram == 9999) |
| 519 | { |
| 520 | vertexProgram = res.vertexShaderID = glCreateShader(GL_VERTEX_SHADER); |
| 521 | glShaderSource(res.vertexShaderID, 1, &vertexShader,NULL); |
| 522 | OPENGL_CHECK_ERRORS; |
| 523 | glCompileShader(res.vertexShaderID); |
| 524 | OPENGL_CHECK_ERRORS; |
| 525 | } |
| 526 | else |
| 527 | { |
| 528 | res.vertexShaderID = vertexProgram; |
| 529 | } |
| 530 | |
| 531 | |
| 532 | //Create 4 shaders, with and without alphatest + with and without fog |
| 533 | GenerateProgramStr(); |
| 534 | |
| 535 | for(int alphaTest = 0;alphaTest < 2;alphaTest++) |
| 536 | { |
| 537 | for(int fog = 0;fog < 2;fog++) { |
| 538 | res.fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); |
| 539 | |
| 540 | char* tmpShader = (char*)malloc(sizeof(char) * 4096); |
| 541 | strcpy(tmpShader,"#version " GLSL_VERSION "\n"); |
| 542 | |
| 543 | if(alphaTest == 1) |
| 544 | { |
| 545 | strcat(tmpShader,"#define ALPHA_TEST\n"); |
| 546 | } |
| 547 | if(fog == 1) |
| 548 | { |
| 549 | strcat(tmpShader,"#define FOG\n"); |
| 550 | } |
| 551 | |
| 552 | res.fogIsUsed = fog == 1; |
| 553 | res.alphaTest = alphaTest == 1; |
| 554 | strcat(tmpShader,oglNewFP); |
| 555 | |
| 556 | glShaderSource(res.fragmentShaderID, 1,(const char**) &tmpShader,NULL); |
| 557 | free(tmpShader); |
| 558 | |
| 559 | |
| 560 | OPENGL_CHECK_ERRORS; |
| 561 | glCompileShader(res.fragmentShaderID); |
| 562 | |
| 563 | glGetShaderiv(res.fragmentShaderID, GL_COMPILE_STATUS, &success); |
| 564 | if (!success) |
| 565 | { |
| 566 | char Log[1024]; |
| 567 | GLint nLength; |
| 568 | glGetShaderInfoLog(res.fragmentShaderID, 1024, &nLength, Log); |
| 569 | printf("Error compiling shader!\n %s",oglNewFP); |
| 570 | printf("%s", Log); |
| 571 | } |
| 572 | |
| 573 | res.programID = glCreateProgram(); |
| 574 | glAttachShader(res.programID,res.vertexShaderID); |
| 575 | glAttachShader(res.programID,res.fragmentShaderID); |
| 576 | |
| 577 | //Bind Attributes |
| 578 | glBindAttribLocation(res.programID,VS_COLOR,"aColor"); |
| 579 | OPENGL_CHECK_ERRORS; |
| 580 | glBindAttribLocation(res.programID,VS_TEXCOORD0,"aTexCoord0"); |
| 581 | OPENGL_CHECK_ERRORS; |
| 582 | glBindAttribLocation(res.programID,VS_TEXCOORD1,"aTexCoord1"); |
| 583 | OPENGL_CHECK_ERRORS; |
| 584 | glBindAttribLocation(res.programID,VS_POSITION,"aPosition"); |
| 585 | OPENGL_CHECK_ERRORS; |
| 586 | glBindAttribLocation(res.programID,VS_FOG,"aFogCoord"); |
| 587 | OPENGL_CHECK_ERRORS; |
| 588 | |
| 589 | glLinkProgram(res.programID); |
| 590 | OPENGL_CHECK_ERRORS; |
| 591 | |
| 592 | glGetProgramiv(res.programID, GL_LINK_STATUS, &success); |
| 593 | if (!success) |
| 594 | { |
| 595 | char Log[1024]; |
| 596 | GLint nLength; |
| 597 | glGetShaderInfoLog(res.fragmentShaderID, 1024, &nLength, Log); |
| 598 | printf("Error linking program!\n"); |
| 599 | printf("%s\n",Log); |
| 600 | } |
| 601 | |
| 602 | UseProgram(res.programID); |
| 603 | OPENGL_CHECK_ERRORS; |
| 604 | |
| 605 | //Bind texture samplers |
| 606 | GLint tex0 = glGetUniformLocation(res.programID,"uTex0"); |
| 607 | GLint tex1 = glGetUniformLocation(res.programID,"uTex1"); |
| 608 | |
| 609 | if(tex0 != -1) |
| 610 | glUniform1i(tex0,0); |
| 611 | if(tex1 != -1) |
| 612 | glUniform1i(tex1,1); |
| 613 | |
| 614 | //Bind Uniforms |
| 615 | res.PrimColorLocation = glGetUniformLocation(res.programID,"PrimColor"); |
| 616 | OPENGL_CHECK_ERRORS; |
| 617 | res.EnvColorLocation = glGetUniformLocation(res.programID,"EnvColor"); |
| 618 | OPENGL_CHECK_ERRORS; |
| 619 | res.PrimFracLocation = glGetUniformLocation(res.programID,"PrimFrac"); |
| 620 | OPENGL_CHECK_ERRORS; |
| 621 | res.EnvFracLocation = glGetUniformLocation(res.programID,"EnvFrac"); |
| 622 | OPENGL_CHECK_ERRORS; |
| 623 | res.AlphaRefLocation = glGetUniformLocation(res.programID,"AlphaRef"); |
| 624 | OPENGL_CHECK_ERRORS; |
| 625 | res.FogColorLocation = glGetUniformLocation(res.programID,"FogColor"); |
| 626 | OPENGL_CHECK_ERRORS; |
| 627 | res.FogMinMaxLocation = glGetUniformLocation(res.programID,"FogMinMax"); |
| 628 | OPENGL_CHECK_ERRORS; |
| 629 | |
| 630 | res.dwMux0 = m_pDecodedMux->m_dwMux0; |
| 631 | res.dwMux1 = m_pDecodedMux->m_dwMux1; |
| 632 | |
| 633 | m_vCompiledShaders.push_back(res); |
| 634 | } |
| 635 | } |
| 636 | m_lastIndex = m_vCompiledShaders.size()-4; |
| 637 | |
| 638 | return m_lastIndex; |
| 639 | } |
| 640 | |
| 641 | void COGL_FragmentProgramCombiner::GenerateCombinerSetting(int index) |
| 642 | { |
| 643 | GLuint ID = m_vCompiledShaders[index].programID; |
| 644 | |
| 645 | UseProgram(ID); |
| 646 | glEnableVertexAttribArray(VS_POSITION); |
| 647 | OPENGL_CHECK_ERRORS; |
| 648 | glVertexAttribPointer(VS_POSITION,4,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][0])); |
| 649 | OPENGL_CHECK_ERRORS; |
| 650 | |
| 651 | glEnableVertexAttribArray(VS_TEXCOORD0); |
| 652 | OPENGL_CHECK_ERRORS; |
| 653 | glVertexAttribPointer(VS_TEXCOORD0,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[0].u)); |
| 654 | OPENGL_CHECK_ERRORS; |
| 655 | |
| 656 | glEnableVertexAttribArray(VS_TEXCOORD1); |
| 657 | OPENGL_CHECK_ERRORS; |
| 658 | glVertexAttribPointer(VS_TEXCOORD1,2,GL_FLOAT,GL_FALSE, sizeof( TLITVERTEX ), &(g_vtxBuffer[0].tcord[1].u)); |
| 659 | OPENGL_CHECK_ERRORS; |
| 660 | |
| 661 | glEnableVertexAttribArray(VS_COLOR); |
| 662 | OPENGL_CHECK_ERRORS; |
| 663 | glVertexAttribPointer(VS_COLOR, 4, GL_UNSIGNED_BYTE,GL_TRUE, sizeof(uint8)*4, &(g_oglVtxColors[0][0]) ); |
| 664 | OPENGL_CHECK_ERRORS; |
| 665 | |
| 666 | glEnableVertexAttribArray(VS_FOG); |
| 667 | OPENGL_CHECK_ERRORS; |
| 668 | glVertexAttribPointer(VS_FOG,1,GL_FLOAT,GL_FALSE,sizeof(float)*5,&(g_vtxProjected5[0][4])); |
| 669 | OPENGL_CHECK_ERRORS; |
| 670 | } |
| 671 | |
| 672 | void COGL_FragmentProgramCombiner::GenerateCombinerSettingConstants(int index) |
| 673 | { |
| 674 | OGLShaderCombinerSaveType &prog = m_vCompiledShaders[index]; |
| 675 | |
| 676 | UseProgram(prog.programID); |
| 677 | float *pf; |
| 678 | if(prog.EnvColorLocation != -1) |
| 679 | { |
| 680 | pf = GetEnvColorfv(); |
| 681 | if (memcmp(pf, prog.EnvColors, sizeof(prog.EnvColors))) { |
| 682 | memcpy(prog.EnvColors, pf, sizeof(prog.EnvColors)); |
| 683 | glUniform4fv(prog.EnvColorLocation, 1, pf); |
| 684 | OPENGL_CHECK_ERRORS; |
| 685 | } |
| 686 | } |
| 687 | |
| 688 | if(prog.PrimColorLocation != -1) |
| 689 | { |
| 690 | pf = GetPrimitiveColorfv(); |
| 691 | if (memcmp(pf, prog.PrimColors, sizeof(prog.PrimColors))) { |
| 692 | memcpy(prog.PrimColors, pf, sizeof(prog.PrimColors)); |
| 693 | glUniform4fv(prog.PrimColorLocation, 1, pf); |
| 694 | OPENGL_CHECK_ERRORS; |
| 695 | } |
| 696 | } |
| 697 | |
| 698 | if(prog.EnvFracLocation != -1) |
| 699 | { |
| 700 | // avoid slow float compare.. |
| 701 | if( *(int *)&gRDP.LODFrac != *(int *)&prog.EnvLODFrac ) { |
| 702 | prog.EnvLODFrac = gRDP.LODFrac; |
| 703 | float frac = gRDP.LODFrac / 255.0f; |
| 704 | float tempf[4] = {frac,frac,frac,frac}; |
| 705 | glUniform4fv(prog.EnvFracLocation, 1, tempf); |
| 706 | OPENGL_CHECK_ERRORS; |
| 707 | } |
| 708 | } |
| 709 | |
| 710 | if(prog.PrimFracLocation != -1) |
| 711 | { |
| 712 | if( *(int *)&gRDP.primLODFrac != *(int *)&prog.PrimLODFrac ) { |
| 713 | prog.PrimLODFrac = gRDP.primLODFrac; |
| 714 | float frac2 = gRDP.primLODFrac / 255.0f; |
| 715 | float tempf2[4] = {frac2,frac2,frac2,frac2}; |
| 716 | glUniform4fv(prog.PrimFracLocation, 1, tempf2); |
| 717 | OPENGL_CHECK_ERRORS; |
| 718 | } |
| 719 | } |
| 720 | |
| 721 | if(prog.FogColorLocation != -1) |
| 722 | { |
| 723 | pf = &gRDP.fvFogColor[0]; |
| 724 | if (memcmp(pf, prog.FogColors, sizeof(prog.FogColors))) { |
| 725 | memcpy(prog.FogColors, pf, sizeof(prog.FogColors)); |
| 726 | glUniform4fv(prog.FogColorLocation, 1, pf); |
| 727 | OPENGL_CHECK_ERRORS; |
| 728 | } |
| 729 | } |
| 730 | |
| 731 | if(prog.FogMinMaxLocation != -1) |
| 732 | { |
| 733 | if( gRSPfFogMin != prog.FogMin || gRSPfFogMax != prog.FogMax ) { |
| 734 | prog.FogMin = gRSPfFogMin; |
| 735 | prog.FogMax = gRSPfFogMax; |
| 736 | glUniform2f(prog.FogMinMaxLocation,gRSPfFogMin,gRSPfFogMax); |
| 737 | OPENGL_CHECK_ERRORS; |
| 738 | } |
| 739 | } |
| 740 | |
| 741 | if(prog.AlphaRefLocation != -1) |
| 742 | { |
| 743 | if( m_AlphaRef != prog.AlphaRef ) { |
| 744 | prog.AlphaRef = m_AlphaRef; |
| 745 | glUniform1f(prog.AlphaRefLocation, m_AlphaRef); |
| 746 | OPENGL_CHECK_ERRORS; |
| 747 | } |
| 748 | } |
| 749 | } |
| 750 | |
| 751 | int COGL_FragmentProgramCombiner::FindCompiledMux() |
| 752 | { |
| 753 | #ifdef DEBUGGER |
| 754 | if( debuggerDropCombiners ) |
| 755 | { |
| 756 | m_vCompiledShaders.clear(); |
| 757 | //m_dwLastMux0 = m_dwLastMux1 = 0; |
| 758 | debuggerDropCombiners = false; |
| 759 | } |
| 760 | #endif |
| 761 | for( uint32 i=0; i<m_vCompiledShaders.size(); i++ ) |
| 762 | { |
| 763 | if( m_vCompiledShaders[i].dwMux0 == m_pDecodedMux->m_dwMux0 |
| 764 | && m_vCompiledShaders[i].dwMux1 == m_pDecodedMux->m_dwMux1 |
| 765 | && m_vCompiledShaders[i].fogIsUsed == bFogState |
| 766 | && m_vCompiledShaders[i].alphaTest == bAlphaTestState) |
| 767 | { |
| 768 | return (int)i; |
| 769 | } |
| 770 | } |
| 771 | |
| 772 | return -1; |
| 773 | } |
| 774 | |
| 775 | ////////////////////////////////////////////////////////////////////////// |
| 776 | void COGL_FragmentProgramCombiner::InitCombinerCycle12(void) |
| 777 | { |
| 778 | if( !m_bFragmentProgramIsSupported ) |
| 779 | { |
| 780 | COGLColorCombiner4::InitCombinerCycle12(); |
| 781 | return; |
| 782 | } |
| 783 | |
| 784 | #ifdef DEBUGGER |
| 785 | if( debuggerDropCombiners ) |
| 786 | { |
| 787 | UpdateCombiner(m_pDecodedMux->m_dwMux0,m_pDecodedMux->m_dwMux1); |
| 788 | m_vCompiledShaders.clear(); |
| 789 | m_dwLastMux0 = m_dwLastMux1 = 0; |
| 790 | debuggerDropCombiners = false; |
| 791 | } |
| 792 | #endif |
| 793 | |
| 794 | m_pOGLRender->EnableMultiTexture(); |
| 795 | |
| 796 | bool combinerIsChanged = false; |
| 797 | |
| 798 | if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 |
| 799 | || bAlphaTestState != bAlphaTestPreviousState || bFogState != bFogPreviousState || m_lastIndex < 0 ) |
| 800 | { |
| 801 | combinerIsChanged = true; |
| 802 | m_lastIndex = FindCompiledMux(); |
| 803 | if( m_lastIndex < 0 ) // Can not found |
| 804 | { |
| 805 | m_lastIndex = ParseDecodedMux(); |
| 806 | } |
| 807 | |
| 808 | m_dwLastMux0 = m_pDecodedMux->m_dwMux0; |
| 809 | m_dwLastMux1 = m_pDecodedMux->m_dwMux1; |
| 810 | bAlphaTestPreviousState = bAlphaTestState; |
| 811 | bFogPreviousState = bFogState; |
| 812 | m_AlphaRef = (float)(m_pOGLRender->m_dwAlpha)/255.0f; |
| 813 | } |
| 814 | |
| 815 | |
| 816 | GenerateCombinerSettingConstants(m_lastIndex); |
| 817 | if( m_bCycleChanged || combinerIsChanged || gRDP.texturesAreReloaded || gRDP.colorsAreReloaded ) |
| 818 | { |
| 819 | if( m_bCycleChanged || combinerIsChanged ) |
| 820 | { |
| 821 | GenerateCombinerSettingConstants(m_lastIndex); |
| 822 | GenerateCombinerSetting(m_lastIndex); |
| 823 | } |
| 824 | else if( gRDP.colorsAreReloaded ) |
| 825 | { |
| 826 | GenerateCombinerSettingConstants(m_lastIndex); |
| 827 | } |
| 828 | |
| 829 | m_pOGLRender->SetAllTexelRepeatFlag(); |
| 830 | |
| 831 | gRDP.colorsAreReloaded = false; |
| 832 | gRDP.texturesAreReloaded = false; |
| 833 | } |
| 834 | else |
| 835 | { |
| 836 | m_pOGLRender->SetAllTexelRepeatFlag(); |
| 837 | } |
| 838 | } |
| 839 | |
| 840 | #ifdef DEBUGGER |
| 841 | void COGL_FragmentProgramCombiner::DisplaySimpleMuxString(void) |
| 842 | { |
| 843 | COGLColorCombiner::DisplaySimpleMuxString(); |
| 844 | DecodedMuxForPixelShader &mux = *(DecodedMuxForPixelShader*)m_pDecodedMux; |
| 845 | mux.Reformat(false); |
| 846 | GenerateProgramStr(); |
| 847 | //sprintf(oglNewFP, oglFP, |
| 848 | // MuxToOC(mux.aRGB0), MuxToOC(mux.bRGB0), MuxToOC(mux.cRGB0), MuxToOC(mux.dRGB0), |
| 849 | // MuxToOA(mux.aA0), MuxToOA(mux.bA0), MuxToOA(mux.cA0), MuxToOA(mux.dA0), |
| 850 | // MuxToOC(mux.aRGB1), MuxToOC(mux.bRGB1), MuxToOC(mux.cRGB1), MuxToOC(mux.dRGB1), |
| 851 | // MuxToOA(mux.aA1), MuxToOA(mux.bA1), MuxToOA(mux.cA1), MuxToOA(mux.dA1) |
| 852 | // ); |
| 853 | |
| 854 | TRACE0("OGL Fragment Program:"); |
| 855 | TRACE0(oglNewFP); |
| 856 | } |
| 857 | #endif |
| 858 | |