1 // shader.cpp: OpenGL assembly/GLSL shader management
6 Shader
*Shader::lastshader
= NULL
;
8 Shader
*defaultshader
= NULL
, *notextureshader
= NULL
, *nocolorshader
= NULL
, *foggedshader
= NULL
, *foggednotextureshader
= NULL
;
10 static hashtable
<const char *, Shader
> shaders
;
11 static Shader
*curshader
= NULL
;
12 static vector
<ShaderParam
> curparams
;
13 static ShaderParamState vertexparamstate
[RESERVEDSHADERPARAMS
+ MAXSHADERPARAMS
], pixelparamstate
[RESERVEDSHADERPARAMS
+ MAXSHADERPARAMS
];
14 static int dirtyparams
= 0;
18 exec("data/stdshader.cfg");
19 defaultshader
= lookupshaderbyname("default");
20 notextureshader
= lookupshaderbyname("notexture");
21 nocolorshader
= lookupshaderbyname("nocolor");
22 foggedshader
= lookupshaderbyname("fogged");
23 foggednotextureshader
= lookupshaderbyname("foggednotexture");
24 if(renderpath
!=R_FIXEDFUNCTION
)
26 glEnable(GL_VERTEX_PROGRAM_ARB
);
27 glEnable(GL_FRAGMENT_PROGRAM_ARB
);
32 Shader
*lookupshaderbyname(const char *name
)
34 Shader
*s
= shaders
.access(name
);
35 return s
&& s
->altshader
? s
->altshader
: s
;
38 static bool compileasmshader(GLenum type
, GLuint
&idx
, const char *def
, const char *tname
, const char *name
, bool msg
= true, bool nativeonly
= false)
40 glGenPrograms_(1, &idx
);
41 glBindProgram_(type
, idx
);
42 def
+= strspn(def
, " \t\r\n");
43 glProgramString_(type
, GL_PROGRAM_FORMAT_ASCII_ARB
, (GLsizei
)strlen(def
), def
);
45 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB
, &err
);
46 glGetProgramiv_(type
, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB
, &native
);
49 conoutf("COMPILE ERROR (%s:%s) - %s", tname
, name
, glGetString(GL_PROGRAM_ERROR_STRING_ARB
));
50 if(err
>=0 && err
<(int)strlen(def
))
52 loopi(err
) putchar(*def
++);
54 while(*def
) putchar(*def
++);
57 else if(msg
&& !native
) conoutf("%s:%s EXCEEDED NATIVE LIMITS", tname
, name
);
58 if(err
!=-1 || (!native
&& nativeonly
))
60 glDeletePrograms_(1, &idx
);
66 static void showglslinfo(GLhandleARB obj
, const char *tname
, const char *name
)
69 glGetObjectParameteriv_(obj
, GL_OBJECT_INFO_LOG_LENGTH_ARB
, &length
);
72 GLcharARB
*log
= new GLcharARB
[length
];
73 glGetInfoLog_(obj
, length
, &length
, log
);
74 conoutf("GLSL ERROR (%s:%s)", tname
, name
);
80 static void compileglslshader(GLenum type
, GLhandleARB
&obj
, const char *def
, const char *tname
, const char *name
, bool msg
= true)
82 const GLcharARB
*source
= (const GLcharARB
*)(def
+ strspn(def
, " \t\r\n"));
83 obj
= glCreateShaderObject_(type
);
84 glShaderSource_(obj
, 1, &source
, NULL
);
85 glCompileShader_(obj
);
87 glGetObjectParameteriv_(obj
, GL_OBJECT_COMPILE_STATUS_ARB
, &success
);
90 if(msg
) showglslinfo(obj
, tname
, name
);
96 static void linkglslprogram(Shader
&s
, bool msg
= true)
98 s
.program
= glCreateProgramObject_();
100 if(s
.program
&& s
.vsobj
&& s
.psobj
)
102 glAttachObject_(s
.program
, s
.vsobj
);
103 glAttachObject_(s
.program
, s
.psobj
);
104 glLinkProgram_(s
.program
);
105 glGetObjectParameteriv_(s
.program
, GL_OBJECT_LINK_STATUS_ARB
, &success
);
109 glUseProgramObject_(s
.program
);
112 s_sprintfd(arg
)("tex%d", i
);
113 GLint loc
= glGetUniformLocation_(s
.program
, arg
);
114 if(loc
!= -1) glUniform1i_(loc
, i
);
116 loopv(s
.defaultparams
)
118 ShaderParam
¶m
= s
.defaultparams
[i
];
120 if(param
.type
==SHPARAM_UNIFORM
) s_strcpy(pname
, param
.name
);
121 else s_sprintf(pname
)("%s%d", param
.type
==SHPARAM_VERTEX
? "v" : "p", param
.index
);
122 param
.loc
= glGetUniformLocation_(s
.program
, pname
);
124 glUseProgramObject_(0);
130 if(msg
) showglslinfo(s
.program
, "PROG", s
.name
);
131 glDeleteObject_(s
.program
);
134 if(s
.vsobj
) { glDeleteObject_(s
.vsobj
); s
.vsobj
= 0; }
135 if(s
.psobj
) { glDeleteObject_(s
.psobj
); s
.psobj
= 0; }
139 bool checkglslsupport()
141 /* check if GLSL profile supports loops
142 * might need to rewrite this if compiler does strength reduction
144 const GLcharARB
*source
=
146 "uniform vec4 delta;\n"
147 "void main(void) {\n"
148 " vec4 test = vec4(0.0, 0.0, 0.0, 0.0);\n"
149 " for(int i = 0; i < N; i++) test += delta;\n"
150 " gl_FragColor = test;\n"
152 GLhandleARB obj
= glCreateShaderObject_(GL_FRAGMENT_SHADER_ARB
);
153 if(!obj
) return false;
154 glShaderSource_(obj
, 1, &source
, NULL
);
155 glCompileShader_(obj
);
157 glGetObjectParameteriv_(obj
, GL_OBJECT_COMPILE_STATUS_ARB
, &success
);
160 glDeleteObject_(obj
);
163 GLhandleARB program
= glCreateProgramObject_();
166 glDeleteObject_(obj
);
169 glAttachObject_(program
, obj
);
170 glLinkProgram_(program
);
171 glGetObjectParameteriv_(program
, GL_OBJECT_LINK_STATUS_ARB
, &success
);
172 glDeleteObject_(obj
);
173 glDeleteObject_(program
);
177 static LocalShaderParamState unusedextparam
;
179 static void allocglsluniformparam(Shader
&s
, int type
, int index
, bool local
= false)
181 ShaderParamState
&val
= (type
==SHPARAM_VERTEX
? vertexparamstate
[index
] : pixelparamstate
[index
]);
182 int loc
= val
.name
? glGetUniformLocation_(s
.program
, val
.name
) : -1;
185 s_sprintfd(altname
)("%s%d", type
==SHPARAM_VERTEX
? "v" : "p", index
);
186 loc
= glGetUniformLocation_(s
.program
, val
.name
);
190 LocalShaderParamState
*alt
= (type
==SHPARAM_VERTEX
? s
.extpixparams
[index
] : s
.extvertparams
[index
]);
191 if(alt
&& alt
!= &unusedextparam
&& alt
->loc
== loc
)
193 if(type
==SHPARAM_VERTEX
) s
.extvertparams
[index
] = alt
;
194 else s
.extpixparams
[index
] = alt
;
200 if(type
==SHPARAM_VERTEX
) s
.extvertparams
[index
] = local
? &unusedextparam
: NULL
;
201 else s
.extpixparams
[index
] = local
? &unusedextparam
: NULL
;
204 LocalShaderParamState
&ext
= s
.extparams
.add();
207 ext
.index
= local
? -1 : index
;
209 if(type
==SHPARAM_VERTEX
) s
.extvertparams
[index
] = &ext
;
210 else s
.extpixparams
[index
] = &ext
;
213 void Shader::allocenvparams(Slot
*slot
)
215 if(!(type
& SHADER_GLSLANG
)) return;
219 #define UNIFORMTEX(name, tmu) \
221 loc = glGetUniformLocation_(program, name); \
223 if(loc != -1) glUniform1i_(loc, val); \
226 if(type
& SHADER_NORMALSLMS
)
228 UNIFORMTEX("lmcolor", 1);
229 UNIFORMTEX("lmdir", 2);
232 else UNIFORMTEX("lightmap", 1);
233 if(type
& SHADER_ENVMAP
) UNIFORMTEX("envmap", tmu
++);
234 UNIFORMTEX("shadowmap", 7);
238 Slot::Tex
&t
= slot
->sts
[i
];
241 case TEX_DIFFUSE
: UNIFORMTEX("diffusemap", 0); break;
242 case TEX_NORMAL
: UNIFORMTEX("normalmap", tmu
++); break;
243 case TEX_GLOW
: UNIFORMTEX("glowmap", tmu
++); break;
244 case TEX_DECAL
: UNIFORMTEX("decal", tmu
++); break;
245 case TEX_SPEC
: if(t
.combined
<0) UNIFORMTEX("specmap", tmu
++); break;
246 case TEX_DEPTH
: if(t
.combined
<0) UNIFORMTEX("depthmap", tmu
++); break;
249 s_sprintfd(sname
)("stex%d", stex
++);
250 UNIFORMTEX(sname
, tmu
++);
256 loopi(RESERVEDSHADERPARAMS
) if(vertexparamstate
[i
].name
&& !vertexparamstate
[i
].local
)
257 allocglsluniformparam(*this, SHPARAM_VERTEX
, i
);
258 loopi(RESERVEDSHADERPARAMS
) if(pixelparamstate
[i
].name
&& !pixelparamstate
[i
].local
)
259 allocglsluniformparam(*this, SHPARAM_PIXEL
, i
);
262 void setenvparamf(const char *name
, int type
, int index
, float x
, float y
, float z
, float w
)
264 ShaderParamState
&val
= (type
==SHPARAM_VERTEX
? vertexparamstate
[index
] : pixelparamstate
[index
]);
267 if(val
.val
[0]!=x
|| val
.val
[1]!=y
|| val
.val
[2]!=z
|| val
.val
[3]!=w
)
273 if(!val
.dirty
) dirtyparams
++;
278 void setenvparamfv(const char *name
, int type
, int index
, const float *v
)
280 ShaderParamState
&val
= (type
==SHPARAM_VERTEX
? vertexparamstate
[index
] : pixelparamstate
[index
]);
283 if(memcmp(val
.val
, v
, sizeof(val
.val
)))
285 memcpy(val
.val
, v
, sizeof(val
.val
));
286 if(!val
.dirty
) dirtyparams
++;
291 void flushenvparam(int type
, int index
, bool local
)
293 ShaderParamState
&val
= (type
==SHPARAM_VERTEX
? vertexparamstate
[index
] : pixelparamstate
[index
]);
295 if(Shader::lastshader
&& Shader::lastshader
->type
&SHADER_GLSLANG
)
297 LocalShaderParamState
*&ext
= (type
==SHPARAM_VERTEX
? Shader::lastshader
->extvertparams
[index
] : Shader::lastshader
->extpixparams
[index
]);
298 if(!ext
) allocglsluniformparam(*Shader::lastshader
, type
, index
, local
);
299 if(!ext
|| ext
== &unusedextparam
) return;
300 if(!memcmp(ext
->curval
, val
.val
, sizeof(ext
->curval
))) return;
301 memcpy(ext
->curval
, val
.val
, sizeof(ext
->curval
));
302 glUniform4fv_(ext
->loc
, 1, ext
->curval
);
306 glProgramEnvParameter4fv_(type
==SHPARAM_VERTEX
? GL_VERTEX_PROGRAM_ARB
: GL_FRAGMENT_PROGRAM_ARB
, index
, val
.val
);
312 void setlocalparamf(const char *name
, int type
, int index
, float x
, float y
, float z
, float w
)
314 setenvparamf(name
, type
, index
, x
, y
, z
, w
);
315 flushenvparam(type
, index
, true);
318 void setlocalparamfv(const char *name
, int type
, int index
, const float *v
)
320 setenvparamfv(name
, type
, index
, v
);
321 flushenvparam(type
, index
, true);
324 void Shader::flushenvparams(Slot
*slot
)
326 if(type
& SHADER_GLSLANG
)
328 if(!used
) allocenvparams(slot
);
332 LocalShaderParamState
&ext
= extparams
[i
];
333 if(ext
.index
<0) continue;
334 float *val
= ext
.type
==SHPARAM_VERTEX
? vertexparamstate
[ext
.index
].val
: pixelparamstate
[ext
.index
].val
;
335 if(!memcmp(ext
.curval
, val
, sizeof(ext
.val
))) continue;
336 memcpy(ext
.curval
, val
, sizeof(ext
.val
));
337 glUniform4fv_(ext
.loc
, 1, ext
.curval
);
342 loopi(RESERVEDSHADERPARAMS
)
344 ShaderParamState
&val
= vertexparamstate
[i
];
345 if(val
.local
|| !val
.dirty
) continue;
346 glProgramEnvParameter4fv_(GL_VERTEX_PROGRAM_ARB
, i
, val
.val
);
350 loopi(RESERVEDSHADERPARAMS
)
352 ShaderParamState
&val
= pixelparamstate
[i
];
353 if(val
.local
|| !val
.dirty
) continue;
354 glProgramEnvParameter4fv_(GL_FRAGMENT_PROGRAM_ARB
, i
, val
.val
);
362 void Shader::setslotparams(Slot
&slot
)
364 uint unimask
= 0, vertmask
= 0, pixmask
= 0;
367 ShaderParam
&p
= slot
.params
[i
];
368 if(type
& SHADER_GLSLANG
)
370 LocalShaderParamState
&l
= defaultparams
[p
.index
];
372 if(!memcmp(l
.curval
, p
.val
, sizeof(l
.curval
))) continue;
373 memcpy(l
.curval
, p
.val
, sizeof(l
.curval
));
374 glUniform4fv_(l
.loc
, 1, l
.curval
);
376 else if(p
.type
!=SHPARAM_UNIFORM
)
378 ShaderParamState
&val
= (p
.type
==SHPARAM_VERTEX
? vertexparamstate
[RESERVEDSHADERPARAMS
+p
.index
] : pixelparamstate
[RESERVEDSHADERPARAMS
+p
.index
]);
379 if(p
.type
==SHPARAM_VERTEX
) vertmask
|= 1<<p
.index
;
380 else pixmask
|= 1<<p
.index
;
381 if(memcmp(val
.val
, p
.val
, sizeof(val
.val
))) memcpy(val
.val
, p
.val
, sizeof(val
.val
));
382 else if(!val
.dirty
) continue;
383 glProgramEnvParameter4fv_(p
.type
==SHPARAM_VERTEX
? GL_VERTEX_PROGRAM_ARB
: GL_FRAGMENT_PROGRAM_ARB
, RESERVEDSHADERPARAMS
+p
.index
, val
.val
);
384 if(val
.dirty
) dirtyparams
--;
391 LocalShaderParamState
&l
= defaultparams
[i
];
392 if(type
& SHADER_GLSLANG
)
394 if(unimask
&(1<<i
)) continue;
395 if(!memcmp(l
.curval
, l
.val
, sizeof(l
.curval
))) continue;
396 memcpy(l
.curval
, l
.val
, sizeof(l
.curval
));
397 glUniform4fv_(l
.loc
, 1, l
.curval
);
399 else if(l
.type
!=SHPARAM_UNIFORM
)
401 if(l
.type
==SHPARAM_VERTEX
)
403 if(vertmask
& (1<<l
.index
)) continue;
405 else if(pixmask
& (1<<l
.index
)) continue;
406 ShaderParamState
&val
= (l
.type
==SHPARAM_VERTEX
? vertexparamstate
[RESERVEDSHADERPARAMS
+l
.index
] : pixelparamstate
[RESERVEDSHADERPARAMS
+l
.index
]);
407 if(memcmp(val
.val
, l
.val
, sizeof(val
.val
))) memcpy(val
.val
, l
.val
, sizeof(val
.val
));
408 else if(!val
.dirty
) continue;
409 glProgramEnvParameter4fv_(l
.type
==SHPARAM_VERTEX
? GL_VERTEX_PROGRAM_ARB
: GL_FRAGMENT_PROGRAM_ARB
, RESERVEDSHADERPARAMS
+l
.index
, val
.val
);
410 if(val
.dirty
) dirtyparams
--;
417 void Shader::bindprograms()
419 if(this==lastshader
) return;
420 if(type
& SHADER_GLSLANG
)
422 glUseProgramObject_(program
);
426 if(lastshader
&& lastshader
->type
& SHADER_GLSLANG
) glUseProgramObject_(0);
428 glBindProgram_(GL_VERTEX_PROGRAM_ARB
, vs
);
429 glBindProgram_(GL_FRAGMENT_PROGRAM_ARB
, ps
);
434 VARFN(shaders
, useshaders
, -1, -1, 1, initwarning());
435 VARF(shaderprecision
, 0, 0, 2, initwarning());
436 VARP(shaderdetail
, 0, MAXSHADERDETAIL
, MAXSHADERDETAIL
);
438 Shader
*newshader(int type
, char *name
, char *vs
, char *ps
, Shader
*variant
= NULL
, int row
= 0)
440 char *rname
= newstring(name
);
441 Shader
&s
= shaders
[rname
];
444 loopi(MAXSHADERDETAIL
) s
.fastshader
[i
] = &s
;
445 memset(s
.extvertparams
, 0, sizeof(s
.extvertparams
));
446 memset(s
.extpixparams
, 0, sizeof(s
.extpixparams
));
447 if(variant
) loopv(variant
->defaultparams
) s
.defaultparams
.add(variant
->defaultparams
[i
]);
448 else loopv(curparams
) s
.defaultparams
.add(curparams
[i
]);
449 if(renderpath
!=R_FIXEDFUNCTION
)
451 if(type
& SHADER_GLSLANG
)
453 compileglslshader(GL_VERTEX_SHADER_ARB
, s
.vsobj
, vs
, "VS", name
, !variant
);
454 compileglslshader(GL_FRAGMENT_SHADER_ARB
, s
.psobj
, ps
, "PS", name
, !variant
);
455 linkglslprogram(s
, !variant
);
459 if(!compileasmshader(GL_VERTEX_PROGRAM_ARB
, s
.vs
, vs
, "VS", name
, !variant
, variant
!=NULL
))
461 if(!compileasmshader(GL_FRAGMENT_PROGRAM_ARB
, s
.ps
, ps
, "PS", name
, !variant
, variant
!=NULL
))
463 if(!s
.vs
|| !s
.ps
|| (variant
&& !s
.native
))
465 if(s
.vs
) { glDeletePrograms_(1, &s
.vs
); s
.vs
= 0; }
466 if(s
.ps
) { glDeletePrograms_(1, &s
.ps
); s
.ps
= 0; }
469 if(!s
.program
&& !s
.vs
&& !s
.ps
)
471 shaders
.remove(rname
);
475 if(variant
) variant
->variants
[row
].add(&s
);
479 static uint
findusedtexcoords(char *str
)
484 char *tc
= strstr(str
, "result.texcoord[");
486 tc
+= strlen("result.texcoord[");
487 int n
= strtol(tc
, &str
, 10);
488 if(n
<0 || n
>=16) continue;
494 static bool findunusedtexcoordcomponent(char *str
, int &texcoord
, int &component
)
497 memset(texcoords
, 0, sizeof(texcoords
));
500 char *tc
= strstr(str
, "result.texcoord[");
502 tc
+= strlen("result.texcoord[");
503 int n
= strtol(tc
, &str
, 10);
504 if(n
<0 || n
>=(int)sizeof(texcoords
)) continue;
505 while(*str
&& *str
!=']') str
++;
508 if(*++str
!='.') { texcoords
[n
] = 0xF; continue; }
513 case 'r': case 'x': texcoords
[n
] |= 1; continue;
514 case 'g': case 'y': texcoords
[n
] |= 2; continue;
515 case 'b': case 'z': texcoords
[n
] |= 4; continue;
516 case 'a': case 'w': texcoords
[n
] |= 8; continue;
522 loopi(sizeof(texcoords
)) if(texcoords
[i
]>0 && texcoords
[i
]<0xF)
524 loopk(4) if(!(texcoords
[i
]&(1<<k
))) { texcoord
= i
; component
= k
; return true; }
529 #define EMUFOGVS(cond, vsbuf, start, end, fogcoord, fogtc, fogcomp) \
532 vsbuf.put(start, fogcoord-start); \
533 const char *afterfogcoord = fogcoord + strlen("result.fogcoord"); \
534 if(*afterfogcoord=='.') afterfogcoord += 2; \
535 s_sprintfd(repfogcoord)("result.texcoord[%d].%c", fogtc, fogcomp==3 ? 'w' : 'x'+fogcomp); \
536 vsbuf.put(repfogcoord, strlen(repfogcoord)); \
537 vsbuf.put(afterfogcoord, end-afterfogcoord); \
539 else vsbuf.put(start, end-start);
541 #define EMUFOGPS(cond, psbuf, fogtc, fogcomp) \
544 char *fogoption = strstr(psbuf.getbuf(), "OPTION ARB_fog_linear;"); \
545 /* OPTION ARB_fog_linear; */ \
546 const char *tmpdef = "TEMP emufogcolor; "; \
547 if(fogoption) while(*tmpdef) *fogoption++ = *tmpdef++; \
549 const char *tmpuse = " emufogcolor"; \
550 char *str = psbuf.getbuf(); \
553 str = strstr(str, "result.color"); \
555 if(str[12]!='.' || (str[13]!='a' && str[13]!='w')) memcpy(str, tmpuse, strlen(tmpuse)); \
558 s_sprintfd(fogtcstr)("fragment.texcoord[%d].%c", fogtc, fogcomp==3 ? 'w' : 'x'+fogcomp); \
559 str = strstr(psbuf.getbuf(), "fragment.fogcoord.x"); \
562 int fogtclen = strlen(fogtcstr); \
563 memcpy(str, fogtcstr, 19); \
564 psbuf.insert(&str[19] - psbuf.getbuf(), &fogtcstr[19], fogtclen-19); \
566 char *end = strstr(psbuf.getbuf(), "END"); \
567 if(end) psbuf.setsizenodelete(end - psbuf.getbuf()); \
568 s_sprintfd(calcfog)( \
570 "SUB emufog, state.fog.params.z, %s;\n" \
571 "MUL_SAT emufog, emufog, state.fog.params.w;\n" \
572 "LRP result.color.rgb, emufog, emufogcolor, state.fog.color;\n" \
575 psbuf.put(calcfog, strlen(calcfog)+1); \
578 VAR(reserveshadowmaptc
, 1, 0, 0);
579 VAR(reservedynlighttc
, 1, 0, 0);
581 static void gendynlightvariant(Shader
&s
, char *sname
, char *vs
, char *ps
, int row
= 0)
583 int numlights
= 0, lights
[MAXDYNLIGHTS
];
584 int emufogtc
= -1, emufogcomp
= -1;
585 const char *emufogcoord
= NULL
;
586 if(s
.type
& SHADER_GLSLANG
) numlights
= MAXDYNLIGHTS
;
589 uint usedtc
= findusedtexcoords(vs
);
591 glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB
, &maxtc
);
592 int reservetc
= row
%2 ? reserveshadowmaptc
: reservedynlighttc
;
593 if(maxtc
-reservetc
<0) return;
594 loopi(maxtc
-reservetc
) if(!(usedtc
&(1<<i
)))
596 lights
[numlights
++] = i
;
597 if(numlights
>=MAXDYNLIGHTS
) break;
599 extern int emulatefog
;
600 if(emulatefog
&& reservetc
>0 && numlights
+1<MAXDYNLIGHTS
&& !(usedtc
&(1<<(maxtc
-reservetc
))) && strstr(ps
, "OPTION ARB_fog_linear;"))
602 emufogcoord
= strstr(vs
, "result.fogcoord");
605 emufogtc
= maxtc
-reservetc
;
607 lights
[numlights
++] = maxtc
-reservetc
;
610 if(!numlights
) return;
613 char *vspragma
= strstr(vs
, "#pragma CUBE2_dynlight"), *pspragma
= strstr(ps
, "#pragma CUBE2_dynlight");
615 vspragma
+= strcspn(vspragma
, "\n");
616 if(*vspragma
) vspragma
++;
618 if(sscanf(pspragma
, "#pragma CUBE2_dynlight %s", pslight
)!=1) return;
620 pspragma
+= strcspn(pspragma
, "\n");
621 if(*pspragma
) pspragma
++;
623 vector
<char> vsdl
, psdl
;
626 vsdl
.setsizenodelete(0);
627 psdl
.setsizenodelete(0);
629 if(s
.type
& SHADER_GLSLANG
)
633 s_sprintfd(pos
)("%sdynlight%dpos%s", !k
? "uniform vec4 " : " ", k
, k
==i
? ";\n" : ",");
634 vsdl
.put(pos
, strlen(pos
));
636 s_sprintfd(color
)("%sdynlight%dcolor%s", !k
? "uniform vec4 " : " ", k
, k
==i
? ";\n" : ",");
637 psdl
.put(color
, strlen(color
));
641 s_sprintfd(dir
)("%sdynlight%ddir%s", !k
? "varying vec3 " : " ", k
, k
==i
? ";\n" : ",");
642 vsdl
.put(dir
, strlen(dir
));
643 psdl
.put(dir
, strlen(dir
));
647 EMUFOGVS(emufogcoord
&& i
+1==numlights
&& emufogcoord
< vspragma
, vsdl
, vs
, vspragma
, emufogcoord
, emufogtc
, emufogcomp
);
648 psdl
.put(ps
, pspragma
-ps
);
653 if(s
.type
& SHADER_GLSLANG
) s_sprintf(tc
)(
654 "dynlight%ddir = gl_Vertex.xyz - dynlight%dpos.xyz;\n",
657 "SUB result.texcoord[%d].xyz, vertex.position, program.env[%d];\n",
659 vsdl
.put(tc
, strlen(tc
));
661 if(s
.type
& SHADER_GLSLANG
) s_sprintf(dl
)(
662 "%s.rgb += dynlight%dcolor.rgb * clamp(1.0 - dynlight%dcolor.a*dot(dynlight%ddir, dynlight%ddir), 0.0, 1.0);\n",
663 pslight
, k
, k
, k
, k
);
666 "DP3 dynlight, fragment.texcoord[%d], fragment.texcoord[%d];\n"
667 "MAD_SAT dynlight, dynlight, program.env[%d].a, 1;\n"
668 "MAD %s.rgb, program.env[%d], dynlight, %s;\n",
670 !k
? "TEMP dynlight;\n" : "",
671 lights
[k
], lights
[k
],
673 pslight
, 10+k
, pslight
);
674 psdl
.put(dl
, strlen(dl
));
677 EMUFOGVS(emufogcoord
&& i
+1==numlights
&& emufogcoord
>= vspragma
, vsdl
, vspragma
, vspragma
+strlen(vspragma
)+1, emufogcoord
, emufogtc
, emufogcomp
);
678 psdl
.put(pspragma
, strlen(pspragma
)+1);
680 EMUFOGPS(emufogcoord
&& i
+1==numlights
, psdl
, emufogtc
, emufogcomp
);
682 s_sprintfd(name
)("<dynlight %d>%s", i
+1, sname
);
683 Shader
*variant
= newshader(s
.type
, name
, vsdl
.getbuf(), psdl
.getbuf(), &s
, row
);
688 static void genshadowmapvariant(Shader
&s
, char *sname
, char *vs
, char *ps
, int row
= 1)
690 int smtc
= -1, emufogtc
= -1, emufogcomp
= -1;
691 const char *emufogcoord
= NULL
;
692 if(!(s
.type
& SHADER_GLSLANG
))
694 uint usedtc
= findusedtexcoords(vs
);
696 glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB
, &maxtc
);
697 if(maxtc
-reserveshadowmaptc
<0) return;
698 loopi(maxtc
-reserveshadowmaptc
) if(!(usedtc
&(1<<i
))) { smtc
= i
; break; }
699 extern int emulatefog
;
700 if(smtc
<0 && emulatefog
&& reserveshadowmaptc
>0 && !(usedtc
&(1<<(maxtc
-reserveshadowmaptc
))) && strstr(ps
, "OPTION ARB_fog_linear;"))
702 emufogcoord
= strstr(vs
, "result.fogcoord");
703 if(!emufogcoord
|| !findunusedtexcoordcomponent(vs
, emufogtc
, emufogcomp
)) return;
704 smtc
= maxtc
-reserveshadowmaptc
;
709 char *vspragma
= strstr(vs
, "#pragma CUBE2_shadowmap"), *pspragma
= strstr(ps
, "#pragma CUBE2_shadowmap");
711 vspragma
+= strcspn(vspragma
, "\n");
712 if(*vspragma
) vspragma
++;
714 if(sscanf(pspragma
, "#pragma CUBE2_shadowmap %s", pslight
)!=1) return;
716 pspragma
+= strcspn(pspragma
, "\n");
717 if(*pspragma
) pspragma
++;
719 vector
<char> vssm
, pssm
;
721 if(s
.type
& SHADER_GLSLANG
)
723 const char *tc
= "varying vec3 shadowmaptc;\n";
724 vssm
.put(tc
, strlen(tc
));
725 pssm
.put(tc
, strlen(tc
));
727 "uniform sampler2D shadowmap;\n"
728 "uniform vec4 shadowmapambient;\n";
729 pssm
.put(smtex
, strlen(smtex
));
730 if(!strstr(ps
, "ambient"))
732 const char *amb
= "uniform vec4 ambient;\n";
733 pssm
.put(amb
, strlen(amb
));
737 EMUFOGVS(emufogcoord
&& emufogcoord
< vspragma
, vssm
, vs
, vspragma
, emufogcoord
, emufogtc
, emufogcomp
);
738 pssm
.put(ps
, pspragma
-ps
);
740 if(s
.type
& SHADER_GLSLANG
)
743 "shadowmaptc = vec3(gl_TextureMatrix[2] * gl_Vertex);\n";
744 vssm
.put(tc
, strlen(tc
));
746 "vec3 smvals = texture2D(shadowmap, shadowmaptc.xy).xyz;\n"
747 "vec2 smdiff = shadowmaptc.zz*smvals.y + smvals.xz;\n"
748 "float shadowed = smdiff.x > 0.0 && smdiff.y < 0.0 ? smvals.y : 0.0;\n";
749 pssm
.put(sm
, strlen(sm
));
751 "%s.rgb = mix(%s.rgb, min(%s.rgb, shadowmapambient.rgb), shadowed);\n",
752 pslight
, pslight
, pslight
);
753 pssm
.put(smlight
, strlen(smlight
));
758 "DP4 result.texcoord[%d].x, state.matrix.texture[2].row[0], vertex.position;\n"
759 "DP4 result.texcoord[%d].y, state.matrix.texture[2].row[1], vertex.position;\n"
760 "DP4 result.texcoord[%d].z, state.matrix.texture[2].row[2], vertex.position;\n",
762 vssm
.put(tc
, strlen(tc
));
765 "TEMP smvals, shadowed, smambient;\n"
766 "TEX smvals, fragment.texcoord[%d], texture[7], 2D;\n"
767 "MAD smvals.xz, fragment.texcoord[%d].z, smvals.y, smvals;\n",
769 pssm
.put(sm
, strlen(sm
));
771 "CMP shadowed, -smvals.x, smvals.y, 0;\n"
772 "CMP shadowed, smvals.z, shadowed, 0;\n"
773 "MIN smambient.rgb, program.env[7], %s;\n"
774 "LRP %s.rgb, shadowed, smambient, %s;\n",
775 pslight
, pslight
, pslight
);
776 pssm
.put(sm
, strlen(sm
));
779 EMUFOGVS(emufogcoord
&& emufogcoord
>= vspragma
, vssm
, vspragma
, vspragma
+strlen(vspragma
)+1, emufogcoord
, emufogtc
, emufogcomp
);
780 pssm
.put(pspragma
, strlen(pspragma
)+1);
782 EMUFOGPS(emufogcoord
, pssm
, emufogtc
, emufogcomp
);
784 s_sprintfd(name
)("<shadowmap>%s", sname
);
785 Shader
*variant
= newshader(s
.type
, name
, vssm
.getbuf(), pssm
.getbuf(), &s
, row
);
788 if(strstr(vs
, "#pragma CUBE2_dynlight")) gendynlightvariant(s
, name
, vssm
.getbuf(), pssm
.getbuf(), row
);
791 static void genwatervariant(Shader
&s
, char *sname
, char *vs
, char *ps
, int row
= 2)
793 char *pspragma
= strstr(ps
, "#pragma CUBE2_water");
794 pspragma
+= strcspn(pspragma
, "\n");
795 if(*pspragma
) pspragma
++;
798 psw
.put(ps
, pspragma
-ps
);
799 const char *fogtoalpha
= s
.type
& SHADER_GLSLANG
? "gl_FragColor.a = gl_FogFragCoord*0.25 + 0.5;\n" : "MAD result.color.a, fragment.fogcoord.x, 0.25, 0.5;\n";
800 psw
.put(fogtoalpha
, strlen(fogtoalpha
));
801 psw
.put(pspragma
, strlen(pspragma
)+1);
803 s_sprintfd(name
)("<water>%s", sname
);
804 Shader
*variant
= newshader(s
.type
, name
, vs
, psw
.getbuf(), &s
, row
);
807 if(strstr(vs
, "#pragma CUBE2_shadowmap")) genshadowmapvariant(s
, name
, vs
, psw
.getbuf(), row
+1);
808 if(strstr(vs
, "#pragma CUBE2_dynlight")) gendynlightvariant(s
, name
, vs
, psw
.getbuf(), row
);
811 void shader(int *type
, char *name
, char *vs
, char *ps
)
813 if(lookupshaderbyname(name
)) return;
815 if(renderpath
!=R_FIXEDFUNCTION
)
817 if((renderpath
!=R_GLSLANG
&& *type
& SHADER_GLSLANG
) ||
818 (!hasCM
&& strstr(ps
, *type
& SHADER_GLSLANG
? "textureCube" : "CUBE")) ||
819 (!hasTR
&& strstr(ps
, *type
& SHADER_GLSLANG
? "texture2DRect" : "RECT")))
823 if(curparams
[i
].name
) delete[] curparams
[i
].name
;
825 curparams
.setsize(0);
828 s_sprintfd(info
)("shader %s", name
);
829 show_out_of_renderloop_progress(0.0, info
);
831 Shader
*s
= newshader(*type
, name
, vs
, ps
);
832 if(s
&& renderpath
!=R_FIXEDFUNCTION
)
834 // '#' is a comment in vertex/fragment programs, while '#pragma' allows an escape for GLSL, so can handle both at once
835 if(strstr(ps
, "#pragma CUBE2_water")) genwatervariant(*s
, s
->name
, vs
, ps
);
836 if(strstr(vs
, "#pragma CUBE2_shadowmap")) genshadowmapvariant(*s
, s
->name
, vs
, ps
);
837 if(strstr(vs
, "#pragma CUBE2_dynlight")) gendynlightvariant(*s
, s
->name
, vs
, ps
);
839 curparams
.setsize(0);
842 void setshader(char *name
)
844 Shader
*s
= lookupshaderbyname(name
);
847 if(renderpath
!=R_FIXEDFUNCTION
) conoutf("no such shader: %s", name
);
852 if(curparams
[i
].name
) delete[] curparams
[i
].name
;
854 curparams
.setsize(0);
857 ShaderParam
*findshaderparam(Slot
&s
, const char *name
, int type
, int index
)
859 if(!s
.shader
) return NULL
;
862 ShaderParam
¶m
= s
.params
[i
];
863 if((name
&& param
.name
&& !strcmp(name
, param
.name
)) || (param
.type
==type
&& param
.index
==index
)) return ¶m
;
865 loopv(s
.shader
->defaultparams
)
867 ShaderParam
¶m
= s
.shader
->defaultparams
[i
];
868 if((name
&& param
.name
&& !strcmp(name
, param
.name
)) || (param
.type
==type
&& param
.index
==index
)) return ¶m
;
873 void setslotshader(Slot
&s
)
875 s
.shader
= curshader
? curshader
: defaultshader
;
876 if(!s
.shader
) return;
879 ShaderParam
¶m
= curparams
[i
], *defaultparam
= findshaderparam(s
, param
.name
, param
.type
, param
.index
);
880 if(!defaultparam
|| !memcmp(param
.val
, defaultparam
->val
, sizeof(param
.val
))) continue;
881 ShaderParam
&override
= s
.params
.add(param
);
882 override
.name
= defaultparam
->name
;
883 if(s
.shader
->type
&SHADER_GLSLANG
) override
.index
= (LocalShaderParamState
*)defaultparam
- &s
.shader
->defaultparams
[0];
887 VAR(nativeshaders
, 0, 1, 1);
889 void altshader(char *origname
, char *altname
)
891 Shader
*alt
= lookupshaderbyname(altname
);
893 Shader
*orig
= lookupshaderbyname(origname
);
896 if(nativeshaders
&& !orig
->native
) orig
->altshader
= alt
;
899 char *rname
= newstring(origname
);
900 Shader
&s
= shaders
[rname
];
905 void fastshader(char *nice
, char *fast
, int *detail
)
907 Shader
*ns
= shaders
.access(nice
);
908 if(!ns
|| ns
->altshader
) return;
909 Shader
*fs
= lookupshaderbyname(fast
);
911 loopi(min(*detail
+1, MAXSHADERDETAIL
)) ns
->fastshader
[i
] = fs
;
914 COMMAND(shader
, "isss");
915 COMMAND(setshader
, "s");
916 COMMAND(altshader
, "ss");
917 COMMAND(fastshader
, "ssi");
919 void isshaderdefined(char *name
)
921 Shader
*s
= lookupshaderbyname(name
);
925 void isshadernative(char *name
)
927 Shader
*s
= lookupshaderbyname(name
);
928 intret(s
&& s
->native
? 1 : 0);
931 COMMAND(isshaderdefined
, "s");
932 COMMAND(isshadernative
, "s");
934 void setshaderparam(char *name
, int type
, int n
, float x
, float y
, float z
, float w
)
936 if(!name
&& (n
<0 || n
>=MAXSHADERPARAMS
))
938 conoutf("shader param index must be 0..%d\n", MAXSHADERPARAMS
-1);
943 ShaderParam
¶m
= curparams
[i
];
944 if(param
.type
== type
&& (name
? !strstr(param
.name
, name
) : param
.index
== n
))
953 ShaderParam param
= {name
? newstring(name
) : NULL
, type
, n
, -1, {x
, y
, z
, w
}};
954 curparams
.add(param
);
957 void setvertexparam(int *n
, float *x
, float *y
, float *z
, float *w
)
959 setshaderparam(NULL
, SHPARAM_VERTEX
, *n
, *x
, *y
, *z
, *w
);
962 void setpixelparam(int *n
, float *x
, float *y
, float *z
, float *w
)
964 setshaderparam(NULL
, SHPARAM_PIXEL
, *n
, *x
, *y
, *z
, *w
);
967 void setuniformparam(char *name
, float *x
, float *y
, float *z
, float *w
)
969 setshaderparam(name
, SHPARAM_UNIFORM
, -1, *x
, *y
, *z
, *w
);
972 COMMAND(setvertexparam
, "iffff");
973 COMMAND(setpixelparam
, "iffff");
974 COMMAND(setuniformparam
, "sffff");
976 const int NUMSCALE
= 7;
977 Shader
*fsshader
= NULL
, *scaleshader
= NULL
, *initshader
= NULL
;
978 GLuint rendertarget
[NUMSCALE
];
979 GLuint fsfb
[NUMSCALE
-1];
981 int fs_w
= 0, fs_h
= 0, fspasses
= NUMSCALE
, fsskip
= 1;
983 void setfullscreenshader(char *name
, int *x
, int *y
, int *z
, int *w
)
991 Shader
*s
= lookupshaderbyname(name
);
992 if(!s
) return conoutf("no such fullscreen shader: %s", name
);
994 s_sprintfd(ssname
)("%s_scale", name
);
995 s_sprintfd(isname
)("%s_init", name
);
996 scaleshader
= lookupshaderbyname(ssname
);
997 initshader
= lookupshaderbyname(isname
);
1002 int len
= strlen(name
);
1003 char c
= name
[--len
];
1006 if(len
>0 && isdigit(name
[--len
]))
1009 fspasses
= name
[len
]-'0';
1011 else fspasses
= c
-'0';
1014 conoutf("now rendering with: %s", name
);
1015 fsparams
[0] = *x
/255.0f
;
1016 fsparams
[1] = *y
/255.0f
;
1017 fsparams
[2] = *z
/255.0f
;
1018 fsparams
[3] = *w
/255.0f
;
1022 COMMAND(setfullscreenshader
, "siiii");
1024 void renderfsquad(int w
, int h
, Shader
*s
)
1027 glViewport(0, 0, w
, h
);
1028 if(s
==scaleshader
|| s
==initshader
)
1034 glTexCoord2i(0, 0); glVertex3f(-1, -1, 0);
1035 glTexCoord2i(w
, 0); glVertex3f( 1, -1, 0);
1036 glTexCoord2i(w
, h
); glVertex3f( 1, 1, 0);
1037 glTexCoord2i(0, h
); glVertex3f(-1, 1, 0);
1041 void renderfullscreenshader(int w
, int h
)
1043 if(!fsshader
|| renderpath
==R_FIXEDFUNCTION
) return;
1045 glDisable(GL_DEPTH_TEST
);
1046 glDepthMask(GL_FALSE
);
1047 glEnable(GL_TEXTURE_RECTANGLE_ARB
);
1049 if(fs_w
!= w
|| fs_h
!= h
)
1053 glGenTextures(NUMSCALE
, rendertarget
);
1054 if(hasFBO
) glGenFramebuffers_(NUMSCALE
-1, fsfb
);
1057 createtexture(rendertarget
[i
], w
>>i
, h
>>i
, NULL
, 3, false, GL_RGB
, GL_TEXTURE_RECTANGLE_ARB
);
1064 glBindFramebuffer_(GL_FRAMEBUFFER_EXT
, fsfb
[i
]);
1065 glFramebufferTexture2D_(GL_FRAMEBUFFER_EXT
, GL_COLOR_ATTACHMENT0_EXT
, GL_TEXTURE_RECTANGLE_ARB
, rendertarget
[i
+1], 0);
1067 glBindFramebuffer_(GL_FRAMEBUFFER_EXT
, 0);
1071 setenvparamfv("fsparams", SHPARAM_PIXEL
, 0, fsparams
);
1072 setenvparamf("millis", SHPARAM_VERTEX
, 1, lastmillis
/1000.0f
, lastmillis
/1000.0f
, lastmillis
/1000.0f
);
1078 glBindTexture(GL_TEXTURE_RECTANGLE_ARB
, rendertarget
[i
*fsskip
]);
1079 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB
, 0, 0, 0, 0, 0, nw
, nh
);
1080 if(i
>=fspasses
-1 || !scaleshader
|| fsfb
[0]) break;
1081 renderfsquad(nw
>>= fsskip
, nh
>>= fsskip
, !i
&& initshader
? initshader
: scaleshader
);
1083 if(scaleshader
&& fsfb
[0])
1087 if(i
) glBindTexture(GL_TEXTURE_RECTANGLE_ARB
, rendertarget
[i
*fsskip
]);
1088 glBindFramebuffer_(GL_FRAMEBUFFER_EXT
, fsfb
[(i
+1)*fsskip
-1]);
1089 renderfsquad(nw
>>= fsskip
, nh
>>= fsskip
, !i
&& initshader
? initshader
: scaleshader
);
1091 glBindFramebuffer_(GL_FRAMEBUFFER_EXT
, 0);
1094 if(scaleshader
) loopi(fspasses
)
1096 glActiveTexture_(GL_TEXTURE0_ARB
+i
);
1097 glEnable(GL_TEXTURE_RECTANGLE_ARB
);
1098 glBindTexture(GL_TEXTURE_RECTANGLE_ARB
, rendertarget
[i
*fsskip
]);
1100 renderfsquad(w
, h
, fsshader
);
1102 if(scaleshader
) loopi(fspasses
)
1104 glActiveTexture_(GL_TEXTURE0_ARB
+i
);
1105 glDisable(GL_TEXTURE_RECTANGLE_ARB
);
1108 glActiveTexture_(GL_TEXTURE0_ARB
);
1109 glDepthMask(GL_TRUE
);
1110 glEnable(GL_DEPTH_TEST
);
1115 GLenum combine
, sources
[3], ops
[3];
1126 #define INVALIDTMU \
1129 { -1, -1, -1, -1 }, \
1130 { 0, { 0, 0, 0, }, { 0, 0, 0 }, 0 }, \
1131 { 0, { 0, 0, 0, }, { 0, 0, 0 }, 0 } \
1138 { GL_MODULATE, { GL_TEXTURE, GL_PREVIOUS_ARB, GL_CONSTANT_ARB }, { GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_ALPHA }, 1 }, \
1139 { GL_MODULATE, { GL_TEXTURE, GL_PREVIOUS_ARB, GL_CONSTANT_ARB }, { GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA }, 1 } \
1156 VAR(maxtmus
, 1, 0, 0);
1158 void parsetmufunc(tmufunc
&f
, const char *s
)
1161 while(*s
) switch(tolower(*s
++))
1163 case 't': f
.sources
[++arg
] = GL_TEXTURE
; f
.ops
[arg
] = GL_SRC_COLOR
; break;
1164 case 'p': f
.sources
[++arg
] = GL_PREVIOUS_ARB
; f
.ops
[arg
] = GL_SRC_COLOR
; break;
1165 case 'k': f
.sources
[++arg
] = GL_CONSTANT_ARB
; f
.ops
[arg
] = GL_SRC_COLOR
; break;
1166 case 'c': f
.sources
[++arg
] = GL_PRIMARY_COLOR_ARB
; f
.ops
[arg
] = GL_SRC_COLOR
; break;
1167 case '~': f
.ops
[arg
] = GL_ONE_MINUS_SRC_COLOR
; break;
1168 case 'a': f
.ops
[arg
] = f
.ops
[arg
]==GL_ONE_MINUS_SRC_COLOR
? GL_ONE_MINUS_SRC_ALPHA
: GL_SRC_ALPHA
; break;
1169 case '=': f
.combine
= GL_REPLACE
; break;
1170 case '*': f
.combine
= GL_MODULATE
; break;
1171 case '+': f
.combine
= GL_ADD
; break;
1172 case '-': f
.combine
= GL_SUBTRACT_ARB
; break;
1174 case '@': f
.combine
= GL_INTERPOLATE_ARB
; break;
1175 case '.': f
.combine
= GL_DOT3_RGB_ARB
; break;
1176 case 'x': while(!isdigit(*s
)) s
++; f
.scale
= *s
++-'0'; break;
1180 void committmufunc(bool rgb
, tmufunc
&dst
, tmufunc
&src
)
1182 if(dst
.combine
!=src
.combine
) glTexEnvi(GL_TEXTURE_ENV
, rgb
? GL_COMBINE_RGB_ARB
: GL_COMBINE_ALPHA_ARB
, src
.combine
);
1185 if(dst
.sources
[i
]!=src
.sources
[i
]) glTexEnvi(GL_TEXTURE_ENV
, (rgb
? GL_SOURCE0_RGB_ARB
: GL_SOURCE0_ALPHA_ARB
)+i
, src
.sources
[i
]);
1186 if(dst
.ops
[i
]!=src
.ops
[i
]) glTexEnvi(GL_TEXTURE_ENV
, (rgb
? GL_OPERAND0_RGB_ARB
: GL_OPERAND0_ALPHA_ARB
)+i
, src
.ops
[i
]);
1188 if(dst
.scale
!=src
.scale
) glTexEnvi(GL_TEXTURE_ENV
, rgb
? GL_RGB_SCALE_ARB
: GL_ALPHA_SCALE
, src
.scale
);
1191 void committmu(int n
, tmu
&f
)
1193 if(renderpath
!=R_FIXEDFUNCTION
|| n
>=maxtmus
) return;
1194 if(tmus
[n
].mode
!=f
.mode
) glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, f
.mode
);
1195 if(memcmp(tmus
[n
].color
, f
.color
, sizeof(f
.color
))) glTexEnvfv(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_COLOR
, f
.color
);
1196 committmufunc(true, tmus
[n
].rgb
, f
.rgb
);
1197 committmufunc(false, tmus
[n
].alpha
, f
.alpha
);
1201 void resettmu(int n
)
1204 f
.mode
= GL_MODULATE
;
1210 void scaletmu(int n
, int rgbscale
, int alphascale
)
1213 if(rgbscale
) f
.rgb
.scale
= rgbscale
;
1214 if(alphascale
) f
.alpha
.scale
= alphascale
;
1218 void colortmu(int n
, float r
, float g
, float b
, float a
)
1228 void setuptmu(int n
, const char *rgbfunc
, const char *alphafunc
)
1230 static tmu init
= INITTMU
;
1233 f
.mode
= GL_COMBINE_ARB
;
1234 if(rgbfunc
) parsetmufunc(f
.rgb
, rgbfunc
);
1235 else f
.rgb
= init
.rgb
;
1236 if(alphafunc
) parsetmufunc(f
.alpha
, alphafunc
);
1237 else f
.alpha
= init
.alpha
;
1242 VAR(nolights
, 1, 0, 0);
1243 VAR(nowater
, 1, 0, 0);
1244 VAR(nomasks
, 1, 0, 0);
1250 glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB
, (GLint
*)&maxtmus
);
1251 maxtmus
= max(1, min(MAXTMUS
, maxtmus
));
1254 glActiveTexture_(GL_TEXTURE0_ARB
+i
);
1257 glActiveTexture_(GL_TEXTURE0_ARB
);
1259 if(renderpath
==R_FIXEDFUNCTION
)
1261 if(maxtmus
<4) caustics
= 0;
1264 nolights
= nowater
= nomasks
= 1;
1265 extern int lightmodels
;