]> icculus.org git repositories - divverent/netradiant.git/blob - plugins/shaders/shaders.cpp
NOW I do it right: #woxblox#
[divverent/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
1098   void unrealise()
1099   {
1100     GlobalTexturesCache().release(m_pTexture);
1101
1102     if(m_notfound != 0)
1103     {
1104       GlobalTexturesCache().release(m_notfound);
1105     }
1106
1107     unrealiseLighting();
1108   }
1109
1110   void realiseLighting()
1111   {
1112     if(m_lightingEnabled)
1113     {
1114       LoadImageCallback loader = GlobalTexturesCache().defaultLoader();
1115       if(!string_empty(m_template.m_heightmapScale.c_str()))
1116       {
1117         m_heightmapScale = evaluateFloat(m_template.m_heightmapScale, m_template.m_params, m_args);
1118         loader = LoadImageCallback(&m_heightmapScale, loadHeightmap);
1119       }
1120       m_pDiffuse = evaluateTexture(m_template.m_diffuse, m_template.m_params, m_args);
1121       m_pBump = evaluateTexture(m_template.m_bump, m_template.m_params, m_args, loader);
1122       m_pSpecular = evaluateTexture(m_template.m_specular, m_template.m_params, m_args);
1123       m_pLightFalloffImage = evaluateTexture(m_template.m_lightFalloffImage, m_template.m_params, m_args);
1124
1125       for(ShaderTemplate::MapLayers::const_iterator i = m_template.m_layers.begin(); i != m_template.m_layers.end(); ++i)
1126       {
1127         m_layers.push_back(evaluateLayer(*i, m_template.m_params, m_args));
1128       }
1129
1130       if(m_layers.size() == 1)
1131       {
1132         const BlendFuncExpression& blendFunc = m_template.m_layers.front().blendFunc();
1133         if(!string_empty(blendFunc.second.c_str()))
1134         {
1135           m_blendFunc = BlendFunc(
1136             evaluateBlendFactor(blendFunc.first.c_str(), m_template.m_params, m_args),
1137             evaluateBlendFactor(blendFunc.second.c_str(), m_template.m_params, m_args)
1138           );
1139         }
1140         else
1141         {
1142           const char* blend = evaluateShaderValue(blendFunc.first.c_str(), m_template.m_params, m_args);
1143
1144           if(string_equal_nocase(blend, "add"))
1145           {
1146             m_blendFunc = BlendFunc(BLEND_ONE, BLEND_ONE);
1147           }
1148           else if(string_equal_nocase(blend, "filter"))
1149           {
1150             m_blendFunc = BlendFunc(BLEND_DST_COLOUR, BLEND_ZERO);
1151           }
1152           else if(string_equal_nocase(blend, "blend"))
1153           {
1154             m_blendFunc = BlendFunc(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
1155           }
1156           else
1157           {
1158             globalErrorStream() << "parsing blend value failed: " << makeQuoted(blend) << "\n";
1159           }
1160         }
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       m_blendFunc = BlendFunc(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
1182     }
1183   }
1184
1185   // set shader name
1186   void setName(const char* name)
1187   {
1188     m_Name = name;
1189   }
1190
1191   class MapLayer : public ShaderLayer
1192   {
1193     qtexture_t* m_texture;
1194     BlendFunc m_blendFunc;
1195     bool m_clampToBorder;
1196     float m_alphaTest;
1197   public:
1198     MapLayer(qtexture_t* texture, BlendFunc blendFunc, bool clampToBorder, float alphaTest) :
1199       m_texture(texture),
1200       m_blendFunc(blendFunc),
1201       m_clampToBorder(false),
1202       m_alphaTest(alphaTest)
1203     {
1204     }
1205     qtexture_t* texture() const
1206     {
1207       return m_texture;
1208     }
1209     BlendFunc blendFunc() const
1210     {
1211       return m_blendFunc;
1212     }
1213     bool clampToBorder() const
1214     {
1215       return m_clampToBorder;
1216     }
1217     float alphaTest() const
1218     {
1219       return m_alphaTest;
1220     }
1221   };
1222
1223   static MapLayer evaluateLayer(const ShaderTemplate::MapLayerTemplate& layerTemplate, const ShaderParameters& params, const ShaderArguments& args)
1224   {
1225     return MapLayer(
1226       evaluateTexture(layerTemplate.texture(), params, args),
1227       evaluateBlendFunc(layerTemplate.blendFunc(), params, args),
1228       layerTemplate.clampToBorder(),
1229       evaluateFloat(layerTemplate.alphaTest(), params, args)
1230     );
1231   }
1232
1233   typedef std::vector<MapLayer> MapLayers;
1234   MapLayers m_layers;
1235
1236   const ShaderLayer* firstLayer() const
1237   {
1238     if(m_layers.empty())
1239     {
1240       return 0;
1241     }
1242     return &m_layers.front();
1243   }
1244   void forEachLayer(const ShaderLayerCallback& callback) const
1245   {
1246     for(MapLayers::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i)
1247     {
1248       callback(*i);
1249     }
1250   }
1251
1252   qtexture_t* lightFalloffImage() const
1253   {
1254     if(!string_empty(m_template.m_lightFalloffImage.c_str()))
1255     {
1256       return m_pLightFalloffImage;
1257     }
1258     return 0;
1259   }
1260 };
1261
1262 bool CShader::m_lightingEnabled = false;
1263
1264 typedef SmartPointer<CShader> ShaderPointer;
1265 typedef std::map<CopiedString, ShaderPointer, shader_less_t> shaders_t;
1266
1267 shaders_t g_ActiveShaders;
1268
1269 static shaders_t::iterator g_ActiveShadersIterator;
1270
1271 void ActiveShaders_IteratorBegin()
1272 {
1273   g_ActiveShadersIterator = g_ActiveShaders.begin();
1274 }
1275
1276 bool ActiveShaders_IteratorAtEnd()
1277 {
1278   return g_ActiveShadersIterator == g_ActiveShaders.end();
1279 }
1280
1281 IShader *ActiveShaders_IteratorCurrent()
1282 {
1283   return static_cast<CShader*>(g_ActiveShadersIterator->second);
1284 }
1285
1286 void ActiveShaders_IteratorIncrement()
1287 {
1288   ++g_ActiveShadersIterator;
1289 }
1290
1291 void debug_check_shaders(shaders_t& shaders)
1292 {
1293   for(shaders_t::iterator i = shaders.begin(); i != shaders.end(); ++i)
1294   {
1295     ASSERT_MESSAGE(i->second->refcount() == 1, "orphan shader still referenced");
1296   }
1297 }
1298
1299 // will free all GL binded qtextures and shaders
1300 // NOTE: doesn't make much sense out of Radiant exit or called during a reload
1301 void FreeShaders()
1302 {
1303   // reload shaders
1304   // empty the actives shaders list
1305   debug_check_shaders(g_ActiveShaders);
1306   g_ActiveShaders.clear();
1307   g_shaders.clear();
1308   g_shaderTemplates.clear();
1309   g_shaderDefinitions.clear();
1310   g_ActiveShadersChangedNotify();
1311 }
1312
1313 bool ShaderTemplate::parseQuake3(Tokeniser& tokeniser)
1314 {
1315   // name of the qtexture_t we'll use to represent this shader (this one has the "textures\" before)
1316   m_textureName = m_Name.c_str();
1317
1318   tokeniser.nextLine();
1319
1320   // we need to read until we hit a balanced }
1321   int depth = 0;
1322   for(;;)
1323   {
1324     tokeniser.nextLine();
1325     const char* token = tokeniser.getToken();
1326
1327     if(token == 0)
1328       return false;
1329
1330     if(string_equal(token, "{"))
1331     {
1332       ++depth;
1333       continue;
1334     }
1335     else if(string_equal(token, "}"))
1336     {
1337       --depth;
1338       if(depth < 0) // underflow
1339       {
1340         return false;
1341       }
1342       if(depth == 0) // end of shader
1343       {
1344         break;
1345       }
1346
1347       continue;
1348     }
1349
1350     if(depth == 1)
1351     {
1352       if (string_equal_nocase(token, "qer_nocarve"))
1353       {
1354         m_nFlags |= QER_NOCARVE;
1355       }
1356       else if (string_equal_nocase(token, "qer_trans"))
1357       {
1358         RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, m_fTrans));
1359         m_nFlags |= QER_TRANS;
1360       }
1361       else if (string_equal_nocase(token, "qer_editorimage"))
1362       {
1363         RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, m_textureName));
1364       }
1365       else if (string_equal_nocase(token, "qer_alphafunc"))
1366       {
1367         const char* alphafunc = tokeniser.getToken();
1368       
1369         if(alphafunc == 0)
1370         {
1371           Tokeniser_unexpectedError(tokeniser, alphafunc, "#alphafunc");
1372           return false;
1373         }
1374
1375         if(string_equal_nocase(alphafunc, "equal"))
1376         {
1377           m_AlphaFunc = IShader::eEqual;
1378         }
1379         else if(string_equal_nocase(alphafunc, "greater"))
1380         {
1381           m_AlphaFunc = IShader::eGreater;
1382         }
1383         else if(string_equal_nocase(alphafunc, "less"))
1384         {
1385           m_AlphaFunc = IShader::eLess;
1386         }
1387         else if(string_equal_nocase(alphafunc, "gequal"))
1388         {
1389           m_AlphaFunc = IShader::eGEqual;
1390         }
1391         else if(string_equal_nocase(alphafunc, "lequal"))
1392         {
1393           m_AlphaFunc = IShader::eLEqual;
1394         }
1395         else
1396         {
1397           m_AlphaFunc = IShader::eAlways;
1398         }
1399
1400         m_nFlags |= QER_ALPHATEST;
1401
1402         RETURN_FALSE_IF_FAIL(Tokeniser_getFloat(tokeniser, m_AlphaRef));
1403       }
1404       else if (string_equal_nocase(token, "cull"))
1405       {
1406         const char* cull = tokeniser.getToken();
1407
1408         if(cull == 0)
1409         {
1410           Tokeniser_unexpectedError(tokeniser, cull, "#cull");
1411           return false;
1412         }
1413
1414         if(string_equal_nocase(cull, "none")
1415           || string_equal_nocase(cull, "twosided")
1416           || string_equal_nocase(cull, "disable"))
1417         {
1418           m_Cull = IShader::eCullNone;
1419         }
1420         else if(string_equal_nocase(cull, "back")
1421           || string_equal_nocase(cull, "backside")
1422           || string_equal_nocase(cull, "backsided"))
1423         {
1424           m_Cull = IShader::eCullBack;
1425         }
1426         else
1427         {
1428           m_Cull = IShader::eCullBack;
1429         }
1430
1431         m_nFlags |= QER_CULL;
1432       }
1433       else if (string_equal_nocase(token, "surfaceparm"))
1434       {
1435         const char* surfaceparm = tokeniser.getToken();
1436
1437         if(surfaceparm == 0)
1438         {
1439           Tokeniser_unexpectedError(tokeniser, surfaceparm, "#surfaceparm");
1440           return false;
1441         }
1442
1443         if (string_equal_nocase(surfaceparm, "fog"))
1444         {
1445           m_nFlags |= QER_FOG;
1446           if (m_fTrans == 1.0f)  // has not been explicitly set by qer_trans
1447           {
1448             m_fTrans = 0.35f;
1449           }
1450         }
1451         else if (string_equal_nocase(surfaceparm, "nodraw"))
1452         {
1453           m_nFlags |= QER_NODRAW;
1454         }
1455         else if (string_equal_nocase(surfaceparm, "nonsolid"))
1456         {
1457           m_nFlags |= QER_NONSOLID;
1458         }
1459         else if (string_equal_nocase(surfaceparm, "water"))
1460         {
1461           m_nFlags |= QER_WATER;
1462         }
1463         else if (string_equal_nocase(surfaceparm, "lava"))
1464         {
1465           m_nFlags |= QER_LAVA;
1466         }
1467         else if (string_equal_nocase(surfaceparm, "areaportal"))
1468         {
1469           m_nFlags |= QER_AREAPORTAL;
1470         }
1471         else if (string_equal_nocase(surfaceparm, "playerclip"))
1472         {
1473           m_nFlags |= QER_CLIP;
1474         }
1475         else if (string_equal_nocase(surfaceparm, "botclip"))
1476         {
1477           m_nFlags |= QER_BOTCLIP;
1478         }
1479       }
1480     }
1481   }
1482
1483   return true;
1484 }
1485
1486 class Layer
1487 {
1488 public:
1489   LayerTypeId m_type;
1490   TextureExpression m_texture;
1491   BlendFunc m_blendFunc;
1492   bool m_clampToBorder;
1493   float m_alphaTest;
1494   float m_heightmapScale;
1495
1496   Layer() : m_type(LAYER_NONE), m_blendFunc(BLEND_ONE, BLEND_ZERO), m_clampToBorder(false), m_alphaTest(-1), m_heightmapScale(0)
1497   {
1498   }
1499 };
1500
1501 std::list<CopiedString> g_shaderFilenames;
1502
1503 void ParseShaderFile(Tokeniser& tokeniser, const char* filename)
1504 {
1505   g_shaderFilenames.push_back(filename);
1506   filename = g_shaderFilenames.back().c_str();
1507   tokeniser.nextLine();
1508   for(;;)
1509   {
1510     const char* token = tokeniser.getToken();
1511
1512     if(token == 0)
1513     {
1514       break;
1515     }
1516
1517     if(string_equal(token, "table"))
1518     {
1519       if(tokeniser.getToken() == 0)
1520       {
1521         Tokeniser_unexpectedError(tokeniser, 0, "#table-name");
1522         return;
1523       }
1524       if(!Tokeniser_parseToken(tokeniser, "{"))
1525       {
1526         return;
1527       }
1528       for(;;)
1529       {
1530         const char* option = tokeniser.getToken();
1531         if(string_equal(option, "{"))
1532         {
1533           for(;;)
1534           {
1535             const char* value = tokeniser.getToken();
1536             if(string_equal(value, "}"))
1537             {
1538               break;
1539             }
1540           }
1541
1542           if(!Tokeniser_parseToken(tokeniser, "}"))
1543           {
1544             return;
1545           }
1546           break;
1547         }
1548       }
1549     }
1550     else
1551     {
1552       if(string_equal(token, "guide"))
1553       {
1554         parseTemplateInstance(tokeniser, filename);
1555       }
1556       else
1557       {
1558         if(!string_equal(token, "material")
1559           && !string_equal(token, "particle")
1560           && !string_equal(token, "skin"))
1561         {
1562           tokeniser.ungetToken();
1563         }
1564         // first token should be the path + name.. (from base)
1565         CopiedString name;
1566         if(!Tokeniser_parseShaderName(tokeniser, name))
1567         {
1568         }
1569         ShaderTemplatePointer shaderTemplate(new ShaderTemplate());
1570         shaderTemplate->setName(name.c_str());
1571
1572         g_shaders.insert(ShaderTemplateMap::value_type(shaderTemplate->getName(), shaderTemplate));
1573
1574         bool result = (g_shaderLanguage == SHADERLANGUAGE_QUAKE3)
1575           ? shaderTemplate->parseQuake3(tokeniser)
1576           : shaderTemplate->parseDoom3(tokeniser);
1577         if (result)
1578         {
1579           // do we already have this shader?
1580           if(!g_shaderDefinitions.insert(ShaderDefinitionMap::value_type(shaderTemplate->getName(), ShaderDefinition(shaderTemplate.get(), ShaderArguments(), filename))).second)
1581           {
1582   #ifdef _DEBUG
1583             globalOutputStream() << "WARNING: shader " << shaderTemplate->getName() << " is already in memory, definition in " << filename << " ignored.\n";
1584   #endif
1585           }
1586         }
1587         else
1588         {
1589           globalErrorStream() << "Error parsing shader " << shaderTemplate->getName() << "\n";
1590           return;
1591         }
1592       }
1593     }
1594   }
1595 }
1596
1597 void parseGuideFile(Tokeniser& tokeniser, const char* filename)
1598 {
1599   tokeniser.nextLine();
1600   for(;;)
1601   {
1602     const char* token = tokeniser.getToken();
1603
1604     if(token == 0)
1605     {
1606       break;
1607     }
1608
1609     if(string_equal(token, "guide"))
1610     {
1611       // first token should be the path + name.. (from base)
1612       ShaderTemplatePointer shaderTemplate(new ShaderTemplate);
1613       shaderTemplate->parseTemplate(tokeniser);
1614       if(!g_shaderTemplates.insert(ShaderTemplateMap::value_type(shaderTemplate->getName(), shaderTemplate)).second)
1615       {
1616         globalErrorStream() << "guide " << makeQuoted(shaderTemplate->getName()) << ": already defined, second definition ignored\n";
1617       }
1618     }
1619     else if(string_equal(token, "inlineGuide"))
1620     {
1621       // skip entire inlineGuide definition
1622       std::size_t depth = 0;
1623       for(;;)
1624       {
1625         tokeniser.nextLine();
1626         token = tokeniser.getToken();
1627         if(string_equal(token, "{"))
1628         {
1629           ++depth;
1630         }
1631         else if(string_equal(token, "}"))
1632         {
1633           if(--depth == 0)
1634           {
1635             break;
1636           }
1637         }
1638       }
1639     }
1640   }
1641 }
1642
1643 void LoadShaderFile(const char* filename)
1644 {
1645   ArchiveTextFile* file = GlobalFileSystem().openTextFile(filename);
1646
1647   if(file != 0)
1648   {
1649     globalOutputStream() << "Parsing shaderfile " << filename << "\n";
1650
1651     Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser(file->getInputStream());
1652
1653     ParseShaderFile(tokeniser, filename);
1654
1655     tokeniser.release();
1656     file->release();
1657   }
1658   else
1659   {
1660     globalOutputStream() << "Unable to read shaderfile " << filename << "\n";
1661   }
1662 }
1663
1664 typedef FreeCaller1<const char*, LoadShaderFile> LoadShaderFileCaller;
1665
1666
1667 void loadGuideFile(const char* filename)
1668 {
1669   StringOutputStream fullname(256);
1670   fullname << "guides/" << filename;
1671   ArchiveTextFile* file = GlobalFileSystem().openTextFile(fullname.c_str());
1672
1673   if(file != 0)
1674   {
1675     globalOutputStream() << "Parsing guide file " << fullname.c_str() << "\n";
1676
1677     Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser(file->getInputStream());
1678
1679     parseGuideFile(tokeniser, fullname.c_str());
1680
1681     tokeniser.release();
1682     file->release();
1683   }
1684   else
1685   {
1686     globalOutputStream() << "Unable to read guide file " << fullname.c_str() << "\n";
1687   }
1688 }
1689
1690 typedef FreeCaller1<const char*, loadGuideFile> LoadGuideFileCaller;
1691
1692
1693 CShader* Try_Shader_ForName(const char* name)
1694 {
1695   {
1696     shaders_t::iterator i = g_ActiveShaders.find(name);
1697     if(i != g_ActiveShaders.end())
1698     {
1699       return (*i).second;
1700     }
1701   }
1702   // active shader was not found
1703   
1704   // find matching shader definition
1705   ShaderDefinitionMap::iterator i = g_shaderDefinitions.find(name);
1706   if(i == g_shaderDefinitions.end())
1707   {
1708     // shader definition was not found
1709
1710     // create new shader definition from default shader template
1711     ShaderTemplatePointer shaderTemplate(new ShaderTemplate());
1712     shaderTemplate->CreateDefault(name);
1713     g_shaderTemplates.insert(ShaderTemplateMap::value_type(shaderTemplate->getName(), shaderTemplate));
1714
1715     i = g_shaderDefinitions.insert(ShaderDefinitionMap::value_type(name, ShaderDefinition(shaderTemplate.get(), ShaderArguments(), ""))).first;
1716   }
1717
1718   // create shader from existing definition
1719   ShaderPointer pShader(new CShader((*i).second));
1720   pShader->setName(name);
1721   g_ActiveShaders.insert(shaders_t::value_type(name, pShader));
1722   g_ActiveShadersChangedNotify();
1723   return pShader;
1724 }
1725
1726 IShader *Shader_ForName(const char *name)
1727 {
1728   ASSERT_NOTNULL(name);
1729
1730   IShader *pShader = Try_Shader_ForName(name);
1731   pShader->IncRef();
1732   return pShader;
1733 }
1734
1735
1736
1737
1738 // the list of scripts/*.shader files we need to work with
1739 // those are listed in shaderlist file
1740 GSList *l_shaderfiles = 0;
1741
1742 GSList* Shaders_getShaderFileList()
1743 {
1744   return l_shaderfiles;
1745 }
1746
1747 /*
1748 ==================
1749 DumpUnreferencedShaders
1750 usefull function: dumps the list of .shader files that are not referenced to the console
1751 ==================
1752 */
1753 void IfFound_dumpUnreferencedShader(bool& bFound, const char* filename)
1754 {
1755   bool listed = false;
1756
1757   for(GSList* sh = l_shaderfiles; sh != 0; sh = g_slist_next(sh))
1758   {
1759     if(!strcmp((char*)sh->data, filename))
1760     {
1761       listed = true;
1762       break;
1763     }
1764   }
1765
1766   if(!listed)
1767   {
1768     if(!bFound)
1769     {
1770       bFound = true;
1771       globalOutputStream() << "Following shader files are not referenced in any shaderlist.txt:\n";
1772     }
1773     globalOutputStream() << "\t" << filename << "\n";
1774   }
1775 }
1776 typedef ReferenceCaller1<bool, const char*, IfFound_dumpUnreferencedShader> IfFoundDumpUnreferencedShaderCaller;
1777
1778 void DumpUnreferencedShaders()
1779 {
1780   bool bFound = false;
1781   GlobalFileSystem().forEachFile(g_shadersDirectory, g_shadersExtension, IfFoundDumpUnreferencedShaderCaller(bFound));
1782 }
1783
1784 void ShaderList_addShaderFile(const char* dirstring)
1785 {
1786   bool found = false;
1787
1788   for(GSList* tmp = l_shaderfiles; tmp != 0; tmp = tmp->next)
1789   {
1790     if(string_equal_nocase(dirstring, (char*)tmp->data))
1791     {
1792       found = true;
1793       globalOutputStream() << "duplicate entry \"" << (char*)tmp->data << "\" in shaderlist.txt\n";
1794       break;
1795     }
1796   }
1797   
1798   if(!found)
1799   {
1800     l_shaderfiles = g_slist_append(l_shaderfiles, strdup(dirstring));
1801   }
1802 }
1803
1804 typedef FreeCaller1<const char*, ShaderList_addShaderFile> AddShaderFileCaller;
1805
1806
1807 /*
1808 ==================
1809 BuildShaderList
1810 build a CStringList of shader names
1811 ==================
1812 */
1813 void BuildShaderList(TextInputStream& shaderlist)
1814 {
1815   Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewSimpleTokeniser(shaderlist);
1816   tokeniser.nextLine();
1817   const char* token = tokeniser.getToken();
1818   StringOutputStream shaderFile(64);
1819   while(token != 0)
1820   {
1821     // each token should be a shader filename
1822     shaderFile << token << "." << g_shadersExtension;
1823     
1824     ShaderList_addShaderFile(shaderFile.c_str());
1825
1826     tokeniser.nextLine();
1827     token = tokeniser.getToken();
1828
1829     shaderFile.clear();
1830   }
1831   tokeniser.release();
1832 }
1833
1834 void FreeShaderList()
1835 {
1836   while(l_shaderfiles != 0)
1837   {
1838     free(l_shaderfiles->data);
1839     l_shaderfiles = g_slist_remove(l_shaderfiles, l_shaderfiles->data);
1840   }
1841 }
1842
1843 void ShaderList_addFromArchive(const char *archivename)
1844 {
1845   const char *shaderpath = GlobalRadiant().getGameDescriptionKeyValue("shaderpath");
1846   if (string_empty(shaderpath))
1847     return;
1848
1849   StringOutputStream shaderlist(256);
1850   shaderlist << DirectoryCleaned(shaderpath) << "shaderlist.txt";
1851
1852   Archive *archive = GlobalFileSystem().getArchive(archivename, false);
1853   if (archive)
1854   {
1855     ArchiveTextFile *file = archive->openTextFile(shaderlist.c_str());
1856     if (file)
1857     {
1858       globalOutputStream() << "Found shaderlist.txt in " << archivename << "\n";
1859       BuildShaderList(file->getInputStream());
1860       file->release();
1861     }
1862   }
1863 }
1864
1865 typedef FreeCaller1<const char *, ShaderList_addFromArchive> AddShaderListFromArchiveCaller;
1866
1867 #include "stream/filestream.h"
1868
1869 bool shaderlist_findOrInstall(const char* enginePath, const char* toolsPath, const char* shaderPath, const char* gamename)
1870 {
1871   StringOutputStream absShaderList(256);
1872   absShaderList << enginePath << gamename << '/' << shaderPath << "shaderlist.txt";
1873   if(file_exists(absShaderList.c_str()))
1874   {
1875     return true;
1876   }
1877   {
1878     StringOutputStream directory(256);
1879     directory << enginePath << gamename << '/' << shaderPath;
1880     if(!file_exists(directory.c_str()) && !Q_mkdir(directory.c_str()))
1881     {
1882       return false;
1883     }
1884   }
1885   {
1886     StringOutputStream defaultShaderList(256);
1887     defaultShaderList << toolsPath << gamename << '/' << "default_shaderlist.txt";
1888     if(file_exists(defaultShaderList.c_str()))
1889     {
1890       return file_copy(defaultShaderList.c_str(), absShaderList.c_str());
1891     }
1892   }
1893   return false;
1894 }
1895
1896 void Shaders_Load()
1897 {
1898   if(g_shaderLanguage == SHADERLANGUAGE_QUAKE4)
1899   {
1900     GlobalFileSystem().forEachFile("guides/", "guide", LoadGuideFileCaller(), 0);
1901   }
1902
1903   const char* shaderPath = GlobalRadiant().getGameDescriptionKeyValue("shaderpath");
1904   if(!string_empty(shaderPath))
1905   {
1906     StringOutputStream path(256);
1907     path << DirectoryCleaned(shaderPath);
1908
1909     if(g_useShaderList)
1910     {
1911       // preload shader files that have been listed in shaderlist.txt
1912       const char* basegame = GlobalRadiant().getRequiredGameDescriptionKeyValue("basegame");
1913       const char* gamename = GlobalRadiant().getGameName();
1914       const char* enginePath = GlobalRadiant().getEnginePath();
1915       const char* toolsPath = GlobalRadiant().getGameToolsPath();
1916
1917       bool isMod = !string_equal(basegame, gamename);
1918
1919       if(!isMod || !shaderlist_findOrInstall(enginePath, toolsPath, path.c_str(), gamename))
1920       {
1921         gamename = basegame;
1922         shaderlist_findOrInstall(enginePath, toolsPath, path.c_str(), gamename);
1923       }
1924
1925       GlobalFileSystem().forEachArchive(AddShaderListFromArchiveCaller(), false, true);
1926       DumpUnreferencedShaders();
1927     }
1928     else
1929     {
1930       GlobalFileSystem().forEachFile(path.c_str(), g_shadersExtension, AddShaderFileCaller(), 0);
1931     }
1932
1933     GSList *lst = l_shaderfiles;
1934     StringOutputStream shadername(256);
1935     while(lst)
1936     {
1937       shadername << path.c_str() << reinterpret_cast<const char*>(lst->data);
1938       LoadShaderFile(shadername.c_str());
1939       shadername.clear();
1940       lst = lst->next;
1941     }
1942   }
1943
1944   //StringPool_analyse(ShaderPool::instance());
1945 }
1946
1947 void Shaders_Free()
1948 {
1949   FreeShaders();
1950   FreeShaderList();
1951   g_shaderFilenames.clear();
1952 }
1953
1954 ModuleObservers g_observers;
1955
1956 std::size_t g_shaders_unrealised = 1; // wait until filesystem and is realised before loading anything
1957 bool Shaders_realised()
1958 {
1959   return g_shaders_unrealised == 0;
1960 }
1961 void Shaders_Realise()
1962 {
1963   if(--g_shaders_unrealised == 0)
1964   {
1965     Shaders_Load();
1966     g_observers.realise();
1967   }
1968 }
1969 void Shaders_Unrealise()
1970 {
1971   if(++g_shaders_unrealised == 1)
1972   {
1973     g_observers.unrealise();
1974     Shaders_Free();
1975   }
1976 }
1977
1978 void Shaders_Refresh() 
1979 {
1980   Shaders_Unrealise();
1981   Shaders_Realise();
1982 }
1983
1984 class Quake3ShaderSystem : public ShaderSystem, public ModuleObserver
1985 {
1986 public:
1987   void realise()
1988   {
1989     Shaders_Realise();
1990   }
1991   void unrealise()
1992   {
1993     Shaders_Unrealise();
1994   }
1995   void refresh()
1996   {
1997     Shaders_Refresh();
1998   }
1999
2000   IShader* getShaderForName(const char* name)
2001   {
2002     return Shader_ForName(name);
2003   }
2004
2005   void foreachShaderName(const ShaderNameCallback& callback)
2006   {
2007     for(ShaderDefinitionMap::const_iterator i = g_shaderDefinitions.begin(); i != g_shaderDefinitions.end(); ++i)
2008     {
2009       callback((*i).first.c_str());
2010     }
2011   }
2012
2013   void beginActiveShadersIterator()
2014   {
2015     ActiveShaders_IteratorBegin();
2016   }
2017   bool endActiveShadersIterator()
2018   {
2019     return ActiveShaders_IteratorAtEnd();
2020   }
2021   IShader* dereferenceActiveShadersIterator()
2022   {
2023     return ActiveShaders_IteratorCurrent();
2024   }
2025   void incrementActiveShadersIterator()
2026   {
2027     ActiveShaders_IteratorIncrement();
2028   }
2029   void setActiveShadersChangedNotify(const Callback& notify)
2030   {
2031     g_ActiveShadersChangedNotify = notify;
2032   }
2033
2034   void attach(ModuleObserver& observer)
2035   {
2036     g_observers.attach(observer);
2037   }
2038   void detach(ModuleObserver& observer)
2039   {
2040     g_observers.detach(observer);
2041   }
2042
2043   void setLightingEnabled(bool enabled)
2044   {
2045     if(CShader::m_lightingEnabled != enabled)
2046     {
2047       for(shaders_t::const_iterator i = g_ActiveShaders.begin(); i != g_ActiveShaders.end(); ++i)
2048       {
2049         (*i).second->unrealiseLighting();
2050       }
2051       CShader::m_lightingEnabled = enabled;
2052       for(shaders_t::const_iterator i = g_ActiveShaders.begin(); i != g_ActiveShaders.end(); ++i)
2053       {
2054         (*i).second->realiseLighting();
2055       }
2056     }
2057   }
2058
2059   const char* getTexturePrefix() const
2060   {
2061     return g_texturePrefix;
2062   }
2063 };
2064
2065 Quake3ShaderSystem g_Quake3ShaderSystem;
2066
2067 ShaderSystem& GetShaderSystem()
2068 {
2069   return g_Quake3ShaderSystem;
2070 }
2071
2072 void Shaders_Construct()
2073 {
2074   GlobalFileSystem().attach(g_Quake3ShaderSystem);
2075 }
2076 void Shaders_Destroy()
2077 {
2078   GlobalFileSystem().detach(g_Quake3ShaderSystem);
2079
2080   if(Shaders_realised())
2081   {
2082     Shaders_Free();
2083   }
2084 }