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