1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7 
8 This file is part of the OpenJK source code.
9 
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
13 
14 This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
21 ===========================================================================
22 */
23 
24 // tr_shader.c -- this file deals with the parsing and definition of shaders
25 
26 #include "tr_local.h"
27 
28 static char *s_shaderText;
29 
30 // the shader is parsed into these global variables, then copied into
31 // dynamically allocated memory if it is valid.
32 static	shaderStage_t	stages[MAX_SHADER_STAGES];
33 static	shader_t		shader;
34 static	texModInfo_t	texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS];
35 
36 // Hash value (generated using the generateHashValueForText function) for the original
37 // retail JKA shader for gfx/2d/wedge.
38 #define RETAIL_ROCKET_WEDGE_SHADER_HASH (1217042)
39 
40 // Hash value (generated using the generateHashValueForText function) for the original
41 // retail JKA shader for gfx/menus/radar/arrow_w.
42 #define RETAIL_ARROW_W_SHADER_HASH (1650186)
43 
44 #define FILE_HASH_SIZE		1024
45 static	shader_t*		hashTable[FILE_HASH_SIZE];
46 
47 #define MAX_SHADERTEXT_HASH		2048
48 static char **shaderTextHashTable[MAX_SHADERTEXT_HASH] = { 0 };
49 
KillTheShaderHashTable(void)50 void KillTheShaderHashTable(void)
51 {
52 	memset(shaderTextHashTable, 0, sizeof(shaderTextHashTable));
53 }
54 
ShaderHashTableExists(void)55 qboolean ShaderHashTableExists(void)
56 {
57 	if (shaderTextHashTable[0])
58 	{
59 		return qtrue;
60 	}
61 	return qfalse;
62 }
63 
64 const int lightmapsNone[MAXLIGHTMAPS] =
65 {
66 	LIGHTMAP_NONE,
67 	LIGHTMAP_NONE,
68 	LIGHTMAP_NONE,
69 	LIGHTMAP_NONE
70 };
71 
72 const int lightmaps2d[MAXLIGHTMAPS] =
73 {
74 	LIGHTMAP_2D,
75 	LIGHTMAP_2D,
76 	LIGHTMAP_2D,
77 	LIGHTMAP_2D
78 };
79 
80 const int lightmapsVertex[MAXLIGHTMAPS] =
81 {
82 	LIGHTMAP_BY_VERTEX,
83 	LIGHTMAP_BY_VERTEX,
84 	LIGHTMAP_BY_VERTEX,
85 	LIGHTMAP_BY_VERTEX
86 };
87 
88 const int lightmapsFullBright[MAXLIGHTMAPS] =
89 {
90 	LIGHTMAP_WHITEIMAGE,
91 	LIGHTMAP_WHITEIMAGE,
92 	LIGHTMAP_WHITEIMAGE,
93 	LIGHTMAP_WHITEIMAGE
94 };
95 
96 const byte stylesDefault[MAXLIGHTMAPS] =
97 {
98 	LS_NORMAL,
99 	LS_LSNONE,
100 	LS_LSNONE,
101 	LS_LSNONE
102 };
103 
ClearGlobalShader(void)104 static void ClearGlobalShader(void)
105 {
106 	int	i;
107 
108 	memset( &shader, 0, sizeof( shader ) );
109 	memset( &stages, 0, sizeof( stages ) );
110 	for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
111 		stages[i].bundle[0].texMods = texMods[i];
112 		stages[i].mGLFogColorOverride = GLFOGOVERRIDE_NONE;
113 	}
114 
115 	shader.contentFlags = CONTENTS_SOLID | CONTENTS_OPAQUE;
116 }
117 
generateHashValueForText(const char * string,size_t length)118 static uint32_t generateHashValueForText( const char *string, size_t length )
119 {
120 	int i = 0;
121 	uint32_t hash = 0;
122 
123 	while ( length-- )
124 	{
125 		hash += string[i] * (i + 119);
126 		i++;
127 	}
128 
129 	return (hash ^ (hash >> 10) ^ (hash >> 20));
130 }
131 
132 /*
133 ================
134 return a hash value for the filename
135 ================
136 */
generateHashValue(const char * fname,const int size)137 static long generateHashValue( const char *fname, const int size ) {
138 	int		i;
139 	long	hash;
140 	char	letter;
141 
142 	hash = 0;
143 	i = 0;
144 	while (fname[i] != '\0') {
145 		letter = tolower((unsigned char)fname[i]);
146 		if (letter =='.') break;				// don't include extension
147 		if (letter =='\\') letter = '/';		// damn path names
148 		if (letter == PATH_SEP) letter = '/';		// damn path names
149 		hash+=(long)(letter)*(i+119);
150 		i++;
151 	}
152 	hash = (hash ^ (hash >> 10) ^ (hash >> 20));
153 	hash &= (size-1);
154 	return hash;
155 }
156 
R_RemapShader(const char * shaderName,const char * newShaderName,const char * timeOffset)157 void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) {
158 	char		strippedName[MAX_QPATH];
159 	int			hash;
160 	shader_t	*sh, *sh2;
161 	qhandle_t	h;
162 
163 	sh = R_FindShaderByName( shaderName );
164 	if (sh == NULL || sh == tr.defaultShader) {
165 		h = RE_RegisterShaderLightMap(shaderName, lightmapsNone, stylesDefault);
166 		sh = R_GetShaderByHandle(h);
167 	}
168 	if (sh == NULL || sh == tr.defaultShader) {
169 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: R_RemapShader: shader %s not found\n", shaderName );
170 		return;
171 	}
172 
173 	sh2 = R_FindShaderByName( newShaderName );
174 	if (sh2 == NULL || sh2 == tr.defaultShader) {
175 		h = RE_RegisterShaderLightMap(newShaderName, lightmapsNone, stylesDefault);
176 		sh2 = R_GetShaderByHandle(h);
177 	}
178 
179 	if (sh2 == NULL || sh2 == tr.defaultShader) {
180 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: R_RemapShader: new shader %s not found\n", newShaderName );
181 		return;
182 	}
183 
184 	// remap all the shaders with the given name
185 	// even tho they might have different lightmaps
186 	COM_StripExtension( shaderName, strippedName, sizeof( strippedName ) );
187 	hash = generateHashValue(strippedName, FILE_HASH_SIZE);
188 	for (sh = hashTable[hash]; sh; sh = sh->next) {
189 		if (Q_stricmp(sh->name, strippedName) == 0) {
190 			if (sh != sh2) {
191 				sh->remappedShader = sh2;
192 			} else {
193 				sh->remappedShader = NULL;
194 			}
195 		}
196 	}
197 	if (timeOffset) {
198 		sh2->timeOffset = atof(timeOffset);
199 	}
200 }
201 
202 /*
203 ===============
204 ParseVector
205 ===============
206 */
ParseVector(const char ** text,int count,float * v)207 qboolean ParseVector( const char **text, int count, float *v ) {
208 	char	*token;
209 	int		i;
210 
211 	// FIXME: spaces are currently required after parens, should change parseext...
212 	token = COM_ParseExt( text, qfalse );
213 	if ( strcmp( token, "(" ) ) {
214 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parenthesis in shader '%s'\n", shader.name );
215 		return qfalse;
216 	}
217 
218 	for ( i = 0 ; i < count ; i++ ) {
219 		token = COM_ParseExt( text, qfalse );
220 		if ( !token[0] ) {
221 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing vector element in shader '%s'\n", shader.name );
222 			return qfalse;
223 		}
224 		v[i] = atof( token );
225 	}
226 
227 	token = COM_ParseExt( text, qfalse );
228 	if ( strcmp( token, ")" ) ) {
229 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parenthesis in shader '%s'\n", shader.name );
230 		return qfalse;
231 	}
232 
233 	return qtrue;
234 }
235 
236 
237 /*
238 ===============
239 NameToAFunc
240 ===============
241 */
NameToAFunc(const char * funcname)242 static unsigned NameToAFunc( const char *funcname )
243 {
244 	if ( !Q_stricmp( funcname, "GT0" ) )
245 	{
246 		return GLS_ATEST_GT_0;
247 	}
248 	else if ( !Q_stricmp( funcname, "LT128" ) )
249 	{
250 		return GLS_ATEST_LT_80;
251 	}
252 	else if ( !Q_stricmp( funcname, "GE128" ) )
253 	{
254 		return GLS_ATEST_GE_80;
255 	}
256 	else if ( !Q_stricmp( funcname, "GE192" ) )
257 	{
258 		return GLS_ATEST_GE_C0;
259 	}
260 
261 	ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name );
262 	return 0;
263 }
264 
265 
266 /*
267 ===============
268 NameToSrcBlendMode
269 ===============
270 */
NameToSrcBlendMode(const char * name)271 static int NameToSrcBlendMode( const char *name )
272 {
273 	if ( !Q_stricmp( name, "GL_ONE" ) )
274 	{
275 		return GLS_SRCBLEND_ONE;
276 	}
277 	else if ( !Q_stricmp( name, "GL_ZERO" ) )
278 	{
279 		return GLS_SRCBLEND_ZERO;
280 	}
281 	else if ( !Q_stricmp( name, "GL_DST_COLOR" ) )
282 	{
283 		return GLS_SRCBLEND_DST_COLOR;
284 	}
285 	else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) )
286 	{
287 		return GLS_SRCBLEND_ONE_MINUS_DST_COLOR;
288 	}
289 	else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
290 	{
291 		return GLS_SRCBLEND_SRC_ALPHA;
292 	}
293 	else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
294 	{
295 		return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA;
296 	}
297 	else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
298 	{
299 		return GLS_SRCBLEND_DST_ALPHA;
300 	}
301 	else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
302 	{
303 		return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA;
304 	}
305 	else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) )
306 	{
307 		return GLS_SRCBLEND_ALPHA_SATURATE;
308 	}
309 
310 	ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
311 	return GLS_SRCBLEND_ONE;
312 }
313 
314 /*
315 ===============
316 NameToDstBlendMode
317 ===============
318 */
NameToDstBlendMode(const char * name)319 static int NameToDstBlendMode( const char *name )
320 {
321 	if ( !Q_stricmp( name, "GL_ONE" ) )
322 	{
323 		return GLS_DSTBLEND_ONE;
324 	}
325 	else if ( !Q_stricmp( name, "GL_ZERO" ) )
326 	{
327 		return GLS_DSTBLEND_ZERO;
328 	}
329 	else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
330 	{
331 		return GLS_DSTBLEND_SRC_ALPHA;
332 	}
333 	else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
334 	{
335 		return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
336 	}
337 	else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
338 	{
339 		return GLS_DSTBLEND_DST_ALPHA;
340 	}
341 	else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
342 	{
343 		return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA;
344 	}
345 	else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) )
346 	{
347 		return GLS_DSTBLEND_SRC_COLOR;
348 	}
349 	else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) )
350 	{
351 		return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR;
352 	}
353 
354 	ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
355 	return GLS_DSTBLEND_ONE;
356 }
357 
358 /*
359 ===============
360 NameToGenFunc
361 ===============
362 */
NameToGenFunc(const char * funcname)363 static genFunc_t NameToGenFunc( const char *funcname )
364 {
365 	if ( !Q_stricmp( funcname, "sin" ) )
366 	{
367 		return GF_SIN;
368 	}
369 	else if ( !Q_stricmp( funcname, "square" ) )
370 	{
371 		return GF_SQUARE;
372 	}
373 	else if ( !Q_stricmp( funcname, "triangle" ) )
374 	{
375 		return GF_TRIANGLE;
376 	}
377 	else if ( !Q_stricmp( funcname, "sawtooth" ) )
378 	{
379 		return GF_SAWTOOTH;
380 	}
381 	else if ( !Q_stricmp( funcname, "inversesawtooth" ) )
382 	{
383 		return GF_INVERSE_SAWTOOTH;
384 	}
385 	else if ( !Q_stricmp( funcname, "noise" ) )
386 	{
387 		return GF_NOISE;
388 	}
389 	else if ( !Q_stricmp( funcname, "random" ) )
390 	{
391 		return GF_RAND;
392 	}
393 
394 	ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name );
395 	return GF_SIN;
396 }
397 
398 
399 /*
400 ===================
401 ParseWaveForm
402 ===================
403 */
ParseWaveForm(const char ** text,waveForm_t * wave)404 static void ParseWaveForm( const char **text, waveForm_t *wave )
405 {
406 	char *token;
407 
408 	token = COM_ParseExt( text, qfalse );
409 	if ( token[0] == 0 )
410 	{
411 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing waveform parm in shader '%s'\n", shader.name );
412 		return;
413 	}
414 	wave->func = NameToGenFunc( token );
415 
416 	// BASE, AMP, PHASE, FREQ
417 	token = COM_ParseExt( text, qfalse );
418 	if ( token[0] == 0 )
419 	{
420 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing waveform parm in shader '%s'\n", shader.name );
421 		return;
422 	}
423 	wave->base = atof( token );
424 
425 	token = COM_ParseExt( text, qfalse );
426 	if ( token[0] == 0 )
427 	{
428 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing waveform parm in shader '%s'\n", shader.name );
429 		return;
430 	}
431 	wave->amplitude = atof( token );
432 
433 	token = COM_ParseExt( text, qfalse );
434 	if ( token[0] == 0 )
435 	{
436 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing waveform parm in shader '%s'\n", shader.name );
437 		return;
438 	}
439 	wave->phase = atof( token );
440 
441 	token = COM_ParseExt( text, qfalse );
442 	if ( token[0] == 0 )
443 	{
444 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing waveform parm in shader '%s'\n", shader.name );
445 		return;
446 	}
447 	wave->frequency = atof( token );
448 }
449 
450 
451 /*
452 ===================
453 ParseTexMod
454 ===================
455 */
ParseTexMod(const char * _text,shaderStage_t * stage)456 static void ParseTexMod( const char *_text, shaderStage_t *stage )
457 {
458 	const char *token;
459 	const char **text = &_text;
460 	texModInfo_t *tmi;
461 
462 	if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) {
463 		Com_Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'\n", shader.name );
464 		return;
465 	}
466 
467 	tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods];
468 	stage->bundle[0].numTexMods++;
469 
470 	token = COM_ParseExt( text, qfalse );
471 
472 	//
473 	// turb
474 	//
475 	if ( !Q_stricmp( token, "turb" ) )
476 	{
477 		token = COM_ParseExt( text, qfalse );
478 		if ( token[0] == 0 )
479 		{
480 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name );
481 			return;
482 		}
483 		tmi->wave.base = atof( token );
484 		token = COM_ParseExt( text, qfalse );
485 		if ( token[0] == 0 )
486 		{
487 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
488 			return;
489 		}
490 		tmi->wave.amplitude = atof( token );
491 		token = COM_ParseExt( text, qfalse );
492 		if ( token[0] == 0 )
493 		{
494 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
495 			return;
496 		}
497 		tmi->wave.phase = atof( token );
498 		token = COM_ParseExt( text, qfalse );
499 		if ( token[0] == 0 )
500 		{
501 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
502 			return;
503 		}
504 		tmi->wave.frequency = atof( token );
505 
506 		tmi->type = TMOD_TURBULENT;
507 	}
508 	//
509 	// scale
510 	//
511 	else if ( !Q_stricmp( token, "scale" ) )
512 	{
513 		token = COM_ParseExt( text, qfalse );
514 		if ( token[0] == 0 )
515 		{
516 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing scale parms in shader '%s'\n", shader.name );
517 			return;
518 		}
519 		tmi->translate[0] = atof( token );	//scale unioned
520 
521 		token = COM_ParseExt( text, qfalse );
522 		if ( token[0] == 0 )
523 		{
524 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing scale parms in shader '%s'\n", shader.name );
525 			return;
526 		}
527 		tmi->translate[1] = atof( token );	//scale unioned
528 		tmi->type = TMOD_SCALE;
529 	}
530 	//
531 	// scroll
532 	//
533 	else if ( !Q_stricmp( token, "scroll" ) )
534 	{
535 		token = COM_ParseExt( text, qfalse );
536 		if ( token[0] == 0 )
537 		{
538 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
539 			return;
540 		}
541 		tmi->translate[0] = atof( token );	//scroll unioned
542 		token = COM_ParseExt( text, qfalse );
543 		if ( token[0] == 0 )
544 		{
545 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
546 			return;
547 		}
548 		tmi->translate[1] = atof( token );	//scroll unioned
549 		tmi->type = TMOD_SCROLL;
550 	}
551 	//
552 	// stretch
553 	//
554 	else if ( !Q_stricmp( token, "stretch" ) )
555 	{
556 		token = COM_ParseExt( text, qfalse );
557 		if ( token[0] == 0 )
558 		{
559 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing stretch parms in shader '%s'\n", shader.name );
560 			return;
561 		}
562 		tmi->wave.func = NameToGenFunc( token );
563 
564 		token = COM_ParseExt( text, qfalse );
565 		if ( token[0] == 0 )
566 		{
567 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing stretch parms in shader '%s'\n", shader.name );
568 			return;
569 		}
570 		tmi->wave.base = atof( token );
571 
572 		token = COM_ParseExt( text, qfalse );
573 		if ( token[0] == 0 )
574 		{
575 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing stretch parms in shader '%s'\n", shader.name );
576 			return;
577 		}
578 		tmi->wave.amplitude = atof( token );
579 
580 		token = COM_ParseExt( text, qfalse );
581 		if ( token[0] == 0 )
582 		{
583 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing stretch parms in shader '%s'\n", shader.name );
584 			return;
585 		}
586 		tmi->wave.phase = atof( token );
587 
588 		token = COM_ParseExt( text, qfalse );
589 		if ( token[0] == 0 )
590 		{
591 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing stretch parms in shader '%s'\n", shader.name );
592 			return;
593 		}
594 		tmi->wave.frequency = atof( token );
595 
596 		tmi->type = TMOD_STRETCH;
597 	}
598 	//
599 	// transform
600 	//
601 	else if ( !Q_stricmp( token, "transform" ) )
602 	{
603 		token = COM_ParseExt( text, qfalse );
604 		if ( token[0] == 0 )
605 		{
606 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing transform parms in shader '%s'\n", shader.name );
607 			return;
608 		}
609 		tmi->matrix[0][0] = atof( token );
610 
611 		token = COM_ParseExt( text, qfalse );
612 		if ( token[0] == 0 )
613 		{
614 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing transform parms in shader '%s'\n", shader.name );
615 			return;
616 		}
617 		tmi->matrix[0][1] = atof( token );
618 
619 		token = COM_ParseExt( text, qfalse );
620 		if ( token[0] == 0 )
621 		{
622 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing transform parms in shader '%s'\n", shader.name );
623 			return;
624 		}
625 		tmi->matrix[1][0] = atof( token );
626 
627 		token = COM_ParseExt( text, qfalse );
628 		if ( token[0] == 0 )
629 		{
630 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing transform parms in shader '%s'\n", shader.name );
631 			return;
632 		}
633 		tmi->matrix[1][1] = atof( token );
634 
635 		token = COM_ParseExt( text, qfalse );
636 		if ( token[0] == 0 )
637 		{
638 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing transform parms in shader '%s'\n", shader.name );
639 			return;
640 		}
641 		tmi->translate[0] = atof( token );
642 
643 		token = COM_ParseExt( text, qfalse );
644 		if ( token[0] == 0 )
645 		{
646 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing transform parms in shader '%s'\n", shader.name );
647 			return;
648 		}
649 		tmi->translate[1] = atof( token );
650 
651 		tmi->type = TMOD_TRANSFORM;
652 	}
653 	//
654 	// rotate
655 	//
656 	else if ( !Q_stricmp( token, "rotate" ) )
657 	{
658 		token = COM_ParseExt( text, qfalse );
659 		if ( token[0] == 0 )
660 		{
661 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name );
662 			return;
663 		}
664 		tmi->translate[0]= atof( token );	//rotateSpeed unioned
665 		tmi->type = TMOD_ROTATE;
666 	}
667 	//
668 	// entityTranslate
669 	//
670 	else if ( !Q_stricmp( token, "entityTranslate" ) )
671 	{
672 		tmi->type = TMOD_ENTITY_TRANSLATE;
673 	}
674 	else
675 	{
676 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name );
677 	}
678 }
679 
680 
681 
682 /*
683 /////===== Part of the VERTIGON system =====/////
684 ===================
685 ParseSurfaceSprites
686 ===================
687 */
688 // surfaceSprites <type> <width> <height> <density> <fadedist>
689 //
690 // NOTE:  This parsing function used to be 12 pages long and very complex.  The new version of surfacesprites
691 // utilizes optional parameters parsed in ParseSurfaceSpriteOptional.
ParseSurfaceSprites(const char * _text,shaderStage_t * stage)692 static void ParseSurfaceSprites( const char *_text, shaderStage_t *stage )
693 {
694 	const char *token;
695 	const char **text = &_text;
696 	float width, height, density, fadedist;
697 	int sstype=SURFSPRITE_NONE;
698 
699 	//
700 	// spritetype
701 	//
702 	token = COM_ParseExt( text, qfalse );
703 
704 	if (token[0]==0)
705 	{
706 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfaceSprites params in shader '%s'\n", shader.name );
707 		return;
708 	}
709 
710 	if (!Q_stricmp(token, "vertical"))
711 	{
712 		sstype = SURFSPRITE_VERTICAL;
713 	}
714 	else if (!Q_stricmp(token, "oriented"))
715 	{
716 		sstype = SURFSPRITE_ORIENTED;
717 	}
718 	else if (!Q_stricmp(token, "effect"))
719 	{
720 		sstype = SURFSPRITE_EFFECT;
721 	}
722 	else if (!Q_stricmp(token, "flattened"))
723 	{
724 		sstype = SURFSPRITE_FLATTENED;
725 	}
726 	else
727 	{
728 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid type in shader '%s'\n", shader.name );
729 		return;
730 	}
731 
732 	//
733 	// width
734 	//
735 	token = COM_ParseExt( text, qfalse );
736 	if (token[0]==0)
737 	{
738 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfaceSprites params in shader '%s'\n", shader.name );
739 		return;
740 	}
741 	width=atof(token);
742 	if (width <= 0)
743 	{
744 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid width in shader '%s'\n", shader.name );
745 		return;
746 	}
747 
748 	//
749 	// height
750 	//
751 	token = COM_ParseExt( text, qfalse );
752 	if (token[0]==0)
753 	{
754 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfaceSprites params in shader '%s'\n", shader.name );
755 		return;
756 	}
757 	height=atof(token);
758 	if (height <= 0)
759 	{
760 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid height in shader '%s'\n", shader.name );
761 		return;
762 	}
763 
764 	//
765 	// density
766 	//
767 	token = COM_ParseExt( text, qfalse );
768 	if (token[0]==0)
769 	{
770 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfaceSprites params in shader '%s'\n", shader.name );
771 		return;
772 	}
773 	density=atof(token);
774 	if (density <= 0)
775 	{
776 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid density in shader '%s'\n", shader.name );
777 		return;
778 	}
779 
780 	//
781 	// fadedist
782 	//
783 	token = COM_ParseExt( text, qfalse );
784 	if (token[0]==0)
785 	{
786 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfaceSprites params in shader '%s'\n", shader.name );
787 		return;
788 	}
789 	fadedist=atof(token);
790 	if (fadedist < 32)
791 	{
792 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid fadedist (%f < 32) in shader '%s'\n", fadedist, shader.name );
793 		return;
794 	}
795 
796 	if (!stage->ss)
797 	{
798 		stage->ss = (surfaceSprite_t *)Hunk_Alloc( sizeof( surfaceSprite_t ), h_low );
799 	}
800 
801 	// These are all set by the command lines.
802 	stage->ss->surfaceSpriteType = sstype;
803 	stage->ss->width = width;
804 	stage->ss->height = height;
805 	stage->ss->density = density;
806 	stage->ss->fadeDist = fadedist;
807 
808 	// These are defaults that can be overwritten.
809 	stage->ss->fadeMax = fadedist*1.33;
810 	stage->ss->fadeScale = 0.0;
811 	stage->ss->wind = 0.0;
812 	stage->ss->windIdle = 0.0;
813 	stage->ss->variance[0] = 0.0;
814 	stage->ss->variance[1] = 0.0;
815 	stage->ss->facing = SURFSPRITE_FACING_NORMAL;
816 
817 	// A vertical parameter that needs a default regardless
818 	stage->ss->vertSkew = 0.0f;
819 
820 	// These are effect parameters that need defaults nonetheless.
821 	stage->ss->fxDuration = 1000;		// 1 second
822 	stage->ss->fxGrow[0] = 0.0;
823 	stage->ss->fxGrow[1] = 0.0;
824 	stage->ss->fxAlphaStart = 1.0;
825 	stage->ss->fxAlphaEnd = 0.0;
826 }
827 
828 
829 
830 
831 /*
832 /////===== Part of the VERTIGON system =====/////
833 ===========================
834 ParseSurfaceSpritesOptional
835 ===========================
836 */
837 //
838 // ssFademax <fademax>
839 // ssFadescale <fadescale>
840 // ssVariance <varwidth> <varheight>
841 // ssHangdown
842 // ssAnyangle
843 // ssFaceup
844 // ssWind <wind>
845 // ssWindIdle <windidle>
846 // ssVertSkew <skew>
847 // ssFXDuration <duration>
848 // ssFXGrow <growwidth> <growheight>
849 // ssFXAlphaRange <alphastart> <startend>
850 // ssFXWeather
851 //
852 // Optional parameters that will override the defaults set in the surfacesprites command above.
853 //
ParseSurfaceSpritesOptional(const char * param,const char * _text,shaderStage_t * stage)854 static void ParseSurfaceSpritesOptional( const char *param, const char *_text, shaderStage_t *stage )
855 {
856 	const char *token;
857 	const char **text = &_text;
858 	float	value;
859 
860 	if (!stage->ss)
861 	{
862 		stage->ss = (surfaceSprite_t *)Hunk_Alloc( sizeof( surfaceSprite_t ), h_low );
863 	}
864 	//
865 	// fademax
866 	//
867 	if (!Q_stricmp(param, "ssFademax"))
868 	{
869 		token = COM_ParseExt( text, qfalse);
870 		if (token[0]==0)
871 		{
872 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite fademax in shader '%s'\n", shader.name );
873 			return;
874 		}
875 		value = atof(token);
876 		if (value <= stage->ss->fadeDist)
877 		{
878 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid surfacesprite fademax (%.2f <= fadeDist(%.2f)) in shader '%s'\n", value, stage->ss->fadeDist, shader.name );
879 			return;
880 		}
881 		stage->ss->fadeMax=value;
882 		return;
883 	}
884 
885 	//
886 	// fadescale
887 	//
888 	if (!Q_stricmp(param, "ssFadescale"))
889 	{
890 		token = COM_ParseExt( text, qfalse);
891 		if (token[0]==0)
892 		{
893 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite fadescale in shader '%s'\n", shader.name );
894 			return;
895 		}
896 		value = atof(token);
897 		stage->ss->fadeScale=value;
898 		return;
899 	}
900 
901 	//
902 	// variance
903 	//
904 	if (!Q_stricmp(param, "ssVariance"))
905 	{
906 		token = COM_ParseExt( text, qfalse);
907 		if (token[0]==0)
908 		{
909 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite variance width in shader '%s'\n", shader.name );
910 			return;
911 		}
912 		value = atof(token);
913 		if (value < 0)
914 		{
915 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid surfacesprite variance width in shader '%s'\n", shader.name );
916 			return;
917 		}
918 		stage->ss->variance[0]=value;
919 
920 		token = COM_ParseExt( text, qfalse);
921 		if (token[0]==0)
922 		{
923 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite variance height in shader '%s'\n", shader.name );
924 			return;
925 		}
926 		value = atof(token);
927 		if (value < 0)
928 		{
929 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid surfacesprite variance height in shader '%s'\n", shader.name );
930 			return;
931 		}
932 		stage->ss->variance[1]=value;
933 		return;
934 	}
935 
936 	//
937 	// hangdown
938 	//
939 	if (!Q_stricmp(param, "ssHangdown"))
940 	{
941 		if (stage->ss->facing != SURFSPRITE_FACING_NORMAL)
942 		{
943 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: Hangdown facing overrides previous facing in shader '%s'\n", shader.name );
944 			return;
945 		}
946 		stage->ss->facing=SURFSPRITE_FACING_DOWN;
947 		return;
948 	}
949 
950 	//
951 	// anyangle
952 	//
953 	if (!Q_stricmp(param, "ssAnyangle"))
954 	{
955 		if (stage->ss->facing != SURFSPRITE_FACING_NORMAL)
956 		{
957 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: Anyangle facing overrides previous facing in shader '%s'\n", shader.name );
958 			return;
959 		}
960 		stage->ss->facing=SURFSPRITE_FACING_ANY;
961 		return;
962 	}
963 
964 	//
965 	// faceup
966 	//
967 	if (!Q_stricmp(param, "ssFaceup"))
968 	{
969 		if (stage->ss->facing != SURFSPRITE_FACING_NORMAL)
970 		{
971 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: Faceup facing overrides previous facing in shader '%s'\n", shader.name );
972 			return;
973 		}
974 		stage->ss->facing=SURFSPRITE_FACING_UP;
975 		return;
976 	}
977 
978 	//
979 	// wind
980 	//
981 	if (!Q_stricmp(param, "ssWind"))
982 	{
983 		token = COM_ParseExt( text, qfalse);
984 		if (token[0]==0)
985 		{
986 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite wind in shader '%s'\n", shader.name );
987 			return;
988 		}
989 		value = atof(token);
990 		if (value < 0.0)
991 		{
992 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid surfacesprite wind in shader '%s'\n", shader.name );
993 			return;
994 		}
995 		stage->ss->wind=value;
996 		if (stage->ss->windIdle <= 0)
997 		{	// Also override the windidle, it usually is the same as wind
998 			stage->ss->windIdle = value;
999 		}
1000 		return;
1001 	}
1002 
1003 	//
1004 	// windidle
1005 	//
1006 	if (!Q_stricmp(param, "ssWindidle"))
1007 	{
1008 		token = COM_ParseExt( text, qfalse);
1009 		if (token[0]==0)
1010 		{
1011 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite windidle in shader '%s'\n", shader.name );
1012 			return;
1013 		}
1014 		value = atof(token);
1015 		if (value < 0.0)
1016 		{
1017 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid surfacesprite windidle in shader '%s'\n", shader.name );
1018 			return;
1019 		}
1020 		stage->ss->windIdle=value;
1021 		return;
1022 	}
1023 
1024 	//
1025 	// vertskew
1026 	//
1027 	if (!Q_stricmp(param, "ssVertskew"))
1028 	{
1029 		token = COM_ParseExt( text, qfalse);
1030 		if (token[0]==0)
1031 		{
1032 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite vertskew in shader '%s'\n", shader.name );
1033 			return;
1034 		}
1035 		value = atof(token);
1036 		if (value < 0.0)
1037 		{
1038 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid surfacesprite vertskew in shader '%s'\n", shader.name );
1039 			return;
1040 		}
1041 		stage->ss->vertSkew=value;
1042 		return;
1043 	}
1044 
1045 	//
1046 	// fxduration
1047 	//
1048 	if (!Q_stricmp(param, "ssFXDuration"))
1049 	{
1050 		token = COM_ParseExt( text, qfalse);
1051 		if (token[0]==0)
1052 		{
1053 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite duration in shader '%s'\n", shader.name );
1054 			return;
1055 		}
1056 		value = atof(token);
1057 		if (value <= 0)
1058 		{
1059 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid surfacesprite duration in shader '%s'\n", shader.name );
1060 			return;
1061 		}
1062 		stage->ss->fxDuration=value;
1063 		return;
1064 	}
1065 
1066 	//
1067 	// fxgrow
1068 	//
1069 	if (!Q_stricmp(param, "ssFXGrow"))
1070 	{
1071 		token = COM_ParseExt( text, qfalse);
1072 		if (token[0]==0)
1073 		{
1074 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite grow width in shader '%s'\n", shader.name );
1075 			return;
1076 		}
1077 		value = atof(token);
1078 		if (value < 0)
1079 		{
1080 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid surfacesprite grow width in shader '%s'\n", shader.name );
1081 			return;
1082 		}
1083 		stage->ss->fxGrow[0]=value;
1084 
1085 		token = COM_ParseExt( text, qfalse);
1086 		if (token[0]==0)
1087 		{
1088 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite grow height in shader '%s'\n", shader.name );
1089 			return;
1090 		}
1091 		value = atof(token);
1092 		if (value < 0)
1093 		{
1094 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid surfacesprite grow height in shader '%s'\n", shader.name );
1095 			return;
1096 		}
1097 		stage->ss->fxGrow[1]=value;
1098 		return;
1099 	}
1100 
1101 	//
1102 	// fxalpharange
1103 	//
1104 	if (!Q_stricmp(param, "ssFXAlphaRange"))
1105 	{
1106 		token = COM_ParseExt( text, qfalse);
1107 		if (token[0]==0)
1108 		{
1109 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite fxalpha start in shader '%s'\n", shader.name );
1110 			return;
1111 		}
1112 		value = atof(token);
1113 		if (value < 0 || value > 1.0)
1114 		{
1115 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid surfacesprite fxalpha start in shader '%s'\n", shader.name );
1116 			return;
1117 		}
1118 		stage->ss->fxAlphaStart=value;
1119 
1120 		token = COM_ParseExt( text, qfalse);
1121 		if (token[0]==0)
1122 		{
1123 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing surfacesprite fxalpha end in shader '%s'\n", shader.name );
1124 			return;
1125 		}
1126 		value = atof(token);
1127 		if (value < 0 || value > 1.0)
1128 		{
1129 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid surfacesprite fxalpha end in shader '%s'\n", shader.name );
1130 			return;
1131 		}
1132 		stage->ss->fxAlphaEnd=value;
1133 		return;
1134 	}
1135 
1136 	//
1137 	// fxweather
1138 	//
1139 	if (!Q_stricmp(param, "ssFXWeather"))
1140 	{
1141 		if (stage->ss->surfaceSpriteType != SURFSPRITE_EFFECT)
1142 		{
1143 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: weather applied to non-effect surfacesprite in shader '%s'\n", shader.name );
1144 			return;
1145 		}
1146 		stage->ss->surfaceSpriteType = SURFSPRITE_WEATHERFX;
1147 		return;
1148 	}
1149 
1150 	//
1151 	// invalid ss command.
1152 	//
1153 	ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid optional surfacesprite param '%s' in shader '%s'\n", param, shader.name );
1154 	return;
1155 }
1156 
1157 
1158 /*
1159 ===================
1160 ParseStage
1161 ===================
1162 */
ParseStage(shaderStage_t * stage,const char ** text)1163 static qboolean ParseStage( shaderStage_t *stage, const char **text )
1164 {
1165 	char *token;
1166 	int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0;
1167 	qboolean depthMaskExplicit = qfalse;
1168 
1169 	stage->active = qtrue;
1170 
1171 	while ( 1 )
1172 	{
1173 		token = COM_ParseExt( text, qtrue );
1174 		if ( !token[0] )
1175 		{
1176 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: no matching '}' found\n" );
1177 			return qfalse;
1178 		}
1179 
1180 		if ( token[0] == '}' )
1181 		{
1182 			break;
1183 		}
1184 		//
1185 		// map <name>
1186 		//
1187 		else if ( !Q_stricmp( token, "map" ) )
1188 		{
1189 			token = COM_ParseExt( text, qfalse );
1190 			if ( !token[0] )
1191 			{
1192 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name );
1193 				return qfalse;
1194 			}
1195 
1196 			if ( !Q_stricmp( token, "$whiteimage" ) )
1197 			{
1198 				stage->bundle[0].image = tr.whiteImage;
1199 				continue;
1200 			}
1201 			else if ( !Q_stricmp( token, "$lightmap" ) )
1202 			{
1203 				stage->bundle[0].isLightmap = qtrue;
1204 				if ( shader.lightmapIndex[0] < 0 || shader.lightmapIndex[0] >= tr.numLightmaps )
1205 				{
1206 #ifndef FINAL_BUILD
1207 					ri.Printf( PRINT_ALL, S_COLOR_RED"Lightmap requested but none available for shader %s\n", shader.name);
1208 #endif
1209 					stage->bundle[0].image = tr.whiteImage;
1210 				}
1211 				else
1212 				{
1213 					stage->bundle[0].image = tr.lightmaps[shader.lightmapIndex[0]];
1214 				}
1215 				continue;
1216 			}
1217 			else
1218 			{
1219 				stage->bundle[0].image = R_FindImageFile( token, (qboolean)!shader.noMipMaps, (qboolean)!shader.noPicMip, (qboolean)!shader.noTC, GL_REPEAT );
1220 				if ( !stage->bundle[0].image )
1221 				{
1222 					ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
1223 					return qfalse;
1224 				}
1225 			}
1226 		}
1227 		//
1228 		// clampmap <name>
1229 		//
1230 		else if ( !Q_stricmp( token, "clampmap" ) )
1231 		{
1232 			token = COM_ParseExt( text, qfalse );
1233 			if ( !token[0] )
1234 			{
1235 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name );
1236 				return qfalse;
1237 			}
1238 			stage->bundle[0].image = R_FindImageFile( token, (qboolean)!shader.noMipMaps, (qboolean)!shader.noPicMip, (qboolean)!shader.noTC, GL_CLAMP );
1239 			if ( !stage->bundle[0].image )
1240 			{
1241 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
1242 				return qfalse;
1243 			}
1244 		}
1245 		//
1246 		// animMap <frequency> <image1> .... <imageN>
1247 		//
1248 		else if ( !Q_stricmp( token, "animMap" ) || !Q_stricmp( token, "clampanimMap" ) || !Q_stricmp( token, "oneshotanimMap" ))
1249 		{
1250 			#define	MAX_IMAGE_ANIMATIONS	32
1251 			image_t *images[MAX_IMAGE_ANIMATIONS];
1252 			bool bClamp = !Q_stricmp( token, "clampanimMap" );
1253 			bool oneShot = !Q_stricmp( token, "oneshotanimMap" );
1254 
1255 			token = COM_ParseExt( text, qfalse );
1256 			if ( !token[0] )
1257 			{
1258 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parameter for '%s' keyword in shader '%s'\n", (bClamp ? "animMap":"clampanimMap"), shader.name );
1259 				return qfalse;
1260 			}
1261 			stage->bundle[0].imageAnimationSpeed = atof( token );
1262 			stage->bundle[0].oneShotAnimMap = oneShot;
1263 
1264 			// parse up to MAX_IMAGE_ANIMATIONS animations
1265 			while ( 1 ) {
1266 				int		num;
1267 
1268 				token = COM_ParseExt( text, qfalse );
1269 				if ( !token[0] ) {
1270 					break;
1271 				}
1272 				num = stage->bundle[0].numImageAnimations;
1273 				if ( num < MAX_IMAGE_ANIMATIONS ) {
1274 					images[num] = R_FindImageFile( token, (qboolean)!shader.noMipMaps, (qboolean)!shader.noPicMip, (qboolean)!shader.noTC, bClamp?GL_CLAMP:GL_REPEAT );
1275 					if ( !images[num] )
1276 					{
1277 						ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
1278 						return qfalse;
1279 					}
1280 					stage->bundle[0].numImageAnimations++;
1281 				}
1282 			}
1283 			// Copy image ptrs into an array of ptrs
1284 			stage->bundle[0].image = (image_t*) Hunk_Alloc( stage->bundle[0].numImageAnimations * sizeof( image_t* ), h_low );
1285 			memcpy( stage->bundle[0].image,	images,			stage->bundle[0].numImageAnimations * sizeof( image_t* ) );
1286 		}
1287 		else if ( !Q_stricmp( token, "videoMap" ) )
1288 		{
1289 			token = COM_ParseExt( text, qfalse );
1290 			if ( !token[0] )
1291 			{
1292 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parameter for 'videoMap' keyword in shader '%s'\n", shader.name );
1293 				return qfalse;
1294 			}
1295 			stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader));
1296 			if (stage->bundle[0].videoMapHandle != -1) {
1297 				stage->bundle[0].isVideoMap = qtrue;
1298 				assert (stage->bundle[0].videoMapHandle<NUM_SCRATCH_IMAGES);
1299 				stage->bundle[0].image = tr.scratchImage[stage->bundle[0].videoMapHandle];
1300 			}
1301 		}
1302 
1303 		//
1304 		// alphafunc <func>
1305 		//
1306 		else if ( !Q_stricmp( token, "alphaFunc" ) )
1307 		{
1308 			token = COM_ParseExt( text, qfalse );
1309 			if ( !token[0] )
1310 			{
1311 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name );
1312 				return qfalse;
1313 			}
1314 
1315 			atestBits = NameToAFunc( token );
1316 		}
1317 		//
1318 		// depthFunc <func>
1319 		//
1320 		else if ( !Q_stricmp( token, "depthfunc" ) )
1321 		{
1322 			token = COM_ParseExt( text, qfalse );
1323 
1324 			if ( !token[0] )
1325 			{
1326 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name );
1327 				return qfalse;
1328 			}
1329 
1330 			if ( !Q_stricmp( token, "lequal" ) )
1331 			{
1332 				depthFuncBits = 0;
1333 			}
1334 			else if ( !Q_stricmp( token, "equal" ) )
1335 			{
1336 				depthFuncBits = GLS_DEPTHFUNC_EQUAL;
1337 			}
1338 			else if ( !Q_stricmp( token, "disable" ) )
1339 			{
1340 				depthFuncBits = GLS_DEPTHTEST_DISABLE;
1341 			}
1342 			else
1343 			{
1344 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name );
1345 				continue;
1346 			}
1347 		}
1348 		//
1349 		// detail
1350 		//
1351 		else if ( !Q_stricmp( token, "detail" ) )
1352 		{
1353 			stage->isDetail = qtrue;
1354 		}
1355 		//
1356 		// blendfunc <srcFactor> <dstFactor>
1357 		// or blendfunc <add|filter|blend>
1358 		//
1359 		else if ( !Q_stricmp( token, "blendfunc" ) )
1360 		{
1361 			token = COM_ParseExt( text, qfalse );
1362 			if ( token[0] == 0 )
1363 			{
1364 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
1365 				continue;
1366 			}
1367 			// check for "simple" blends first
1368 			if ( !Q_stricmp( token, "add" ) ) {
1369 				blendSrcBits = GLS_SRCBLEND_ONE;
1370 				blendDstBits = GLS_DSTBLEND_ONE;
1371 			} else if ( !Q_stricmp( token, "filter" ) ) {
1372 				blendSrcBits = GLS_SRCBLEND_DST_COLOR;
1373 				blendDstBits = GLS_DSTBLEND_ZERO;
1374 			} else if ( !Q_stricmp( token, "blend" ) ) {
1375 				blendSrcBits = GLS_SRCBLEND_SRC_ALPHA;
1376 				blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
1377 			} else {
1378 				// complex double blends
1379 				blendSrcBits = NameToSrcBlendMode( token );
1380 
1381 				token = COM_ParseExt( text, qfalse );
1382 				if ( token[0] == 0 )
1383 				{
1384 					ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
1385 					continue;
1386 				}
1387 				blendDstBits = NameToDstBlendMode( token );
1388 			}
1389 
1390 			// clear depth mask for blended surfaces
1391 			if ( !depthMaskExplicit )
1392 			{
1393 				depthMaskBits = 0;
1394 			}
1395 		}
1396 		//
1397 		// rgbGen
1398 		//
1399 		else if ( !Q_stricmp( token, "rgbGen" ) )
1400 		{
1401 			token = COM_ParseExt( text, qfalse );
1402 			if ( token[0] == 0 )
1403 			{
1404 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name );
1405 				continue;
1406 			}
1407 
1408 			if ( !Q_stricmp( token, "wave" ) )
1409 			{
1410 				ParseWaveForm( text, &stage->rgbWave );
1411 				stage->rgbGen = CGEN_WAVEFORM;
1412 			}
1413 			else if ( !Q_stricmp( token, "const" ) )
1414 			{
1415 				vec3_t	color;
1416 
1417 				VectorClear( color );
1418 
1419 				ParseVector( text, 3, color );
1420 				stage->constantColor[0] = 255 * color[0];
1421 				stage->constantColor[1] = 255 * color[1];
1422 				stage->constantColor[2] = 255 * color[2];
1423 
1424 				stage->rgbGen = CGEN_CONST;
1425 			}
1426 			else if ( !Q_stricmp( token, "identity" ) )
1427 			{
1428 				stage->rgbGen = CGEN_IDENTITY;
1429 			}
1430 			else if ( !Q_stricmp( token, "identityLighting" ) )
1431 			{
1432 				stage->rgbGen = CGEN_IDENTITY_LIGHTING;
1433 			}
1434 			else if ( !Q_stricmp( token, "entity" ) )
1435 			{
1436 				stage->rgbGen = CGEN_ENTITY;
1437 			}
1438 			else if ( !Q_stricmp( token, "oneMinusEntity" ) )
1439 			{
1440 				stage->rgbGen = CGEN_ONE_MINUS_ENTITY;
1441 			}
1442 			else if ( !Q_stricmp( token, "vertex" ) )
1443 			{
1444 				stage->rgbGen = CGEN_VERTEX;
1445 				if ( stage->alphaGen == 0 ) {
1446 					stage->alphaGen = AGEN_VERTEX;
1447 				}
1448 			}
1449 			else if ( !Q_stricmp( token, "exactVertex" ) )
1450 			{
1451 				stage->rgbGen = CGEN_EXACT_VERTEX;
1452 			}
1453 			else if ( !Q_stricmp( token, "lightingDiffuse" ) )
1454 			{
1455 				stage->rgbGen = CGEN_LIGHTING_DIFFUSE;
1456 
1457 			}
1458 			else if ( !Q_stricmp( token, "lightingDiffuseEntity" ) )
1459 			{
1460 				if (shader.lightmapIndex[0] != LIGHTMAP_NONE)
1461 				{
1462 					ri.Printf( PRINT_ALL, S_COLOR_RED "ERROR: rgbGen lightingDiffuseEntity used on a misc_model! in shader '%s'\n", shader.name );
1463 				}
1464 				stage->rgbGen = CGEN_LIGHTING_DIFFUSE_ENTITY;
1465 
1466 			}
1467 			else if ( !Q_stricmp( token, "oneMinusVertex" ) )
1468 			{
1469 				stage->rgbGen = CGEN_ONE_MINUS_VERTEX;
1470 			}
1471 			else
1472 			{
1473 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name );
1474 				continue;
1475 			}
1476 		}
1477 		//
1478 		// alphaGen
1479 		//
1480 		else if ( !Q_stricmp( token, "alphaGen" ) )
1481 		{
1482 			token = COM_ParseExt( text, qfalse );
1483 			if ( token[0] == 0 )
1484 			{
1485 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name );
1486 				continue;
1487 			}
1488 
1489 			if ( !Q_stricmp( token, "wave" ) )
1490 			{
1491 				ParseWaveForm( text, &stage->alphaWave );
1492 				stage->alphaGen = AGEN_WAVEFORM;
1493 			}
1494 			else if ( !Q_stricmp( token, "const" ) )
1495 			{
1496 				token = COM_ParseExt( text, qfalse );
1497 				stage->constantColor[3] = 255 * atof( token );
1498 				stage->alphaGen = AGEN_CONST;
1499 			}
1500 			else if ( !Q_stricmp( token, "identity" ) )
1501 			{
1502 				stage->alphaGen = AGEN_IDENTITY;
1503 			}
1504 			else if ( !Q_stricmp( token, "entity" ) )
1505 			{
1506 				stage->alphaGen = AGEN_ENTITY;
1507 			}
1508 			else if ( !Q_stricmp( token, "oneMinusEntity" ) )
1509 			{
1510 				stage->alphaGen = AGEN_ONE_MINUS_ENTITY;
1511 			}
1512 			else if ( !Q_stricmp( token, "vertex" ) )
1513 			{
1514 				stage->alphaGen = AGEN_VERTEX;
1515 			}
1516 			else if ( !Q_stricmp( token, "lightingSpecular" ) )
1517 			{
1518 				stage->alphaGen = AGEN_LIGHTING_SPECULAR;
1519 			}
1520 			else if ( !Q_stricmp( token, "oneMinusVertex" ) )
1521 			{
1522 				stage->alphaGen = AGEN_ONE_MINUS_VERTEX;
1523 			}
1524 			else if ( !Q_stricmp( token, "dot" ) )
1525 			{
1526 				stage->alphaGen = AGEN_DOT;
1527 			}
1528 			else if ( !Q_stricmp( token, "oneMinusDot" ) )
1529 			{
1530 				stage->alphaGen = AGEN_ONE_MINUS_DOT;
1531 			}
1532 			else if ( !Q_stricmp( token, "portal" ) )
1533 			{
1534 				stage->alphaGen = AGEN_PORTAL;
1535 				token = COM_ParseExt( text, qfalse );
1536 				if ( token[0] == 0 )
1537 				{
1538 					shader.portalRange = 256;
1539 					ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name );
1540 				}
1541 				else
1542 				{
1543 					shader.portalRange = atof( token );
1544 				}
1545 			}
1546 			else
1547 			{
1548 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name );
1549 				continue;
1550 			}
1551 		}
1552 		//
1553 		// tcGen <function>
1554 		//
1555 		else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) )
1556 		{
1557 			token = COM_ParseExt( text, qfalse );
1558 			if ( token[0] == 0 )
1559 			{
1560 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing texgen parm in shader '%s'\n", shader.name );
1561 				continue;
1562 			}
1563 
1564 			if ( !Q_stricmp( token, "environment" ) )
1565 			{
1566 				stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED;
1567 			}
1568 			else if ( !Q_stricmp( token, "lightmap" ) )
1569 			{
1570 				stage->bundle[0].tcGen = TCGEN_LIGHTMAP;
1571 			}
1572 			else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) )
1573 			{
1574 				stage->bundle[0].tcGen = TCGEN_TEXTURE;
1575 			}
1576 			else if ( !Q_stricmp( token, "vector" ) )
1577 			{
1578 				stage->bundle[0].tcGenVectors = ( vec3_t *) Hunk_Alloc( 2 * sizeof( vec3_t ), h_low );
1579 				ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] );
1580 				ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] );
1581 
1582 				stage->bundle[0].tcGen = TCGEN_VECTOR;
1583 			}
1584 			else
1585 			{
1586 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: unknown texgen parm in shader '%s'\n", shader.name );
1587 			}
1588 		}
1589 		//
1590 		// tcMod <type> <...>
1591 		//
1592 		else if ( !Q_stricmp( token, "tcMod" ) )
1593 		{
1594 			char buffer[1024] = "";
1595 
1596 			while ( 1 )
1597 			{
1598 				token = COM_ParseExt( text, qfalse );
1599 				if ( token[0] == 0 )
1600 					break;
1601 				Q_strcat( buffer, sizeof( buffer ), token );
1602 				Q_strcat( buffer, sizeof( buffer ), " " );
1603 			}
1604 
1605 			ParseTexMod( buffer, stage );
1606 
1607 			continue;
1608 		}
1609 		//
1610 		// depthmask
1611 		//
1612 		else if ( !Q_stricmp( token, "depthwrite" ) )
1613 		{
1614 			depthMaskBits = GLS_DEPTHMASK_TRUE;
1615 			depthMaskExplicit = qtrue;
1616 
1617 			continue;
1618 		}
1619 		// If this stage has glow...	GLOWXXX
1620 		else if ( Q_stricmp( token, "glow" ) == 0 )
1621 		{
1622 			stage->glow = true;
1623 
1624 			continue;
1625 		}
1626 		//
1627 		// surfaceSprites <type> ...
1628 		//
1629 		else if ( !Q_stricmp( token, "surfaceSprites" ) )
1630 		{
1631 			char buffer[1024] = "";
1632 
1633 			while ( 1 )
1634 			{
1635 				token = COM_ParseExt( text, qfalse );
1636 				if ( token[0] == 0 )
1637 					break;
1638 				Q_strcat( buffer, sizeof( buffer ), token );
1639 				Q_strcat( buffer, sizeof( buffer ), " " );
1640 			}
1641 
1642 			ParseSurfaceSprites( buffer, stage );
1643 
1644 			continue;
1645 		}
1646 		//
1647 		// ssFademax <fademax>
1648 		// ssFadescale <fadescale>
1649 		// ssVariance <varwidth> <varheight>
1650 		// ssHangdown
1651 		// ssAnyangle
1652 		// ssFaceup
1653 		// ssWind <wind>
1654 		// ssWindIdle <windidle>
1655 		// ssDuration <duration>
1656 		// ssGrow <growwidth> <growheight>
1657 		// ssWeather
1658 		//
1659 		else if (!Q_stricmpn(token, "ss", 2))	// <--- NOTE ONLY COMPARING FIRST TWO LETTERS
1660 		{
1661 			char buffer[1024] = "";
1662 			char param[128];
1663 			strcpy(param,token);
1664 
1665 			while ( 1 )
1666 			{
1667 				token = COM_ParseExt( text, qfalse );
1668 				if ( token[0] == 0 )
1669 					break;
1670 				Q_strcat( buffer, sizeof( buffer ), token );
1671 				Q_strcat( buffer, sizeof( buffer ), " " );
1672 			}
1673 
1674 			ParseSurfaceSpritesOptional( param, buffer, stage );
1675 
1676 			continue;
1677 		}
1678 		else
1679 		{
1680 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name );
1681 			return qfalse;
1682 		}
1683 	}
1684 
1685 	//
1686 	// if cgen isn't explicitly specified, use either identity or identitylighting
1687 	//
1688 	if ( stage->rgbGen == CGEN_BAD ) {
1689 		if ( //blendSrcBits == 0 ||
1690 			blendSrcBits == GLS_SRCBLEND_ONE ||
1691 			blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) {
1692 			stage->rgbGen = CGEN_IDENTITY_LIGHTING;
1693 		} else {
1694 			stage->rgbGen = CGEN_IDENTITY;
1695 		}
1696 	}
1697 
1698 
1699 	//
1700 	// implicitly assume that a GL_ONE GL_ZERO blend mask disables blending
1701 	//
1702 	if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) &&
1703 		 ( blendDstBits == GLS_DSTBLEND_ZERO ) )
1704 	{
1705 		blendDstBits = blendSrcBits = 0;
1706 		depthMaskBits = GLS_DEPTHMASK_TRUE;
1707 	}
1708 
1709 	// decide which agens we can skip
1710 	if ( stage->alphaGen == AGEN_IDENTITY ) {
1711 		if ( stage->rgbGen == CGEN_IDENTITY
1712 			|| stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) {
1713 			stage->alphaGen = AGEN_SKIP;
1714 		}
1715 	}
1716 
1717 	//
1718 	// compute state bits
1719 	//
1720 	stage->stateBits = depthMaskBits |
1721 		               blendSrcBits | blendDstBits |
1722 					   atestBits |
1723 					   depthFuncBits;
1724 
1725 	return qtrue;
1726 }
1727 
1728 /*
1729 ===============
1730 ParseDeform
1731 
1732 deformVertexes wave <spread> <waveform> <base> <amplitude> <phase> <frequency>
1733 deformVertexes normal <frequency> <amplitude>
1734 deformVertexes move <vector> <waveform> <base> <amplitude> <phase> <frequency>
1735 deformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed>
1736 deformVertexes projectionShadow
1737 deformVertexes autoSprite
1738 deformVertexes autoSprite2
1739 deformVertexes text[0-7]
1740 ===============
1741 */
ParseDeform(const char ** text)1742 static void ParseDeform( const char **text ) {
1743 	char	*token;
1744 	deformStage_t	*ds;
1745 
1746 	token = COM_ParseExt( text, qfalse );
1747 	if ( token[0] == 0 )
1748 	{
1749 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing deform parm in shader '%s'\n", shader.name );
1750 		return;
1751 	}
1752 
1753 	if ( shader.numDeforms == MAX_SHADER_DEFORMS ) {
1754 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name );
1755 		return;
1756 	}
1757 
1758 	shader.deforms[ shader.numDeforms ] = (deformStage_t *)Hunk_Alloc( sizeof( deformStage_t ), h_low );
1759 
1760 	ds = shader.deforms[ shader.numDeforms ];
1761 	shader.numDeforms++;
1762 
1763 	if ( !Q_stricmp( token, "projectionShadow" ) ) {
1764 		ds->deformation = DEFORM_PROJECTION_SHADOW;
1765 		return;
1766 	}
1767 
1768 	if ( !Q_stricmp( token, "autosprite" ) ) {
1769 		ds->deformation = DEFORM_AUTOSPRITE;
1770 		return;
1771 	}
1772 
1773 	if ( !Q_stricmp( token, "autosprite2" ) ) {
1774 		ds->deformation = DEFORM_AUTOSPRITE2;
1775 		return;
1776 	}
1777 
1778 	if ( !Q_stricmpn( token, "text", 4 ) ) {
1779 		int		n;
1780 
1781 		n = token[4] - '0';
1782 		if ( n < 0 || n > 7 ) {
1783 			n = 0;
1784 		}
1785 		ds->deformation = (deform_t)(DEFORM_TEXT0 + n);
1786 		return;
1787 	}
1788 
1789 	if ( !Q_stricmp( token, "bulge" ) )	{
1790 		token = COM_ParseExt( text, qfalse );
1791 		if ( token[0] == 0 )
1792 		{
1793 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
1794 			return;
1795 		}
1796 		ds->bulgeWidth = atof( token );
1797 
1798 		token = COM_ParseExt( text, qfalse );
1799 		if ( token[0] == 0 )
1800 		{
1801 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
1802 			return;
1803 		}
1804 		ds->bulgeHeight = atof( token );
1805 
1806 		token = COM_ParseExt( text, qfalse );
1807 		if ( token[0] == 0 )
1808 		{
1809 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
1810 			return;
1811 		}
1812 		ds->bulgeSpeed = atof( token );
1813 
1814 		ds->deformation = DEFORM_BULGE;
1815 		return;
1816 	}
1817 
1818 	if ( !Q_stricmp( token, "wave" ) )
1819 	{
1820 		token = COM_ParseExt( text, qfalse );
1821 		if ( token[0] == 0 )
1822 		{
1823 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
1824 			return;
1825 		}
1826 
1827 		if ( atof( token ) != 0 )
1828 		{
1829 			ds->deformationSpread = 1.0f / atof( token );
1830 		}
1831 		else
1832 		{
1833 			ds->deformationSpread = 100.0f;
1834 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name );
1835 		}
1836 
1837 		ParseWaveForm( text, &ds->deformationWave );
1838 		ds->deformation = DEFORM_WAVE;
1839 		return;
1840 	}
1841 
1842 	if ( !Q_stricmp( token, "normal" ) )
1843 	{
1844 		token = COM_ParseExt( text, qfalse );
1845 		if ( token[0] == 0 )
1846 		{
1847 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
1848 			return;
1849 		}
1850 		ds->deformationWave.amplitude = atof( token );
1851 
1852 		token = COM_ParseExt( text, qfalse );
1853 		if ( token[0] == 0 )
1854 		{
1855 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
1856 			return;
1857 		}
1858 		ds->deformationWave.frequency = atof( token );
1859 
1860 		ds->deformation = DEFORM_NORMALS;
1861 		return;
1862 	}
1863 
1864 	if ( !Q_stricmp( token, "move" ) ) {
1865 		int		i;
1866 
1867 		for ( i = 0 ; i < 3 ; i++ ) {
1868 			token = COM_ParseExt( text, qfalse );
1869 			if ( token[0] == 0 ) {
1870 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
1871 				return;
1872 			}
1873 			ds->moveVector[i] = atof( token );
1874 		}
1875 
1876 		ParseWaveForm( text, &ds->deformationWave );
1877 		ds->deformation = DEFORM_MOVE;
1878 		return;
1879 	}
1880 
1881 	ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name );
1882 }
1883 
1884 
1885 /*
1886 ===============
1887 ParseSkyParms
1888 
1889 skyParms <outerbox> <cloudheight> <innerbox>
1890 ===============
1891 */
ParseSkyParms(const char ** text)1892 static void ParseSkyParms( const char **text ) {
1893 	char		*token;
1894 	const char	*suf[6] = {"rt", "lf", "bk", "ft", "up", "dn"};
1895 	char		pathname[MAX_QPATH];
1896 	int			i;
1897 
1898 	shader.sky = (skyParms_t *)Hunk_Alloc( sizeof( skyParms_t ), h_low );
1899 
1900 	// outerbox
1901 	token = COM_ParseExt( text, qfalse );
1902 	if ( token[0] == 0 ) {
1903 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
1904 		return;
1905 	}
1906 	if ( strcmp( token, "-" ) ) {
1907 		for (i=0 ; i<6 ; i++) {
1908 			Com_sprintf( pathname, sizeof(pathname), "%s_%s", token, suf[i] );
1909 			shader.sky->outerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, (qboolean)!shader.noTC, GL_CLAMP );
1910 			if ( !shader.sky->outerbox[i] ) {
1911 				if (i) {
1912 					shader.sky->outerbox[i] = shader.sky->outerbox[i-1];//not found, so let's use the previous image
1913 				} else {
1914 					shader.sky->outerbox[i] = tr.defaultImage;
1915 				}
1916 			}
1917 		}
1918 	}
1919 
1920 	// cloudheight
1921 	token = COM_ParseExt( text, qfalse );
1922 	if ( token[0] == 0 ) {
1923 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: 'skyParms' missing cloudheight in shader '%s'\n", shader.name );
1924 		return;
1925 	}
1926 	shader.sky->cloudHeight = atof( token );
1927 	if ( !shader.sky->cloudHeight ) {
1928 		shader.sky->cloudHeight = 512;
1929 	}
1930 	R_InitSkyTexCoords( shader.sky->cloudHeight );
1931 
1932 	// innerbox
1933 	token = COM_ParseExt( text, qfalse );
1934 	if ( strcmp( token, "-" ) ) {
1935 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: in shader '%s' 'skyParms', innerbox is not supported!", shader.name);
1936 	}
1937 }
1938 
1939 
1940 /*
1941 =================
1942 ParseSort
1943 =================
1944 */
ParseSort(const char ** text)1945 static void ParseSort( const char **text ) {
1946 	char	*token;
1947 
1948 	token = COM_ParseExt( text, qfalse );
1949 	if ( token[0] == 0 ) {
1950 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing sort parameter in shader '%s'\n", shader.name );
1951 		return;
1952 	}
1953 
1954 	if ( !Q_stricmp( token, "portal" ) ) {
1955 		shader.sort = SS_PORTAL;
1956 	} else if ( !Q_stricmp( token, "sky" ) ) {
1957 		shader.sort = SS_ENVIRONMENT;
1958 	} else if ( !Q_stricmp( token, "opaque" ) ) {
1959 		shader.sort = SS_OPAQUE;
1960 	} else if ( !Q_stricmp( token, "decal" ) ) {
1961 		shader.sort = SS_DECAL;
1962 	} else if ( !Q_stricmp( token, "seeThrough" ) ) {
1963 		shader.sort = SS_SEE_THROUGH;
1964 	} else if ( !Q_stricmp( token, "banner" ) ) {
1965 		shader.sort = SS_BANNER;
1966 	} else if ( !Q_stricmp( token, "additive" ) ) {
1967 		shader.sort = SS_BLEND1;
1968 	} else if ( !Q_stricmp( token, "nearest" ) ) {
1969 		shader.sort = SS_NEAREST;
1970 	} else if ( !Q_stricmp( token, "underwater" ) ) {
1971 		shader.sort = SS_UNDERWATER;
1972 	} else if ( !Q_stricmp( token, "inside" ) ) {
1973 		shader.sort = SS_INSIDE;
1974 	} else if ( !Q_stricmp( token, "mid_inside" ) ) {
1975 		shader.sort = SS_MID_INSIDE;
1976 	} else if ( !Q_stricmp( token, "middle" ) ) {
1977 		shader.sort = SS_MIDDLE;
1978 	} else if ( !Q_stricmp( token, "mid_outside" ) ) {
1979 		shader.sort = SS_MID_OUTSIDE;
1980 	} else if ( !Q_stricmp( token, "outside" ) ) {
1981 		shader.sort = SS_OUTSIDE;
1982 	}
1983 	else {
1984 		shader.sort = atof( token );
1985 	}
1986 }
1987 
1988 /*
1989 =================
1990 ParseMaterial
1991 =================
1992 */
1993 const char *materialNames[MATERIAL_LAST] =
1994 {
1995 	MATERIALS
1996 };
1997 
ParseMaterial(const char ** text)1998 void ParseMaterial( const char **text )
1999 {
2000 	char	*token;
2001 	int		i;
2002 
2003 	token = COM_ParseExt( text, qfalse );
2004 	if ( token[0] == 0 )
2005 	{
2006 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing material in shader '%s'\n", shader.name );
2007 		return;
2008 	}
2009 	for(i = 0; i < MATERIAL_LAST; i++)
2010 	{
2011 		if ( !Q_stricmp( token, materialNames[i] ) )
2012 		{
2013 			shader.surfaceFlags |= i;
2014 			break;
2015 		}
2016 	}
2017 }
2018 
2019 
2020 // this table is also present in q3map
2021 
2022 typedef struct infoParm_s {
2023 	const char	*name;
2024 	uint32_t	clearSolid, surfaceFlags, contents;
2025 } infoParm_t;
2026 
2027 infoParm_t	infoParms[] = {
2028 	// Game content Flags
2029 	{ "nonsolid",		~CONTENTS_SOLID,					SURF_NONE,			CONTENTS_NONE },		// special hack to clear solid flag
2030 	{ "nonopaque",		~CONTENTS_OPAQUE,					SURF_NONE,			CONTENTS_NONE },		// special hack to clear opaque flag
2031 	{ "lava",			~CONTENTS_SOLID,					SURF_NONE,			CONTENTS_LAVA },		// very damaging
2032 	{ "slime",			~CONTENTS_SOLID,					SURF_NONE,			CONTENTS_SLIME },		// mildly damaging
2033 	{ "water",			~CONTENTS_SOLID,					SURF_NONE,			CONTENTS_WATER },		//
2034 	{ "fog",			~CONTENTS_SOLID,					SURF_NONE,			CONTENTS_FOG},			// carves surfaces entering
2035 	{ "shotclip",		~CONTENTS_SOLID,					SURF_NONE,			CONTENTS_SHOTCLIP },	// block shots, but not people
2036 	{ "playerclip",		~(CONTENTS_SOLID|CONTENTS_OPAQUE),	SURF_NONE,			CONTENTS_PLAYERCLIP },	// block only the player
2037 	{ "monsterclip",	~(CONTENTS_SOLID|CONTENTS_OPAQUE),	SURF_NONE,			CONTENTS_MONSTERCLIP },	//
2038 	{ "botclip",		~(CONTENTS_SOLID|CONTENTS_OPAQUE),	SURF_NONE,			CONTENTS_BOTCLIP },		// for bots
2039 	{ "trigger",		~(CONTENTS_SOLID|CONTENTS_OPAQUE),	SURF_NONE,			CONTENTS_TRIGGER },		//
2040 	{ "nodrop",			~(CONTENTS_SOLID|CONTENTS_OPAQUE),	SURF_NONE,			CONTENTS_NODROP },		// don't drop items or leave bodies (death fog, lava, etc)
2041 	{ "terrain",		~(CONTENTS_SOLID|CONTENTS_OPAQUE),	SURF_NONE,			CONTENTS_TERRAIN },		// use special terrain collsion
2042 	{ "ladder",			~(CONTENTS_SOLID|CONTENTS_OPAQUE),	SURF_NONE,			CONTENTS_LADDER },		// climb up in it like water
2043 	{ "abseil",			~(CONTENTS_SOLID|CONTENTS_OPAQUE),	SURF_NONE,			CONTENTS_ABSEIL },		// can abseil down this brush
2044 	{ "outside",		~(CONTENTS_SOLID|CONTENTS_OPAQUE),	SURF_NONE,			CONTENTS_OUTSIDE },		// volume is considered to be in the outside (i.e. not indoors)
2045 	{ "inside",			~(CONTENTS_SOLID|CONTENTS_OPAQUE),	SURF_NONE,			CONTENTS_INSIDE },		// volume is considered to be inside (i.e. indoors)
2046 
2047 	{ "detail",			CONTENTS_ALL,						SURF_NONE,			CONTENTS_DETAIL },		// don't include in structural bsp
2048 	{ "trans",			CONTENTS_ALL,						SURF_NONE,			CONTENTS_TRANSLUCENT },	// surface has an alpha component
2049 
2050 	/* Game surface flags */
2051 	{ "sky",			CONTENTS_ALL,						SURF_SKY,			CONTENTS_NONE },		// emit light from an environment map
2052 	{ "slick",			CONTENTS_ALL,						SURF_SLICK,			CONTENTS_NONE },		//
2053 
2054 	{ "nodamage",		CONTENTS_ALL,						SURF_NODAMAGE,		CONTENTS_NONE },		//
2055 	{ "noimpact",		CONTENTS_ALL,						SURF_NOIMPACT,		CONTENTS_NONE },		// don't make impact explosions or marks
2056 	{ "nomarks",		CONTENTS_ALL,						SURF_NOMARKS,		CONTENTS_NONE },		// don't make impact marks, but still explode
2057 	{ "nodraw",			CONTENTS_ALL,						SURF_NODRAW,		CONTENTS_NONE },		// don't generate a drawsurface (or a lightmap)
2058 	{ "nosteps",		CONTENTS_ALL,						SURF_NOSTEPS,		CONTENTS_NONE },		//
2059 	{ "nodlight",		CONTENTS_ALL,						SURF_NODLIGHT,		CONTENTS_NONE },		// don't ever add dynamic lights
2060 	{ "metalsteps",		CONTENTS_ALL,						SURF_METALSTEPS,	CONTENTS_NONE },		//
2061 	{ "nomiscents",		CONTENTS_ALL,						SURF_NOMISCENTS,	CONTENTS_NONE },		// No misc ents on this surface
2062 	{ "forcefield",		CONTENTS_ALL,						SURF_FORCEFIELD,	CONTENTS_NONE },		//
2063 	{ "forcesight",		CONTENTS_ALL,						SURF_FORCESIGHT,	CONTENTS_NONE },		// only visible with force sight
2064 };
2065 
2066 
2067 /*
2068 ===============
2069 ParseSurfaceParm
2070 
2071 surfaceparm <name>
2072 ===============
2073 */
ParseSurfaceParm(const char ** text)2074 static void ParseSurfaceParm( const char **text ) {
2075 	char	*token;
2076 	int		numInfoParms = sizeof(infoParms) / sizeof(infoParms[0]);
2077 	int		i;
2078 
2079 	token = COM_ParseExt( text, qfalse );
2080 	for ( i = 0 ; i < numInfoParms ; i++ ) {
2081 		if ( !Q_stricmp( token, infoParms[i].name ) ) {
2082 			shader.surfaceFlags |= infoParms[i].surfaceFlags;
2083 			shader.contentFlags |= infoParms[i].contents;
2084 			shader.contentFlags &= infoParms[i].clearSolid;
2085 			break;
2086 		}
2087 	}
2088 }
2089 
2090 /*
2091 =================
2092 ParseShader
2093 
2094 The current text pointer is at the explicit text definition of the
2095 shader.  Parse it into the global shader variable.  Later functions
2096 will optimize it.
2097 =================
2098 */
ParseShader(const char ** text)2099 static qboolean ParseShader( const char **text )
2100 {
2101 	char *token;
2102 	const char *begin = *text;
2103 	int s;
2104 
2105 	s = 0;
2106 
2107 	token = COM_ParseExt( text, qtrue );
2108 	if ( token[0] != '{' )
2109 	{
2110 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name );
2111 		return qfalse;
2112 	}
2113 
2114 	while ( 1 )
2115 	{
2116 		token = COM_ParseExt( text, qtrue );
2117 		if ( !token[0] )
2118 		{
2119 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: no concluding '}' in shader %s\n", shader.name );
2120 			return qfalse;
2121 		}
2122 
2123 		// end of shader definition
2124 		if ( token[0] == '}' )
2125 		{
2126 			break;
2127 		}
2128 		// stage definition
2129 		else if ( token[0] == '{' )
2130 		{
2131 			if ( s >= MAX_SHADER_STAGES ) {
2132 				ri.Printf( PRINT_WARNING, "WARNING: too many stages in shader %s (max is %i)\n", shader.name, MAX_SHADER_STAGES );
2133 				return qfalse;
2134 			}
2135 
2136 			if ( !ParseStage( &stages[s], text ) )
2137 			{
2138 				return qfalse;
2139 			}
2140 			stages[s].active = qtrue;
2141 			if ( stages[s].glow )
2142 			{
2143 				shader.hasGlow = true;
2144 			}
2145 			s++;
2146 			continue;
2147 		}
2148 		// skip stuff that only the QuakeEdRadient needs
2149 		else if ( !Q_stricmpn( token, "qer", 3 ) ) {
2150 			SkipRestOfLine( text );
2151 			continue;
2152 		}
2153 		// material deprecated as of 11 Jan 01
2154 		// material undeprecated as of 7 May 01 - q3map_material deprecated
2155 		else if ( !Q_stricmp( token, "material" ) || !Q_stricmp( token, "q3map_material" ) )
2156 		{
2157 			ParseMaterial( text );
2158 		}
2159 		// sun parms
2160 		else if ( !Q_stricmp( token, "sun" ) || !Q_stricmp( token, "q3map_sun" ) || !Q_stricmp( token, "q3map_sunExt" ) )
2161 		{
2162 			token = COM_ParseExt( text, qfalse );
2163 			tr.sunLight[0] = atof( token );
2164 			token = COM_ParseExt( text, qfalse );
2165 			tr.sunLight[1] = atof( token );
2166 			token = COM_ParseExt( text, qfalse );
2167 			tr.sunLight[2] = atof( token );
2168 
2169 			VectorNormalize( tr.sunLight );
2170 
2171 			token = COM_ParseExt( text, qfalse );
2172 			float a = atof( token );
2173 			VectorScale( tr.sunLight, a, tr.sunLight);
2174 
2175 			token = COM_ParseExt( text, qfalse );
2176 			a = atof( token );
2177 			a = a / 180 * M_PI;
2178 
2179 			token = COM_ParseExt( text, qfalse );
2180 			float b = atof( token );
2181 			b = b / 180 * M_PI;
2182 
2183 			tr.sunDirection[0] = cos( a ) * cos( b );
2184 			tr.sunDirection[1] = sin( a ) * cos( b );
2185 			tr.sunDirection[2] = sin( b );
2186 
2187 			SkipRestOfLine( text );
2188 			continue;
2189 		}
2190 		// q3map_surfacelight deprecated as of 16 Jul 01
2191 		else if ( !Q_stricmp( token, "surfacelight" ) || !Q_stricmp( token, "q3map_surfacelight" ) )
2192 		{
2193 			token = COM_ParseExt( text, qfalse );
2194 			tr.sunSurfaceLight = atoi( token );
2195 		}
2196 		else if ( !Q_stricmp( token, "lightColor" ) )
2197 		{
2198 			/*
2199 			if ( !ParseVector( text, 3, tr.sunAmbient ) )
2200 			{
2201 				return qfalse;
2202 			}
2203 			*/
2204 			//SP skips this so I'm skipping it here too.
2205 			SkipRestOfLine( text );
2206 			continue;
2207 		}
2208 		else if ( !Q_stricmp( token, "deformvertexes" ) || !Q_stricmp( token, "deform" )) {
2209 			ParseDeform( text );
2210 			continue;
2211 		}
2212 		else if ( !Q_stricmp( token, "tesssize" ) ) {
2213 			SkipRestOfLine( text );
2214 			continue;
2215 		}
2216 		else if ( !Q_stricmp( token, "clampTime" ) ) {
2217 			token = COM_ParseExt( text, qfalse );
2218 			if (token[0]) {
2219 				shader.clampTime = atof(token);
2220 			}
2221 		}
2222 		// skip stuff that only the q3map needs
2223 		else if ( !Q_stricmpn( token, "q3map", 5 ) ) {
2224 			SkipRestOfLine( text );
2225 			continue;
2226 		}
2227 		// skip stuff that only q3map or the server needs
2228 		else if ( !Q_stricmp( token, "surfaceParm" ) ) {
2229 			ParseSurfaceParm( text );
2230 			continue;
2231 		}
2232 		// no mip maps
2233 		else if ( !Q_stricmp( token, "nomipmaps" ) )
2234 		{
2235 			shader.noMipMaps = true;
2236 			shader.noPicMip = true;
2237 			continue;
2238 		}
2239 		// no picmip adjustment
2240 		else if ( !Q_stricmp( token, "nopicmip" ) )
2241 		{
2242 			shader.noPicMip = true;
2243 			continue;
2244 		}
2245 		else if ( !Q_stricmp( token, "noglfog" ) )
2246 		{
2247 			shader.fogPass = FP_NONE;
2248 			continue;
2249 		}
2250 		// polygonOffset
2251 		else if ( !Q_stricmp( token, "polygonOffset" ) )
2252 		{
2253 			shader.polygonOffset = true;
2254 			continue;
2255 		}
2256 		else if ( !Q_stricmp( token, "noTC" ) )
2257 		{
2258 			shader.noTC = true;
2259 			continue;
2260 		}
2261 		// entityMergable, allowing sprite surfaces from multiple entities
2262 		// to be merged into one batch.  This is a savings for smoke
2263 		// puffs and blood, but can't be used for anything where the
2264 		// shader calcs (not the surface function) reference the entity color or scroll
2265 		else if ( !Q_stricmp( token, "entityMergable" ) )
2266 		{
2267 			shader.entityMergable = true;
2268 			continue;
2269 		}
2270 		// fogParms
2271 		else if ( !Q_stricmp( token, "fogParms" ) )
2272 		{
2273 			shader.fogParms = (fogParms_t *)Hunk_Alloc( sizeof( fogParms_t ), h_low );
2274 			if ( !ParseVector( text, 3, shader.fogParms->color ) ) {
2275 				return qfalse;
2276 			}
2277 
2278 			token = COM_ParseExt( text, qfalse );
2279 			if ( !token[0] )
2280 			{
2281 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name );
2282 				continue;
2283 			}
2284 			shader.fogParms->depthForOpaque = atof( token );
2285 
2286 			// skip any old gradient directions
2287 			SkipRestOfLine( text );
2288 			continue;
2289 		}
2290 		// portal
2291 		else if ( !Q_stricmp(token, "portal") )
2292 		{
2293 			shader.sort = SS_PORTAL;
2294 			continue;
2295 		}
2296 		// skyparms <cloudheight> <outerbox> <innerbox>
2297 		else if ( !Q_stricmp( token, "skyparms" ) )
2298 		{
2299 			ParseSkyParms( text );
2300 			continue;
2301 		}
2302 		// light <value> determines flaring in q3map, not needed here
2303 		else if ( !Q_stricmp(token, "light") )
2304 		{
2305 			token = COM_ParseExt( text, qfalse );
2306 			continue;
2307 		}
2308 		// cull <face>
2309 		else if ( !Q_stricmp( token, "cull") )
2310 		{
2311 			token = COM_ParseExt( text, qfalse );
2312 			if ( token[0] == 0 )
2313 			{
2314 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: missing cull parms in shader '%s'\n", shader.name );
2315 				continue;
2316 			}
2317 
2318 			if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) )
2319 			{
2320 				shader.cullType = CT_TWO_SIDED;
2321 			}
2322 			else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) )
2323 			{
2324 				shader.cullType = CT_BACK_SIDED;
2325 			}
2326 			else
2327 			{
2328 				ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name );
2329 			}
2330 			continue;
2331 		}
2332 		// sort
2333 		else if ( !Q_stricmp( token, "sort" ) )
2334 		{
2335 			ParseSort( text );
2336 			continue;
2337 		}
2338 		else
2339 		{
2340 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name );
2341 			return qfalse;
2342 		}
2343 	}
2344 
2345 	//
2346 	// ignore shaders that don't have any stages, unless it is a sky or fog
2347 	//
2348 	if ( s == 0 && !shader.sky && !(shader.contentFlags & CONTENTS_FOG ) ) {
2349 		return qfalse;
2350 	}
2351 
2352 	shader.explicitlyDefined = true;
2353 
2354 	// The basejka rocket lock wedge shader uses the incorrect blending mode.
2355 	// It only worked because the shader state was not being set, and relied
2356 	// on previous state to be multiplied by alpha. Since fixing RB_RotatePic,
2357 	// the shader needs to be fixed here to render correctly.
2358 	//
2359 	// We match against the retail version of gfx/2d/wedge by calculating the
2360 	// hash value of the shader text, and comparing it against a precalculated
2361 	// value.
2362 	uint32_t shaderHash = generateHashValueForText( begin, *text - begin );
2363 	if ( shaderHash == RETAIL_ROCKET_WEDGE_SHADER_HASH &&
2364 		Q_stricmp( shader.name, "gfx/2d/wedge" ) == 0 )
2365 	{
2366 		stages[0].stateBits &= ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS);
2367 		stages[0].stateBits |= GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
2368 	}
2369 
2370 	// The basejka radar arrow contains an incorrect rgbGen of identity
2371 	// It only worked because the original code didn't check shaders at all,
2372 	// thus setcolor worked fine but with fixing RB_RotatePic it no longer
2373 	// functioned because rgbGen identity doesn't work with setcolor.
2374 	//
2375 	// We match against retail version of gfx/menus/radar/arrow_w by calculating
2376 	// the hash value of the shader text, and comparing it against a
2377 	// precalculated value.
2378 	if ( shaderHash == RETAIL_ARROW_W_SHADER_HASH &&
2379 		Q_stricmp( shader.name, "gfx/menus/radar/arrow_w" ) == 0 )
2380 	{
2381 		stages[0].rgbGen = CGEN_VERTEX;
2382 		stages[0].alphaGen = AGEN_VERTEX;
2383 	}
2384 
2385 	return qtrue;
2386 }
2387 
2388 /*
2389 ========================================================================================
2390 
2391 SHADER OPTIMIZATION AND FOGGING
2392 
2393 ========================================================================================
2394 */
2395 
2396 typedef struct collapse_s {
2397 	int		blendA;
2398 	int		blendB;
2399 
2400 	int		multitextureEnv;
2401 	int		multitextureBlend;
2402 } collapse_t;
2403 
2404 static collapse_t	collapse[] = {
2405 	{ 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
2406 		GL_MODULATE, 0 },
2407 
2408 	{ 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
2409 		GL_MODULATE, 0 },
2410 
2411 	{ GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
2412 		GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
2413 
2414 	{ GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
2415 		GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
2416 
2417 	{ GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
2418 		GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
2419 
2420 	{ GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
2421 		GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
2422 
2423 	{ 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
2424 		GL_ADD, 0 },
2425 
2426 	{ GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
2427 		GL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE },
2428 #if 0
2429 	{ 0, GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA,
2430 		GL_DECAL, 0 },
2431 #endif
2432 	{ -1 }
2433 };
2434 /*
2435 ================
2436 CollapseMultitexture
2437 
2438 Attempt to combine two stages into a single multitexture stage
2439 FIXME: I think modulated add + modulated add collapses incorrectly
2440 =================
2441 */
CollapseMultitexture(void)2442 static qboolean CollapseMultitexture( void ) {
2443 	int abits, bbits;
2444 	int i;
2445 	textureBundle_t tmpBundle;
2446 	if ( !qglActiveTextureARB ) {
2447 		return qfalse;
2448 	}
2449 
2450 	// make sure both stages are active
2451 	if ( !stages[0].active || !stages[1].active ) {
2452 		return qfalse;
2453 	}
2454 
2455 	abits = stages[0].stateBits;
2456 	bbits = stages[1].stateBits;
2457 
2458 	// make sure that both stages have identical state other than blend modes
2459 	if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) !=
2460 		( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) {
2461 		return qfalse;
2462 	}
2463 
2464 	abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
2465 	bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
2466 
2467 	// search for a valid multitexture blend function
2468 	for ( i = 0; collapse[i].blendA != -1 ; i++ ) {
2469 		if ( abits == collapse[i].blendA
2470 			&& bbits == collapse[i].blendB ) {
2471 			break;
2472 		}
2473 	}
2474 
2475 	// nothing found
2476 	if ( collapse[i].blendA == -1 ) {
2477 		return qfalse;
2478 	}
2479 
2480 	// GL_ADD is a separate extension
2481 	if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) {
2482 		return qfalse;
2483 	}
2484 
2485 	// make sure waveforms have identical parameters
2486 	if ( ( stages[0].rgbGen != stages[1].rgbGen ) ||
2487 		( stages[0].alphaGen != stages[1].alphaGen ) )  {
2488 		return qfalse;
2489 	}
2490 
2491 	// an add collapse can only have identity colors
2492 	if ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) {
2493 		return qfalse;
2494 	}
2495 
2496 	if ( stages[0].rgbGen == CGEN_WAVEFORM )
2497 	{
2498 		if ( memcmp( &stages[0].rgbWave,
2499 					 &stages[1].rgbWave,
2500 					 sizeof( stages[0].rgbWave ) ) )
2501 		{
2502 			return qfalse;
2503 		}
2504 	}
2505 	if ( stages[0].alphaGen == AGEN_WAVEFORM )
2506 	{
2507 		if ( memcmp( &stages[0].alphaWave,
2508 					 &stages[1].alphaWave,
2509 					 sizeof( stages[0].alphaWave ) ) )
2510 		{
2511 			return qfalse;
2512 		}
2513 	}
2514 
2515 
2516 	// make sure that lightmaps are in bundle 1 for 3dfx
2517 	if ( stages[0].bundle[0].isLightmap )
2518 	{
2519 		tmpBundle = stages[0].bundle[0];
2520 		stages[0].bundle[0] = stages[1].bundle[0];
2521 		stages[0].bundle[1] = tmpBundle;
2522 	}
2523 	else
2524 	{
2525 		stages[0].bundle[1] = stages[1].bundle[0];
2526 	}
2527 
2528 	// set the new blend state bits
2529 	shader.multitextureEnv = collapse[i].multitextureEnv;
2530 	stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
2531 	stages[0].stateBits |= collapse[i].multitextureBlend;
2532 
2533 	//
2534 	// move down subsequent shaders
2535 	//
2536 	memmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) );
2537 	memset( &stages[MAX_SHADER_STAGES-1], 0, sizeof( stages[0] ) );
2538 	return qtrue;
2539 }
2540 
2541 /*
2542 =============
2543 
2544 FixRenderCommandList
2545 https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
2546 Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated
2547 but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces
2548 to be rendered with bad shaders. To fix this, need to go through all render commands and fix
2549 sortedIndex.
2550 ==============
2551 */
2552 extern bool gServerSkinHack;
FixRenderCommandList(int newShader)2553 static void FixRenderCommandList( int newShader ) {
2554 	if( !gServerSkinHack ) {
2555 		renderCommandList_t	*cmdList = &backEndData->commands;
2556 
2557 		if( cmdList ) {
2558 			const void *curCmd = cmdList->cmds;
2559 
2560 			while ( 1 ) {
2561 				curCmd = PADP(curCmd, sizeof(void *));
2562 
2563 				switch ( *(const int *)curCmd ) {
2564 				case RC_SET_COLOR:
2565 					{
2566 					const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd;
2567 					curCmd = (const void *)(sc_cmd + 1);
2568 					break;
2569 					}
2570 				case RC_STRETCH_PIC:
2571 					{
2572 					const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd;
2573 					curCmd = (const void *)(sp_cmd + 1);
2574 					break;
2575 					}
2576 				case RC_ROTATE_PIC:
2577 					{
2578 					const rotatePicCommand_t *sp_cmd = (const rotatePicCommand_t *)curCmd;
2579 					curCmd = (const void *)(sp_cmd + 1);
2580 					break;
2581 					}
2582 				case RC_ROTATE_PIC2:
2583 					{
2584 					const rotatePicCommand_t *sp_cmd = (const rotatePicCommand_t *)curCmd;
2585 					curCmd = (const void *)(sp_cmd + 1);
2586 					break;
2587 					}
2588 				case RC_DRAW_SURFS:
2589 					{
2590 					int i;
2591 					drawSurf_t	*drawSurf;
2592 					shader_t	*shader;
2593 					int			fogNum;
2594 					int			entityNum;
2595 					int			dlightMap;
2596 					int			sortedIndex;
2597 					const drawSurfsCommand_t *ds_cmd =  (const drawSurfsCommand_t *)curCmd;
2598 
2599 					for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) {
2600 						R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap );
2601 						sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1));
2602 						if( sortedIndex >= newShader ) {
2603 							sortedIndex++;
2604 							drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | (entityNum << QSORT_REFENTITYNUM_SHIFT) | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
2605 						}
2606 					}
2607 					curCmd = (const void *)(ds_cmd + 1);
2608 					break;
2609 					}
2610 				case RC_DRAW_BUFFER:
2611 				case RC_WORLD_EFFECTS:
2612 				case RC_AUTO_MAP:
2613 					{
2614 					const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd;
2615 					curCmd = (const void *)(db_cmd + 1);
2616 					break;
2617 					}
2618 				case RC_SWAP_BUFFERS:
2619 					{
2620 					const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd;
2621 					curCmd = (const void *)(sb_cmd + 1);
2622 					break;
2623 					}
2624 				case RC_END_OF_LIST:
2625 				default:
2626 					return;
2627 				}
2628 			}
2629 		}
2630 	}
2631 }
2632 
2633 /*
2634 ==============
2635 SortNewShader
2636 
2637 Positions the most recently created shader in the tr.sortedShaders[]
2638 array so that the shader->sort key is sorted reletive to the other
2639 shaders.
2640 
2641 Sets shader->sortedIndex
2642 ==============
2643 */
SortNewShader(void)2644 static void SortNewShader( void ) {
2645 	int		i;
2646 	float	sort;
2647 	shader_t	*newShader;
2648 
2649 	newShader = tr.shaders[ tr.numShaders - 1 ];
2650 	sort = newShader->sort;
2651 
2652 	for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) {
2653 		if ( tr.sortedShaders[ i ]->sort <= sort ) {
2654 			break;
2655 		}
2656 		tr.sortedShaders[i+1] = tr.sortedShaders[i];
2657 		tr.sortedShaders[i+1]->sortedIndex++;
2658 	}
2659 
2660 	// Arnout: fix rendercommandlist
2661 	// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
2662 	FixRenderCommandList( i+1 );
2663 
2664 	newShader->sortedIndex = i+1;
2665 	tr.sortedShaders[i+1] = newShader;
2666 }
2667 
2668 
2669 /*
2670 ====================
2671 GeneratePermanentShader
2672 ====================
2673 */
GeneratePermanentShader(void)2674 static shader_t *GeneratePermanentShader( void ) {
2675 	shader_t	*newShader;
2676 	int			i, b;
2677 	int			size;
2678 
2679 	if ( tr.numShaders == MAX_SHADERS ) {
2680 		//ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n");
2681 		ri.Printf( PRINT_ALL, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n");
2682 		return tr.defaultShader;
2683 	}
2684 
2685 	newShader = (struct shader_s *)ri.Hunk_Alloc( sizeof( shader_t ), h_low );
2686 
2687 	*newShader = shader;
2688 
2689 	if ( shader.sort <= /*SS_OPAQUE*/SS_SEE_THROUGH ) {
2690 		newShader->fogPass = FP_EQUAL;
2691 	} else if ( shader.contentFlags & CONTENTS_FOG ) {
2692 		newShader->fogPass = FP_LE;
2693 	}
2694 
2695 	tr.shaders[ tr.numShaders ] = newShader;
2696 	newShader->index = tr.numShaders;
2697 
2698 	tr.sortedShaders[ tr.numShaders ] = newShader;
2699 	newShader->sortedIndex = tr.numShaders;
2700 
2701 	tr.numShaders++;
2702 
2703 	size = newShader->numUnfoggedPasses ? newShader->numUnfoggedPasses * sizeof( stages[0] ) : sizeof( stages[0] );
2704 	newShader->stages = (shaderStage_t *) Hunk_Alloc( size, h_low );
2705 
2706 	for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) {
2707 		if ( !stages[i].active ) {
2708 			break;
2709 		}
2710 		newShader->stages[i] = stages[i];
2711 
2712 		for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) {
2713 			if (newShader->stages[i].bundle[b].numTexMods)
2714 			{
2715 				size = newShader->stages[i].bundle[b].numTexMods * sizeof( texModInfo_t );
2716 				newShader->stages[i].bundle[b].texMods = (texModInfo_t *)Hunk_Alloc( size, h_low );
2717 				memcpy( newShader->stages[i].bundle[b].texMods, stages[i].bundle[b].texMods, size );
2718 			}
2719 			else
2720 			{
2721 				newShader->stages[i].bundle[b].texMods = 0;	//clear the globabl ptr jic
2722 			}
2723 		}
2724 	}
2725 
2726 	SortNewShader();
2727 
2728 	const int hash = generateHashValue(newShader->name, FILE_HASH_SIZE);
2729 	newShader->next = hashTable[hash];
2730 	hashTable[hash] = newShader;
2731 
2732 	return newShader;
2733 }
2734 
2735 /*
2736 =================
2737 VertexLightingCollapse
2738 
2739 If vertex lighting is enabled, only render a single
2740 pass, trying to guess which is the correct one to best approximate
2741 what it is supposed to look like.
2742 
2743   OUTPUT:  Number of stages after the collapse (in the case of surfacesprites this isn't one).
2744 =================
2745 */
2746 //rww - no longer used, at least for now. destroys alpha shaders completely.
2747 #if 0
2748 static int VertexLightingCollapse( void ) {
2749 	int		stage, nextopenstage;
2750 	shaderStage_t	*bestStage;
2751 	int		bestImageRank;
2752 	int		rank;
2753 	int		finalstagenum=1;
2754 
2755 	// if we aren't opaque, just use the first pass
2756 	if ( shader.sort == SS_OPAQUE ) {
2757 
2758 		// pick the best texture for the single pass
2759 		bestStage = &stages[0];
2760 		bestImageRank = -999999;
2761 
2762 		for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {
2763 			shaderStage_t *pStage = &stages[stage];
2764 
2765 			if ( !pStage->active ) {
2766 				break;
2767 			}
2768 			rank = 0;
2769 
2770 			if ( pStage->bundle[0].isLightmap ) {
2771 				rank -= 100;
2772 			}
2773 			if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) {
2774 				rank -= 5;
2775 			}
2776 			if ( pStage->bundle[0].numTexMods ) {
2777 				rank -= 5;
2778 			}
2779 			if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) {
2780 				rank -= 3;
2781 			}
2782 
2783 			// SurfaceSprites are most certainly NOT desireable as the collapsed surface texture.
2784 			if ( pStage->ss && pstage->ss->surfaceSpriteType)
2785 			{
2786 				rank -= 1000;
2787 			}
2788 
2789 			if ( rank > bestImageRank  ) {
2790 				bestImageRank = rank;
2791 				bestStage = pStage;
2792 			}
2793 		}
2794 
2795 		stages[0].bundle[0] = bestStage->bundle[0];
2796 		stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
2797 		stages[0].stateBits |= GLS_DEPTHMASK_TRUE;
2798 		if ( shader.lightmapIndex[0] == LIGHTMAP_NONE ) {
2799 			stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
2800 		} else {
2801 			stages[0].rgbGen = CGEN_EXACT_VERTEX;
2802 		}
2803 		stages[0].alphaGen = AGEN_SKIP;
2804 	} else {
2805 		// don't use a lightmap (tesla coils)
2806 		if ( stages[0].bundle[0].isLightmap ) {
2807 			stages[0] = stages[1];
2808 		}
2809 
2810 		// if we were in a cross-fade cgen, hack it to normal
2811 		if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) {
2812 			stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
2813 		}
2814 		if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH )
2815 			&& ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) {
2816 			stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
2817 		}
2818 		if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH )
2819 			&& ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) {
2820 			stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
2821 		}
2822 	}
2823 
2824 	for ( stage=1, nextopenstage=1; stage < MAX_SHADER_STAGES; stage++ ) {
2825 		shaderStage_t *pStage = &stages[stage];
2826 
2827 		if ( !pStage->active ) {
2828 			break;
2829 		}
2830 
2831 		if ( pStage->ss && pstage->ss->surfaceSpriteType)
2832 		{
2833 			// Copy this stage to the next open stage list (that is, we don't want any inactive stages before this one)
2834 			if (nextopenstage != stage)
2835 			{
2836 				stages[nextopenstage] = *pStage;
2837 				stages[nextopenstage].bundle[0] = pStage->bundle[0];
2838 			}
2839 			nextopenstage++;
2840 			finalstagenum++;
2841 			continue;
2842 		}
2843 
2844 		memset( pStage, 0, sizeof( *pStage ) );
2845 	}
2846 
2847 	return finalstagenum;
2848 }
2849 #endif
2850 
2851 /*
2852 =========================
2853 FinishShader
2854 
2855 Returns a freshly allocated shader with all the needed info
2856 from the current global working shader
2857 =========================
2858 */
FinishShader(void)2859 static shader_t *FinishShader( void ) {
2860 	int				stage, lmStage, stageIndex; //rwwRMG - stageIndex for AGEN_BLEND
2861 	qboolean		hasLightmapStage;
2862 	qboolean		vertexLightmap;
2863 
2864 	hasLightmapStage = qfalse;
2865 	vertexLightmap = qfalse;
2866 
2867 	//
2868 	// set sky stuff appropriate
2869 	//
2870 	if ( shader.sky ) {
2871 		shader.sort = SS_ENVIRONMENT;
2872 	}
2873 
2874 	//
2875 	// set polygon offset
2876 	//
2877 	if ( shader.polygonOffset && !shader.sort ) {
2878 		shader.sort = SS_DECAL;
2879 	}
2880 
2881 	for(lmStage = 0; lmStage < MAX_SHADER_STAGES; lmStage++)
2882 	{
2883 		shaderStage_t *pStage = &stages[lmStage];
2884 		if (pStage->active && pStage->bundle[0].isLightmap)
2885 		{
2886 			break;
2887 		}
2888 	}
2889 
2890 	if (lmStage < MAX_SHADER_STAGES)
2891 	{
2892 		if (shader.lightmapIndex[0] == LIGHTMAP_BY_VERTEX)
2893 		{
2894 			if (lmStage == 0)	//< MAX_SHADER_STAGES-1)
2895 			{//copy the rest down over the lightmap slot
2896 				memmove(&stages[lmStage], &stages[lmStage+1], sizeof(shaderStage_t) * (MAX_SHADER_STAGES-lmStage-1));
2897 				memset(&stages[MAX_SHADER_STAGES-1], 0, sizeof(shaderStage_t));
2898 				//change blending on the moved down stage
2899 				stages[lmStage].stateBits = GLS_DEFAULT;
2900 			}
2901 			//change anything that was moved down (or the *white if LM is first) to use vertex color
2902 			stages[lmStage].rgbGen = CGEN_EXACT_VERTEX;
2903 			stages[lmStage].alphaGen = AGEN_SKIP;
2904 			lmStage = MAX_SHADER_STAGES;	//skip the style checking below
2905 		}
2906 	}
2907 
2908 	if (lmStage < MAX_SHADER_STAGES)// && !r_fullbright->value)
2909 	{
2910 		int	numStyles;
2911 		int	i;
2912 
2913 		for(numStyles=0;numStyles<MAXLIGHTMAPS;numStyles++)
2914 		{
2915 			if (shader.styles[numStyles] >= LS_UNUSED)
2916 			{
2917 				break;
2918 			}
2919 		}
2920 		numStyles--;
2921 		if (numStyles > 0)
2922 		{
2923 			for(i=MAX_SHADER_STAGES-1;i>lmStage+numStyles;i--)
2924 			{
2925 				stages[i] = stages[i-numStyles];
2926 			}
2927 
2928 			for(i=0;i<numStyles;i++)
2929 			{
2930 				stages[lmStage+i+1] = stages[lmStage];
2931 				if (shader.lightmapIndex[i+1] == LIGHTMAP_BY_VERTEX)
2932 				{
2933 					stages[lmStage+i+1].bundle[0].image = tr.whiteImage;
2934 				}
2935 				else if (shader.lightmapIndex[i+1] < 0)
2936 				{
2937 					Com_Error( ERR_DROP, "FinishShader: light style with no light map or vertex color for shader %s", shader.name);
2938 				}
2939 				else
2940 				{
2941 					stages[lmStage+i+1].bundle[0].image = tr.lightmaps[shader.lightmapIndex[i+1]];
2942 					stages[lmStage+i+1].bundle[0].tcGen = (texCoordGen_t)(TCGEN_LIGHTMAP+i+1);
2943 				}
2944 				stages[lmStage+i+1].rgbGen = CGEN_LIGHTMAPSTYLE;
2945 				stages[lmStage+i+1].stateBits &= ~(GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS);
2946 				stages[lmStage+i+1].stateBits |= GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE;
2947 			}
2948 		}
2949 
2950 		for(i=0;i<=numStyles;i++)
2951 		{
2952 			stages[lmStage+i].lightmapStyle = shader.styles[i];
2953 		}
2954 	}
2955 
2956 	//
2957 	// set appropriate stage information
2958 	//
2959 	stageIndex = 0; //rwwRMG - needed for AGEN_BLEND
2960 	for ( stage = 0; stage < MAX_SHADER_STAGES; ) {
2961 		shaderStage_t *pStage = &stages[stage];
2962 
2963 		if ( !pStage->active ) {
2964 			break;
2965 		}
2966 
2967     // check for a missing texture
2968 		if ( !pStage->bundle[0].image ) {
2969 			ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "Shader %s has a stage with no image\n", shader.name );
2970 			pStage->active = qfalse;
2971 			stage++;
2972 			continue;
2973 		}
2974 
2975 		//
2976 		// ditch this stage if it's detail and detail textures are disabled
2977 		//
2978 		if ( pStage->isDetail && !r_detailTextures->integer ) {
2979 			int index;
2980 
2981 			for ( index=stage+1; index<MAX_SHADER_STAGES; index++ ) {
2982 				if ( !stages[index].active )
2983 					break;
2984 			}
2985 
2986 			if ( index < MAX_SHADER_STAGES )
2987 				memmove( pStage, pStage + 1, sizeof( *pStage ) * ( index - stage ) );
2988 			else {
2989 				if ( stage + 1 < MAX_SHADER_STAGES )
2990 					memmove( pStage, pStage + 1, sizeof( *pStage ) * ( index - stage - 1 ) );
2991 
2992 				Com_Memset( &stages[index - 1], 0, sizeof( *stages ) );
2993 			}
2994 
2995 			continue;
2996 		}
2997 
2998 		pStage->index = stageIndex; //rwwRMG - needed for AGEN_BLEND
2999 
3000 		//
3001 		// default texture coordinate generation
3002 		//
3003 		if ( pStage->bundle[0].isLightmap ) {
3004 			if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
3005 				pStage->bundle[0].tcGen = TCGEN_LIGHTMAP;
3006 			}
3007 			hasLightmapStage = qtrue;
3008 		} else {
3009 			if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
3010 				pStage->bundle[0].tcGen = TCGEN_TEXTURE;
3011 			}
3012 		}
3013 
3014 
3015     // not a true lightmap but we want to leave existing
3016     // behaviour in place and not print out a warning
3017     //if (pStage->rgbGen == CGEN_VERTEX) {
3018     //  vertexLightmap = qtrue;
3019     //}
3020 
3021 
3022 
3023 		//
3024 		// determine sort order and fog color adjustment
3025 		//
3026 		if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) &&
3027 			 ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) {
3028 			int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS;
3029 			int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS;
3030 
3031 			// fog color adjustment only works for blend modes that have a contribution
3032 			// that aproaches 0 as the modulate values aproach 0 --
3033 			// GL_ONE, GL_ONE
3034 			// GL_ZERO, GL_ONE_MINUS_SRC_COLOR
3035 			// GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
3036 
3037 			// modulate, additive
3038 			if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) ||
3039 				( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) {
3040 				pStage->adjustColorsForFog = ACFF_MODULATE_RGB;
3041 			}
3042 			// strict blend
3043 			else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
3044 			{
3045 				pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA;
3046 			}
3047 			// premultiplied alpha
3048 			else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
3049 			{
3050 				pStage->adjustColorsForFog = ACFF_MODULATE_RGBA;
3051 			} else {
3052 				// we can't adjust this one correctly, so it won't be exactly correct in fog
3053 			}
3054 
3055 			// don't screw with sort order if this is a portal or environment
3056 			if ( !shader.sort ) {
3057 				// see through item, like a grill or grate
3058 				if ( pStage->stateBits & GLS_DEPTHMASK_TRUE )
3059 				{
3060 					shader.sort = SS_SEE_THROUGH;
3061 				}
3062 				else
3063 				{
3064 					/*
3065 					if (( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ))
3066 					{
3067 						// GL_ONE GL_ONE needs to come a bit later
3068 						shader.sort = SS_BLEND2;
3069 					}
3070 					else if (( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ))
3071 					{ //rww - Pushed SS_BLEND1 up to SS_BLEND2, inserting this so that saber glow will render above water and things.
3072 					  //Unfortunately it still affects other shaders with the same blend settings, but it seems more or less alright.
3073 						shader.sort = SS_BLEND1;
3074 					}
3075 					else
3076 					{
3077 						shader.sort = SS_BLEND0;
3078 					}
3079 					*/
3080 					if (( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ))
3081 					{
3082 						// GL_ONE GL_ONE needs to come a bit later
3083 						shader.sort = SS_BLEND1;
3084 					}
3085 					else
3086 					{
3087 						shader.sort = SS_BLEND0;
3088 					}
3089 				}
3090 			}
3091 		}
3092 
3093 		//rww - begin hw fog
3094 		if ((pStage->stateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS)) == (GLS_SRCBLEND_ONE|GLS_DSTBLEND_ONE))
3095 		{
3096 			pStage->mGLFogColorOverride = GLFOGOVERRIDE_BLACK;
3097 		}
3098 		else if ((pStage->stateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS)) == (GLS_SRCBLEND_SRC_ALPHA|GLS_DSTBLEND_ONE) &&
3099 			pStage->alphaGen == AGEN_LIGHTING_SPECULAR && stage)
3100 		{
3101 			pStage->mGLFogColorOverride = GLFOGOVERRIDE_BLACK;
3102 		}
3103 		else if ((pStage->stateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS)) == (GLS_SRCBLEND_ZERO|GLS_DSTBLEND_ZERO))
3104 		{
3105 			pStage->mGLFogColorOverride = GLFOGOVERRIDE_WHITE;
3106 		}
3107 		else if ((pStage->stateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS)) == (GLS_SRCBLEND_ONE|GLS_DSTBLEND_ZERO))
3108 		{
3109 			pStage->mGLFogColorOverride = GLFOGOVERRIDE_WHITE;
3110 		}
3111 		else if ((pStage->stateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS)) == 0 && stage)
3112 		{	//
3113 			pStage->mGLFogColorOverride = GLFOGOVERRIDE_WHITE;
3114 		}
3115 		else if ((pStage->stateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS)) == 0 && pStage->bundle[0].isLightmap && stage < MAX_SHADER_STAGES-1 &&
3116 			stages[stage+1].bundle[0].isLightmap)
3117 		{	// multiple light map blending
3118 			pStage->mGLFogColorOverride = GLFOGOVERRIDE_WHITE;
3119 		}
3120 		else if ((pStage->stateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS)) == (GLS_SRCBLEND_DST_COLOR|GLS_DSTBLEND_ZERO) && pStage->bundle[0].isLightmap)
3121 		{ //I don't know, it works. -rww
3122 			pStage->mGLFogColorOverride = GLFOGOVERRIDE_WHITE;
3123 		}
3124 		else if ((pStage->stateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS)) == (GLS_SRCBLEND_DST_COLOR|GLS_DSTBLEND_ZERO))
3125 		{ //I don't know, it works. -rww
3126 			pStage->mGLFogColorOverride = GLFOGOVERRIDE_BLACK;
3127 		}
3128 		else if ((pStage->stateBits & (GLS_SRCBLEND_BITS|GLS_DSTBLEND_BITS)) == (GLS_SRCBLEND_ONE|GLS_DSTBLEND_ONE_MINUS_SRC_COLOR))
3129 		{ //I don't know, it works. -rww
3130 			pStage->mGLFogColorOverride = GLFOGOVERRIDE_BLACK;
3131 		}
3132 		else
3133 		{
3134 			pStage->mGLFogColorOverride = GLFOGOVERRIDE_NONE;
3135 		}
3136 		//rww - end hw fog
3137 
3138 		stageIndex++; //rwwRMG - needed for AGEN_BLEND
3139 		stage++;
3140 	}
3141 
3142 	// there are times when you will need to manually apply a sort to
3143 	// opaque alpha tested shaders that have later blend passes
3144 	if ( !shader.sort ) {
3145 		shader.sort = SS_OPAQUE;
3146 	}
3147 
3148 	//
3149 	// if we are in r_vertexLight mode, never use a lightmap texture
3150 	//
3151 	if ( stage > 1 && (r_vertexLight->integer && !r_uiFullScreen->integer) ) {
3152 		//stage = VertexLightingCollapse();
3153 		//rww - since this does bad things, I am commenting it out for now. If you want to attempt a fix, feel free.
3154 		hasLightmapStage = qfalse;
3155 	}
3156 
3157 	//
3158 	// look for multitexture potential
3159 	//
3160 	if ( stage > 1 && CollapseMultitexture() ) {
3161 		stage--;
3162 	}
3163 
3164 	if ( shader.lightmapIndex[0] >= 0 && !hasLightmapStage )
3165 	{
3166 		if (vertexLightmap)
3167 		{
3168 //			ri.DPrintf( "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name );
3169 		}
3170 		else
3171 		{
3172 			ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name );
3173 			memcpy(shader.lightmapIndex, lightmapsNone, sizeof(shader.lightmapIndex));
3174 			memcpy(shader.styles, stylesDefault, sizeof(shader.styles));
3175 		}
3176 	}
3177 
3178 
3179 	//
3180 	// compute number of passes
3181 	//
3182 	shader.numUnfoggedPasses = stage;
3183 
3184 	// fogonly shaders don't have any normal passes
3185 	if ( stage == 0 && !shader.sky ) {
3186 		shader.sort = SS_FOG;
3187 	}
3188 
3189 	for ( stage = 1; stage < shader.numUnfoggedPasses; stage++ )
3190 	{
3191 		// Make sure stage is non detail and active
3192 		if(stages[stage].isDetail || !stages[stage].active)
3193 		{
3194 			break;
3195 		}
3196 		// MT lightmaps are always in bundle 1
3197 		if(stages[stage].bundle[0].isLightmap)
3198 		{
3199 			continue;
3200 		}
3201 	}
3202 
3203 	return GeneratePermanentShader();
3204 }
3205 
3206 //========================================================================================
3207 
3208 /*
3209 ====================
3210 FindShaderInShaderText
3211 
3212 Scans the combined text description of all the shader files for
3213 the given shader name.
3214 
3215 return NULL if not found
3216 
3217 If found, it will return a valid shader
3218 =====================
3219 */
FindShaderInShaderText(const char * shadername)3220 static const char *FindShaderInShaderText( const char *shadername ) {
3221 	char *token;
3222 	const char *p;
3223 
3224 	int i, hash;
3225 
3226 	hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH);
3227 
3228 	if ( shaderTextHashTable[hash] ) {
3229 		for (i = 0; shaderTextHashTable[hash][i]; i++) {
3230 			p = shaderTextHashTable[hash][i];
3231 			token = COM_ParseExt(&p, qtrue);
3232 			if ( !Q_stricmp( token, shadername ) )
3233 				return p;
3234 		}
3235 	}
3236 
3237 	p = s_shaderText;
3238 
3239 	if ( !p ) {
3240 		return NULL;
3241 	}
3242 
3243 	// look for label
3244 	while ( 1 ) {
3245 		token = COM_ParseExt( &p, qtrue );
3246 		if ( token[0] == 0 ) {
3247 			break;
3248 		}
3249 
3250 		if ( !Q_stricmp( token, shadername ) ) {
3251 			return p;
3252 		}
3253 		else {
3254 			// skip the definition
3255 			SkipBracedSection( &p, 0 );
3256 		}
3257 	}
3258 
3259 	return NULL;
3260 }
3261 
3262 
3263 /*
3264 ==================
3265 R_FindShaderByName
3266 
3267 Will always return a valid shader, but it might be the
3268 default shader if the real one can't be found.
3269 ==================
3270 */
R_FindShaderByName(const char * name)3271 shader_t *R_FindShaderByName( const char *name ) {
3272 	char		strippedName[MAX_QPATH];
3273 	int			hash;
3274 	shader_t	*sh;
3275 
3276 	if ( (name==NULL) || (name[0] == 0) ) {
3277 		return tr.defaultShader;
3278 	}
3279 
3280 	COM_StripExtension( name, strippedName, sizeof( strippedName ) );
3281 
3282 	hash = generateHashValue(strippedName, FILE_HASH_SIZE);
3283 
3284 	//
3285 	// see if the shader is already loaded
3286 	//
3287 	for (sh=hashTable[hash]; sh; sh=sh->next) {
3288 		// NOTE: if there was no shader or image available with the name strippedName
3289 		// then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
3290 		// have to check all default shaders otherwise for every call to R_FindShader
3291 		// with that same strippedName a new default shader is created.
3292 		if (Q_stricmp(sh->name, strippedName) == 0) {
3293 			// match found
3294 			return sh;
3295 		}
3296 	}
3297 
3298 	return tr.defaultShader;
3299 }
3300 
3301 
IsShader(shader_t * sh,const char * name,const int * lightmapIndex,const byte * styles)3302 inline qboolean IsShader(shader_t *sh, const char *name, const int *lightmapIndex, const byte *styles)
3303 {
3304 	int	i;
3305 
3306 	if (Q_stricmp(sh->name, name))
3307 	{
3308 		return qfalse;
3309 	}
3310 
3311 	if (!sh->defaultShader)
3312 	{
3313 		for(i=0;i<MAXLIGHTMAPS;i++)
3314 		{
3315 			if (sh->lightmapIndex[i] != lightmapIndex[i])
3316 			{
3317 				return qfalse;
3318 			}
3319 			if (sh->styles[i] != styles[i])
3320 			{
3321 				return qfalse;
3322 			}
3323 		}
3324 	}
3325 
3326 	return qtrue;
3327 }
3328 
3329 /*
3330  ===============
3331  R_FindLightmap ( needed for -external LMs created by ydnar's q3map2 )
3332  given a (potentially erroneous) lightmap index, attempts to load
3333  an external lightmap image and/or sets the index to a valid number
3334  ===============
3335  */
3336 #define EXTERNAL_LIGHTMAP     "lm_%04d.tga"     // THIS MUST BE IN SYNC WITH Q3MAP2
R_FindLightmap(const int * lightmapIndex)3337 static inline const int *R_FindLightmap( const int *lightmapIndex )
3338 {
3339 	image_t          *image;
3340 	char          fileName[ MAX_QPATH ];
3341 
3342 	// don't bother with vertex lighting
3343 	if( *lightmapIndex < 0 )
3344 		return lightmapIndex;
3345 
3346 	// does this lightmap already exist?
3347 	if( *lightmapIndex < tr.numLightmaps && tr.lightmaps[ *lightmapIndex ] != NULL )
3348 		return lightmapIndex;
3349 
3350 	// bail if no world dir
3351 	if( tr.worldDir[0] == '\0' )
3352 	{
3353 		return lightmapsVertex;
3354 	}
3355 
3356 	// sync up render thread, because we're going to have to load an image
3357 	//R_SyncRenderThread();
3358 
3359 	// attempt to load an external lightmap
3360 	Com_sprintf( fileName, sizeof(fileName), "%s/" EXTERNAL_LIGHTMAP, tr.worldDir, *lightmapIndex );
3361 	image = R_FindImageFile( fileName, qfalse, qfalse, (qboolean)r_ext_compressed_lightmaps->integer, GL_CLAMP );
3362 	if( image == NULL )
3363 	{
3364 		return lightmapsVertex;
3365 	}
3366 
3367 	// add it to the lightmap list
3368 	if( *lightmapIndex >= tr.numLightmaps )
3369 		tr.numLightmaps = *lightmapIndex + 1;
3370 	tr.lightmaps[ *lightmapIndex ] = image;
3371 	return lightmapIndex;
3372 }
3373 
3374 /*
3375 ===============
3376 R_FindShader
3377 
3378 Will always return a valid shader, but it might be the
3379 default shader if the real one can't be found.
3380 
3381 In the interest of not requiring an explicit shader text entry to
3382 be defined for every single image used in the game, three default
3383 shader behaviors can be auto-created for any image:
3384 
3385 If lightmapIndex == LIGHTMAP_NONE, then the image will have
3386 dynamic diffuse lighting applied to it, as appropriate for most
3387 entity skin surfaces.
3388 
3389 If lightmapIndex == LIGHTMAP_2D, then the image will be used
3390 for 2D rendering unless an explicit shader is found
3391 
3392 If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use
3393 the vertex rgba modulate values, as appropriate for misc_model
3394 pre-lit surfaces.
3395 
3396 Other lightmapIndex values will have a lightmap stage created
3397 and src*dest blending applied with the texture, as appropriate for
3398 most world construction surfaces.
3399 
3400 ===============
3401 */
R_FindShader(const char * name,const int * lightmapIndex,const byte * styles,qboolean mipRawImage)3402 shader_t *R_FindShader( const char *name, const int *lightmapIndex, const byte *styles, qboolean mipRawImage )
3403 {
3404 	char		strippedName[MAX_QPATH];
3405 	char		fileName[MAX_QPATH];
3406 	int			hash;
3407 	const char	*shaderText;
3408 	image_t		*image;
3409 	shader_t	*sh;
3410 
3411 	if ( name[0] == 0 ) {
3412 		return tr.defaultShader;
3413 	}
3414 
3415 	// use (fullbright) vertex lighting if the bsp file doesn't have
3416 	// lightmaps
3417 /*	if ( lightmapIndex[0] >= 0 && lightmapIndex[0] >= tr.numLightmaps )
3418 	{
3419 		lightmapIndex = lightmapsVertex;
3420 	}*/
3421 
3422 	lightmapIndex = R_FindLightmap( lightmapIndex );
3423 
3424 	if ( lightmapIndex[0] < LIGHTMAP_2D )
3425 	{
3426 		// negative lightmap indexes cause stray pointers (think tr.lightmaps[lightmapIndex])
3427 		ri.Printf( PRINT_WARNING, "WARNING: shader '%s' has invalid lightmap index of %d\n", name, lightmapIndex[0] );
3428 		lightmapIndex = lightmapsVertex;
3429 	}
3430 
3431 	COM_StripExtension( name, strippedName, sizeof( strippedName ) );
3432 
3433 	hash = generateHashValue(strippedName, FILE_HASH_SIZE);
3434 
3435 	//
3436 	// see if the shader is already loaded
3437 	//
3438 	for (sh = hashTable[hash]; sh; sh = sh->next) {
3439 		// NOTE: if there was no shader or image available with the name strippedName
3440 		// then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
3441 		// have to check all default shaders otherwise for every call to R_FindShader
3442 		// with that same strippedName a new default shader is created.
3443 		if (IsShader(sh, strippedName, lightmapIndex, styles))
3444 		{
3445 			return sh;
3446 		}
3447 	}
3448 
3449 	// clear the global shader
3450 	ClearGlobalShader();
3451 	Q_strncpyz(shader.name, strippedName, sizeof(shader.name));
3452 	Com_Memcpy(shader.lightmapIndex, lightmapIndex, sizeof(shader.lightmapIndex));
3453 	Com_Memcpy(shader.styles, styles, sizeof(shader.styles));
3454 
3455 	//
3456 	// attempt to define shader from an explicit parameter file
3457 	//
3458 	shaderText = FindShaderInShaderText( strippedName );
3459 	if ( shaderText ) {
3460 		if ( !ParseShader( &shaderText ) ) {
3461 			// had errors, so use default shader
3462 			shader.defaultShader = true;
3463 		}
3464 		sh = FinishShader();
3465 		return sh;
3466 	}
3467 
3468 
3469 	//
3470 	// if not defined in the in-memory shader descriptions,
3471 	// look for a single TGA, BMP, or PCX
3472 	//
3473 	COM_StripExtension( name, fileName, sizeof( fileName ) );
3474 	image = R_FindImageFile( fileName, mipRawImage, mipRawImage, qtrue, mipRawImage ? GL_REPEAT : GL_CLAMP );
3475 	if ( !image ) {
3476 		ri.Printf( PRINT_DEVELOPER, S_COLOR_RED "Couldn't find image for shader %s\n", name );
3477 		shader.defaultShader = true;
3478 		return FinishShader();
3479 	}
3480 	//
3481 	// create the default shading commands
3482 	//
3483 	if ( shader.lightmapIndex[0] == LIGHTMAP_NONE ) {
3484 		// dynamic colors at vertexes
3485 		stages[0].bundle[0].image = image;
3486 		stages[0].active = qtrue;
3487 		stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
3488 		stages[0].stateBits = GLS_DEFAULT;
3489 	} else if ( shader.lightmapIndex[0] == LIGHTMAP_BY_VERTEX ) {
3490 		// explicit colors at vertexes
3491 		stages[0].bundle[0].image = image;
3492 		stages[0].active = qtrue;
3493 		stages[0].rgbGen = CGEN_EXACT_VERTEX;
3494 		stages[0].alphaGen = AGEN_SKIP;
3495 		stages[0].stateBits = GLS_DEFAULT;
3496 	} else if ( shader.lightmapIndex[0] == LIGHTMAP_2D ) {
3497 		// GUI elements
3498 		stages[0].bundle[0].image = image;
3499 		stages[0].active = qtrue;
3500 		stages[0].rgbGen = CGEN_VERTEX;
3501 		stages[0].alphaGen = AGEN_VERTEX;
3502 		stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
3503 			  GLS_SRCBLEND_SRC_ALPHA |
3504 			  GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
3505 	} else if ( shader.lightmapIndex[0] == LIGHTMAP_WHITEIMAGE ) {
3506 		// fullbright level
3507 		stages[0].bundle[0].image = tr.whiteImage;
3508 		stages[0].active = qtrue;
3509 		stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
3510 		stages[0].stateBits = GLS_DEFAULT;
3511 
3512 		stages[1].bundle[0].image = image;
3513 		stages[1].active = qtrue;
3514 		stages[1].rgbGen = CGEN_IDENTITY;
3515 		stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
3516 	} else {
3517 		// two pass lightmap
3518 		stages[0].bundle[0].image = tr.lightmaps[shader.lightmapIndex[0]];
3519 		stages[0].bundle[0].isLightmap = qtrue;
3520 		stages[0].active = qtrue;
3521 		stages[0].rgbGen = CGEN_IDENTITY;	// lightmaps are scaled on creation
3522 													// for identitylight
3523 		stages[0].stateBits = GLS_DEFAULT;
3524 
3525 		stages[1].bundle[0].image = image;
3526 		stages[1].active = qtrue;
3527 		stages[1].rgbGen = CGEN_IDENTITY;
3528 		stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
3529 	}
3530 
3531 	return FinishShader();
3532 }
3533 
R_FindServerShader(const char * name,const int * lightmapIndex,const byte * styles,qboolean mipRawImage)3534 shader_t *R_FindServerShader( const char *name, const int *lightmapIndex, const byte *styles, qboolean mipRawImage )
3535 {
3536 	char		strippedName[MAX_QPATH];
3537 	int			hash;
3538 	shader_t	*sh;
3539 
3540 	if ( name[0] == 0 ) {
3541 		return tr.defaultShader;
3542 	}
3543 
3544 	COM_StripExtension( name, strippedName, sizeof( strippedName ) );
3545 
3546 	hash = generateHashValue(strippedName, FILE_HASH_SIZE);
3547 
3548 	//
3549 	// see if the shader is already loaded
3550 	//
3551 	for (sh = hashTable[hash]; sh; sh = sh->next) {
3552 		// NOTE: if there was no shader or image available with the name strippedName
3553 		// then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
3554 		// have to check all default shaders otherwise for every call to R_FindShader
3555 		// with that same strippedName a new default shader is created.
3556 		if (IsShader(sh, strippedName, lightmapIndex, styles))
3557 		{
3558 			return sh;
3559 		}
3560 	}
3561 
3562 	// clear the global shader
3563 	ClearGlobalShader();
3564 	Q_strncpyz(shader.name, strippedName, sizeof(shader.name));
3565 	memcpy(shader.lightmapIndex, lightmapIndex, sizeof(shader.lightmapIndex));
3566 	memcpy(shader.styles, styles, sizeof(shader.styles));
3567 
3568 	shader.defaultShader = true;
3569 	return FinishShader();
3570 }
3571 
RE_RegisterShaderFromImage(const char * name,int * lightmapIndex,byte * styles,image_t * image,qboolean mipRawImage)3572 qhandle_t RE_RegisterShaderFromImage(const char *name, int *lightmapIndex, byte *styles, image_t *image, qboolean mipRawImage) {
3573 	int			i, hash;
3574 	shader_t	*sh;
3575 
3576 	hash = generateHashValue(name, FILE_HASH_SIZE);
3577 
3578 	// probably not necessary since this function
3579 	// only gets called from tr_font.c with lightmapIndex == LIGHTMAP_2D
3580 	// but better safe than sorry.
3581 	// Doesn't actually ever get called in JA at all
3582 	if ( lightmapIndex[0] >= tr.numLightmaps ) {
3583 		lightmapIndex = (int *)lightmapsFullBright;
3584 	}
3585 
3586 	//
3587 	// see if the shader is already loaded
3588 	//
3589 	for (sh=hashTable[hash]; sh; sh=sh->next) {
3590 		// NOTE: if there was no shader or image available with the name strippedName
3591 		// then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
3592 		// have to check all default shaders otherwise for every call to R_FindShader
3593 		// with that same strippedName a new default shader is created.
3594 		if (IsShader(sh, name, lightmapIndex, styles))
3595 		{
3596 			return sh->index;
3597 		}
3598 	}
3599 
3600 	// clear the global shader
3601 	memset( &shader, 0, sizeof( shader ) );
3602 	memset( &stages, 0, sizeof( stages ) );
3603 	Q_strncpyz(shader.name, name, sizeof(shader.name));
3604 	memcpy(shader.lightmapIndex, lightmapIndex, sizeof(shader.lightmapIndex));
3605 	memcpy(shader.styles, styles, sizeof(shader.styles));
3606 
3607 	for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
3608 		stages[i].bundle[0].texMods = texMods[i];
3609 	}
3610 
3611 	//
3612 	// create the default shading commands
3613 	//
3614 	if ( shader.lightmapIndex[0] == LIGHTMAP_NONE ) {
3615 		// dynamic colors at vertexes
3616 		stages[0].bundle[0].image = image;
3617 		stages[0].active = qtrue;
3618 		stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
3619 		stages[0].stateBits = GLS_DEFAULT;
3620 	} else if ( shader.lightmapIndex[0] == LIGHTMAP_BY_VERTEX ) {
3621 		// explicit colors at vertexes
3622 		stages[0].bundle[0].image = image;
3623 		stages[0].active = qtrue;
3624 		stages[0].rgbGen = CGEN_EXACT_VERTEX;
3625 		stages[0].alphaGen = AGEN_SKIP;
3626 		stages[0].stateBits = GLS_DEFAULT;
3627 	} else if ( shader.lightmapIndex[0] == LIGHTMAP_2D ) {
3628 		// GUI elements
3629 		stages[0].bundle[0].image = image;
3630 		stages[0].active = qtrue;
3631 		stages[0].rgbGen = CGEN_VERTEX;
3632 		stages[0].alphaGen = AGEN_VERTEX;
3633 		stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
3634 			  GLS_SRCBLEND_SRC_ALPHA |
3635 			  GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
3636 	} else if ( shader.lightmapIndex[0] == LIGHTMAP_WHITEIMAGE ) {
3637 		// fullbright level
3638 		stages[0].bundle[0].image = tr.whiteImage;
3639 		stages[0].active = qtrue;
3640 		stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
3641 		stages[0].stateBits = GLS_DEFAULT;
3642 
3643 		stages[1].bundle[0].image = image;
3644 		stages[1].active = qtrue;
3645 		stages[1].rgbGen = CGEN_IDENTITY;
3646 		stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
3647 	} else {
3648 		// two pass lightmap
3649 		stages[0].bundle[0].image = tr.lightmaps[shader.lightmapIndex[0]];
3650 		stages[0].bundle[0].isLightmap = qtrue;
3651 		stages[0].active = qtrue;
3652 		stages[0].rgbGen = CGEN_IDENTITY;	// lightmaps are scaled on creation
3653 													// for identitylight
3654 		stages[0].stateBits = GLS_DEFAULT;
3655 
3656 		stages[1].bundle[0].image = image;
3657 		stages[1].active = qtrue;
3658 		stages[1].rgbGen = CGEN_IDENTITY;
3659 		stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
3660 	}
3661 
3662 	sh = FinishShader();
3663   return sh->index;
3664 }
3665 
3666 
3667 /*
3668 ====================
3669 RE_RegisterShader
3670 
3671 This is the exported shader entry point for the rest of the system
3672 It will always return an index that will be valid.
3673 
3674 This should really only be used for explicit shaders, because there is no
3675 way to ask for different implicit lighting modes (vertex, lightmap, etc)
3676 ====================
3677 */
RE_RegisterShaderLightMap(const char * name,const int * lightmapIndex,const byte * styles)3678 qhandle_t RE_RegisterShaderLightMap( const char *name, const int *lightmapIndex, const byte *styles )
3679 {
3680 	shader_t	*sh;
3681 
3682 	if ( strlen( name ) >= MAX_QPATH ) {
3683 		ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
3684 		return 0;
3685 	}
3686 
3687 	sh = R_FindShader( name, lightmapIndex, styles, qtrue );
3688 
3689 	// we want to return 0 if the shader failed to
3690 	// load for some reason, but R_FindShader should
3691 	// still keep a name allocated for it, so if
3692 	// something calls RE_RegisterShader again with
3693 	// the same name, we don't try looking for it again
3694 	if ( sh->defaultShader ) {
3695 		return 0;
3696 	}
3697 
3698 	return sh->index;
3699 }
3700 
3701 
3702 /*
3703 ====================
3704 RE_RegisterShader
3705 
3706 This is the exported shader entry point for the rest of the system
3707 It will always return an index that will be valid.
3708 
3709 This should really only be used for explicit shaders, because there is no
3710 way to ask for different implicit lighting modes (vertex, lightmap, etc)
3711 ====================
3712 */
RE_RegisterShader(const char * name)3713 qhandle_t RE_RegisterShader( const char *name ) {
3714 	shader_t	*sh;
3715 
3716 	if ( strlen( name ) >= MAX_QPATH ) {
3717 		ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
3718 		return 0;
3719 	}
3720 
3721 	sh = R_FindShader( name, lightmaps2d, stylesDefault, qtrue );
3722 
3723 	// we want to return 0 if the shader failed to
3724 	// load for some reason, but R_FindShader should
3725 	// still keep a name allocated for it, so if
3726 	// something calls RE_RegisterShader again with
3727 	// the same name, we don't try looking for it again
3728 	if ( sh->defaultShader ) {
3729 		return 0;
3730 	}
3731 
3732 	return sh->index;
3733 }
3734 
3735 
3736 /*
3737 ====================
3738 RE_RegisterShaderNoMip
3739 
3740 For menu graphics that should never be picmiped
3741 ====================
3742 */
RE_RegisterShaderNoMip(const char * name)3743 qhandle_t RE_RegisterShaderNoMip( const char *name ) {
3744 	shader_t	*sh;
3745 
3746 	if ( strlen( name ) >= MAX_QPATH ) {
3747 		ri.Printf( PRINT_ALL, "Shader name exceeds MAX_QPATH\n" );
3748 		return 0;
3749 	}
3750 
3751 	sh = R_FindShader( name, lightmaps2d, stylesDefault, qfalse );
3752 
3753 	// we want to return 0 if the shader failed to
3754 	// load for some reason, but R_FindShader should
3755 	// still keep a name allocated for it, so if
3756 	// something calls RE_RegisterShader again with
3757 	// the same name, we don't try looking for it again
3758 	if ( sh->defaultShader ) {
3759 		return 0;
3760 	}
3761 
3762 	return sh->index;
3763 }
3764 
3765 
3766 //added for ui -rww
RE_ShaderNameFromIndex(int index)3767 const char *RE_ShaderNameFromIndex(int index)
3768 {
3769 	assert(index >= 0 && index < tr.numShaders && tr.shaders[index]);
3770 	return tr.shaders[index]->name;
3771 }
3772 
3773 
3774 /*
3775 ====================
3776 R_GetShaderByHandle
3777 
3778 When a handle is passed in by another module, this range checks
3779 it and returns a valid (possibly default) shader_t to be used internally.
3780 ====================
3781 */
R_GetShaderByHandle(qhandle_t hShader)3782 shader_t *R_GetShaderByHandle( qhandle_t hShader ) {
3783 	if ( hShader < 0 ) {
3784 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
3785 		return tr.defaultShader;
3786 	}
3787 	if ( hShader >= tr.numShaders ) {
3788 		ri.Printf( PRINT_ALL, S_COLOR_YELLOW  "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
3789 		return tr.defaultShader;
3790 	}
3791 	return tr.shaders[hShader];
3792 }
3793 
3794 /*
3795 ===============
3796 R_ShaderList_f
3797 
3798 Dump information on all valid shaders to the console
3799 A second parameter will cause it to print in sorted order
3800 ===============
3801 */
R_ShaderList_f(void)3802 void	R_ShaderList_f (void) {
3803 	int			i;
3804 	int			count;
3805 	shader_t	*shader;
3806 
3807 	ri.Printf( PRINT_ALL,  "-----------------------\n");
3808 
3809 	count = 0;
3810 	for ( i = 0 ; i < tr.numShaders ; i++ ) {
3811 		if ( ri.Cmd_Argc() > 1 ) {
3812 			shader = tr.sortedShaders[i];
3813 		} else {
3814 			shader = tr.shaders[i];
3815 		}
3816 
3817 		ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses );
3818 
3819 		if (shader->lightmapIndex[0] >= 0 ) {
3820 			ri.Printf( PRINT_ALL,  "L ");
3821 		} else {
3822 			ri.Printf( PRINT_ALL,  "  ");
3823 		}
3824 		if ( shader->multitextureEnv == GL_ADD ) {
3825 			ri.Printf( PRINT_ALL, "MT(a) " );
3826 		} else if ( shader->multitextureEnv == GL_MODULATE ) {
3827 			ri.Printf( PRINT_ALL, "MT(m) " );
3828 		} else if ( shader->multitextureEnv == GL_DECAL ) {
3829 			ri.Printf( PRINT_ALL, "MT(d) " );
3830 		} else {
3831 			ri.Printf( PRINT_ALL, "      " );
3832 		}
3833 		if ( shader->explicitlyDefined ) {
3834 			ri.Printf( PRINT_ALL, "E " );
3835 		} else {
3836 			ri.Printf( PRINT_ALL, "  " );
3837 		}
3838 
3839 		if ( shader->sky )
3840 		{
3841 			ri.Printf( PRINT_ALL, "sky " );
3842 		} else {
3843 			ri.Printf( PRINT_ALL, "gen " );
3844 		}
3845 		if ( shader->defaultShader ) {
3846 			ri.Printf( PRINT_ALL,   ": %s (DEFAULTED)\n", shader->name);
3847 		} else {
3848 			ri.Printf( PRINT_ALL,   ": %s\n", shader->name);
3849 		}
3850 		count++;
3851 	}
3852 	ri.Printf( PRINT_ALL,  "%i total shaders\n", count);
3853 	ri.Printf( PRINT_ALL,  "------------------\n");
3854 }
3855 
COM_CompressShader(char * data_p)3856 int COM_CompressShader( char *data_p )
3857 {
3858 	char *in, *out;
3859 	int c;
3860 	qboolean newline = qfalse, whitespace = qfalse;
3861 
3862 	in = out = data_p;
3863 	if ( in )
3864 	{
3865 		while ( (c = *in) != 0 )
3866 		{
3867 			// skip double slash comments
3868 			if ( c == '/' && in[1] == '/' )
3869 			{
3870 				while ( *in && *in != '\n' )
3871 				{
3872 					in++;
3873 				}
3874 			}
3875 			// skip number sign comments
3876 			else if ( c == '#' )
3877 			{
3878 				while ( *in && *in != '\n' )
3879 				{
3880 					in++;
3881 				}
3882 			}
3883 			// skip /* */ comments
3884 			else if ( c == '/' && in[1] == '*' )
3885 			{
3886 				while ( *in && (*in != '*' || in[1] != '/') )
3887 					in++;
3888 				if ( *in )
3889 					in += 2;
3890 			}
3891 			// record when we hit a newline
3892 			else if ( c == '\n' || c == '\r' )
3893 			{
3894 				newline = qtrue;
3895 				in++;
3896 			}
3897 			// record when we hit whitespace
3898 			else if ( c == ' ' || c == '\t' )
3899 			{
3900 				whitespace = qtrue;
3901 				in++;
3902 				// an actual token
3903 			}
3904 			else
3905 			{
3906 				// if we have a pending newline, emit it (and it counts as whitespace)
3907 				if ( newline )
3908 				{
3909 					*out++ = '\n';
3910 					newline = qfalse;
3911 					whitespace = qfalse;
3912 				} if ( whitespace )
3913 				{
3914 					*out++ = ' ';
3915 					whitespace = qfalse;
3916 				}
3917 
3918 				// copy quoted strings unmolested
3919 				if ( c == '"' )
3920 				{
3921 					*out++ = c;
3922 					in++;
3923 					while ( 1 )
3924 					{
3925 						c = *in;
3926 						if ( c && c != '"' )
3927 						{
3928 							*out++ = c;
3929 							in++;
3930 						}
3931 						else
3932 						{
3933 							break;
3934 						}
3935 					}
3936 					if ( c == '"' )
3937 					{
3938 						*out++ = c;
3939 						in++;
3940 					}
3941 				}
3942 				else
3943 				{
3944 					*out = c;
3945 					out++;
3946 					in++;
3947 				}
3948 			}
3949 		}
3950 
3951 		*out = 0;
3952 	}
3953 	return out - data_p;
3954 }
3955 
3956 /*
3957 ====================
3958 ScanAndLoadShaderFiles
3959 
3960 Finds and loads all .shader files, combining them into
3961 a single large text block that can be scanned for shader names
3962 =====================
3963 */
3964 #define	MAX_SHADER_FILES	4096
ScanAndLoadShaderFiles(void)3965 static void ScanAndLoadShaderFiles( void )
3966 {
3967 	char **shaderFiles;
3968 	char *buffers[MAX_SHADER_FILES];
3969 	const char *p;
3970 	int numShaderFiles;
3971 	int i;
3972 	char *oldp, *token, *hashMem, *textEnd;
3973 	int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size;
3974 	char shaderName[MAX_QPATH];
3975 	int shaderLine;
3976 
3977 	long sum = 0, summand;
3978 	// scan for shader files
3979 	shaderFiles = ri.FS_ListFiles( "shaders", ".shader", &numShaderFiles );
3980 
3981 	if ( !shaderFiles || !numShaderFiles )
3982 	{
3983 		ri.Error( ERR_FATAL, "ERROR: no shader files found" );
3984 		return;
3985 	}
3986 
3987 	if ( numShaderFiles > MAX_SHADER_FILES ) {
3988 		numShaderFiles = MAX_SHADER_FILES;
3989 	}
3990 
3991 	// load and parse shader files
3992 	for ( i = 0; i < numShaderFiles; i++ )
3993 	{
3994 		char filename[MAX_QPATH];
3995 
3996 		Com_sprintf( filename, sizeof( filename ), "shaders/%s", shaderFiles[i] );
3997 		ri.Printf( PRINT_DEVELOPER, "...loading '%s'\n", filename );
3998 		summand = ri.FS_ReadFile( filename, (void **)&buffers[i] );
3999 
4000 		if ( !buffers[i] ) {
4001 			ri.Error( ERR_DROP, "Couldn't load %s", filename );
4002 		}
4003 
4004 		// Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders.
4005 		p = buffers[i];
4006 		COM_BeginParseSession(filename);
4007 		while(1)
4008 		{
4009 			token = COM_ParseExt(&p, qtrue);
4010 
4011 			if(!*token)
4012 				break;
4013 
4014 			Q_strncpyz(shaderName, token, sizeof(shaderName));
4015 			shaderLine = COM_GetCurrentParseLine();
4016 
4017 			if ( token[0] == '#' )
4018 			{
4019 				ri.Printf( PRINT_WARNING, "WARNING: Deprecated shader comment \"%s\" on line %d in file %s.  Ignoring line.\n",
4020 					shaderName, shaderLine, filename );
4021 				SkipRestOfLine( &p );
4022 				continue;
4023 			}
4024 
4025 			token = COM_ParseExt(&p, qtrue);
4026 			if(token[0] != '{' || token[1] != '\0')
4027 			{
4028 				ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing opening brace",
4029 							filename, shaderName, shaderLine);
4030 				if (token[0])
4031 				{
4032 					ri.Printf(PRINT_WARNING, " (found \"%s\" on line %d)", token, COM_GetCurrentParseLine());
4033 				}
4034 				ri.Printf(PRINT_WARNING, ".\n");
4035 				ri.FS_FreeFile(buffers[i]);
4036 				buffers[i] = NULL;
4037 				break;
4038 			}
4039 
4040 			if(!SkipBracedSection(&p, 1))
4041 			{
4042 				ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n",
4043 							filename, shaderName, shaderLine);
4044 				ri.FS_FreeFile(buffers[i]);
4045 				buffers[i] = NULL;
4046 				break;
4047 			}
4048 		}
4049 
4050 
4051 		if (buffers[i])
4052 			sum += summand;
4053 	}
4054 
4055 	// build single large buffer
4056 	s_shaderText = (char *)ri.Hunk_Alloc( sum + numShaderFiles*2, h_low );
4057 	s_shaderText[ 0 ] = '\0';
4058 	textEnd = s_shaderText;
4059 
4060 	// free in reverse order, so the temp files are all dumped
4061 	for ( i = numShaderFiles - 1; i >= 0 ; i-- )
4062 	{
4063 		if ( !buffers[i] )
4064 			continue;
4065 
4066 		strcat( textEnd, buffers[i] );
4067 		strcat( textEnd, "\n" );
4068 		textEnd += strlen( textEnd );
4069 		ri.FS_FreeFile( buffers[i] );
4070 	}
4071 
4072 	COM_CompressShader( s_shaderText );
4073 
4074 	// free up memory
4075 	ri.FS_FreeFileList( shaderFiles );
4076 
4077 	memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
4078 	size = 0;
4079 
4080 	p = s_shaderText;
4081 	// look for shader names
4082 	while ( 1 ) {
4083 		token = COM_ParseExt( &p, qtrue );
4084 		if ( token[0] == 0 ) {
4085 			break;
4086 		}
4087 
4088 		if ( token[0] == '#' )
4089 		{
4090 			SkipRestOfLine( &p );
4091 			continue;
4092 		}
4093 
4094 		hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
4095 		shaderTextHashTableSizes[hash]++;
4096 		size++;
4097 		SkipBracedSection( &p, 0 );
4098 	}
4099 
4100 	size += MAX_SHADERTEXT_HASH;
4101 
4102 	hashMem = (char *)ri.Hunk_Alloc( size * sizeof(char *), h_low );
4103 
4104 	for (i = 0; i < MAX_SHADERTEXT_HASH; i++) {
4105 		shaderTextHashTable[i] = (char **) hashMem;
4106 		hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *));
4107 	}
4108 
4109 	memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
4110 
4111 	p = s_shaderText;
4112 	// look for shader names
4113 	while ( 1 ) {
4114 		oldp = (char *)p;
4115 		token = COM_ParseExt( &p, qtrue );
4116 		if ( token[0] == 0 ) {
4117 			break;
4118 		}
4119 
4120 		if ( token[0] == '#' )
4121 		{
4122 			SkipRestOfLine( &p );
4123 			continue;
4124 		}
4125 
4126 		hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
4127 		shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp;
4128 
4129 		SkipBracedSection( &p, 0 );
4130 	}
4131 
4132 	return;
4133 }
4134 
4135 /*
4136 ====================
4137 CreateInternalShaders
4138 ====================
4139 */
CreateInternalShaders(void)4140 static void CreateInternalShaders( void ) {
4141 	tr.numShaders = 0;
4142 
4143 	// init the default shader
4144 	memset( &shader, 0, sizeof( shader ) );
4145 	memset( &stages, 0, sizeof( stages ) );
4146 
4147 	Q_strncpyz( shader.name, "<default>", sizeof( shader.name ) );
4148 
4149 	memcpy(shader.lightmapIndex, lightmapsNone, sizeof(shader.lightmapIndex));
4150 	memcpy(shader.styles, stylesDefault, sizeof(shader.styles));
4151 	for ( int i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
4152 		stages[i].bundle[0].texMods = texMods[i];
4153 	}
4154 
4155 	stages[0].bundle[0].image = tr.defaultImage;
4156 	stages[0].active = qtrue;
4157 	stages[0].stateBits = GLS_DEFAULT;
4158 	tr.defaultShader = FinishShader();
4159 
4160 	// shadow shader is just a marker
4161 	Q_strncpyz( shader.name, "<stencil shadow>", sizeof( shader.name ) );
4162 	shader.sort = SS_BANNER; //SS_STENCIL_SHADOW;
4163 	tr.shadowShader = FinishShader();
4164 
4165 	// distortion shader is just a marker
4166 	Q_strncpyz( shader.name, "internal_distortion", sizeof( shader.name ) );
4167 	shader.sort = SS_BLEND0;
4168 	shader.defaultShader = qfalse;
4169 	tr.distortionShader = FinishShader();
4170 	shader.defaultShader = qtrue;
4171 
4172 	ARB_InitGPUShaders();
4173 }
4174 
CreateExternalShaders(void)4175 static void CreateExternalShaders( void ) {
4176 	tr.projectionShadowShader = R_FindShader( "projectionShadow", lightmapsNone, stylesDefault, qtrue );
4177 	tr.projectionShadowShader->sort = SS_STENCIL_SHADOW;
4178 	tr.sunShader = R_FindShader( "sun", lightmapsNone, stylesDefault, qtrue );
4179 }
4180 
4181 /*
4182 ==================
4183 R_InitShaders
4184 ==================
4185 */
R_InitShaders(qboolean server)4186 void R_InitShaders(qboolean server)
4187 {
4188 	//ri.Printf( PRINT_ALL, "Initializing Shaders\n" );
4189 
4190 	memset(hashTable, 0, sizeof(hashTable));
4191 
4192 	if ( !server )
4193 	{
4194 		CreateInternalShaders();
4195 
4196 		ScanAndLoadShaderFiles();
4197 
4198 		CreateExternalShaders();
4199 	}
4200 }
4201