292f9317 |
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 |
0c9dca78 |
27 | #define ENABLE true |
28 | #define DISABLE false |
292f9317 |
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"\ |
ea03ad21 |
38 | "attribute mediump float aFogCoord; \n"\ |
292f9317 |
39 | " \n"\ |
74e43de0 |
40 | "uniform vec2 FogMinMax; \n"\ |
41 | " \n"\ |
292f9317 |
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"\ |
74e43de0 |
54 | "vFog = (FogMinMax[1] - aFogCoord) / (FogMinMax[1] - FogMinMax[0]); \n"\ |
292f9317 |
55 | " \n"\ |
74e43de0 |
56 | "vFog = clamp(vFog, 0.0, 1.0); \n"\ |
292f9317 |
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"\ |
292f9317 |
78 | "varying lowp vec4 vShadeColor; \n"\ |
79 | "varying mediump vec2 vTexCoord0; \n"\ |
80 | "varying lowp vec2 vTexCoord1; \n"\ |
7ec5739f |
81 | "varying lowp float vFog; \n"\ |
292f9317 |
82 | " \n"\ |
83 | "void main() \n"\ |
84 | "{ \n"\ |
85 | "vec4 comb,comb2; \n"\ |
86 | " \n"\ |
ea03ad21 |
87 | "#ifdef NEED_TEX0 \n"\ |
292f9317 |
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"\ |
ea03ad21 |
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"\ |
0c9dca78 |
105 | ALPHA_TEST |
ea03ad21 |
106 | "#endif \n"\ |
292f9317 |
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 | |
6c753368 |
150 | // COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); |
292f9317 |
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; |
ea03ad21 |
197 | bAlphaTestState = false; |
198 | bAlphaTestPreviousState = false; |
199 | bFogState = false; |
200 | bFogPreviousState = false; |
292f9317 |
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 | |
6c753368 |
298 | // COGLGraphicsContext *pcontext = (COGLGraphicsContext *)(CGraphicsContext::g_pGraphicsContext); |
292f9317 |
299 | // if( pcontext->IsExtensionSupported("GL_fragment_program") ) |
300 | // { |
301 | m_bFragmentProgramIsSupported = true; |
302 | // } |
303 | |
304 | return true; |
305 | } |
306 | |
307 | |
308 | |
6c753368 |
309 | void COGL_FragmentProgramCombiner::UseProgram(GLuint program) |
310 | { |
311 | if (program != currentProgram) { |
312 | glUseProgram(program); |
313 | currentProgram = program; |
314 | } |
315 | } |
316 | |
292f9317 |
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); |
6c753368 |
328 | UseProgram(copyProgram); |
292f9317 |
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; |
ea03ad21 |
339 | glDisableVertexAttribArray(VS_FOG); |
340 | OPENGL_CHECK_ERRORS; |
292f9317 |
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 | { |
6c753368 |
351 | UseProgram(fillProgram); |
292f9317 |
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"); |
292f9317 |
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 | |
0c9dca78 |
532 | //Create 4 shaders, with and without alphatest + with and without fog |
292f9317 |
533 | GenerateProgramStr(); |
534 | |
535 | for(int alphaTest = 0;alphaTest < 2;alphaTest++) |
536 | { |
0c9dca78 |
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; |
ea03ad21 |
586 | glBindAttribLocation(res.programID,VS_FOG,"aFogCoord"); |
587 | OPENGL_CHECK_ERRORS; |
0c9dca78 |
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 | |
6c753368 |
602 | UseProgram(res.programID); |
0c9dca78 |
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 | } |
292f9317 |
635 | } |
0c9dca78 |
636 | m_lastIndex = m_vCompiledShaders.size()-4; |
292f9317 |
637 | |
638 | return m_lastIndex; |
639 | } |
640 | |
641 | void COGL_FragmentProgramCombiner::GenerateCombinerSetting(int index) |
642 | { |
643 | GLuint ID = m_vCompiledShaders[index].programID; |
644 | |
6c753368 |
645 | UseProgram(ID); |
292f9317 |
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; |
ea03ad21 |
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; |
292f9317 |
670 | } |
671 | |
672 | void COGL_FragmentProgramCombiner::GenerateCombinerSettingConstants(int index) |
673 | { |
6c753368 |
674 | OGLShaderCombinerSaveType &prog = m_vCompiledShaders[index]; |
292f9317 |
675 | |
6c753368 |
676 | UseProgram(prog.programID); |
292f9317 |
677 | float *pf; |
678 | if(prog.EnvColorLocation != -1) |
679 | { |
680 | pf = GetEnvColorfv(); |
6c753368 |
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 | } |
292f9317 |
686 | } |
687 | |
688 | if(prog.PrimColorLocation != -1) |
689 | { |
690 | pf = GetPrimitiveColorfv(); |
6c753368 |
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 | } |
292f9317 |
696 | } |
697 | |
698 | if(prog.EnvFracLocation != -1) |
699 | { |
6c753368 |
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 | } |
292f9317 |
708 | } |
709 | |
710 | if(prog.PrimFracLocation != -1) |
711 | { |
6c753368 |
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 | } |
292f9317 |
719 | } |
720 | |
6c753368 |
721 | if(prog.FogColorLocation != -1) |
292f9317 |
722 | { |
6c753368 |
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 | } |
0c9dca78 |
729 | } |
730 | |
6c753368 |
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 | } |
292f9317 |
739 | } |
0c9dca78 |
740 | |
741 | if(prog.AlphaRefLocation != -1) |
6c753368 |
742 | { |
743 | if( m_AlphaRef != prog.AlphaRef ) { |
744 | prog.AlphaRef = m_AlphaRef; |
745 | glUniform1f(prog.AlphaRefLocation, m_AlphaRef); |
746 | OPENGL_CHECK_ERRORS; |
747 | } |
748 | } |
292f9317 |
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 |
0c9dca78 |
765 | && m_vCompiledShaders[i].fogIsUsed == bFogState |
766 | && m_vCompiledShaders[i].alphaTest == bAlphaTestState) |
292f9317 |
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 | |
0c9dca78 |
798 | if( m_pDecodedMux->m_dwMux0 != m_dwLastMux0 || m_pDecodedMux->m_dwMux1 != m_dwLastMux1 |
799 | || bAlphaTestState != bAlphaTestPreviousState || bFogState != bFogPreviousState || m_lastIndex < 0 ) |
292f9317 |
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; |
0c9dca78 |
810 | bAlphaTestPreviousState = bAlphaTestState; |
811 | bFogPreviousState = bFogState; |
812 | m_AlphaRef = (float)(m_pOGLRender->m_dwAlpha)/255.0f; |
813 | } |
292f9317 |
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 | |