Quellcode durchsuchen

Clean up tolua++ bindings for handling (POD)Vector to table conversion.
Any C++ classes (either RefCounted or not) that are exposed to Lua scripting should be now supported in this conversion via new template function implementation. There should be no need to modify the ToluaUtils.cpp and .h anymore.

Yao Wei Tjong 姚伟忠 vor 10 Jahren
Ursprung
Commit
8658afabb0

+ 16 - 2
Source/ThirdParty/toluapp/src/lib/tolua_is.c

@@ -12,6 +12,8 @@
 ** enhancements, or modifications.
 */
 
+// Modified by Yao Wei Tjong for Urho3D
+
 #include "tolua++.h"
 #include "lauxlib.h"
 
@@ -297,7 +299,7 @@ TOLUA_API int tolua_isvaluenil (lua_State* L, int lo, tolua_Error* err) {
 		return 0; /* somebody else should chack this */
 	if (!lua_isnil(L, lo))
 		return 0;
-	
+
 	err->index = lo;
 	err->array = 0;
 	err->type = "value";
@@ -343,6 +345,8 @@ TOLUA_API int tolua_isbooleanarray
 	else
 	{
 		int i;
+		if (dim == -1)		// Urho3D - auto detect the array size if -1 is given
+			dim = (int)lua_objlen(L, lo);
 		for (i=1; i<=dim; ++i)
 		{
 			lua_pushnumber(L,i);
@@ -370,6 +374,8 @@ TOLUA_API int tolua_isnumberarray
 	else
 	{
 		int i;
+		if (dim == -1)		// Urho3D - auto detect the array size if -1 is given
+			dim = (int)lua_objlen(L, lo);
 		for (i=1; i<=dim; ++i)
 		{
 			lua_pushnumber(L,i);
@@ -397,6 +403,8 @@ TOLUA_API int tolua_isstringarray
 	else
 	{
 		int i;
+		if (dim == -1)		// Urho3D - auto detect the array size if -1 is given
+			dim = (int)lua_objlen(L, lo);
 		for (i=1; i<=dim; ++i)
 		{
 			lua_pushnumber(L,i);
@@ -424,6 +432,8 @@ TOLUA_API int tolua_istablearray
 	else
 	{
 		int i;
+		if (dim == -1)		// Urho3D - auto detect the array size if -1 is given
+			dim = (int)lua_objlen(L, lo);
 		for (i=1; i<=dim; ++i)
 		{
 			lua_pushnumber(L,i);
@@ -451,6 +461,8 @@ TOLUA_API int tolua_isuserdataarray
 	else
 	{
 		int i;
+		if (dim == -1)		// Urho3D - auto detect the array size if -1 is given
+			dim = (int)lua_objlen(L, lo);
 		for (i=1; i<=dim; ++i)
 		{
 			lua_pushnumber(L,i);
@@ -478,11 +490,13 @@ TOLUA_API int tolua_isusertypearray
 	else
 	{
 		int i;
+		if (dim == -1)		// Urho3D - auto detect the array size if -1 is given
+			dim = (int)lua_objlen(L, lo);
 		for (i=1; i<=dim; ++i)
 		{
 			lua_pushnumber(L,i);
 			lua_gettable(L,lo);
-	  if (!(lua_isnil(L,-1) || lua_isuserdata(L,-1)) &&
+	  if (!(lua_isnil(L,-1) || lua_isusertype(L,-1, type)) &&	// Urho3D - bug fix to check user type instead of user data
 			    !(def && lua_isnil(L,-1))
 						)
 			{

+ 137 - 315
Source/Urho3D/LuaScript/ToluaUtils.cpp

@@ -22,15 +22,13 @@
 
 #include "../Precompiled.h"
 
-#include "../Core/Object.h"
-
 #include <toluapp/tolua++.h>
+
 #include "../LuaScript/ToluaUtils.h"
 
 const char* tolua_tourho3dstring(lua_State* L, int narg, const char* str)
 {
-    const char* s = tolua_tostring(L, narg, str);
-    return s ? s : "";
+    return tolua_tostring(L, narg, str);
 }
 
 const char* tolua_tourho3dstring(lua_State* L, int narg, const String& str)
@@ -61,448 +59,272 @@ Context* GetContext(lua_State* L)
     return i->second_;
 }
 
-template <> int ToluaIsVector<String>(lua_State* L, int lo, const char* type, int def, tolua_Error* err)
-{
-    if (lua_istable(L, lo))
-    {
-        size_t length = lua_objlen(L, lo);
-        for (unsigned i = 1; i <= length; ++i)
-        {
-            lua_rawgeti(L, lo, i);
-            if (!lua_isstring(L, -1))
-            {
-                lua_pop(L, 1);
-
-                err->index = lo;
-                err->array = 0;
-                err->type = type;
-
-                return 0;
-            }
-
-            lua_pop(L, 1);
-        }
-
-        return 1;
-    }
-
-    err->index = lo;
-    err->array = 0;
-    err->type = type;
-    return 0;
-}
+// Explicit template specialization only required for StringVector
 
-template <> int ToluaIsVector<Variant>(lua_State* L, int lo, const char* type, int def, tolua_Error* err)
+template <> int ToluaIsVector<String>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
 {
-    if (lua_istable(L, lo))
-    {
-        size_t length = lua_objlen(L, lo);
-        for (unsigned i = 1; i <= length; ++i)
-        {
-            lua_rawgeti(L, lo, i);
-            if (!tolua_isusertype(L, -1, "Variant", def, err))
-            {
-                lua_pop(L, 1);
-                return 0;
-            }
-            lua_pop(L, 1);
-        }
-        return 1;
-    }
-
-    err->index = lo;
-    err->array = 0;
-    err->type = type;
-    return 0;
+    return tolua_isstringarray(L, lo, -1, def, err);
 }
 
-template <> void* ToluaToVector<String>(lua_State* L, int narg, void* def)
+template <> void* ToluaToVector<String>(lua_State* L, int narg, void* /*def*/)
 {
     if (!lua_istable(L, narg))
         return 0;
-
     static Vector<String> result;
     result.Clear();
     result.Resize((unsigned)lua_objlen(L, narg));
     for (unsigned i = 0; i < result.Size(); ++i)
     {
         lua_rawgeti(L, narg, i + 1);
-        if (!lua_isstring(L, -1))
-        {
-            lua_pop(L, 1);
-            return 0;
-        }
         result[i] = tolua_tourho3dstring(L, -1, "");
         lua_pop(L, 1);
     }
-
-    return &result;
-}
-
-template <> void* ToluaToVector<Variant>(lua_State* L, int narg, void* def)
-{
-    if (!lua_istable(L, narg))
-        return 0;
-
-    static Vector<Variant> result;
-    result.Clear();
-    result.Resize((unsigned)lua_objlen(L, narg));
-    for (unsigned i = 0; i < result.Size(); ++i)
-    {
-        lua_rawgeti(L, narg, i + 1);    // Lua index starts from 1
-        tolua_Error error;
-        if (!tolua_isusertype(L, -1, "Variant", 0, &error))
-        {
-            lua_pop(L, 1);
-            return 0;
-        }
-        result[i] = *static_cast<Variant*>(tolua_tousertype(L, -1, def));
-        lua_pop(L, 1);
-    }
-
     return &result;
 }
 
-template <> int ToluaPushVector<String>(lua_State* L, void* data, const char* type)
+template <> int ToluaPushVector<String>(lua_State* L, void* data, const char* /*type*/)
 {
-    const Vector<String>& vectorstring = *((const Vector<String>*)data);
     lua_newtable(L);
-    for (unsigned i = 0; i < vectorstring.Size(); ++i)
+    const Vector<String>& vector = *static_cast<const Vector<String>*>(data);
+    for (unsigned i = 0; i < vector.Size(); ++i)
     {
-        tolua_pushurho3dstring(L, vectorstring[i]);
+        tolua_pushurho3dstring(L, vector[i]);
         lua_rawseti(L, -2, i + 1);
     }
     return 1;
 }
 
-template <> int ToluaPushVector<StringHash>(lua_State* L, void* data, const char* type)
+// Explicit template specialization only required for Lua number and boolean types
+
+template <> int ToluaIsPODVector<char>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
 {
-    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;
+    return tolua_isnumberarray(L, lo, -1, def, err);
 }
 
-template <> int ToluaPushVector<Variant>(lua_State* L, void* data, const char* type)
+template <> int ToluaIsPODVector<unsigned char>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
 {
-    lua_newtable(L);
-    Vector<Variant>& vector = *reinterpret_cast<Vector<Variant>*>(data);
-    for (unsigned i = 0; i < vector.Size(); ++i)
-    {
-        tolua_pushusertype(L, &vector[i], "Variant");
-        lua_rawseti(L, -2, i + 1);
-    }
-    return 1;
+    return tolua_isnumberarray(L, lo, -1, def, err);
 }
 
-template <> int ToluaIsPODVector<unsigned>(lua_State* L, int lo, const char* type, int def, tolua_Error* err)
+template <> int ToluaIsPODVector<short>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
 {
-    if (lua_istable(L, lo))
-    {
-        size_t length = lua_objlen(L, lo);
-        for (int i = 1; i <= length; ++i)
-        {
-            lua_pushinteger(L, i);
-            lua_gettable(L, lo);
-            if (!lua_isnumber(L, -1))
-            {
-                lua_pop(L, 1);
-
-                err->index = lo;
-                err->array = 0;
-                err->type = type;
-
-                return 0;
-            }
-
-            lua_pop(L, 1);
-        }
-
-        return 1;
-    }
+    return tolua_isnumberarray(L, lo, -1, def, err);
+}
 
-    err->index = lo;
-    err->array = 0;
-    err->type = type;
-    return 0;
+template <> int ToluaIsPODVector<unsigned short>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
+{
+    return tolua_isnumberarray(L, lo, -1, def, err);
 }
 
-template <> int ToluaIsPODVector<Vector2>(lua_State* L, int lo, const char* type, int def, tolua_Error* err)
+template <> int ToluaIsPODVector<int>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
 {
-    if (lua_istable(L, lo))
-    {
-        size_t length = lua_objlen(L, lo);
-        for (int i = 1; i <= length; ++i)
-        {
-            lua_pushinteger(L, i);
-            lua_gettable(L, lo);
-            if (!tolua_isusertype(L, -1, "Vector2", 0, err))
-            {
-                lua_pop(L, 1);
-                return 0;
-            }
-
-            lua_pop(L, 1);
-        }
-
-        return 1;
-    }
+    return tolua_isnumberarray(L, lo, -1, def, err);
+}
 
-    err->index = lo;
-    err->array = 0;
-    err->type = type;
-    return 0;
+template <> int ToluaIsPODVector<unsigned>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
+{
+    return tolua_isnumberarray(L, lo, -1, def, err);
 }
 
-template <> void* ToluaToPODVector<unsigned>(lua_State* L, int narg, void* def)
+template <> int ToluaIsPODVector<long>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
 {
-    if (!lua_istable(L, narg))
-        return 0;
+    return tolua_isnumberarray(L, lo, -1, def, err);
+}
 
-    static PODVector<unsigned> result;
-    result.Clear();
+template <> int ToluaIsPODVector<unsigned long>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
+{
+    return tolua_isnumberarray(L, lo, -1, def, err);
+}
 
-    size_t length = lua_objlen(L, narg);
-    for (int i = 1; i <= length; ++i)
-    {
-        lua_pushinteger(L, i);
-        lua_gettable(L, narg);
+template <> int ToluaIsPODVector<long long>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
+{
+    return tolua_isnumberarray(L, lo, -1, def, err);
+}
 
-        if (!lua_isnumber(L, -1))
-        {
-            lua_pop(L, 1);
-            return 0;
-        }
+template <> int ToluaIsPODVector<unsigned long long>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
+{
+    return tolua_isnumberarray(L, lo, -1, def, err);
+}
 
-        unsigned value = (unsigned)tolua_tonumber(L, -1, 0);
-        result.Push(value);
+template <> int ToluaIsPODVector<float>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
+{
+    return tolua_isnumberarray(L, lo, -1, def, err);
+}
 
-        lua_pop(L, 1);
-    }
+template <> int ToluaIsPODVector<double>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
+{
+    return tolua_isnumberarray(L, lo, -1, def, err);
+}
 
-    return &result;
+template <> int ToluaIsPODVector<bool>(lua_State* L, int lo, const char* /*type*/, int def, tolua_Error* err)
+{
+    return tolua_isbooleanarray(L, lo, -1, def, err);
 }
 
-template <> void* ToluaToPODVector<Vector2>(lua_State* L, int narg, void* def)
+template <typename T> void* ToluaToNumberVector(lua_State* L, int narg, void* def)
 {
     if (!lua_istable(L, narg))
         return 0;
-
-    static PODVector<Vector2> result;
+    static PODVector<T> result;
     result.Clear();
-
-    tolua_Error tolua_err;
-
-    size_t length = lua_objlen(L, narg);
-    for (int i = 1; i <= length; ++i)
+    result.Resize((unsigned)lua_objlen(L, narg));
+    for (unsigned i = 0; i < result.Size(); ++i)
     {
-        lua_pushinteger(L, i);
-        lua_gettable(L, narg);
-
-        if (!tolua_isusertype(L, -1, "Vector2", 0, &tolua_err))
-        {
-            lua_pop(L, 1);
-            return 0;
-        }
-
-        Vector2* value = (Vector2*)tolua_touserdata(L, -1, 0);
-        result.Push(*value);
-
+        lua_rawgeti(L, narg, i + 1);
+        result[i] = (T)tolua_tonumber(L, -1, 0);
         lua_pop(L, 1);
     }
-
     return &result;
 }
 
-template <> int ToluaPushPODVector<int>(lua_State* L, void* data, const char*)
+void* ToluaToBooleanVector(lua_State* L, int narg, void* def)
 {
-    const PODVector<int>& vector = *((const PODVector<int>*)data);
-    lua_newtable(L);
-    for (unsigned i = 0; i < vector.Size(); ++i)
+    if (!lua_istable(L, narg))
+        return 0;
+    static PODVector<bool> result;
+    result.Clear();
+    result.Resize((unsigned)lua_objlen(L, narg));
+    for (unsigned i = 0; i < result.Size(); ++i)
     {
-        lua_pushinteger(L, vector[i]);
-        lua_rawseti(L, -2, i + 1);
+        lua_rawgeti(L, narg, i + 1);
+        result[i] = (bool)tolua_toboolean(L, -1, 0);
+        lua_pop(L, 1);
     }
-
-    return 1;
+    return &result;
 }
 
-template <> int ToluaPushPODVector<unsigned>(lua_State* L, void* data, const char*)
+template <> void* ToluaToPODVector<char>(lua_State* L, int narg, void* def)
 {
-    const PODVector<unsigned>& vector = *((const PODVector<unsigned>*)data);
-    lua_newtable(L);
-    for (unsigned i = 0; i < vector.Size(); ++i)
-    {
-        lua_pushinteger(L, vector[i]);
-        lua_rawseti(L, -2, i + 1);
-    }
-
-    return 1;
+    return ToluaToNumberVector<char>(L, narg, def);
 }
 
-template <> int ToluaPushPODVector<Component*>(lua_State* L, void* data, const char*)
+template <> void* ToluaToPODVector<unsigned char>(lua_State* L, int narg, void* def)
 {
-    const PODVector<Component*>& vector = *((const PODVector<Component*>*)data);
-    lua_newtable(L);
-    for (unsigned i = 0; i < vector.Size(); ++i)
-    {
-        tolua_pushusertype(L, vector[i], "Component");
-        lua_rawseti(L, -2, i + 1);
-    }
-    return 1;
+    return ToluaToNumberVector<unsigned char>(L, narg, def);
 }
 
-template <> int ToluaPushPODVector<Node*>(lua_State* L, void* data, const char*)
+template <> void* ToluaToPODVector<short>(lua_State* L, int narg, void* def)
 {
-    const PODVector<Node*>& vector = *((const PODVector<Node*>*)data);
-    lua_newtable(L);
-    for (unsigned i = 0; i < vector.Size(); ++i)
-    {
-        tolua_pushusertype(L, vector[i], "Node");
-        lua_rawseti(L, -2, i + 1);
-    }
-    return 1;
+    return ToluaToNumberVector<short>(L, narg, def);
 }
 
-template <> int ToluaPushPODVector<SoundSource*>(lua_State* L, void* data, const char*)
+template <> void* ToluaToPODVector<unsigned short>(lua_State* L, int narg, void* def)
 {
-    const PODVector<SoundSource*>& vector = *((const PODVector<SoundSource*>*)data);
-    lua_newtable(L);
-    for (unsigned i = 0; i < vector.Size(); ++i)
-    {
-        tolua_pushusertype(L, vector[i], "SoundSource");
-        lua_rawseti(L, -2, i + 1);
-    }
-    return 1;
+    return ToluaToNumberVector<unsigned short>(L, narg, def);
 }
 
-template <> int ToluaPushPODVector<UIElement*>(lua_State* L, void* data, const char*)
+template <> void* ToluaToPODVector<int>(lua_State* L, int narg, void* def)
 {
-    const PODVector<UIElement*>& vector = *((const PODVector<UIElement*>*)data);
-    lua_newtable(L);
-    for (unsigned i = 0; i < vector.Size(); ++i)
-    {
-        tolua_pushusertype(L, vector[i], "UIElement");
-        lua_rawseti(L, -2, i + 1);
-    }
-    return 1;
+    return ToluaToNumberVector<int>(L, narg, def);
 }
 
-#ifdef URHO3D_NAVIGATION
-
-template <> int ToluaPushPODVector<CrowdAgent*>(lua_State* L, void* data, const char*)
+template <> void* ToluaToPODVector<unsigned>(lua_State* L, int narg, void* def)
 {
-    const PODVector<CrowdAgent*>& vector = *((const PODVector<CrowdAgent*>*)data);
-    lua_newtable(L);
-    for (unsigned i = 0; i < vector.Size(); ++i)
-    {
-        tolua_pushusertype(L, vector[i], "CrowdAgent");
-        lua_rawseti(L, -2, i + 1);
-    }
-    return 1;
+    return ToluaToNumberVector<unsigned>(L, narg, def);
 }
 
-#endif
+template <> void* ToluaToPODVector<long>(lua_State* L, int narg, void* def)
+{
+    return ToluaToNumberVector<long>(L, narg, def);
+}
 
-#ifdef URHO3D_PHYSICS
+template <> void* ToluaToPODVector<unsigned long>(lua_State* L, int narg, void* def)
+{
+    return ToluaToNumberVector<unsigned long>(L, narg, def);
+}
 
-template <> int ToluaPushPODVector<RigidBody*>(lua_State* L, void* data, const char*)
+template <> void* ToluaToPODVector<float>(lua_State* L, int narg, void* def)
 {
-    const PODVector<RigidBody*>& vector = *((const PODVector<RigidBody*>*)data);
-    lua_newtable(L);
-    for (unsigned i = 0; i < vector.Size(); ++i)
-    {
-        tolua_pushusertype(L, vector[i], "RigidBody");
-        lua_rawseti(L, -2, i + 1);
-    }
-    return 1;
+    return ToluaToNumberVector<float>(L, narg, def);
 }
 
-#endif
+template <> void* ToluaToPODVector<double>(lua_State* L, int narg, void* def)
+{
+    return ToluaToNumberVector<double>(L, narg, def);
+}
 
-#ifdef URHO3D_URHO2D
+template <> void* ToluaToPODVector<bool>(lua_State* L, int narg, void* def)
+{
+    return ToluaToBooleanVector(L, narg, def);
+}
 
-template <> int ToluaPushPODVector<RigidBody2D*>(lua_State* L, void* data, const char*)
+template <typename T> int ToluaPushNumberVector(lua_State* L, void* data, const char* /*type*/)
 {
-    const PODVector<RigidBody2D*>& vector = *((const PODVector<RigidBody2D*>*)data);
     lua_newtable(L);
+    const PODVector<T>& vector = *static_cast<const PODVector<T>*>(data);
     for (unsigned i = 0; i < vector.Size(); ++i)
     {
-        tolua_pushusertype(L, vector[i], "RigidBody2D");
+        lua_pushnumber(L, vector[i]);
         lua_rawseti(L, -2, i + 1);
     }
     return 1;
 }
 
-#endif
-
-template <typename T> int tolua_pushurho3dpodvectorusertype(lua_State* L, const PODVector<T>& vector, const char* typeName)
+int ToluaPushBooleanVector(lua_State* L, void* data, const char* /*type*/)
 {
     lua_newtable(L);
+    const PODVector<bool>& vector = *static_cast<const PODVector<bool>*>(data);
     for (unsigned i = 0; i < vector.Size(); ++i)
     {
-        void* tolua_obj = Mtolua_new((T)(vector[i]));
-        tolua_pushusertype(L, tolua_obj, typeName);
-        tolua_register_gc(L, lua_gettop(L));
-
+        lua_pushboolean(L, vector[i]);
         lua_rawseti(L, -2, i + 1);
     }
-
     return 1;
 }
 
-template <> int ToluaPushPODVector<Vector3>(lua_State* L, void* data, const char*)
+template <> int ToluaPushPODVector<char>(lua_State* L, void* data, const char* type)
 {
-    return tolua_pushurho3dpodvectorusertype(L, *((const PODVector<Vector3>*)data), "Vector3");
+    return ToluaPushNumberVector<char>(L, data, type);
 }
 
-template <> int ToluaPushPODVector<IntVector2>(lua_State* L, void* data, const char*)
+template <> int ToluaPushPODVector<unsigned char>(lua_State* L, void* data, const char* type)
 {
-    return tolua_pushurho3dpodvectorusertype(L, *((const PODVector<IntVector2>*)data), "IntVector2");
+    return ToluaPushNumberVector<unsigned char>(L, data, type);
 }
 
-template <> int ToluaPushPODVector<OctreeQueryResult>(lua_State* L, void* data, const char*)
+template <> int ToluaPushPODVector<short>(lua_State* L, void* data, const char* type)
 {
-    return tolua_pushurho3dpodvectorusertype(L, *((const PODVector<OctreeQueryResult>*)data), "OctreeQueryResult");
+    return ToluaPushNumberVector<short>(L, data, type);
 }
 
-#ifdef URHO3D_PHYSICS
+template <> int ToluaPushPODVector<unsigned short>(lua_State* L, void* data, const char* type)
+{
+    return ToluaPushNumberVector<unsigned short>(L, data, type);
+}
 
-template <> int ToluaPushPODVector<PhysicsRaycastResult>(lua_State* L, void* data, const char*)
+template <> int ToluaPushPODVector<int>(lua_State* L, void* data, const char* type)
 {
-    return tolua_pushurho3dpodvectorusertype(L, *((const PODVector<PhysicsRaycastResult>*)data), "PhysicsRaycastResult");
+    return ToluaPushNumberVector<int>(L, data, type);
 }
 
-#endif
+template <> int ToluaPushPODVector<unsigned>(lua_State* L, void* data, const char* type)
+{
+    return ToluaPushNumberVector<unsigned>(L, data, type);
+}
 
-#ifdef URHO3D_URHO2D
+template <> int ToluaPushPODVector<long>(lua_State* L, void* data, const char* type)
+{
+    return ToluaPushNumberVector<long>(L, data, type);
+}
 
-template <> int ToluaPushPODVector<PhysicsRaycastResult2D>(lua_State* L, void* data, const char*)
+template <> int ToluaPushPODVector<unsigned long>(lua_State* L, void* data, const char* type)
 {
-    return tolua_pushurho3dpodvectorusertype(L, *((const PODVector<PhysicsRaycastResult2D>*)data), "PhysicsRaycastResult2D");
+    return ToluaPushNumberVector<unsigned long>(L, data, type);
 }
 
-#endif
+template <> int ToluaPushPODVector<float>(lua_State* L, void* data, const char* type)
+{
+    return ToluaPushNumberVector<float>(L, data, type);
+}
 
-template <> int ToluaPushPODVector<RayQueryResult>(lua_State* L, void* data, const char*)
+template <> int ToluaPushPODVector<double>(lua_State* L, void* data, const char* type)
 {
-    return tolua_pushurho3dpodvectorusertype(L, *((const PODVector<RayQueryResult>*)data), "RayQueryResult");
+    return ToluaPushNumberVector<double>(L, data, type);
 }
 
-template <> int ToluaPushPODVector<Pass*>(lua_State* L, void* data, const char*)
+template <> int ToluaPushPODVector<bool>(lua_State* L, void* data, const char* type)
 {
-    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;
+    return ToluaPushBooleanVector(L, data, type);
 }
 
 void ToluaPushObject(lua_State* L, void* data, const char* type)

+ 66 - 80
Source/Urho3D/LuaScript/ToluaUtils.h

@@ -23,30 +23,9 @@
 #pragma once
 
 #include "../Core/Context.h"
-#include "../Graphics/OctreeQuery.h"
-#include "../Math/Vector2.h"
-#include "../Math/Vector3.h"
-#ifdef URHO3D_PHYSICS
-#include "../Physics/PhysicsWorld.h"
-#endif
-#ifdef URHO3D_URHO2D
-#include "../Urho2D/PhysicsWorld2D.h"
-#endif
 
 struct lua_State;
 
-namespace Urho3D
-{
-class Component;
-class Context;
-#ifdef URHO3D_NAVIGATION
-class CrowdAgent;
-#endif
-class Pass;
-class SoundSource;
-class UIElement;
-}
-
 using namespace Urho3D;
 
 /// Check is String.
@@ -89,83 +68,90 @@ template <typename T> int ToluaGetSubsystem(lua_State* tolua_S)
 }
 
 /// Check is Vector<T>.
-template <typename T> int ToluaIsVector(lua_State* L, int lo, const char* type, int def, tolua_Error* err);
+template <typename T> int ToluaIsVector(lua_State* L, int lo, const char* type, int def, tolua_Error* err)
+{
+    return tolua_isusertypearray(L, lo, type, -1, def, err);
+}
+
 /// Check is Vector<String>.
 template <> int ToluaIsVector<String>(lua_State* L, int lo, const char* type, int def, tolua_Error* err);
 
-/// Convert to Vector<T>.
-template <typename T> void* ToluaToVector(lua_State* L, int narg, void* def);
-/// Convert to Vector<String>.
+/// Convert to Vector<T>. This function is not thread-safe.
+template <typename T> void* ToluaToVector(lua_State* L, int narg, void* def)
+{
+    if (!lua_istable(L, narg))
+        return 0;
+    static Vector<T> result;
+    result.Clear();
+    result.Resize((unsigned)lua_objlen(L, narg));
+    for (unsigned i = 0; i < result.Size(); ++i)
+    {
+        lua_rawgeti(L, narg, i + 1);    // Lua index starts from 1
+        result[i] = *static_cast<T*>(tolua_tousertype(L, -1, def));
+        lua_pop(L, 1);
+    }
+    return &result;
+}
+
+/// Convert to Vector<String>. This function is not thread-safe.
 template <> void* ToluaToVector<String>(lua_State* L, int narg, void* def);
 
 /// Push Vector<T> to Lua as a table.
-template <typename T> int ToluaPushVector(lua_State* L, void* data, const char* type);
+template <typename T> int ToluaPushVector(lua_State* L, void* data, const char* type)
+{
+    lua_newtable(L);
+    Vector<T>& vector = *static_cast<Vector<T>*>(data);
+    for (unsigned i = 0; i < vector.Size(); ++i)
+    {
+        tolua_pushusertype(L, &vector[i], type);
+        lua_rawseti(L, -2, i + 1);
+    }
+    return 1;
+}
+
 /// 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);
+template <typename T> int ToluaIsPODVector(lua_State* L, int lo, const char* type, int def, tolua_Error* err)
+{
+    // Whether it is POD or non-POD, on Lua side they are just usertype object, so we can reuse the same function
+    return ToluaIsVector<T>(L, lo, type, def, err);
+}
+
 /// Check is PODVector<unsigned>.
 template <> int ToluaIsPODVector<unsigned>(lua_State* L, int lo, const char* type, int def, tolua_Error* err);
-/// Check is PODVector<Vector2>.
-template <> int ToluaIsPODVector<Vector2>(lua_State* L, int lo, const char* type, int def, tolua_Error* err);
 
-/// Convert to PODVector<T>.
-template <typename T> void* ToluaToPODVector(lua_State* L, int narg, void* def);
-/// Convert PODVector<unsigned>.
+/// Convert to PODVector<T>. This function is not thread-safe.
+template <typename T> void* ToluaToPODVector(lua_State* L, int narg, void* def)
+{
+    return ToluaToVector<T>(L, narg, def);
+}
+
+/// Convert to PODVector<unsigned>. This function is not thread-safe.
 template <> void* ToluaToPODVector<unsigned>(lua_State* L, int narg, void* def);
-/// Convert PODVector<Vector2>.
-template <> void* ToluaToPODVector<Vector2>(lua_State* L, int narg, void* def);
 
 /// Push PODVector<T> to Lua as a table.
-template <typename T> int ToluaPushPODVector(lua_State* L, void* data, const char* type);
-/// Push PODVector<int> to Lua as a table.
-template <> int ToluaPushPODVector<int>(lua_State* L, void* data, const char* type);
+template <typename T> int ToluaPushPODVector(lua_State* L, void* data, const char* type)
+{
+    return ToluaPushVector<T>(L, data, type);
+}
+
 /// Push PODVector<unsigned> to Lua as a table.
 template <> int ToluaPushPODVector<unsigned>(lua_State* L, void* data, const char* type);
 
-/// Push PODVector<Component*> to Lua as a table.
-template <> int ToluaPushPODVector<Component*>(lua_State* L, void* data, const char* type);
-
-/// Push PODVector<Node*> to Lua as a table.
-template <> int ToluaPushPODVector<Node*>(lua_State* L, void* data, const char* type);
-
-/// Push PODVector<SoundSource*> to Lua as a table.
-template <> int ToluaPushPODVector<SoundSource*>(lua_State* L, void* data, const char* type);
-/// Push PODVector<UIElement*> to Lua as a table.
-template <> int ToluaPushPODVector<UIElement*>(lua_State* L, void* data, const char* type);
-#ifdef URHO3D_PHYSICS
-/// Push PODVector<RigidBody*> to Lua as a table.
-template <> int ToluaPushPODVector<RigidBody*>(lua_State* L, void* data, const char* type);
-#endif
-#ifdef URHO3D_URHO2D
-/// Push PODVector<RigidBody2D*> to Lua as a table.
-template <> int ToluaPushPODVector<RigidBody2D*>(lua_State* L, void* data, const char* type);
-#endif
-/// Push PODVector<Vector3> to Lua as a table.
-template <> int ToluaPushPODVector<Vector3>(lua_State* L, void* data, const char* type);
-/// Push PODVector<IntVector2> to Lua as a table.
-template <> int ToluaPushPODVector<IntVector2>(lua_State* L, void* data, const char* type);
-/// Push PODVector<OctreeQueryResult> to Lua as a table.
-template <> int ToluaPushPODVector<OctreeQueryResult>(lua_State* L, void* data, const char* type);
-#ifdef URHO3D_NAVIGATION
-/// Push PODVector<CrowdAgent*> to Lua as a table.
-template <> int ToluaPushPODVector<CrowdAgent*>(lua_State* L, void* data, const char* type);
-#endif
-#ifdef URHO3D_PHYSICS
-/// Push PODVector<PhysicsRaycastResult> to Lua as a table.
-template <> int ToluaPushPODVector<PhysicsRaycastResult>(lua_State* L, void* data, const char* type);
-#endif
-#ifdef URHO3D_URHO2D
-/// Push PODVector<PhysicsRaycastResult2D> to Lua as a table.
-template <> int ToluaPushPODVector<PhysicsRaycastResult2D>(lua_State* L, void* data, const char* type);
-#endif
-/// 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 PODVector<RefCounted*> to Lua as a table. Use template function overload as non-type partial template specialization is not allowed.
+template <typename T> int ToluaPushPODVector(const char* overload, lua_State* L, void* data, const char* /*type*/)
+{
+    lua_newtable(L);
+    const PODVector<T>& vector = *static_cast<const PODVector<T>*>(data);
+    for (unsigned i = 0; i < vector.Size(); ++i)
+    {
+        tolua_pushusertype(L, vector[i], overload);
+        lua_rawseti(L, -2, i + 1);
+    }
+    return 1;
+}
+
 /// Push Object to Lua.
 void ToluaPushObject(lua_State* L, void* data, const char* type);
-

+ 111 - 3
Source/Urho3D/LuaScript/pkgs/Core/Variant.pkg

@@ -1,4 +1,5 @@
 $#include "Core/Variant.h"
+$#include "IO/VectorBuffer.h"
 
 enum VariantType
 {
@@ -59,8 +60,13 @@ class Variant
     static void _Setup(const char* type);
 
     Variant();
-    Variant(void* value);           // Somehow non-specific type must be declared first so that it get considered last
+
+    //NOTE: do not change the constructor overloads order without also changing the special case handling below
+    Variant(const Vector<Variant>& value);  // VariantVector and StringVector are special cases as they are converted to Lua tables
+    Variant(const Vector<String>& value);
+    Variant(void* value);                   // Non-specific types must be declared first so that they get considered last
     Variant(RefCounted* value);
+
     Variant(int value);
     Variant(unsigned value);
     Variant(const StringHash& value);
@@ -77,8 +83,6 @@ class Variant
     Variant(const VectorBuffer& value);
     Variant(const ResourceRef& value);
     Variant(const ResourceRefList& value);
-    Variant(const Vector<Variant>& value);
-    Variant(const Vector<String>& value);
     Variant(const VariantMap& value);
     Variant(const IntRect& value);
     Variant(const IntVector2& value);
@@ -210,6 +214,110 @@ static int tolua_CoreLuaAPI_Variant__Setup00(lua_State* tolua_S)
     return 0;
 }
 
+// NOTE: the index number must match with the above variant constructor overloads order)
+// Special cases handling for converted VariantVector and StringVector as Lua table
+// The auto-generated code are almost correct, except for the tolua_isnoobj() always return false for third index,
+//   probably due to another tolua++ bug not setting the stack correctly, instead of noobj, 3rd index contains first table member
+
+// Forward declaration,
+static int tolua_CoreLuaAPI_Variant_new00(lua_State* tolua_S);
+static int tolua_CoreLuaAPI_Variant_new00_local(lua_State* tolua_S);
+
+// Correct auto-generated code
+#define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_new01
+static int tolua_CoreLuaAPI_Variant_new01(lua_State* tolua_S)
+{
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertable(tolua_S,1,"Variant",0,&tolua_err) ||
+ (tolua_isvaluenil(tolua_S,2,&tolua_err) || !ToluaIsVector<Variant>(tolua_S,2,"const Vector<Variant>",0,&tolua_err)) /*||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)*/
+ )
+ goto tolua_lerror;
+ else
+ {
+  const Vector<Variant>* value = ((const Vector<Variant>*)  ToluaToVector<Variant>(tolua_S,2,0));
+ {
+  Variant* tolua_ret = (Variant*)  Mtolua_new((Variant)(*value));
+  tolua_pushusertype(tolua_S,(void*)tolua_ret,"Variant");
+ }
+ }
+ return 1;
+tolua_lerror:
+ return tolua_CoreLuaAPI_Variant_new00(tolua_S);
+}
+
+#define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_new01_local
+static int tolua_CoreLuaAPI_Variant_new01_local(lua_State* tolua_S)
+{
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertable(tolua_S,1,"Variant",0,&tolua_err) ||
+ (tolua_isvaluenil(tolua_S,2,&tolua_err) || !ToluaIsVector<Variant>(tolua_S,2,"const Vector<Variant>",0,&tolua_err)) /*||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)*/
+ )
+ goto tolua_lerror;
+ else
+ {
+  const Vector<Variant>* value = ((const Vector<Variant>*)  ToluaToVector<Variant>(tolua_S,2,0));
+ {
+  Variant* tolua_ret = (Variant*)  Mtolua_new((Variant)(*value));
+  tolua_pushusertype(tolua_S,(void*)tolua_ret,"Variant");
+ tolua_register_gc(tolua_S,lua_gettop(tolua_S));
+ }
+ }
+ return 1;
+tolua_lerror:
+ return tolua_CoreLuaAPI_Variant_new00_local(tolua_S);
+}
+
+#define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_new02
+static int tolua_CoreLuaAPI_Variant_new02(lua_State* tolua_S)
+{
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertable(tolua_S,1,"Variant",0,&tolua_err) ||
+ (tolua_isvaluenil(tolua_S,2,&tolua_err) || !ToluaIsVector<String>(tolua_S,2,"const Vector<String>",0,&tolua_err)) /*||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)*/
+ )
+ goto tolua_lerror;
+ else
+ {
+  const Vector<String>* value = ((const Vector<String>*)  ToluaToVector<String>(tolua_S,2,0));
+ {
+  Variant* tolua_ret = (Variant*)  Mtolua_new((Variant)(*value));
+  tolua_pushusertype(tolua_S,(void*)tolua_ret,"Variant");
+ }
+ }
+ return 1;
+tolua_lerror:
+ return tolua_CoreLuaAPI_Variant_new01(tolua_S);
+}
+
+#define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_new02_local
+static int tolua_CoreLuaAPI_Variant_new02_local(lua_State* tolua_S)
+{
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertable(tolua_S,1,"Variant",0,&tolua_err) ||
+ (tolua_isvaluenil(tolua_S,2,&tolua_err) || !ToluaIsVector<String>(tolua_S,2,"const Vector<String>",0,&tolua_err)) /*||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)*/
+ )
+ goto tolua_lerror;
+ else
+ {
+  const Vector<String>* value = ((const Vector<String>*)  ToluaToVector<String>(tolua_S,2,0));
+ {
+  Variant* tolua_ret = (Variant*)  Mtolua_new((Variant)(*value));
+  tolua_pushusertype(tolua_S,(void*)tolua_ret,"Variant");
+ tolua_register_gc(tolua_S,lua_gettop(tolua_S));
+ }
+ }
+ return 1;
+tolua_lerror:
+ return tolua_CoreLuaAPI_Variant_new01_local(tolua_S);
+}
+
 #define TOLUA_DISABLE_tolua_CoreLuaAPI_Variant_GetVoidPtr00
 static int tolua_CoreLuaAPI_Variant_GetVoidPtr00(lua_State* tolua_S)
 {

+ 20 - 14
Source/Urho3D/LuaScript/pkgs/ToCppHook.lua

@@ -57,11 +57,9 @@ function post_output_hook(package)
             end
         until not e
         result = currentString..string.sub(result, nxt)
-        --if k == 0 then print('Pattern not replaced', pattern) end
     end
 
     replace("\t", "  ")
-
     replace([[#ifndef __cplusplus
 #include "stdlib.h"
 #endif
@@ -103,6 +101,11 @@ function post_output_hook(package)
 #include <Urho3D/LuaScript/ToluaUtils.h>]])
     end
 
+    -- Special handling for vector to table conversion which would simply the implementation of the template functions
+    result = string.gsub(result, "ToluaIs(P?O?D?)Vector([^\"]-)\"c?o?n?s?t? ?P?O?D?Vector<([^*>]-)%*?>\"", "ToluaIs%1Vector%2\"%3\"")
+    result = string.gsub(result, "ToluaPush(P?O?D?)Vector([^\"]-)\"c?o?n?s?t? ?P?O?D?Vector<([^*>]-)%*?>\"", "ToluaPush%1Vector%2\"%3\"")
+    result = string.gsub(result, "@([^(]+)%(", "(\"%1\",")      -- RefCounted* overload
+
     WRITE(result)
     WRITE([[
 #if __clang__
@@ -132,11 +135,12 @@ function get_push_function(t)
     if not urho3d_is_vector(t) then
         return old_get_push_function(t)
     end
-    
+
+    local T = t:match("<.*>")
     if not urho3d_is_podvector(t) then
-        return "ToluaPushVector" .. t:match("<.*>")
+        return "ToluaPushVector" .. T
     else
-        return "ToluaPushPODVector" .. t:match("<.*>")
+        return "ToluaPushPODVector" .. T .. (T:match("%*>") and "@" .. T:match("<([^*]+)%*>") or "")     -- may be overloadded
     end
 end
 
@@ -144,11 +148,12 @@ function get_to_function(t)
     if not urho3d_is_vector(t) then
         return old_get_to_function(t)
     end
-    
+
+    local T = t:match("<.*>")
     if not urho3d_is_podvector(t) then
-        return "ToluaToVector" .. t:match("<.*>")
+        return "ToluaToVector" .. T
     else
-        return "ToluaToPODVector" .. t:match("<.*>")
+        return "ToluaToPODVector" .. T
     end
 end
 
@@ -156,11 +161,12 @@ function get_is_function(t)
     if not urho3d_is_vector(t) then
         return old_get_is_function(t)
     end
-    
+
+    local T = t:match("<.*>")
     if not urho3d_is_podvector(t) then
-        return "ToluaIsVector" .. t:match("<.*>")
+        return "ToluaIsVector" .. T
     else
-        return "ToluaIsPODVector" .. t:match("<.*>")
+        return "ToluaIsPODVector" .. T
     end
 end
 
@@ -169,17 +175,17 @@ function get_property_methods_hook(ptype, name)
         local Name = string.upper(string.sub(name, 1, 1))..string.sub(name, 2)
         return "Get"..Name, "Set"..Name
     end
-    
+
     if ptype == "is_set" then
         local Name = string.upper(string.sub(name, 1, 1))..string.sub(name, 2)
         return "Is"..Name, "Set"..Name
     end
-    
+
     if ptype == "has_set" then
         local Name = string.upper(string.sub(name, 1, 1))..string.sub(name, 2)
         return "Has"..Name, "Set"..Name
     end
-    
+
     if ptype == "no_prefix" then
         local Name = string.upper(string.sub(name, 1, 1))..string.sub(name, 2)
         return Name, "Set"..Name