1 /*
2 ===========================================================================
3
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (RTCW MP Source Code).
8
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "tr_local.h"
30
31 // tr_shader.c -- this file deals with the parsing and definition of shaders
32
33 static char *s_shaderText;
34
35 // the shader is parsed into these global variables, then copied into
36 // dynamically allocated memory if it is valid.
37 static shaderStage_t stages[MAX_SHADER_STAGES];
38 static shader_t shader;
39 static texModInfo_t texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS];
40
41 #define FILE_HASH_SIZE 4096
42 static shader_t* hashTable[FILE_HASH_SIZE];
43
44 /*
45 ================
46 return a hash value for the filename
47 ================
48 */
49 #ifdef __GNUCC__
50 #warning TODO: check if long is ok here
51 #endif
generateHashValue(const char * fname)52 static long generateHashValue( const char *fname ) {
53 int i;
54 long hash;
55 char letter;
56
57 hash = 0;
58 i = 0;
59 while ( fname[i] != '\0' ) {
60 letter = tolower( fname[i] );
61 if ( letter == '.' ) {
62 break; // don't include extension
63 }
64 if ( letter == '\\' ) {
65 letter = '/'; // damn path names
66 }
67 if ( letter == PATH_SEP ) {
68 letter = '/'; // damn path names
69 }
70 hash += (long)( letter ) * ( i + 119 );
71 i++;
72 }
73 hash &= ( FILE_HASH_SIZE - 1 );
74 return hash;
75 }
76
R_RemapShader(const char * shaderName,const char * newShaderName,const char * timeOffset)77 void R_RemapShader( const char *shaderName, const char *newShaderName, const char *timeOffset ) {
78 char strippedName[MAX_QPATH];
79 int hash;
80 shader_t *sh, *sh2;
81 qhandle_t h;
82
83 sh = R_FindShaderByName( shaderName );
84 if ( sh == NULL || sh == tr.defaultShader ) {
85 h = RE_RegisterShaderLightMap( shaderName, 0 );
86 sh = R_GetShaderByHandle( h );
87 }
88 if ( sh == NULL || sh == tr.defaultShader ) {
89 ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName );
90 return;
91 }
92
93 sh2 = R_FindShaderByName( newShaderName );
94 if ( sh2 == NULL || sh2 == tr.defaultShader ) {
95 h = RE_RegisterShaderLightMap( newShaderName, 0 );
96 sh2 = R_GetShaderByHandle( h );
97 }
98
99 if ( sh2 == NULL || sh2 == tr.defaultShader ) {
100 ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName );
101 return;
102 }
103
104 // remap all the shaders with the given name
105 // even tho they might have different lightmaps
106 COM_StripExtension( shaderName, strippedName, sizeof( strippedName ) );
107 hash = generateHashValue( strippedName );
108 for ( sh = hashTable[hash]; sh; sh = sh->next ) {
109 if ( Q_stricmp( sh->name, strippedName ) == 0 ) {
110 if ( sh != sh2 ) {
111 sh->remappedShader = sh2;
112 } else {
113 sh->remappedShader = NULL;
114 }
115 }
116 }
117 if ( timeOffset ) {
118 sh2->timeOffset = atof( timeOffset );
119 }
120 }
121
122 /*
123 ===============
124 ParseVector
125 ===============
126 */
ParseVector(char ** text,int count,float * v)127 static qboolean ParseVector( char **text, int count, float *v ) {
128 char *token;
129 int i;
130
131 // FIXME: spaces are currently required after parens, should change parseext...
132 token = COM_ParseExt( text, qfalse );
133 if ( strcmp( token, "(" ) ) {
134 ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
135 return qfalse;
136 }
137
138 for ( i = 0 ; i < count ; i++ ) {
139 token = COM_ParseExt( text, qfalse );
140 if ( !token[0] ) {
141 ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name );
142 return qfalse;
143 }
144 v[i] = atof( token );
145 }
146
147 token = COM_ParseExt( text, qfalse );
148 if ( strcmp( token, ")" ) ) {
149 ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
150 return qfalse;
151 }
152
153 return qtrue;
154 }
155
156
157 /*
158 ===============
159 NameToAFunc
160 ===============
161 */
NameToAFunc(const char * funcname)162 static unsigned NameToAFunc( const char *funcname ) {
163 if ( !Q_stricmp( funcname, "GT0" ) ) {
164 return GLS_ATEST_GT_0;
165 } else if ( !Q_stricmp( funcname, "LT128" ) ) {
166 return GLS_ATEST_LT_80;
167 } else if ( !Q_stricmp( funcname, "GE128" ) ) {
168 return GLS_ATEST_GE_80;
169 }
170
171 ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name );
172 return 0;
173 }
174
175
176 /*
177 ===============
178 NameToSrcBlendMode
179 ===============
180 */
NameToSrcBlendMode(const char * name)181 static int NameToSrcBlendMode( const char *name ) {
182 if ( !Q_stricmp( name, "GL_ONE" ) ) {
183 return GLS_SRCBLEND_ONE;
184 } else if ( !Q_stricmp( name, "GL_ZERO" ) ) {
185 return GLS_SRCBLEND_ZERO;
186 } else if ( !Q_stricmp( name, "GL_DST_COLOR" ) ) {
187 return GLS_SRCBLEND_DST_COLOR;
188 } else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) ) {
189 return GLS_SRCBLEND_ONE_MINUS_DST_COLOR;
190 } else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) {
191 return GLS_SRCBLEND_SRC_ALPHA;
192 } else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) {
193 return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA;
194 } else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) {
195 return GLS_SRCBLEND_DST_ALPHA;
196 } else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) {
197 return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA;
198 } else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) ) {
199 return GLS_SRCBLEND_ALPHA_SATURATE;
200 }
201
202 ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
203 return GLS_SRCBLEND_ONE;
204 }
205
206 /*
207 ===============
208 NameToDstBlendMode
209 ===============
210 */
NameToDstBlendMode(const char * name)211 static int NameToDstBlendMode( const char *name ) {
212 if ( !Q_stricmp( name, "GL_ONE" ) ) {
213 return GLS_DSTBLEND_ONE;
214 } else if ( !Q_stricmp( name, "GL_ZERO" ) ) {
215 return GLS_DSTBLEND_ZERO;
216 } else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) ) {
217 return GLS_DSTBLEND_SRC_ALPHA;
218 } else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) ) {
219 return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
220 } else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) ) {
221 return GLS_DSTBLEND_DST_ALPHA;
222 } else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) ) {
223 return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA;
224 } else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) ) {
225 return GLS_DSTBLEND_SRC_COLOR;
226 } else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) ) {
227 return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR;
228 }
229
230 ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
231 return GLS_DSTBLEND_ONE;
232 }
233
234 /*
235 ===============
236 NameToGenFunc
237 ===============
238 */
NameToGenFunc(const char * funcname)239 static genFunc_t NameToGenFunc( const char *funcname ) {
240 if ( !Q_stricmp( funcname, "sin" ) ) {
241 return GF_SIN;
242 } else if ( !Q_stricmp( funcname, "square" ) ) {
243 return GF_SQUARE;
244 } else if ( !Q_stricmp( funcname, "triangle" ) ) {
245 return GF_TRIANGLE;
246 } else if ( !Q_stricmp( funcname, "sawtooth" ) ) {
247 return GF_SAWTOOTH;
248 } else if ( !Q_stricmp( funcname, "inversesawtooth" ) ) {
249 return GF_INVERSE_SAWTOOTH;
250 } else if ( !Q_stricmp( funcname, "noise" ) ) {
251 return GF_NOISE;
252 }
253
254 ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name );
255 return GF_SIN;
256 }
257
258
259 /*
260 ===================
261 ParseWaveForm
262 ===================
263 */
ParseWaveForm(char ** text,waveForm_t * wave)264 static void ParseWaveForm( char **text, waveForm_t *wave ) {
265 char *token;
266
267 token = COM_ParseExt( text, qfalse );
268 if ( token[0] == 0 ) {
269 ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
270 return;
271 }
272 wave->func = NameToGenFunc( token );
273
274 // BASE, AMP, PHASE, FREQ
275 token = COM_ParseExt( text, qfalse );
276 if ( token[0] == 0 ) {
277 ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
278 return;
279 }
280 wave->base = atof( token );
281
282 token = COM_ParseExt( text, qfalse );
283 if ( token[0] == 0 ) {
284 ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
285 return;
286 }
287 wave->amplitude = atof( token );
288
289 token = COM_ParseExt( text, qfalse );
290 if ( token[0] == 0 ) {
291 ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
292 return;
293 }
294 wave->phase = atof( token );
295
296 token = COM_ParseExt( text, qfalse );
297 if ( token[0] == 0 ) {
298 ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
299 return;
300 }
301 wave->frequency = atof( token );
302 }
303
304
305 /*
306 ===================
307 ParseTexMod
308 ===================
309 */
ParseTexMod(char * _text,shaderStage_t * stage)310 static void ParseTexMod( char *_text, shaderStage_t *stage ) {
311 const char *token;
312 char **text = &_text;
313 texModInfo_t *tmi;
314
315 if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) {
316 ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'", shader.name );
317 return;
318 }
319
320 tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods];
321 stage->bundle[0].numTexMods++;
322
323 token = COM_ParseExt( text, qfalse );
324
325 //
326 // swap
327 //
328 if ( !Q_stricmp( token, "swap" ) ) { // swap S/T coords (rotate 90d)
329 tmi->type = TMOD_SWAP;
330 }
331 //
332 // turb
333 //
334 // (SA) added 'else' so it wouldn't claim 'swap' was unknown.
335 else if ( !Q_stricmp( token, "turb" ) ) {
336 token = COM_ParseExt( text, qfalse );
337 if ( token[0] == 0 ) {
338 ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name );
339 return;
340 }
341 tmi->wave.base = atof( token );
342 token = COM_ParseExt( text, qfalse );
343 if ( token[0] == 0 ) {
344 ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
345 return;
346 }
347 tmi->wave.amplitude = atof( token );
348 token = COM_ParseExt( text, qfalse );
349 if ( token[0] == 0 ) {
350 ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
351 return;
352 }
353 tmi->wave.phase = atof( token );
354 token = COM_ParseExt( text, qfalse );
355 if ( token[0] == 0 ) {
356 ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
357 return;
358 }
359 tmi->wave.frequency = atof( token );
360
361 tmi->type = TMOD_TURBULENT;
362 }
363 //
364 // scale
365 //
366 else if ( !Q_stricmp( token, "scale" ) ) {
367 token = COM_ParseExt( text, qfalse );
368 if ( token[0] == 0 ) {
369 ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
370 return;
371 }
372 tmi->scale[0] = atof( token );
373
374 token = COM_ParseExt( text, qfalse );
375 if ( token[0] == 0 ) {
376 ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
377 return;
378 }
379 tmi->scale[1] = atof( token );
380 tmi->type = TMOD_SCALE;
381 }
382 //
383 // scroll
384 //
385 else if ( !Q_stricmp( token, "scroll" ) ) {
386 token = COM_ParseExt( text, qfalse );
387 if ( token[0] == 0 ) {
388 ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
389 return;
390 }
391 tmi->scroll[0] = atof( token );
392 token = COM_ParseExt( text, qfalse );
393 if ( token[0] == 0 ) {
394 ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
395 return;
396 }
397 tmi->scroll[1] = atof( token );
398 tmi->type = TMOD_SCROLL;
399 }
400 //
401 // stretch
402 //
403 else if ( !Q_stricmp( token, "stretch" ) ) {
404 token = COM_ParseExt( text, qfalse );
405 if ( token[0] == 0 ) {
406 ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
407 return;
408 }
409 tmi->wave.func = NameToGenFunc( token );
410
411 token = COM_ParseExt( text, qfalse );
412 if ( token[0] == 0 ) {
413 ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
414 return;
415 }
416 tmi->wave.base = atof( token );
417
418 token = COM_ParseExt( text, qfalse );
419 if ( token[0] == 0 ) {
420 ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
421 return;
422 }
423 tmi->wave.amplitude = atof( token );
424
425 token = COM_ParseExt( text, qfalse );
426 if ( token[0] == 0 ) {
427 ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
428 return;
429 }
430 tmi->wave.phase = atof( token );
431
432 token = COM_ParseExt( text, qfalse );
433 if ( token[0] == 0 ) {
434 ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
435 return;
436 }
437 tmi->wave.frequency = atof( token );
438
439 tmi->type = TMOD_STRETCH;
440 }
441 //
442 // transform
443 //
444 else if ( !Q_stricmp( token, "transform" ) ) {
445 token = COM_ParseExt( text, qfalse );
446 if ( token[0] == 0 ) {
447 ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
448 return;
449 }
450 tmi->matrix[0][0] = atof( token );
451
452 token = COM_ParseExt( text, qfalse );
453 if ( token[0] == 0 ) {
454 ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
455 return;
456 }
457 tmi->matrix[0][1] = atof( token );
458
459 token = COM_ParseExt( text, qfalse );
460 if ( token[0] == 0 ) {
461 ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
462 return;
463 }
464 tmi->matrix[1][0] = atof( token );
465
466 token = COM_ParseExt( text, qfalse );
467 if ( token[0] == 0 ) {
468 ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
469 return;
470 }
471 tmi->matrix[1][1] = atof( token );
472
473 token = COM_ParseExt( text, qfalse );
474 if ( token[0] == 0 ) {
475 ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
476 return;
477 }
478 tmi->translate[0] = atof( token );
479
480 token = COM_ParseExt( text, qfalse );
481 if ( token[0] == 0 ) {
482 ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
483 return;
484 }
485 tmi->translate[1] = atof( token );
486
487 tmi->type = TMOD_TRANSFORM;
488 }
489 //
490 // rotate
491 //
492 else if ( !Q_stricmp( token, "rotate" ) ) {
493 token = COM_ParseExt( text, qfalse );
494 if ( token[0] == 0 ) {
495 ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name );
496 return;
497 }
498 tmi->rotateSpeed = atof( token );
499 tmi->type = TMOD_ROTATE;
500 }
501 //
502 // entityTranslate
503 //
504 else if ( !Q_stricmp( token, "entityTranslate" ) ) {
505 tmi->type = TMOD_ENTITY_TRANSLATE;
506 } else
507 {
508 ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name );
509 }
510 }
511
512
513 /*
514 ===================
515 ParseStage
516 ===================
517 */
ParseStage(shaderStage_t * stage,char ** text)518 static qboolean ParseStage( shaderStage_t *stage, char **text ) {
519 char *token;
520 int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0;
521 qboolean depthMaskExplicit = qfalse;
522
523 stage->active = qtrue;
524
525 while ( 1 )
526 {
527 token = COM_ParseExt( text, qtrue );
528 if ( !token[0] ) {
529 ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" );
530 return qfalse;
531 }
532
533 if ( token[0] == '}' ) {
534 break;
535 }
536 //
537 // check special case for map16/map32/mapcomp/mapnocomp (compression enabled)
538 if ( !Q_stricmp( token, "map16" ) ) { // only use this texture if 16 bit color depth
539 if ( glConfig.colorBits <= 16 ) {
540 token = "map"; // use this map
541 } else {
542 COM_ParseExt( text, qfalse ); // ignore the map
543 continue;
544 }
545 } else if ( !Q_stricmp( token, "map32" ) ) { // only use this texture if 16 bit color depth
546 if ( glConfig.colorBits > 16 ) {
547 token = "map"; // use this map
548 } else {
549 COM_ParseExt( text, qfalse ); // ignore the map
550 continue;
551 }
552 } else if ( !Q_stricmp( token, "mapcomp" ) ) { // only use this texture if compression is enabled
553 if ( glConfig.textureCompression && r_ext_compressed_textures->integer ) {
554 token = "map"; // use this map
555 } else {
556 COM_ParseExt( text, qfalse ); // ignore the map
557 continue;
558 }
559 } else if ( !Q_stricmp( token, "mapnocomp" ) ) { // only use this texture if compression is not available or disabled
560 if ( !glConfig.textureCompression ) {
561 token = "map"; // use this map
562 } else {
563 COM_ParseExt( text, qfalse ); // ignore the map
564 continue;
565 }
566 } else if ( !Q_stricmp( token, "animmapcomp" ) ) { // only use this texture if compression is enabled
567 if ( glConfig.textureCompression && r_ext_compressed_textures->integer ) {
568 token = "animmap"; // use this map
569 } else {
570 while ( token[0] )
571 COM_ParseExt( text, qfalse ); // ignore the map
572 continue;
573 }
574 } else if ( !Q_stricmp( token, "animmapnocomp" ) ) { // only use this texture if compression is not available or disabled
575 if ( !glConfig.textureCompression ) {
576 token = "animmap"; // use this map
577 } else {
578 while ( token[0] )
579 COM_ParseExt( text, qfalse ); // ignore the map
580 continue;
581 }
582 }
583 //
584 // map <name>
585 //
586 if ( !Q_stricmp( token, "map" ) ) {
587 token = COM_ParseExt( text, qfalse );
588 if ( !token[0] ) {
589 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name );
590 return qfalse;
591 }
592
593 //----(SA) fixes startup error and allows polygon shadows to work again
594 if ( !Q_stricmp( token, "$whiteimage" ) || !Q_stricmp( token, "*white" ) ) {
595 //----(SA) end
596 stage->bundle[0].image[0] = tr.whiteImage;
597 continue;
598 }
599 //----(SA) added
600 else if ( !Q_stricmp( token, "$dlight" ) ) {
601 stage->bundle[0].image[0] = tr.dlightImage;
602 continue;
603 }
604 //----(SA) end
605 else if ( !Q_stricmp( token, "$lightmap" ) ) {
606 stage->bundle[0].isLightmap = qtrue;
607 if ( shader.lightmapIndex < 0 || !tr.lightmaps ) {
608 stage->bundle[0].image[0] = tr.whiteImage;
609 } else {
610 stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
611 }
612 continue;
613 } else
614 {
615 imgType_t type = IMGTYPE_COLORALPHA;
616 imgFlags_t flags = IMGFLAG_NONE;
617
618 if (!shader.noMipMaps)
619 flags |= IMGFLAG_MIPMAP;
620
621 if (!shader.noPicMip)
622 flags |= IMGFLAG_PICMIP;
623
624 stage->bundle[0].image[0] = R_FindImageFile( token, type, flags );
625
626 if ( !stage->bundle[0].image[0] ) {
627 ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
628 return qfalse;
629 }
630 }
631 }
632 //
633 // clampmap <name>
634 //
635 else if ( !Q_stricmp( token, "clampmap" ) ) {
636 imgType_t type = IMGTYPE_COLORALPHA;
637 imgFlags_t flags = IMGFLAG_CLAMPTOEDGE;
638
639 token = COM_ParseExt( text, qfalse );
640 if ( !token[0] ) {
641 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name );
642 return qfalse;
643 }
644
645 if (!shader.noMipMaps)
646 flags |= IMGFLAG_MIPMAP;
647
648 if (!shader.noPicMip)
649 flags |= IMGFLAG_PICMIP;
650
651 stage->bundle[0].image[0] = R_FindImageFile( token, type, flags );
652
653 if ( !stage->bundle[0].image[0] ) {
654 ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
655 return qfalse;
656 }
657 }
658 //
659 // animMap <frequency> <image1> .... <imageN>
660 //
661 else if ( !Q_stricmp( token, "animMap" ) ) {
662 int totalImages = 0;
663
664 token = COM_ParseExt( text, qfalse );
665 if ( !token[0] ) {
666 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMap' keyword in shader '%s'\n", shader.name );
667 return qfalse;
668 }
669 stage->bundle[0].imageAnimationSpeed = atof( token );
670
671 // parse up to MAX_IMAGE_ANIMATIONS animations
672 while ( 1 ) {
673 int num;
674
675 token = COM_ParseExt( text, qfalse );
676 if ( !token[0] ) {
677 break;
678 }
679 num = stage->bundle[0].numImageAnimations;
680 if ( num < MAX_IMAGE_ANIMATIONS ) {
681 imgFlags_t flags = IMGFLAG_NONE;
682
683 if (!shader.noMipMaps)
684 flags |= IMGFLAG_MIPMAP;
685
686 if (!shader.noPicMip)
687 flags |= IMGFLAG_PICMIP;
688
689 stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags );
690
691 if ( !stage->bundle[0].image[num] ) {
692 ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
693 return qfalse;
694 }
695 stage->bundle[0].numImageAnimations++;
696 }
697 totalImages++;
698 }
699
700 if ( totalImages > MAX_IMAGE_ANIMATIONS ) {
701 ri.Printf( PRINT_WARNING, "WARNING: ignoring excess images for 'animMap' (found %d, max is %d) in shader '%s'\n",
702 totalImages, MAX_IMAGE_ANIMATIONS, shader.name );
703 }
704 } else if ( !Q_stricmp( token, "videoMap" ) ) {
705 token = COM_ParseExt( text, qfalse );
706 if ( !token[0] ) {
707 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMap' keyword in shader '%s'\n", shader.name );
708 return qfalse;
709 }
710 stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, ( CIN_loop | CIN_silent | CIN_shader ) );
711 if ( stage->bundle[0].videoMapHandle != -1 ) {
712 stage->bundle[0].isVideoMap = qtrue;
713 stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle];
714 } else {
715 ri.Printf( PRINT_WARNING, "WARNING: could not load '%s' for 'videoMap' keyword in shader '%s'\n", token, shader.name );
716 }
717 }
718 //
719 // alphafunc <func>
720 //
721 else if ( !Q_stricmp( token, "alphaFunc" ) ) {
722 token = COM_ParseExt( text, qfalse );
723 if ( !token[0] ) {
724 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name );
725 return qfalse;
726 }
727
728 atestBits = NameToAFunc( token );
729 }
730 //
731 // depthFunc <func>
732 //
733 else if ( !Q_stricmp( token, "depthfunc" ) ) {
734 token = COM_ParseExt( text, qfalse );
735
736 if ( !token[0] ) {
737 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name );
738 return qfalse;
739 }
740
741 if ( !Q_stricmp( token, "lequal" ) ) {
742 depthFuncBits = 0;
743 } else if ( !Q_stricmp( token, "equal" ) ) {
744 depthFuncBits = GLS_DEPTHFUNC_EQUAL;
745 } else
746 {
747 ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name );
748 continue;
749 }
750 }
751 //
752 // detail
753 //
754 else if ( !Q_stricmp( token, "detail" ) ) {
755 stage->isDetail = qtrue;
756 }
757 //
758 // fog
759 //
760 else if ( !Q_stricmp( token, "fog" ) ) {
761 token = COM_ParseExt( text, qfalse );
762 if ( token[0] == 0 ) {
763 ri.Printf( PRINT_WARNING, "WARNING: missing parm for fog in shader '%s'\n", shader.name );
764 continue;
765 }
766 if ( !Q_stricmp( token, "on" ) ) {
767 stage->isFogged = qtrue;
768 } else {
769 stage->isFogged = qfalse;
770 }
771 }
772 //
773 // blendfunc <srcFactor> <dstFactor>
774 // or blendfunc <add|filter|blend>
775 //
776 else if ( !Q_stricmp( token, "blendfunc" ) ) {
777 token = COM_ParseExt( text, qfalse );
778 if ( token[0] == 0 ) {
779 ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
780 continue;
781 }
782 // check for "simple" blends first
783 if ( !Q_stricmp( token, "add" ) ) {
784 blendSrcBits = GLS_SRCBLEND_ONE;
785 blendDstBits = GLS_DSTBLEND_ONE;
786 } else if ( !Q_stricmp( token, "filter" ) ) {
787 blendSrcBits = GLS_SRCBLEND_DST_COLOR;
788 blendDstBits = GLS_DSTBLEND_ZERO;
789 } else if ( !Q_stricmp( token, "blend" ) ) {
790 blendSrcBits = GLS_SRCBLEND_SRC_ALPHA;
791 blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
792 } else {
793 // complex double blends
794 blendSrcBits = NameToSrcBlendMode( token );
795
796 token = COM_ParseExt( text, qfalse );
797 if ( token[0] == 0 ) {
798 ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
799 continue;
800 }
801 blendDstBits = NameToDstBlendMode( token );
802 }
803
804 // clear depth mask for blended surfaces
805 if ( !depthMaskExplicit ) {
806 depthMaskBits = 0;
807 }
808 }
809 //
810 // rgbGen
811 //
812 else if ( !Q_stricmp( token, "rgbGen" ) ) {
813 token = COM_ParseExt( text, qfalse );
814 if ( token[0] == 0 ) {
815 ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name );
816 continue;
817 }
818
819 if ( !Q_stricmp( token, "wave" ) ) {
820 ParseWaveForm( text, &stage->rgbWave );
821 stage->rgbGen = CGEN_WAVEFORM;
822 } else if ( !Q_stricmp( token, "const" ) ) {
823 vec3_t color;
824
825 VectorClear( color );
826
827 ParseVector( text, 3, color );
828 stage->constantColor[0] = 255 * color[0];
829 stage->constantColor[1] = 255 * color[1];
830 stage->constantColor[2] = 255 * color[2];
831
832 stage->rgbGen = CGEN_CONST;
833 } else if ( !Q_stricmp( token, "identity" ) ) {
834 stage->rgbGen = CGEN_IDENTITY;
835 } else if ( !Q_stricmp( token, "identityLighting" ) ) {
836 stage->rgbGen = CGEN_IDENTITY_LIGHTING;
837 } else if ( !Q_stricmp( token, "entity" ) ) {
838 stage->rgbGen = CGEN_ENTITY;
839 } else if ( !Q_stricmp( token, "oneMinusEntity" ) ) {
840 stage->rgbGen = CGEN_ONE_MINUS_ENTITY;
841 } else if ( !Q_stricmp( token, "vertex" ) ) {
842 stage->rgbGen = CGEN_VERTEX;
843 if ( stage->alphaGen == 0 ) {
844 stage->alphaGen = AGEN_VERTEX;
845 }
846 } else if ( !Q_stricmp( token, "exactVertex" ) ) {
847 stage->rgbGen = CGEN_EXACT_VERTEX;
848 } else if ( !Q_stricmp( token, "lightingDiffuse" ) ) {
849 stage->rgbGen = CGEN_LIGHTING_DIFFUSE;
850 } else if ( !Q_stricmp( token, "oneMinusVertex" ) ) {
851 stage->rgbGen = CGEN_ONE_MINUS_VERTEX;
852 } else
853 {
854 ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name );
855 continue;
856 }
857 }
858 //
859 // alphaGen
860 //
861 else if ( !Q_stricmp( token, "alphaGen" ) ) {
862 token = COM_ParseExt( text, qfalse );
863 if ( token[0] == 0 ) {
864 ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name );
865 continue;
866 }
867
868 if ( !Q_stricmp( token, "wave" ) ) {
869 ParseWaveForm( text, &stage->alphaWave );
870 stage->alphaGen = AGEN_WAVEFORM;
871 } else if ( !Q_stricmp( token, "const" ) ) {
872 token = COM_ParseExt( text, qfalse );
873 stage->constantColor[3] = 255 * atof( token );
874 stage->alphaGen = AGEN_CONST;
875 } else if ( !Q_stricmp( token, "identity" ) ) {
876 stage->alphaGen = AGEN_IDENTITY;
877 } else if ( !Q_stricmp( token, "entity" ) ) {
878 stage->alphaGen = AGEN_ENTITY;
879 } else if ( !Q_stricmp( token, "oneMinusEntity" ) ) {
880 stage->alphaGen = AGEN_ONE_MINUS_ENTITY;
881 }
882 // Ridah
883 else if ( !Q_stricmp( token, "normalzfade" ) ) {
884 stage->alphaGen = AGEN_NORMALZFADE;
885 token = COM_ParseExt( text, qfalse );
886 if ( token[0] ) {
887 stage->constantColor[3] = 255 * atof( token );
888 } else {
889 stage->constantColor[3] = 255;
890 }
891
892 token = COM_ParseExt( text, qfalse );
893 if ( token[0] ) {
894 stage->zFadeBounds[0] = atof( token ); // lower range
895 token = COM_ParseExt( text, qfalse );
896 stage->zFadeBounds[1] = atof( token ); // upper range
897 } else {
898 stage->zFadeBounds[0] = -1.0; // lower range
899 stage->zFadeBounds[1] = 1.0; // upper range
900 }
901
902 }
903 // done.
904 else if ( !Q_stricmp( token, "vertex" ) ) {
905 stage->alphaGen = AGEN_VERTEX;
906 } else if ( !Q_stricmp( token, "lightingSpecular" ) ) {
907 stage->alphaGen = AGEN_LIGHTING_SPECULAR;
908 } else if ( !Q_stricmp( token, "oneMinusVertex" ) ) {
909 stage->alphaGen = AGEN_ONE_MINUS_VERTEX;
910 } else if ( !Q_stricmp( token, "portal" ) ) {
911 stage->alphaGen = AGEN_PORTAL;
912 token = COM_ParseExt( text, qfalse );
913 if ( token[0] == 0 ) {
914 shader.portalRange = 256;
915 ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name );
916 } else
917 {
918 shader.portalRange = atof( token );
919 }
920 } else
921 {
922 ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name );
923 continue;
924 }
925 }
926 //
927 // tcGen <function>
928 //
929 else if ( !Q_stricmp( token, "texgen" ) || !Q_stricmp( token, "tcGen" ) ) {
930 token = COM_ParseExt( text, qfalse );
931 if ( token[0] == 0 ) {
932 ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name );
933 continue;
934 }
935
936 if ( !Q_stricmp( token, "environment" ) ) {
937 stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED;
938 } else if ( !Q_stricmp( token, "firerisenv" ) ) {
939 stage->bundle[0].tcGen = TCGEN_FIRERISEENV_MAPPED;
940 } else if ( !Q_stricmp( token, "lightmap" ) ) {
941 stage->bundle[0].tcGen = TCGEN_LIGHTMAP;
942 } else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) ) {
943 stage->bundle[0].tcGen = TCGEN_TEXTURE;
944 } else if ( !Q_stricmp( token, "vector" ) ) {
945 ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] );
946 ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] );
947
948 stage->bundle[0].tcGen = TCGEN_VECTOR;
949 } else
950 {
951 ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name );
952 }
953 }
954 //
955 // tcMod <type> <...>
956 //
957 else if ( !Q_stricmp( token, "tcMod" ) ) {
958 char buffer[1024] = "";
959
960 while ( 1 )
961 {
962 token = COM_ParseExt( text, qfalse );
963 if ( token[0] == 0 ) {
964 break;
965 }
966 Q_strcat( buffer, sizeof (buffer), token );
967 Q_strcat( buffer, sizeof (buffer), " " );
968 }
969
970 ParseTexMod( buffer, stage );
971
972 continue;
973 }
974 //
975 // depthmask
976 //
977 else if ( !Q_stricmp( token, "depthwrite" ) ) {
978 depthMaskBits = GLS_DEPTHMASK_TRUE;
979 depthMaskExplicit = qtrue;
980
981 continue;
982 } else
983 {
984 ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name );
985 return qfalse;
986 }
987 }
988
989 //
990 // if cgen isn't explicitly specified, use either identity or identitylighting
991 //
992 if ( stage->rgbGen == CGEN_BAD ) {
993 if ( blendSrcBits == 0 ||
994 blendSrcBits == GLS_SRCBLEND_ONE ||
995 blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) {
996 stage->rgbGen = CGEN_IDENTITY_LIGHTING;
997 } else {
998 stage->rgbGen = CGEN_IDENTITY;
999 }
1000 }
1001
1002 // allow crosshairs to be colorized for cg_crosshairHealth
1003 if ( strstr( shader.name, "crosshair" ) && shader.lightmapIndex == LIGHTMAP_2D ) {
1004 if ( stage->rgbGen == CGEN_IDENTITY || stage->rgbGen == CGEN_IDENTITY_LIGHTING ) {
1005 stage->rgbGen = CGEN_VERTEX;
1006 }
1007 }
1008
1009 //
1010 // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending
1011 //
1012 if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) &&
1013 ( blendDstBits == GLS_DSTBLEND_ZERO ) ) {
1014 blendDstBits = blendSrcBits = 0;
1015 depthMaskBits = GLS_DEPTHMASK_TRUE;
1016 }
1017
1018 // decide which agens we can skip
1019 if ( stage->alphaGen == AGEN_IDENTITY ) {
1020 if ( stage->rgbGen == CGEN_IDENTITY
1021 || stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) {
1022 stage->alphaGen = AGEN_SKIP;
1023 }
1024 }
1025
1026 //
1027 // compute state bits
1028 //
1029 stage->stateBits = depthMaskBits |
1030 blendSrcBits | blendDstBits |
1031 atestBits |
1032 depthFuncBits;
1033
1034 return qtrue;
1035 }
1036
1037 /*
1038 ===============
1039 ParseDeform
1040
1041 deformVertexes wave <spread> <waveform> <base> <amplitude> <phase> <frequency>
1042 deformVertexes normal <frequency> <amplitude>
1043 deformVertexes move <vector> <waveform> <base> <amplitude> <phase> <frequency>
1044 deformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed>
1045 deformVertexes projectionShadow
1046 deformVertexes autoSprite
1047 deformVertexes autoSprite2
1048 deformVertexes text[0-7]
1049 ===============
1050 */
ParseDeform(char ** text)1051 static void ParseDeform( char **text ) {
1052 char *token;
1053 deformStage_t *ds;
1054
1055 token = COM_ParseExt( text, qfalse );
1056 if ( token[0] == 0 ) {
1057 ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name );
1058 return;
1059 }
1060
1061 if ( shader.numDeforms == MAX_SHADER_DEFORMS ) {
1062 ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name );
1063 return;
1064 }
1065
1066 ds = &shader.deforms[ shader.numDeforms ];
1067 shader.numDeforms++;
1068
1069 if ( !Q_stricmp( token, "projectionShadow" ) ) {
1070 ds->deformation = DEFORM_PROJECTION_SHADOW;
1071 return;
1072 }
1073
1074 if ( !Q_stricmp( token, "autosprite" ) ) {
1075 ds->deformation = DEFORM_AUTOSPRITE;
1076 return;
1077 }
1078
1079 if ( !Q_stricmp( token, "autosprite2" ) ) {
1080 ds->deformation = DEFORM_AUTOSPRITE2;
1081 return;
1082 }
1083
1084 if ( !Q_stricmpn( token, "text", 4 ) ) {
1085 int n;
1086
1087 n = token[4] - '0';
1088 if ( n < 0 || n > 7 ) {
1089 n = 0;
1090 }
1091 ds->deformation = DEFORM_TEXT0 + n;
1092 return;
1093 }
1094
1095 if ( !Q_stricmp( token, "bulge" ) ) {
1096 token = COM_ParseExt( text, qfalse );
1097 if ( token[0] == 0 ) {
1098 ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
1099 return;
1100 }
1101 ds->bulgeWidth = atof( token );
1102
1103 token = COM_ParseExt( text, qfalse );
1104 if ( token[0] == 0 ) {
1105 ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
1106 return;
1107 }
1108 ds->bulgeHeight = atof( token );
1109
1110 token = COM_ParseExt( text, qfalse );
1111 if ( token[0] == 0 ) {
1112 ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
1113 return;
1114 }
1115 ds->bulgeSpeed = atof( token );
1116
1117 ds->deformation = DEFORM_BULGE;
1118 return;
1119 }
1120
1121 if ( !Q_stricmp( token, "wave" ) ) {
1122 token = COM_ParseExt( text, qfalse );
1123 if ( token[0] == 0 ) {
1124 ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
1125 return;
1126 }
1127
1128 if ( atof( token ) != 0 ) {
1129 ds->deformationSpread = 1.0f / atof( token );
1130 } else
1131 {
1132 ds->deformationSpread = 100.0f;
1133 ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name );
1134 }
1135
1136 ParseWaveForm( text, &ds->deformationWave );
1137 ds->deformation = DEFORM_WAVE;
1138 return;
1139 }
1140
1141 if ( !Q_stricmp( token, "normal" ) ) {
1142 token = COM_ParseExt( text, qfalse );
1143 if ( token[0] == 0 ) {
1144 ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
1145 return;
1146 }
1147 ds->deformationWave.amplitude = atof( token );
1148
1149 token = COM_ParseExt( text, qfalse );
1150 if ( token[0] == 0 ) {
1151 ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
1152 return;
1153 }
1154 ds->deformationWave.frequency = atof( token );
1155
1156 ds->deformation = DEFORM_NORMALS;
1157 return;
1158 }
1159
1160 if ( !Q_stricmp( token, "move" ) ) {
1161 int i;
1162
1163 for ( i = 0 ; i < 3 ; i++ ) {
1164 token = COM_ParseExt( text, qfalse );
1165 if ( token[0] == 0 ) {
1166 ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
1167 return;
1168 }
1169 ds->moveVector[i] = atof( token );
1170 }
1171
1172 ParseWaveForm( text, &ds->deformationWave );
1173 ds->deformation = DEFORM_MOVE;
1174 return;
1175 }
1176
1177 ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name );
1178 }
1179
1180
1181 /*
1182 ===============
1183 ParseSkyParms
1184
1185 skyParms <outerbox> <cloudheight> <innerbox>
1186 ===============
1187 */
ParseSkyParms(char ** text)1188 static void ParseSkyParms( char **text ) {
1189 char *token;
1190 static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
1191 char pathname[MAX_QPATH];
1192 int i;
1193 imgFlags_t imgFlags = IMGFLAG_MIPMAP | IMGFLAG_PICMIP;
1194
1195 // outerbox
1196 token = COM_ParseExt( text, qfalse );
1197 if ( token[0] == 0 ) {
1198 ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
1199 return;
1200 }
1201 if ( strcmp( token, "-" ) ) {
1202 for ( i = 0 ; i < 6 ; i++ ) {
1203 Com_sprintf( pathname, sizeof( pathname ), "%s_%s.tga"
1204 , token, suf[i] );
1205 shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags | IMGFLAG_CLAMPTOEDGE );
1206
1207 if ( !shader.sky.outerbox[i] ) {
1208 shader.sky.outerbox[i] = tr.defaultImage;
1209 }
1210 }
1211 }
1212
1213 // cloudheight
1214 token = COM_ParseExt( text, qfalse );
1215 if ( token[0] == 0 ) {
1216 ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
1217 return;
1218 }
1219 shader.sky.cloudHeight = atof( token );
1220 if ( !shader.sky.cloudHeight ) {
1221 shader.sky.cloudHeight = 512;
1222 }
1223 R_InitSkyTexCoords( shader.sky.cloudHeight );
1224
1225
1226 // innerbox
1227 token = COM_ParseExt( text, qfalse );
1228 if ( token[0] == 0 ) {
1229 ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
1230 return;
1231 }
1232 if ( strcmp( token, "-" ) ) {
1233 for ( i = 0 ; i < 6 ; i++ ) {
1234 Com_sprintf( pathname, sizeof( pathname ), "%s_%s.tga"
1235 , token, suf[i] );
1236 shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags );
1237
1238 if ( !shader.sky.innerbox[i] ) {
1239 shader.sky.innerbox[i] = tr.defaultImage;
1240 }
1241 }
1242 }
1243
1244 shader.isSky = qtrue;
1245 }
1246
1247
1248 /*
1249 =================
1250 ParseSort
1251 =================
1252 */
ParseSort(char ** text)1253 void ParseSort( char **text ) {
1254 char *token;
1255
1256 token = COM_ParseExt( text, qfalse );
1257 if ( token[0] == 0 ) {
1258 ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name );
1259 return;
1260 }
1261
1262 if ( !Q_stricmp( token, "portal" ) ) {
1263 shader.sort = SS_PORTAL;
1264 } else if ( !Q_stricmp( token, "sky" ) ) {
1265 shader.sort = SS_ENVIRONMENT;
1266 } else if ( !Q_stricmp( token, "opaque" ) ) {
1267 shader.sort = SS_OPAQUE;
1268 } else if ( !Q_stricmp( token, "decal" ) ) {
1269 shader.sort = SS_DECAL;
1270 } else if ( !Q_stricmp( token, "seeThrough" ) ) {
1271 shader.sort = SS_SEE_THROUGH;
1272 } else if ( !Q_stricmp( token, "banner" ) ) {
1273 shader.sort = SS_BANNER;
1274 } else if ( !Q_stricmp( token, "additive" ) ) {
1275 shader.sort = SS_BLEND1;
1276 } else if ( !Q_stricmp( token, "nearest" ) ) {
1277 shader.sort = SS_NEAREST;
1278 } else if ( !Q_stricmp( token, "underwater" ) ) {
1279 shader.sort = SS_UNDERWATER;
1280 } else {
1281 shader.sort = atof( token );
1282 }
1283 }
1284
1285
1286
1287 // this table is also present in q3map
1288
1289 typedef struct {
1290 char *name;
1291 int clearSolid, surfaceFlags, contents;
1292 } infoParm_t;
1293
1294 infoParm_t infoParms[] = {
1295 // server relevant contents
1296
1297 //----(SA) modified
1298 {"clipmissile", 1, 0, CONTENTS_MISSILECLIP}, // impact only specific weapons (rl, gl)
1299 //----(SA) end
1300
1301 {"water", 1, 0, CONTENTS_WATER },
1302 {"slag", 1, 0, CONTENTS_SLIME }, // uses the CONTENTS_SLIME flag, but the shader reference is changed to 'slag'
1303 // to idendify that this doesn't work the same as 'slime' did.
1304 // (slime hurts instantly, slag doesn't)
1305 // {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging
1306 {"lava", 1, 0, CONTENTS_LAVA }, // very damaging
1307 {"playerclip", 1, 0, CONTENTS_PLAYERCLIP },
1308 {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP },
1309 {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc)
1310 {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag
1311
1312 // utility relevant attributes
1313 {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes
1314 {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces
1315 {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp
1316 {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas
1317 {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas
1318 {"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots
1319 {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots
1320
1321 // Rafael - nopass
1322 {"donotenterlarge", 1, 0, CONTENTS_DONOTENTER_LARGE }, // for larger bots
1323
1324 {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering
1325 {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map
1326 {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it
1327 {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis
1328 {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter
1329
1330 // server attributes
1331 {"slick", 0, SURF_SLICK, 0 },
1332 {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks
1333 {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode
1334 {"ladder", 0, SURF_LADDER, 0 },
1335 {"nodamage", 0, SURF_NODAMAGE, 0 },
1336
1337 {"monsterslick", 0, SURF_MONSTERSLICK, 0}, // surf only slick for monsters
1338
1339 // {"flesh", 0, SURF_FLESH, 0 },
1340 {"glass", 0, SURF_GLASS, 0 }, //----(SA) added
1341 {"ceramic", 0, SURF_CERAMIC, 0 }, //----(SA) added
1342
1343 // steps
1344 {"metal", 0, SURF_METAL, 0 },
1345 {"metalsteps", 0, SURF_METAL, 0 }, // retain bw compatibility with Q3A metal shaders... (SA)
1346 {"nosteps", 0, SURF_NOSTEPS, 0 },
1347 {"woodsteps", 0, SURF_WOOD, 0 },
1348 {"grasssteps", 0, SURF_GRASS, 0 },
1349 {"gravelsteps", 0, SURF_GRAVEL, 0 },
1350 {"carpetsteps", 0, SURF_CARPET, 0 },
1351 {"snowsteps", 0, SURF_SNOW, 0 },
1352 {"roofsteps", 0, SURF_ROOF, 0 }, // tile roof
1353
1354 {"rubble", 0, SURF_RUBBLE, 0 },
1355
1356 // drawsurf attributes
1357 {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap)
1358 {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes
1359 {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap
1360 {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights
1361
1362 {"monsterslicknorth", 0, SURF_MONSLICK_N,0},
1363 {"monsterslickeast", 0, SURF_MONSLICK_E,0},
1364 {"monsterslicksouth", 0, SURF_MONSLICK_S,0},
1365 {"monsterslickwest", 0, SURF_MONSLICK_W,0}
1366
1367 };
1368
1369
1370 /*
1371 ===============
1372 ParseSurfaceParm
1373
1374 surfaceparm <name>
1375 ===============
1376 */
ParseSurfaceParm(char ** text)1377 static void ParseSurfaceParm( char **text ) {
1378 char *token;
1379 int numInfoParms = ARRAY_LEN( infoParms );
1380 int i;
1381
1382 token = COM_ParseExt( text, qfalse );
1383 for ( i = 0 ; i < numInfoParms ; i++ ) {
1384 if ( !Q_stricmp( token, infoParms[i].name ) ) {
1385 shader.surfaceFlags |= infoParms[i].surfaceFlags;
1386 shader.contentFlags |= infoParms[i].contents;
1387 #if 0
1388 if ( infoParms[i].clearSolid ) {
1389 si->contents &= ~CONTENTS_SOLID;
1390 }
1391 #endif
1392 break;
1393 }
1394 }
1395 }
1396
1397 /*
1398 =================
1399 ParseShader
1400
1401 The current text pointer is at the explicit text definition of the
1402 shader. Parse it into the global shader variable. Later functions
1403 will optimize it.
1404 =================
1405 */
ParseShader(char ** text)1406 static qboolean ParseShader( char **text ) {
1407 char *token;
1408 int s;
1409
1410 s = 0;
1411
1412 token = COM_ParseExt( text, qtrue );
1413 if ( token[0] != '{' ) {
1414 ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name );
1415 return qfalse;
1416 }
1417
1418 while ( 1 )
1419 {
1420 token = COM_ParseExt( text, qtrue );
1421 if ( !token[0] ) {
1422 ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name );
1423 return qfalse;
1424 }
1425
1426 // end of shader definition
1427 if ( token[0] == '}' ) {
1428 break;
1429 }
1430 // stage definition
1431 else if ( token[0] == '{' ) {
1432 if ( s >= MAX_SHADER_STAGES ) {
1433 ri.Printf( PRINT_WARNING, "WARNING: too many stages in shader %s (max is %i)\n", shader.name, MAX_SHADER_STAGES );
1434 return qfalse;
1435 }
1436
1437 if ( !ParseStage( &stages[s], text ) ) {
1438 return qfalse;
1439 }
1440 stages[s].active = qtrue;
1441 s++;
1442 continue;
1443 }
1444 // skip stuff that only the QuakeEdRadient needs
1445 else if ( !Q_stricmpn( token, "qer", 3 ) ) {
1446 SkipRestOfLine( text );
1447 continue;
1448 }
1449 // sun parms
1450 else if ( !Q_stricmp( token, "q3map_sun" ) || !Q_stricmp( token, "q3map_sunExt" ) ) {
1451 float a, b;
1452
1453 token = COM_ParseExt( text, qfalse );
1454 tr.sunLight[0] = atof( token );
1455 token = COM_ParseExt( text, qfalse );
1456 tr.sunLight[1] = atof( token );
1457 token = COM_ParseExt( text, qfalse );
1458 tr.sunLight[2] = atof( token );
1459
1460 VectorNormalize( tr.sunLight );
1461
1462 token = COM_ParseExt( text, qfalse );
1463 a = atof( token );
1464 VectorScale( tr.sunLight, a, tr.sunLight );
1465
1466 token = COM_ParseExt( text, qfalse );
1467 a = atof( token );
1468 a = a / 180 * M_PI;
1469
1470 token = COM_ParseExt( text, qfalse );
1471 b = atof( token );
1472 b = b / 180 * M_PI;
1473
1474 tr.sunDirection[0] = cos( a ) * cos( b );
1475 tr.sunDirection[1] = sin( a ) * cos( b );
1476 tr.sunDirection[2] = sin( b );
1477
1478 SkipRestOfLine( text );
1479 continue;
1480 } else if ( !Q_stricmp( token, "deformVertexes" ) ) {
1481 ParseDeform( text );
1482 continue;
1483 } else if ( !Q_stricmp( token, "tesssize" ) ) {
1484 SkipRestOfLine( text );
1485 continue;
1486 } else if ( !Q_stricmp( token, "clampTime" ) ) {
1487 token = COM_ParseExt( text, qfalse );
1488 if ( token[0] ) {
1489 shader.clampTime = atof( token );
1490 }
1491 }
1492 // skip stuff that only the q3map needs
1493 else if ( !Q_stricmpn( token, "q3map", 5 ) ) {
1494 SkipRestOfLine( text );
1495 continue;
1496 }
1497 // skip stuff that only q3map or the server needs
1498 else if ( !Q_stricmp( token, "surfaceParm" ) ) {
1499 ParseSurfaceParm( text );
1500 continue;
1501 }
1502 // no mip maps
1503 else if ( ( !Q_stricmp( token, "nomipmaps" ) ) || ( !Q_stricmp( token,"nomipmap" ) ) ) {
1504 shader.noMipMaps = qtrue;
1505 shader.noPicMip = qtrue;
1506 continue;
1507 }
1508 // no picmip adjustment
1509 else if ( !Q_stricmp( token, "nopicmip" ) ) {
1510 shader.noPicMip = qtrue;
1511 continue;
1512 }
1513 // polygonOffset
1514 else if ( !Q_stricmp( token, "polygonOffset" ) ) {
1515 shader.polygonOffset = qtrue;
1516 continue;
1517 }
1518 // entityMergable, allowing sprite surfaces from multiple entities
1519 // to be merged into one batch. This is a savings for smoke
1520 // puffs and blood, but can't be used for anything where the
1521 // shader calcs (not the surface function) reference the entity color or scroll
1522 else if ( !Q_stricmp( token, "entityMergable" ) ) {
1523 shader.entityMergable = qtrue;
1524 continue;
1525 }
1526 // fogParms
1527 else if ( !Q_stricmp( token, "fogParms" ) ) {
1528 if ( !ParseVector( text, 3, shader.fogParms.color ) ) {
1529 return qfalse;
1530 }
1531
1532 if ( r_greyscale->integer )
1533 {
1534 float luminance;
1535
1536 luminance = LUMA( shader.fogParms.color[0], shader.fogParms.color[1], shader.fogParms.color[2] );
1537 VectorSet( shader.fogParms.color, luminance, luminance, luminance );
1538 }
1539 else if ( r_greyscale->value )
1540 {
1541 float luminance;
1542
1543 luminance = LUMA( shader.fogParms.color[0], shader.fogParms.color[1], shader.fogParms.color[2] );
1544 shader.fogParms.color[0] = LERP( shader.fogParms.color[0], luminance, r_greyscale->value );
1545 shader.fogParms.color[1] = LERP( shader.fogParms.color[1], luminance, r_greyscale->value );
1546 shader.fogParms.color[2] = LERP( shader.fogParms.color[2], luminance, r_greyscale->value );
1547 }
1548
1549 token = COM_ParseExt( text, qfalse );
1550 if ( !token[0] ) {
1551 ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name );
1552 continue;
1553 }
1554 shader.fogParms.depthForOpaque = atof( token );
1555
1556 // skip any old gradient directions
1557 SkipRestOfLine( text );
1558 continue;
1559 }
1560 // portal
1561 else if ( !Q_stricmp( token, "portal" ) ) {
1562 shader.sort = SS_PORTAL;
1563 continue;
1564 }
1565 // skyparms <cloudheight> <outerbox> <innerbox>
1566 else if ( !Q_stricmp( token, "skyparms" ) ) {
1567 ParseSkyParms( text );
1568 continue;
1569 }
1570 // This is fixed fog for the skybox/clouds determined solely by the shader
1571 // it will not change in a level and will not be necessary
1572 // to force clients to use a sky fog the server says to.
1573 // skyfogvars <(r,g,b)> <dist>
1574 else if ( !Q_stricmp( token, "skyfogvars" ) ) {
1575 vec3_t fogColor;
1576
1577 if ( !ParseVector( text, 3, fogColor ) ) {
1578 return qfalse;
1579 }
1580 token = COM_ParseExt( text, qfalse );
1581
1582 if ( !token[0] ) {
1583 ri.Printf( PRINT_WARNING, "WARNING: missing density value for sky fog\n" );
1584 continue;
1585 }
1586
1587 if ( atof( token ) > 1 ) {
1588 ri.Printf( PRINT_WARNING, "WARNING: last value for skyfogvars is 'density' which needs to be 0.0-1.0\n" );
1589 continue;
1590 }
1591
1592 R_SetFog( FOG_SKY, 0, 5, fogColor[0], fogColor[1], fogColor[2], atof( token ) );
1593 continue;
1594 } else if ( !Q_stricmp( token, "sunshader" ) ) {
1595 token = COM_ParseExt( text, qfalse );
1596 if ( !token[0] ) {
1597 ri.Printf( PRINT_WARNING, "WARNING: missing shader name for 'sunshader'\n" );
1598 continue;
1599 }
1600 // tr.sunShaderName = CopyString( token );
1601 tr.sunShaderName = "sun";
1602 }
1603 //----(SA) added
1604 else if ( !Q_stricmp( token, "lightgridmulamb" ) ) { // ambient multiplier for lightgrid
1605 token = COM_ParseExt( text, qfalse );
1606 if ( !token[0] ) {
1607 ri.Printf( PRINT_WARNING, "WARNING: missing value for 'lightgrid ambient multiplier'\n" );
1608 continue;
1609 }
1610 if ( atof( token ) > 0 ) {
1611 tr.lightGridMulAmbient = atof( token );
1612 }
1613 } else if ( !Q_stricmp( token, "lightgridmuldir" ) ) { // directional multiplier for lightgrid
1614 token = COM_ParseExt( text, qfalse );
1615 if ( !token[0] ) {
1616 ri.Printf( PRINT_WARNING, "WARNING: missing value for 'lightgrid directional multiplier'\n" );
1617 continue;
1618 }
1619 if ( atof( token ) > 0 ) {
1620 tr.lightGridMulDirected = atof( token );
1621 }
1622 }
1623 //----(SA) end
1624 else if ( !Q_stricmp( token, "waterfogvars" ) ) {
1625 vec3_t watercolor;
1626 float fogvar;
1627
1628 if ( !ParseVector( text, 3, watercolor ) ) {
1629 return qfalse;
1630 }
1631 token = COM_ParseExt( text, qfalse );
1632
1633 if ( !token[0] ) {
1634 ri.Printf( PRINT_WARNING, "WARNING: missing density/distance value for water fog\n" );
1635 continue;
1636 }
1637
1638 fogvar = atof( token );
1639
1640 //----(SA) right now allow one water color per map. I'm sure this will need
1641 // to change at some point, but I'm not sure how to track fog parameters
1642 // on a "per-water volume" basis yet.
1643
1644 if ( fogvar == 0 ) { // '0' specifies "use the map values for everything except the fog color
1645 // TODO
1646 } else if ( fogvar > 1 ) { // distance "linear" fog
1647 R_SetFog( FOG_WATER, 0, fogvar, watercolor[0], watercolor[1], watercolor[2], 1.1 );
1648 } else { // density "exp" fog
1649 R_SetFog( FOG_WATER, 0, 5, watercolor[0], watercolor[1], watercolor[2], fogvar );
1650 }
1651
1652 continue;
1653 }
1654 // fogvars
1655 else if ( !Q_stricmp( token, "fogvars" ) ) {
1656 vec3_t fogColor;
1657 float fogDensity;
1658 int fogFar;
1659
1660 if ( !ParseVector( text, 3, fogColor ) ) {
1661 return qfalse;
1662 }
1663
1664 token = COM_ParseExt( text, qfalse );
1665 if ( !token[0] ) {
1666 ri.Printf( PRINT_WARNING, "WARNING: missing density value for the fog\n" );
1667 continue;
1668 }
1669
1670
1671 //----(SA) NOTE: fogFar > 1 means the shader is setting the farclip, < 1 means setting
1672 // density (so old maps or maps that just need softening fog don't have to care about farclip)
1673
1674 fogDensity = atof( token );
1675 if ( fogDensity > 1 ) { // linear
1676 fogFar = fogDensity;
1677 } else {
1678 fogFar = 5;
1679 }
1680
1681 R_SetFog( FOG_MAP, 0, fogFar, fogColor[0], fogColor[1], fogColor[2], fogDensity );
1682 R_SetFog( FOG_CMD_SWITCHFOG, FOG_MAP, 50, 0, 0, 0, 0 );
1683
1684 continue;
1685 }
1686 // done.
1687 // Ridah, allow disable fog for some shaders
1688 else if ( !Q_stricmp( token, "nofog" ) ) {
1689 shader.noFog = qtrue;
1690 continue;
1691 }
1692 // done.
1693 // RF, allow each shader to permit compression if available
1694 else if ( !Q_stricmp( token, "allowcompress" ) ) {
1695 tr.allowCompress = qtrue;
1696 continue;
1697 } else if ( !Q_stricmp( token, "nocompress" ) ) {
1698 tr.allowCompress = -1;
1699 continue;
1700 }
1701 // done.
1702 // light <value> determines flaring in q3map, not needed here
1703 else if ( !Q_stricmp( token, "light" ) ) {
1704 COM_ParseExt( text, qfalse );
1705 continue;
1706 }
1707 // cull <face>
1708 else if ( !Q_stricmp( token, "cull" ) ) {
1709 token = COM_ParseExt( text, qfalse );
1710 if ( token[0] == 0 ) {
1711 ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name );
1712 continue;
1713 }
1714
1715 if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) ) {
1716 shader.cullType = CT_TWO_SIDED;
1717 } else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) ) {
1718 shader.cullType = CT_BACK_SIDED;
1719 } else
1720 {
1721 ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name );
1722 }
1723 continue;
1724 }
1725 // sort
1726 else if ( !Q_stricmp( token, "sort" ) ) {
1727 ParseSort( text );
1728 continue;
1729 } else
1730 {
1731 ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name );
1732 return qfalse;
1733 }
1734 }
1735
1736 //
1737 // ignore shaders that don't have any stages, unless it is a sky or fog
1738 //
1739 if ( s == 0 && !shader.isSky && !( shader.contentFlags & CONTENTS_FOG ) ) {
1740 return qfalse;
1741 }
1742
1743 shader.explicitlyDefined = qtrue;
1744
1745 return qtrue;
1746 }
1747
1748 /*
1749 ========================================================================================
1750
1751 SHADER OPTIMIZATION AND FOGGING
1752
1753 ========================================================================================
1754 */
1755
1756 /*
1757 ===================
1758 ComputeStageIteratorFunc
1759
1760 See if we can use on of the simple fastpath stage functions,
1761 otherwise set to the generic stage function
1762 ===================
1763 */
ComputeStageIteratorFunc(void)1764 static void ComputeStageIteratorFunc( void ) {
1765 shader.optimalStageIteratorFunc = RB_StageIteratorGeneric;
1766
1767 //
1768 // see if this should go into the sky path
1769 //
1770 if ( shader.isSky ) {
1771 shader.optimalStageIteratorFunc = RB_StageIteratorSky;
1772 return;
1773 }
1774
1775 if ( r_ignoreFastPath->integer ) {
1776 return;
1777 }
1778
1779 //
1780 // see if this can go into the vertex lit fast path
1781 //
1782 if ( shader.numUnfoggedPasses == 1 ) {
1783 if ( stages[0].rgbGen == CGEN_LIGHTING_DIFFUSE ) {
1784 if ( stages[0].alphaGen == AGEN_IDENTITY ) {
1785 if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE ) {
1786 if ( !shader.polygonOffset ) {
1787 if ( !shader.multitextureEnv ) {
1788 if ( !shader.numDeforms ) {
1789 shader.optimalStageIteratorFunc = RB_StageIteratorVertexLitTexture;
1790 return;
1791 }
1792 }
1793 }
1794 }
1795 }
1796 }
1797 }
1798
1799 //
1800 // see if this can go into an optimized LM, multitextured path
1801 //
1802 if ( shader.numUnfoggedPasses == 1 ) {
1803 if ( ( stages[0].rgbGen == CGEN_IDENTITY ) && ( stages[0].alphaGen == AGEN_IDENTITY ) ) {
1804 if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE &&
1805 stages[0].bundle[1].tcGen == TCGEN_LIGHTMAP ) {
1806 if ( !shader.polygonOffset ) {
1807 if ( !shader.numDeforms ) {
1808 if ( shader.multitextureEnv ) {
1809 shader.optimalStageIteratorFunc = RB_StageIteratorLightmappedMultitexture;
1810 }
1811 }
1812 }
1813 }
1814 }
1815 }
1816 }
1817
1818 typedef struct {
1819 int blendA;
1820 int blendB;
1821
1822 int multitextureEnv;
1823 int multitextureBlend;
1824 } collapse_t;
1825
1826 static collapse_t collapse[] = {
1827 { 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
1828 GL_MODULATE, 0 },
1829
1830 { 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
1831 GL_MODULATE, 0 },
1832
1833 { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
1834 GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
1835
1836 { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
1837 GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
1838
1839 { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
1840 GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
1841
1842 { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
1843 GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
1844
1845 { 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
1846 GL_ADD, 0 },
1847
1848 { GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
1849 GL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE },
1850 #if 0
1851 { 0, GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA,
1852 GL_DECAL, 0 },
1853 #endif
1854 { -1 }
1855 };
1856
1857 /*
1858 ================
1859 CollapseMultitexture
1860
1861 Attempt to combine two stages into a single multitexture stage
1862 FIXME: I think modulated add + modulated add collapses incorrectly
1863 =================
1864 */
CollapseMultitexture(void)1865 static qboolean CollapseMultitexture( void ) {
1866 int abits, bbits;
1867 int i;
1868 textureBundle_t tmpBundle;
1869
1870 if ( !qglActiveTextureARB ) {
1871 return qfalse;
1872 }
1873
1874 // make sure both stages are active
1875 if ( !stages[0].active || !stages[1].active ) {
1876 return qfalse;
1877 }
1878
1879 // on voodoo2, don't combine different tmus
1880 if ( glConfig.driverType == GLDRV_VOODOO ) {
1881 if ( stages[0].bundle[0].image[0]->TMU ==
1882 stages[1].bundle[0].image[0]->TMU ) {
1883 return qfalse;
1884 }
1885 }
1886
1887 abits = stages[0].stateBits;
1888 bbits = stages[1].stateBits;
1889
1890 // make sure that both stages have identical state other than blend modes
1891 if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) !=
1892 ( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) {
1893 return qfalse;
1894 }
1895
1896 abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
1897 bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
1898
1899 // search for a valid multitexture blend function
1900 for ( i = 0; collapse[i].blendA != -1 ; i++ ) {
1901 if ( abits == collapse[i].blendA
1902 && bbits == collapse[i].blendB ) {
1903 break;
1904 }
1905 }
1906
1907 // nothing found
1908 if ( collapse[i].blendA == -1 ) {
1909 return qfalse;
1910 }
1911
1912 // GL_ADD is a separate extension
1913 if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) {
1914 return qfalse;
1915 }
1916
1917 // make sure waveforms have identical parameters
1918 if ( ( stages[0].rgbGen != stages[1].rgbGen ) ||
1919 ( stages[0].alphaGen != stages[1].alphaGen ) ) {
1920 return qfalse;
1921 }
1922
1923 // an add collapse can only have identity colors
1924 if ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) {
1925 return qfalse;
1926 }
1927
1928 if ( stages[0].rgbGen == CGEN_WAVEFORM ) {
1929 if ( memcmp( &stages[0].rgbWave,
1930 &stages[1].rgbWave,
1931 sizeof( stages[0].rgbWave ) ) ) {
1932 return qfalse;
1933 }
1934 }
1935 if ( stages[0].alphaGen == AGEN_WAVEFORM ) {
1936 if ( memcmp( &stages[0].alphaWave,
1937 &stages[1].alphaWave,
1938 sizeof( stages[0].alphaWave ) ) ) {
1939 return qfalse;
1940 }
1941 }
1942
1943
1944 // make sure that lightmaps are in bundle 1 for 3dfx
1945 if ( stages[0].bundle[0].isLightmap ) {
1946 tmpBundle = stages[0].bundle[0];
1947 stages[0].bundle[0] = stages[1].bundle[0];
1948 stages[0].bundle[1] = tmpBundle;
1949 } else
1950 {
1951 stages[0].bundle[1] = stages[1].bundle[0];
1952 }
1953
1954 // set the new blend state bits
1955 shader.multitextureEnv = collapse[i].multitextureEnv;
1956 stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
1957 stages[0].stateBits |= collapse[i].multitextureBlend;
1958
1959 //
1960 // move down subsequent shaders
1961 //
1962 memmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) );
1963 memset( &stages[MAX_SHADER_STAGES - 1], 0, sizeof( stages[0] ) );
1964
1965 return qtrue;
1966 }
1967
1968 /*
1969 =============
1970 FixRenderCommandList
1971
1972 Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated
1973 but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces
1974 to be rendered with bad shaders. To fix this, need to go through all render commands and fix
1975 sortedIndex.
1976 ==============
1977 */
FixRenderCommandList(int newShader)1978 static void FixRenderCommandList( int newShader ) {
1979 renderCommandList_t *cmdList = &backEndData->commands;
1980
1981 if ( cmdList ) {
1982 const void *curCmd = cmdList->cmds;
1983
1984 while ( 1 ) {
1985 curCmd = PADP(curCmd, sizeof(void *));
1986
1987 switch ( *(const int *)curCmd ) {
1988 case RC_SET_COLOR:
1989 {
1990 const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd;
1991 curCmd = (const void *)( sc_cmd + 1 );
1992 break;
1993 }
1994 case RC_STRETCH_PIC:
1995 case RC_ROTATED_PIC:
1996 case RC_STRETCH_PIC_GRADIENT:
1997 {
1998 const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd;
1999 curCmd = (const void *)( sp_cmd + 1 );
2000 break;
2001 }
2002 case RC_DRAW_SURFS:
2003 {
2004 int i;
2005 drawSurf_t *drawSurf;
2006 shader_t *shader;
2007 int fogNum;
2008 int entityNum;
2009 int dlightMap;
2010 int sortedIndex;
2011 const drawSurfsCommand_t *ds_cmd = (const drawSurfsCommand_t *)curCmd;
2012
2013 for ( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) {
2014 R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap );
2015 sortedIndex = ( ( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & ( MAX_SHADERS - 1 ) );
2016 if ( sortedIndex >= newShader ) {
2017 sortedIndex++;
2018 drawSurf->sort = ( sortedIndex << QSORT_SHADERNUM_SHIFT ) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
2019 }
2020 }
2021 curCmd = (const void *)( ds_cmd + 1 );
2022 break;
2023 }
2024 case RC_DRAW_BUFFER:
2025 {
2026 const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd;
2027 curCmd = (const void *)( db_cmd + 1 );
2028 break;
2029 }
2030 case RC_SWAP_BUFFERS:
2031 {
2032 const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd;
2033 curCmd = (const void *)( sb_cmd + 1 );
2034 break;
2035 }
2036 case RC_END_OF_LIST:
2037 default:
2038 return;
2039 }
2040 }
2041 }
2042 }
2043
2044 /*
2045 ==============
2046 SortNewShader
2047
2048 Positions the most recently created shader in the tr.sortedShaders[]
2049 array so that the shader->sort key is sorted relative to the other
2050 shaders.
2051
2052 Sets shader->sortedIndex
2053 ==============
2054 */
SortNewShader(void)2055 static void SortNewShader( void ) {
2056 int i;
2057 float sort;
2058 shader_t *newShader;
2059
2060 newShader = tr.shaders[ tr.numShaders - 1 ];
2061 sort = newShader->sort;
2062
2063 for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) {
2064 if ( tr.sortedShaders[ i ]->sort <= sort ) {
2065 break;
2066 }
2067 tr.sortedShaders[i + 1] = tr.sortedShaders[i];
2068 tr.sortedShaders[i + 1]->sortedIndex++;
2069 }
2070
2071 // Arnout: fix rendercommandlist
2072 FixRenderCommandList( i + 1 );
2073
2074 newShader->sortedIndex = i + 1;
2075 tr.sortedShaders[i + 1] = newShader;
2076 }
2077
2078
2079 /*
2080 ====================
2081 GeneratePermanentShader
2082 ====================
2083 */
GeneratePermanentShader(void)2084 static shader_t *GeneratePermanentShader( void ) {
2085 shader_t *newShader;
2086 int i, b;
2087 int size, hash;
2088
2089 if ( tr.numShaders == MAX_SHADERS ) {
2090 ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n" );
2091 return tr.defaultShader;
2092 }
2093
2094 newShader = ri.Hunk_Alloc( sizeof( shader_t ), h_low );
2095
2096 *newShader = shader;
2097
2098 if ( shader.sort <= SS_OPAQUE ) {
2099 newShader->fogPass = FP_EQUAL;
2100 } else if ( shader.contentFlags & CONTENTS_FOG ) {
2101 newShader->fogPass = FP_LE;
2102 }
2103
2104 tr.shaders[ tr.numShaders ] = newShader;
2105 newShader->index = tr.numShaders;
2106
2107 tr.sortedShaders[ tr.numShaders ] = newShader;
2108 newShader->sortedIndex = tr.numShaders;
2109
2110 tr.numShaders++;
2111
2112 for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) {
2113 if ( !stages[i].active ) {
2114 newShader->stages[i] = NULL; // Ridah, make sure it's null
2115 break;
2116 }
2117 newShader->stages[i] = ri.Hunk_Alloc( sizeof( stages[i] ), h_low );
2118 *newShader->stages[i] = stages[i];
2119
2120 for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) {
2121 if ( !newShader->stages[i]->bundle[b].numTexMods ) {
2122 // make sure unalloc'd texMods aren't pointing to some random point in memory
2123 newShader->stages[i]->bundle[b].texMods = NULL;
2124 continue;
2125 }
2126 size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t );
2127 newShader->stages[i]->bundle[b].texMods = ri.Hunk_Alloc( size, h_low );
2128 Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size );
2129 }
2130 }
2131
2132 SortNewShader();
2133
2134 hash = generateHashValue( newShader->name );
2135 newShader->next = hashTable[hash];
2136 hashTable[hash] = newShader;
2137
2138 return newShader;
2139 }
2140
2141 /*
2142 =================
2143 VertexLightingCollapse
2144
2145 If vertex lighting is enabled, only render a single
2146 pass, trying to guess which is the correct one to best aproximate
2147 what it is supposed to look like.
2148 =================
2149 */
VertexLightingCollapse(void)2150 static void VertexLightingCollapse( void ) {
2151 int stage;
2152 shaderStage_t *bestStage;
2153 int bestImageRank;
2154 int rank;
2155
2156 // if we aren't opaque, just use the first pass
2157 if ( shader.sort == SS_OPAQUE ) {
2158
2159 // pick the best texture for the single pass
2160 bestStage = &stages[0];
2161 bestImageRank = -999999;
2162
2163 for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {
2164 shaderStage_t *pStage = &stages[stage];
2165
2166 if ( !pStage->active ) {
2167 break;
2168 }
2169 rank = 0;
2170
2171 if ( pStage->bundle[0].isLightmap ) {
2172 rank -= 100;
2173 }
2174 if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) {
2175 rank -= 5;
2176 }
2177 if ( pStage->bundle[0].numTexMods ) {
2178 rank -= 5;
2179 }
2180 if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) {
2181 rank -= 3;
2182 }
2183
2184 if ( rank > bestImageRank ) {
2185 bestImageRank = rank;
2186 bestStage = pStage;
2187 }
2188 }
2189
2190 stages[0].bundle[0] = bestStage->bundle[0];
2191 stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
2192 stages[0].stateBits |= GLS_DEPTHMASK_TRUE;
2193 if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
2194 stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
2195 } else {
2196 stages[0].rgbGen = CGEN_EXACT_VERTEX;
2197 }
2198 stages[0].alphaGen = AGEN_SKIP;
2199 } else {
2200 // don't use a lightmap (tesla coils)
2201 if ( stages[0].bundle[0].isLightmap ) {
2202 stages[0] = stages[1];
2203 }
2204
2205 // if we were in a cross-fade cgen, hack it to normal
2206 if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) {
2207 stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
2208 }
2209 if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH )
2210 && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) {
2211 stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
2212 }
2213 if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH )
2214 && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) {
2215 stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
2216 }
2217 }
2218
2219 for ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) {
2220 shaderStage_t *pStage = &stages[stage];
2221
2222 if ( !pStage->active ) {
2223 break;
2224 }
2225
2226 memset( pStage, 0, sizeof( *pStage ) );
2227 }
2228 }
2229
2230 /*
2231 ===============
2232 InitShader
2233 ===============
2234 */
InitShader(const char * name,int lightmapIndex)2235 static void InitShader( const char *name, int lightmapIndex ) {
2236 int i;
2237
2238 // clear the global shader
2239 Com_Memset( &shader, 0, sizeof( shader ) );
2240 Com_Memset( &stages, 0, sizeof( stages ) );
2241
2242 Q_strncpyz( shader.name, name, sizeof( shader.name ) );
2243 shader.lightmapIndex = lightmapIndex;
2244
2245 for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
2246 stages[i].bundle[0].texMods = texMods[i];
2247 }
2248 }
2249
2250 /*
2251 =========================
2252 FinishShader
2253
2254 Returns a freshly allocated shader with all the needed info
2255 from the current global working shader
2256 =========================
2257 */
FinishShader(void)2258 static shader_t *FinishShader( void ) {
2259 int stage;
2260 qboolean hasLightmapStage;
2261 qboolean vertexLightmap;
2262
2263 hasLightmapStage = qfalse;
2264 vertexLightmap = qfalse;
2265
2266 //
2267 // set sky stuff appropriate
2268 //
2269 if ( shader.isSky ) {
2270 shader.sort = SS_ENVIRONMENT;
2271 }
2272
2273 //
2274 // set polygon offset
2275 //
2276 if ( shader.polygonOffset && !shader.sort ) {
2277 shader.sort = SS_DECAL;
2278 }
2279
2280 //
2281 // set appropriate stage information
2282 //
2283 for ( stage = 0; stage < MAX_SHADER_STAGES; ) {
2284 shaderStage_t *pStage = &stages[stage];
2285
2286 if ( !pStage->active ) {
2287 break;
2288 }
2289
2290 // check for a missing texture
2291 if ( !pStage->bundle[0].image[0] ) {
2292 ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name );
2293 pStage->active = qfalse;
2294 stage++;
2295 continue;
2296 }
2297
2298 //
2299 // ditch this stage if it's detail and detail textures are disabled
2300 //
2301 if ( pStage->isDetail && !r_detailTextures->integer )
2302 {
2303 int index;
2304
2305 for(index = stage + 1; index < MAX_SHADER_STAGES; index++)
2306 {
2307 if(!stages[index].active)
2308 break;
2309 }
2310
2311 if(index < MAX_SHADER_STAGES)
2312 memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage));
2313 else
2314 {
2315 if(stage + 1 < MAX_SHADER_STAGES)
2316 memmove(pStage, pStage + 1, sizeof(*pStage) * (index - stage - 1));
2317
2318 Com_Memset(&stages[index - 1], 0, sizeof(*stages));
2319 }
2320
2321 continue;
2322 }
2323
2324 //
2325 // default texture coordinate generation
2326 //
2327 if ( pStage->bundle[0].isLightmap ) {
2328 if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
2329 pStage->bundle[0].tcGen = TCGEN_LIGHTMAP;
2330 }
2331 hasLightmapStage = qtrue;
2332 } else {
2333 if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
2334 pStage->bundle[0].tcGen = TCGEN_TEXTURE;
2335 }
2336 }
2337
2338
2339 // not a true lightmap but we want to leave existing
2340 // behaviour in place and not print out a warning
2341 //if (pStage->rgbGen == CGEN_VERTEX) {
2342 // vertexLightmap = qtrue;
2343 //}
2344
2345
2346
2347 //
2348 // determine sort order and fog color adjustment
2349 //
2350 if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) &&
2351 ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) {
2352 int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS;
2353 int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS;
2354
2355 // fog color adjustment only works for blend modes that have a contribution
2356 // that aproaches 0 as the modulate values aproach 0 --
2357 // GL_ONE, GL_ONE
2358 // GL_ZERO, GL_ONE_MINUS_SRC_COLOR
2359 // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
2360
2361 // modulate, additive
2362 if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) ||
2363 ( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) {
2364 pStage->adjustColorsForFog = ACFF_MODULATE_RGB;
2365 }
2366 // strict blend
2367 else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) {
2368 pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA;
2369 }
2370 // premultiplied alpha
2371 else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) ) {
2372 pStage->adjustColorsForFog = ACFF_MODULATE_RGBA;
2373 } else {
2374 // we can't adjust this one correctly, so it won't be exactly correct in fog
2375 }
2376
2377 // don't screw with sort order if this is a portal or environment
2378 if ( !shader.sort ) {
2379 // see through item, like a grill or grate
2380 if ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) {
2381 shader.sort = SS_SEE_THROUGH;
2382 } else {
2383 shader.sort = SS_BLEND0;
2384 }
2385 }
2386 }
2387
2388 stage++;
2389 }
2390
2391 // there are times when you will need to manually apply a sort to
2392 // opaque alpha tested shaders that have later blend passes
2393 if ( !shader.sort ) {
2394 shader.sort = SS_OPAQUE;
2395 }
2396
2397 //
2398 // if we are in r_vertexLight mode, never use a lightmap texture
2399 //
2400 // NERVE - SMF - temp fix, terrain is having problems with lighting collapse
2401 if ( 0 && ( stage > 1 && ( ( r_vertexLight->integer && !r_uiFullScreen->integer ) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) ) {
2402 VertexLightingCollapse();
2403 stage = 1;
2404 hasLightmapStage = qfalse;
2405 }
2406
2407 //
2408 // look for multitexture potential
2409 //
2410 if ( stage > 1 && CollapseMultitexture() ) {
2411 stage--;
2412 }
2413
2414 if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) {
2415 if ( vertexLightmap ) {
2416 ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name );
2417 } else {
2418 ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name );
2419 shader.lightmapIndex = LIGHTMAP_NONE;
2420 }
2421 }
2422
2423
2424 //
2425 // compute number of passes
2426 //
2427 shader.numUnfoggedPasses = stage;
2428
2429 // fogonly shaders don't have any normal passes
2430 if (stage == 0 && !shader.isSky)
2431 shader.sort = SS_FOG;
2432
2433 // determine which stage iterator function is appropriate
2434 ComputeStageIteratorFunc();
2435
2436 // RF default back to no compression for next shader
2437 if ( r_ext_compressed_textures->integer == 2 ) {
2438 tr.allowCompress = qfalse;
2439 }
2440
2441 return GeneratePermanentShader();
2442 }
2443
2444 //========================================================================================
2445
2446 /*
2447 ====================
2448 FindShaderInShaderText
2449
2450 Scans the combined text description of all the shader files for
2451 the given shader name.
2452
2453 return NULL if not found
2454
2455 If found, it will return a valid shader
2456 =====================
2457 */
FindShaderInShaderText(const char * shadername)2458 static char *FindShaderInShaderText( const char *shadername ) {
2459 char *p = s_shaderText;
2460 char *token;
2461
2462 if ( !p ) {
2463 return NULL;
2464 }
2465
2466 // look for label
2467 // note that this could get confused if a shader name is used inside
2468 // another shader definition
2469 while ( 1 ) {
2470 token = COM_ParseExt( &p, qtrue );
2471 if ( token[0] == 0 ) {
2472 break;
2473 }
2474
2475 if ( token[0] == '{' ) {
2476 // skip the definition
2477 SkipBracedSection( &p, 0 );
2478 } else if ( !Q_stricmp( token, shadername ) ) {
2479 return p;
2480 } else {
2481 // skip to end of line
2482 SkipRestOfLine( &p );
2483 }
2484 }
2485
2486 return NULL;
2487 }
2488
2489 /*
2490 ==================
2491 R_FindShaderByName
2492
2493 Will always return a valid shader, but it might be the
2494 default shader if the real one can't be found.
2495 ==================
2496 */
R_FindShaderByName(const char * name)2497 shader_t *R_FindShaderByName( const char *name ) {
2498 char strippedName[MAX_QPATH];
2499 int hash;
2500 shader_t *sh;
2501
2502 if ( ( name == NULL ) || ( name[0] == 0 ) ) {
2503 return tr.defaultShader;
2504 }
2505
2506 COM_StripExtension( name, strippedName, sizeof( strippedName ) );
2507
2508 hash = generateHashValue( strippedName );
2509
2510 //
2511 // see if the shader is already loaded
2512 //
2513 for ( sh = hashTable[hash]; sh; sh = sh->next ) {
2514 // NOTE: if there was no shader or image available with the name strippedName
2515 // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
2516 // have to check all default shaders otherwise for every call to R_FindShader
2517 // with that same strippedName a new default shader is created.
2518 if ( Q_stricmp( sh->name, strippedName ) == 0 ) {
2519 // match found
2520 return sh;
2521 }
2522 }
2523
2524 return tr.defaultShader;
2525 }
2526
2527
2528 /*
2529 ===============
2530 R_FindShader
2531
2532 Will always return a valid shader, but it might be the
2533 default shader if the real one can't be found.
2534
2535 In the interest of not requiring an explicit shader text entry to
2536 be defined for every single image used in the game, three default
2537 shader behaviors can be auto-created for any image:
2538
2539 If lightmapIndex == LIGHTMAP_NONE, then the image will have
2540 dynamic diffuse lighting applied to it, as apropriate for most
2541 entity skin surfaces.
2542
2543 If lightmapIndex == LIGHTMAP_2D, then the image will be used
2544 for 2D rendering unless an explicit shader is found
2545
2546 If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use
2547 the vertex rgba modulate values, as apropriate for misc_model
2548 pre-lit surfaces.
2549
2550 Other lightmapIndex values will have a lightmap stage created
2551 and src*dest blending applied with the texture, as apropriate for
2552 most world construction surfaces.
2553
2554 ===============
2555 */
R_FindShader(const char * name,int lightmapIndex,qboolean mipRawImage)2556 shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) {
2557 char strippedName[MAX_QPATH];
2558 int hash;
2559 char *shaderText;
2560 image_t *image;
2561 shader_t *sh;
2562
2563 if ( name[0] == 0 ) {
2564 return tr.defaultShader;
2565 }
2566
2567 // use (fullbright) vertex lighting if the bsp file doesn't have
2568 // lightmaps
2569 if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) {
2570 lightmapIndex = LIGHTMAP_BY_VERTEX;
2571 } else if ( lightmapIndex < LIGHTMAP_2D ) {
2572 // negative lightmap indexes cause stray pointers (think tr.lightmaps[lightmapIndex])
2573 ri.Printf( PRINT_WARNING, "WARNING: shader '%s' has invalid lightmap index of %d\n", name, lightmapIndex );
2574 lightmapIndex = LIGHTMAP_BY_VERTEX;
2575 }
2576
2577 COM_StripExtension( name, strippedName, sizeof( strippedName ) );
2578
2579 hash = generateHashValue( strippedName );
2580
2581 //
2582 // see if the shader is already loaded
2583 //
2584 for ( sh = hashTable[hash]; sh; sh = sh->next ) {
2585 // NOTE: if there was no shader or image available with the name strippedName
2586 // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
2587 // have to check all default shaders otherwise for every call to R_FindShader
2588 // with that same strippedName a new default shader is created.
2589 if ( ( sh->lightmapIndex == lightmapIndex || sh->defaultShader ) &&
2590 !Q_stricmp( sh->name, strippedName ) ) {
2591 // match found
2592 return sh;
2593 }
2594 }
2595
2596 InitShader( strippedName, lightmapIndex );
2597
2598 // FIXME: set these "need" values apropriately
2599 shader.needsNormal = qtrue;
2600 shader.needsST1 = qtrue;
2601 shader.needsST2 = qtrue;
2602 shader.needsColor = qtrue;
2603
2604 //
2605 // attempt to define shader from an explicit parameter file
2606 //
2607 shaderText = FindShaderInShaderText( strippedName );
2608 if ( shaderText ) {
2609 // enable this when building a pak file to get a global list
2610 // of all explicit shaders
2611 if ( r_printShaders->integer ) {
2612 ri.Printf( PRINT_ALL, "*SHADER* %s\n", name );
2613 }
2614
2615 if ( !ParseShader( &shaderText ) ) {
2616 // had errors, so use default shader
2617 shader.defaultShader = qtrue;
2618 }
2619 sh = FinishShader();
2620 return sh;
2621 }
2622
2623
2624 //
2625 // if not defined in the in-memory shader descriptions,
2626 // look for a single supported image file
2627 //
2628 {
2629 imgFlags_t flags;
2630
2631 flags = IMGFLAG_NONE;
2632
2633 if (mipRawImage)
2634 {
2635 flags |= IMGFLAG_MIPMAP | IMGFLAG_PICMIP;
2636 }
2637 else
2638 {
2639 flags |= IMGFLAG_CLAMPTOEDGE;
2640 }
2641
2642 image = R_FindImageFile( name, IMGTYPE_COLORALPHA, flags );
2643 if ( !image ) {
2644 ri.Printf( PRINT_DEVELOPER, "Couldn't find image file for shader %s\n", name );
2645 shader.defaultShader = qtrue;
2646 return FinishShader();
2647 }
2648 }
2649
2650 //
2651 // create the default shading commands
2652 //
2653 if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
2654 // dynamic colors at vertexes
2655 stages[0].bundle[0].image[0] = image;
2656 stages[0].active = qtrue;
2657 stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
2658 stages[0].stateBits = GLS_DEFAULT;
2659 } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
2660 // explicit colors at vertexes
2661 stages[0].bundle[0].image[0] = image;
2662 stages[0].active = qtrue;
2663 stages[0].rgbGen = CGEN_EXACT_VERTEX;
2664 stages[0].alphaGen = AGEN_SKIP;
2665 stages[0].stateBits = GLS_DEFAULT;
2666 } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
2667 // GUI elements
2668 stages[0].bundle[0].image[0] = image;
2669 stages[0].active = qtrue;
2670 stages[0].rgbGen = CGEN_VERTEX;
2671 stages[0].alphaGen = AGEN_VERTEX;
2672 stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
2673 GLS_SRCBLEND_SRC_ALPHA |
2674 GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
2675 } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
2676 // fullbright level
2677 stages[0].bundle[0].image[0] = tr.whiteImage;
2678 stages[0].active = qtrue;
2679 stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
2680 stages[0].stateBits = GLS_DEFAULT;
2681
2682 stages[1].bundle[0].image[0] = image;
2683 stages[1].active = qtrue;
2684 stages[1].rgbGen = CGEN_IDENTITY;
2685 stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
2686 } else {
2687 // two pass lightmap
2688 stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
2689 stages[0].bundle[0].isLightmap = qtrue;
2690 stages[0].active = qtrue;
2691 stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
2692 // for identitylight
2693 stages[0].stateBits = GLS_DEFAULT;
2694
2695 stages[1].bundle[0].image[0] = image;
2696 stages[1].active = qtrue;
2697 stages[1].rgbGen = CGEN_IDENTITY;
2698 stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
2699 }
2700
2701 return FinishShader();
2702 }
2703
2704
RE_RegisterShaderFromImage(const char * name,int lightmapIndex,image_t * image,qboolean mipRawImage)2705 qhandle_t RE_RegisterShaderFromImage( const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage ) {
2706 int hash;
2707 shader_t *sh;
2708
2709 hash = generateHashValue( name );
2710
2711 // probably not necessary since this function
2712 // only gets called from tr_font.c with lightmapIndex == LIGHTMAP_2D
2713 // but better safe than sorry.
2714 if ( lightmapIndex >= tr.numLightmaps ) {
2715 lightmapIndex = LIGHTMAP_WHITEIMAGE;
2716 }
2717
2718 //
2719 // see if the shader is already loaded
2720 //
2721 for ( sh = hashTable[hash]; sh; sh = sh->next ) {
2722 // NOTE: if there was no shader or image available with the name strippedName
2723 // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
2724 // have to check all default shaders otherwise for every call to R_FindShader
2725 // with that same strippedName a new default shader is created.
2726 if ( ( sh->lightmapIndex == lightmapIndex || sh->defaultShader ) &&
2727 // index by name
2728 !Q_stricmp( sh->name, name ) ) {
2729 // match found
2730 return sh->index;
2731 }
2732 }
2733
2734 InitShader( name, lightmapIndex );
2735
2736 // FIXME: set these "need" values apropriately
2737 shader.needsNormal = qtrue;
2738 shader.needsST1 = qtrue;
2739 shader.needsST2 = qtrue;
2740 shader.needsColor = qtrue;
2741
2742 //
2743 // create the default shading commands
2744 //
2745 if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
2746 // dynamic colors at vertexes
2747 stages[0].bundle[0].image[0] = image;
2748 stages[0].active = qtrue;
2749 stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
2750 stages[0].stateBits = GLS_DEFAULT;
2751 } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
2752 // explicit colors at vertexes
2753 stages[0].bundle[0].image[0] = image;
2754 stages[0].active = qtrue;
2755 stages[0].rgbGen = CGEN_EXACT_VERTEX;
2756 stages[0].alphaGen = AGEN_SKIP;
2757 stages[0].stateBits = GLS_DEFAULT;
2758 } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
2759 // GUI elements
2760 stages[0].bundle[0].image[0] = image;
2761 stages[0].active = qtrue;
2762 stages[0].rgbGen = CGEN_VERTEX;
2763 stages[0].alphaGen = AGEN_VERTEX;
2764 stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
2765 GLS_SRCBLEND_SRC_ALPHA |
2766 GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
2767 } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
2768 // fullbright level
2769 stages[0].bundle[0].image[0] = tr.whiteImage;
2770 stages[0].active = qtrue;
2771 stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
2772 stages[0].stateBits = GLS_DEFAULT;
2773
2774 stages[1].bundle[0].image[0] = image;
2775 stages[1].active = qtrue;
2776 stages[1].rgbGen = CGEN_IDENTITY;
2777 stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
2778 } else {
2779 // two pass lightmap
2780 stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
2781 stages[0].bundle[0].isLightmap = qtrue;
2782 stages[0].active = qtrue;
2783 stages[0].rgbGen = CGEN_IDENTITY; // lightmaps are scaled on creation
2784 // for identitylight
2785 stages[0].stateBits = GLS_DEFAULT;
2786
2787 stages[1].bundle[0].image[0] = image;
2788 stages[1].active = qtrue;
2789 stages[1].rgbGen = CGEN_IDENTITY;
2790 stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
2791 }
2792
2793 sh = FinishShader();
2794 return sh->index;
2795 }
2796
2797
2798 /*
2799 ====================
2800 RE_RegisterShaderLightMap
2801
2802 This is the exported shader entry point for the rest of the system
2803 It will always return an index that will be valid.
2804
2805 This should really only be used for explicit shaders, because there is no
2806 way to ask for different implicit lighting modes (vertex, lightmap, etc)
2807 ====================
2808 */
RE_RegisterShaderLightMap(const char * name,int lightmapIndex)2809 qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) {
2810 shader_t *sh;
2811
2812 if ( strlen( name ) >= MAX_QPATH ) {
2813 ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
2814 return 0;
2815 }
2816
2817 sh = R_FindShader( name, lightmapIndex, qtrue );
2818
2819 // we want to return 0 if the shader failed to
2820 // load for some reason, but R_FindShader should
2821 // still keep a name allocated for it, so if
2822 // something calls RE_RegisterShader again with
2823 // the same name, we don't try looking for it again
2824 if ( sh->defaultShader ) {
2825 return 0;
2826 }
2827
2828 return sh->index;
2829 }
2830
2831
2832 /*
2833 ====================
2834 RE_RegisterShader
2835
2836 This is the exported shader entry point for the rest of the system
2837 It will always return an index that will be valid.
2838
2839 This should really only be used for explicit shaders, because there is no
2840 way to ask for different implicit lighting modes (vertex, lightmap, etc)
2841 ====================
2842 */
RE_RegisterShader(const char * name)2843 qhandle_t RE_RegisterShader( const char *name ) {
2844 shader_t *sh;
2845
2846 if ( strlen( name ) >= MAX_QPATH ) {
2847 ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
2848 return 0;
2849 }
2850
2851 sh = R_FindShader( name, LIGHTMAP_2D, qtrue );
2852
2853 // we want to return 0 if the shader failed to
2854 // load for some reason, but R_FindShader should
2855 // still keep a name allocated for it, so if
2856 // something calls RE_RegisterShader again with
2857 // the same name, we don't try looking for it again
2858 if ( sh->defaultShader ) {
2859 return 0;
2860 }
2861
2862 return sh->index;
2863 }
2864
2865
2866 /*
2867 ====================
2868 RE_RegisterShaderNoMip
2869
2870 For menu graphics that should never be picmiped
2871 ====================
2872 */
RE_RegisterShaderNoMip(const char * name)2873 qhandle_t RE_RegisterShaderNoMip( const char *name ) {
2874 shader_t *sh;
2875
2876 if ( strlen( name ) >= MAX_QPATH ) {
2877 ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
2878 return 0;
2879 }
2880
2881 sh = R_FindShader( name, LIGHTMAP_2D, qfalse );
2882
2883 // we want to return 0 if the shader failed to
2884 // load for some reason, but R_FindShader should
2885 // still keep a name allocated for it, so if
2886 // something calls RE_RegisterShader again with
2887 // the same name, we don't try looking for it again
2888 if ( sh->defaultShader ) {
2889 return 0;
2890 }
2891
2892 return sh->index;
2893 }
2894
2895
2896 /*
2897 ====================
2898 R_GetShaderByHandle
2899
2900 When a handle is passed in by another module, this range checks
2901 it and returns a valid (possibly default) shader_t to be used internally.
2902 ====================
2903 */
R_GetShaderByHandle(qhandle_t hShader)2904 shader_t *R_GetShaderByHandle( qhandle_t hShader ) {
2905 if ( hShader < 0 ) {
2906 ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
2907 return tr.defaultShader;
2908 }
2909 if ( hShader >= tr.numShaders ) {
2910 ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
2911 return tr.defaultShader;
2912 }
2913 return tr.shaders[hShader];
2914 }
2915
2916 /*
2917 ===============
2918 R_ShaderList_f
2919
2920 Dump information on all valid shaders to the console
2921 A second parameter will cause it to print in sorted order
2922 ===============
2923 */
R_ShaderList_f(void)2924 void R_ShaderList_f( void ) {
2925 int i;
2926 int count;
2927 shader_t *shader;
2928
2929 ri.Printf( PRINT_ALL, "-----------------------\n" );
2930
2931 count = 0;
2932 for ( i = 0 ; i < tr.numShaders ; i++ ) {
2933 if ( ri.Cmd_Argc() > 1 ) {
2934 shader = tr.sortedShaders[i];
2935 } else {
2936 shader = tr.shaders[i];
2937 }
2938
2939 ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses );
2940
2941 if ( shader->lightmapIndex >= 0 ) {
2942 ri.Printf( PRINT_ALL, "L " );
2943 } else {
2944 ri.Printf( PRINT_ALL, " " );
2945 }
2946 if ( shader->multitextureEnv == GL_ADD ) {
2947 ri.Printf( PRINT_ALL, "MT(a) " );
2948 } else if ( shader->multitextureEnv == GL_MODULATE ) {
2949 ri.Printf( PRINT_ALL, "MT(m) " );
2950 } else if ( shader->multitextureEnv == GL_DECAL ) {
2951 ri.Printf( PRINT_ALL, "MT(d) " );
2952 } else {
2953 ri.Printf( PRINT_ALL, " " );
2954 }
2955 if ( shader->explicitlyDefined ) {
2956 ri.Printf( PRINT_ALL, "E " );
2957 } else {
2958 ri.Printf( PRINT_ALL, " " );
2959 }
2960
2961 if ( shader->optimalStageIteratorFunc == RB_StageIteratorGeneric ) {
2962 ri.Printf( PRINT_ALL, "gen " );
2963 } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorSky ) {
2964 ri.Printf( PRINT_ALL, "sky " );
2965 } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorLightmappedMultitexture ) {
2966 ri.Printf( PRINT_ALL, "lmmt" );
2967 } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorVertexLitTexture ) {
2968 ri.Printf( PRINT_ALL, "vlt " );
2969 } else {
2970 ri.Printf( PRINT_ALL, " " );
2971 }
2972
2973 if ( shader->defaultShader ) {
2974 ri.Printf( PRINT_ALL, ": %s (DEFAULTED)\n", shader->name );
2975 } else {
2976 ri.Printf( PRINT_ALL, ": %s\n", shader->name );
2977 }
2978 count++;
2979 }
2980 ri.Printf( PRINT_ALL, "%i total shaders\n", count );
2981 ri.Printf( PRINT_ALL, "------------------\n" );
2982 }
2983
2984
2985 /*
2986 ====================
2987 ScanAndLoadShaderFiles
2988
2989 Finds and loads all .shader files, combining them into
2990 a single large text block that can be scanned for shader names
2991 =====================
2992 */
2993 #define MAX_SHADER_FILES 4096
ScanAndLoadShaderFiles(void)2994 static void ScanAndLoadShaderFiles( void ) {
2995 char **shaderFiles;
2996 char *buffers[MAX_SHADER_FILES] = {NULL};
2997 char *p;
2998 int numShaderFiles;
2999 int i;
3000 char *token, *textEnd;
3001 char shaderName[MAX_QPATH];
3002 int shaderLine;
3003
3004 long sum = 0, summand;
3005 // scan for shader files
3006 shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles );
3007
3008 if ( !shaderFiles || !numShaderFiles ) {
3009 ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" );
3010 return;
3011 }
3012
3013 if ( numShaderFiles > MAX_SHADER_FILES ) {
3014 numShaderFiles = MAX_SHADER_FILES;
3015 }
3016
3017 // load and parse shader files
3018 for ( i = 0; i < numShaderFiles; i++ )
3019 {
3020 char filename[MAX_QPATH];
3021
3022 Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
3023 ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename );
3024 summand = ri.FS_ReadFile( filename, (void **)&buffers[i] );
3025
3026 if ( !buffers[i] )
3027 ri.Error( ERR_DROP, "Couldn't load %s", filename );
3028
3029 // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders.
3030 p = buffers[i];
3031 COM_BeginParseSession(filename);
3032 while(1)
3033 {
3034 token = COM_ParseExt(&p, qtrue);
3035
3036 if(!*token)
3037 break;
3038
3039 Q_strncpyz(shaderName, token, sizeof(shaderName));
3040 shaderLine = COM_GetCurrentParseLine();
3041
3042 token = COM_ParseExt(&p, qtrue);
3043 if( !Q_stricmp( shaderName, token ) ) {
3044 ri.Printf(PRINT_WARNING, "WARNING: In shader file %s...Invalid shader name \"%s\" on line %d.\n",
3045 filename, shaderName, shaderLine);
3046 break;
3047 }
3048
3049 if(token[0] != '{' || token[1] != '\0')
3050 {
3051 ri.Printf(PRINT_WARNING, "WARNING: In shader file %s...Shader \"%s\" on line %d is missing opening brace",
3052 filename, shaderName, shaderLine);
3053 if (token[0])
3054 {
3055 ri.Printf(PRINT_WARNING, " (found \"%s\" on line %d)", token, COM_GetCurrentParseLine());
3056 }
3057 ri.Printf(PRINT_WARNING, "...Ignored\n");
3058 ri.FS_FreeFile(buffers[i]);
3059 buffers[i] = NULL;
3060 break;
3061 }
3062
3063 if(!SkipBracedSection(&p, 1))
3064 {
3065 ri.Printf(PRINT_WARNING, "WARNING: In shader file %s...Shader \"%s\" on line %d is missing closing brace",
3066 filename, shaderName, shaderLine);
3067 if( !Q_stricmp( filename, "common.shader" ) ) { // HACK...Broken shader in pak0.pk3
3068 ri.Printf(PRINT_WARNING, "...Ignored\n");
3069 ri.FS_FreeFile(buffers[i]);
3070 buffers[i] = NULL;
3071 break;
3072 } else {
3073 ri.Printf(PRINT_WARNING, ".\n");
3074 }
3075 }
3076 }
3077
3078 if (buffers[i])
3079 sum += summand;
3080 }
3081
3082 // build single large buffer
3083
3084 s_shaderText = ri.Hunk_Alloc( sum + numShaderFiles*2, h_low );
3085 s_shaderText[ 0 ] = '\0';
3086 textEnd = s_shaderText;
3087
3088 // free in reverse order, so the temp files are all dumped
3089 for ( i = numShaderFiles - 1; i >= 0 ; i-- )
3090 {
3091 if ( !buffers[i] )
3092 continue;
3093
3094 strcat( textEnd, buffers[i] );
3095 strcat( textEnd, "\n" );
3096 textEnd += strlen( textEnd );
3097 ri.FS_FreeFile( buffers[i] );
3098 }
3099
3100 COM_Compress( s_shaderText );
3101
3102 // free up memory
3103 ri.FS_FreeFileList( shaderFiles );
3104 }
3105
3106
3107 /*
3108 ====================
3109 CreateInternalShaders
3110 ====================
3111 */
CreateInternalShaders(void)3112 static void CreateInternalShaders( void ) {
3113 tr.numShaders = 0;
3114
3115 // init the default shader
3116 InitShader( "<default>", LIGHTMAP_NONE );
3117 stages[0].bundle[0].image[0] = tr.defaultImage;
3118 stages[0].active = qtrue;
3119 stages[0].stateBits = GLS_DEFAULT;
3120 tr.defaultShader = FinishShader();
3121
3122 // shadow shader is just a marker
3123 Q_strncpyz( shader.name, "<stencil shadow>", sizeof( shader.name ) );
3124 shader.sort = SS_STENCIL_SHADOW;
3125 tr.shadowShader = FinishShader();
3126 }
3127
CreateExternalShaders(void)3128 static void CreateExternalShaders( void ) {
3129 tr.projectionShadowShader = R_FindShader( "projectionShadow", LIGHTMAP_NONE, qtrue );
3130 tr.flareShader = R_FindShader( "flareShader", LIGHTMAP_NONE, qtrue );
3131
3132 // Hack to make fogging work correctly on flares. Fog colors are calculated
3133 // in tr_flare.c already.
3134 if(!tr.flareShader->defaultShader)
3135 {
3136 int index;
3137
3138 for(index = 0; index < tr.flareShader->numUnfoggedPasses; index++)
3139 {
3140 tr.flareShader->stages[index]->adjustColorsForFog = ACFF_NONE;
3141 tr.flareShader->stages[index]->stateBits |= GLS_DEPTHTEST_DISABLE;
3142 }
3143 }
3144
3145 // tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue ); //----(SA) let sky shader set this
3146 tr.sunflareShader[0] = R_FindShader( "sunflare1", LIGHTMAP_NONE, qtrue );
3147 tr.dlightShader = R_FindShader( "dlightshader", LIGHTMAP_NONE, qtrue );
3148 }
3149
3150
3151 /*
3152 ==================
3153 R_InitShaders
3154 ==================
3155 */
R_InitShaders(void)3156 void R_InitShaders( void ) {
3157
3158 glfogNum = FOG_NONE;
3159
3160 ri.Printf( PRINT_ALL, "Initializing Shaders\n" );
3161
3162 memset( hashTable, 0, sizeof( hashTable ) );
3163
3164 CreateInternalShaders();
3165
3166 ScanAndLoadShaderFiles();
3167
3168 CreateExternalShaders();
3169 }
3170
3171