Browse Source

Fix Technique class to recalculate memory used based on numPasses.
Add and expose convenient methods to retrieve the Passes in the Technique based on the pass type StringHash.
Note the API breaking change. In AngelScript the Technique's "passes" property is now returning all passes without taking any index. Use the "GetPass(StringHash)" method to get a single pass instead.

Yao Wei Tjong 姚伟忠 11 years ago
parent
commit
2c5fb1db03

+ 18 - 0
Source/Engine/Container/HashTable.h

@@ -145,6 +145,24 @@ public:
         return 0;
     }
     
+    /// Return all the keys.
+    PODVector<unsigned> Keys() const
+    {
+        PODVector<unsigned> ret;
+
+        for (unsigned i = 0; i < U; ++i)
+        {
+            Node* ptr = ptrs_[i];
+            while (ptr)
+            {
+                ret.Push(ptr->hash_);
+                ptr = ptr->next_;
+            }
+        }
+
+        return ret;
+    }
+
     /// Return pointers to all values.
     PODVector<T*> Values() const
     {

+ 33 - 8
Source/Engine/Graphics/Technique.cpp

@@ -157,7 +157,8 @@ void Pass::MarkShadersLoaded(unsigned frameNumber)
 
 Technique::Technique(Context* context) :
     Resource(context),
-    isSM3_(false)
+    isSM3_(false),
+    numPasses_(0)
 {
     Graphics* graphics = GetSubsystem<Graphics>();
     sm3Support_ = graphics ? graphics->GetSM3Support() : true;
@@ -175,6 +176,8 @@ void Technique::RegisterObject(Context* context)
 bool Technique::BeginLoad(Deserializer& source)
 {
     passes_.Clear();
+
+    numPasses_ = 0;
     SetMemoryUse(sizeof(Technique));
     
     SharedPtr<XMLFile> xml(new XMLFile(context_));
@@ -198,8 +201,6 @@ bool Technique::BeginLoad(Deserializer& source)
     if (rootElem.HasAttribute("alphamask"))
         globalAlphaMask = rootElem.GetBool("alphamask");
     
-    unsigned numPasses = 0;
-    
     XMLElement passElem = rootElem.GetChild("pass");
     while (passElem)
     {
@@ -208,7 +209,6 @@ bool Technique::BeginLoad(Deserializer& source)
             StringHash nameHash(passElem.GetAttribute("name"));
             
             Pass* newPass = CreatePass(nameHash);
-            ++numPasses;
             
             if (passElem.HasAttribute("sm3"))
                 newPass->SetIsSM3(passElem.GetBool("sm3"));
@@ -271,8 +271,6 @@ bool Technique::BeginLoad(Deserializer& source)
         passElem = passElem.GetNext("pass");
     }
     
-    // Calculate memory use now
-    SetMemoryUse(sizeof(Technique) + numPasses * sizeof(Pass));
     return true;
 }
 
@@ -291,7 +289,6 @@ void Technique::ReleaseShaders()
 
 Pass* Technique::CreatePass(StringHash type)
 {
-    /// \todo Memory use is not tracked when creating passes programmatically due to HashTable not returning the element count
     Pass* oldPass = GetPass(type);
     if (oldPass)
         return oldPass;
@@ -299,12 +296,40 @@ Pass* Technique::CreatePass(StringHash type)
     SharedPtr<Pass> newPass(new Pass(type));
     passes_.Insert(type.Value(), newPass);
     
+    // Calculate memory use now
+    SetMemoryUse(sizeof(Technique) + ++numPasses_ * sizeof(Pass));
+
     return newPass;
 }
 
 void Technique::RemovePass(StringHash type)
 {
-    passes_.Erase(type.Value());
+    if (passes_.Erase(type.Value()))
+        SetMemoryUse(sizeof(Technique) + --numPasses_ * sizeof(Pass));
+}
+
+Vector<StringHash> Technique::GetPassTypes() const
+{
+    // Convert PODVector<unsigned> to Vector<StringHash>
+    PODVector<unsigned> vectorIn = passes_.Keys();
+    Vector<StringHash> vectorOut;
+    vectorOut.Reserve(vectorIn.Size());
+    for (unsigned i = 0; i < vectorIn.Size(); ++i)
+        vectorOut.Push(StringHash(vectorIn[i]));
+
+    return vectorOut;
+}
+
+PODVector<Pass*> Technique::GetPasses() const
+{
+    // Convert PODVector<SharedPtr<Pass>*> to PODVector<Pass*>
+    PODVector<SharedPtr<Pass>*> vectorIn = passes_.Values();
+    PODVector<Pass*> vectorOut;
+    vectorOut.Reserve(vectorIn.Size());
+    for (unsigned i = 0; i < vectorIn.Size(); ++i)
+        vectorOut.Push(vectorIn[i]->Get());
+
+    return vectorOut;
 }
 
 }

+ 9 - 0
Source/Engine/Graphics/Technique.h

@@ -180,6 +180,13 @@ public:
         return pass && (!pass->IsSM3() || sm3Support_) ? pass : 0;
     }
     
+    /// Return number of passes.
+    unsigned GetNumPasses() const { return numPasses_; }
+    /// Return all the pass types in the hash table. The returned collection is not guaranteed to be in the same order as the hash table insertion order.
+    Vector<StringHash> GetPassTypes() const;
+    /// Return all the passes in the hash table. The returned collection is not guaranteed to be in the same order as the hash table insertion order.
+    PODVector<Pass*> GetPasses() const;
+
 private:
     /// Require %Shader %Model 3 flag.
     bool isSM3_;
@@ -187,6 +194,8 @@ private:
     bool sm3Support_;
     /// Passes.
     HashTable<SharedPtr<Pass>, 16> passes_;
+    /// Number of passes.
+    unsigned numPasses_;
 };
 
 }

+ 24 - 0
Source/Engine/LuaScript/ToluaUtils.cpp

@@ -133,6 +133,18 @@ template<> int ToluaPushVector<String>(lua_State* L, void* data, const char* typ
     return 1;
 }
 
+template<> int ToluaPushVector<StringHash>(lua_State* L, void* data, const char* type)
+{
+    Vector<StringHash>& vector = *((Vector<StringHash>*)data);
+    lua_newtable(L);
+    for (unsigned i = 0; i < vector.Size(); ++i)
+    {
+        tolua_pushusertype(L, &vector[i], "StringHash");
+        lua_rawseti(L, -2, i + 1);
+    }
+    return 1;
+}
+
 template<> int ToluaIsPODVector<unsigned>(lua_State* L, int lo, const char* type, int def, tolua_Error* err)
 {
     if (lua_istable(L, lo))
@@ -375,6 +387,18 @@ template<> int ToluaPushPODVector<RayQueryResult>(lua_State* L, void* data, cons
     return tolua_pushurho3dpodvectorusertype(L, *((const PODVector<RayQueryResult>*)data), "RayQueryResult");
 }
 
+template<> int ToluaPushPODVector<Pass*>(lua_State* L, void* data, const char*)
+{
+    const PODVector<Pass*>& vector = *((const PODVector<Pass*>*)data);
+    lua_newtable(L);
+    for (unsigned i = 0; i < vector.Size(); ++i)
+    {
+        tolua_pushusertype(L, vector[i], "Pass");
+        lua_rawseti(L, -2, i + 1);
+    }
+    return 1;
+}
+
 void ToluaPushObject(lua_State*L, void* data, const char* type)
 {
     tolua_pushusertype(L, data, data ? static_cast<Object*>(data)->GetTypeName().CString() : type);

+ 5 - 0
Source/Engine/LuaScript/ToluaUtils.h

@@ -36,6 +36,7 @@ struct lua_State;
 namespace Urho3D
 {
 class Context;
+class Pass;
 class SoundSource;
 class UIElement;
 }
@@ -94,6 +95,8 @@ template<> void* ToluaToVector<String>(lua_State* L, int narg, void* def);
 template<typename T> int ToluaPushVector(lua_State*L, void* data, const char* type);
 /// Push Vector<String> to Lua as a table.
 template<> int ToluaPushVector<String>(lua_State* L, void* data, const char* type);
+/// Push Vector<StringHash> to Lua as a table.
+template<> int ToluaPushVector<StringHash>(lua_State* L, void* data, const char* type);
 
 /// Check is PODVector<T>.
 template<typename T> int ToluaIsPODVector(lua_State* L, int lo, const char* type, int def, tolua_Error* err);
@@ -139,6 +142,8 @@ template<> int ToluaPushPODVector<PhysicsRaycastResult>(lua_State* L, void* data
 template<> int ToluaPushPODVector<PhysicsRaycastResult2D>(lua_State* L, void* data, const char* type);
 /// Push PODVector<RayQueryResult> to Lua as a table.
 template<> int ToluaPushPODVector<RayQueryResult>(lua_State* L, void* data, const char* type);
+/// Push PODVector<Pass*> to Lua as a table.
+template<> int ToluaPushPODVector<Pass*>(lua_State* L, void* data, const char* type);
 /// Push Object to Lua.
 void ToluaPushObject(lua_State*L, void* data, const char* type);
 

+ 28 - 3
Source/Engine/LuaScript/pkgs/Graphics/Technique.pkg

@@ -10,13 +10,38 @@ enum PassLightingMode
 class Pass : public RefCounted
 {
     bool IsSM3() const;
+    const String GetVertexShader() const;
+    const String GetPixelShader() const;
+
     tolua_readonly tolua_property__is_set bool SM3;
+    tolua_readonly tolua_property__get_set const String vertexShader;
+    tolua_readonly tolua_property__get_set const String pixelShader;
 };
 
 class Technique : public Resource
 {
-    bool HasPass(const String type) const;
-    Pass* GetPass(const String  type) const;
+    bool HasPass(const StringHash type) const;
+    Pass* GetPass(const StringHash type) const;
+    Pass* GetSupportedPass(const StringHash type) const;
     bool IsSM3() const;
+    unsigned GetNumPasses() const;
+    tolua_outside const Vector<StringHash>& TechniqueGetPassTypes @ GetPassTypes() const;
+    tolua_outside const PODVector<Pass*>& TechniqueGetPasses @ GetPasses() const;
+
     tolua_readonly tolua_property__is_set bool SM3;
-};
+    tolua_readonly tolua_property__get_set unsigned numPasses;
+};
+
+${
+static const Vector<StringHash>& TechniqueGetPassTypes(const Technique* technique)
+{
+    static Vector<StringHash> vector = technique->GetPassTypes();
+    return vector;
+}
+
+static const PODVector<Pass*>& TechniqueGetPasses(const Technique* technique)
+{
+    static PODVector<Pass*> vector = technique->GetPasses();
+    return vector;
+}
+$}

+ 15 - 1
Source/Engine/Script/GraphicsAPI.cpp

@@ -510,6 +510,16 @@ static void ConstructTechniqueEntry(TechniqueEntry* ptr)
     new(ptr) TechniqueEntry();
 }
 
+static CScriptArray* TechniqueGetPassTypes(const Technique& technique)
+{
+    return VectorToArray<StringHash>(technique.GetPassTypes(), "Array<StringHash>");
+}
+
+static CScriptArray* TechniqueGetPasses(const Technique& technique)
+{
+    return VectorToHandleArray<Pass>(technique.GetPasses(), "Array<Pass@>");
+}
+
 static void ConstructTechniqueEntryCopy(const TechniqueEntry& entry, TechniqueEntry* ptr)
 {
     new(ptr) TechniqueEntry(entry);
@@ -620,9 +630,13 @@ static void RegisterMaterial(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Technique", "Pass@+ CreatePass(StringHash)", asMETHOD(Technique, CreatePass), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "void RemovePass(StringHash)", asMETHOD(Technique, RemovePass), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "bool HasPass(StringHash) const", asMETHOD(Technique, HasPass), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Technique", "Pass@+ GetPass(StringHash)", asMETHOD(Technique, GetPass), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Technique", "Pass@+ GetSupportedPass(StringHash)", asMETHOD(Technique, GetSupportedPass), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "void set_sm3(bool)", asMETHOD(Technique, SetIsSM3), asCALL_THISCALL);
     engine->RegisterObjectMethod("Technique", "bool get_sm3() const", asMETHOD(Technique, IsSM3), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Technique", "Pass@+ get_passes(StringHash)", asMETHOD(Technique, GetPass), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Technique", "uint get_numPasses() const", asMETHOD(Technique, GetNumPasses), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Technique", "Array<StringHash>@ get_passTypes() const", asFUNCTION(TechniqueGetPassTypes), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("Technique", "Array<Pass@>@ get_passes() const", asFUNCTION(TechniqueGetPasses), asCALL_CDECL_OBJLAST);
     
     engine->RegisterObjectType("TechniqueEntry", sizeof(TechniqueEntry), asOBJ_VALUE | asOBJ_APP_CLASS_CD);
     engine->RegisterObjectBehaviour("TechniqueEntry", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructTechniqueEntry), asCALL_CDECL_OBJLAST);