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