home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 58 / pcpp58a.iso / extras / quake 3 source / Q3A_ToolSource.exe / Main / shaders.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-02  |  14.2 KB  |  587 lines

  1.  
  2. #include <string.h>
  3. #include <math.h>
  4. #include "cmdlib.h"
  5. #include "mathlib.h"
  6. #include "imagelib.h"
  7. #include "scriplib.h"
  8.  
  9. #ifdef _TTIMOBUILD
  10. #include "../common/qfiles.h"
  11. #include "../common/surfaceflags.h"
  12. #else
  13. #include "../code/qcommon/qfiles.h"
  14. #include "../code/game/surfaceflags.h"
  15. #endif
  16.  
  17. #include "shaders.h"
  18. #ifdef _WIN32
  19.  
  20. #ifdef _TTIMOBUILD
  21. #include "pakstuff.h"
  22. #include "jpeglib.h"
  23. #else
  24. #include "../libs/pakstuff.h"
  25. #include "../libs/jpeglib.h"
  26. #endif
  27.  
  28. #endif
  29.  
  30.  
  31. // 5% backsplash by default
  32. #define    DEFAULT_BACKSPLASH_FRACTION        0.05
  33. #define    DEFAULT_BACKSPLASH_DISTANCE        24
  34.  
  35.  
  36. #define    MAX_SURFACE_INFO    3192
  37.  
  38. shaderInfo_t    defaultInfo;
  39. shaderInfo_t    shaderInfo[MAX_SURFACE_INFO];
  40. int                numShaderInfo;
  41.  
  42.  
  43. typedef struct {
  44.     char    *name;
  45.     int        clearSolid, surfaceFlags, contents;
  46. } infoParm_t;
  47.  
  48. infoParm_t    infoParms[] = {
  49.     // server relevant contents
  50.     {"water",        1,    0,    CONTENTS_WATER },
  51.     {"slime",        1,    0,    CONTENTS_SLIME },        // mildly damaging
  52.     {"lava",        1,    0,    CONTENTS_LAVA },        // very damaging
  53.     {"playerclip",    1,    0,    CONTENTS_PLAYERCLIP },
  54.     {"monsterclip",    1,    0,    CONTENTS_MONSTERCLIP },
  55.     {"nodrop",        1,    0,    CONTENTS_NODROP },        // don't drop items or leave bodies (death fog, lava, etc)
  56.     {"nonsolid",    1,    SURF_NONSOLID,    0},                        // clears the solid flag
  57.  
  58.     // utility relevant attributes
  59.     {"origin",        1,    0,    CONTENTS_ORIGIN },        // center of rotating brushes
  60.     {"trans",        0,    0,    CONTENTS_TRANSLUCENT },    // don't eat contained surfaces
  61.     {"detail",        0,    0,    CONTENTS_DETAIL },        // don't include in structural bsp
  62.     {"structural",    0,    0,    CONTENTS_STRUCTURAL },    // force into structural bsp even if trnas
  63.     {"areaportal",    1,    0,    CONTENTS_AREAPORTAL },    // divides areas
  64.     {"clusterportal",1, 0,  CONTENTS_CLUSTERPORTAL },// for bots
  65.     {"donotenter",  1,  0,  CONTENTS_DONOTENTER },    // for bots
  66.     {"botclip",     1,  0,  CONTENTS_BOTCLIP },        // for bots
  67.  
  68.     {"fog",            1,    0,    CONTENTS_FOG},            // carves surfaces entering
  69.     {"sky",            0,    SURF_SKY,        0 },        // emit light from an environment map
  70.     {"lightfilter",    0,    SURF_LIGHTFILTER, 0 },        // filter light going through it
  71.     {"alphashadow",    0,    SURF_ALPHASHADOW, 0 },        // test light on a per-pixel basis
  72.     {"hint",        0,    SURF_HINT,        0 },        // use as a primary splitter
  73.  
  74.     // server attributes
  75.     {"slick",        0,    SURF_SLICK,        0 },
  76.     {"noimpact",    0,    SURF_NOIMPACT,    0 },        // don't make impact explosions or marks
  77.     {"nomarks",        0,    SURF_NOMARKS,    0 },        // don't make impact marks, but still explode
  78.     {"ladder",        0,    SURF_LADDER,    0 },
  79.     {"nodamage",    0,    SURF_NODAMAGE,    0 },
  80.     {"metalsteps",    0,    SURF_METALSTEPS,0 },
  81.     {"flesh",        0,    SURF_FLESH,        0 },
  82.     {"nosteps",        0,    SURF_NOSTEPS,    0 },
  83.  
  84.     // drawsurf attributes
  85.     {"nodraw",        0,    SURF_NODRAW,    0 },        // don't generate a drawsurface (or a lightmap)
  86.     {"pointlight",    0,    SURF_POINTLIGHT, 0 },        // sample lighting at vertexes
  87.     {"nolightmap",    0,    SURF_NOLIGHTMAP,0 },        // don't generate a lightmap
  88.     {"nodlight",    0,    SURF_NODLIGHT, 0 },            // don't ever add dynamic lights
  89.     {"dust",        0,    SURF_DUST, 0}                // leave dust trail when walking on this surface
  90. };
  91.  
  92.  
  93. /*
  94. ===============
  95. LoadShaderImage
  96. ===============
  97. */
  98.  
  99. byte* LoadImageFile(char *filename, qboolean *bTGA)
  100. {
  101.   byte *buffer = NULL;
  102.   int nLen = 0;
  103.   *bTGA = qtrue;
  104.   if (FileExists(filename))
  105.   {
  106.     LoadFileBlock(filename, &buffer);
  107.   }
  108. #ifdef _WIN32
  109.   else
  110.   {
  111.     PakLoadAnyFile(filename, &buffer);
  112.   }
  113. #endif
  114.   if ( buffer == NULL)
  115.   {
  116.     nLen = strlen(filename);
  117.     filename[nLen-3] = 'j';
  118.     filename[nLen-2] = 'p';
  119.     filename[nLen-1] = 'g';
  120.     if (FileExists(filename))
  121.     {
  122.       LoadFileBlock(filename, &buffer);
  123.     }
  124. #ifdef _WIN32
  125.     else
  126.     {
  127.       PakLoadAnyFile(filename, &buffer);
  128.     }
  129. #endif
  130.     if ( buffer )
  131.     {
  132.       *bTGA = qfalse;
  133.     }
  134.   }
  135.   return buffer;
  136. }
  137.  
  138. /*
  139. ===============
  140. LoadShaderImage
  141. ===============
  142. */
  143. static void LoadShaderImage( shaderInfo_t *si ) {
  144.     char            filename[1024];
  145.     int                i, count;
  146.     float            color[4];
  147.   byte      *buffer;
  148.   qboolean  bTGA = qtrue;
  149.  
  150.     // look for the lightimage if it is specified
  151.     if ( si->lightimage[0] ) {
  152.         sprintf( filename, "%s%s", gamedir, si->lightimage );
  153.         DefaultExtension( filename, ".tga" );
  154.     buffer = LoadImageFile(filename, &bTGA);
  155.     if ( buffer != NULL) {
  156.       goto loadTga;
  157.     }
  158.   }
  159.  
  160.     // look for the editorimage if it is specified
  161.     if ( si->editorimage[0] ) {
  162.         sprintf( filename, "%s%s", gamedir, si->editorimage );
  163.         DefaultExtension( filename, ".tga" );
  164.     buffer = LoadImageFile(filename, &bTGA);
  165.     if ( buffer != NULL) {
  166.       goto loadTga;
  167.     }
  168.   }
  169.  
  170.   // just try the shader name with a .tga
  171.     // on unix, we have case sensitivity problems...
  172.   sprintf( filename, "%s%s.tga", gamedir, si->shader );
  173.   buffer = LoadImageFile(filename, &bTGA);
  174.   if ( buffer != NULL) {
  175.         goto loadTga;
  176.     }
  177.  
  178.   sprintf( filename, "%s%s.TGA", gamedir, si->shader );
  179.   buffer = LoadImageFile(filename, &bTGA);
  180.   if ( buffer != NULL) {
  181.         goto loadTga;
  182.     }
  183.  
  184.     // couldn't load anything
  185.     _printf("WARNING: Couldn't find image for shader %s\n", si->shader );
  186.  
  187.     si->color[0] = 1;
  188.     si->color[1] = 1;
  189.     si->color[2] = 1;
  190.     si->width = 64;
  191.     si->height = 64;
  192.     si->pixels = malloc( si->width * si->height * 4 );
  193.     memset ( si->pixels, 255, si->width * si->height * 4 );
  194.     return;
  195.  
  196.     // load the image to get dimensions and color
  197. loadTga:
  198.   if ( bTGA) {
  199.       LoadTGABuffer( buffer, &si->pixels, &si->width, &si->height );
  200.   }
  201.   else {
  202. #ifdef _WIN32
  203.     LoadJPGBuff(buffer, &si->pixels, &si->width, &si->height );
  204. #endif
  205.   }
  206.  
  207.   free(buffer);
  208.  
  209.     count = si->width * si->height;
  210.  
  211.     VectorClear( color );
  212.     color[ 3 ] = 0;
  213.     for ( i = 0 ; i < count ; i++ ) {
  214.         color[0] += si->pixels[ i * 4 + 0 ];
  215.         color[1] += si->pixels[ i * 4 + 1 ];
  216.         color[2] += si->pixels[ i * 4 + 2 ];
  217.         color[3] += si->pixels[ i * 4 + 3 ];
  218.     }
  219.     ColorNormalize( color, si->color );
  220.     VectorScale( color, 1.0/count, si->averageColor );
  221. }
  222.  
  223. /*
  224. ===============
  225. AllocShaderInfo
  226. ===============
  227. */
  228. static shaderInfo_t    *AllocShaderInfo( void ) {
  229.     shaderInfo_t    *si;
  230.  
  231.     if ( numShaderInfo == MAX_SURFACE_INFO ) {
  232.         Error( "MAX_SURFACE_INFO" );
  233.     }
  234.     si = &shaderInfo[ numShaderInfo ];
  235.     numShaderInfo++;
  236.  
  237.     // set defaults
  238.  
  239.     si->contents = CONTENTS_SOLID;
  240.  
  241.     si->backsplashFraction = DEFAULT_BACKSPLASH_FRACTION;
  242.     si->backsplashDistance = DEFAULT_BACKSPLASH_DISTANCE;
  243.  
  244.     si->lightmapSampleSize = 0;
  245.     si->forceTraceLight = qfalse;
  246.     si->forceVLight = qfalse;
  247.     si->patchShadows = qfalse;
  248.     si->vertexShadows = qfalse;
  249.     si->noVertexShadows = qfalse;
  250.     si->forceSunLight = qfalse;
  251.     si->vertexScale = 1.0;
  252.     si->notjunc = qfalse;
  253.  
  254.     return si;
  255. }
  256.  
  257. /*
  258. ===============
  259. ShaderInfoForShader
  260. ===============
  261. */
  262. shaderInfo_t    *ShaderInfoForShader( const char *shaderName ) {
  263.     int                i;
  264.     shaderInfo_t    *si;
  265.     char            shader[MAX_QPATH];
  266.  
  267.     // strip off extension
  268.     strcpy( shader, shaderName );
  269.     StripExtension( shader );
  270.  
  271.     // search for it
  272.     for ( i = 0 ; i < numShaderInfo ; i++ ) {
  273.         si = &shaderInfo[ i ];
  274.         if ( !Q_stricmp( shader, si->shader ) ) {
  275.             if ( !si->width ) {
  276.                 LoadShaderImage( si );
  277.             }
  278.             return si;
  279.         }
  280.     }
  281.  
  282.     si = AllocShaderInfo();
  283.     strcpy( si->shader, shader );
  284.  
  285.     LoadShaderImage( si );
  286.  
  287.     return si;
  288. }
  289.  
  290. /*
  291. ===============
  292. ParseShaderFile
  293. ===============
  294. */
  295. static void ParseShaderFile( const char *filename ) {
  296.     int        i;
  297.     int        numInfoParms = sizeof(infoParms) / sizeof(infoParms[0]);
  298.     shaderInfo_t    *si;
  299.  
  300. //    qprintf( "shaderFile: %s\n", filename );
  301.     LoadScriptFile( filename );
  302.     while ( 1 ) {
  303.         if ( !GetToken( qtrue ) ) {
  304.             break;
  305.         }
  306.  
  307.         si = AllocShaderInfo();
  308.         strcpy( si->shader, token );
  309.         MatchToken( "{" );
  310.         while ( 1 ) {
  311.             if ( !GetToken( qtrue ) ) {
  312.                 break;
  313.             }
  314.             if ( !strcmp( token, "}" ) ) {
  315.                 break;
  316.             }
  317.  
  318.             // skip internal braced sections
  319.             if ( !strcmp( token, "{" ) ) {
  320.                 si->hasPasses = qtrue;
  321.                 while ( 1 ) {
  322.                     if ( !GetToken( qtrue ) ) {
  323.                         break;
  324.                     }
  325.                     if ( !strcmp( token, "}" ) ) {
  326.                         break;
  327.                     }
  328.                 }
  329.                 continue;
  330.             }
  331.  
  332.             if ( !Q_stricmp( token, "surfaceparm" ) ) {
  333.                 GetToken( qfalse );
  334.                 for ( i = 0 ; i < numInfoParms ; i++ ) {
  335.                     if ( !Q_stricmp( token, infoParms[i].name ) ) {
  336.                         si->surfaceFlags |= infoParms[i].surfaceFlags;
  337.                         si->contents |= infoParms[i].contents;
  338.                         if ( infoParms[i].clearSolid ) {
  339.                             si->contents &= ~CONTENTS_SOLID;
  340.                         }
  341.                         break;
  342.                     }
  343.                 }
  344.                 if ( i == numInfoParms ) {
  345.                     // we will silently ignore all tokens beginning with qer,
  346.                     // which are QuakeEdRadient parameters
  347.                     if ( Q_strncasecmp( token, "qer", 3 ) ) {
  348.                         _printf( "Unknown surfaceparm: \"%s\"\n", token );
  349.                     }
  350.                 }
  351.                 continue;
  352.             }
  353.  
  354.  
  355.             // qer_editorimage <image>
  356.             if ( !Q_stricmp( token, "qer_editorimage" ) ) {
  357.                 GetToken( qfalse );
  358.                 strcpy( si->editorimage, token );
  359.                 DefaultExtension( si->editorimage, ".tga" );
  360.                 continue;
  361.             }
  362.  
  363.             // q3map_lightimage <image>
  364.             if ( !Q_stricmp( token, "q3map_lightimage" ) ) {
  365.                 GetToken( qfalse );
  366.                 strcpy( si->lightimage, token );
  367.                 DefaultExtension( si->lightimage, ".tga" );
  368.                 continue;
  369.             }
  370.  
  371.             // q3map_surfacelight <value>
  372.             if ( !Q_stricmp( token, "q3map_surfacelight" )  ) {
  373.                 GetToken( qfalse );
  374.                 si->value = atoi( token );
  375.                 continue;
  376.             }
  377.  
  378.             // q3map_lightsubdivide <value>
  379.             if ( !Q_stricmp( token, "q3map_lightsubdivide" )  ) {
  380.                 GetToken( qfalse );
  381.                 si->lightSubdivide = atoi( token );
  382.                 continue;
  383.             }
  384.  
  385.             // q3map_lightmapsamplesize <value>
  386.             if ( !Q_stricmp( token, "q3map_lightmapsamplesize" ) ) {
  387.                 GetToken( qfalse );
  388.                 si->lightmapSampleSize = atoi( token );
  389.                 continue;
  390.             }
  391.  
  392.             // q3map_tracelight
  393.             if ( !Q_stricmp( token, "q3map_tracelight" ) ) {
  394.                 si->forceTraceLight = qtrue;
  395.                 continue;
  396.             }
  397.  
  398.             // q3map_vlight
  399.             if ( !Q_stricmp( token, "q3map_vlight" ) ) {
  400.                 si->forceVLight = qtrue;
  401.                 continue;
  402.             }
  403.  
  404.             // q3map_patchshadows
  405.             if ( !Q_stricmp( token, "q3map_patchshadows" ) ) {
  406.                 si->patchShadows = qtrue;
  407.                 continue;
  408.             }
  409.  
  410.             // q3map_vertexshadows
  411.             if ( !Q_stricmp( token, "q3map_vertexshadows" ) ) {
  412.                 si->vertexShadows = qtrue;
  413.                 continue;
  414.             }
  415.  
  416.             // q3map_novertexshadows
  417.             if ( !Q_stricmp( token, "q3map_novertexshadows" ) ) {
  418.                 si->noVertexShadows = qtrue;
  419.                 continue;
  420.             }
  421.  
  422.             // q3map_forcesunlight
  423.             if ( !Q_stricmp( token, "q3map_forcesunlight" ) ) {
  424.                 si->forceSunLight = qtrue;
  425.                 continue;
  426.             }
  427.  
  428.             // q3map_vertexscale
  429.             if ( !Q_stricmp( token, "q3map_vertexscale" ) ) {
  430.                 GetToken( qfalse );
  431.                 si->vertexScale = atof(token);
  432.                 continue;
  433.             }
  434.  
  435.             // q3map_notjunc
  436.             if ( !Q_stricmp( token, "q3map_notjunc" ) ) {
  437.                 si->notjunc = qtrue;
  438.                 continue;
  439.             }
  440.  
  441.             // q3map_globaltexture
  442.             if ( !Q_stricmp( token, "q3map_globaltexture" )  ) {
  443.                 si->globalTexture = qtrue;
  444.                 continue;
  445.             }
  446.  
  447.             // q3map_backsplash <percent> <distance>
  448.             if ( !Q_stricmp( token, "q3map_backsplash" ) ) {
  449.                 GetToken( qfalse );
  450.                 si->backsplashFraction = atof( token ) * 0.01;
  451.                 GetToken( qfalse );
  452.                 si->backsplashDistance = atof( token );
  453.                 continue;
  454.             }
  455.  
  456.             // q3map_backshader <shader>
  457.             if ( !Q_stricmp( token, "q3map_backshader" ) ) {
  458.                 GetToken( qfalse );
  459.                 strcpy( si->backShader, token );
  460.                 continue;
  461.             }
  462.  
  463.             // q3map_flare <shader>
  464.             if ( !Q_stricmp( token, "q3map_flare" ) ) {
  465.                 GetToken( qfalse );
  466.                 strcpy( si->flareShader, token );
  467.                 continue;
  468.             }
  469.  
  470.             // light <value> 
  471.             // old style flare specification
  472.             if ( !Q_stricmp( token, "light" ) ) {
  473.                 GetToken( qfalse );
  474.                 strcpy( si->flareShader, "flareshader" );
  475.                 continue;
  476.             }
  477.  
  478.             // q3map_sun <red> <green> <blue> <intensity> <degrees> <elivation>
  479.             // color will be normalized, so it doesn't matter what range you use
  480.             // intensity falls off with angle but not distance 100 is a fairly bright sun
  481.             // degree of 0 = from the east, 90 = north, etc.  altitude of 0 = sunrise/set, 90 = noon
  482.             if ( !Q_stricmp( token, "q3map_sun" ) ) {
  483.                 float    a, b;
  484.  
  485.                 GetToken( qfalse );
  486.                 si->sunLight[0] = atof( token );
  487.                 GetToken( qfalse );
  488.                 si->sunLight[1] = atof( token );
  489.                 GetToken( qfalse );
  490.                 si->sunLight[2] = atof( token );
  491.                 
  492.                 VectorNormalize( si->sunLight, si->sunLight);
  493.  
  494.                 GetToken( qfalse );
  495.                 a = atof( token );
  496.                 VectorScale( si->sunLight, a, si->sunLight);
  497.  
  498.                 GetToken( qfalse );
  499.                 a = atof( token );
  500.                 a = a / 180 * Q_PI;
  501.  
  502.                 GetToken( qfalse );
  503.                 b = atof( token );
  504.                 b = b / 180 * Q_PI;
  505.  
  506.                 si->sunDirection[0] = cos( a ) * cos( b );
  507.                 si->sunDirection[1] = sin( a ) * cos( b );
  508.                 si->sunDirection[2] = sin( b );
  509.  
  510.                 si->surfaceFlags |= SURF_SKY;
  511.                 continue;
  512.             }
  513.  
  514.             // tesssize is used to force liquid surfaces to subdivide
  515.             if ( !Q_stricmp( token, "tesssize" ) ) {
  516.                 GetToken( qfalse );
  517.                 si->subdivisions = atof( token );
  518.                 continue;
  519.             }
  520.  
  521.             // cull none will set twoSided
  522.             if ( !Q_stricmp( token, "cull" ) ) {
  523.                 GetToken( qfalse );
  524.                 if ( !Q_stricmp( token, "none" ) ) {
  525.                     si->twoSided = qtrue;
  526.                 }
  527.                 continue;
  528.             }
  529.  
  530.  
  531.             // deformVertexes autosprite[2]
  532.             // we catch this so autosprited surfaces become point
  533.             // lights instead of area lights
  534.             if ( !Q_stricmp( token, "deformVertexes" ) ) {
  535.                 GetToken( qfalse );
  536.                 if ( !Q_strncasecmp( token, "autosprite", 10 ) ) {
  537.                     si->autosprite = qtrue;
  538.           si->contents = CONTENTS_DETAIL;
  539.                 }
  540.                 continue;
  541.             }
  542.  
  543.  
  544.             // ignore all other tokens on the line
  545.  
  546.             while ( TokenAvailable() ) {
  547.                 GetToken( qfalse );
  548.             }
  549.         }            
  550.     }
  551. }
  552.  
  553. /*
  554. ===============
  555. LoadShaderInfo
  556. ===============
  557. */
  558. #define    MAX_SHADER_FILES    64
  559. void LoadShaderInfo( void ) {
  560.     char            filename[1024];
  561.     int                i;
  562.     char            *shaderFiles[MAX_SHADER_FILES];
  563.     int                numShaderFiles;
  564.  
  565.     sprintf( filename, "%sscripts/shaderlist.txt", gamedir );
  566.     LoadScriptFile( filename );
  567.  
  568.     numShaderFiles = 0;
  569.     while ( 1 ) {
  570.         if ( !GetToken( qtrue ) ) {
  571.             break;
  572.         }
  573.     shaderFiles[numShaderFiles] = malloc(MAX_OS_PATH);
  574.         strcpy( shaderFiles[ numShaderFiles ], token );
  575.         numShaderFiles++;
  576.     }
  577.  
  578.     for ( i = 0 ; i < numShaderFiles ; i++ ) {
  579.         sprintf( filename, "%sscripts/%s.shader", gamedir, shaderFiles[i] );
  580.         ParseShaderFile( filename );
  581.     free(shaderFiles[i]);
  582.     }
  583.  
  584.     qprintf( "%5i shaderInfo\n", numShaderInfo);
  585. }
  586.  
  587.