Browse Source

Allow a material to refer to any texture unit. Optimize setting batch's material renderstate by only looping through the used texture units. Note: the material editor in the editor does not support the extra units yet.

Lasse Öörni 11 years ago
parent
commit
8c8f18a961

+ 3 - 1
Source/Engine/Graphics/Batch.cpp

@@ -557,7 +557,9 @@ void Batch::Prepare(View* view, bool setModelTransform) const
         }
         
         const SharedPtr<Texture>* textures = material_->GetTextures();
-        for (unsigned i = 0; i < MAX_MATERIAL_TEXTURE_UNITS; ++i)
+        unsigned numTextures = material_->GetNumUsedTextureUnits();
+
+        for (unsigned i = 0; i < numTextures; ++i)
         {
             TextureUnit unit = (TextureUnit)i;
             if (textures[i] && graphics->HasTextureUnit(unit))

+ 2 - 1
Source/Engine/Graphics/GraphicsDefs.h

@@ -245,7 +245,8 @@ enum TextureUnit
     TU_LIGHTBUFFER = 11,
     TU_VOLUMEMAP = 12,
     TU_ZONE = 13,
-    MAX_TEXTURE_UNITS = 14
+    MAX_NAMED_TEXTURE_UNITS = 14,
+    MAX_TEXTURE_UNITS = 16
 };
 
 /// Billboard camera facing modes.

+ 23 - 9
Source/Engine/Graphics/Material.cpp

@@ -32,6 +32,7 @@
 #include "ResourceCache.h"
 #include "Scene.h"
 #include "SceneEvents.h"
+#include "StringUtils.h"
 #include "Technique.h"
 #include "Texture2D.h"
 #include "TextureCube.h"
@@ -92,7 +93,7 @@ TextureUnit ParseTextureUnitName(String name)
             unit = TU_ENVIRONMENT;
         // Finally check for specifying the texture unit directly as a number
         else if (name.Length() < 3)
-            unit = (TextureUnit)Clamp(ToInt(name), 0, MAX_TEXTURE_UNITS);
+            unit = (TextureUnit)Clamp(ToInt(name), 0, MAX_TEXTURE_UNITS - 1);
     }
 
     if (unit == MAX_TEXTURE_UNITS)
@@ -152,6 +153,7 @@ void ShaderParameterAnimationInfo::ApplyValue(const Variant& newValue)
 Material::Material(Context* context) :
     Resource(context),
     auxViewFrameNumber_(0),
+    numUsedTextureUnits_(0),
     occlusion_(true),
     specular_(false),
     subscribed_(false)
@@ -284,7 +286,7 @@ bool Material::Load(const XMLElement& source)
         TextureUnit unit = TU_DIFFUSE;
         if (textureElem.HasAttribute("unit"))
             unit = ParseTextureUnitName(textureElem.GetAttribute("unit"));
-        if (unit < MAX_MATERIAL_TEXTURE_UNITS)
+        if (unit < MAX_TEXTURE_UNITS)
         {
             String name = textureElem.GetAttribute("name");
             // Detect cube maps by file extension: they are defined by an XML file
@@ -372,13 +374,13 @@ bool Material::Save(XMLElement& dest) const
     }
 
     // Write texture units
-    for (unsigned j = 0; j < MAX_MATERIAL_TEXTURE_UNITS; ++j)
+    for (unsigned j = 0; j < MAX_TEXTURE_UNITS; ++j)
     {
         Texture* texture = GetTexture((TextureUnit)j);
         if (texture)
         {
             XMLElement textureElem = dest.CreateChild("texture");
-            textureElem.SetString("unit", textureUnitNames[j]);
+            textureElem.SetString("unit", j < MAX_NAMED_TEXTURE_UNITS ? textureUnitNames[j] : String(j).CString());
             textureElem.SetString("name", texture->GetName());
         }
     }
@@ -513,8 +515,19 @@ void Material::SetShaderParameterAnimationSpeed(const String& name, float speed)
 
 void Material::SetTexture(TextureUnit unit, Texture* texture)
 {
-    if (unit < MAX_MATERIAL_TEXTURE_UNITS)
+    if (unit < MAX_TEXTURE_UNITS)
+    {
         textures_[unit] = texture;
+
+        // Update the number of used texture units
+        if (texture && (unsigned)unit >= numUsedTextureUnits_)
+            numUsedTextureUnits_ = unit + 1;
+        else if (!texture)
+        {
+            if (unit == numUsedTextureUnits_ - 1)
+                --numUsedTextureUnits_;
+        }
+    }
 }
 
 void Material::SetUVTransform(const Vector2& offset, float rotation, const Vector2& repeat)
@@ -603,12 +616,13 @@ SharedPtr<Material> Material::Clone(const String& cloneName) const
     ret->SetName(cloneName);
     ret->techniques_ = techniques_;
     ret->shaderParameters_ = shaderParameters_;
-    for (unsigned i = 0; i < MAX_MATERIAL_TEXTURE_UNITS; ++i)
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
         ret->textures_[i] = textures_[i];
     ret->occlusion_ = occlusion_;
     ret->specular_ = specular_;
     ret->cullMode_ = cullMode_;
     ret->shadowCullMode_ = shadowCullMode_;
+    ret->numUsedTextureUnits_ = numUsedTextureUnits_;
     ret->RefreshMemoryUse();
 
     return ret;
@@ -642,7 +656,7 @@ Pass* Material::GetPass(unsigned index, StringHash passType) const
 
 Texture* Material::GetTexture(TextureUnit unit) const
 {
-    return unit < MAX_MATERIAL_TEXTURE_UNITS ? textures_[unit] : (Texture*)0;
+    return unit < MAX_TEXTURE_UNITS ? textures_[unit] : (Texture*)0;
 }
 
 const Variant& Material::GetShaderParameter(const String& name) const
@@ -713,7 +727,7 @@ void Material::ResetToDefaults()
     SetNumTechniques(1);
     SetTechnique(0, GetSubsystem<ResourceCache>()->GetResource<Technique>("Techniques/NoTexture.xml"));
 
-    for (unsigned i = 0; i < MAX_MATERIAL_TEXTURE_UNITS; ++i)
+    for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
         textures_[i] = 0;
 
     shaderParameters_.Clear();
@@ -737,7 +751,7 @@ void Material::RefreshMemoryUse()
     unsigned memoryUse = sizeof(Material);
 
     memoryUse += techniques_.Size() * sizeof(TechniqueEntry);
-    memoryUse += MAX_MATERIAL_TEXTURE_UNITS * sizeof(SharedPtr<Texture>);
+    memoryUse += MAX_TEXTURE_UNITS * sizeof(SharedPtr<Texture>);
     memoryUse += shaderParameters_.Size() * sizeof(MaterialShaderParameter);
 
     SetMemoryUse(memoryUse);

+ 5 - 1
Source/Engine/Graphics/Material.h

@@ -189,6 +189,8 @@ public:
     bool GetSpecular() const { return specular_; }
     /// Return the scene associated with the material for shader parameter animation updates.
     Scene* GetScene() const;
+    /// Return the last non-null texture unit + 1. Used as an optimization when applying the material to render state.
+    unsigned GetNumUsedTextureUnits() const { return numUsedTextureUnits_; }
 
     /// Return name for texture unit.
     static String GetTextureUnitName(TextureUnit unit);
@@ -212,7 +214,7 @@ private:
     /// Techniques.
     Vector<TechniqueEntry> techniques_;
     /// Textures.
-    SharedPtr<Texture> textures_[MAX_MATERIAL_TEXTURE_UNITS];
+    SharedPtr<Texture> textures_[MAX_TEXTURE_UNITS];
     /// %Shader parameters.
     HashMap<StringHash, MaterialShaderParameter> shaderParameters_;
     /// %Shader parameters animation infos.
@@ -225,6 +227,8 @@ private:
     BiasParameters depthBias_;
     /// Last auxiliary view rendered frame number.
     unsigned auxViewFrameNumber_;
+    /// Number of maximum non-null texture unit + 1.
+    unsigned numUsedTextureUnits_;
     /// Render occlusion flag.
     bool occlusion_;
     /// Specular lighting flag.

+ 3 - 2
Source/Engine/Graphics/View.cpp

@@ -2637,8 +2637,9 @@ Technique* View::GetTechnique(Drawable* drawable, Material* material)
 void View::CheckMaterialForAuxView(Material* material)
 {
     const SharedPtr<Texture>* textures = material->GetTextures();
-    
-    for (unsigned i = 0; i < MAX_MATERIAL_TEXTURE_UNITS; ++i)
+    unsigned numTextures = material->GetNumUsedTextureUnits();
+
+    for (unsigned i = 0; i < numTextures; ++i)
     {
         Texture* texture = textures[i];
         if (texture && texture->GetUsage() == TEXTURE_RENDERTARGET)

+ 2 - 1
Source/Engine/LuaScript/pkgs/Graphics/GraphicsDefs.pkg

@@ -187,7 +187,8 @@ enum TextureUnit
     TU_LIGHTBUFFER = 11,
     TU_VOLUMEMAP = 12,
     TU_ZONE = 13,
-    MAX_TEXTURE_UNITS = 14
+    MAX_NAMED_TEXTURE_UNITS = 14,
+    MAX_TEXTURE_UNITS = 16
 };
 
 enum FaceCameraMode

+ 3 - 1
Source/Engine/LuaScript/pkgs/Graphics/Material.pkg

@@ -46,13 +46,15 @@ class Material : public Resource
     CullMode GetShadowCullMode() const;
     const BiasParameters& GetDepthBias() const;
     unsigned GetAuxViewFrameNumber() const;
+    unsigned GetNumUsedTextureUnits() const;
     bool GetOcclusion() const;
     bool GetSpecular() const;
     Scene* GetScene() const;
-    
+
     tolua_readonly tolua_property__get_set CullMode cullMode;
     tolua_readonly tolua_property__get_set CullMode shadowCullMode;
     tolua_readonly tolua_property__get_set unsigned auxViewFrameNumber;
+    tolua_readonly tolua_property__get_set unsigned numUsedTextureUnits;
     tolua_readonly tolua_property__get_set bool occlusion;
     tolua_readonly tolua_property__get_set bool specular;
     tolua_property__get_set Scene* scene;

+ 2 - 0
Source/Engine/Script/GraphicsAPI.cpp

@@ -294,6 +294,7 @@ static void RegisterRenderPath(asIScriptEngine* engine)
     engine->RegisterEnumValue("TextureUnit", "TU_VOLUMEMAP", TU_VOLUMEMAP);
     engine->RegisterEnumValue("TextureUnit", "TU_ZONE", TU_ZONE);
     engine->RegisterEnumValue("TextureUnit", "MAX_MATERIAL_TEXTURE_UNITS", MAX_MATERIAL_TEXTURE_UNITS);
+    engine->RegisterEnumValue("TextureUnit", "MAX_NAMED_TEXTURE_UNITS", MAX_NAMED_TEXTURE_UNITS);
     engine->RegisterEnumValue("TextureUnit", "MAX_TEXTURE_UNITS", MAX_TEXTURE_UNITS);
     
     engine->RegisterObjectType("RenderTargetInfo", sizeof(RenderTargetInfo), asOBJ_VALUE | asOBJ_APP_CLASS_C);
@@ -684,6 +685,7 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Material", "CullMode get_shadowCullMode() const", asMETHOD(Material, GetShadowCullMode), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_depthBias(const BiasParameters&in)", asMETHOD(Material, SetDepthBias), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "const BiasParameters& get_depthBias() const", asMETHOD(Material, GetDepthBias), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Material", "uint get_numUsedTextureUnits() const", asMETHOD(Material, GetNumUsedTextureUnits), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "void set_scene(Scene@+)", asMETHOD(Material, SetScene), asCALL_THISCALL);
     engine->RegisterObjectMethod("Material", "Scene@+ get_scene() const", asMETHOD(Material, GetScene), asCALL_THISCALL);