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