]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - plugins/shaders/shaders.cpp
fixed blended-decal rendering in textured mode
[xonotic/netradiant.git] / plugins / shaders / shaders.cpp
index 3bfa7296305f14eed5c9d034cb23b294d7c3e659..ba9b578cfc7adce9b6497c6f7fcb649e96b6e2f1 100644 (file)
@@ -51,7 +51,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <glib/gslist.h>
 
 #include "debugging/debugging.h"
-#include "string/string.h"
+#include "string/pooledstring.h"
 #include "math/vector.h"
 #include "generic/callback.h"
 #include "generic/referencecounted.h"
@@ -225,21 +225,29 @@ Image* loadSpecial(void* environment, const char* name)
   return GlobalTexturesCache().loadImage(name);
 }
 
-
+class ShaderPoolContext
+{
+};
+typedef Static<StringPool, ShaderPoolContext> ShaderPool;
+typedef PooledString<ShaderPool> ShaderString;
+typedef ShaderString ShaderVariable;
+typedef ShaderString ShaderValue;
+typedef CopiedString TextureExpression;
 
 // clean a texture name to the qtexture_t name format we use internally
 // NOTE: case sensitivity: the engine is case sensitive. we store the shader name with case information and save with case
 // information as well. but we assume there won't be any case conflict and so when doing lookups based on shader name,
 // we compare as case insensitive. That is Radiant is case insensitive, but knows that the engine is case sensitive.
 //++timo FIXME: we need to put code somewhere to detect when two shaders that are case insensitive equal are present
-void parseTextureName(CopiedString& name, const char* token)
+template<typename StringType>
+void parseTextureName(StringType& name, const char* token)
 {
   StringOutputStream cleaned(256);
   cleaned << PathCleaned(token);
-  name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
+  name = CopiedString(StringRange(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str()))).c_str(); // remove extension
 }
 
-bool Tokeniser_parseTextureName(Tokeniser& tokeniser, CopiedString& name)
+bool Tokeniser_parseTextureName(Tokeniser& tokeniser, TextureExpression& name)
 {
   const char* token = tokeniser.getToken();
   if(token == 0)
@@ -251,13 +259,6 @@ bool Tokeniser_parseTextureName(Tokeniser& tokeniser, CopiedString& name)
   return true;
 }
 
-void parseShaderName(CopiedString& name, const char* token)
-{
-  StringOutputStream cleaned(256);
-  cleaned << PathCleaned(token);
-  name = cleaned.c_str();
-}
-
 bool Tokeniser_parseShaderName(Tokeniser& tokeniser, CopiedString& name)
 {
   const char* token = tokeniser.getToken();
@@ -266,11 +267,11 @@ bool Tokeniser_parseShaderName(Tokeniser& tokeniser, CopiedString& name)
     Tokeniser_unexpectedError(tokeniser, token, "#shader-name");
     return false;
   }
-  parseShaderName(name, token);
+  parseTextureName(name, token);
   return true;
 }
 
-bool Tokeniser_parseString(Tokeniser& tokeniser, CopiedString& string)
+bool Tokeniser_parseString(Tokeniser& tokeniser, ShaderString& string)
 {
   const char* token = tokeniser.getToken();
   if(token == 0)
@@ -284,12 +285,10 @@ bool Tokeniser_parseString(Tokeniser& tokeniser, CopiedString& string)
 
 
 
-typedef std::list<CopiedString> ShaderParameters;
-typedef std::list<CopiedString> ShaderArguments;
+typedef std::list<ShaderVariable> ShaderParameters;
+typedef std::list<ShaderVariable> ShaderArguments;
 
-typedef CopiedString TextureExpression;
-typedef CopiedString ShaderValue;
-typedef std::pair<CopiedString, CopiedString> BlendFuncExpression;
+typedef std::pair<ShaderVariable, ShaderVariable> BlendFuncExpression;
 
 class ShaderTemplate
 {
@@ -406,7 +405,7 @@ public:
 };
 
 
-bool Doom3Shader_parseHeightmap(Tokeniser& tokeniser, CopiedString& bump, CopiedString& heightmapScale)
+bool Doom3Shader_parseHeightmap(Tokeniser& tokeniser, TextureExpression& bump, ShaderValue& heightmapScale)
 {
   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
   RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, bump));
@@ -416,20 +415,20 @@ bool Doom3Shader_parseHeightmap(Tokeniser& tokeniser, CopiedString& bump, Copied
   return true;
 }
 
-bool Doom3Shader_parseAddnormals(Tokeniser& tokeniser, CopiedString& bump)
+bool Doom3Shader_parseAddnormals(Tokeniser& tokeniser, TextureExpression& bump)
 {
   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
   RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, bump));
   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ","));
   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "heightmap"));
-  CopiedString heightmapName;
-  CopiedString heightmapScale;
+  TextureExpression heightmapName;
+  ShaderValue heightmapScale;
   RETURN_FALSE_IF_FAIL(Doom3Shader_parseHeightmap(tokeniser, heightmapName, heightmapScale));
   RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
   return true;
 }
 
-bool Doom3Shader_parseBumpmap(Tokeniser& tokeniser, CopiedString& bump, CopiedString& heightmapScale)
+bool Doom3Shader_parseBumpmap(Tokeniser& tokeniser, TextureExpression& bump, ShaderValue& heightmapScale)
 {
   const char* token = tokeniser.getToken();
   if(token == 0)
@@ -465,7 +464,7 @@ class LayerTemplate
 {
 public:
   LayerTypeId m_type;
-  CopiedString m_texture;
+  TextureExpression m_texture;
   BlendFuncExpression m_blendFunc;
   bool m_clampToBorder;
   ShaderValue m_alphaTest;
@@ -741,9 +740,9 @@ bool ShaderTemplate::parseDoom3(Tokeniser& tokeniser)
         if(string_equal_nocase(lightFalloffImage, "makeintensity"))
         {
           RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, "("));
-          CopiedString name;
+          TextureExpression name;
           RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, name));
-          m_lightFalloffImage = name.c_str();
+          m_lightFalloffImage = name;
           RETURN_FALSE_IF_FAIL(Tokeniser_parseToken(tokeniser, ")"));
         }
         else
@@ -797,7 +796,7 @@ ShaderDefinitionMap g_shaderDefinitions;
 bool parseTemplateInstance(Tokeniser& tokeniser, const char* filename)
 {
   CopiedString name;
-  RETURN_FALSE_IF_FAIL(Tokeniser_parseTextureName(tokeniser, name));
+  RETURN_FALSE_IF_FAIL(Tokeniser_parseShaderName(tokeniser, name));
   const char* templateName = tokeniser.getToken();
   ShaderTemplate* shaderTemplate = findTemplate(templateName);
   if(shaderTemplate == 0)
@@ -1094,39 +1093,6 @@ public:
     }
 
     realiseLighting();
-
-    if(m_layers.size() == 1)
-    {
-      const BlendFuncExpression& blendFunc = m_template.m_layers.front().blendFunc();
-      if(!string_empty(blendFunc.second.c_str()))
-      {
-        m_blendFunc = BlendFunc(
-          evaluateBlendFactor(blendFunc.first.c_str(), m_template.m_params, m_args),
-          evaluateBlendFactor(blendFunc.second.c_str(), m_template.m_params, m_args)
-        );
-      }
-      else
-      {
-        const char* blend = evaluateShaderValue(blendFunc.first.c_str(), m_template.m_params, m_args);
-
-        if(string_equal_nocase(blend, "add"))
-        {
-          m_blendFunc = BlendFunc(BLEND_ONE, BLEND_ONE);
-        }
-        else if(string_equal_nocase(blend, "filter"))
-        {
-          m_blendFunc = BlendFunc(BLEND_DST_COLOUR, BLEND_ZERO);
-        }
-        else if(string_equal_nocase(blend, "blend"))
-        {
-          m_blendFunc = BlendFunc(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
-        }
-        else
-        {
-          globalErrorStream() << "parsing blend value failed: " << makeQuoted(blend) << "\n";
-        }
-      }
-    }
   }
 
   void unrealise()
@@ -1160,6 +1126,39 @@ public:
       {
         m_layers.push_back(evaluateLayer(*i, m_template.m_params, m_args));
       }
+
+      if(m_layers.size() == 1)
+      {
+        const BlendFuncExpression& blendFunc = m_template.m_layers.front().blendFunc();
+        if(!string_empty(blendFunc.second.c_str()))
+        {
+          m_blendFunc = BlendFunc(
+            evaluateBlendFactor(blendFunc.first.c_str(), m_template.m_params, m_args),
+            evaluateBlendFactor(blendFunc.second.c_str(), m_template.m_params, m_args)
+          );
+        }
+        else
+        {
+          const char* blend = evaluateShaderValue(blendFunc.first.c_str(), m_template.m_params, m_args);
+
+          if(string_equal_nocase(blend, "add"))
+          {
+            m_blendFunc = BlendFunc(BLEND_ONE, BLEND_ONE);
+          }
+          else if(string_equal_nocase(blend, "filter"))
+          {
+            m_blendFunc = BlendFunc(BLEND_DST_COLOUR, BLEND_ZERO);
+          }
+          else if(string_equal_nocase(blend, "blend"))
+          {
+            m_blendFunc = BlendFunc(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
+          }
+          else
+          {
+            globalErrorStream() << "parsing blend value failed: " << makeQuoted(blend) << "\n";
+          }
+        }
+      }
     }
   }
 
@@ -1177,6 +1176,9 @@ public:
       {
         GlobalTexturesCache().release((*i).texture());
       }
+      m_layers.clear();
+
+      m_blendFunc = BlendFunc(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA);
     }
   }
 
@@ -1311,7 +1313,7 @@ void FreeShaders()
 bool ShaderTemplate::parseQuake3(Tokeniser& tokeniser)
 {
   // name of the qtexture_t we'll use to represent this shader (this one has the "textures\" before)
-  m_textureName = m_Name;
+  m_textureName = m_Name.c_str();
 
   tokeniser.nextLine();
 
@@ -1485,7 +1487,7 @@ class Layer
 {
 public:
   LayerTypeId m_type;
-  CopiedString m_texture;
+  TextureExpression m_texture;
   BlendFunc m_blendFunc;
   bool m_clampToBorder;
   float m_alphaTest;
@@ -1923,6 +1925,8 @@ void Shaders_Load()
       lst = lst->next;
     }
   }
+
+  //StringPool_analyse(ShaderPool::instance());
 }
 
 void Shaders_Free()