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->