diff options
-rw-r--r-- | Editor/GUI/EditorWindows.h | 7 | ||||
-rw-r--r-- | Editor/Scripting/EditorGUI/ContainerWindow.bind.cpp | 4 | ||||
-rw-r--r-- | Editor/Scripting/EditorGUI/GUIWindow.bind.cpp | 10 | ||||
-rw-r--r-- | Resources/DefaultContent/Libraries/GameLab/Engine/Math/Euler.lua | 11 | ||||
-rw-r--r-- | Resources/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua | 21 | ||||
-rw-r--r-- | Resources/DefaultContent/Libraries/GameLab/Engine/Math/Matrix3x3.lua | 7 | ||||
-rw-r--r-- | Resources/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua | 12 | ||||
-rw-r--r-- | Resources/DefaultContent/Libraries/GameLab/Engine/Math/init.lua | 7 | ||||
-rw-r--r-- | Resources/Libraries/GameLab/Editor/GUI/EditorWindow.lua | 14 | ||||
-rw-r--r-- | Resources/Scripts/EditorApplication.lua | 9 | ||||
-rw-r--r-- | Runtime/Lua/LuaBind/LuaBindClass.hpp | 630 | ||||
-rw-r--r-- | Runtime/Lua/LuaBind/LuaBindClass.inc | 628 | ||||
-rw-r--r-- | Runtime/Lua/LuaBind/LuaBindRef.cpp | 4 | ||||
-rw-r--r-- | Runtime/Lua/LuaBind/LuaBindRef.h | 25 | ||||
-rw-r--r-- | Runtime/Lua/LuaBind/LuaBindRefTable.h | 10 | ||||
-rw-r--r-- | Runtime/Lua/LuaBind/LuaBindState.h | 5 |
16 files changed, 735 insertions, 669 deletions
diff --git a/Editor/GUI/EditorWindows.h b/Editor/GUI/EditorWindows.h index ba71c06..58a37fb 100644 --- a/Editor/GUI/EditorWindows.h +++ b/Editor/GUI/EditorWindows.h @@ -159,16 +159,19 @@ private: HDC m_DC; HGLRC m_RC; - LuaBind::Ref m_Script; + LuaBind::Ref m_Instance; // EditorWindow脚本 LUA_BIND_DECL_FACTORY(GUIWindow); - LUA_BIND_DECL_METHOD(_New); + LUA_BIND_DECL_METHOD(_New); + LUA_BIND_DECL_METHOD(_GC); LUA_BIND_DECL_METHOD(_DoPaint); LUA_BIND_DECL_METHOD(_Focus); LUA_BIND_DECL_METHOD(_SetContainerWindow); LUA_BIND_DECL_METHOD(_SetPosition); + LUA_BIND_DECL_METHOD(_SetInstance); + }; #endif
\ No newline at end of file diff --git a/Editor/Scripting/EditorGUI/ContainerWindow.bind.cpp b/Editor/Scripting/EditorGUI/ContainerWindow.bind.cpp index 9c75829..75d28aa 100644 --- a/Editor/Scripting/EditorGUI/ContainerWindow.bind.cpp +++ b/Editor/Scripting/EditorGUI/ContainerWindow.bind.cpp @@ -3,10 +3,10 @@ LUA_BIND_REGISTRY(ContainerWindow) { LUA_BIND_REGISTER_METHODS(state, + { "New", _New }, { "SetTitle", _SetTitle }, { "SetIcon", _SetIcon }, - { "DoPaint", _DoPaint }, - { "New", _New } + { "DoPaint", _DoPaint } ); } diff --git a/Editor/Scripting/EditorGUI/GUIWindow.bind.cpp b/Editor/Scripting/EditorGUI/GUIWindow.bind.cpp index 50acf44..78ea635 100644 --- a/Editor/Scripting/EditorGUI/GUIWindow.bind.cpp +++ b/Editor/Scripting/EditorGUI/GUIWindow.bind.cpp @@ -7,7 +7,8 @@ LUA_BIND_REGISTRY(GUIWindow) { "Focus", _Focus }, { "SetContainerWindow", _SetContainerWindow }, { "SetPosition", _SetPosition }, - { "New", _New } + { "New", _New }, + { "__gc", _GC } ); } @@ -15,6 +16,13 @@ LUA_BIND_POSTPROCESS(GUIWindow) { } +LUA_BIND_IMPL_METHOD(GUIWindow, _GC) +{ + LUA_BIND_PREPARE(L, GUIWindow); + + return 0; +} + LUA_BIND_IMPL_METHOD(GUIWindow, _DoPaint) { LUA_BIND_PREPARE(L, GUIWindow); diff --git a/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Euler.lua b/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Euler.lua index e69de29..1f2ed78 100644 --- a/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Euler.lua +++ b/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Euler.lua @@ -0,0 +1,11 @@ +local Euler = GameLab.Class("Euler", "GameLab.Engine.Math") + +Euler.Ctor = function (self, x, y, z) + self.x = x or 0 + self.y = y or 0 + self.z = z or 0 +end + + + +return Euler
\ No newline at end of file diff --git a/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua b/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua new file mode 100644 index 0000000..4ec067e --- /dev/null +++ b/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Math.lua @@ -0,0 +1,21 @@ +-- 鏁板鍑芥暟 +GameLab.Engine.Math = GameLab.Engine.Math or {} +local m = GameLab.Engine.Math + +m.Abs = function(n) + +end + +m.Lerp = function (a, b, t) + +end + +m.Round = function (n) + +end + +m.Sign = function(n) + +end + +return m
\ No newline at end of file diff --git a/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Matrix3x3.lua b/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Matrix3x3.lua index e69de29..f7dc352 100644 --- a/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Matrix3x3.lua +++ b/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Matrix3x3.lua @@ -0,0 +1,7 @@ +local Matrix3x3 = GameLab.Class("Matrix3x3", "GameLab.Engine.Math") + +Matrix3x3.Ctor = function(self) + +end + +return Matrix3x3
\ No newline at end of file diff --git a/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua b/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua index 4c71f52..4d690e3 100644 --- a/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua +++ b/Resources/DefaultContent/Libraries/GameLab/Engine/Math/Quaternion.lua @@ -1,4 +1,14 @@ local Quaternion = {} -return Quaternion +Quaternion.Ctor = function(self) + self.x = 0 + self.y = 0 + self.z = 0 + self.w = 0 +end +Quaternion.Euler = function(euler) + +end + +return Quaternion
\ No newline at end of file diff --git a/Resources/DefaultContent/Libraries/GameLab/Engine/Math/init.lua b/Resources/DefaultContent/Libraries/GameLab/Engine/Math/init.lua index 0cf945e..662cbc4 100644 --- a/Resources/DefaultContent/Libraries/GameLab/Engine/Math/init.lua +++ b/Resources/DefaultContent/Libraries/GameLab/Engine/Math/init.lua @@ -1,10 +1,9 @@ GameLab.Engine.Math = GameLab.Engine.Math or {}
-
-local Debug = GameLab.Debug
-
local m = GameLab.Engine.Math
+
local require = GameLab.require(...)
+require("Math")
m.Vector2 = require("Vector2")
m.Vector3 = require("Vector3")
m.Vector4 = require("Vector4")
@@ -14,6 +13,6 @@ m.Quaternion = require("Quaternion") package.loaded["GameLab.Math"] = m
-Debug.Log("GameLab.Engine.Math loaded")
+GameLab.Debug.Log("GameLab.Engine.Math loaded")
return m
\ No newline at end of file diff --git a/Resources/Libraries/GameLab/Editor/GUI/EditorWindow.lua b/Resources/Libraries/GameLab/Editor/GUI/EditorWindow.lua index 99d242d..2ec7f95 100644 --- a/Resources/Libraries/GameLab/Editor/GUI/EditorWindow.lua +++ b/Resources/Libraries/GameLab/Editor/GUI/EditorWindow.lua @@ -1,10 +1,18 @@ local EditorWindow = GameLab.Class("EditorWindow", "GameLab.Editor.GUI")
-EditorWindow.Ctor = function(self, ...)
+EditorWindow.Ctor = function(self)
end
-EditorWindow.SetGUIWindow = function(self)
- print("SetGUIwidow")
+EditorWindow.OnGUI = function(self)
+end
+
+EditorWindow.OnUpdate = function(self)
+end
+
+EditorWindow.OnStart = function(self)
+end
+
+EditorWindow.OnStop = function(self)
end
return EditorWindow
\ No newline at end of file diff --git a/Resources/Scripts/EditorApplication.lua b/Resources/Scripts/EditorApplication.lua index cb4bcb0..f09a197 100644 --- a/Resources/Scripts/EditorApplication.lua +++ b/Resources/Scripts/EditorApplication.lua @@ -17,9 +17,12 @@ mainWindow:SetIcon("./Icon/GameLab.ico") app:SetMainWindow(mainWindow) local guiWindow = GUI.GUIWindow.New() -guiWindow:SetContainerWindow(mainWindow) -guiWindow:SetPosition({0,0, 500, 400}) +--guiWindow:SetContainerWindow(mainWindow) +--guiWindow:SetPosition({0,0, 500, 400}) +guiWindow.a = 10 +guiWindow = nil +collectgarbage() Debug.Log(GameLab.Path.GetRootDirectory()) @@ -37,4 +40,4 @@ while true do app:PullMessage() -end +end
\ No newline at end of file diff --git a/Runtime/Lua/LuaBind/LuaBindClass.hpp b/Runtime/Lua/LuaBind/LuaBindClass.hpp index 2bf1451..154a4ce 100644 --- a/Runtime/Lua/LuaBind/LuaBindClass.hpp +++ b/Runtime/Lua/LuaBind/LuaBindClass.hpp @@ -203,6 +203,636 @@ namespace LuaBind }; #endif + //--------------------------------------------------------------------------------// + + // + // 对不同类型,通过调用GetLuaClassName获得类型名,如果是派生类,GetClassName会被覆盖,指向luax_c_getupvalue。 + // + template<class TYPE, class BASE> + int NativeClass<TYPE, BASE>::_GetClassName(lua_State* L) + { + LUA_BIND_SETUP(L, "*"); + + cc8* type = TYPE::GetClassName(); + state.Push(type); + return 1; + } + + //--------------------------------------------------------------------------------// + + // + // 注册工厂和单例共有的类成员 + // + template<class TYPE, class BASE> + void NativeClass<TYPE, BASE>::RegisterClassShared(State& state) + { + luaL_Reg regTable[] = { + { "GetClass", _GetClass }, + { "GetClassName", _GetClassName }, + { NULL, NULL } + }; + + state.RegisterMethods(regTable); + } + + // + // 工厂类的成员,注册在class table + // + template<class TYPE, class BASE> + void NativeClass<TYPE, BASE>::RegisterFactoryClass(State& state) + { + luaL_Reg regTable[] = { + { "GetRefTable", _GetRefTable }, + { NULL, NULL } + }; + + state.RegisterMethods(regTable); + } + + // + // 单例类的成员,注册在class table + // + template<class TYPE, class BASE> + void NativeClass<TYPE, BASE>::RegisterSingletonClass(State& state) + { + luaL_Reg regTable[] = { + { NULL, NULL } + }; + + state.RegisterMethods(regTable); + } + + template<class TYPE, class BASE> + void NativeClass<TYPE, BASE>::PushClassTable(State& state) + { + assert(mClassTable); + + mClassTable.PushRef(state); + } + + template<class TYPE, class BASE> + void NativeClass<TYPE, BASE>::SetClassTableRef(State& state, int idx) + { + mClassTable.SetRef(state, idx); + } + + template<class TYPE, class BASE> + NativeClass<TYPE, BASE>::NativeClass() + : mWatchDog() +#if LUA_BIND_PROFILER + , mSafer(false) +#endif + { + } + + template<class TYPE, class BASE> + NativeClass<TYPE, BASE>::~NativeClass() + { + } + +#if LUA_BIND_PROFILER + template<class TYPE, class BASE> + void NativeClass<TYPE, BASE>::operator delete(void* pdead, size_t size) + { + if (pdead == nullptr) + return; + // 堆上创建的实例必须使用Release释放。 + TYPE* p = static_cast<TYPE*>(pdead); + assert(p->mSafer); + ::operator delete(pdead, size); + } +#endif + + template<class TYPE, class BASE> + void NativeClass<TYPE, BASE>::Retain() + { + ++mWatchDog.mNativeRef; + } + + template<class TYPE, class BASE> + void NativeClass<TYPE, BASE>::Release() + { + if (mWatchDog.mNativeRef > 0) + --mWatchDog.mNativeRef; + if (mWatchDog) + { +#if LUA_BIND_PROFILER + mSafer = true; +#endif + delete this; + } + } + + template<class TYPE, class BASE> + template<typename U> + void NativeClass<TYPE, BASE>::Retain(State& state, U* userdata) + { + if (PushRefTable(state)) + { + if (userdata->PushUserdata(state)) + { + lua_pushvalue(state, -1); // copy the userdata + lua_gettable(state, -3); // get the count (or nil) + u32 count = state.GetValue<u32>(-1, 0); // get the count (or 0) + lua_pop(state, 1); // pop the old count + lua_pushnumber(state, count + 1); // push the new count + lua_settable(state, -3); // save it in the table: reftable[userdata] = count + } + } + } + + template<class TYPE, class BASE> + template<typename U> + void NativeClass<TYPE, BASE>::Release(State& state, U* userdata) + { + if (PushRefTable(state)) + { + if (userdata->PushUserdata(state)) + { + lua_pushvalue(state, -1); // copy the userdata + lua_gettable(state, -3); // get the count (or nil) + u32 count = state.GetValue<u32>(-1, 0); // get the count (or 0) + lua_pop(state, 1); // pop the old count + + // no such reference + if (count == 0) + { + state.Pop(2); // userdata, reftable + return; // nothing to do + } + + if (count > 1) { + lua_pushnumber(state, count - 1); // push the new count + } + else { + lua_pushnil(state); // maybe cause gc + } + lua_settable(state, -3); // save it in the table + + state.Pop(1); // reftable + return; + } + state.Pop(2); // nil, reftable + return; + } + } + + template<class TYPE, class BASE> + bool NativeClass<TYPE, BASE>::PushUserdata(State& state) + { + assert(!TYPE::IsClassSingleton()); + if (!mUserdata) + { + BindToLua(state); + return true; + } + return mUserdata.PushRef(state); + } + + template<class TYPE, class BASE> + bool NativeClass<TYPE, BASE>::PushMemberTable(State& state) + { + int top = state.GetTop(); + if (this->PushUserdata(state)) + { + if (lua_getmetatable(state, -1)) // ref table + { + lua_replace(state, -2); + if (lua_getmetatable(state, -1)) // member table + { + lua_replace(state, -2); + return true; + } + } + } + lua_settop(state, top); + lua_pushnil(state); + return false; + } + + template<class TYPE, class BASE> + bool NativeClass<TYPE, BASE>::PushRefTable(State& state) + { + // Singleton + if (TYPE::IsClassSingleton()) + { + if (!this->mSingletonRefTable) { + lua_newtable(state); + this->mSingletonRefTable.SetRef(state, -1); // strong ref to member table won't be garbage collected + } + else { + this->mSingletonRefTable.PushRef(state); + } + return true; + } + // Factory + else + { + if (this->PushUserdata(state)) + { + if (lua_getmetatable(state, -1)) + { + lua_replace(state, -2); + return true; + } + } + } + return false; + } + + // 创建userdata,并以此添加ref table,member table和class table。 + // ref table 是kv强引用table,保存对其他userdata的引用计数(通过userdata作为key, + // 计数为value),以及成员引用 + // member table 保存lua创建的实例的成员 + // class table 所有本类型的实例共有的函数表 + // + // BindToLua只会在第一次注册给Lua虚拟机时调用。 + template<class TYPE, class BASE> + void NativeClass<TYPE, BASE>::BindToLua(State& state) + { + // 单例不能绑定userdata + assert(!TYPE::IsClassSingleton()); + assert(!mUserdata); + + // 创建userdata并留在栈顶,注意地址要转换为TYPE*,直接用this可能会导致多重继承的类丧失多态。 + // 如果直接传this进去,在多重继承情况下,是拿不到另一头的虚函数表的。所以这里需要将this + // 转换为整个对象的低地址,这样可以拿到另一个基类的虚函数表,通过另一个基类实现多态。 + TYPE* p = static_cast<TYPE*>(this); + state.PushPtrUserdata(p); + + lua_newtable(state); // ref table,无法在lua处访问,用来管理C对象的生命周期 + lua_newtable(state); // member table,lua中创建的对象成员都保存在这里 + PushClassTable(state); // class table + + // stack: + // -1: class table + // -2: member table + // -3: ref table + // -4: userdata + + int top = state.GetTop(); + int memberTable = top - 1; + int refTable = top - 2; + + // ref table 注册 __tostring 和 __gc + lua_pushcfunction(state, __tostring); + lua_setfield(state, refTable, "__tostring"); + + lua_pushcfunction(state, __gc); + lua_setfield(state, refTable, "__gc"); + + // ref table 的 __index 和 __newindex 设为 member table + lua_pushvalue(state, memberTable); + lua_setfield(state, refTable, "__index"); + + lua_pushvalue(state, memberTable); + lua_setfield(state, refTable, "__newindex"); + + // 设置元表 + lua_setmetatable(state, -2); // class is meta of member + lua_setmetatable(state, -2); // member is meta of ref + lua_setmetatable(state, -2); // ref is meta of userdata + + // 设置一个userdata的弱引用,方便通过PushLuaUserdata方法返回lua对象 + mUserdata.SetRef(state, -1); + assert(mUserdata); + + // 增加一个虚拟机引用,在GC时-1 + ++mWatchDog.mVMRef; +#if LUA_BIND_PROFILER + mRefVMs.insert(state.GetVM()); +#endif + } + + // + // 成员引用管理 + // + template<class TYPE, class BASE> + void NativeClass<TYPE, BASE>::SetMemberRef(State& state, MemberRef& memRef, int idx) + { + ClearMemberRef(state, memRef); + if (!lua_isnil(state, idx)) + { + idx = state.AbsIndex(idx); + if (PushRefTable(state)) + { + lua_pushvalue(state, idx); + memRef.refID = luaL_ref(state, -2); + state.Pop(); // ref table + } + } + } + + template<class TYPE, class BASE> + bool NativeClass<TYPE, BASE>::PushMemberRef(State& state, MemberRef& memRef) + { + if (memRef) + { + if (PushRefTable(state)) + { + lua_rawgeti(state, -1, memRef.refID); + lua_replace(state, -2); // ref table + if (lua_isnil(state, -1)) + goto failed; + return true; + } + } + lua_pushnil(state); + failed: + memRef.refID = LUA_NOREF; + return false; + } + + template<class TYPE, class BASE> + bool NativeClass<TYPE, BASE>::PushMemberRef(State& state, int refID) + { + if (PushRefTable(state)) + { + lua_rawgeti(state, -1, refID); + lua_replace(state, -2); // ref table + if (lua_isnil(state, -1)) + goto failed; + return true; + } + lua_pushnil(state); + failed: + return false; + } + + template<class TYPE, class BASE> + void NativeClass<TYPE, BASE>::ClearMemberRef(State& state, MemberRef& memRef) + { + if (memRef) + { + if (PushRefTable(state)) + { + luaL_unref(state, -1, memRef.refID); + state.Pop(); // ref table + } + memRef.refID = LUA_NOREF; + } + } + + //--------------------------------------------------------------------------------// + + // + // 释放工厂创建的实例 + // + template<class TYPE, class BASE> + int NativeClass<TYPE, BASE>::__gc(lua_State* L) + { + LUA_BIND_STATE(L); + + TYPE* self = state.GetUserdata<TYPE>(1); + assert(self); + +#if LUA_BIND_PROFILER + std::cout << ": GC<" << TYPE::GetClassName() << ">\n"; +#endif + + if (self->mWatchDog.mVMRef > 0) + --self->mWatchDog.mVMRef; + + self->Release(); + + return 0; + } + + // + // 输出格式如下: + // 地址 类名 + // + template<class TYPE, class BASE> + int NativeClass<TYPE, BASE>::__tostring(lua_State* L) + { + // params: + // 1: userdata + + LUA_BIND_STATE(L); + TYPE* self = state.GetUserdata<TYPE>(1); + if (self) + { + cc8* classname = ""; + lua_getfield(state, 1, "GetClassName"); + if (state.IsType(-1, LUA_TFUNCTION)) + { + lua_pushvalue(L, 1); // userdata + state.Call(1, 1); // 派生类的GetClassName函数 + classname = state.GetValue<cc8*>(-1, ""); + } + else + { + classname = TYPE::GetClassName(); + } + lua_pushfstring(L, "%s: %p", classname, self); + return 1; + } + return 0; + } + +#if LUA_BIND_ENABLE_NATIVE_EXTEND + // 派生出子类,在lua里对派生类的成员和行为进行重新设计,但是保证了userdata的统一。Native class的派生提供__init支持,在 + // native实体创建后可以使用__init进行初始化,派生类拥有和基类一样的New参数列表,且native对象是一样的类型。 + template<class TYPE, class BASE> + int NativeClass<TYPE, BASE>::_ExtendFactory(lua_State* L) + { + // upvalues: + // 1: base class + + // params: + // 1: class name + + int baseClass = lua_upvalueindex(1); + + lua_newtable(L); // class table + + int inheritClass = lua_gettop(L); + + // .GetClassName() + cc8* type = lua_tostring(L, 1); + lua_pushstring(L, type); + lua_pushcclosure(L, luax_c_getupvalue, 1); + lua_setfield(L, -2, "GetClassName"); + + // .GetClass() + lua_pushvalue(L, inheritClass); + lua_pushcclosure(L, luax_c_getupvalue, 1); + lua_setfield(L, -2, "GetClass"); + + // .Extend() + lua_pushvalue(L, inheritClass); + lua_pushcclosure(L, _ExtendFactory, 1); + lua_setfield(L, -2, "Extend"); + + // .New() + lua_pushvalue(L, inheritClass); + lua_getfield(L, baseClass, "New"); + lua_pushcclosure(L, _New, 2); + lua_setfield(L, -2, "New"); + + // __base = baseClass + lua_pushvalue(L, baseClass); + lua_setfield(L, -2, "__base"); + + // __index = inheritClass + lua_pushvalue(L, inheritClass); + lua_setfield(L, -2, "__index"); + + // metatable is baseClass + lua_pushvalue(L, baseClass); + lua_setmetatable(L, inheritClass); + + return 1; + } + + template<class TYPE, class BASE> + int NativeClass<TYPE, BASE>::_ExtendSingleton(lua_State* L) + { + // upvalues: + // 1: base class + + // params: + // 1: class name + + int baseClass = lua_upvalueindex(1); + + lua_newtable(L); // class name + + int inheritClass = lua_gettop(L); + + // .GetClassName() + cc8* type = lua_tostring(L, 1); + lua_pushstring(L, type); + lua_pushcclosure(L, luax_c_getupvalue, 1); + lua_setfield(L, -2, "GetClassName"); + + // .GetClass() + lua_pushvalue(L, inheritClass); + lua_pushcclosure(L, luax_c_getupvalue, 1); + lua_setfield(L, -2, "GetClass"); + + // .Extend() + lua_pushvalue(L, inheritClass); + lua_pushcclosure(L, _ExtendFactory, 1); + lua_setfield(L, -2, "Extend"); + + // __base = baseClass + lua_pushvalue(L, baseClass); + lua_setfield(L, -2, "__base"); + + // __index = inheritClass + lua_pushvalue(L, inheritClass); + lua_setfield(L, -2, "__index"); + + // metatable is baseClass + lua_pushvalue(L, baseClass); + lua_setmetatable(L, inheritClass); + + return 1; + } + + template<class TYPE, class BASE> + int NativeClass<TYPE, BASE>::_New(lua_State* L) + { + LUA_BIND_STATE(L); + + // upvalues: + // 1: class table + // 2: original New() + + // stack: + // -1~-n: args + + int n = lua_gettop(L); // n args + + lua_pushvalue(L, lua_upvalueindex(2)); + if (state.IsType(-1, LUA_TFUNCTION)) + { + // stack: + // -1: New + // -2~-1-n: args + + state.PushValues(-1 - n, n); + + // stack: + // -1~-n: args + // -n-1: New + // -n-2~-1-2n: args + + state.Call(n, 1); + + // stack: + // -1: userdata + // -2~-1-n: args + + // reset member table's metatable to class table + if (state.IsType(-1, LUA_TUSERDATA)) + { + if (lua_getmetatable(L, -1)) // ref table + { + if (lua_getmetatable(L, -1)) // member table + { + lua_pushvalue(L, lua_upvalueindex(1)); // class table + lua_setmetatable(L, -2); + state.Pop(); // member table + } + state.Pop(); // ref table + } + + // stack: + // -1: userdata + // -2~-1-n: args + + int args = state.AbsIndex(-1 - n); + + // 尝试调用__init函数 + lua_getfield(L, lua_upvalueindex(1), "__init"); + + if (state.IsType(-1, LUA_TFUNCTION)) + { + lua_pushvalue(L, -2); // userdata + state.PushValues(args, n); + state.Call(n + 1, 0); + } + else + state.Pop(); + + } + + return 1; + } + return 0; + } + +#endif /*LUA_BIND_ENABLE_NATIVE_EXTEND*/ + + template<class TYPE, class BASE> + int NativeClass<TYPE, BASE>::_GetClass(lua_State* L) + { + LUA_BIND_STATE(L); + if (!mClassTable) + lua_pushnil(L); + else + mClassTable.PushRef(state); + return 1; + } + + template<class TYPE, class BASE> + int NativeClass<TYPE, BASE>::_GetRefTable(lua_State* L) + { + LUA_BIND_STATE(L); + TYPE* self = state.GetUserdata<TYPE>(1); + bool success = self->PushRefTable(state); + if (!success) + lua_pushnil(L); + return 1; + } + + template<class TYPE, class BASE> StrongRef NativeClass<TYPE, BASE>::mClassTable; // class table + template<class TYPE, class BASE> StrongRef NativeClass<TYPE, BASE>::mSingletonRefTable; // 单例 + + + } #endif
\ No newline at end of file diff --git a/Runtime/Lua/LuaBind/LuaBindClass.inc b/Runtime/Lua/LuaBind/LuaBindClass.inc index 05bd9c7..3c5990e 100644 --- a/Runtime/Lua/LuaBind/LuaBindClass.inc +++ b/Runtime/Lua/LuaBind/LuaBindClass.inc @@ -1,632 +1,4 @@ namespace LuaBind { - //--------------------------------------------------------------------------------// - - // - // 对不同类型,通过调用GetLuaClassName获得类型名,如果是派生类,GetClassName会被覆盖,指向luax_c_getupvalue。 - // - template<class TYPE, class BASE> - int NativeClass<TYPE, BASE>::_GetClassName(lua_State* L) - { - LUA_BIND_SETUP(L, "*"); - - cc8* type = TYPE::GetClassName(); - state.Push(type); - return 1; - } - - //--------------------------------------------------------------------------------// - - // - // 注册工厂和单例共有的类成员 - // - template<class TYPE, class BASE> - void NativeClass<TYPE, BASE>::RegisterClassShared(State& state) - { - luaL_Reg regTable[] = { - { "GetClass", _GetClass }, - { "GetClassName", _GetClassName }, - { NULL, NULL } - }; - - state.RegisterMethods(regTable); - } - - // - // 工厂类的成员,注册在class table - // - template<class TYPE, class BASE> - void NativeClass<TYPE, BASE>::RegisterFactoryClass(State& state) - { - luaL_Reg regTable[] = { - { "GetRefTable", _GetRefTable }, - { NULL, NULL } - }; - - state.RegisterMethods(regTable); - } - - // - // 单例类的成员,注册在class table - // - template<class TYPE, class BASE> - void NativeClass<TYPE, BASE>::RegisterSingletonClass(State& state) - { - luaL_Reg regTable[] = { - { NULL, NULL } - }; - - state.RegisterMethods(regTable); - } - - template<class TYPE, class BASE> - void NativeClass<TYPE, BASE>::PushClassTable(State& state) - { - assert(mClassTable); - - mClassTable.PushRef(state); - } - - template<class TYPE, class BASE> - void NativeClass<TYPE, BASE>::SetClassTableRef(State& state, int idx) - { - mClassTable.SetRef(state, idx); - } - - template<class TYPE, class BASE> - NativeClass<TYPE, BASE>::NativeClass() - : mWatchDog() -#if LUA_BIND_PROFILER - , mSafer(false) -#endif - { - } - - template<class TYPE, class BASE> - NativeClass<TYPE, BASE>::~NativeClass() - { - } - -#if LUA_BIND_PROFILER - template<class TYPE, class BASE> - void NativeClass<TYPE, BASE>::operator delete(void* pdead, size_t size) - { - if (pdead == nullptr) - return; - // 堆上创建的实例必须使用Release释放。 - TYPE* p = static_cast<TYPE*>(pdead); - assert(p->mSafer); - ::operator delete(pdead, size); - } -#endif - - template<class TYPE, class BASE> - void NativeClass<TYPE, BASE>::Retain() - { - ++mWatchDog.mNativeRef; - } - - template<class TYPE, class BASE> - void NativeClass<TYPE, BASE>::Release() - { - if (mWatchDog.mNativeRef > 0) - --mWatchDog.mNativeRef; - if (mWatchDog) - { -#if LUA_BIND_PROFILER - mSafer = true; -#endif - delete this; - } - } - - template<class TYPE, class BASE> - template<typename U> - void NativeClass<TYPE, BASE>::Retain(State& state, U* userdata) - { - if (PushRefTable(state)) - { - if (userdata->PushUserdata(state)) - { - lua_pushvalue(state, -1); // copy the userdata - lua_gettable(state, -3); // get the count (or nil) - u32 count = state.GetValue<u32>(-1, 0); // get the count (or 0) - lua_pop(state, 1); // pop the old count - lua_pushnumber(state, count + 1); // push the new count - lua_settable(state, -3); // save it in the table: reftable[userdata] = count - } - } - } - - template<class TYPE, class BASE> - template<typename U> - void NativeClass<TYPE, BASE>::Release(State& state, U* userdata) - { - if (PushRefTable(state)) - { - if (userdata->PushUserdata(state)) - { - lua_pushvalue(state, -1); // copy the userdata - lua_gettable(state, -3); // get the count (or nil) - u32 count = state.GetValue<u32>(-1, 0); // get the count (or 0) - lua_pop(state, 1); // pop the old count - - // no such reference - if (count == 0) - { - state.Pop(2); // userdata, reftable - return; // nothing to do - } - - if (count > 1) { - lua_pushnumber(state, count - 1); // push the new count - } - else { - lua_pushnil(state); // maybe cause gc - } - lua_settable(state, -3); // save it in the table - - state.Pop(1); // reftable - return; - } - state.Pop(2); // nil, reftable - return; - } - } - - template<class TYPE, class BASE> - bool NativeClass<TYPE, BASE>::PushUserdata(State& state) - { - assert(!TYPE::IsClassSingleton()); - if (!mUserdata) - { - BindToLua(state); - return true; - } - return mUserdata.PushRef(state); - } - - template<class TYPE, class BASE> - bool NativeClass<TYPE, BASE>::PushMemberTable(State& state) - { - int top = state.GetTop(); - if (this->PushUserdata(state)) - { - if (lua_getmetatable(state, -1)) // ref table - { - lua_replace(state, -2); - if (lua_getmetatable(state, -1)) // member table - { - lua_replace(state, -2); - return true; - } - } - } - lua_settop(state, top); - lua_pushnil(state); - return false; - } - - template<class TYPE, class BASE> - bool NativeClass<TYPE, BASE>::PushRefTable(State& state) - { - // Singleton - if (TYPE::IsClassSingleton()) - { - if (!this->mSingletonRefTable) { - lua_newtable(state); - this->mSingletonRefTable.SetRef(state, -1); // strong ref to member table won't be garbage collected - } - else { - this->mSingletonRefTable.PushRef(state); - } - return true; - } - // Factory - else - { - if (this->PushUserdata(state)) - { - if (lua_getmetatable(state, -1)) - { - lua_replace(state, -2); - return true; - } - } - } - return false; - } - - // 创建userdata,并以此添加ref table,member table和class table。 - // ref table 是kv强引用table,保存对其他userdata的引用计数(通过userdata作为key, - // 计数为value),以及成员引用 - // member table 保存lua创建的实例的成员 - // class table 所有本类型的实例共有的函数表 - // - // BindToLua只会在第一次注册给Lua虚拟机时调用。 - template<class TYPE, class BASE> - void NativeClass<TYPE, BASE>::BindToLua(State& state) - { - // 单例不能绑定userdata - assert(!TYPE::IsClassSingleton()); - assert(!mUserdata); - - // 创建userdata并留在栈顶,注意地址要转换为TYPE*,直接用this可能会导致多重继承的类丧失多态。 - // 如果直接传this进去,在多重继承情况下,是拿不到另一头的虚函数表的。所以这里需要将this - // 转换为整个对象的低地址,这样可以拿到另一个基类的虚函数表,通过另一个基类实现多态。 - TYPE* p = static_cast<TYPE*>(this); - state.PushPtrUserdata(p); - - lua_newtable(state); // ref table,无法在lua处访问,用来管理C对象的生命周期 - lua_newtable(state); // member table,lua中创建的对象成员都保存在这里 - PushClassTable(state); // class table - - // stack: - // -1: class table - // -2: member table - // -3: ref table - // -4: userdata - - int top = state.GetTop(); - int memberTable = top - 1; - int refTable = top - 2; - - // ref table 注册 __tostring 和 __gc - lua_pushcfunction(state, __tostring); - lua_setfield(state, refTable, "__tostring"); - - lua_pushcfunction(state, __gc); - lua_setfield(state, refTable, "__gc"); - - // ref table 的 __index 和 __newindex 设为 member table - lua_pushvalue(state, memberTable); - lua_setfield(state, refTable, "__index"); - - lua_pushvalue(state, memberTable); - lua_setfield(state, refTable, "__newindex"); - - // 设置元表 - lua_setmetatable(state, -2); // class is meta of member - lua_setmetatable(state, -2); // member is meta of ref - lua_setmetatable(state, -2); // ref is meta of userdata - - // 设置一个userdata的弱引用,方便通过PushLuaUserdata方法返回lua对象 - mUserdata.SetRef(state, -1); - assert(mUserdata); - - // 增加一个虚拟机引用,在GC时-1 - ++mWatchDog.mVMRef; -#if LUA_BIND_PROFILER - mRefVMs.insert(state.GetVM()); -#endif - } - - // - // 成员引用管理 - // - template<class TYPE, class BASE> - void NativeClass<TYPE, BASE>::SetMemberRef(State& state, MemberRef& memRef, int idx) - { - ClearMemberRef(state, memRef); - if (!lua_isnil(state, idx)) - { - idx = state.AbsIndex(idx); - if (PushRefTable(state)) - { - lua_pushvalue(state, idx); - memRef.refID = luaL_ref(state, -2); - state.Pop(); // ref table - } - } - } - - template<class TYPE, class BASE> - bool NativeClass<TYPE, BASE>::PushMemberRef(State& state, MemberRef& memRef) - { - if (memRef) - { - if (PushRefTable(state)) - { - lua_rawgeti(state, -1, memRef.refID); - lua_replace(state, -2); // ref table - if (lua_isnil(state, -1)) - goto failed; - return true; - } - } - lua_pushnil(state); - failed: - memRef.refID = LUA_NOREF; - return false; - } - - template<class TYPE, class BASE> - bool NativeClass<TYPE, BASE>::PushMemberRef(State& state, int refID) - { - if (PushRefTable(state)) - { - lua_rawgeti(state, -1, refID); - lua_replace(state, -2); // ref table - if (lua_isnil(state, -1)) - goto failed; - return true; - } - lua_pushnil(state); - failed: - return false; - } - - template<class TYPE, class BASE> - void NativeClass<TYPE, BASE>::ClearMemberRef(State& state, MemberRef& memRef) - { - if (memRef) - { - if (PushRefTable(state)) - { - luaL_unref(state, -1, memRef.refID); - state.Pop(); // ref table - } - memRef.refID = LUA_NOREF; - } - } - - //--------------------------------------------------------------------------------// - - // - // 释放工厂创建的实例 - // - template<class TYPE, class BASE> - int NativeClass<TYPE, BASE>::__gc(lua_State* L) - { - LUA_BIND_STATE(L); - - TYPE* self = state.GetUserdata<TYPE>(1); - assert(self); - -#if LUA_BIND_PROFILER - std::cout << ": GC<" << TYPE::GetClassName() << ">\n"; -#endif - - if(self->mWatchDog.mVMRef > 0) - --self->mWatchDog.mVMRef; - - self->Release(); - - return 0; - } - - // - // 输出格式如下: - // 地址 类名 - // - template<class TYPE, class BASE> - int NativeClass<TYPE, BASE>::__tostring(lua_State* L) - { - // params: - // 1: userdata - - LUA_BIND_STATE(L); - TYPE* self = state.GetUserdata<TYPE>(1); - if (self) - { - cc8* classname = ""; - lua_getfield(state, 1, "GetClassName"); - if (state.IsType(-1, LUA_TFUNCTION)) - { - lua_pushvalue(L, 1); // userdata - state.Call(1, 1); // 派生类的GetClassName函数 - classname = state.GetValue<cc8*>(-1, ""); - } - else - { - classname = TYPE::GetClassName(); - } - lua_pushfstring(L, "%s: %p", classname, self); - return 1; - } - return 0; - } - -#if LUA_BIND_ENABLE_NATIVE_EXTEND - // 派生出子类,在lua里对派生类的成员和行为进行重新设计,但是保证了userdata的统一。Native class的派生提供__init支持,在 - // native实体创建后可以使用__init进行初始化,派生类拥有和基类一样的New参数列表,且native对象是一样的类型。 - template<class TYPE, class BASE> - int NativeClass<TYPE, BASE>::_ExtendFactory(lua_State* L) - { - // upvalues: - // 1: base class - - // params: - // 1: class name - - int baseClass = lua_upvalueindex(1); - - lua_newtable(L); // class table - - int inheritClass = lua_gettop(L); - - // .GetClassName() - cc8* type = lua_tostring(L, 1); - lua_pushstring(L, type); - lua_pushcclosure(L, luax_c_getupvalue, 1); - lua_setfield(L, -2, "GetClassName"); - - // .GetClass() - lua_pushvalue(L, inheritClass); - lua_pushcclosure(L, luax_c_getupvalue, 1); - lua_setfield(L, -2, "GetClass"); - - // .Extend() - lua_pushvalue(L, inheritClass); - lua_pushcclosure(L, _ExtendFactory, 1); - lua_setfield(L, -2, "Extend"); - - // .New() - lua_pushvalue(L, inheritClass); - lua_getfield(L, baseClass, "New"); - lua_pushcclosure(L, _New, 2); - lua_setfield(L, -2, "New"); - - // __base = baseClass - lua_pushvalue(L, baseClass); - lua_setfield(L, -2, "__base"); - - // __index = inheritClass - lua_pushvalue(L, inheritClass); - lua_setfield(L, -2, "__index"); - - // metatable is baseClass - lua_pushvalue(L, baseClass); - lua_setmetatable(L, inheritClass); - - return 1; - } - - template<class TYPE, class BASE> - int NativeClass<TYPE, BASE>::_ExtendSingleton(lua_State* L) - { - // upvalues: - // 1: base class - - // params: - // 1: class name - - int baseClass = lua_upvalueindex(1); - - lua_newtable(L); // class name - - int inheritClass = lua_gettop(L); - - // .GetClassName() - cc8* type = lua_tostring(L, 1); - lua_pushstring(L, type); - lua_pushcclosure(L, luax_c_getupvalue, 1); - lua_setfield(L, -2, "GetClassName"); - - // .GetClass() - lua_pushvalue(L, inheritClass); - lua_pushcclosure(L, luax_c_getupvalue, 1); - lua_setfield(L, -2, "GetClass"); - - // .Extend() - lua_pushvalue(L, inheritClass); - lua_pushcclosure(L, _ExtendFactory, 1); - lua_setfield(L, -2, "Extend"); - - // __base = baseClass - lua_pushvalue(L, baseClass); - lua_setfield(L, -2, "__base"); - - // __index = inheritClass - lua_pushvalue(L, inheritClass); - lua_setfield(L, -2, "__index"); - - // metatable is baseClass - lua_pushvalue(L, baseClass); - lua_setmetatable(L, inheritClass); - - return 1; - } - - template<class TYPE, class BASE> - int NativeClass<TYPE, BASE>::_New(lua_State* L) - { - LUA_BIND_STATE(L); - - // upvalues: - // 1: class table - // 2: original New() - - // stack: - // -1~-n: args - - int n = lua_gettop(L); // n args - - lua_pushvalue(L, lua_upvalueindex(2)); - if (state.IsType(-1, LUA_TFUNCTION)) - { - // stack: - // -1: New - // -2~-1-n: args - - state.PushValues(-1 - n, n); - - // stack: - // -1~-n: args - // -n-1: New - // -n-2~-1-2n: args - - state.Call(n, 1); - - // stack: - // -1: userdata - // -2~-1-n: args - - // reset member table's metatable to class table - if (state.IsType(-1, LUA_TUSERDATA)) - { - if (lua_getmetatable(L, -1)) // ref table - { - if (lua_getmetatable(L, -1)) // member table - { - lua_pushvalue(L, lua_upvalueindex(1)); // class table - lua_setmetatable(L, -2); - state.Pop(); // member table - } - state.Pop(); // ref table - } - - // stack: - // -1: userdata - // -2~-1-n: args - - int args = state.AbsIndex(-1 - n); - - // 尝试调用__init函数 - lua_getfield(L, lua_upvalueindex(1), "__init"); - - if (state.IsType(-1, LUA_TFUNCTION)) - { - lua_pushvalue(L, -2); // userdata - state.PushValues(args, n); - state.Call(n + 1, 0); - } - else - state.Pop(); - - } - - return 1; - } - return 0; - } - -#endif /*LUA_BIND_ENABLE_NATIVE_EXTEND*/ - - template<class TYPE, class BASE> - int NativeClass<TYPE, BASE>::_GetClass(lua_State* L) - { - LUA_BIND_STATE(L); - if (!mClassTable) - lua_pushnil(L); - else - mClassTable.PushRef(state); - return 1; - } - - template<class TYPE, class BASE> - int NativeClass<TYPE, BASE>::_GetRefTable(lua_State* L) - { - LUA_BIND_STATE(L); - TYPE* self = state.GetUserdata<TYPE>(1); - bool success = self->PushRefTable(state); - if (!success) - lua_pushnil(L); - return 1; - } - - template<class TYPE, class BASE> StrongRef NativeClass<TYPE, BASE>::mClassTable; // class table - template<class TYPE, class BASE> StrongRef NativeClass<TYPE, BASE>::mSingletonRefTable; // 单例 - }
\ No newline at end of file diff --git a/Runtime/Lua/LuaBind/LuaBindRef.cpp b/Runtime/Lua/LuaBind/LuaBindRef.cpp index 00a65d0..676525a 100644 --- a/Runtime/Lua/LuaBind/LuaBindRef.cpp +++ b/Runtime/Lua/LuaBind/LuaBindRef.cpp @@ -4,7 +4,7 @@ namespace LuaBind { - Ref::Ref(int mode) + Ref::Ref(RefMode mode) : mRefID(LUA_NOREF) , mMode(mode) { @@ -12,6 +12,8 @@ namespace LuaBind Ref::~Ref() { + // 自动释放引用 + } Ref::operator bool() diff --git a/Runtime/Lua/LuaBind/LuaBindRef.h b/Runtime/Lua/LuaBind/LuaBindRef.h index 93b30be..7058094 100644 --- a/Runtime/Lua/LuaBind/LuaBindRef.h +++ b/Runtime/Lua/LuaBind/LuaBindRef.h @@ -7,9 +7,7 @@ namespace LuaBind { - // - // 引用,存在LUA_REGISTRYINDEX下面的两个表里 - // + // 全局引用,保存在LUA_REGISTRYINDEX下面的两个表里 class Ref { public: @@ -20,26 +18,29 @@ namespace LuaBind WEAK_REF }; - Ref(int mode = STRONG_REF); + Ref(RefMode mode = STRONG_REF); virtual ~Ref(); operator bool(); + // 将栈上的对象添加到全局引用表中 void SetRef(State& state, int idx); + + // 将引用的对象压入栈 bool PushRef(State& state); - int GetRefID(); + int GetRefID() { return mRefID; } + + RefMode GetRefMode() { return mMode; } private: - int mRefID; // luaL_ref - int mMode; // strong or weak + int mRefID; + RefMode mMode; }; - // - // 强引用,在LUA_REGISTRYINDEX["_LUA_BIND_STRONGREF_TABLE"]里,保证lua object不会被回收。 - // + // 强引用,在LUA_REGISTRYINDEX["GAMELAB_UNIVERSAL_STRONG_REFERENCE_TABLE"]里,保证lua object不会被回收 class StrongRef: public Ref { public: @@ -47,9 +48,7 @@ namespace LuaBind }; - // - // 弱引用,在LUA_REGISTRYINDEX["_LUA_BIND_WEAKREF_TABLE"]里,不影响lua object的回收,只是作为一个方便取lua object的映射。 - // + // 弱引用,在LUA_REGISTRYINDEX["GAMELAB_UNIVERSAL_WEAK_REFERENCE_TABLE"]里,不影响lua object的回收,只是作为一个方便取lua object的映射 class WeakRef : public Ref { public: diff --git a/Runtime/Lua/LuaBind/LuaBindRefTable.h b/Runtime/Lua/LuaBind/LuaBindRefTable.h index 0d4c2d4..3401a53 100644 --- a/Runtime/Lua/LuaBind/LuaBindRefTable.h +++ b/Runtime/Lua/LuaBind/LuaBindRefTable.h @@ -8,9 +8,7 @@ namespace LuaBind class State; - // // ref table 管理,对strong ref table和weak ref table两个table的代理。 - // class RefTable { public: @@ -31,25 +29,17 @@ namespace LuaBind bool IsKeyWeak(); bool IsValueWeak(); - // // 对stack[idx]的实体在此ref table中增加一个引用,并返回refID - // int Ref(State& state, int idx); void Unref(State& state, int refID); - // // 将此 ref table 放在栈顶 - // void PushRefTable(State& state); - // // 将 reftable[refID] 放在栈顶 - // void PushRef(State& state, int refID); - // // 清空 ref table,表还留在LUA_REGISTRYINDEX[mName] - // void Clear(State& state); private: diff --git a/Runtime/Lua/LuaBind/LuaBindState.h b/Runtime/Lua/LuaBind/LuaBindState.h index ec2a350..9028583 100644 --- a/Runtime/Lua/LuaBind/LuaBindState.h +++ b/Runtime/Lua/LuaBind/LuaBindState.h @@ -286,10 +286,13 @@ namespace LuaBind TYPE::RegisterFactoryClass(state); TYPE::RegisterClass(state); - // 自定义流程 + // 自定义注册内容 if (onRegisterFactoryClass) onRegisterFactoryClass(state, clsIdx, type, g_NameSpace); + // 清理栈 + lua_settop(state, clsIdx); + // 检测TYPE里面是否没有注册必须的方法 #define _assertmethod(I, NAME) \ GetField(I, NAME); \ |