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