cm_shader.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. #include "../server/exe_headers.h"
  2. #include "../game/q_shared.h"
  3. #include "cm_local.h"
  4. #include "memory.h"
  5. #include "chash.h"
  6. class CCMShaderText
  7. {
  8. private:
  9. char mName[MAX_QPATH];
  10. class CCMShaderText *mNext;
  11. const char *mData;
  12. public:
  13. // Constructors
  14. CCMShaderText(const char *name, const char *data) { Q_strncpyz(mName, name, MAX_QPATH); mNext = NULL; mData = data; }
  15. ~CCMShaderText(void) {}
  16. // Accessors
  17. const char *GetName(void) const { return(mName); }
  18. class CCMShaderText *GetNext(void) const { return(mNext); }
  19. void SetNext(class CCMShaderText *next) { mNext = next; }
  20. void Destroy(void) { delete this; }
  21. const char *GetData(void) const { return(mData); }
  22. };
  23. char *shaderText = NULL;
  24. CHash<CCMShaderText> shaderTextTable;
  25. CHash<CCMShader> cmShaderTable;
  26. const char *SkipWhitespace( const char *data, qboolean *hasNewLines );
  27. //rwwFIXMEFIXME: Called at RE_BeginRegistration because Hunk_Clear
  28. //destroys the memory cmShaderTable is on. This is a temp solution
  29. //I guess.
  30. void ShaderTableCleanup()
  31. {
  32. cmShaderTable.clear();
  33. }
  34. /*
  35. ====================
  36. CM_CreateShaderTextHash
  37. =====================
  38. */
  39. void CM_CreateShaderTextHash(void)
  40. {
  41. const char *p;
  42. qboolean hasNewLines;
  43. char *token;
  44. CCMShaderText *shader;
  45. p = shaderText;
  46. // look for label
  47. while (p)
  48. {
  49. p = SkipWhitespace(p, &hasNewLines);
  50. token = COM_ParseExt( &p, qtrue );
  51. if ( !token[0] )
  52. {
  53. break;
  54. }
  55. shader = new CCMShaderText(token, p);
  56. shaderTextTable.insert(shader);
  57. SkipBracedSection(&p);
  58. }
  59. }
  60. /*
  61. ====================
  62. CM_LoadShaderFiles
  63. Finds and loads all .shader files, combining them into
  64. a single large text block that can be scanned for shader names
  65. =====================
  66. */
  67. #define MAX_SHADER_FILES 1024
  68. void CM_LoadShaderFiles( void )
  69. {
  70. char **shaderFiles1;
  71. int numShaders1;
  72. char *buffers[MAX_SHADER_FILES];
  73. int numShaders;
  74. int i;
  75. int sum = 0;
  76. // scan for shader files
  77. shaderFiles1 = FS_ListFiles( "shaders", ".shader", &numShaders1 );
  78. if ( !shaderFiles1 || !numShaders1 )
  79. {
  80. Com_Printf( S_COLOR_YELLOW "WARNING: no shader files found\n" );
  81. return;
  82. }
  83. numShaders = numShaders1;
  84. if ( numShaders > MAX_SHADER_FILES )
  85. {
  86. numShaders = MAX_SHADER_FILES;
  87. }
  88. // load and parse shader files
  89. for ( i = 0; i < numShaders1; i++ )
  90. {
  91. char filename[MAX_QPATH];
  92. Com_sprintf( filename, sizeof( filename ), "shaders/%s", shaderFiles1[i] );
  93. Com_DPrintf( "...loading '%s'\n", filename );
  94. FS_ReadFile( filename, (void **)&buffers[i] );
  95. if ( !buffers[i] )
  96. {
  97. Com_Error( ERR_DROP, "Couldn't load %s", filename );
  98. }
  99. sum += COM_Compress( buffers[i] );
  100. }
  101. // build single large buffer
  102. shaderText = (char *)Z_Malloc( sum + numShaders * 2, TAG_SHADERTEXT, qtrue);
  103. // free in reverse order, so the temp files are all dumped
  104. for ( i = numShaders - 1; i >= 0 ; i-- )
  105. {
  106. strcat( shaderText, "\n" );
  107. strcat( shaderText, buffers[i] );
  108. FS_FreeFile( buffers[i] );
  109. }
  110. // free up memory
  111. FS_FreeFileList( shaderFiles1 );
  112. }
  113. /*
  114. ==================
  115. CM_GetShaderText
  116. ==================
  117. */
  118. const char *CM_GetShaderText(const char *key)
  119. {
  120. CCMShaderText *st;
  121. st = shaderTextTable[key];
  122. if(st)
  123. {
  124. return(st->GetData());
  125. }
  126. return(NULL);
  127. }
  128. /*
  129. ==================
  130. CM_FreeShaderText
  131. ==================
  132. */
  133. void CM_FreeShaderText(void)
  134. {
  135. shaderTextTable.clear();
  136. if(shaderText)
  137. {
  138. Z_Free(shaderText);
  139. shaderText = NULL;
  140. }
  141. }
  142. /*
  143. ==================
  144. CM_LoadShaderText
  145. Loads in all the .shader files so it can be accessed by the server and the renderer
  146. Creates a hash table to quickly access the shader text
  147. ==================
  148. */
  149. void CM_LoadShaderText(bool forceReload)
  150. {
  151. if(forceReload)
  152. {
  153. CM_FreeShaderText();
  154. }
  155. if(shaderText)
  156. {
  157. return;
  158. }
  159. Com_Printf("Loading shader text .....\n");
  160. CM_LoadShaderFiles();
  161. CM_CreateShaderTextHash();
  162. Com_Printf("..... %d shader definitions loaded\n", shaderTextTable.count());
  163. }
  164. /*
  165. ===============
  166. ParseSurfaceParm
  167. surfaceparm <name>
  168. ===============
  169. */
  170. typedef struct
  171. {
  172. char *name;
  173. int clearSolid, surfaceFlags, contents;
  174. } infoParm_t;
  175. infoParm_t svInfoParms[] =
  176. {
  177. // Game content Flags
  178. {"nonsolid", ~CONTENTS_SOLID, 0, 0 }, // special hack to clear solid flag
  179. {"nonopaque", ~CONTENTS_OPAQUE, 0, 0 }, // special hack to clear opaque flag
  180. {"lava", ~CONTENTS_SOLID, 0, CONTENTS_LAVA }, // very damaging
  181. {"slime", ~CONTENTS_SOLID, 0, CONTENTS_SLIME }, // mildly damaging
  182. {"water", ~CONTENTS_SOLID, 0, CONTENTS_WATER },
  183. {"fog", ~CONTENTS_SOLID, 0, CONTENTS_FOG}, // carves surfaces entering
  184. {"shotclip", ~CONTENTS_SOLID, 0, CONTENTS_SHOTCLIP }, /* block shots, but not people */
  185. {"playerclip", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_PLAYERCLIP }, /* block only the player */
  186. {"monsterclip", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_MONSTERCLIP },
  187. {"botclip", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_BOTCLIP }, /* NPC do not enter */
  188. {"trigger", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_TRIGGER },
  189. {"nodrop", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc)
  190. {"terrain", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_TERRAIN }, /* use special terrain collsion */
  191. {"ladder", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_LADDER }, // climb up in it like water
  192. {"abseil", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_ABSEIL }, // can abseil down this brush
  193. {"outside", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_OUTSIDE }, // volume is considered to be in the outside (i.e. not indoors)
  194. {"inside", ~(CONTENTS_SOLID|CONTENTS_OPAQUE),0,CONTENTS_INSIDE }, // volume is considered to be inside (i.e. indoors)
  195. {"detail", -1, 0, CONTENTS_DETAIL }, // don't include in structural bsp
  196. {"trans", -1, 0, CONTENTS_TRANSLUCENT }, // surface has an alpha component
  197. /* Game surface flags */
  198. {"sky", -1, SURF_SKY, 0 }, /* emit light from an environment map */
  199. {"slick", -1, SURF_SLICK, 0 },
  200. {"nodamage", -1, SURF_NODAMAGE, 0 },
  201. {"noimpact", -1, SURF_NOIMPACT, 0 }, /* don't make impact explosions or marks */
  202. {"nomarks", -1, SURF_NOMARKS, 0 }, /* don't make impact marks, but still explode */
  203. {"nodraw", -1, SURF_NODRAW, 0 }, /* don't generate a drawsurface (or a lightmap) */
  204. {"nosteps", -1, SURF_NOSTEPS, 0 },
  205. {"nodlight", -1, SURF_NODLIGHT, 0 }, /* don't ever add dynamic lights */
  206. {"metalsteps", -1, SURF_METALSTEPS,0 },
  207. {"nomiscents", -1, SURF_NOMISCENTS,0 }, /* No misc ents on this surface */
  208. {"forcefield", -1, SURF_FORCEFIELD,0 },
  209. {"forcesight", -1, SURF_FORCESIGHT,0 }, // only visible with force sight
  210. };
  211. void SV_ParseSurfaceParm( CCMShader * shader, const char **text )
  212. {
  213. char *token;
  214. int numsvInfoParms = sizeof(svInfoParms) / sizeof(svInfoParms[0]);
  215. int i;
  216. token = COM_ParseExt( text, qfalse );
  217. for ( i = 0 ; i < numsvInfoParms ; i++ )
  218. {
  219. if ( !Q_stricmp( token, svInfoParms[i].name ) )
  220. {
  221. shader->surfaceFlags |= svInfoParms[i].surfaceFlags;
  222. shader->contentFlags |= svInfoParms[i].contents;
  223. shader->contentFlags &= svInfoParms[i].clearSolid;
  224. break;
  225. }
  226. }
  227. }
  228. /*
  229. =================
  230. ParseMaterial
  231. =================
  232. */
  233. const char *svMaterialNames[MATERIAL_LAST] =
  234. {
  235. MATERIALS
  236. };
  237. void SV_ParseMaterial( CCMShader *shader, const char **text )
  238. {
  239. char *token;
  240. int i;
  241. token = COM_ParseExt( text, qfalse );
  242. if ( !token[0] )
  243. {
  244. Com_Printf( S_COLOR_YELLOW "WARNING: missing material in shader '%s'\n", shader->shader );
  245. return;
  246. }
  247. for(i = 0; i < MATERIAL_LAST; i++)
  248. {
  249. if ( !Q_stricmp( token, svMaterialNames[i] ) )
  250. {
  251. shader->surfaceFlags &= ~MATERIAL_MASK;//safety, clear it first
  252. shader->surfaceFlags |= i;
  253. break;
  254. }
  255. }
  256. }
  257. /*
  258. ===============
  259. ParseVector
  260. ===============
  261. */
  262. qboolean CM_ParseVector( CCMShader *shader, const char **text, int count, float *v )
  263. {
  264. char *token;
  265. int i;
  266. // FIXME: spaces are currently required after parens, should change parseext...
  267. token = COM_ParseExt( text, qfalse );
  268. if ( strcmp( token, "(" ) )
  269. {
  270. Com_Printf( S_COLOR_YELLOW "WARNING: missing parenthesis in shader '%s'\n", shader->shader );
  271. return qfalse;
  272. }
  273. for ( i = 0 ; i < count ; i++ )
  274. {
  275. token = COM_ParseExt( text, qfalse );
  276. if ( !token[0] )
  277. {
  278. Com_Printf( S_COLOR_YELLOW "WARNING: missing vector element in shader '%s'\n", shader->shader );
  279. return qfalse;
  280. }
  281. v[i] = atof( token );
  282. }
  283. token = COM_ParseExt( text, qfalse );
  284. if ( strcmp( token, ")" ) )
  285. {
  286. Com_Printf( S_COLOR_YELLOW "WARNING: missing parenthesis in shader '%s'\n", shader->shader );
  287. return qfalse;
  288. }
  289. return qtrue;
  290. }
  291. /*
  292. =================
  293. CM_ParseShader
  294. The current text pointer is at the explicit text definition of the
  295. shader. Parse it into the global shader variable.
  296. This extracts all the info from the shader required for physics and collision
  297. It is designed to *NOT* load any image files and not require any of the renderer to
  298. be initialised.
  299. =================
  300. */
  301. void CM_ParseShader( CCMShader *shader, const char **text )
  302. {
  303. char *token;
  304. token = COM_ParseExt( text, qtrue );
  305. if ( token[0] != '{' )
  306. {
  307. Com_Printf( S_COLOR_YELLOW "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader->shader );
  308. return;
  309. }
  310. while ( true )
  311. {
  312. token = COM_ParseExt( text, qtrue );
  313. if ( !token[0] )
  314. {
  315. Com_Printf( S_COLOR_YELLOW "WARNING: no concluding '}' in shader %s\n", shader->shader );
  316. return;
  317. }
  318. // end of shader definition
  319. if ( token[0] == '}' )
  320. {
  321. break;
  322. }
  323. // stage definition
  324. else if ( token[0] == '{' )
  325. {
  326. SkipBracedSection( text );
  327. continue;
  328. }
  329. // material deprecated as of 11 Jan 01
  330. // material undeprecated as of 7 May 01 - q3map_material deprecated
  331. else if ( !Q_stricmp( token, "material" ) || !Q_stricmp( token, "q3map_material" ) )
  332. {
  333. SV_ParseMaterial( shader, text );
  334. }
  335. // sun parms
  336. // q3map_sun deprecated as of 11 Jan 01
  337. else if ( !Q_stricmp( token, "sun" ) || !Q_stricmp( token, "q3map_sun" ) )
  338. {
  339. // float a, b;
  340. token = COM_ParseExt( text, qfalse );
  341. // shader->sunLight[0] = atof( token );
  342. token = COM_ParseExt( text, qfalse );
  343. // shader->sunLight[1] = atof( token );
  344. token = COM_ParseExt( text, qfalse );
  345. // shader->sunLight[2] = atof( token );
  346. // VectorNormalize( shader->sunLight );
  347. token = COM_ParseExt( text, qfalse );
  348. // a = atof( token );
  349. // VectorScale( shader->sunLight, a, shader->sunLight);
  350. token = COM_ParseExt( text, qfalse );
  351. // a = DEG2RAD(atof( token ));
  352. token = COM_ParseExt( text, qfalse );
  353. // b = DEG2RAD(atof( token ));
  354. // shader->sunDirection[0] = cos( a ) * cos( b );
  355. // shader->sunDirection[1] = sin( a ) * cos( b );
  356. // shader->sunDirection[2] = sin( b );
  357. }
  358. else if ( !Q_stricmp( token, "surfaceParm" ) )
  359. {
  360. SV_ParseSurfaceParm( shader, text );
  361. continue;
  362. }
  363. else if ( !Q_stricmp( token, "fogParms" ) )
  364. {
  365. vec3_t fogColor;
  366. if ( !CM_ParseVector( shader, text, 3, fogColor ) )
  367. {
  368. return;
  369. }
  370. token = COM_ParseExt( text, qfalse );
  371. if ( !token[0] )
  372. {
  373. Com_Printf( S_COLOR_YELLOW "WARNING: missing parm for 'fogParms' keyword in shader '%s'\n", shader->shader );
  374. continue;
  375. }
  376. // shader->depthForOpaque = atof( token );
  377. // skip any old gradient directions
  378. SkipRestOfLine( (const char **)text );
  379. continue;
  380. }
  381. }
  382. return;
  383. }
  384. /*
  385. =================
  386. CM_SetupShaderProperties
  387. Scans thru the shaders loaded for the map, parses the text of that shader and
  388. extracts the interesting info *WITHOUT* loading up any images or requiring
  389. the renderer to be active.
  390. =================
  391. */
  392. void CM_SetupShaderProperties(void)
  393. {
  394. int i;
  395. const char *def;
  396. CCMShader *shader;
  397. // Add all basic shaders to the cmShaderTable
  398. for(i = 0; i < cmg.numShaders; i++)
  399. {
  400. cmShaderTable.insert(CM_GetShaderInfo(i));
  401. }
  402. // Go through and parse evaluate shader names to shadernums
  403. for(i = 0; i < cmg.numShaders; i++)
  404. {
  405. shader = CM_GetShaderInfo(i);
  406. def = CM_GetShaderText(shader->shader);
  407. if(def)
  408. {
  409. CM_ParseShader(shader, &def);
  410. }
  411. }
  412. }
  413. void CM_ShutdownShaderProperties(void)
  414. {
  415. if(cmShaderTable.count())
  416. {
  417. Com_Printf("Shutting down cmShaderTable .....\n");
  418. cmShaderTable.clear();
  419. }
  420. }
  421. CCMShader *CM_GetShaderInfo( const char *name )
  422. {
  423. CCMShader *out;
  424. const char *def;
  425. out = cmShaderTable[name];
  426. if(out)
  427. {
  428. return(out);
  429. }
  430. // Create a new CCMShader class
  431. //out = (CCMShader *)Hunk_Alloc( sizeof( CCMShader ), h_high );
  432. out = (CCMShader *)Hunk_Alloc( sizeof( CCMShader ), qtrue );
  433. // Set defaults
  434. Q_strncpyz(out->shader, name, MAX_QPATH);
  435. out->contentFlags = CONTENTS_SOLID | CONTENTS_OPAQUE;
  436. // Parse in any text if it exists
  437. def = CM_GetShaderText(name);
  438. if(def)
  439. {
  440. CM_ParseShader(out, &def);
  441. }
  442. cmShaderTable.insert(out);
  443. return(out);
  444. }
  445. CCMShader *CM_GetShaderInfo( int shaderNum )
  446. {
  447. CCMShader *out;
  448. if((shaderNum < 0) || (shaderNum >= cmg.numShaders))
  449. {
  450. return(NULL);
  451. }
  452. out = cmg.shaders + shaderNum;
  453. return(out);
  454. }
  455. // end