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