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