123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530 |
- #include "../server/exe_headers.h"
- #include "../game/q_shared.h"
- #include "cm_local.h"
- #include "memory.h"
- #include "chash.h"
- class CCMShaderText
- {
- private:
- char mName[MAX_QPATH];
- class CCMShaderText *mNext;
- const char *mData;
- public:
- // Constructors
- CCMShaderText(const char *name, const char *data) { Q_strncpyz(mName, name, MAX_QPATH); mNext = NULL; mData = data; }
- ~CCMShaderText(void) {}
- // Accessors
- const char *GetName(void) const { return(mName); }
- class CCMShaderText *GetNext(void) const { return(mNext); }
- void SetNext(class CCMShaderText *next) { mNext = next; }
- void Destroy(void) { delete this; }
- const char *GetData(void) const { return(mData); }
- };
- char *shaderText = NULL;
- CHash<CCMShaderText> shaderTextTable;
- CHash<CCMShader> cmShaderTable;
- const char *SkipWhitespace( const char *data, qboolean *hasNewLines );
- //rwwFIXMEFIXME: Called at RE_BeginRegistration because Hunk_Clear
- //destroys the memory cmShaderTable is on. This is a temp solution
- //I guess.
- void ShaderTableCleanup()
- {
- cmShaderTable.clear();
- }
- /*
- ====================
- CM_CreateShaderTextHash
- =====================
- */
- void CM_CreateShaderTextHash(void)
- {
- const char *p;
- qboolean hasNewLines;
- char *token;
- CCMShaderText *shader;
- p = shaderText;
- // look for label
- while (p)
- {
- p = SkipWhitespace(p, &hasNewLines);
- token = COM_ParseExt( &p, qtrue );
- if ( !token[0] )
- {
- break;
- }
- shader = new CCMShaderText(token, p);
- shaderTextTable.insert(shader);
- SkipBracedSection(&p);
- }
- }
- /*
- ====================
- CM_LoadShaderFiles
- Finds and loads all .shader files, combining them into
- a single large text block that can be scanned for shader names
- =====================
- */
- #define MAX_SHADER_FILES 1024
- void CM_LoadShaderFiles( void )
- {
- char **shaderFiles1;
- int numShaders1;
- char *buffers[MAX_SHADER_FILES];
- int numShaders;
- int i;
- int sum = 0;
- // scan for shader files
- shaderFiles1 = FS_ListFiles( "shaders", ".shader", &numShaders1 );
- if ( !shaderFiles1 || !numShaders1 )
- {
- Com_Printf( S_COLOR_YELLOW "WARNING: no shader files found\n" );
- return;
- }
- numShaders = numShaders1;
- if ( numShaders > MAX_SHADER_FILES )
- {
- numShaders = MAX_SHADER_FILES;
- }
- // load and parse shader files
- for ( i = 0; i < numShaders1; i++ )
- {
- char filename[MAX_QPATH];
- Com_sprintf( filename, sizeof( filename ), "shaders/%s", shaderFiles1[i] );
- Com_DPrintf( "...loading '%s'\n", filename );
- FS_ReadFile( filename, (void **)&buffers[i] );
- if ( !buffers[i] )
- {
- Com_Error( ERR_DROP, "Couldn't load %s", filename );
- }
- sum += COM_Compress( buffers[i] );
- }
- // build single large buffer
- shaderText = (char *)Z_Malloc( sum + numShaders * 2, TAG_SHADERTEXT, qtrue);
- // free in reverse order, so the temp files are all dumped
- for ( i = numShaders - 1; i >= 0 ; i-- )
- {
- strcat( shaderText, "\n" );
- strcat( shaderText, buffers[i] );
- FS_FreeFile( buffers[i] );
- }
- // free up memory
- FS_FreeFileList( shaderFiles1 );
- }
- /*
- ==================
- CM_GetShaderText
- ==================
- */
- const char *CM_GetShaderText(const char *key)
- {
- CCMShaderText *st;
- st = shaderTextTable[key];
- if(st)
- {
- return(st->GetData());
- }
- return(NULL);
- }
- /*
- ==================
- CM_FreeShaderText
- ==================
- */
- void CM_FreeShaderText(void)
- {
- shaderTextTable.clear();
- if(shaderText)
- {
- Z_Free(shaderText);
- shaderText = NULL;
- }
- }
- /*
- ==================
- CM_LoadShaderText
- Loads in all the .shader files so it can be accessed by the server and the renderer
- Creates a hash table to quickly access the shader text
- ==================
- */
- void CM_LoadShaderText(bool forceReload)
- {
- if(forceReload)
- {
- CM_FreeShaderText();
- }
- if(shaderText)
- {
- return;
- }
- Com_Printf("Loading shader text .....\n");
- CM_LoadShaderFiles();
- CM_CreateShaderTextHash();
- Com_Printf("..... %d shader definitions loaded\n", shaderTextTable.count());
- }
- /*
- ===============
- ParseSurfaceParm
- surfaceparm <name>
- ===============
- */
- typedef struct
- {
- char *name;
- int clearSolid, surfaceFlags, contents;
- } infoParm_t;
- infoParm_t svInfoParms[] =
- {
- // Game content Flags
- {"nonsolid", ~CONTENTS_SOLID, 0, 0 }, // special hack to clear solid flag
- {"nonopaque", ~CONTENTS_OPAQUE, 0, 0 }, // special hack to clear opaque flag
- {"lava", ~CONTENTS_SOLID, 0, CONTENTS_LAVA }, // very damaging
- {"slime", ~CONTENTS_SOLID, 0, CONTENTS_SLIME }, // mildly damaging
- {"water", ~CONTENTS_SOLID, 0, CONTENTS_WATER },
- {"fog", ~CONTENTS_SOLID, 0, CONTENTS_FOG}, // carves surfaces entering
- {"shotclip", ~CONTENTS_SOLID, 0, CONTENTS_SHOTCLIP }, /* block shots, but not people */
- {"playerclip", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_PLAYERCLIP }, /* block only the player */
- {"monsterclip", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_MONSTERCLIP },
- {"botclip", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_BOTCLIP }, /* NPC do not enter */
- {"trigger", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_TRIGGER },
- {"nodrop", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc)
- {"terrain", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_TERRAIN }, /* use special terrain collsion */
- {"ladder", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_LADDER }, // climb up in it like water
- {"abseil", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_ABSEIL }, // can abseil down this brush
- {"outside", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_OUTSIDE }, // volume is considered to be in the outside (i.e. not indoors)
- {"inside", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_INSIDE }, // volume is considered to be inside (i.e. indoors)
-
- {"detail", -1, 0, CONTENTS_DETAIL }, // don't include in structural bsp
- {"trans", -1, 0, CONTENTS_TRANSLUCENT }, // surface has an alpha component
-
- /* Game surface flags */
- {"sky", -1, SURF_SKY, 0 }, /* emit light from an environment map */
- {"slick", -1, SURF_SLICK, 0 },
- {"nodamage", -1, SURF_NODAMAGE, 0 },
- {"noimpact", -1, SURF_NOIMPACT, 0 }, /* don't make impact explosions or marks */
- {"nomarks", -1, SURF_NOMARKS, 0 }, /* don't make impact marks, but still explode */
- {"nodraw", -1, SURF_NODRAW, 0 }, /* don't generate a drawsurface (or a lightmap) */
- {"nosteps", -1, SURF_NOSTEPS, 0 },
- {"nodlight", -1, SURF_NODLIGHT, 0 }, /* don't ever add dynamic lights */
- {"metalsteps", -1, SURF_METALSTEPS,0 },
- {"nomiscents", -1, SURF_NOMISCENTS,0 }, /* No misc ents on this surface */
- {"forcefield", -1, SURF_FORCEFIELD,0 },
- {"forcesight", -1, SURF_FORCESIGHT,0 }, // only visible with force sight
- };
- void SV_ParseSurfaceParm( CCMShader * shader, const char **text )
- {
- char *token;
- int numsvInfoParms = sizeof(svInfoParms) / sizeof(svInfoParms[0]);
- int i;
- token = COM_ParseExt( text, qfalse );
- for ( i = 0 ; i < numsvInfoParms ; i++ )
- {
- if ( !Q_stricmp( token, svInfoParms[i].name ) )
- {
- shader->surfaceFlags |= svInfoParms[i].surfaceFlags;
- shader->contentFlags |= svInfoParms[i].contents;
- shader->contentFlags &= svInfoParms[i].clearSolid;
- break;
- }
- }
- }
- /*
- =================
- ParseMaterial
- =================
- */
- const char *svMaterialNames[MATERIAL_LAST] =
- {
- MATERIALS
- };
- void SV_ParseMaterial( CCMShader *shader, const char **text )
- {
- char *token;
- int i;
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- Com_Printf( S_COLOR_YELLOW "WARNING: missing material in shader '%s'\n", shader->shader );
- return;
- }
- for(i = 0; i < MATERIAL_LAST; i++)
- {
- if ( !Q_stricmp( token, svMaterialNames[i] ) )
- {
- shader->surfaceFlags &= ~MATERIAL_MASK;//safety, clear it first
- shader->surfaceFlags |= i;
- break;
- }
- }
- }
- /*
- ===============
- ParseVector
- ===============
- */
- qboolean CM_ParseVector( CCMShader *shader, const char **text, int count, float *v )
- {
- char *token;
- int i;
- // FIXME: spaces are currently required after parens, should change parseext...
- token = COM_ParseExt( text, qfalse );
- if ( strcmp( token, "(" ) )
- {
- Com_Printf( S_COLOR_YELLOW "WARNING: missing parenthesis in shader '%s'\n", shader->shader );
- return qfalse;
- }
- for ( i = 0 ; i < count ; i++ )
- {
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- Com_Printf( S_COLOR_YELLOW "WARNING: missing vector element in shader '%s'\n", shader->shader );
- return qfalse;
- }
- v[i] = atof( token );
- }
- token = COM_ParseExt( text, qfalse );
- if ( strcmp( token, ")" ) )
- {
- Com_Printf( S_COLOR_YELLOW "WARNING: missing parenthesis in shader '%s'\n", shader->shader );
- return qfalse;
- }
- return qtrue;
- }
- /*
- =================
- CM_ParseShader
- The current text pointer is at the explicit text definition of the
- shader. Parse it into the global shader variable.
- This extracts all the info from the shader required for physics and collision
- It is designed to *NOT* load any image files and not require any of the renderer to
- be initialised.
- =================
- */
- void CM_ParseShader( CCMShader *shader, const char **text )
- {
- char *token;
- token = COM_ParseExt( text, qtrue );
- if ( token[0] != '{' )
- {
- Com_Printf( S_COLOR_YELLOW "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader->shader );
- return;
- }
- while ( true )
- {
- token = COM_ParseExt( text, qtrue );
- if ( !token[0] )
- {
- Com_Printf( S_COLOR_YELLOW "WARNING: no concluding '}' in shader %s\n", shader->shader );
- return;
- }
- // end of shader definition
- if ( token[0] == '}' )
- {
- break;
- }
- // stage definition
- else if ( token[0] == '{' )
- {
- SkipBracedSection( text );
- continue;
- }
- // material deprecated as of 11 Jan 01
- // material undeprecated as of 7 May 01 - q3map_material deprecated
- else if ( !Q_stricmp( token, "material" ) || !Q_stricmp( token, "q3map_material" ) )
- {
- SV_ParseMaterial( shader, text );
- }
- // sun parms
- // q3map_sun deprecated as of 11 Jan 01
- else if ( !Q_stricmp( token, "sun" ) || !Q_stricmp( token, "q3map_sun" ) )
- {
- // float a, b;
- token = COM_ParseExt( text, qfalse );
- // shader->sunLight[0] = atof( token );
- token = COM_ParseExt( text, qfalse );
- // shader->sunLight[1] = atof( token );
- token = COM_ParseExt( text, qfalse );
- // shader->sunLight[2] = atof( token );
-
- // VectorNormalize( shader->sunLight );
- token = COM_ParseExt( text, qfalse );
- // a = atof( token );
- // VectorScale( shader->sunLight, a, shader->sunLight);
- token = COM_ParseExt( text, qfalse );
- // a = DEG2RAD(atof( token ));
- token = COM_ParseExt( text, qfalse );
- // b = DEG2RAD(atof( token ));
- // shader->sunDirection[0] = cos( a ) * cos( b );
- // shader->sunDirection[1] = sin( a ) * cos( b );
- // shader->sunDirection[2] = sin( b );
- }
- else if ( !Q_stricmp( token, "surfaceParm" ) )
- {
- SV_ParseSurfaceParm( shader, text );
- continue;
- }
- else if ( !Q_stricmp( token, "fogParms" ) )
- {
- vec3_t fogColor;
- if ( !CM_ParseVector( shader, text, 3, fogColor ) )
- {
- return;
- }
- token = COM_ParseExt( text, qfalse );
- if ( !token[0] )
- {
- Com_Printf( S_COLOR_YELLOW "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader->shader );
- continue;
- }
- // shader->depthForOpaque = atof( token );
- // skip any old gradient directions
- SkipRestOfLine( (const char **)text );
- continue;
- }
- }
- return;
- }
- /*
- =================
- CM_SetupShaderProperties
- Scans thru the shaders loaded for the map, parses the text of that shader and
- extracts the interesting info *WITHOUT* loading up any images or requiring
- the renderer to be active.
- =================
- */
- void CM_SetupShaderProperties(void)
- {
- int i;
- const char *def;
- CCMShader *shader;
- // Add all basic shaders to the cmShaderTable
- for(i = 0; i < cmg.numShaders; i++)
- {
- cmShaderTable.insert(CM_GetShaderInfo(i));
- }
- // Go through and parse evaluate shader names to shadernums
- for(i = 0; i < cmg.numShaders; i++)
- {
- shader = CM_GetShaderInfo(i);
- def = CM_GetShaderText(shader->shader);
- if(def)
- {
- CM_ParseShader(shader, &def);
- }
- }
- }
- void CM_ShutdownShaderProperties(void)
- {
- if(cmShaderTable.count())
- {
- Com_Printf("Shutting down cmShaderTable .....\n");
- cmShaderTable.clear();
- }
- }
- CCMShader *CM_GetShaderInfo( const char *name )
- {
- CCMShader *out;
- const char *def;
- out = cmShaderTable[name];
- if(out)
- {
- return(out);
- }
- // Create a new CCMShader class
- //out = (CCMShader *)Hunk_Alloc( sizeof( CCMShader ), h_high );
- out = (CCMShader *)Hunk_Alloc( sizeof( CCMShader ), qtrue );
- // Set defaults
- Q_strncpyz(out->shader, name, MAX_QPATH);
- out->contentFlags = CONTENTS_SOLID | CONTENTS_OPAQUE;
- // Parse in any text if it exists
- def = CM_GetShaderText(name);
- if(def)
- {
- CM_ParseShader(out, &def);
- }
- cmShaderTable.insert(out);
- return(out);
- }
- CCMShader *CM_GetShaderInfo( int shaderNum )
- {
- CCMShader *out;
- if((shaderNum < 0) || (shaderNum >= cmg.numShaders))
- {
- return(NULL);
- }
- out = cmg.shaders + shaderNum;
- return(out);
- }
- // end
|