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