shaders.cpp 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066
  1. /*
  2. Copyright (c) 2001, Loki software, inc.
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without modification,
  5. are permitted provided that the following conditions are met:
  6. Redistributions of source code must retain the above copyright notice, this list
  7. of conditions and the following disclaimer.
  8. Redistributions in binary form must reproduce the above copyright notice, this
  9. list of conditions and the following disclaimer in the documentation and/or
  10. other materials provided with the distribution.
  11. Neither the name of Loki software nor the names of its contributors may be used
  12. to endorse or promote products derived from this software without specific prior
  13. written permission.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
  15. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
  18. DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  21. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. //
  26. // Shaders Manager Plugin
  27. //
  28. // Leonardo Zide (leo@lokigames.com)
  29. //
  30. #include "shaders.h"
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <map>
  34. #include <list>
  35. #include "ifilesystem.h"
  36. #include "ishaders.h"
  37. #include "iscriplib.h"
  38. #include "itextures.h"
  39. #include "qerplugin.h"
  40. #include "irender.h"
  41. #include <glib/gslist.h>
  42. #include "debugging/debugging.h"
  43. #include "string/string.h"
  44. #include "math/vector.h"
  45. #include "generic/callback.h"
  46. #include "generic/referencecounted.h"
  47. #include "stream/memstream.h"
  48. #include "stream/stringstream.h"
  49. #include "stream/textfilestream.h"
  50. #include "os/path.h"
  51. #include "os/dir.h"
  52. #include "os/file.h"
  53. #include "stringio.h"
  54. #include "shaderlib.h"
  55. #include "texturelib.h"
  56. #include "cmdlib.h"
  57. #include "moduleobservers.h"
  58. #include "archivelib.h"
  59. #include "imagelib.h"
  60. const char* g_shadersExtension = "";
  61. const char* g_shadersDirectory = "";
  62. bool g_enableDefaultShaders = true;
  63. ShaderLanguage g_shaderLanguage = SHADERLANGUAGE_QUAKE3;
  64. bool g_useShaderList = true;
  65. _QERPlugImageTable* g_bitmapModule = 0;
  66. const char* g_texturePrefix = "textures/";
  67. void ActiveShaders_IteratorBegin();
  68. bool ActiveShaders_IteratorAtEnd();
  69. IShader *ActiveShaders_IteratorCurrent();
  70. void ActiveShaders_IteratorIncrement();
  71. Callback g_ActiveShadersChangedNotify;
  72. void FreeShaders();
  73. void LoadShaderFile (const char *filename);
  74. qtexture_t *Texture_ForName (const char *filename);
  75. /*!
  76. NOTE TTimo: there is an important distinction between SHADER_NOT_FOUND and SHADER_NOTEX:
  77. SHADER_NOT_FOUND means we didn't find the raw texture or the shader for this
  78. SHADER_NOTEX means we recognize this as a shader script, but we are missing the texture to represent it
  79. this was in the initial design of the shader code since early GtkRadiant alpha, and got sort of foxed in 1.2 and put back in
  80. */
  81. Image* loadBitmap(void* environment, const char* name)
  82. {
  83. DirectoryArchiveFile file(name, name);
  84. if(!file.failed())
  85. {
  86. return g_bitmapModule->loadImage(file);
  87. }
  88. return 0;
  89. }
  90. inline byte* getPixel(byte* pixels, int width, int height, int x, int y)
  91. {
  92. return pixels + (((((y + height) % height) * width) + ((x + width) % width)) * 4);
  93. }
  94. class KernelElement
  95. {
  96. public:
  97. int x, y;
  98. float w;
  99. };
  100. Image& convertHeightmapToNormalmap(Image& heightmap, float scale)
  101. {
  102. int w = heightmap.getWidth();
  103. int h = heightmap.getHeight();
  104. Image& normalmap = *(new RGBAImage(heightmap.getWidth(), heightmap.getHeight()));
  105. byte* in = heightmap.getRGBAPixels();
  106. byte* out = normalmap.getRGBAPixels();
  107. #if 1
  108. // no filtering
  109. const int kernelSize = 2;
  110. KernelElement kernel_du[kernelSize] = {
  111. {-1, 0,-0.5f },
  112. { 1, 0, 0.5f }
  113. };
  114. KernelElement kernel_dv[kernelSize] = {
  115. { 0, 1, 0.5f },
  116. { 0,-1,-0.5f }
  117. };
  118. #else
  119. // 3x3 Prewitt
  120. const int kernelSize = 6;
  121. KernelElement kernel_du[kernelSize] = {
  122. {-1, 1,-1.0f },
  123. {-1, 0,-1.0f },
  124. {-1,-1,-1.0f },
  125. { 1, 1, 1.0f },
  126. { 1, 0, 1.0f },
  127. { 1,-1, 1.0f }
  128. };
  129. KernelElement kernel_dv[kernelSize] = {
  130. {-1, 1, 1.0f },
  131. { 0, 1, 1.0f },
  132. { 1, 1, 1.0f },
  133. {-1,-1,-1.0f },
  134. { 0,-1,-1.0f },
  135. { 1,-1,-1.0f }
  136. };
  137. #endif
  138. int x, y = 0;
  139. while( y < h )
  140. {
  141. x = 0;
  142. while( x < w )
  143. {
  144. float du = 0;
  145. for(KernelElement* i = kernel_du; i != kernel_du + kernelSize; ++i)
  146. {
  147. du += (getPixel(in, w, h, x + (*i).x, y + (*i).y)[0] / 255.0) * (*i).w;
  148. }
  149. float dv = 0;
  150. for(KernelElement* i = kernel_dv; i != kernel_dv + kernelSize; ++i)
  151. {
  152. dv += (getPixel(in, w, h, x + (*i).x, y + (*i).y)[0] / 255.0) * (*i).w;
  153. }
  154. float nx = -du * scale;
  155. float ny = -dv * scale;
  156. float nz = 1.0;
  157. // Normalize
  158. float norm = 1.0/sqrt(nx*nx + ny*ny + nz*nz);
  159. out[0] = float_to_integer(((nx * norm) + 1) * 127.5);
  160. out[1] = float_to_integer(((ny * norm) + 1) * 127.5);
  161. out[2] = float_to_integer(((nz * norm) + 1) * 127.5);
  162. out[3] = 255;
  163. x++;
  164. out += 4;
  165. }
  166. y++;
  167. }
  168. return normalmap;
  169. }
  170. Image* loadHeightmap(void* environment, const char* name)
  171. {
  172. Image* heightmap = GlobalTexturesCache().loadImage(name);
  173. if(heightmap != 0)
  174. {
  175. Image& normalmap = convertHeightmapToNormalmap(*heightmap, *reinterpret_cast<float*>(environment));
  176. heightmap->release();
  177. return &normalmap;
  178. }
  179. return 0;
  180. }
  181. Image* loadSpecial(void* environment, const char* name)
  182. {
  183. if(*name == '_') // special image
  184. {
  185. StringOutputStream bitmapName(256);
  186. bitmapName << GlobalRadiant().getAppPath() << "bitmaps/" << name + 1 << ".bmp";
  187. Image* image = loadBitmap(environment, bitmapName.c_str());
  188. if(image != 0)
  189. {
  190. return image;
  191. }
  192. }
  193. return GlobalTexturesCache().loadImage(name);
  194. }
  195. // clean a texture name to the qtexture_t name format we use internally
  196. // NOTE: case sensitivity: the engine is case sensitive. we store the shader name with case information and save with case
  197. // information as well. but we assume there won't be any case conflict and so when doing lookups based on shader name,
  198. // we compare as case insensitive. That is Radiant is case insensitive, but knows that the engine is case sensitive.
  199. //++timo FIXME: we need to put code somewhere to detect when two shaders that are case insensitive equal are present
  200. void parseTextureName(CopiedString& name, const char* token)
  201. {
  202. StringOutputStream cleaned(256);
  203. cleaned << PathCleaned(token);
  204. name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
  205. }
  206. bool Tokeniser_parseTextureName(Tokeniser& tokeniser, CopiedString& name)
  207. {
  208. const char* token = tokeniser.getToken();
  209. if(token == 0)
  210. {
  211. Tokeniser_unexpectedError(tokeniser, token, "#texture-name");
  212. return false;
  213. }
  214. parseTextureName(name, token);
  215. return true;
  216. }
  217. void parseShaderName(CopiedString& name, const char* token)
  218. {
  219. StringOutputStream cleaned(256);
  220. cleaned << PathCleaned(token);
  221. name = cleaned.c_str();
  222. }
  223. bool Tokeniser_parseShaderName(Tokeniser& tokeniser, CopiedString& name)
  224. {
  225. const char* token = tokeniser.getToken();
  226. if(token == 0)
  227. {
  228. Tokeniser_unexpectedError(tokeniser, token, "#shader-name");
  229. return false;
  230. }
  231. parseShaderName(name, token);
  232. return true;
  233. }
  234. bool Tokeniser_parseString(Tokeniser& tokeniser, CopiedString& string)
  235. {
  236. const char* token = tokeniser.getToken();
  237. if(token == 0)
  238. {
  239. Tokeniser_unexpectedError(tokeniser, token, "#string");
  240. return false;
  241. }
  242. string = token;
  243. return true;
  244. }
  245. typedef std::list<CopiedString> ShaderParameters;
  246. typedef std::list<CopiedString> ShaderArguments;
  247. typedef CopiedString TextureExpression;
  248. typedef CopiedString ShaderValue;
  249. typedef std::pair<CopiedString, CopiedString> BlendFuncExpression;
  250. class ShaderTemplate
  251. {
  252. std::size_t m_refcount;
  253. CopiedString m_Name;
  254. public:
  255. ShaderParameters m_params;
  256. TextureExpression m_textureName;
  257. TextureExpression m_diffuse;
  258. TextureExpression m_bump;
  259. ShaderValue m_heightmapScale;
  260. TextureExpression m_specular;
  261. TextureExpression m_lightFalloffImage;
  262. int m_nFlags;
  263. float m_fTrans;
  264. // alphafunc stuff
  265. IShader::EAlphaFunc m_AlphaFunc;
  266. float m_AlphaRef;
  267. // cull stuff
  268. IShader::ECull m_Cull;
  269. ShaderTemplate() :
  270. m_refcount(0)
  271. {
  272. m_nFlags = 0;
  273. m_fTrans = 1.0f;
  274. }
  275. void IncRef()
  276. {
  277. ++m_refcount;
  278. }
  279. void DecRef()
  280. {
  281. ASSERT_MESSAGE(m_refcount != 0, "shader reference-count going below zero");
  282. if(--m_refcount == 0)
  283. {
  284. delete this;
  285. }
  286. }
  287. std::size_t refcount()
  288. {
  289. return m_refcount;
  290. }
  291. const char* getName() const
  292. {
  293. return m_Name.c_str();
  294. }
  295. void setName(const char* name)
  296. {
  297. m_Name = name;
  298. }
  299. // -----------------------------------------
  300. bool parseDoom3(Tokeniser& tokeniser);
  301. bool parseQuake3(Tokeniser& tokeniser);
  302. bool parseTemplate(Tokeniser& tokeniser);
  303. void CreateDefault(const char *name)
  304. {
  305. if(g_enableDefaultShaders)
  306. {
  307. m_textureName = name;
  308. }
  309. else
  310. {
  311. m_textureName = "";
  312. }
  313. setName(name);
  314. }
  315. class MapLayerTemplate
  316. {
  317. TextureExpression m_texture;
  318. BlendFuncExpression m_blendFunc;
  319. bool m_clampToBorder;
  320. ShaderValue m_alphaTest;
  321. public:
  322. MapLayerTemplate(const TextureExpression& texture, const BlendFuncExpression& blendFunc, bool clampToBorder, const ShaderValue& alphaTest) :
  323. m_texture(texture),
  324. m_blendFunc(blendFunc),
  325. m_clampToBorder(false),
  326. m_alphaTest(alphaTest)
  327. {
  328. }
  329. const TextureExpression& texture() const
  330. {
  331. return m_texture;
  332. }
  333. const BlendFuncExpression& blendFunc() const
  334. {
  335. return m_blendFunc;
  336. }
  337. bool clampToBorder() const
  338. {
  339. return m_clampToBorder;
  340. }
  341. const ShaderValue& alphaTest() const
  342. {
  343. return m_alphaTest;
  344. }
  345. };
  346. typedef std::vector<MapLayerTemplate> MapLayers;
  347. MapLayers m_layers;
  348. };
  349. bool Doom3Shader_parseHeightmap(Tokeniser& tokeniser, CopiedString& bump, CopiedString& heightmapScale)
  350. {
  351. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
  352. RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, bump));
  353. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ","));
  354. RETURN_FALSE_IF_FAIL(Tokeniser_parseString(tokeniser, heightmapScale));
  355. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
  356. return true;
  357. }
  358. bool Doom3Shader_parseAddnormals(Tokeniser& tokeniser, CopiedString& bump)
  359. {
  360. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
  361. RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, bump));
  362. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ","));
  363. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "heightmap"));
  364. CopiedString heightmapName;
  365. CopiedString heightmapScale;
  366. RETURN_FALSE_IF_FAIL(Doom3Shader_parseHeightmap(tokeniser, heightmapName, heightmapScale));
  367. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
  368. return true;
  369. }
  370. bool Doom3Shader_parseBumpmap(Tokeniser& tokeniser, CopiedString& bump, CopiedString& heightmapScale)
  371. {
  372. const char* token = tokeniser.getToken();
  373. if(token == 0)
  374. {
  375. Tokeniser_unexpectedError(tokeniser, token, "#bumpmap");
  376. return false;
  377. }
  378. if(string_equal(token, "heightmap"))
  379. {
  380. RETURN_FALSE_IF_FAIL(Doom3Shader_parseHeightmap(tokeniser, bump, heightmapScale));
  381. }
  382. else if(string_equal(token, "addnormals"))
  383. {
  384. RETURN_FALSE_IF_FAIL(Doom3Shader_parseAddnormals(tokeniser, bump));
  385. }
  386. else
  387. {
  388. parseTextureName(bump, token);
  389. }
  390. return true;
  391. }
  392. enum LayerTypeId
  393. {
  394. LAYER_NONE,
  395. LAYER_BLEND,
  396. LAYER_DIFFUSEMAP,
  397. LAYER_BUMPMAP,
  398. LAYER_SPECULARMAP
  399. };
  400. class LayerTemplate
  401. {
  402. public:
  403. LayerTypeId m_type;
  404. CopiedString m_texture;
  405. BlendFuncExpression m_blendFunc;
  406. bool m_clampToBorder;
  407. ShaderValue m_alphaTest;
  408. ShaderValue m_heightmapScale;
  409. LayerTemplate() : m_type(LAYER_NONE), m_blendFunc("GL_ONE", "GL_ZERO"), m_clampToBorder(false), m_alphaTest("-1"), m_heightmapScale("0")
  410. {
  411. }
  412. };
  413. bool parseShaderParameters(Tokeniser& tokeniser, ShaderParameters& params)
  414. {
  415. Tokeniser_parseToken(tokeniser, "(");
  416. for(;;)
  417. {
  418. const char* param = tokeniser.getToken();
  419. if(string_equal(param, ")"))
  420. {
  421. break;
  422. }
  423. params.push_back(param);
  424. const char* comma = tokeniser.getToken();
  425. if(string_equal(comma, ")"))
  426. {
  427. break;
  428. }
  429. if(!string_equal(comma, ","))
  430. {
  431. Tokeniser_unexpectedError(tokeniser, comma, ",");
  432. return false;
  433. }
  434. }
  435. return true;
  436. }
  437. bool ShaderTemplate::parseTemplate(Tokeniser& tokeniser)
  438. {
  439. m_Name = tokeniser.getToken();
  440. if(!parseShaderParameters(tokeniser, m_params))
  441. {
  442. globalErrorStream() << "shader template: " << makeQuoted(m_Name.c_str()) << ": parameter parse failed\n";
  443. return false;
  444. }
  445. return parseDoom3(tokeniser);
  446. }
  447. bool ShaderTemplate::parseDoom3(Tokeniser& tokeniser)
  448. {
  449. LayerTemplate currentLayer;
  450. bool isFog = false;
  451. // we need to read until we hit a balanced }
  452. int depth = 0;
  453. for(;;)
  454. {
  455. tokeniser.nextLine();
  456. const char* token = tokeniser.getToken();
  457. if(token == 0)
  458. return false;
  459. if(string_equal(token, "{"))
  460. {
  461. ++depth;
  462. continue;
  463. }
  464. else if(string_equal(token, "}"))
  465. {
  466. --depth;
  467. if(depth < 0) // error
  468. {
  469. return false;
  470. }
  471. if(depth == 0) // end of shader
  472. {
  473. break;
  474. }
  475. if(depth == 1) // end of layer
  476. {
  477. if(currentLayer.m_type == LAYER_DIFFUSEMAP)
  478. {
  479. m_diffuse = currentLayer.m_texture;
  480. }
  481. else if(currentLayer.m_type == LAYER_BUMPMAP)
  482. {
  483. m_bump = currentLayer.m_texture;
  484. }
  485. else if(currentLayer.m_type == LAYER_SPECULARMAP)
  486. {
  487. m_specular = currentLayer.m_texture;
  488. }
  489. else if(!string_empty(currentLayer.m_texture.c_str()))
  490. {
  491. m_layers.push_back(MapLayerTemplate(
  492. currentLayer.m_texture.c_str(),
  493. currentLayer.m_blendFunc,
  494. currentLayer.m_clampToBorder,
  495. currentLayer.m_alphaTest
  496. ));
  497. }
  498. currentLayer.m_type = LAYER_NONE;
  499. currentLayer.m_texture = "";
  500. }
  501. continue;
  502. }
  503. if(depth == 2) // in layer
  504. {
  505. if(string_equal_nocase(token, "blend"))
  506. {
  507. const char* blend = tokeniser.getToken();
  508. if(blend == 0)
  509. {
  510. Tokeniser_unexpectedError(tokeniser, blend, "#blend");
  511. return false;
  512. }
  513. if(string_equal_nocase(blend, "diffusemap"))
  514. {
  515. currentLayer.m_type = LAYER_DIFFUSEMAP;
  516. }
  517. else if(string_equal_nocase(blend, "bumpmap"))
  518. {
  519. currentLayer.m_type = LAYER_BUMPMAP;
  520. }
  521. else if(string_equal_nocase(blend, "specularmap"))
  522. {
  523. currentLayer.m_type = LAYER_SPECULARMAP;
  524. }
  525. else
  526. {
  527. currentLayer.m_blendFunc.first = blend;
  528. const char* comma = tokeniser.getToken();
  529. if(comma == 0)
  530. {
  531. Tokeniser_unexpectedError(tokeniser, comma, "#comma");
  532. return false;
  533. }
  534. if(string_equal(comma, ","))
  535. {
  536. RETURN_FALSE_IF_FAIL(Tokeniser_parseString(tokeniser, currentLayer.m_blendFunc.second));
  537. }
  538. else
  539. {
  540. currentLayer.m_blendFunc.second = "";
  541. tokeniser.ungetToken();
  542. }
  543. }
  544. }
  545. else if(string_equal_nocase(token, "map"))
  546. {
  547. if(currentLayer.m_type == LAYER_BUMPMAP)
  548. {
  549. RETURN_FALSE_IF_FAIL(Doom3Shader_parseBumpmap(tokeniser, currentLayer.m_texture, currentLayer.m_heightmapScale));
  550. }
  551. else
  552. {
  553. const char* map = tokeniser.getToken();
  554. if(map == 0)
  555. {
  556. Tokeniser_unexpectedError(tokeniser, map, "#map");
  557. return false;
  558. }
  559. if(string_equal(map, "makealpha"))
  560. {
  561. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
  562. const char* texture = tokeniser.getToken();
  563. if(texture == 0)
  564. {
  565. Tokeniser_unexpectedError(tokeniser, texture, "#texture");
  566. return false;
  567. }
  568. currentLayer.m_texture = texture;
  569. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
  570. }
  571. else
  572. {
  573. parseTextureName(currentLayer.m_texture, map);
  574. }
  575. }
  576. }
  577. else if(string_equal_nocase(token, "zeroclamp"))
  578. {
  579. currentLayer.m_clampToBorder = true;
  580. }
  581. #if 0
  582. else if(string_equal_nocase(token, "alphaTest"))
  583. {
  584. Tokeniser_getFloat(tokeniser, currentLayer.m_alphaTest);
  585. }
  586. #endif
  587. }
  588. else if(depth == 1)
  589. {
  590. if(string_equal_nocase(token, "qer_editorimage"))
  591. {
  592. RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, m_textureName));
  593. }
  594. else if (string_equal_nocase(token, "qer_trans"))
  595. {
  596. m_fTrans = string_read_float(tokeniser.getToken());
  597. m_nFlags |= QER_TRANS;
  598. }
  599. else if (string_equal_nocase(token, "translucent"))
  600. {
  601. m_fTrans = 1;
  602. m_nFlags |= QER_TRANS;
  603. }
  604. else if (string_equal(token, "DECAL_MACRO"))
  605. {
  606. m_fTrans = 1;
  607. m_nFlags |= QER_TRANS;
  608. }
  609. else if (string_equal_nocase(token, "bumpmap"))
  610. {
  611. RETURN_FALSE_IF_FAIL(Doom3Shader_parseBumpmap(tokeniser, m_bump, m_heightmapScale));
  612. }
  613. else if (string_equal_nocase(token, "diffusemap"))
  614. {
  615. RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, m_diffuse));
  616. }
  617. else if (string_equal_nocase(token, "specularmap"))
  618. {
  619. RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, m_specular));
  620. }
  621. else if (string_equal_nocase(token, "twosided"))
  622. {
  623. m_Cull = IShader::eCullNone;
  624. m_nFlags |= QER_CULL;
  625. }
  626. else if (string_equal_nocase(token, "nodraw"))
  627. {
  628. m_nFlags |= QER_NODRAW;
  629. }
  630. else if (string_equal_nocase(token, "nonsolid"))
  631. {
  632. m_nFlags |= QER_NONSOLID;
  633. }
  634. else if (string_equal_nocase(token, "liquid"))
  635. {
  636. m_nFlags |= QER_WATER;
  637. }
  638. else if (string_equal_nocase(token, "areaportal"))
  639. {
  640. m_nFlags |= QER_AREAPORTAL;
  641. }
  642. else if (string_equal_nocase(token, "playerclip")
  643. || string_equal_nocase(token, "monsterclip")
  644. || string_equal_nocase(token, "ikclip")
  645. || string_equal_nocase(token, "moveableclip"))
  646. {
  647. m_nFlags |= QER_CLIP;
  648. }
  649. if (string_equal_nocase(token, "fogLight"))
  650. {
  651. isFog = true;
  652. }
  653. else if (!isFog && string_equal_nocase(token, "lightFalloffImage"))
  654. {
  655. const char* lightFalloffImage = tokeniser.getToken();
  656. if(lightFalloffImage == 0)
  657. {
  658. Tokeniser_unexpectedError(tokeniser, lightFalloffImage, "#lightFalloffImage");
  659. return false;
  660. }
  661. if(string_equal_nocase(lightFalloffImage, "makeintensity"))
  662. {
  663. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
  664. CopiedString name;
  665. RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, name));
  666. m_lightFalloffImage = name.c_str();
  667. RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
  668. }
  669. else
  670. {
  671. m_lightFalloffImage = lightFalloffImage;
  672. }
  673. }
  674. }
  675. }
  676. if(string_empty(m_textureName.c_str()))
  677. {
  678. m_textureName = m_diffuse;
  679. }
  680. return true;
  681. }
  682. typedef SmartPointer<ShaderTemplate> ShaderTemplatePointer;
  683. typedef std::map<CopiedString, ShaderTemplatePointer> ShaderTemplateMap;
  684. ShaderTemplateMap g_shaders;
  685. ShaderTemplateMap g_shaderTemplates;
  686. ShaderTemplate* findTemplate(const char* name)
  687. {
  688. ShaderTemplateMap::iterator i = g_shaderTemplates.find(name);
  689. if(i != g_shaderTemplates.end())
  690. {
  691. return (*i).second.get();
  692. }
  693. return 0;
  694. }
  695. class ShaderDefinition
  696. {
  697. public:
  698. ShaderDefinition(ShaderTemplate* shaderTemplate, const ShaderArguments& args, const char* filename)
  699. : shaderTemplate(shaderTemplate), args(args), filename(filename)
  700. {
  701. }
  702. ShaderTemplate* shaderTemplate;
  703. ShaderArguments args;
  704. const char* filename;
  705. };
  706. typedef std::map<CopiedString, ShaderDefinition> ShaderDefinitionMap;
  707. ShaderDefinitionMap g_shaderDefinitions;
  708. bool parseTemplateInstance(Tokeniser& tokeniser, const char* filename)
  709. {
  710. CopiedString name;
  711. RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, name));
  712. const char* templateName = tokeniser.getToken();
  713. ShaderTemplate* shaderTemplate = findTemplate(templateName);
  714. if(shaderTemplate == 0)
  715. {
  716. globalErrorStream() << "shader instance: " << makeQuoted(name.c_str()) << ": shader template not found: " << makeQuoted(templateName) << "\n";
  717. }
  718. ShaderArguments args;
  719. if(!parseShaderParameters(tokeniser, args))
  720. {
  721. globalErrorStream() << "shader instance: " << makeQuoted(name.c_str()) << ": argument parse failed\n";
  722. return false;
  723. }
  724. if(shaderTemplate != 0)
  725. {
  726. if(!g_shaderDefinitions.insert(ShaderDefinitionMap::value_type(name, ShaderDefinition(shaderTemplate, args, filename))).second)
  727. {
  728. globalErrorStream() << "shader instance: " << makeQuoted(name.c_str()) << ": already exists, second definition ignored\n";
  729. }
  730. }
  731. return true;
  732. }
  733. const char* evaluateShaderValue(const char* value, const ShaderParameters& params, const ShaderArguments& args)
  734. {
  735. ShaderArguments::const_iterator j = args.begin();
  736. for(ShaderParameters::const_iterator i = params.begin(); i != params.end(); ++i, ++j)
  737. {
  738. const char* other = (*i).c_str();
  739. if(string_equal(value, other))
  740. {
  741. return (*j).c_str();
  742. }
  743. }
  744. return value;
  745. }
  746. ///\todo BlendFunc parsing
  747. BlendFunc evaluateBlendFunc(const BlendFuncExpression& blendFunc, const ShaderParameters& params, const ShaderArguments& args)
  748. {
  749. return BlendFunc(BLEND_ONE, BLEND_ZERO);
  750. }
  751. qtexture_t* evaluateTexture(const TextureExpression& texture, const ShaderParameters& params, const ShaderArguments& args, const LoadImageCallback& loader = GlobalTexturesCache().defaultLoader())
  752. {
  753. StringOutputStream result(64);
  754. const char* expression = texture.c_str();
  755. const char* end = expression + string_length(expression);
  756. if(!string_empty(expression))
  757. {
  758. for(;;)
  759. {
  760. const char* best = end;
  761. const char* bestParam = 0;
  762. const char* bestArg = 0;
  763. ShaderArguments::const_iterator j = args.begin();
  764. for(ShaderParameters::const_iterator i = params.begin(); i != params.end(); ++i, ++j)
  765. {
  766. const char* found = strstr(expression, (*i).c_str());
  767. if(found != 0 && found < best)
  768. {
  769. best = found;
  770. bestParam = (*i).c_str();
  771. bestArg = (*j).c_str();
  772. }
  773. }
  774. if(best != end)
  775. {
  776. result << StringRange(expression, best);
  777. result << PathCleaned(bestArg);
  778. expression = best + string_length(bestParam);
  779. }
  780. else
  781. {
  782. break;
  783. }
  784. }
  785. result << expression;
  786. }
  787. return GlobalTexturesCache().capture(loader, result.c_str());
  788. }
  789. float evaluateFloat(const ShaderValue& value, const ShaderParameters& params, const ShaderArguments& args)
  790. {
  791. const char* result = evaluateShaderValue(value.c_str(), params, args);
  792. float f;
  793. if(!string_parse_float(result, f))
  794. {
  795. globalErrorStream() << "parsing float value failed: " << makeQuoted(result) << "\n";
  796. }
  797. return f;
  798. }
  799. BlendFactor evaluateBlendFactor(const ShaderValue& value, const ShaderParameters& params, const ShaderArguments& args)
  800. {
  801. const char* result = evaluateShaderValue(value.c_str(), params, args);
  802. if(string_equal_nocase(result, "gl_zero"))
  803. {
  804. return BLEND_ZERO;
  805. }
  806. if(string_equal_nocase(result, "gl_one"))
  807. {
  808. return BLEND_ONE;
  809. }
  810. if(string_equal_nocase(result, "gl_src_color"))
  811. {
  812. return BLEND_SRC_COLOUR;
  813. }
  814. if(string_equal_nocase(result, "gl_one_minus_src_color"))
  815. {
  816. return BLEND_ONE_MINUS_SRC_COLOUR;
  817. }
  818. if(string_equal_nocase(result, "gl_src_alpha"))
  819. {
  820. return BLEND_SRC_ALPHA;
  821. }
  822. if(string_equal_nocase(result, "gl_one_minus_src_alpha"))
  823. {
  824. return BLEND_ONE_MINUS_SRC_ALPHA;
  825. }
  826. if(string_equal_nocase(result, "gl_dst_color"))
  827. {
  828. return BLEND_DST_COLOUR;
  829. }
  830. if(string_equal_nocase(result, "gl_one_minus_dst_color"))
  831. {
  832. return BLEND_ONE_MINUS_DST_COLOUR;
  833. }
  834. if(string_equal_nocase(result, "gl_dst_alpha"))
  835. {
  836. return BLEND_DST_ALPHA;
  837. }
  838. if(string_equal_nocase(result, "gl_one_minus_dst_alpha"))
  839. {
  840. return BLEND_ONE_MINUS_DST_ALPHA;
  841. }
  842. if(string_equal_nocase(result, "gl_src_alpha_saturate"))
  843. {
  844. return BLEND_SRC_ALPHA_SATURATE;
  845. }
  846. globalErrorStream() << "parsing blend-factor value failed: " << makeQuoted(result) << "\n";
  847. return BLEND_ZERO;
  848. }
  849. class CShader : public IShader
  850. {
  851. std::size_t m_refcount;
  852. const ShaderTemplate& m_template;
  853. const ShaderArguments& m_args;
  854. const char* m_filename;
  855. // name is shader-name, otherwise texture-name (if not a real shader)
  856. CopiedString m_Name;
  857. qtexture_t* m_pTexture;
  858. qtexture_t* m_notfound;
  859. qtexture_t* m_pDiffuse;
  860. float m_heightmapScale;
  861. qtexture_t* m_pBump;
  862. qtexture_t* m_pSpecular;
  863. qtexture_t* m_pLightFalloffImage;
  864. BlendFunc m_blendFunc;
  865. bool m_bInUse;
  866. public:
  867. static bool m_lightingEnabled;
  868. CShader(const ShaderDefinition& definition) :
  869. m_refcount(0),
  870. m_template(*definition.shaderTemplate),
  871. m_args(definition.args),
  872. m_filename(definition.filename),
  873. m_blendFunc(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA),
  874. m_bInUse(false)
  875. {
  876. m_pTexture = 0;
  877. m_pDiffuse = 0;
  878. m_pBump = 0;
  879. m_pSpecular = 0;
  880. m_notfound = 0;
  881. realise();
  882. }
  883. virtual ~CShader()
  884. {
  885. unrealise();
  886. ASSERT_MESSAGE(m_refcount == 0, "deleting active shader");
  887. }
  888. // IShaders implementation -----------------
  889. void IncRef()
  890. {
  891. ++m_refcount;
  892. }
  893. void DecRef()
  894. {
  895. ASSERT_MESSAGE(m_refcount != 0, "shader reference-count going below zero");
  896. if(--m_refcount == 0)
  897. {
  898. delete this;
  899. }
  900. }
  901. std::size_t refcount()
  902. {
  903. return m_refcount;
  904. }
  905. // get/set the qtexture_t* Radiant uses to represent this shader object
  906. qtexture_t* getTexture() const
  907. {
  908. return m_pTexture;
  909. }
  910. qtexture_t* getDiffuse() const
  911. {
  912. return m_pDiffuse;
  913. }
  914. qtexture_t* getBump() const
  915. {
  916. return m_pBump;
  917. }
  918. qtexture_t* getSpecular() const
  919. {
  920. return m_pSpecular;
  921. }
  922. // get shader name
  923. const char* getName() const
  924. {
  925. return m_Name.c_str();
  926. }
  927. bool IsInUse() const
  928. {
  929. return m_bInUse;
  930. }
  931. void SetInUse(bool bInUse)
  932. {
  933. m_bInUse = bInUse;
  934. g_ActiveShadersChangedNotify();
  935. }
  936. // get the shader flags
  937. int getFlags() const
  938. {
  939. return m_template.m_nFlags;
  940. }
  941. // get the transparency value
  942. float getTrans() const
  943. {
  944. return m_template.m_fTrans;
  945. }
  946. // test if it's a true shader, or a default shader created to wrap around a texture
  947. bool IsDefault() const
  948. {
  949. return string_empty(m_filename);
  950. }
  951. // get the alphaFunc
  952. void getAlphaFunc(EAlphaFunc *func, float *ref) { *func = m_template.m_AlphaFunc; *ref = m_template.m_AlphaRef; };
  953. BlendFunc getBlendFunc() const
  954. {
  955. return m_blendFunc;
  956. }
  957. // get the cull type
  958. ECull getCull()
  959. {
  960. return m_template.m_Cull;
  961. };
  962. // get shader file name (ie the file where this one is defined)
  963. const char* getShaderFileName() const
  964. {
  965. return m_filename;
  966. }
  967. // -----------------------------------------
  968. void realise()
  969. {
  970. m_pTexture = evaluateTexture(m_template.m_textureName, m_template.m_params, m_args);
  971. if(m_pTexture->texture_number == 0)
  972. {
  973. m_notfound = m_pTexture;
  974. {
  975. StringOutputStream name(256);
  976. name << GlobalRadiant().getAppPath() << "bitmaps/" << (IsDefault() ? "notex.bmp" : "shadernotex.bmp");
  977. m_pTexture = GlobalTexturesCache().capture(LoadImageCallback(0, loadBitmap), name.c_str());
  978. }
  979. }
  980. realiseLighting();
  981. if(m_layers.size() == 1)
  982. {
  983. const BlendFuncExpression& blendFunc = m_template.m_layers.front().blendFunc();
  984. if(!string_empty(blendFunc.second.c_str()))
  985. {
  986. m_blendFunc = BlendFunc(
  987. evaluateBlendFactor(blendFunc.first.c_str(), m_template.m_params, m_args),
  988. evaluateBlendFactor(blendFunc.second.c_str(), m_template.m_params, m_args)
  989. );
  990. }
  991. else
  992. {
  993. const char* blend = evaluateShaderValue(blendFunc.first.c_str(), m_template.m_params, m_args);
  994. if(string_equal_nocase(blend, "add"))
  995. {
  996. m_blendFunc = BlendFunc(BLEND_ONE, BLEND_ONE);
  997. }
  998. else if(string_equal_nocase(blend, "filter"))
  999. {
  1000. m_blendFunc = BlendFunc(BLEND_DST_COLOUR, BLEND_ZERO);
  1001. }
  1002. else if(string_equal_nocase(blend, "blend"))
  1003. {
  1004. m_blendFunc = BlendFunc(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
  1005. }
  1006. else
  1007. {
  1008. globalErrorStream() << "parsing blend value failed: " << makeQuoted(blend) << "\n";
  1009. }
  1010. }
  1011. }
  1012. }
  1013. void unrealise()
  1014. {
  1015. GlobalTexturesCache().release(m_pTexture);
  1016. if(m_notfound != 0)
  1017. {
  1018. GlobalTexturesCache().release(m_notfound);
  1019. }
  1020. unrealiseLighting();
  1021. }
  1022. void realiseLighting()
  1023. {
  1024. if(m_lightingEnabled)
  1025. {
  1026. LoadImageCallback loader = GlobalTexturesCache().defaultLoader();
  1027. if(!string_empty(m_template.m_heightmapScale.c_str()))
  1028. {
  1029. m_heightmapScale = evaluateFloat(m_template.m_heightmapScale, m_template.m_params, m_args);
  1030. loader = LoadImageCallback(&m_heightmapScale, loadHeightmap);
  1031. }
  1032. m_pDiffuse = evaluateTexture(m_template.m_diffuse, m_template.m_params, m_args);
  1033. m_pBump = evaluateTexture(m_template.m_bump, m_template.m_params, m_args, loader);
  1034. m_pSpecular = evaluateTexture(m_template.m_specular, m_template.m_params, m_args);
  1035. m_pLightFalloffImage = evaluateTexture(m_template.m_lightFalloffImage, m_template.m_params, m_args);
  1036. for(ShaderTemplate::MapLayers::const_iterator i = m_template.m_layers.begin(); i != m_template.m_layers.end(); ++i)
  1037. {
  1038. m_layers.push_back(evaluateLayer(*i, m_template.m_params, m_args));
  1039. }
  1040. }
  1041. }
  1042. void unrealiseLighting()
  1043. {
  1044. if(m_lightingEnabled)
  1045. {
  1046. GlobalTexturesCache().release(m_pDiffuse);
  1047. GlobalTexturesCache().release(m_pBump);
  1048. GlobalTexturesCache().release(m_pSpecular);
  1049. GlobalTexturesCache().release(m_pLightFalloffImage);
  1050. for(MapLayers::iterator i = m_layers.begin(); i != m_layers.end(); ++i)
  1051. {
  1052. GlobalTexturesCache().release((*i).texture());
  1053. }
  1054. }
  1055. }
  1056. // set shader name
  1057. void setName(const char* name)
  1058. {
  1059. m_Name = name;
  1060. }
  1061. class MapLayer : public ShaderLayer
  1062. {
  1063. qtexture_t* m_texture;
  1064. BlendFunc m_blendFunc;
  1065. bool m_clampToBorder;
  1066. float m_alphaTest;
  1067. public:
  1068. MapLayer(qtexture_t* texture, BlendFunc blendFunc, bool clampToBorder, float alphaTest) :
  1069. m_texture(texture),
  1070. m_blendFunc(blendFunc),
  1071. m_clampToBorder(false),
  1072. m_alphaTest(alphaTest)
  1073. {
  1074. }
  1075. qtexture_t* texture() const
  1076. {
  1077. return m_texture;
  1078. }
  1079. BlendFunc blendFunc() const
  1080. {
  1081. return m_blendFunc;
  1082. }
  1083. bool clampToBorder() const
  1084. {
  1085. return m_clampToBorder;
  1086. }
  1087. float alphaTest() const
  1088. {
  1089. return m_alphaTest;
  1090. }
  1091. };
  1092. static MapLayer evaluateLayer(const ShaderTemplate::MapLayerTemplate& layerTemplate, const ShaderParameters& params, const ShaderArguments& args)
  1093. {
  1094. return MapLayer(
  1095. evaluateTexture(layerTemplate.texture(), params, args),
  1096. evaluateBlendFunc(layerTemplate.blendFunc(), params, args),
  1097. layerTemplate.clampToBorder(),
  1098. evaluateFloat(layerTemplate.alphaTest(), params, args)
  1099. );
  1100. }
  1101. typedef std::vector<MapLayer> MapLayers;
  1102. MapLayers m_layers;
  1103. const ShaderLayer* firstLayer() const
  1104. {
  1105. if(m_layers.empty())
  1106. {
  1107. return 0;
  1108. }
  1109. return &m_layers.front();
  1110. }
  1111. void forEachLayer(const ShaderLayerCallback& callback) const
  1112. {
  1113. for(MapLayers::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i)
  1114. {
  1115. callback(*i);
  1116. }
  1117. }
  1118. qtexture_t* lightFalloffImage() const
  1119. {
  1120. if(!string_empty(m_template.m_lightFalloffImage.c_str()))
  1121. {
  1122. return m_pLightFalloffImage;
  1123. }
  1124. return 0;
  1125. }
  1126. };
  1127. bool CShader::m_lightingEnabled = false;
  1128. typedef SmartPointer<CShader> ShaderPointer;
  1129. typedef std::map<CopiedString, ShaderPointer, shader_less_t> shaders_t;
  1130. shaders_t g_ActiveShaders;
  1131. static shaders_t::iterator g_ActiveShadersIterator;
  1132. void ActiveShaders_IteratorBegin()
  1133. {
  1134. g_ActiveShadersIterator = g_ActiveShaders.begin();
  1135. }
  1136. bool ActiveShaders_IteratorAtEnd()
  1137. {
  1138. return g_ActiveShadersIterator == g_ActiveShaders.end();
  1139. }
  1140. IShader *ActiveShaders_IteratorCurrent()
  1141. {
  1142. return static_cast<CShader*>(g_ActiveShadersIterator->second);
  1143. }
  1144. void ActiveShaders_IteratorIncrement()
  1145. {
  1146. ++g_ActiveShadersIterator;
  1147. }
  1148. void debug_check_shaders(shaders_t& shaders)
  1149. {
  1150. for(shaders_t::iterator i = shaders.begin(); i != shaders.end(); ++i)
  1151. {
  1152. ASSERT_MESSAGE(i->second->refcount() == 1, "orphan shader still referenced");
  1153. }
  1154. }
  1155. // will free all GL binded qtextures and shaders
  1156. // NOTE: doesn't make much sense out of Radiant exit or called during a reload
  1157. void FreeShaders()
  1158. {
  1159. // reload shaders
  1160. // empty the actives shaders list
  1161. debug_check_shaders(g_ActiveShaders);
  1162. g_ActiveShaders.clear();
  1163. g_shaders.clear();
  1164. g_shaderTemplates.clear();
  1165. g_shaderDefinitions.clear();
  1166. g_ActiveShadersChangedNotify();
  1167. }
  1168. bool ShaderTemplate::parseQuake3(Tokeniser& tokeniser)
  1169. {
  1170. // name of the qtexture_t we'll use to represent this shader (this one has the "textures\" before)
  1171. m_textureName = m_Name;
  1172. tokeniser.nextLine();
  1173. // we need to read until we hit a balanced }
  1174. int depth = 0;
  1175. for(;;)
  1176. {
  1177. tokeniser.nextLine();
  1178. const char* token = tokeniser.getToken();
  1179. if(token == 0)
  1180. return false;
  1181. if(string_equal(token, "{"))
  1182. {
  1183. ++depth;
  1184. continue;
  1185. }
  1186. else if(string_equal(token, "}"))
  1187. {
  1188. --depth;
  1189. if(depth < 0) // underflow
  1190. {
  1191. return false;
  1192. }
  1193. if(depth == 0) // end of shader
  1194. {
  1195. break;
  1196. }
  1197. continue;
  1198. }
  1199. if(depth == 1)
  1200. {
  1201. if (string_equal_nocase(token, "qer_nocarve"))
  1202. {
  1203. m_nFlags |= QER_NOCARVE;
  1204. }
  1205. else if (string_equal_nocase(token, "qer_trans"))
  1206. {
  1207. RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, m_fTrans));
  1208. m_nFlags |= QER_TRANS;
  1209. }
  1210. else if (string_equal_nocase(token, "qer_editorimage"))
  1211. {
  1212. RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, m_textureName));
  1213. }
  1214. else if (string_equal_nocase(token, "qer_alphafunc"))
  1215. {
  1216. const char* alphafunc = tokeniser.getToken();
  1217. if(alphafunc == 0)
  1218. {
  1219. Tokeniser_unexpectedError(tokeniser, alphafunc, "#alphafunc");
  1220. return false;
  1221. }
  1222. if(string_equal_nocase(alphafunc, "equal"))
  1223. {
  1224. m_AlphaFunc = IShader::eEqual;
  1225. }
  1226. else if(string_equal_nocase(alphafunc, "greater"))
  1227. {
  1228. m_AlphaFunc = IShader::eGreater;
  1229. }
  1230. else if(string_equal_nocase(alphafunc, "less"))
  1231. {
  1232. m_AlphaFunc = IShader::eLess;
  1233. }
  1234. else if(string_equal_nocase(alphafunc, "gequal"))
  1235. {
  1236. m_AlphaFunc = IShader::eGEqual;
  1237. }
  1238. else if(string_equal_nocase(alphafunc, "lequal"))
  1239. {
  1240. m_AlphaFunc = IShader::eLEqual;
  1241. }
  1242. else
  1243. {
  1244. m_AlphaFunc = IShader::eAlways;
  1245. }
  1246. m_nFlags |= QER_ALPHATEST;
  1247. RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, m_AlphaRef));
  1248. }
  1249. else if (string_equal_nocase(token, "cull"))
  1250. {
  1251. const char* cull = tokeniser.getToken();
  1252. if(cull == 0)
  1253. {
  1254. Tokeniser_unexpectedError(tokeniser, cull, "#cull");
  1255. return false;
  1256. }
  1257. if(string_equal_nocase(cull, "none")
  1258. || string_equal_nocase(cull, "twosided")
  1259. || string_equal_nocase(cull, "disable"))
  1260. {
  1261. m_Cull = IShader::eCullNone;
  1262. }
  1263. else if(string_equal_nocase(cull, "back")
  1264. || string_equal_nocase(cull, "backside")
  1265. || string_equal_nocase(cull, "backsided"))
  1266. {
  1267. m_Cull = IShader::eCullBack;
  1268. }
  1269. else
  1270. {
  1271. m_Cull = IShader::eCullBack;
  1272. }
  1273. m_nFlags |= QER_CULL;
  1274. }
  1275. else if (string_equal_nocase(token, "surfaceparm"))
  1276. {
  1277. const char* surfaceparm = tokeniser.getToken();
  1278. if(surfaceparm == 0)
  1279. {
  1280. Tokeniser_unexpectedError(tokeniser, surfaceparm, "#surfaceparm");
  1281. return false;
  1282. }
  1283. if (string_equal_nocase(surfaceparm, "fog"))
  1284. {
  1285. m_nFlags |= QER_FOG;
  1286. if (m_fTrans == 1.0f) // has not been explicitly set by qer_trans
  1287. {
  1288. m_fTrans = 0.35f;
  1289. }
  1290. }
  1291. else if (string_equal_nocase(surfaceparm, "nodraw"))
  1292. {
  1293. m_nFlags |= QER_NODRAW;
  1294. }
  1295. else if (string_equal_nocase(surfaceparm, "nonsolid"))
  1296. {
  1297. m_nFlags |= QER_NONSOLID;
  1298. }
  1299. else if (string_equal_nocase(surfaceparm, "water"))
  1300. {
  1301. m_nFlags |= QER_WATER;
  1302. }
  1303. else if (string_equal_nocase(surfaceparm, "lava"))
  1304. {
  1305. m_nFlags |= QER_LAVA;
  1306. }
  1307. else if (string_equal_nocase(surfaceparm, "areaportal"))
  1308. {
  1309. m_nFlags |= QER_AREAPORTAL;
  1310. }
  1311. else if (string_equal_nocase(surfaceparm, "playerclip"))
  1312. {
  1313. m_nFlags |= QER_CLIP;
  1314. }
  1315. else if (string_equal_nocase(surfaceparm, "botclip"))
  1316. {
  1317. m_nFlags |= QER_BOTCLIP;
  1318. }
  1319. }
  1320. }
  1321. }
  1322. return true;
  1323. }
  1324. class Layer
  1325. {
  1326. public:
  1327. LayerTypeId m_type;
  1328. CopiedString m_texture;
  1329. BlendFunc m_blendFunc;
  1330. bool m_clampToBorder;
  1331. float m_alphaTest;
  1332. float m_heightmapScale;
  1333. Layer() : m_type(LAYER_NONE), m_blendFunc(BLEND_ONE, BLEND_ZERO), m_clampToBorder(false), m_alphaTest(-1), m_heightmapScale(0)
  1334. {
  1335. }
  1336. };
  1337. std::list<CopiedString> g_shaderFilenames;
  1338. void ParseShaderFile(Tokeniser& tokeniser, const char* filename)
  1339. {
  1340. g_shaderFilenames.push_back(filename);
  1341. filename = g_shaderFilenames.back().c_str();
  1342. tokeniser.nextLine();
  1343. for(;;)
  1344. {
  1345. const char* token = tokeniser.getToken();
  1346. if(token == 0)
  1347. {
  1348. break;
  1349. }
  1350. if(string_equal(token, "table"))
  1351. {
  1352. if(tokeniser.getToken() == 0)
  1353. {
  1354. Tokeniser_unexpectedError(tokeniser, 0, "#table-name");
  1355. return;
  1356. }
  1357. if(!Tokeniser_parseToken(tokeniser, "{"))
  1358. {
  1359. return;
  1360. }
  1361. for(;;)
  1362. {
  1363. const char* option = tokeniser.getToken();
  1364. if(string_equal(option, "{"))
  1365. {
  1366. for(;;)
  1367. {
  1368. const char* value = tokeniser.getToken();
  1369. if(string_equal(value, "}"))
  1370. {
  1371. break;
  1372. }
  1373. }
  1374. if(!Tokeniser_parseToken(tokeniser, "}"))
  1375. {
  1376. return;
  1377. }
  1378. break;
  1379. }
  1380. }
  1381. }
  1382. else
  1383. {
  1384. if(string_equal(token, "guide"))
  1385. {
  1386. parseTemplateInstance(tokeniser, filename);
  1387. }
  1388. else
  1389. {
  1390. if(!string_equal(token, "material")
  1391. && !string_equal(token, "particle")
  1392. && !string_equal(token, "skin"))
  1393. {
  1394. tokeniser.ungetToken();
  1395. }
  1396. // first token should be the path + name.. (from base)
  1397. CopiedString name;
  1398. if(!Tokeniser_parseShaderName(tokeniser, name))
  1399. {
  1400. }
  1401. ShaderTemplatePointer shaderTemplate(new ShaderTemplate());
  1402. shaderTemplate->setName(name.c_str());
  1403. g_shaders.insert(ShaderTemplateMap::value_type(shaderTemplate->getName(), shaderTemplate));
  1404. bool result = (g_shaderLanguage == SHADERLANGUAGE_QUAKE3)
  1405. ? shaderTemplate->parseQuake3(tokeniser)
  1406. : shaderTemplate->parseDoom3(tokeniser);
  1407. if (result)
  1408. {
  1409. // do we already have this shader?
  1410. if(!g_shaderDefinitions.insert(ShaderDefinitionMap::value_type(shaderTemplate->getName(), ShaderDefinition(shaderTemplate.get(), ShaderArguments(), filename))).second)
  1411. {
  1412. #ifdef _DEBUG
  1413. globalOutputStream() << "WARNING: shader " << shaderTemplate->getName() << " is already in memory, definition in " << filename << " ignored.\n";
  1414. #endif
  1415. }
  1416. }
  1417. else
  1418. {
  1419. globalErrorStream() << "Error parsing shader " << shaderTemplate->getName() << "\n";
  1420. return;
  1421. }
  1422. }
  1423. }
  1424. }
  1425. }
  1426. void parseGuideFile(Tokeniser& tokeniser, const char* filename)
  1427. {
  1428. tokeniser.nextLine();
  1429. for(;;)
  1430. {
  1431. const char* token = tokeniser.getToken();
  1432. if(token == 0)
  1433. {
  1434. break;
  1435. }
  1436. if(string_equal(token, "guide"))
  1437. {
  1438. // first token should be the path + name.. (from base)
  1439. ShaderTemplatePointer shaderTemplate(new ShaderTemplate);
  1440. shaderTemplate->parseTemplate(tokeniser);
  1441. if(!g_shaderTemplates.insert(ShaderTemplateMap::value_type(shaderTemplate->getName(), shaderTemplate)).second)
  1442. {
  1443. globalErrorStream() << "guide " << makeQuoted(shaderTemplate->getName()) << ": already defined, second definition ignored\n";
  1444. }
  1445. }
  1446. else if(string_equal(token, "inlineGuide"))
  1447. {
  1448. // skip entire inlineGuide definition
  1449. std::size_t depth = 0;
  1450. for(;;)
  1451. {
  1452. tokeniser.nextLine();
  1453. token = tokeniser.getToken();
  1454. if(string_equal(token, "{"))
  1455. {
  1456. ++depth;
  1457. }
  1458. else if(string_equal(token, "}"))
  1459. {
  1460. if(--depth == 0)
  1461. {
  1462. break;
  1463. }
  1464. }
  1465. }
  1466. }
  1467. }
  1468. }
  1469. void LoadShaderFile(const char* filename)
  1470. {
  1471. ArchiveTextFile* file = GlobalFileSystem().openTextFile(filename);
  1472. if(file != 0)
  1473. {
  1474. globalOutputStream() << "Parsing shaderfile " << filename << "\n";
  1475. Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser(file->getInputStream());
  1476. ParseShaderFile(tokeniser, filename);
  1477. tokeniser.release();
  1478. file->release();
  1479. }
  1480. else
  1481. {
  1482. globalOutputStream() << "Unable to read shaderfile " << filename << "\n";
  1483. }
  1484. }
  1485. typedef FreeCaller1<const char*, LoadShaderFile> LoadShaderFileCaller;
  1486. void loadGuideFile(const char* filename)
  1487. {
  1488. StringOutputStream fullname(256);
  1489. fullname << "guides/" << filename;
  1490. ArchiveTextFile* file = GlobalFileSystem().openTextFile(fullname.c_str());
  1491. if(file != 0)
  1492. {
  1493. globalOutputStream() << "Parsing guide file " << fullname.c_str() << "\n";
  1494. Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser(file->getInputStream());
  1495. parseGuideFile(tokeniser, fullname.c_str());
  1496. tokeniser.release();
  1497. file->release();
  1498. }
  1499. else
  1500. {
  1501. globalOutputStream() << "Unable to read guide file " << fullname.c_str() << "\n";
  1502. }
  1503. }
  1504. typedef FreeCaller1<const char*, loadGuideFile> LoadGuideFileCaller;
  1505. CShader* Try_Shader_ForName(const char* name)
  1506. {
  1507. {
  1508. shaders_t::iterator i = g_ActiveShaders.find(name);
  1509. if(i != g_ActiveShaders.end())
  1510. {
  1511. return (*i).second;
  1512. }
  1513. }
  1514. // not found, create it
  1515. ShaderDefinitionMap::iterator i = g_shaderDefinitions.find(name);
  1516. if(i == g_shaderDefinitions.end())
  1517. {
  1518. ShaderTemplatePointer shaderTemplate(new ShaderTemplate());
  1519. shaderTemplate->CreateDefault(name);
  1520. g_shaderTemplates.insert(ShaderTemplateMap::value_type(shaderTemplate->getName(), shaderTemplate));
  1521. i = g_shaderDefinitions.insert(ShaderDefinitionMap::value_type(name, ShaderDefinition(shaderTemplate.get(), ShaderArguments(), ""))).first;
  1522. }
  1523. ShaderPointer pShader(new CShader((*i).second));
  1524. pShader->setName(name);
  1525. g_ActiveShaders.insert(shaders_t::value_type(name, pShader));
  1526. g_ActiveShadersChangedNotify();
  1527. return pShader;
  1528. }
  1529. IShader *Shader_ForName(const char *name)
  1530. {
  1531. ASSERT_NOTNULL(name);
  1532. IShader *pShader = Try_Shader_ForName(name);
  1533. pShader->IncRef();
  1534. return pShader;
  1535. }
  1536. // the list of scripts/*.shader files we need to work with
  1537. // those are listed in shaderlist file
  1538. GSList *l_shaderfiles = 0;
  1539. GSList* Shaders_getShaderFileList()
  1540. {
  1541. return l_shaderfiles;
  1542. }
  1543. /*
  1544. ==================
  1545. DumpUnreferencedShaders
  1546. usefull function: dumps the list of .shader files that are not referenced to the console
  1547. ==================
  1548. */
  1549. void IfFound_dumpUnreferencedShader(bool& bFound, const char* filename)
  1550. {
  1551. bool listed = false;
  1552. for(GSList* sh = l_shaderfiles; sh != 0; sh = g_slist_next(sh))
  1553. {
  1554. if(!strcmp((char*)sh->data, filename))
  1555. {
  1556. listed = true;
  1557. break;
  1558. }
  1559. }
  1560. if(!listed)
  1561. {
  1562. if(!bFound)
  1563. {
  1564. bFound = true;
  1565. globalOutputStream() << "Following shader files are not referenced in shaderlist.txt:\n";
  1566. }
  1567. globalOutputStream() << filename << "\n";
  1568. }
  1569. }
  1570. typedef ReferenceCaller1<bool, const char*, IfFound_dumpUnreferencedShader> IfFoundDumpUnreferencedShaderCaller;
  1571. void DumpUnreferencedShaders()
  1572. {
  1573. bool bFound = false;
  1574. GlobalFileSystem().forEachFile(g_shadersDirectory, g_shadersExtension, IfFoundDumpUnreferencedShaderCaller(bFound));
  1575. }
  1576. void ShaderList_addShaderFile(const char* dirstring)
  1577. {
  1578. bool found = false;
  1579. for(GSList* tmp = l_shaderfiles; tmp != 0; tmp = tmp->next)
  1580. {
  1581. if(string_equal_nocase(dirstring, (char*)tmp->data))
  1582. {
  1583. found = true;
  1584. globalOutputStream() << "duplicate entry \"" << (char*)tmp->data << "\" in shaderlist.txt\n";
  1585. break;
  1586. }
  1587. }
  1588. if(!found)
  1589. {
  1590. l_shaderfiles = g_slist_append(l_shaderfiles, strdup(dirstring));
  1591. }
  1592. }
  1593. typedef FreeCaller1<const char*, ShaderList_addShaderFile> AddShaderFileCaller;
  1594. /*
  1595. ==================
  1596. BuildShaderList
  1597. build a CStringList of shader names
  1598. ==================
  1599. */
  1600. void BuildShaderList(TextInputStream& shaderlist)
  1601. {
  1602. Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewSimpleTokeniser(shaderlist);
  1603. tokeniser.nextLine();
  1604. const char* token = tokeniser.getToken();
  1605. StringOutputStream shaderFile(64);
  1606. while(token != 0)
  1607. {
  1608. // each token should be a shader filename
  1609. shaderFile << token << "." << g_shadersExtension;
  1610. ShaderList_addShaderFile(shaderFile.c_str());
  1611. tokeniser.nextLine();
  1612. token = tokeniser.getToken();
  1613. shaderFile.clear();
  1614. }
  1615. tokeniser.release();
  1616. }
  1617. void FreeShaderList()
  1618. {
  1619. while(l_shaderfiles != 0)
  1620. {
  1621. free(l_shaderfiles->data);
  1622. l_shaderfiles = g_slist_remove(l_shaderfiles, l_shaderfiles->data);
  1623. }
  1624. }
  1625. #include "stream/filestream.h"
  1626. bool shaderlist_findOrInstall(const char* enginePath, const char* toolsPath, const char* shaderPath, const char* gamename)
  1627. {
  1628. StringOutputStream absShaderList(256);
  1629. absShaderList << enginePath << gamename << '/' << shaderPath << "shaderlist.txt";
  1630. if(file_exists(absShaderList.c_str()))
  1631. {
  1632. return true;
  1633. }
  1634. {
  1635. StringOutputStream directory(256);
  1636. directory << enginePath << gamename << '/' << shaderPath;
  1637. if(!file_exists(directory.c_str()) && !Q_mkdir(directory.c_str()))
  1638. {
  1639. return false;
  1640. }
  1641. }
  1642. {
  1643. StringOutputStream defaultShaderList(256);
  1644. defaultShaderList << toolsPath << gamename << '/' << "default_shaderlist.txt";
  1645. if(file_exists(defaultShaderList.c_str()))
  1646. {
  1647. return file_copy(defaultShaderList.c_str(), absShaderList.c_str());
  1648. }
  1649. }
  1650. return false;
  1651. }
  1652. void Shaders_Load()
  1653. {
  1654. if(g_shaderLanguage == SHADERLANGUAGE_QUAKE4)
  1655. {
  1656. GlobalFileSystem().forEachFile("guides/", "guide", LoadGuideFileCaller(), 0);
  1657. }
  1658. const char* shaderPath = GlobalRadiant().getGameDescriptionKeyValue("shaderpath");
  1659. if(!string_empty(shaderPath))
  1660. {
  1661. StringOutputStream path(256);
  1662. path << DirectoryCleaned(shaderPath);
  1663. if(g_useShaderList)
  1664. {
  1665. // preload shader files that have been listed in shaderlist.txt
  1666. const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue("basegame");
  1667. const char* gamename = GlobalRadiant().getGameName();
  1668. const char* enginePath = GlobalRadiant().getEnginePath();
  1669. const char* toolsPath = GlobalRadiant().getGameToolsPath();
  1670. bool isMod = !string_equal(basegame, gamename);
  1671. if(!isMod || !shaderlist_findOrInstall(enginePath, toolsPath, path.c_str(), gamename))
  1672. {
  1673. gamename = basegame;
  1674. shaderlist_findOrInstall(enginePath, toolsPath, path.c_str(), gamename);
  1675. }
  1676. StringOutputStream absShaderList(256);
  1677. absShaderList << enginePath << gamename << '/' << path.c_str() << "shaderlist.txt";
  1678. {
  1679. globalOutputStream() << "Parsing shader files from " << absShaderList.c_str() << "\n";
  1680. TextFileInputStream shaderlistFile(absShaderList.c_str());
  1681. if(shaderlistFile.failed())
  1682. {
  1683. globalErrorStream() << "Couldn't find '" << absShaderList.c_str() << "'\n";
  1684. }
  1685. else
  1686. {
  1687. BuildShaderList(shaderlistFile);
  1688. DumpUnreferencedShaders();
  1689. }
  1690. }
  1691. }
  1692. else
  1693. {
  1694. GlobalFileSystem().forEachFile(path.c_str(), g_shadersExtension, AddShaderFileCaller(), 0);
  1695. }
  1696. GSList *lst = l_shaderfiles;
  1697. StringOutputStream shadername(256);
  1698. while(lst)
  1699. {
  1700. shadername << path.c_str() << reinterpret_cast<const char*>(lst->data);
  1701. LoadShaderFile(shadername.c_str());
  1702. shadername.clear();
  1703. lst = lst->next;
  1704. }
  1705. }
  1706. }
  1707. void Shaders_Free()
  1708. {
  1709. FreeShaders();
  1710. FreeShaderList();
  1711. g_shaderFilenames.clear();
  1712. }
  1713. ModuleObservers g_observers;
  1714. std::size_t g_shaders_unrealised = 1; // wait until filesystem and is realised before loading anything
  1715. bool Shaders_realised()
  1716. {
  1717. return g_shaders_unrealised == 0;
  1718. }
  1719. void Shaders_Realise()
  1720. {
  1721. if(--g_shaders_unrealised == 0)
  1722. {
  1723. Shaders_Load();
  1724. g_observers.realise();
  1725. }
  1726. }
  1727. void Shaders_Unrealise()
  1728. {
  1729. if(++g_shaders_unrealised == 1)
  1730. {
  1731. g_observers.unrealise();
  1732. Shaders_Free();
  1733. }
  1734. }
  1735. void Shaders_Refresh()
  1736. {
  1737. Shaders_Unrealise();
  1738. Shaders_Realise();
  1739. }
  1740. class Quake3ShaderSystem : public ShaderSystem, public ModuleObserver
  1741. {
  1742. public:
  1743. void realise()
  1744. {
  1745. Shaders_Realise();
  1746. }
  1747. void unrealise()
  1748. {
  1749. Shaders_Unrealise();
  1750. }
  1751. void refresh()
  1752. {
  1753. Shaders_Refresh();
  1754. }
  1755. IShader* getShaderForName(const char* name)
  1756. {
  1757. return Shader_ForName(name);
  1758. }
  1759. void foreachShaderName(const ShaderNameCallback& callback)
  1760. {
  1761. for(ShaderDefinitionMap::const_iterator i = g_shaderDefinitions.begin(); i != g_shaderDefinitions.end(); ++i)
  1762. {
  1763. callback((*i).first.c_str());
  1764. }
  1765. }
  1766. void beginActiveShadersIterator()
  1767. {
  1768. ActiveShaders_IteratorBegin();
  1769. }
  1770. bool endActiveShadersIterator()
  1771. {
  1772. return ActiveShaders_IteratorAtEnd();
  1773. }
  1774. IShader* dereferenceActiveShadersIterator()
  1775. {
  1776. return ActiveShaders_IteratorCurrent();
  1777. }
  1778. void incrementActiveShadersIterator()
  1779. {
  1780. ActiveShaders_IteratorIncrement();
  1781. }
  1782. void setActiveShadersChangedNotify(const Callback& notify)
  1783. {
  1784. g_ActiveShadersChangedNotify = notify;
  1785. }
  1786. void attach(ModuleObserver& observer)
  1787. {
  1788. g_observers.attach(observer);
  1789. }
  1790. void detach(ModuleObserver& observer)
  1791. {
  1792. g_observers.detach(observer);
  1793. }
  1794. void setLightingEnabled(bool enabled)
  1795. {
  1796. if(CShader::m_lightingEnabled != enabled)
  1797. {
  1798. for(shaders_t::const_iterator i = g_ActiveShaders.begin(); i != g_ActiveShaders.end(); ++i)
  1799. {
  1800. (*i).second->unrealiseLighting();
  1801. }
  1802. CShader::m_lightingEnabled = enabled;
  1803. for(shaders_t::const_iterator i = g_ActiveShaders.begin(); i != g_ActiveShaders.end(); ++i)
  1804. {
  1805. (*i).second->realiseLighting();
  1806. }
  1807. }
  1808. }
  1809. const char* getTexturePrefix() const
  1810. {
  1811. return g_texturePrefix;
  1812. }
  1813. };
  1814. Quake3ShaderSystem g_Quake3ShaderSystem;
  1815. ShaderSystem& GetShaderSystem()
  1816. {
  1817. return g_Quake3ShaderSystem;
  1818. }
  1819. void Shaders_Construct()
  1820. {
  1821. GlobalFileSystem().attach(g_Quake3ShaderSystem);
  1822. }
  1823. void Shaders_Destroy()
  1824. {
  1825. GlobalFileSystem().detach(g_Quake3ShaderSystem);
  1826. if(Shaders_realised())
  1827. {
  1828. Shaders_Free();
  1829. }
  1830. }