Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

tr_shader.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 #include "tr_local.h"
00023 
00024 // tr_shader.c -- this file deals with the parsing and definition of shaders
00025 
00026 static char *s_shaderText;
00027 
00028 // the shader is parsed into these global variables, then copied into
00029 // dynamically allocated memory if it is valid.
00030 static  shaderStage_t   stages[MAX_SHADER_STAGES];      
00031 static  shader_t        shader;
00032 static  texModInfo_t    texMods[MAX_SHADER_STAGES][TR_MAX_TEXMODS];
00033 static  qboolean        deferLoad;
00034 
00035 #define FILE_HASH_SIZE      1024
00036 static  shader_t*       hashTable[FILE_HASH_SIZE];
00037 
00038 #define MAX_SHADERTEXT_HASH     2048
00039 static char **shaderTextHashTable[MAX_SHADERTEXT_HASH];
00040 
00041 /*
00042 ================
00043 return a hash value for the filename
00044 ================
00045 */
00046 static long generateHashValue( const char *fname, const int size ) {
00047     int     i;
00048     long    hash;
00049     char    letter;
00050 
00051     hash = 0;
00052     i = 0;
00053     while (fname[i] != '\0') {
00054         letter = tolower(fname[i]);
00055         if (letter =='.') break;                // don't include extension
00056         if (letter =='\\') letter = '/';        // damn path names
00057         if (letter == PATH_SEP) letter = '/';       // damn path names
00058         hash+=(long)(letter)*(i+119);
00059         i++;
00060     }
00061     hash = (hash ^ (hash >> 10) ^ (hash >> 20));
00062     hash &= (size-1);
00063     return hash;
00064 }
00065 
00066 void R_RemapShader(const char *shaderName, const char *newShaderName, const char *timeOffset) {
00067     char        strippedName[MAX_QPATH];
00068     int         hash;
00069     shader_t    *sh, *sh2;
00070     qhandle_t   h;
00071 
00072     sh = R_FindShaderByName( shaderName );
00073     if (sh == NULL || sh == tr.defaultShader) {
00074         h = RE_RegisterShaderLightMap(shaderName, 0);
00075         sh = R_GetShaderByHandle(h);
00076     }
00077     if (sh == NULL || sh == tr.defaultShader) {
00078         ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: shader %s not found\n", shaderName );
00079         return;
00080     }
00081 
00082     sh2 = R_FindShaderByName( newShaderName );
00083     if (sh2 == NULL || sh2 == tr.defaultShader) {
00084         h = RE_RegisterShaderLightMap(newShaderName, 0);
00085         sh2 = R_GetShaderByHandle(h);
00086     }
00087 
00088     if (sh2 == NULL || sh2 == tr.defaultShader) {
00089         ri.Printf( PRINT_WARNING, "WARNING: R_RemapShader: new shader %s not found\n", newShaderName );
00090         return;
00091     }
00092 
00093     // remap all the shaders with the given name
00094     // even tho they might have different lightmaps
00095     COM_StripExtension( shaderName, strippedName );
00096     hash = generateHashValue(strippedName, FILE_HASH_SIZE);
00097     for (sh = hashTable[hash]; sh; sh = sh->next) {
00098         if (Q_stricmp(sh->name, strippedName) == 0) {
00099             if (sh != sh2) {
00100                 sh->remappedShader = sh2;
00101             } else {
00102                 sh->remappedShader = NULL;
00103             }
00104         }
00105     }
00106     if (timeOffset) {
00107         sh2->timeOffset = atof(timeOffset);
00108     }
00109 }
00110 
00111 /*
00112 ===============
00113 ParseVector
00114 ===============
00115 */
00116 static qboolean ParseVector( char **text, int count, float *v ) {
00117     char    *token;
00118     int     i;
00119 
00120     // FIXME: spaces are currently required after parens, should change parseext...
00121     token = COM_ParseExt( text, qfalse );
00122     if ( strcmp( token, "(" ) ) {
00123         ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
00124         return qfalse;
00125     }
00126 
00127     for ( i = 0 ; i < count ; i++ ) {
00128         token = COM_ParseExt( text, qfalse );
00129         if ( !token[0] ) {
00130             ri.Printf( PRINT_WARNING, "WARNING: missing vector element in shader '%s'\n", shader.name );
00131             return qfalse;
00132         }
00133         v[i] = atof( token );
00134     }
00135 
00136     token = COM_ParseExt( text, qfalse );
00137     if ( strcmp( token, ")" ) ) {
00138         ri.Printf( PRINT_WARNING, "WARNING: missing parenthesis in shader '%s'\n", shader.name );
00139         return qfalse;
00140     }
00141 
00142     return qtrue;
00143 }
00144 
00145 
00146 /*
00147 ===============
00148 NameToAFunc
00149 ===============
00150 */
00151 static unsigned NameToAFunc( const char *funcname )
00152 {   
00153     if ( !Q_stricmp( funcname, "GT0" ) )
00154     {
00155         return GLS_ATEST_GT_0;
00156     }
00157     else if ( !Q_stricmp( funcname, "LT128" ) )
00158     {
00159         return GLS_ATEST_LT_80;
00160     }
00161     else if ( !Q_stricmp( funcname, "GE128" ) )
00162     {
00163         return GLS_ATEST_GE_80;
00164     }
00165 
00166     ri.Printf( PRINT_WARNING, "WARNING: invalid alphaFunc name '%s' in shader '%s'\n", funcname, shader.name );
00167     return 0;
00168 }
00169 
00170 
00171 /*
00172 ===============
00173 NameToSrcBlendMode
00174 ===============
00175 */
00176 static int NameToSrcBlendMode( const char *name )
00177 {
00178     if ( !Q_stricmp( name, "GL_ONE" ) )
00179     {
00180         return GLS_SRCBLEND_ONE;
00181     }
00182     else if ( !Q_stricmp( name, "GL_ZERO" ) )
00183     {
00184         return GLS_SRCBLEND_ZERO;
00185     }
00186     else if ( !Q_stricmp( name, "GL_DST_COLOR" ) )
00187     {
00188         return GLS_SRCBLEND_DST_COLOR;
00189     }
00190     else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_COLOR" ) )
00191     {
00192         return GLS_SRCBLEND_ONE_MINUS_DST_COLOR;
00193     }
00194     else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
00195     {
00196         return GLS_SRCBLEND_SRC_ALPHA;
00197     }
00198     else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
00199     {
00200         return GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA;
00201     }
00202     else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
00203     {
00204         return GLS_SRCBLEND_DST_ALPHA;
00205     }
00206     else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
00207     {
00208         return GLS_SRCBLEND_ONE_MINUS_DST_ALPHA;
00209     }
00210     else if ( !Q_stricmp( name, "GL_SRC_ALPHA_SATURATE" ) )
00211     {
00212         return GLS_SRCBLEND_ALPHA_SATURATE;
00213     }
00214 
00215     ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
00216     return GLS_SRCBLEND_ONE;
00217 }
00218 
00219 /*
00220 ===============
00221 NameToDstBlendMode
00222 ===============
00223 */
00224 static int NameToDstBlendMode( const char *name )
00225 {
00226     if ( !Q_stricmp( name, "GL_ONE" ) )
00227     {
00228         return GLS_DSTBLEND_ONE;
00229     }
00230     else if ( !Q_stricmp( name, "GL_ZERO" ) )
00231     {
00232         return GLS_DSTBLEND_ZERO;
00233     }
00234     else if ( !Q_stricmp( name, "GL_SRC_ALPHA" ) )
00235     {
00236         return GLS_DSTBLEND_SRC_ALPHA;
00237     }
00238     else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_ALPHA" ) )
00239     {
00240         return GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
00241     }
00242     else if ( !Q_stricmp( name, "GL_DST_ALPHA" ) )
00243     {
00244         return GLS_DSTBLEND_DST_ALPHA;
00245     }
00246     else if ( !Q_stricmp( name, "GL_ONE_MINUS_DST_ALPHA" ) )
00247     {
00248         return GLS_DSTBLEND_ONE_MINUS_DST_ALPHA;
00249     }
00250     else if ( !Q_stricmp( name, "GL_SRC_COLOR" ) )
00251     {
00252         return GLS_DSTBLEND_SRC_COLOR;
00253     }
00254     else if ( !Q_stricmp( name, "GL_ONE_MINUS_SRC_COLOR" ) )
00255     {
00256         return GLS_DSTBLEND_ONE_MINUS_SRC_COLOR;
00257     }
00258 
00259     ri.Printf( PRINT_WARNING, "WARNING: unknown blend mode '%s' in shader '%s', substituting GL_ONE\n", name, shader.name );
00260     return GLS_DSTBLEND_ONE;
00261 }
00262 
00263 /*
00264 ===============
00265 NameToGenFunc
00266 ===============
00267 */
00268 static genFunc_t NameToGenFunc( const char *funcname )
00269 {
00270     if ( !Q_stricmp( funcname, "sin" ) )
00271     {
00272         return GF_SIN;
00273     }
00274     else if ( !Q_stricmp( funcname, "square" ) )
00275     {
00276         return GF_SQUARE;
00277     }
00278     else if ( !Q_stricmp( funcname, "triangle" ) )
00279     {
00280         return GF_TRIANGLE;
00281     }
00282     else if ( !Q_stricmp( funcname, "sawtooth" ) )
00283     {
00284         return GF_SAWTOOTH;
00285     }
00286     else if ( !Q_stricmp( funcname, "inversesawtooth" ) )
00287     {
00288         return GF_INVERSE_SAWTOOTH;
00289     }
00290     else if ( !Q_stricmp( funcname, "noise" ) )
00291     {
00292         return GF_NOISE;
00293     }
00294 
00295     ri.Printf( PRINT_WARNING, "WARNING: invalid genfunc name '%s' in shader '%s'\n", funcname, shader.name );
00296     return GF_SIN;
00297 }
00298 
00299 
00300 /*
00301 ===================
00302 ParseWaveForm
00303 ===================
00304 */
00305 static void ParseWaveForm( char **text, waveForm_t *wave )
00306 {
00307     char *token;
00308 
00309     token = COM_ParseExt( text, qfalse );
00310     if ( token[0] == 0 )
00311     {
00312         ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
00313         return;
00314     }
00315     wave->func = NameToGenFunc( token );
00316 
00317     // BASE, AMP, PHASE, FREQ
00318     token = COM_ParseExt( text, qfalse );
00319     if ( token[0] == 0 )
00320     {
00321         ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
00322         return;
00323     }
00324     wave->base = atof( token );
00325 
00326     token = COM_ParseExt( text, qfalse );
00327     if ( token[0] == 0 )
00328     {
00329         ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
00330         return;
00331     }
00332     wave->amplitude = atof( token );
00333 
00334     token = COM_ParseExt( text, qfalse );
00335     if ( token[0] == 0 )
00336     {
00337         ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
00338         return;
00339     }
00340     wave->phase = atof( token );
00341 
00342     token = COM_ParseExt( text, qfalse );
00343     if ( token[0] == 0 )
00344     {
00345         ri.Printf( PRINT_WARNING, "WARNING: missing waveform parm in shader '%s'\n", shader.name );
00346         return;
00347     }
00348     wave->frequency = atof( token );
00349 }
00350 
00351 
00352 /*
00353 ===================
00354 ParseTexMod
00355 ===================
00356 */
00357 static void ParseTexMod( char *_text, shaderStage_t *stage )
00358 {
00359     const char *token;
00360     char **text = &_text;
00361     texModInfo_t *tmi;
00362 
00363     if ( stage->bundle[0].numTexMods == TR_MAX_TEXMODS ) {
00364         ri.Error( ERR_DROP, "ERROR: too many tcMod stages in shader '%s'\n", shader.name );
00365         return;
00366     }
00367 
00368     tmi = &stage->bundle[0].texMods[stage->bundle[0].numTexMods];
00369     stage->bundle[0].numTexMods++;
00370 
00371     token = COM_ParseExt( text, qfalse );
00372 
00373     //
00374     // turb
00375     //
00376     if ( !Q_stricmp( token, "turb" ) )
00377     {
00378         token = COM_ParseExt( text, qfalse );
00379         if ( token[0] == 0 )
00380         {
00381             ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb parms in shader '%s'\n", shader.name );
00382             return;
00383         }
00384         tmi->wave.base = atof( token );
00385         token = COM_ParseExt( text, qfalse );
00386         if ( token[0] == 0 )
00387         {
00388             ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
00389             return;
00390         }
00391         tmi->wave.amplitude = atof( token );
00392         token = COM_ParseExt( text, qfalse );
00393         if ( token[0] == 0 )
00394         {
00395             ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
00396             return;
00397         }
00398         tmi->wave.phase = atof( token );
00399         token = COM_ParseExt( text, qfalse );
00400         if ( token[0] == 0 )
00401         {
00402             ri.Printf( PRINT_WARNING, "WARNING: missing tcMod turb in shader '%s'\n", shader.name );
00403             return;
00404         }
00405         tmi->wave.frequency = atof( token );
00406 
00407         tmi->type = TMOD_TURBULENT;
00408     }
00409     //
00410     // scale
00411     //
00412     else if ( !Q_stricmp( token, "scale" ) )
00413     {
00414         token = COM_ParseExt( text, qfalse );
00415         if ( token[0] == 0 )
00416         {
00417             ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
00418             return;
00419         }
00420         tmi->scale[0] = atof( token );
00421 
00422         token = COM_ParseExt( text, qfalse );
00423         if ( token[0] == 0 )
00424         {
00425             ri.Printf( PRINT_WARNING, "WARNING: missing scale parms in shader '%s'\n", shader.name );
00426             return;
00427         }
00428         tmi->scale[1] = atof( token );
00429         tmi->type = TMOD_SCALE;
00430     }
00431     //
00432     // scroll
00433     //
00434     else if ( !Q_stricmp( token, "scroll" ) )
00435     {
00436         token = COM_ParseExt( text, qfalse );
00437         if ( token[0] == 0 )
00438         {
00439             ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
00440             return;
00441         }
00442         tmi->scroll[0] = atof( token );
00443         token = COM_ParseExt( text, qfalse );
00444         if ( token[0] == 0 )
00445         {
00446             ri.Printf( PRINT_WARNING, "WARNING: missing scale scroll parms in shader '%s'\n", shader.name );
00447             return;
00448         }
00449         tmi->scroll[1] = atof( token );
00450         tmi->type = TMOD_SCROLL;
00451     }
00452     //
00453     // stretch
00454     //
00455     else if ( !Q_stricmp( token, "stretch" ) )
00456     {
00457         token = COM_ParseExt( text, qfalse );
00458         if ( token[0] == 0 )
00459         {
00460             ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
00461             return;
00462         }
00463         tmi->wave.func = NameToGenFunc( token );
00464 
00465         token = COM_ParseExt( text, qfalse );
00466         if ( token[0] == 0 )
00467         {
00468             ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
00469             return;
00470         }
00471         tmi->wave.base = atof( token );
00472 
00473         token = COM_ParseExt( text, qfalse );
00474         if ( token[0] == 0 )
00475         {
00476             ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
00477             return;
00478         }
00479         tmi->wave.amplitude = atof( token );
00480 
00481         token = COM_ParseExt( text, qfalse );
00482         if ( token[0] == 0 )
00483         {
00484             ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
00485             return;
00486         }
00487         tmi->wave.phase = atof( token );
00488 
00489         token = COM_ParseExt( text, qfalse );
00490         if ( token[0] == 0 )
00491         {
00492             ri.Printf( PRINT_WARNING, "WARNING: missing stretch parms in shader '%s'\n", shader.name );
00493             return;
00494         }
00495         tmi->wave.frequency = atof( token );
00496         
00497         tmi->type = TMOD_STRETCH;
00498     }
00499     //
00500     // transform
00501     //
00502     else if ( !Q_stricmp( token, "transform" ) )
00503     {
00504         token = COM_ParseExt( text, qfalse );
00505         if ( token[0] == 0 )
00506         {
00507             ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
00508             return;
00509         }
00510         tmi->matrix[0][0] = atof( token );
00511 
00512         token = COM_ParseExt( text, qfalse );
00513         if ( token[0] == 0 )
00514         {
00515             ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
00516             return;
00517         }
00518         tmi->matrix[0][1] = atof( token );
00519 
00520         token = COM_ParseExt( text, qfalse );
00521         if ( token[0] == 0 )
00522         {
00523             ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
00524             return;
00525         }
00526         tmi->matrix[1][0] = atof( token );
00527 
00528         token = COM_ParseExt( text, qfalse );
00529         if ( token[0] == 0 )
00530         {
00531             ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
00532             return;
00533         }
00534         tmi->matrix[1][1] = atof( token );
00535 
00536         token = COM_ParseExt( text, qfalse );
00537         if ( token[0] == 0 )
00538         {
00539             ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
00540             return;
00541         }
00542         tmi->translate[0] = atof( token );
00543 
00544         token = COM_ParseExt( text, qfalse );
00545         if ( token[0] == 0 )
00546         {
00547             ri.Printf( PRINT_WARNING, "WARNING: missing transform parms in shader '%s'\n", shader.name );
00548             return;
00549         }
00550         tmi->translate[1] = atof( token );
00551 
00552         tmi->type = TMOD_TRANSFORM;
00553     }
00554     //
00555     // rotate
00556     //
00557     else if ( !Q_stricmp( token, "rotate" ) )
00558     {
00559         token = COM_ParseExt( text, qfalse );
00560         if ( token[0] == 0 )
00561         {
00562             ri.Printf( PRINT_WARNING, "WARNING: missing tcMod rotate parms in shader '%s'\n", shader.name );
00563             return;
00564         }
00565         tmi->rotateSpeed = atof( token );
00566         tmi->type = TMOD_ROTATE;
00567     }
00568     //
00569     // entityTranslate
00570     //
00571     else if ( !Q_stricmp( token, "entityTranslate" ) )
00572     {
00573         tmi->type = TMOD_ENTITY_TRANSLATE;
00574     }
00575     else
00576     {
00577         ri.Printf( PRINT_WARNING, "WARNING: unknown tcMod '%s' in shader '%s'\n", token, shader.name );
00578     }
00579 }
00580 
00581 
00582 /*
00583 ===================
00584 ParseStage
00585 ===================
00586 */
00587 static qboolean ParseStage( shaderStage_t *stage, char **text )
00588 {
00589     char *token;
00590     int depthMaskBits = GLS_DEPTHMASK_TRUE, blendSrcBits = 0, blendDstBits = 0, atestBits = 0, depthFuncBits = 0;
00591     qboolean depthMaskExplicit = qfalse;
00592 
00593     stage->active = qtrue;
00594 
00595     while ( 1 )
00596     {
00597         token = COM_ParseExt( text, qtrue );
00598         if ( !token[0] )
00599         {
00600             ri.Printf( PRINT_WARNING, "WARNING: no matching '}' found\n" );
00601             return qfalse;
00602         }
00603 
00604         if ( token[0] == '}' )
00605         {
00606             break;
00607         }
00608         //
00609         // map <name>
00610         //
00611         else if ( !Q_stricmp( token, "map" ) )
00612         {
00613             token = COM_ParseExt( text, qfalse );
00614             if ( !token[0] )
00615             {
00616                 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'map' keyword in shader '%s'\n", shader.name );
00617                 return qfalse;
00618             }
00619 
00620             if ( !Q_stricmp( token, "$whiteimage" ) )
00621             {
00622                 stage->bundle[0].image[0] = tr.whiteImage;
00623                 continue;
00624             }
00625             else if ( !Q_stricmp( token, "$lightmap" ) )
00626             {
00627                 stage->bundle[0].isLightmap = qtrue;
00628                 if ( shader.lightmapIndex < 0 ) {
00629                     stage->bundle[0].image[0] = tr.whiteImage;
00630                 } else {
00631                     stage->bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
00632                 }
00633                 continue;
00634             }
00635             else
00636             {
00637                 stage->bundle[0].image[0] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_REPEAT );
00638                 if ( !stage->bundle[0].image[0] )
00639                 {
00640                     ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
00641                     return qfalse;
00642                 }
00643             }
00644         }
00645         //
00646         // clampmap <name>
00647         //
00648         else if ( !Q_stricmp( token, "clampmap" ) )
00649         {
00650             token = COM_ParseExt( text, qfalse );
00651             if ( !token[0] )
00652             {
00653                 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name );
00654                 return qfalse;
00655             }
00656 
00657             stage->bundle[0].image[0] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_CLAMP );
00658             if ( !stage->bundle[0].image[0] )
00659             {
00660                 ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
00661                 return qfalse;
00662             }
00663         }
00664         //
00665         // animMap <frequency> <image1> .... <imageN>
00666         //
00667         else if ( !Q_stricmp( token, "animMap" ) )
00668         {
00669             token = COM_ParseExt( text, qfalse );
00670             if ( !token[0] )
00671             {
00672                 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'animMmap' keyword in shader '%s'\n", shader.name );
00673                 return qfalse;
00674             }
00675             stage->bundle[0].imageAnimationSpeed = atof( token );
00676 
00677             // parse up to MAX_IMAGE_ANIMATIONS animations
00678             while ( 1 ) {
00679                 int     num;
00680 
00681                 token = COM_ParseExt( text, qfalse );
00682                 if ( !token[0] ) {
00683                     break;
00684                 }
00685                 num = stage->bundle[0].numImageAnimations;
00686                 if ( num < MAX_IMAGE_ANIMATIONS ) {
00687                     stage->bundle[0].image[num] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_REPEAT );
00688                     if ( !stage->bundle[0].image[num] )
00689                     {
00690                         ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name );
00691                         return qfalse;
00692                     }
00693                     stage->bundle[0].numImageAnimations++;
00694                 }
00695             }
00696         }
00697         else if ( !Q_stricmp( token, "videoMap" ) )
00698         {
00699             token = COM_ParseExt( text, qfalse );
00700             if ( !token[0] )
00701             {
00702                 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'videoMmap' keyword in shader '%s'\n", shader.name );
00703                 return qfalse;
00704             }
00705             stage->bundle[0].videoMapHandle = ri.CIN_PlayCinematic( token, 0, 0, 256, 256, (CIN_loop | CIN_silent | CIN_shader));
00706             if (stage->bundle[0].videoMapHandle != -1) {
00707                 stage->bundle[0].isVideoMap = qtrue;
00708                 stage->bundle[0].image[0] = tr.scratchImage[stage->bundle[0].videoMapHandle];
00709             }
00710         }
00711         //
00712         // alphafunc <func>
00713         //
00714         else if ( !Q_stricmp( token, "alphaFunc" ) )
00715         {
00716             token = COM_ParseExt( text, qfalse );
00717             if ( !token[0] )
00718             {
00719                 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'alphaFunc' keyword in shader '%s'\n", shader.name );
00720                 return qfalse;
00721             }
00722 
00723             atestBits = NameToAFunc( token );
00724         }
00725         //
00726         // depthFunc <func>
00727         //
00728         else if ( !Q_stricmp( token, "depthfunc" ) )
00729         {
00730             token = COM_ParseExt( text, qfalse );
00731 
00732             if ( !token[0] )
00733             {
00734                 ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'depthfunc' keyword in shader '%s'\n", shader.name );
00735                 return qfalse;
00736             }
00737 
00738             if ( !Q_stricmp( token, "lequal" ) )
00739             {
00740                 depthFuncBits = 0;
00741             }
00742             else if ( !Q_stricmp( token, "equal" ) )
00743             {
00744                 depthFuncBits = GLS_DEPTHFUNC_EQUAL;
00745             }
00746             else
00747             {
00748                 ri.Printf( PRINT_WARNING, "WARNING: unknown depthfunc '%s' in shader '%s'\n", token, shader.name );
00749                 continue;
00750             }
00751         }
00752         //
00753         // detail
00754         //
00755         else if ( !Q_stricmp( token, "detail" ) )
00756         {
00757             stage->isDetail = qtrue;
00758         }
00759         //
00760         // blendfunc <srcFactor> <dstFactor>
00761         // or blendfunc <add|filter|blend>
00762         //
00763         else if ( !Q_stricmp( token, "blendfunc" ) )
00764         {
00765             token = COM_ParseExt( text, qfalse );
00766             if ( token[0] == 0 )
00767             {
00768                 ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
00769                 continue;
00770             }
00771             // check for "simple" blends first
00772             if ( !Q_stricmp( token, "add" ) ) {
00773                 blendSrcBits = GLS_SRCBLEND_ONE;
00774                 blendDstBits = GLS_DSTBLEND_ONE;
00775             } else if ( !Q_stricmp( token, "filter" ) ) {
00776                 blendSrcBits = GLS_SRCBLEND_DST_COLOR;
00777                 blendDstBits = GLS_DSTBLEND_ZERO;
00778             } else if ( !Q_stricmp( token, "blend" ) ) {
00779                 blendSrcBits = GLS_SRCBLEND_SRC_ALPHA;
00780                 blendDstBits = GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
00781             } else {
00782                 // complex double blends
00783                 blendSrcBits = NameToSrcBlendMode( token );
00784 
00785                 token = COM_ParseExt( text, qfalse );
00786                 if ( token[0] == 0 )
00787                 {
00788                     ri.Printf( PRINT_WARNING, "WARNING: missing parm for blendFunc in shader '%s'\n", shader.name );
00789                     continue;
00790                 }
00791                 blendDstBits = NameToDstBlendMode( token );
00792             }
00793 
00794             // clear depth mask for blended surfaces
00795             if ( !depthMaskExplicit )
00796             {
00797                 depthMaskBits = 0;
00798             }
00799         }
00800         //
00801         // rgbGen
00802         //
00803         else if ( !Q_stricmp( token, "rgbGen" ) )
00804         {
00805             token = COM_ParseExt( text, qfalse );
00806             if ( token[0] == 0 )
00807             {
00808                 ri.Printf( PRINT_WARNING, "WARNING: missing parameters for rgbGen in shader '%s'\n", shader.name );
00809                 continue;
00810             }
00811 
00812             if ( !Q_stricmp( token, "wave" ) )
00813             {
00814                 ParseWaveForm( text, &stage->rgbWave );
00815                 stage->rgbGen = CGEN_WAVEFORM;
00816             }
00817             else if ( !Q_stricmp( token, "const" ) )
00818             {
00819                 vec3_t  color;
00820 
00821                 ParseVector( text, 3, color );
00822                 stage->constantColor[0] = 255 * color[0];
00823                 stage->constantColor[1] = 255 * color[1];
00824                 stage->constantColor[2] = 255 * color[2];
00825 
00826                 stage->rgbGen = CGEN_CONST;
00827             }
00828             else if ( !Q_stricmp( token, "identity" ) )
00829             {
00830                 stage->rgbGen = CGEN_IDENTITY;
00831             }
00832             else if ( !Q_stricmp( token, "identityLighting" ) )
00833             {
00834                 stage->rgbGen = CGEN_IDENTITY_LIGHTING;
00835             }
00836             else if ( !Q_stricmp( token, "entity" ) )
00837             {
00838                 stage->rgbGen = CGEN_ENTITY;
00839             }
00840             else if ( !Q_stricmp( token, "oneMinusEntity" ) )
00841             {
00842                 stage->rgbGen = CGEN_ONE_MINUS_ENTITY;
00843             }
00844             else if ( !Q_stricmp( token, "vertex" ) )
00845             {
00846                 stage->rgbGen = CGEN_VERTEX;
00847                 if ( stage->alphaGen == 0 ) {
00848                     stage->alphaGen = AGEN_VERTEX;
00849                 }
00850             }
00851             else if ( !Q_stricmp( token, "exactVertex" ) )
00852             {
00853                 stage->rgbGen = CGEN_EXACT_VERTEX;
00854             }
00855             else if ( !Q_stricmp( token, "lightingDiffuse" ) )
00856             {
00857                 stage->rgbGen = CGEN_LIGHTING_DIFFUSE;
00858             }
00859             else if ( !Q_stricmp( token, "oneMinusVertex" ) )
00860             {
00861                 stage->rgbGen = CGEN_ONE_MINUS_VERTEX;
00862             }
00863             else
00864             {
00865                 ri.Printf( PRINT_WARNING, "WARNING: unknown rgbGen parameter '%s' in shader '%s'\n", token, shader.name );
00866                 continue;
00867             }
00868         }
00869         //
00870         // alphaGen 
00871         //
00872         else if ( !Q_stricmp( token, "alphaGen" ) )
00873         {
00874             token = COM_ParseExt( text, qfalse );
00875             if ( token[0] == 0 )
00876             {
00877                 ri.Printf( PRINT_WARNING, "WARNING: missing parameters for alphaGen in shader '%s'\n", shader.name );
00878                 continue;
00879             }
00880 
00881             if ( !Q_stricmp( token, "wave" ) )
00882             {
00883                 ParseWaveForm( text, &stage->alphaWave );
00884                 stage->alphaGen = AGEN_WAVEFORM;
00885             }
00886             else if ( !Q_stricmp( token, "const" ) )
00887             {
00888                 token = COM_ParseExt( text, qfalse );
00889                 stage->constantColor[3] = 255 * atof( token );
00890                 stage->alphaGen = AGEN_CONST;
00891             }
00892             else if ( !Q_stricmp( token, "identity" ) )
00893             {
00894                 stage->alphaGen = AGEN_IDENTITY;
00895             }
00896             else if ( !Q_stricmp( token, "entity" ) )
00897             {
00898                 stage->alphaGen = AGEN_ENTITY;
00899             }
00900             else if ( !Q_stricmp( token, "oneMinusEntity" ) )
00901             {
00902                 stage->alphaGen = AGEN_ONE_MINUS_ENTITY;
00903             }
00904             else if ( !Q_stricmp( token, "vertex" ) )
00905             {
00906                 stage->alphaGen = AGEN_VERTEX;
00907             }
00908             else if ( !Q_stricmp( token, "lightingSpecular" ) )
00909             {
00910                 stage->alphaGen = AGEN_LIGHTING_SPECULAR;
00911             }
00912             else if ( !Q_stricmp( token, "oneMinusVertex" ) )
00913             {
00914                 stage->alphaGen = AGEN_ONE_MINUS_VERTEX;
00915             }
00916             else if ( !Q_stricmp( token, "portal" ) )
00917             {
00918                 stage->alphaGen = AGEN_PORTAL;
00919                 token = COM_ParseExt( text, qfalse );
00920                 if ( token[0] == 0 )
00921                 {
00922                     shader.portalRange = 256;
00923                     ri.Printf( PRINT_WARNING, "WARNING: missing range parameter for alphaGen portal in shader '%s', defaulting to 256\n", shader.name );
00924                 }
00925                 else
00926                 {
00927                     shader.portalRange = atof( token );
00928                 }
00929             }
00930             else
00931             {
00932                 ri.Printf( PRINT_WARNING, "WARNING: unknown alphaGen parameter '%s' in shader '%s'\n", token, shader.name );
00933                 continue;
00934             }
00935         }
00936         //
00937         // tcGen <function>
00938         //
00939         else if ( !Q_stricmp(token, "texgen") || !Q_stricmp( token, "tcGen" ) ) 
00940         {
00941             token = COM_ParseExt( text, qfalse );
00942             if ( token[0] == 0 )
00943             {
00944                 ri.Printf( PRINT_WARNING, "WARNING: missing texgen parm in shader '%s'\n", shader.name );
00945                 continue;
00946             }
00947 
00948             if ( !Q_stricmp( token, "environment" ) )
00949             {
00950                 stage->bundle[0].tcGen = TCGEN_ENVIRONMENT_MAPPED;
00951             }
00952             else if ( !Q_stricmp( token, "lightmap" ) )
00953             {
00954                 stage->bundle[0].tcGen = TCGEN_LIGHTMAP;
00955             }
00956             else if ( !Q_stricmp( token, "texture" ) || !Q_stricmp( token, "base" ) )
00957             {
00958                 stage->bundle[0].tcGen = TCGEN_TEXTURE;
00959             }
00960             else if ( !Q_stricmp( token, "vector" ) )
00961             {
00962                 ParseVector( text, 3, stage->bundle[0].tcGenVectors[0] );
00963                 ParseVector( text, 3, stage->bundle[0].tcGenVectors[1] );
00964 
00965                 stage->bundle[0].tcGen = TCGEN_VECTOR;
00966             }
00967             else 
00968             {
00969                 ri.Printf( PRINT_WARNING, "WARNING: unknown texgen parm in shader '%s'\n", shader.name );
00970             }
00971         }
00972         //
00973         // tcMod <type> <...>
00974         //
00975         else if ( !Q_stricmp( token, "tcMod" ) )
00976         {
00977             char buffer[1024] = "";
00978 
00979             while ( 1 )
00980             {
00981                 token = COM_ParseExt( text, qfalse );
00982                 if ( token[0] == 0 )
00983                     break;
00984                 strcat( buffer, token );
00985                 strcat( buffer, " " );
00986             }
00987 
00988             ParseTexMod( buffer, stage );
00989 
00990             continue;
00991         }
00992         //
00993         // depthmask
00994         //
00995         else if ( !Q_stricmp( token, "depthwrite" ) )
00996         {
00997             depthMaskBits = GLS_DEPTHMASK_TRUE;
00998             depthMaskExplicit = qtrue;
00999 
01000             continue;
01001         }
01002         else
01003         {
01004             ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name );
01005             return qfalse;
01006         }
01007     }
01008 
01009     //
01010     // if cgen isn't explicitly specified, use either identity or identitylighting
01011     //
01012     if ( stage->rgbGen == CGEN_BAD ) {
01013         if ( blendSrcBits == 0 ||
01014             blendSrcBits == GLS_SRCBLEND_ONE || 
01015             blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) {
01016             stage->rgbGen = CGEN_IDENTITY_LIGHTING;
01017         } else {
01018             stage->rgbGen = CGEN_IDENTITY;
01019         }
01020     }
01021 
01022 
01023     //
01024     // implicitly assume that a GL_ONE GL_ZERO blend mask disables blending
01025     //
01026     if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && 
01027          ( blendDstBits == GLS_DSTBLEND_ZERO ) )
01028     {
01029         blendDstBits = blendSrcBits = 0;
01030         depthMaskBits = GLS_DEPTHMASK_TRUE;
01031     }
01032 
01033     // decide which agens we can skip
01034     if ( stage->alphaGen == CGEN_IDENTITY ) {
01035         if ( stage->rgbGen == CGEN_IDENTITY
01036             || stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) {
01037             stage->alphaGen = AGEN_SKIP;
01038         }
01039     }
01040 
01041     //
01042     // compute state bits
01043     //
01044     stage->stateBits = depthMaskBits | 
01045                        blendSrcBits | blendDstBits | 
01046                        atestBits | 
01047                        depthFuncBits;
01048 
01049     return qtrue;
01050 }
01051 
01052 /*
01053 ===============
01054 ParseDeform
01055 
01056 deformVertexes wave <spread> <waveform> <base> <amplitude> <phase> <frequency>
01057 deformVertexes normal <frequency> <amplitude>
01058 deformVertexes move <vector> <waveform> <base> <amplitude> <phase> <frequency>
01059 deformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed>
01060 deformVertexes projectionShadow
01061 deformVertexes autoSprite
01062 deformVertexes autoSprite2
01063 deformVertexes text[0-7]
01064 ===============
01065 */
01066 static void ParseDeform( char **text ) {
01067     char    *token;
01068     deformStage_t   *ds;
01069 
01070     token = COM_ParseExt( text, qfalse );
01071     if ( token[0] == 0 )
01072     {
01073         ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name );
01074         return;
01075     }
01076 
01077     if ( shader.numDeforms == MAX_SHADER_DEFORMS ) {
01078         ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name );
01079         return;
01080     }
01081 
01082     ds = &shader.deforms[ shader.numDeforms ];
01083     shader.numDeforms++;
01084 
01085     if ( !Q_stricmp( token, "projectionShadow" ) ) {
01086         ds->deformation = DEFORM_PROJECTION_SHADOW;
01087         return;
01088     }
01089 
01090     if ( !Q_stricmp( token, "autosprite" ) ) {
01091         ds->deformation = DEFORM_AUTOSPRITE;
01092         return;
01093     }
01094 
01095     if ( !Q_stricmp( token, "autosprite2" ) ) {
01096         ds->deformation = DEFORM_AUTOSPRITE2;
01097         return;
01098     }
01099 
01100     if ( !Q_stricmpn( token, "text", 4 ) ) {
01101         int     n;
01102         
01103         n = token[4] - '0';
01104         if ( n < 0 || n > 7 ) {
01105             n = 0;
01106         }
01107         ds->deformation = DEFORM_TEXT0 + n;
01108         return;
01109     }
01110 
01111     if ( !Q_stricmp( token, "bulge" ) ) {
01112         token = COM_ParseExt( text, qfalse );
01113         if ( token[0] == 0 )
01114         {
01115             ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
01116             return;
01117         }
01118         ds->bulgeWidth = atof( token );
01119 
01120         token = COM_ParseExt( text, qfalse );
01121         if ( token[0] == 0 )
01122         {
01123             ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
01124             return;
01125         }
01126         ds->bulgeHeight = atof( token );
01127 
01128         token = COM_ParseExt( text, qfalse );
01129         if ( token[0] == 0 )
01130         {
01131             ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
01132             return;
01133         }
01134         ds->bulgeSpeed = atof( token );
01135 
01136         ds->deformation = DEFORM_BULGE;
01137         return;
01138     }
01139 
01140     if ( !Q_stricmp( token, "wave" ) )
01141     {
01142         token = COM_ParseExt( text, qfalse );
01143         if ( token[0] == 0 )
01144         {
01145             ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
01146             return;
01147         }
01148 
01149         if ( atof( token ) != 0 )
01150         {
01151             ds->deformationSpread = 1.0f / atof( token );
01152         }
01153         else
01154         {
01155             ds->deformationSpread = 100.0f;
01156             ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name );
01157         }
01158 
01159         ParseWaveForm( text, &ds->deformationWave );
01160         ds->deformation = DEFORM_WAVE;
01161         return;
01162     }
01163 
01164     if ( !Q_stricmp( token, "normal" ) )
01165     {
01166         token = COM_ParseExt( text, qfalse );
01167         if ( token[0] == 0 )
01168         {
01169             ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
01170             return;
01171         }
01172         ds->deformationWave.amplitude = atof( token );
01173 
01174         token = COM_ParseExt( text, qfalse );
01175         if ( token[0] == 0 )
01176         {
01177             ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
01178             return;
01179         }
01180         ds->deformationWave.frequency = atof( token );
01181 
01182         ds->deformation = DEFORM_NORMALS;
01183         return;
01184     }
01185 
01186     if ( !Q_stricmp( token, "move" ) ) {
01187         int     i;
01188 
01189         for ( i = 0 ; i < 3 ; i++ ) {
01190             token = COM_ParseExt( text, qfalse );
01191             if ( token[0] == 0 ) {
01192                 ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
01193                 return;
01194             }
01195             ds->moveVector[i] = atof( token );
01196         }
01197 
01198         ParseWaveForm( text, &ds->deformationWave );
01199         ds->deformation = DEFORM_MOVE;
01200         return;
01201     }
01202 
01203     ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name );
01204 }
01205 
01206 
01207 /*
01208 ===============
01209 ParseSkyParms
01210 
01211 skyParms <outerbox> <cloudheight> <innerbox>
01212 ===============
01213 */
01214 static void ParseSkyParms( char **text ) {
01215     char        *token;
01216     static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
01217     char        pathname[MAX_QPATH];
01218     int         i;
01219 
01220     // outerbox
01221     token = COM_ParseExt( text, qfalse );
01222     if ( token[0] == 0 ) {
01223         ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
01224         return;
01225     }
01226     if ( strcmp( token, "-" ) ) {
01227         for (i=0 ; i<6 ; i++) {
01228             Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
01229                 , token, suf[i] );
01230             shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_CLAMP );
01231             if ( !shader.sky.outerbox[i] ) {
01232                 shader.sky.outerbox[i] = tr.defaultImage;
01233             }
01234         }
01235     }
01236 
01237     // cloudheight
01238     token = COM_ParseExt( text, qfalse );
01239     if ( token[0] == 0 ) {
01240         ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
01241         return;
01242     }
01243     shader.sky.cloudHeight = atof( token );
01244     if ( !shader.sky.cloudHeight ) {
01245         shader.sky.cloudHeight = 512;
01246     }
01247     R_InitSkyTexCoords( shader.sky.cloudHeight );
01248 
01249 
01250     // innerbox
01251     token = COM_ParseExt( text, qfalse );
01252     if ( token[0] == 0 ) {
01253         ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
01254         return;
01255     }
01256     if ( strcmp( token, "-" ) ) {
01257         for (i=0 ; i<6 ; i++) {
01258             Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
01259                 , token, suf[i] );
01260             shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_REPEAT );
01261             if ( !shader.sky.innerbox[i] ) {
01262                 shader.sky.innerbox[i] = tr.defaultImage;
01263             }
01264         }
01265     }
01266 
01267     shader.isSky = qtrue;
01268 }
01269 
01270 
01271 /*
01272 =================
01273 ParseSort
01274 =================
01275 */
01276 void ParseSort( char **text ) {
01277     char    *token;
01278 
01279     token = COM_ParseExt( text, qfalse );
01280     if ( token[0] == 0 ) {
01281         ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name );
01282         return;
01283     }
01284 
01285     if ( !Q_stricmp( token, "portal" ) ) {
01286         shader.sort = SS_PORTAL;
01287     } else if ( !Q_stricmp( token, "sky" ) ) {
01288         shader.sort = SS_ENVIRONMENT;
01289     } else if ( !Q_stricmp( token, "opaque" ) ) {
01290         shader.sort = SS_OPAQUE;
01291     }else if ( !Q_stricmp( token, "decal" ) ) {
01292         shader.sort = SS_DECAL;
01293     } else if ( !Q_stricmp( token, "seeThrough" ) ) {
01294         shader.sort = SS_SEE_THROUGH;
01295     } else if ( !Q_stricmp( token, "banner" ) ) {
01296         shader.sort = SS_BANNER;
01297     } else if ( !Q_stricmp( token, "additive" ) ) {
01298         shader.sort = SS_BLEND1;
01299     } else if ( !Q_stricmp( token, "nearest" ) ) {
01300         shader.sort = SS_NEAREST;
01301     } else if ( !Q_stricmp( token, "underwater" ) ) {
01302         shader.sort = SS_UNDERWATER;
01303     } else {
01304         shader.sort = atof( token );
01305     }
01306 }
01307 
01308 
01309 
01310 // this table is also present in q3map
01311 
01312 typedef struct {
01313     char    *name;
01314     int     clearSolid, surfaceFlags, contents;
01315 } infoParm_t;
01316 
01317 infoParm_t  infoParms[] = {
01318     // server relevant contents
01319     {"water",       1,  0,  CONTENTS_WATER },
01320     {"slime",       1,  0,  CONTENTS_SLIME },       // mildly damaging
01321     {"lava",        1,  0,  CONTENTS_LAVA },        // very damaging
01322     {"playerclip",  1,  0,  CONTENTS_PLAYERCLIP },
01323     {"monsterclip", 1,  0,  CONTENTS_MONSTERCLIP },
01324     {"nodrop",      1,  0,  CONTENTS_NODROP },      // don't drop items or leave bodies (death fog, lava, etc)
01325     {"nonsolid",    1,  SURF_NONSOLID,  0},                     // clears the solid flag
01326 
01327     // utility relevant attributes
01328     {"origin",      1,  0,  CONTENTS_ORIGIN },      // center of rotating brushes
01329     {"trans",       0,  0,  CONTENTS_TRANSLUCENT }, // don't eat contained surfaces
01330     {"detail",      0,  0,  CONTENTS_DETAIL },      // don't include in structural bsp
01331     {"structural",  0,  0,  CONTENTS_STRUCTURAL },  // force into structural bsp even if trnas
01332     {"areaportal",  1,  0,  CONTENTS_AREAPORTAL },  // divides areas
01333     {"clusterportal", 1,0,  CONTENTS_CLUSTERPORTAL },   // for bots
01334     {"donotenter",  1,  0,  CONTENTS_DONOTENTER },      // for bots
01335 
01336     {"fog",         1,  0,  CONTENTS_FOG},          // carves surfaces entering
01337     {"sky",         0,  SURF_SKY,       0 },        // emit light from an environment map
01338     {"lightfilter", 0,  SURF_LIGHTFILTER, 0 },      // filter light going through it
01339     {"alphashadow", 0,  SURF_ALPHASHADOW, 0 },      // test light on a per-pixel basis
01340     {"hint",        0,  SURF_HINT,      0 },        // use as a primary splitter
01341 
01342     // server attributes
01343     {"slick",       0,  SURF_SLICK,     0 },
01344     {"noimpact",    0,  SURF_NOIMPACT,  0 },        // don't make impact explosions or marks
01345     {"nomarks",     0,  SURF_NOMARKS,   0 },        // don't make impact marks, but still explode
01346     {"ladder",      0,  SURF_LADDER,    0 },
01347     {"nodamage",    0,  SURF_NODAMAGE,  0 },
01348     {"metalsteps",  0,  SURF_METALSTEPS,0 },
01349     {"flesh",       0,  SURF_FLESH,     0 },
01350     {"nosteps",     0,  SURF_NOSTEPS,   0 },
01351 
01352     // drawsurf attributes
01353     {"nodraw",      0,  SURF_NODRAW,    0 },    // don't generate a drawsurface (or a lightmap)
01354     {"pointlight",  0,  SURF_POINTLIGHT, 0 },   // sample lighting at vertexes
01355     {"nolightmap",  0,  SURF_NOLIGHTMAP,0 },    // don't generate a lightmap
01356     {"nodlight",    0,  SURF_NODLIGHT, 0 },     // don't ever add dynamic lights
01357     {"dust",        0,  SURF_DUST, 0}           // leave a dust trail when walking on this surface
01358 };
01359 
01360 
01361 /*
01362 ===============
01363 ParseSurfaceParm
01364 
01365 surfaceparm <name>
01366 ===============
01367 */
01368 static void ParseSurfaceParm( char **text ) {
01369     char    *token;
01370     int     numInfoParms = sizeof(infoParms) / sizeof(infoParms[0]);
01371     int     i;
01372 
01373     token = COM_ParseExt( text, qfalse );
01374     for ( i = 0 ; i < numInfoParms ; i++ ) {
01375         if ( !Q_stricmp( token, infoParms[i].name ) ) {
01376             shader.surfaceFlags |= infoParms[i].surfaceFlags;
01377             shader.contentFlags |= infoParms[i].contents;
01378 #if 0
01379             if ( infoParms[i].clearSolid ) {
01380                 si->contents &= ~CONTENTS_SOLID;
01381             }
01382 #endif
01383             break;
01384         }
01385     }
01386 }
01387 
01388 /*
01389 =================
01390 ParseShader
01391 
01392 The current text pointer is at the explicit text definition of the
01393 shader.  Parse it into the global shader variable.  Later functions
01394 will optimize it.
01395 =================
01396 */
01397 static qboolean ParseShader( char **text )
01398 {
01399     char *token;
01400     int s;
01401 
01402     s = 0;
01403 
01404     token = COM_ParseExt( text, qtrue );
01405     if ( token[0] != '{' )
01406     {
01407         ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name );
01408         return qfalse;
01409     }
01410 
01411     while ( 1 )
01412     {
01413         token = COM_ParseExt( text, qtrue );
01414         if ( !token[0] )
01415         {
01416             ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name );
01417             return qfalse;
01418         }
01419 
01420         // end of shader definition
01421         if ( token[0] == '}' )
01422         {
01423             break;
01424         }
01425         // stage definition
01426         else if ( token[0] == '{' )
01427         {
01428             if ( !ParseStage( &stages[s], text ) )
01429             {
01430                 return qfalse;
01431             }
01432             stages[s].active = qtrue;
01433             s++;
01434             continue;
01435         }
01436         // skip stuff that only the QuakeEdRadient needs
01437         else if ( !Q_stricmpn( token, "qer", 3 ) ) {
01438             SkipRestOfLine( text );
01439             continue;
01440         }
01441         // sun parms
01442         else if ( !Q_stricmp( token, "q3map_sun" ) ) {
01443             float   a, b;
01444 
01445             token = COM_ParseExt( text, qfalse );
01446             tr.sunLight[0] = atof( token );
01447             token = COM_ParseExt( text, qfalse );
01448             tr.sunLight[1] = atof( token );
01449             token = COM_ParseExt( text, qfalse );
01450             tr.sunLight[2] = atof( token );
01451             
01452             VectorNormalize( tr.sunLight );
01453 
01454             token = COM_ParseExt( text, qfalse );
01455             a = atof( token );
01456             VectorScale( tr.sunLight, a, tr.sunLight);
01457 
01458             token = COM_ParseExt( text, qfalse );
01459             a = atof( token );
01460             a = a / 180 * M_PI;
01461 
01462             token = COM_ParseExt( text, qfalse );
01463             b = atof( token );
01464             b = b / 180 * M_PI;
01465 
01466             tr.sunDirection[0] = cos( a ) * cos( b );
01467             tr.sunDirection[1] = sin( a ) * cos( b );
01468             tr.sunDirection[2] = sin( b );
01469         }
01470         else if ( !Q_stricmp( token, "deformVertexes" ) ) {
01471             ParseDeform( text );
01472             continue;
01473         }
01474         else if ( !Q_stricmp( token, "tesssize" ) ) {
01475             SkipRestOfLine( text );
01476             continue;
01477         }
01478         else if ( !Q_stricmp( token, "clampTime" ) ) {
01479             token = COM_ParseExt( text, qfalse );
01480       if (token[0]) {
01481         shader.clampTime = atof(token);
01482       }
01483     }
01484         // skip stuff that only the q3map needs
01485         else if ( !Q_stricmpn( token, "q3map", 5 ) ) {
01486             SkipRestOfLine( text );
01487             continue;
01488         }
01489         // skip stuff that only q3map or the server needs
01490         else if ( !Q_stricmp( token, "surfaceParm" ) ) {
01491             ParseSurfaceParm( text );
01492             continue;
01493         }
01494         // no mip maps
01495         else if ( !Q_stricmp( token, "nomipmaps" ) )
01496         {
01497             shader.noMipMaps = qtrue;
01498             shader.noPicMip = qtrue;
01499             continue;
01500         }
01501         // no picmip adjustment
01502         else if ( !Q_stricmp( token, "nopicmip" ) )
01503         {
01504             shader.noPicMip = qtrue;
01505             continue;
01506         }
01507         // polygonOffset
01508         else if ( !Q_stricmp( token, "polygonOffset" ) )
01509         {
01510             shader.polygonOffset = qtrue;
01511             continue;
01512         }
01513         // entityMergable, allowing sprite surfaces from multiple entities
01514         // to be merged into one batch.  This is a savings for smoke
01515         // puffs and blood, but can't be used for anything where the
01516         // shader calcs (not the surface function) reference the entity color or scroll
01517         else if ( !Q_stricmp( token, "entityMergable" ) )
01518         {
01519             shader.entityMergable = qtrue;
01520             continue;
01521         }
01522         // fogParms
01523         else if ( !Q_stricmp( token, "fogParms" ) ) 
01524         {
01525             if ( !ParseVector( text, 3, shader.fogParms.color ) ) {
01526                 return qfalse;
01527             }
01528 
01529             token = COM_ParseExt( text, qfalse );
01530             if ( !token[0] ) 
01531             {
01532                 ri.Printf( PRINT_WARNING, "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader.name );
01533                 continue;
01534             }
01535             shader.fogParms.depthForOpaque = atof( token );
01536 
01537             // skip any old gradient directions
01538             SkipRestOfLine( text );
01539             continue;
01540         }
01541         // portal
01542         else if ( !Q_stricmp(token, "portal") )
01543         {
01544             shader.sort = SS_PORTAL;
01545             continue;
01546         }
01547         // skyparms <cloudheight> <outerbox> <innerbox>
01548         else if ( !Q_stricmp( token, "skyparms" ) )
01549         {
01550             ParseSkyParms( text );
01551             continue;
01552         }
01553         // light <value> determines flaring in q3map, not needed here
01554         else if ( !Q_stricmp(token, "light") ) 
01555         {
01556             token = COM_ParseExt( text, qfalse );
01557             continue;
01558         }
01559         // cull <face>
01560         else if ( !Q_stricmp( token, "cull") ) 
01561         {
01562             token = COM_ParseExt( text, qfalse );
01563             if ( token[0] == 0 )
01564             {
01565                 ri.Printf( PRINT_WARNING, "WARNING: missing cull parms in shader '%s'\n", shader.name );
01566                 continue;
01567             }
01568 
01569             if ( !Q_stricmp( token, "none" ) || !Q_stricmp( token, "twosided" ) || !Q_stricmp( token, "disable" ) )
01570             {
01571                 shader.cullType = CT_TWO_SIDED;
01572             }
01573             else if ( !Q_stricmp( token, "back" ) || !Q_stricmp( token, "backside" ) || !Q_stricmp( token, "backsided" ) )
01574             {
01575                 shader.cullType = CT_BACK_SIDED;
01576             }
01577             else
01578             {
01579                 ri.Printf( PRINT_WARNING, "WARNING: invalid cull parm '%s' in shader '%s'\n", token, shader.name );
01580             }
01581             continue;
01582         }
01583         // sort
01584         else if ( !Q_stricmp( token, "sort" ) )
01585         {
01586             ParseSort( text );
01587             continue;
01588         }
01589         else
01590         {
01591             ri.Printf( PRINT_WARNING, "WARNING: unknown general shader parameter '%s' in '%s'\n", token, shader.name );
01592             return qfalse;
01593         }
01594     }
01595 
01596     //
01597     // ignore shaders that don't have any stages, unless it is a sky or fog
01598     //
01599     if ( s == 0 && !shader.isSky && !(shader.contentFlags & CONTENTS_FOG ) ) {
01600         return qfalse;
01601     }
01602 
01603     shader.explicitlyDefined = qtrue;
01604 
01605     return qtrue;
01606 }
01607 
01608 /*
01609 ========================================================================================
01610 
01611 SHADER OPTIMIZATION AND FOGGING
01612 
01613 ========================================================================================
01614 */
01615 
01616 /*
01617 ===================
01618 ComputeStageIteratorFunc
01619 
01620 See if we can use on of the simple fastpath stage functions,
01621 otherwise set to the generic stage function
01622 ===================
01623 */
01624 static void ComputeStageIteratorFunc( void )
01625 {
01626     shader.optimalStageIteratorFunc = RB_StageIteratorGeneric;
01627 
01628     //
01629     // see if this should go into the sky path
01630     //
01631     if ( shader.isSky )
01632     {
01633         shader.optimalStageIteratorFunc = RB_StageIteratorSky;
01634         goto done;
01635     }
01636 
01637     if ( r_ignoreFastPath->integer )
01638     {
01639         return;
01640     }
01641 
01642     //
01643     // see if this can go into the vertex lit fast path
01644     //
01645     if ( shader.numUnfoggedPasses == 1 )
01646     {
01647         if ( stages[0].rgbGen == CGEN_LIGHTING_DIFFUSE )
01648         {
01649             if ( stages[0].alphaGen == AGEN_IDENTITY )
01650             {
01651                 if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE )
01652                 {
01653                     if ( !shader.polygonOffset )
01654                     {
01655                         if ( !shader.multitextureEnv )
01656                         {
01657                             if ( !shader.numDeforms )
01658                             {
01659                                 shader.optimalStageIteratorFunc = RB_StageIteratorVertexLitTexture;
01660                                 goto done;
01661                             }
01662                         }
01663                     }
01664                 }
01665             }
01666         }
01667     }
01668 
01669     //
01670     // see if this can go into an optimized LM, multitextured path
01671     //
01672     if ( shader.numUnfoggedPasses == 1 )
01673     {
01674         if ( ( stages[0].rgbGen == CGEN_IDENTITY ) && ( stages[0].alphaGen == AGEN_IDENTITY ) )
01675         {
01676             if ( stages[0].bundle[0].tcGen == TCGEN_TEXTURE && 
01677                 stages[0].bundle[1].tcGen == TCGEN_LIGHTMAP )
01678             {
01679                 if ( !shader.polygonOffset )
01680                 {
01681                     if ( !shader.numDeforms )
01682                     {
01683                         if ( shader.multitextureEnv )
01684                         {
01685                             shader.optimalStageIteratorFunc = RB_StageIteratorLightmappedMultitexture;
01686                             goto done;
01687                         }
01688                     }
01689                 }
01690             }
01691         }
01692     }
01693 
01694 done:
01695     return;
01696 }
01697 
01698 typedef struct {
01699     int     blendA;
01700     int     blendB;
01701 
01702     int     multitextureEnv;
01703     int     multitextureBlend;
01704 } collapse_t;
01705 
01706 static collapse_t   collapse[] = {
01707     { 0, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,    
01708         GL_MODULATE, 0 },
01709 
01710     { 0, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
01711         GL_MODULATE, 0 },
01712 
01713     { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
01714         GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
01715 
01716     { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR,
01717         GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
01718 
01719     { GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
01720         GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
01721 
01722     { GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO, GLS_DSTBLEND_SRC_COLOR | GLS_SRCBLEND_ZERO,
01723         GL_MODULATE, GLS_DSTBLEND_ZERO | GLS_SRCBLEND_DST_COLOR },
01724 
01725     { 0, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
01726         GL_ADD, 0 },
01727 
01728     { GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE,
01729         GL_ADD, GLS_DSTBLEND_ONE | GLS_SRCBLEND_ONE },
01730 #if 0
01731     { 0, GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_SRCBLEND_SRC_ALPHA,
01732         GL_DECAL, 0 },
01733 #endif
01734     { -1 }
01735 };
01736 
01737 /*
01738 ================
01739 CollapseMultitexture
01740 
01741 Attempt to combine two stages into a single multitexture stage
01742 FIXME: I think modulated add + modulated add collapses incorrectly
01743 =================
01744 */
01745 static qboolean CollapseMultitexture( void ) {
01746     int abits, bbits;
01747     int i;
01748     textureBundle_t tmpBundle;
01749 
01750     if ( !qglActiveTextureARB ) {
01751         return qfalse;
01752     }
01753 
01754     // make sure both stages are active
01755     if ( !stages[0].active || !stages[1].active ) {
01756         return qfalse;
01757     }
01758 
01759     // on voodoo2, don't combine different tmus
01760     if ( glConfig.driverType == GLDRV_VOODOO ) {
01761         if ( stages[0].bundle[0].image[0]->TMU ==
01762              stages[1].bundle[0].image[0]->TMU ) {
01763             return qfalse;
01764         }
01765     }
01766 
01767     abits = stages[0].stateBits;
01768     bbits = stages[1].stateBits;
01769 
01770     // make sure that both stages have identical state other than blend modes
01771     if ( ( abits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) !=
01772         ( bbits & ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS | GLS_DEPTHMASK_TRUE ) ) ) {
01773         return qfalse;
01774     }
01775 
01776     abits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
01777     bbits &= ( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
01778 
01779     // search for a valid multitexture blend function
01780     for ( i = 0; collapse[i].blendA != -1 ; i++ ) {
01781         if ( abits == collapse[i].blendA
01782             && bbits == collapse[i].blendB ) {
01783             break;
01784         }
01785     }
01786 
01787     // nothing found
01788     if ( collapse[i].blendA == -1 ) {
01789         return qfalse;
01790     }
01791 
01792     // GL_ADD is a separate extension
01793     if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) {
01794         return qfalse;
01795     }
01796 
01797     // make sure waveforms have identical parameters
01798     if ( ( stages[0].rgbGen != stages[1].rgbGen ) ||
01799         ( stages[0].alphaGen != stages[1].alphaGen ) )  {
01800         return qfalse;
01801     }
01802 
01803     // an add collapse can only have identity colors
01804     if ( collapse[i].multitextureEnv == GL_ADD && stages[0].rgbGen != CGEN_IDENTITY ) {
01805         return qfalse;
01806     }
01807 
01808     if ( stages[0].rgbGen == CGEN_WAVEFORM )
01809     {
01810         if ( memcmp( &stages[0].rgbWave,
01811                      &stages[1].rgbWave,
01812                      sizeof( stages[0].rgbWave ) ) )
01813         {
01814             return qfalse;
01815         }
01816     }
01817     if ( stages[0].alphaGen == CGEN_WAVEFORM )
01818     {
01819         if ( memcmp( &stages[0].alphaWave,
01820                      &stages[1].alphaWave,
01821                      sizeof( stages[0].alphaWave ) ) )
01822         {
01823             return qfalse;
01824         }
01825     }
01826 
01827 
01828     // make sure that lightmaps are in bundle 1 for 3dfx
01829     if ( stages[0].bundle[0].isLightmap )
01830     {
01831         tmpBundle = stages[0].bundle[0];
01832         stages[0].bundle[0] = stages[1].bundle[0];
01833         stages[0].bundle[1] = tmpBundle;
01834     }
01835     else
01836     {
01837         stages[0].bundle[1] = stages[1].bundle[0];
01838     }
01839 
01840     // set the new blend state bits
01841     shader.multitextureEnv = collapse[i].multitextureEnv;
01842     stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
01843     stages[0].stateBits |= collapse[i].multitextureBlend;
01844 
01845     //
01846     // move down subsequent shaders
01847     //
01848     memmove( &stages[1], &stages[2], sizeof( stages[0] ) * ( MAX_SHADER_STAGES - 2 ) );
01849     Com_Memset( &stages[MAX_SHADER_STAGES-1], 0, sizeof( stages[0] ) );
01850 
01851     return qtrue;
01852 }
01853 
01854 /*
01855 =============
01856 
01857 FixRenderCommandList
01858 https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
01859 Arnout: this is a nasty issue. Shaders can be registered after drawsurfaces are generated
01860 but before the frame is rendered. This will, for the duration of one frame, cause drawsurfaces
01861 to be rendered with bad shaders. To fix this, need to go through all render commands and fix
01862 sortedIndex.
01863 ==============
01864 */
01865 static void FixRenderCommandList( int newShader ) {
01866     renderCommandList_t *cmdList = &backEndData[tr.smpFrame]->commands;
01867 
01868     if( cmdList ) {
01869         const void *curCmd = cmdList->cmds;
01870 
01871         while ( 1 ) {
01872             switch ( *(const int *)curCmd ) {
01873             case RC_SET_COLOR:
01874                 {
01875                 const setColorCommand_t *sc_cmd = (const setColorCommand_t *)curCmd;
01876                 curCmd = (const void *)(sc_cmd + 1);
01877                 break;
01878                 }
01879             case RC_STRETCH_PIC:
01880                 {
01881                 const stretchPicCommand_t *sp_cmd = (const stretchPicCommand_t *)curCmd;
01882                 curCmd = (const void *)(sp_cmd + 1);
01883                 break;
01884                 }
01885             case RC_DRAW_SURFS:
01886                 {
01887                 int i;
01888                 drawSurf_t  *drawSurf;
01889                 shader_t    *shader;
01890                 int         fogNum;
01891                 int         entityNum;
01892                 int         dlightMap;
01893                 int         sortedIndex;
01894                 const drawSurfsCommand_t *ds_cmd =  (const drawSurfsCommand_t *)curCmd;
01895 
01896                 for( i = 0, drawSurf = ds_cmd->drawSurfs; i < ds_cmd->numDrawSurfs; i++, drawSurf++ ) {
01897                     R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlightMap );
01898                     sortedIndex = (( drawSurf->sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1));
01899                     if( sortedIndex >= newShader ) {
01900                         sortedIndex++;
01901                         drawSurf->sort = (sortedIndex << QSORT_SHADERNUM_SHIFT) | entityNum | ( fogNum << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
01902                     }
01903                 }
01904                 curCmd = (const void *)(ds_cmd + 1);
01905                 break;
01906                 }
01907             case RC_DRAW_BUFFER:
01908                 {
01909                 const drawBufferCommand_t *db_cmd = (const drawBufferCommand_t *)curCmd;
01910                 curCmd = (const void *)(db_cmd + 1);
01911                 break;
01912                 }
01913             case RC_SWAP_BUFFERS:
01914                 {
01915                 const swapBuffersCommand_t *sb_cmd = (const swapBuffersCommand_t *)curCmd;
01916                 curCmd = (const void *)(sb_cmd + 1);
01917                 break;
01918                 }
01919             case RC_END_OF_LIST:
01920             default:
01921                 return;
01922             }
01923         }
01924     }
01925 }
01926 
01927 /*
01928 ==============
01929 SortNewShader
01930 
01931 Positions the most recently created shader in the tr.sortedShaders[]
01932 array so that the shader->sort key is sorted reletive to the other
01933 shaders.
01934 
01935 Sets shader->sortedIndex
01936 ==============
01937 */
01938 static void SortNewShader( void ) {
01939     int     i;
01940     float   sort;
01941     shader_t    *newShader;
01942 
01943     newShader = tr.shaders[ tr.numShaders - 1 ];
01944     sort = newShader->sort;
01945 
01946     for ( i = tr.numShaders - 2 ; i >= 0 ; i-- ) {
01947         if ( tr.sortedShaders[ i ]->sort <= sort ) {
01948             break;
01949         }
01950         tr.sortedShaders[i+1] = tr.sortedShaders[i];
01951         tr.sortedShaders[i+1]->sortedIndex++;
01952     }
01953 
01954     // Arnout: fix rendercommandlist
01955     // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=493
01956     FixRenderCommandList( i+1 );
01957 
01958     newShader->sortedIndex = i+1;
01959     tr.sortedShaders[i+1] = newShader;
01960 }
01961 
01962 
01963 /*
01964 ====================
01965 GeneratePermanentShader
01966 ====================
01967 */
01968 static shader_t *GeneratePermanentShader( void ) {
01969     shader_t    *newShader;
01970     int         i, b;
01971     int         size, hash;
01972 
01973     if ( tr.numShaders == MAX_SHADERS ) {
01974         ri.Printf( PRINT_WARNING, "WARNING: GeneratePermanentShader - MAX_SHADERS hit\n");
01975         return tr.defaultShader;
01976     }
01977 
01978     newShader = ri.Hunk_Alloc( sizeof( shader_t ), h_low );
01979 
01980     *newShader = shader;
01981 
01982     if ( shader.sort <= SS_OPAQUE ) {
01983         newShader->fogPass = FP_EQUAL;
01984     } else if ( shader.contentFlags & CONTENTS_FOG ) {
01985         newShader->fogPass = FP_LE;
01986     }
01987 
01988     tr.shaders[ tr.numShaders ] = newShader;
01989     newShader->index = tr.numShaders;
01990     
01991     tr.sortedShaders[ tr.numShaders ] = newShader;
01992     newShader->sortedIndex = tr.numShaders;
01993 
01994     tr.numShaders++;
01995 
01996     for ( i = 0 ; i < newShader->numUnfoggedPasses ; i++ ) {
01997         if ( !stages[i].active ) {
01998             break;
01999         }
02000         newShader->stages[i] = ri.Hunk_Alloc( sizeof( stages[i] ), h_low );
02001         *newShader->stages[i] = stages[i];
02002 
02003         for ( b = 0 ; b < NUM_TEXTURE_BUNDLES ; b++ ) {
02004             size = newShader->stages[i]->bundle[b].numTexMods * sizeof( texModInfo_t );
02005             newShader->stages[i]->bundle[b].texMods = ri.Hunk_Alloc( size, h_low );
02006             Com_Memcpy( newShader->stages[i]->bundle[b].texMods, stages[i].bundle[b].texMods, size );
02007         }
02008     }
02009 
02010     SortNewShader();
02011 
02012     hash = generateHashValue(newShader->name, FILE_HASH_SIZE);
02013     newShader->next = hashTable[hash];
02014     hashTable[hash] = newShader;
02015 
02016     return newShader;
02017 }
02018 
02019 /*
02020 =================
02021 VertexLightingCollapse
02022 
02023 If vertex lighting is enabled, only render a single
02024 pass, trying to guess which is the correct one to best aproximate
02025 what it is supposed to look like.
02026 =================
02027 */
02028 static void VertexLightingCollapse( void ) {
02029     int     stage;
02030     shaderStage_t   *bestStage;
02031     int     bestImageRank;
02032     int     rank;
02033 
02034     // if we aren't opaque, just use the first pass
02035     if ( shader.sort == SS_OPAQUE ) {
02036 
02037         // pick the best texture for the single pass
02038         bestStage = &stages[0];
02039         bestImageRank = -999999;
02040 
02041         for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {
02042             shaderStage_t *pStage = &stages[stage];
02043 
02044             if ( !pStage->active ) {
02045                 break;
02046             }
02047             rank = 0;
02048 
02049             if ( pStage->bundle[0].isLightmap ) {
02050                 rank -= 100;
02051             }
02052             if ( pStage->bundle[0].tcGen != TCGEN_TEXTURE ) {
02053                 rank -= 5;
02054             }
02055             if ( pStage->bundle[0].numTexMods ) {
02056                 rank -= 5;
02057             }
02058             if ( pStage->rgbGen != CGEN_IDENTITY && pStage->rgbGen != CGEN_IDENTITY_LIGHTING ) {
02059                 rank -= 3;
02060             }
02061 
02062             if ( rank > bestImageRank  ) {
02063                 bestImageRank = rank;
02064                 bestStage = pStage;
02065             }
02066         }
02067 
02068         stages[0].bundle[0] = bestStage->bundle[0];
02069         stages[0].stateBits &= ~( GLS_DSTBLEND_BITS | GLS_SRCBLEND_BITS );
02070         stages[0].stateBits |= GLS_DEPTHMASK_TRUE;
02071         if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
02072             stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
02073         } else {
02074             stages[0].rgbGen = CGEN_EXACT_VERTEX;
02075         }
02076         stages[0].alphaGen = AGEN_SKIP;     
02077     } else {
02078         // don't use a lightmap (tesla coils)
02079         if ( stages[0].bundle[0].isLightmap ) {
02080             stages[0] = stages[1];
02081         }
02082 
02083         // if we were in a cross-fade cgen, hack it to normal
02084         if ( stages[0].rgbGen == CGEN_ONE_MINUS_ENTITY || stages[1].rgbGen == CGEN_ONE_MINUS_ENTITY ) {
02085             stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
02086         }
02087         if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_SAWTOOTH )
02088             && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_INVERSE_SAWTOOTH ) ) {
02089             stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
02090         }
02091         if ( ( stages[0].rgbGen == CGEN_WAVEFORM && stages[0].rgbWave.func == GF_INVERSE_SAWTOOTH )
02092             && ( stages[1].rgbGen == CGEN_WAVEFORM && stages[1].rgbWave.func == GF_SAWTOOTH ) ) {
02093             stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
02094         }
02095     }
02096 
02097     for ( stage = 1; stage < MAX_SHADER_STAGES; stage++ ) {
02098         shaderStage_t *pStage = &stages[stage];
02099 
02100         if ( !pStage->active ) {
02101             break;
02102         }
02103 
02104         Com_Memset( pStage, 0, sizeof( *pStage ) );
02105     }
02106 }
02107 
02108 /*
02109 =========================
02110 FinishShader
02111 
02112 Returns a freshly allocated shader with all the needed info
02113 from the current global working shader
02114 =========================
02115 */
02116 static shader_t *FinishShader( void ) {
02117     int stage;
02118     qboolean        hasLightmapStage;
02119     qboolean        vertexLightmap;
02120 
02121     hasLightmapStage = qfalse;
02122     vertexLightmap = qfalse;
02123 
02124     //
02125     // set sky stuff appropriate
02126     //
02127     if ( shader.isSky ) {
02128         shader.sort = SS_ENVIRONMENT;
02129     }
02130 
02131     //
02132     // set polygon offset
02133     //
02134     if ( shader.polygonOffset && !shader.sort ) {
02135         shader.sort = SS_DECAL;
02136     }
02137 
02138     //
02139     // set appropriate stage information
02140     //
02141     for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ ) {
02142         shaderStage_t *pStage = &stages[stage];
02143 
02144         if ( !pStage->active ) {
02145             break;
02146         }
02147 
02148     // check for a missing texture
02149         if ( !pStage->bundle[0].image[0] ) {
02150             ri.Printf( PRINT_WARNING, "Shader %s has a stage with no image\n", shader.name );
02151             pStage->active = qfalse;
02152             continue;
02153         }
02154 
02155         //
02156         // ditch this stage if it's detail and detail textures are disabled
02157         //
02158         if ( pStage->isDetail && !r_detailTextures->integer ) {
02159             if ( stage < ( MAX_SHADER_STAGES - 1 ) ) {
02160                 memmove( pStage, pStage + 1, sizeof( *pStage ) * ( MAX_SHADER_STAGES - stage - 1 ) );
02161                 Com_Memset(  pStage + 1, 0, sizeof( *pStage ) );
02162             }
02163             continue;
02164         }
02165 
02166         //
02167         // default texture coordinate generation
02168         //
02169         if ( pStage->bundle[0].isLightmap ) {
02170             if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
02171                 pStage->bundle[0].tcGen = TCGEN_LIGHTMAP;
02172             }
02173             hasLightmapStage = qtrue;
02174         } else {
02175             if ( pStage->bundle[0].tcGen == TCGEN_BAD ) {
02176                 pStage->bundle[0].tcGen = TCGEN_TEXTURE;
02177             }
02178         }
02179 
02180 
02181     // not a true lightmap but we want to leave existing 
02182     // behaviour in place and not print out a warning
02183     //if (pStage->rgbGen == CGEN_VERTEX) {
02184     //  vertexLightmap = qtrue;
02185     //}
02186 
02187 
02188 
02189         //
02190         // determine sort order and fog color adjustment
02191         //
02192         if ( ( pStage->stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) &&
02193              ( stages[0].stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) ) {
02194             int blendSrcBits = pStage->stateBits & GLS_SRCBLEND_BITS;
02195             int blendDstBits = pStage->stateBits & GLS_DSTBLEND_BITS;
02196 
02197             // fog color adjustment only works for blend modes that have a contribution
02198             // that aproaches 0 as the modulate values aproach 0 --
02199             // GL_ONE, GL_ONE
02200             // GL_ZERO, GL_ONE_MINUS_SRC_COLOR
02201             // GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
02202 
02203             // modulate, additive
02204             if ( ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE ) ) ||
02205                 ( ( blendSrcBits == GLS_SRCBLEND_ZERO ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_COLOR ) ) ) {
02206                 pStage->adjustColorsForFog = ACFF_MODULATE_RGB;
02207             }
02208             // strict blend
02209             else if ( ( blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
02210             {
02211                 pStage->adjustColorsForFog = ACFF_MODULATE_ALPHA;
02212             }
02213             // premultiplied alpha
02214             else if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) && ( blendDstBits == GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ) )
02215             {
02216                 pStage->adjustColorsForFog = ACFF_MODULATE_RGBA;
02217             } else {
02218                 // we can't adjust this one correctly, so it won't be exactly correct in fog
02219             }
02220 
02221             // don't screw with sort order if this is a portal or environment
02222             if ( !shader.sort ) {
02223                 // see through item, like a grill or grate
02224                 if ( pStage->stateBits & GLS_DEPTHMASK_TRUE ) {
02225                     shader.sort = SS_SEE_THROUGH;
02226                 } else {
02227                     shader.sort = SS_BLEND0;
02228                 }
02229             }
02230         }
02231     }
02232 
02233     // there are times when you will need to manually apply a sort to
02234     // opaque alpha tested shaders that have later blend passes
02235     if ( !shader.sort ) {
02236         shader.sort = SS_OPAQUE;
02237     }
02238 
02239     //
02240     // if we are in r_vertexLight mode, never use a lightmap texture
02241     //
02242     if ( stage > 1 && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) {
02243         VertexLightingCollapse();
02244         stage = 1;
02245         hasLightmapStage = qfalse;
02246     }
02247 
02248     //
02249     // look for multitexture potential
02250     //
02251     if ( stage > 1 && CollapseMultitexture() ) {
02252         stage--;
02253     }
02254 
02255     if ( shader.lightmapIndex >= 0 && !hasLightmapStage ) {
02256         if (vertexLightmap) {
02257             ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has VERTEX forced lightmap!\n", shader.name );
02258         } else {
02259             ri.Printf( PRINT_DEVELOPER, "WARNING: shader '%s' has lightmap but no lightmap stage!\n", shader.name );
02260             shader.lightmapIndex = LIGHTMAP_NONE;
02261         }
02262     }
02263 
02264 
02265     //
02266     // compute number of passes
02267     //
02268     shader.numUnfoggedPasses = stage;
02269 
02270     // fogonly shaders don't have any normal passes
02271     if ( stage == 0 ) {
02272         shader.sort = SS_FOG;
02273     }
02274 
02275     // determine which stage iterator function is appropriate
02276     ComputeStageIteratorFunc();
02277 
02278     return GeneratePermanentShader();
02279 }
02280 
02281 //========================================================================================
02282 
02283 /*
02284 ====================
02285 FindShaderInShaderText
02286 
02287 Scans the combined text description of all the shader files for
02288 the given shader name.
02289 
02290 return NULL if not found
02291 
02292 If found, it will return a valid shader
02293 =====================
02294 */
02295 static char *FindShaderInShaderText( const char *shadername ) {
02296 
02297     char *token, *p;
02298 
02299     int i, hash;
02300 
02301     hash = generateHashValue(shadername, MAX_SHADERTEXT_HASH);
02302 
02303     for (i = 0; shaderTextHashTable[hash][i]; i++) {
02304         p = shaderTextHashTable[hash][i];
02305         token = COM_ParseExt(&p, qtrue);
02306         if ( !Q_stricmp( token, shadername ) ) {
02307             return p;
02308         }
02309     }
02310 
02311     p = s_shaderText;
02312 
02313     if ( !p ) {
02314         return NULL;
02315     }
02316 
02317     // look for label
02318     while ( 1 ) {
02319         token = COM_ParseExt( &p, qtrue );
02320         if ( token[0] == 0 ) {
02321             break;
02322         }
02323 
02324         if ( !Q_stricmp( token, shadername ) ) {
02325             return p;
02326         }
02327         else {
02328             // skip the definition
02329             SkipBracedSection( &p );
02330         }
02331     }
02332 
02333     return NULL;
02334 }
02335 
02336 
02337 /*
02338 ==================
02339 R_FindShaderByName
02340 
02341 Will always return a valid shader, but it might be the
02342 default shader if the real one can't be found.
02343 ==================
02344 */
02345 shader_t *R_FindShaderByName( const char *name ) {
02346     char        strippedName[MAX_QPATH];
02347     int         hash;
02348     shader_t    *sh;
02349 
02350     if ( (name==NULL) || (name[0] == 0) ) {  // bk001205
02351         return tr.defaultShader;
02352     }
02353 
02354     COM_StripExtension( name, strippedName );
02355 
02356     hash = generateHashValue(strippedName, FILE_HASH_SIZE);
02357 
02358     //
02359     // see if the shader is already loaded
02360     //
02361     for (sh=hashTable[hash]; sh; sh=sh->next) {
02362         // NOTE: if there was no shader or image available with the name strippedName
02363         // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
02364         // have to check all default shaders otherwise for every call to R_FindShader
02365         // with that same strippedName a new default shader is created.
02366         if (Q_stricmp(sh->name, strippedName) == 0) {
02367             // match found
02368             return sh;
02369         }
02370     }
02371 
02372     return tr.defaultShader;
02373 }
02374 
02375 
02376 /*
02377 ===============
02378 R_FindShader
02379 
02380 Will always return a valid shader, but it might be the
02381 default shader if the real one can't be found.
02382 
02383 In the interest of not requiring an explicit shader text entry to
02384 be defined for every single image used in the game, three default
02385 shader behaviors can be auto-created for any image:
02386 
02387 If lightmapIndex == LIGHTMAP_NONE, then the image will have
02388 dynamic diffuse lighting applied to it, as apropriate for most
02389 entity skin surfaces.
02390 
02391 If lightmapIndex == LIGHTMAP_2D, then the image will be used
02392 for 2D rendering unless an explicit shader is found
02393 
02394 If lightmapIndex == LIGHTMAP_BY_VERTEX, then the image will use
02395 the vertex rgba modulate values, as apropriate for misc_model
02396 pre-lit surfaces.
02397 
02398 Other lightmapIndex values will have a lightmap stage created
02399 and src*dest blending applied with the texture, as apropriate for
02400 most world construction surfaces.
02401 
02402 ===============
02403 */
02404 shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) {
02405     char        strippedName[MAX_QPATH];
02406     char        fileName[MAX_QPATH];
02407     int         i, hash;
02408     char        *shaderText;
02409     image_t     *image;
02410     shader_t    *sh;
02411 
02412     if ( name[0] == 0 ) {
02413         return tr.defaultShader;
02414     }
02415 
02416     // use (fullbright) vertex lighting if the bsp file doesn't have
02417     // lightmaps
02418     if ( lightmapIndex >= 0 && lightmapIndex >= tr.numLightmaps ) {
02419         lightmapIndex = LIGHTMAP_BY_VERTEX;
02420     }
02421 
02422     COM_StripExtension( name, strippedName );
02423 
02424     hash = generateHashValue(strippedName, FILE_HASH_SIZE);
02425 
02426     //
02427     // see if the shader is already loaded
02428     //
02429     for (sh = hashTable[hash]; sh; sh = sh->next) {
02430         // NOTE: if there was no shader or image available with the name strippedName
02431         // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
02432         // have to check all default shaders otherwise for every call to R_FindShader
02433         // with that same strippedName a new default shader is created.
02434         if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&
02435              !Q_stricmp(sh->name, strippedName)) {
02436             // match found
02437             return sh;
02438         }
02439     }
02440 
02441     // make sure the render thread is stopped, because we are probably
02442     // going to have to upload an image
02443     if (r_smp->integer) {
02444         R_SyncRenderThread();
02445     }
02446 
02447     // clear the global shader
02448     Com_Memset( &shader, 0, sizeof( shader ) );
02449     Com_Memset( &stages, 0, sizeof( stages ) );
02450     Q_strncpyz(shader.name, strippedName, sizeof(shader.name));
02451     shader.lightmapIndex = lightmapIndex;
02452     for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
02453         stages[i].bundle[0].texMods = texMods[i];
02454     }
02455 
02456     // FIXME: set these "need" values apropriately
02457     shader.needsNormal = qtrue;
02458     shader.needsST1 = qtrue;
02459     shader.needsST2 = qtrue;
02460     shader.needsColor = qtrue;
02461 
02462     //
02463     // attempt to define shader from an explicit parameter file
02464     //
02465     shaderText = FindShaderInShaderText( strippedName );
02466     if ( shaderText ) {
02467         // enable this when building a pak file to get a global list
02468         // of all explicit shaders
02469         if ( r_printShaders->integer ) {
02470             ri.Printf( PRINT_ALL, "*SHADER* %s\n", name );
02471         }
02472 
02473         if ( !ParseShader( &shaderText ) ) {
02474             // had errors, so use default shader
02475             shader.defaultShader = qtrue;
02476         }
02477         sh = FinishShader();
02478         return sh;
02479     }
02480 
02481 
02482     //
02483     // if not defined in the in-memory shader descriptions,
02484     // look for a single TGA, BMP, or PCX
02485     //
02486     Q_strncpyz( fileName, name, sizeof( fileName ) );
02487     COM_DefaultExtension( fileName, sizeof( fileName ), ".tga" );
02488     image = R_FindImageFile( fileName, mipRawImage, mipRawImage, mipRawImage ? GL_REPEAT : GL_CLAMP );
02489     if ( !image ) {
02490         ri.Printf( PRINT_DEVELOPER, "Couldn't find image for shader %s\n", name );
02491         shader.defaultShader = qtrue;
02492         return FinishShader();
02493     }
02494 
02495     //
02496     // create the default shading commands
02497     //
02498     if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
02499         // dynamic colors at vertexes
02500         stages[0].bundle[0].image[0] = image;
02501         stages[0].active = qtrue;
02502         stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
02503         stages[0].stateBits = GLS_DEFAULT;
02504     } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
02505         // explicit colors at vertexes
02506         stages[0].bundle[0].image[0] = image;
02507         stages[0].active = qtrue;
02508         stages[0].rgbGen = CGEN_EXACT_VERTEX;
02509         stages[0].alphaGen = AGEN_SKIP;
02510         stages[0].stateBits = GLS_DEFAULT;
02511     } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
02512         // GUI elements
02513         stages[0].bundle[0].image[0] = image;
02514         stages[0].active = qtrue;
02515         stages[0].rgbGen = CGEN_VERTEX;
02516         stages[0].alphaGen = AGEN_VERTEX;
02517         stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
02518               GLS_SRCBLEND_SRC_ALPHA |
02519               GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
02520     } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
02521         // fullbright level
02522         stages[0].bundle[0].image[0] = tr.whiteImage;
02523         stages[0].active = qtrue;
02524         stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
02525         stages[0].stateBits = GLS_DEFAULT;
02526 
02527         stages[1].bundle[0].image[0] = image;
02528         stages[1].active = qtrue;
02529         stages[1].rgbGen = CGEN_IDENTITY;
02530         stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
02531     } else {
02532         // two pass lightmap
02533         stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
02534         stages[0].bundle[0].isLightmap = qtrue;
02535         stages[0].active = qtrue;
02536         stages[0].rgbGen = CGEN_IDENTITY;   // lightmaps are scaled on creation
02537                                                     // for identitylight
02538         stages[0].stateBits = GLS_DEFAULT;
02539 
02540         stages[1].bundle[0].image[0] = image;
02541         stages[1].active = qtrue;
02542         stages[1].rgbGen = CGEN_IDENTITY;
02543         stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
02544     }
02545 
02546     return FinishShader();
02547 }
02548 
02549 
02550 qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage) {
02551     int         i, hash;
02552     shader_t    *sh;
02553 
02554     hash = generateHashValue(name, FILE_HASH_SIZE);
02555     
02556     //
02557     // see if the shader is already loaded
02558     //
02559     for (sh=hashTable[hash]; sh; sh=sh->next) {
02560         // NOTE: if there was no shader or image available with the name strippedName
02561         // then a default shader is created with lightmapIndex == LIGHTMAP_NONE, so we
02562         // have to check all default shaders otherwise for every call to R_FindShader
02563         // with that same strippedName a new default shader is created.
02564         if ( (sh->lightmapIndex == lightmapIndex || sh->defaultShader) &&
02565             // index by name
02566             !Q_stricmp(sh->name, name)) {
02567             // match found
02568             return sh->index;
02569         }
02570     }
02571 
02572     // make sure the render thread is stopped, because we are probably
02573     // going to have to upload an image
02574     if (r_smp->integer) {
02575         R_SyncRenderThread();
02576     }
02577 
02578     // clear the global shader
02579     Com_Memset( &shader, 0, sizeof( shader ) );
02580     Com_Memset( &stages, 0, sizeof( stages ) );
02581     Q_strncpyz(shader.name, name, sizeof(shader.name));
02582     shader.lightmapIndex = lightmapIndex;
02583     for ( i = 0 ; i < MAX_SHADER_STAGES ; i++ ) {
02584         stages[i].bundle[0].texMods = texMods[i];
02585     }
02586 
02587     // FIXME: set these "need" values apropriately
02588     shader.needsNormal = qtrue;
02589     shader.needsST1 = qtrue;
02590     shader.needsST2 = qtrue;
02591     shader.needsColor = qtrue;
02592 
02593     //
02594     // create the default shading commands
02595     //
02596     if ( shader.lightmapIndex == LIGHTMAP_NONE ) {
02597         // dynamic colors at vertexes
02598         stages[0].bundle[0].image[0] = image;
02599         stages[0].active = qtrue;
02600         stages[0].rgbGen = CGEN_LIGHTING_DIFFUSE;
02601         stages[0].stateBits = GLS_DEFAULT;
02602     } else if ( shader.lightmapIndex == LIGHTMAP_BY_VERTEX ) {
02603         // explicit colors at vertexes
02604         stages[0].bundle[0].image[0] = image;
02605         stages[0].active = qtrue;
02606         stages[0].rgbGen = CGEN_EXACT_VERTEX;
02607         stages[0].alphaGen = AGEN_SKIP;
02608         stages[0].stateBits = GLS_DEFAULT;
02609     } else if ( shader.lightmapIndex == LIGHTMAP_2D ) {
02610         // GUI elements
02611         stages[0].bundle[0].image[0] = image;
02612         stages[0].active = qtrue;
02613         stages[0].rgbGen = CGEN_VERTEX;
02614         stages[0].alphaGen = AGEN_VERTEX;
02615         stages[0].stateBits = GLS_DEPTHTEST_DISABLE |
02616               GLS_SRCBLEND_SRC_ALPHA |
02617               GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA;
02618     } else if ( shader.lightmapIndex == LIGHTMAP_WHITEIMAGE ) {
02619         // fullbright level
02620         stages[0].bundle[0].image[0] = tr.whiteImage;
02621         stages[0].active = qtrue;
02622         stages[0].rgbGen = CGEN_IDENTITY_LIGHTING;
02623         stages[0].stateBits = GLS_DEFAULT;
02624 
02625         stages[1].bundle[0].image[0] = image;
02626         stages[1].active = qtrue;
02627         stages[1].rgbGen = CGEN_IDENTITY;
02628         stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
02629     } else {
02630         // two pass lightmap
02631         stages[0].bundle[0].image[0] = tr.lightmaps[shader.lightmapIndex];
02632         stages[0].bundle[0].isLightmap = qtrue;
02633         stages[0].active = qtrue;
02634         stages[0].rgbGen = CGEN_IDENTITY;   // lightmaps are scaled on creation
02635                                                     // for identitylight
02636         stages[0].stateBits = GLS_DEFAULT;
02637 
02638         stages[1].bundle[0].image[0] = image;
02639         stages[1].active = qtrue;
02640         stages[1].rgbGen = CGEN_IDENTITY;
02641         stages[1].stateBits |= GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO;
02642     }
02643 
02644     sh = FinishShader();
02645   return sh->index; 
02646 }
02647 
02648 
02649 /* 
02650 ====================
02651 RE_RegisterShader
02652 
02653 This is the exported shader entry point for the rest of the system
02654 It will always return an index that will be valid.
02655 
02656 This should really only be used for explicit shaders, because there is no
02657 way to ask for different implicit lighting modes (vertex, lightmap, etc)
02658 ====================
02659 */
02660 qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ) {
02661     shader_t    *sh;
02662 
02663     if ( strlen( name ) >= MAX_QPATH ) {
02664         Com_Printf( "Shader name exceeds MAX_QPATH\n" );
02665         return 0;
02666     }
02667 
02668     sh = R_FindShader( name, lightmapIndex, qtrue );
02669 
02670     // we want to return 0 if the shader failed to
02671     // load for some reason, but R_FindShader should
02672     // still keep a name allocated for it, so if
02673     // something calls RE_RegisterShader again with
02674     // the same name, we don't try looking for it again
02675     if ( sh->defaultShader ) {
02676         return 0;
02677     }
02678 
02679     return sh->index;
02680 }
02681 
02682 
02683 /* 
02684 ====================
02685 RE_RegisterShader
02686 
02687 This is the exported shader entry point for the rest of the system
02688 It will always return an index that will be valid.
02689 
02690 This should really only be used for explicit shaders, because there is no
02691 way to ask for different implicit lighting modes (vertex, lightmap, etc)
02692 ====================
02693 */
02694 qhandle_t RE_RegisterShader( const char *name ) {
02695     shader_t    *sh;
02696 
02697     if ( strlen( name ) >= MAX_QPATH ) {
02698         Com_Printf( "Shader name exceeds MAX_QPATH\n" );
02699         return 0;
02700     }
02701 
02702     sh = R_FindShader( name, LIGHTMAP_2D, qtrue );
02703 
02704     // we want to return 0 if the shader failed to
02705     // load for some reason, but R_FindShader should
02706     // still keep a name allocated for it, so if
02707     // something calls RE_RegisterShader again with
02708     // the same name, we don't try looking for it again
02709     if ( sh->defaultShader ) {
02710         return 0;
02711     }
02712 
02713     return sh->index;
02714 }
02715 
02716 
02717 /*
02718 ====================
02719 RE_RegisterShaderNoMip
02720 
02721 For menu graphics that should never be picmiped
02722 ====================
02723 */
02724 qhandle_t RE_RegisterShaderNoMip( const char *name ) {
02725     shader_t    *sh;
02726 
02727     if ( strlen( name ) >= MAX_QPATH ) {
02728         Com_Printf( "Shader name exceeds MAX_QPATH\n" );
02729         return 0;
02730     }
02731 
02732     sh = R_FindShader( name, LIGHTMAP_2D, qfalse );
02733 
02734     // we want to return 0 if the shader failed to
02735     // load for some reason, but R_FindShader should
02736     // still keep a name allocated for it, so if
02737     // something calls RE_RegisterShader again with
02738     // the same name, we don't try looking for it again
02739     if ( sh->defaultShader ) {
02740         return 0;
02741     }
02742 
02743     return sh->index;
02744 }
02745 
02746 
02747 /*
02748 ====================
02749 R_GetShaderByHandle
02750 
02751 When a handle is passed in by another module, this range checks
02752 it and returns a valid (possibly default) shader_t to be used internally.
02753 ====================
02754 */
02755 shader_t *R_GetShaderByHandle( qhandle_t hShader ) {
02756     if ( hShader < 0 ) {
02757       ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader ); // bk: FIXME name
02758         return tr.defaultShader;
02759     }
02760     if ( hShader >= tr.numShaders ) {
02761         ri.Printf( PRINT_WARNING, "R_GetShaderByHandle: out of range hShader '%d'\n", hShader );
02762         return tr.defaultShader;
02763     }
02764     return tr.shaders[hShader];
02765 }
02766 
02767 /*
02768 ===============
02769 R_ShaderList_f
02770 
02771 Dump information on all valid shaders to the console
02772 A second parameter will cause it to print in sorted order
02773 ===============
02774 */
02775 void    R_ShaderList_f (void) {
02776     int         i;
02777     int         count;
02778     shader_t    *shader;
02779 
02780     ri.Printf (PRINT_ALL, "-----------------------\n");
02781 
02782     count = 0;
02783     for ( i = 0 ; i < tr.numShaders ; i++ ) {
02784         if ( ri.Cmd_Argc() > 1 ) {
02785             shader = tr.sortedShaders[i];
02786         } else {
02787             shader = tr.shaders[i];
02788         }
02789 
02790         ri.Printf( PRINT_ALL, "%i ", shader->numUnfoggedPasses );
02791 
02792         if (shader->lightmapIndex >= 0 ) {
02793             ri.Printf (PRINT_ALL, "L ");
02794         } else {
02795             ri.Printf (PRINT_ALL, "  ");
02796         }
02797         if ( shader->multitextureEnv == GL_ADD ) {
02798             ri.Printf( PRINT_ALL, "MT(a) " );
02799         } else if ( shader->multitextureEnv == GL_MODULATE ) {
02800             ri.Printf( PRINT_ALL, "MT(m) " );
02801         } else if ( shader->multitextureEnv == GL_DECAL ) {
02802             ri.Printf( PRINT_ALL, "MT(d) " );
02803         } else {
02804             ri.Printf( PRINT_ALL, "      " );
02805         }
02806         if ( shader->explicitlyDefined ) {
02807             ri.Printf( PRINT_ALL, "E " );
02808         } else {
02809             ri.Printf( PRINT_ALL, "  " );
02810         }
02811 
02812         if ( shader->optimalStageIteratorFunc == RB_StageIteratorGeneric ) {
02813             ri.Printf( PRINT_ALL, "gen " );
02814         } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorSky ) {
02815             ri.Printf( PRINT_ALL, "sky " );
02816         } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorLightmappedMultitexture ) {
02817             ri.Printf( PRINT_ALL, "lmmt" );
02818         } else if ( shader->optimalStageIteratorFunc == RB_StageIteratorVertexLitTexture ) {
02819             ri.Printf( PRINT_ALL, "vlt " );
02820         } else {
02821             ri.Printf( PRINT_ALL, "    " );
02822         }
02823 
02824         if ( shader->defaultShader ) {
02825             ri.Printf (PRINT_ALL,  ": %s (DEFAULTED)\n", shader->name);
02826         } else {
02827             ri.Printf (PRINT_ALL,  ": %s\n", shader->name);
02828         }
02829         count++;
02830     }
02831     ri.Printf (PRINT_ALL, "%i total shaders\n", count);
02832     ri.Printf (PRINT_ALL, "------------------\n");
02833 }
02834 
02835 
02836 /*
02837 ====================
02838 ScanAndLoadShaderFiles
02839 
02840 Finds and loads all .shader files, combining them into
02841 a single large text block that can be scanned for shader names
02842 =====================
02843 */
02844 #define MAX_SHADER_FILES    4096
02845 static void ScanAndLoadShaderFiles( void )
02846 {
02847     char **shaderFiles;
02848     char *buffers[MAX_SHADER_FILES];
02849     char *p;
02850     int numShaders;
02851     int i;
02852     char *oldp, *token, *hashMem;
02853     int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size;
02854 
02855     long sum = 0;
02856     // scan for shader files
02857     shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaders );
02858 
02859     if ( !shaderFiles || !numShaders )
02860     {
02861         ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" );
02862         return;
02863     }
02864 
02865     if ( numShaders > MAX_SHADER_FILES ) {
02866         numShaders = MAX_SHADER_FILES;
02867     }
02868 
02869     // load and parse shader files
02870     for ( i = 0; i < numShaders; i++ )
02871     {
02872         char filename[MAX_QPATH];
02873 
02874         Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
02875         ri.Printf( PRINT_ALL, "...loading '%s'\n", filename );
02876         sum += ri.FS_ReadFile( filename, (void **)&buffers[i] );
02877         if ( !buffers[i] ) {
02878             ri.Error( ERR_DROP, "Couldn't load %s", filename );
02879         }
02880     }
02881 
02882     // build single large buffer
02883     s_shaderText = ri.Hunk_Alloc( sum + numShaders*2, h_low );
02884 
02885     // free in reverse order, so the temp files are all dumped
02886     for ( i = numShaders - 1; i >= 0 ; i-- ) {
02887         strcat( s_shaderText, "\n" );
02888         p = &s_shaderText[strlen(s_shaderText)];
02889         strcat( s_shaderText, buffers[i] );
02890         ri.FS_FreeFile( buffers[i] );
02891         buffers[i] = p;
02892         COM_Compress(p);
02893     }
02894 
02895     // free up memory
02896     ri.FS_FreeFileList( shaderFiles );
02897 
02898     Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
02899     size = 0;
02900     //
02901     for ( i = 0; i < numShaders; i++ ) {
02902         // pointer to the first shader file
02903         p = buffers[i];
02904         // look for label
02905         while ( 1 ) {
02906             token = COM_ParseExt( &p, qtrue );
02907             if ( token[0] == 0 ) {
02908                 break;
02909             }
02910 
02911             hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
02912             shaderTextHashTableSizes[hash]++;
02913             size++;
02914             SkipBracedSection(&p);
02915             // if we passed the pointer to the next shader file
02916             if ( i < numShaders - 1 ) {
02917                 if ( p > buffers[i+1] ) {
02918                     break;
02919                 }
02920             }
02921         }
02922     }
02923 
02924     size += MAX_SHADERTEXT_HASH;
02925 
02926     hashMem = ri.Hunk_Alloc( size * sizeof(char *), h_low );
02927 
02928     for (i = 0; i < MAX_SHADERTEXT_HASH; i++) {
02929         shaderTextHashTable[i] = (char **) hashMem;
02930         hashMem = ((char *) hashMem) + ((shaderTextHashTableSizes[i] + 1) * sizeof(char *));
02931     }
02932 
02933     Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));
02934     //
02935     for ( i = 0; i < numShaders; i++ ) {
02936         // pointer to the first shader file
02937         p = buffers[i];
02938         // look for label
02939         while ( 1 ) {
02940             oldp = p;
02941             token = COM_ParseExt( &p, qtrue );
02942             if ( token[0] == 0 ) {
02943                 break;
02944             }
02945 
02946             hash = generateHashValue(token, MAX_SHADERTEXT_HASH);
02947             shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp;
02948 
02949             SkipBracedSection(&p);
02950             // if we passed the pointer to the next shader file
02951             if ( i < numShaders - 1 ) {
02952                 if ( p > buffers[i+1] ) {
02953                     break;
02954                 }
02955             }
02956         }
02957     }
02958 
02959     return;
02960 
02961 }
02962 
02963 
02964 /*
02965 ====================
02966 CreateInternalShaders
02967 ====================
02968 */
02969 static void CreateInternalShaders( void ) {
02970     tr.numShaders = 0;
02971 
02972     // init the default shader
02973     Com_Memset( &shader, 0, sizeof( shader ) );
02974     Com_Memset( &stages, 0, sizeof( stages ) );
02975 
02976     Q_strncpyz( shader.name, "<default>", sizeof( shader.name ) );
02977 
02978     shader.lightmapIndex = LIGHTMAP_NONE;
02979     stages[0].bundle[0].image[0] = tr.defaultImage;
02980     stages[0].active = qtrue;
02981     stages[0].stateBits = GLS_DEFAULT;
02982     tr.defaultShader = FinishShader();
02983 
02984     // shadow shader is just a marker
02985     Q_strncpyz( shader.name, "<stencil shadow>", sizeof( shader.name ) );
02986     shader.sort = SS_STENCIL_SHADOW;
02987     tr.shadowShader = FinishShader();
02988 }
02989 
02990 static void CreateExternalShaders( void ) {
02991     tr.projectionShadowShader = R_FindShader( "projectionShadow", LIGHTMAP_NONE, qtrue );
02992     tr.flareShader = R_FindShader( "flareShader", LIGHTMAP_NONE, qtrue );
02993     tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue );
02994 }
02995 
02996 /*
02997 ==================
02998 R_InitShaders
02999 ==================
03000 */
03001 void R_InitShaders( void ) {
03002     ri.Printf( PRINT_ALL, "Initializing Shaders\n" );
03003 
03004     Com_Memset(hashTable, 0, sizeof(hashTable));
03005 
03006     deferLoad = qfalse;
03007 
03008     CreateInternalShaders();
03009 
03010     ScanAndLoadShaderFiles();
03011 
03012     CreateExternalShaders();
03013 }

Generated on Thu Aug 25 12:37:55 2005 for Quake III Arena by  doxygen 1.3.9.1