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