diff --git a/build/Lol (vs2013).sln b/build/Lol (vs2013).sln index f35810b7..32ddb035 100644 --- a/build/Lol (vs2013).sln +++ b/build/Lol (vs2013).sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +VisualStudioVersion = 12.0.21005.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "deushax", "..\games\deushax\deushax.vcxproj", "{EF1A4E80-63FA-4EB0-B834-12B6C500F31C}" EndProject @@ -153,6 +153,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Doc", "Doc", "{65FD48E9-C93 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared", "..\people\touky\shared\shared.vcxproj", "{EE203B88-44CF-4859-9D42-7A4F43FEDB52}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "14_lol_lua", "..\doc\tutorial\14_lol_lua.vcxproj", "{81C83B42-D00A-4FA3-9A3D-80F9D46524BF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ORBIS = Debug|ORBIS @@ -626,6 +628,16 @@ Global {EE203B88-44CF-4859-9D42-7A4F43FEDB52}.Release|Win32.Build.0 = Release|Win32 {EE203B88-44CF-4859-9D42-7A4F43FEDB52}.Release|x64.ActiveCfg = Release|x64 {EE203B88-44CF-4859-9D42-7A4F43FEDB52}.Release|x64.Build.0 = Release|x64 + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF}.Debug|ORBIS.ActiveCfg = Debug|Win32 + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF}.Debug|Win32.ActiveCfg = Debug|Win32 + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF}.Debug|Win32.Build.0 = Debug|Win32 + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF}.Debug|x64.ActiveCfg = Debug|x64 + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF}.Debug|x64.Build.0 = Debug|x64 + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF}.Release|ORBIS.ActiveCfg = Release|Win32 + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF}.Release|Win32.ActiveCfg = Release|Win32 + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF}.Release|Win32.Build.0 = Release|Win32 + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF}.Release|x64.ActiveCfg = Release|x64 + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -667,6 +679,7 @@ Global {572E5B9C-7E19-489C-BD8A-E8401CFBBC47} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} {E05E23A5-67DE-42B5-98A3-E63CCE0CC0AF} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} {F59FA82C-DDB9-4EE2-80AE-CB0E4C6567A4} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF} = {E74CF679-CA2A-47E9-B1F4-3779D6AC6B04} {32F3F8CF-D22E-45E4-BEB8-AD909E8C5515} = {33704AA4-F2B5-4138-A40D-E3E77F89ED46} {EE203B88-44CF-4859-9D42-7A5F40FECB52} = {8C77EAA8-1077-4EF7-AE53-97C6C60A3601} {B357514A-7881-422D-8358-161B689E7620} = {3D341D8A-E400-4B1D-BC05-B5C35487D9B5} diff --git a/doc/tutorial/14_lol_lua.cpp b/doc/tutorial/14_lol_lua.cpp new file mode 100644 index 00000000..c6fd88e0 --- /dev/null +++ b/doc/tutorial/14_lol_lua.cpp @@ -0,0 +1,290 @@ +// +// Lol Engine - Graphing tutorial +// +// Copyright: (c) 2012-2013 Sam Hocevar +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "loldebug.h" +#include + +using namespace lol; + +//----------------------------------------------------------------------------- +class FooTest +{ +public: + FooTest() + { + } + static int New(Lolua::State* l) + { + int n_args = lua_gettop(l); // Number of arguments + + // We could actually allocate Foo itself as a user data but + // since user data can be GC'ed and we gain unity by using CRT's heap + // all along. + FooTest** udata = (FooTest**)lua_newuserdata(l, sizeof(FooTest*)); + *udata = new FooTest(); + + // Usually, we'll just use "Foo" as the second parameter, but I + // say luaL_Foo here to distinguish the difference: + // + // This 2nd parameter here is an _internal label_ for luaL, it is + // _not_ exposed to Lua by default. + // + // Effectively, this metatable is not accessible by Lua by default. + //luaL_getmetatable(l, m_table_name); + + // The Lua stack at this point looks like this: + // + // 3| metatable "luaL_foo" |-1 + // 2| userdata |-2 + // 1| string parameter |-3 + // + // So the following line sets the metatable for the user data to the luaL_Foo + // metatable + // + // We must set the metatable here because Lua prohibits setting + // the metatable of a userdata in Lua. The only way to set a metatable + // of a userdata is to do it in C. + //lua_setmetatable(l, -2); + + luaL_getmetatable(l, m_table2_name); + lua_setmetatable(l, -2); + + // The Lua stack at this point looks like this: + // + // 2| userdata |-1 + // 1| string parameter |-2 + // + // We return 1 so Lua callsite will get the user data and + // Lua will clean the stack after that. + + return 1; + } + static FooTest* Check(Lolua::State* l, int n) + { + // This checks that the argument is a userdata + // with the metatable "luaL_Foo" + return *(FooTest**)luaL_testudata(l, n, m_table2_name); + } + static int Del(Lolua::State * l) + { + FooTest* foo = Check(l, 1); + delete foo; + + return 0; + } + static void Register(Lolua::State * l) + { + // Create a luaL metatable. This metatable is not + // exposed to Lua. The "luaL_Foo" label is used by luaL + // internally to identity things. + luaL_newmetatable(l, m_table2_name); + luaL_setfuncs(l, FooTest::m_statics2, 0); + lua_pushvalue(l, -1); + lua_setfield(l, -1, "__index"); + //lua_setglobal(l, m_class2_name); + lua_pop(l, 1); + + // Create a luaL metatable. This metatable is not + // exposed to Lua. The "luaL_Foo" label is used by luaL + // internally to identity things. + luaL_newmetatable(l, m_table_name); + + // Register the C functions _into_ the metatable we just created. + luaL_setfuncs(l, FooTest::m_statics, 0); + + // The Lua stack at this point looks like this: + // + // 1| metatable "luaL_Foo" |-1 + lua_pushvalue(l, -1); + + // The Lua stack at this point looks like this: + // + // 2| metatable "luaL_Foo" |-1 + // 1| metatable "luaL_Foo" |-2 + + // Set the "__index" field of the metatable to point to itself + // This pops the stack + lua_setfield(l, -1, "__index"); + + // The Lua stack at this point looks like this: + // + // 1| metatable "luaL_Foo" |-1 + + // The luaL_Foo metatable now has the following fields + // - __gc + // - __index + // - new + + // Now we use setglobal to officially expose the luaL_Foo metatable + // to Lua. And we use the name "Foo". + // + // This allows Lua scripts to _override_ the metatable of Foo. + // For high security code this may not be called for but + // we'll do this to get greater flexibility. + lua_setglobal(l, m_class_name); + } + static int Test1(Lolua::State* L) + { + Lolua::Var i1(L, 1); + i1 += 5; + return i1.Return(L); + } + static int Test2(Lolua::State* L) + { + FooTest* foo = Check(L, 1); + Lolua::Var i1(L, 2); + i1 = foo->Test2Inst(i1.V()); + return i1.Return(L); + } + float Test2Inst(float f) + { + return (f + 10); + } + + static const char m_class_name[]; + static const char m_class2_name[]; + static const char m_table_name[]; + static const char m_table2_name[]; + static const luaL_Reg m_statics[]; + static const luaL_Reg m_statics2[]; + static const luaL_Reg m_methods[]; +}; + +const luaL_Reg FooTest::m_statics[] = { + { "New", &FooTest::New }, + { "__gc", &FooTest::Del }, + { "Test1", &FooTest::Test1 }, + { NULL, NULL } }; +const luaL_Reg FooTest::m_statics2[] = { + { "Test2", &FooTest::Test2 }, + { NULL, NULL } }; +const luaL_Reg FooTest::m_methods[] = { { NULL, NULL } }; +const char FooTest::m_class_name[] = "FooTest"; +const char FooTest::m_class2_name[] = "FooTest2"; +const char FooTest::m_table_name[] = "FooTest_mt"; +const char FooTest::m_table2_name[] = "FooTest_mt2"; + +typedef Lolua::ObjectDef FooTestLuaBase; +class FooTestLua : public FooTestLuaBase +{ +public: + FooTestLua() : FooTestLuaBase() {} + virtual ~FooTestLua() {} + static FooTestLua* New(Lolua::State* l, int arg_nb) + { + return new FooTestLua(); + } + static const char* GetClassName(); + static const char* GetClassLibName(); + static const char* GetClassInstName(); + static const Lolua::ClassMethod* GetStaticMethods(); + static const Lolua::ClassMethod* GetInstanceMethods(); + static int Test1(Lolua::State* L) + { + Lolua::Var i1(L, 1); + i1 += 5; + return i1.Return(L); + } + static int Test2(Lolua::State* L) + { + Lolua::VarPtr foo(L, 1); + Lolua::Var i1(L, 2); + i1 = foo.V()->Test2Inst(i1.V()); + return i1.Return(L); + } + float Test2Inst(float f) + { + return (f + 10); + } +}; + +static const Lolua::ClassMethod FooTest_statics[] = { { "Test1", &FooTestLua::Test1 }, { NULL, NULL } }; +const Lolua::ClassMethod FooTest_methods[] = { { "Test2", &FooTestLua::Test2 }, { NULL, NULL } }; + +const char* FooTestLua::GetClassName() { static const char name[] = "FooTest"; return name; } +const char* FooTestLua::GetClassLibName() { static const char name[] = "FooTestLib"; return name; } +const char* FooTestLua::GetClassInstName() { static const char name[] = "FooTestInst"; return name; } +const Lolua::ClassMethod* FooTestLua::GetStaticMethods() { return FooTest_statics; } +const Lolua::ClassMethod* FooTestLua::GetInstanceMethods() { return FooTest_methods; } + +//----------------------------------------------------------------------------- +class LoluaDemoLoader : public Lolua::Loader +{ +public: + LoluaDemoLoader() : Lolua::Loader() + { + Lolua::State* l = GetLuaState(); + + Lolua::Object::Register(l); + + ExecLua("14_lol_lua.lua"); + } + virtual ~LoluaDemoLoader() + { + + } +}; + +//----------------------------------------------------------------------------- +class LoluaDemo : public WorldEntity +{ +public: + LoluaDemo() + { + } + + virtual void TickGame(float seconds) + { + WorldEntity::TickGame(seconds); + + LoluaDemoLoader* demo_loader = new LoluaDemoLoader(); + + float TestValueNum = demo_loader->GetVar("TestValueNum"); + int32_t TestValueInt = demo_loader->GetVar("TestValueInt"); + uint32_t TestValueUint = demo_loader->GetVar("TestValueUint"); + String TestValueStr = demo_loader->GetVar("TestValueStr"); + //String test_return2 = demo_loader->GetVar("test_return2"); + //String test_return3 = demo_loader->GetVar("test_return3"); + int32_t testtruc_return = demo_loader->GetVar("footest_return"); + float testtruc_return2 = demo_loader->GetVar("footest_return2"); + //int32_t testtruc2_return = demo_loader->GetVar("testtruc_return2"); + + String::Printf("Lua Vars: TestValueNum: %.2f, TestValueInt: %i, TestValueUint: %i, TestValueStr: %s.", + TestValueNum, TestValueInt, TestValueUint, TestValueStr); + + delete demo_loader; + + Ticker::Shutdown(); + } + + virtual void TickDraw(float seconds, Scene &scene) + { + WorldEntity::TickDraw(seconds, scene); + } +}; + +//----------------------------------------------------------------------------- +int main(int argc, char **argv) +{ + System::Init(argc, argv); + + Application app("Tutorial 14: Lolua Demo", ivec2(800, 600), 60.0f); + + new LoluaDemo(); + + app.Run(); + return EXIT_SUCCESS; +} + diff --git a/doc/tutorial/14_lol_lua.lua b/doc/tutorial/14_lol_lua.lua new file mode 100644 index 00000000..023dd19d --- /dev/null +++ b/doc/tutorial/14_lol_lua.lua @@ -0,0 +1,16 @@ +-- Number +TestValueNum = 900.0 +-- Integer +TestValueInt = -900 +-- Unsigned +TestValueUint = 900 +-- String +TestValueStr = "900" + +footest_return = FooTest.Test1(1); +footest_inst = FooTest.New(1,2); +footest_return2 = footest_inst:Test2(2.0); +-- test_return3 = sTest2("bruttruc"); +-- testtruc_return2 = Testtruc.Test2(2); +-- test_return2 = Testtruc:Test2("brut"); +-- test_return = LoluaTestObj:getTest(1, "brut"); \ No newline at end of file diff --git a/doc/tutorial/14_lol_lua.vcxproj b/doc/tutorial/14_lol_lua.vcxproj new file mode 100644 index 00000000..b94d91d9 --- /dev/null +++ b/doc/tutorial/14_lol_lua.vcxproj @@ -0,0 +1,76 @@ + + + + + Debug + ORBIS + + + Debug + Win32 + + + Debug + x64 + + + Debug + Xbox 360 + + + Release + ORBIS + + + Release + Win32 + + + Release + x64 + + + Release + Xbox 360 + + + + + {9e62f2fe-3408-4eae-8238-fd84238ceeda} + + + {83d3b207-c601-4025-8f41-01dedc354661} + + + {d84021ca-b233-4e0f-8a52-071b83bbccc4} + + + + + + + + true + + + + {81C83B42-D00A-4FA3-9A3D-80F9D46524BF} + Application + Win32Proj + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/tutorial/Makefile.am b/doc/tutorial/Makefile.am index 51a32b4e..e67bfdbb 100644 --- a/doc/tutorial/Makefile.am +++ b/doc/tutorial/Makefile.am @@ -3,7 +3,7 @@ include $(top_srcdir)/build/autotools/common.am noinst_PROGRAMS = 01_triangle 02_cube 03_noise 04_texture 05_easymesh \ 06_sprite 07_input 08_fbo 11_fractal \ - 12_voronoi 13_shader_builder + 12_voronoi 13_shader_builder 14_lol_lua 01_triangle_SOURCES = 01_triangle.cpp 01_triangle.lolfx 01_triangle_CPPFLAGS = $(AM_CPPFLAGS) @@ -55,3 +55,7 @@ endif 13_shader_builder_CPPFLAGS = $(AM_CPPFLAGS) 13_shader_builder_DEPENDENCIES = @LOL_DEPS@ +14_lol_lua_SOURCES = 14_lol_lua.cpp +14_lol_lua_CPPFLAGS = $(AM_CPPFLAGS) +14_lol_lua_DEPENDENCIES = @LOL_DEPS@ + diff --git a/src/application/baselua.cpp b/src/application/baselua.cpp index 6ce13280..ebffd242 100644 --- a/src/application/baselua.cpp +++ b/src/application/baselua.cpp @@ -23,9 +23,9 @@ namespace lol //----------------------------------------------------------------------------- class LuaBaseData { - friend class LuaLoader; + friend class Lolua::Loader; - static int LuaPanic(lua_State* L) + static int LuaPanic(Lolua::State* L) { char const *message = lua_tostring(L, -1); Log::Error("%s\n", message); @@ -33,12 +33,12 @@ class LuaBaseData return 0; } - static int LuaDoFile(lua_State *L) + static int LuaDoFile(Lolua::State *L) { if (lua_isnoneornil(L, 1)) return LUA_ERRFILE; - LuaVar var(L, 1); + Lolua::Var var(L, 1); char const *filename = var.V();// lua_tostring(L, 1); int status = LUA_ERRFILE; @@ -67,25 +67,28 @@ class LuaBaseData } }; +namespace Lolua +{ + //----------------------------------------------------------------------------- -LuaLoader::LuaLoader() +Loader::Loader() { m_lua_state = luaL_newstate(); lua_atpanic(m_lua_state, LuaBaseData::LuaPanic); luaL_openlibs(m_lua_state); /* Override dofile() */ - LuaFunction do_file(m_lua_state, "dofile", LuaBaseData::LuaDoFile); + Lolua::Function do_file(m_lua_state, "dofile", LuaBaseData::LuaDoFile); } //----------------------------------------------------------------------------- -LuaLoader::~LuaLoader() +Loader::~Loader() { lua_close(m_lua_state); } //----------------------------------------------------------------------------- -bool LuaLoader::ExecLua(String const &lua) +bool Loader::ExecLua(String const &lua) { const char* c = lua_pushstring(m_lua_state, lua.C()); int status = LuaBaseData::LuaDoFile(m_lua_state); @@ -93,10 +96,12 @@ bool LuaLoader::ExecLua(String const &lua) } //----------------------------------------------------------------------------- -lua_State* LuaLoader::GetLuaState() +Lolua::State* Loader::GetLuaState() { return m_lua_state; } +} /* namespace Lolua */ + } /* namespace lol */ diff --git a/src/application/baselua.h b/src/application/baselua.h index 7e886b8c..82efa350 100644 --- a/src/application/baselua.h +++ b/src/application/baselua.h @@ -12,42 +12,137 @@ // #include "lua/lua.hpp" -#include "lua/luawrapper.hpp" +//#include "lua/luawrapper.hpp" #pragma once namespace lol { +//----------------------------------------------------------------------------- +namespace Lolua +{ + +//----------------------------------------------------------------------------- +typedef luaL_Reg ClassMethod; +typedef lua_State State; + +//----------------------------------------------------------------------------- +template +class ObjectDef +{ +public: + ObjectDef() { } + virtual ~ObjectDef() { } + static ObjectDef* New(State* l, int arg_nb) + { + UNUSED(l); + UNUSED(arg_nb); + ASSERT(false); + return nullptr; + } + static const char* GetClassName() { ASSERT(false); return nullptr; } + static const char* GetClassLibName() { ASSERT(false); return nullptr;; } + static const char* GetClassInstName() { ASSERT(false); return nullptr; } + static const ClassMethod* GetStaticMethods() { ASSERT(false); return nullptr; } + static const ClassMethod* GetInstanceMethods() { ASSERT(false); return nullptr; } + +protected: + T* m_instance = nullptr; +}; + //----------------------------------------------------------------------------- // Class available to link C++ class to Lua methods //-- -class LuaObject +class Object { -protected: - template - struct LuaLibrary +public: + //------------------------------------------------------------------------- + Object() { } + virtual ~Object() { } + + //------------------------------------------------------------------------- + template + static void Register(State *l) { - LuaLibrary() { } - void LoadTo(lua_State* l) + //Default statics + static const luaL_Reg default_statics[] { -#define LOLUA_WRAPPER 1 -#if LOLUA_WRAPPER - luaW_register(l, name, statics, methods, ctor); -#else - luaL_newlib(L, statics); - luaL_newlib(L, methods); -#endif - } - }; + { "New", New }, + { "__gc", Del }, + { NULL, NULL } + }; + //TODO: Touky: Implement that + //__tostring : ToString + //__add : Addition(+) + //__sub : Subtraction(-) + //__mul : Multiplication(*) + //__div : Division(/ ) + //__mod : Modulos(%) + //__unm : Unary - , used for negation on numbers + //__concat : Concatenation(..) + //__eq : Equality(== ) + //__lt : Less than(<) + //__le : Less than or equal to(<= ) + + //Create Static metatable + luaL_newmetatable(l, TLuaClass::GetClassLibName()); + //Register default statics and template one + luaL_setfuncs(l, default_statics, 0); + luaL_setfuncs(l, TLuaClass::GetStaticMethods(), 0); + //Push funcs on metatable + lua_pushvalue(l, -1); + //Set the "__index" field of the metatable to point to itself, pops the stack + lua_setfield(l, -1, "__index"); + //Set it global to validate the operation + lua_setglobal(l, TLuaClass::GetClassName()); + + //Repeat all the operations for instance metatable + luaL_newmetatable(l, TLuaClass::GetClassInstName()); + luaL_setfuncs(l, TLuaClass::GetInstanceMethods(), 0); + lua_pushvalue(l, -1); + lua_setfield(l, -1, "__index"); + //Don't set it to global, but pop the stack to hide the metatable + lua_pop(l, 1); + } + +protected: + //------------------------------------------------------------------------- + template + static int New(State* l) + { + //Number of arguments + int n_args = lua_gettop(l); + + //Create user data + TLuaClass** data = (TLuaClass**)lua_newuserdata(l, sizeof(TLuaClass*)); + *data = TLuaClass::New(l, n_args); + + //Retrieve instance table + luaL_getmetatable(l, TLuaClass::GetClassInstName()); + //Set metatable to instance + lua_setmetatable(l, -2); + //Return 1 so Lua will get the UserData and clean the stack. + return 1; + } + + //------------------------------------------------------------------------- + template + static int Del(State * l) + { + VarPtr obj(l, 1); + ASSERT(obj.V()); + delete obj.V(); + return 0; + } }; //----------------------------------------------------------------------------- // //-- -struct LuaFunction +struct Function { - LuaFunction(lua_State* l, const char* name, int (*function)(lua_State*)) + Function(State* l, const char* name, int(*function)(State*)) { lua_pushcfunction(l, function); lua_setglobal(l, name); @@ -56,67 +151,113 @@ struct LuaFunction //----------------------------------------------------------------------------- template -struct LuaVar +struct VarPtr { -private: - T m_value = T(0); +protected: + T* m_value = nullptr; public: - LuaVar() { } - LuaVar(T value) { m_value = value; } - LuaVar(lua_State* l, int index) { InnerGet(l, index); } - inline T& V() { return m_value; } - inline T& operator=(const T& value) { m_value = value; } - inline int Return(lua_State* l) { InnerPush(l); return 1; } + VarPtr() { } + VarPtr(T* value) { m_value = value; } + VarPtr(State* l, int index) { InnerGet(l, index); } + inline T* V() { return m_value; } + inline T* operator=(T* value) { m_value = value; } + inline int Return(State* l) { InnerPush(l); return 1; } -private: - void InnerGet(lua_State* l, int index) { ASSERT(false); } - void InnerPush(lua_State* l) { ASSERT(false); } +protected: + virtual void InnerGet(State* l, int index) + { + T** obj = static_cast(luaL_checkudata(l, index, T::GetClassInstName())); + m_value = obj ? *obj : nullptr; + } + void InnerPush(State* l) + { + T** data = (T**)lua_newuserdata(l, sizeof(T*)); + *data = m_value; + } +}; +//----------------------------------------------------------------------------- +template +struct VarPtrLight +{ +public: + VarPtrLight() : VarPtr() { } + VarPtrLight(T* value) : VarPtr(T* value) { } + VarPtrLight(State* l, int index) : VarPtr(State* l, int index) { } +protected: + virtual void InnerGet(State* l, int index) + { + T** obj = static_cast(luaL_testudata(l, index, T::GetClassInstName())); + m_value = obj ? *obj : nullptr; + } }; //----------------------------------------------------------------------------- template -struct LuaPtr +struct Var { private: - T* m_value = nullptr; + T m_value; public: - LuaPtr() { } - LuaPtr(T* value) { m_value = value; } - LuaPtr(lua_State* l, int index) { InnerGet(l, index); } - inline T* V() { return m_value; } - inline T* operator=(T* value) { m_value = value; } - inline int Return(lua_State* l) { InnerPush(l); return 1; } + Var() { InnerInit(); } + Var(T value) { m_value = value; } + Var(State* l, int index) { InnerGet(l, index); } + inline T& V() { return m_value; } + inline int Return(State* l) { InnerPush(l); return 1; } + inline Var& operator-(const T& value) { m_value - value; return *this; } + inline Var& operator+(const T& value) { m_value + value; return *this; } + inline Var& operator*(const T& value) { m_value * value; return *this; } + inline Var& operator/(const T& value) { m_value / value; return *this; } + inline Var& operator=(const T& value) { m_value = value; return *this; } + inline Var& operator-=(const T& value) { m_value -= value; return *this; } + inline Var& operator+=(const T& value) { m_value += value; return *this; } + inline Var& operator*=(const T& value) { m_value *= value; return *this; } + inline Var& operator/=(const T& value) { m_value /= value; return *this; } + inline Var& operator-(const Var& o) { m_value - o.m_value; return *this; } + inline Var& operator+(const Var& o) { m_value + o.m_value; return *this; } + inline Var& operator*(const Var& o) { m_value * o.m_value; return *this; } + inline Var& operator/(const Var& o) { m_value / o.m_value; return *this; } + inline Var& operator=(const Var& o) { m_value = o.m_value; return *this; } + inline Var& operator-=(const Var& o) { m_value -= o.m_value; return *this; } + inline Var& operator+=(const Var& o) { m_value += o.m_value; return *this; } + inline Var& operator*=(const Var& o) { m_value *= o.m_value; return *this; } + inline Var& operator/=(const Var& o) { m_value /= o.m_value; return *this; } + inline bool operator==(const T& value) { return m_value == value; } + inline bool operator!=(const T& value) { return m_value != value; } + inline bool operator==(const Var& o) { return m_value == o.m_value; } + inline bool operator!=(const Var& o) { return m_value != o.m_value; } private: - void InnerGet(lua_State* l, int index) { m_value = luaW_check(l, index); } - void InnerPush(lua_State* l) { luaW_push(l, m_value); } + void InnerInit() { m_value = T(0); } + void InnerGet(State* l, int index) { ASSERT(false); } + void InnerPush(State* l) { ASSERT(false); } }; //----------------------------------------------------------------------------- -template<> inline void LuaVar ::InnerGet(lua_State* l, int index) { m_value = lua_tostring(l, index); } -template<> inline void LuaVar::InnerGet(lua_State* l, int index) { m_value = lua_tostring(l, index); } -template<> inline void LuaVar ::InnerGet(lua_State* l, int index) { m_value = lua_tonumber(l, index); } -template<> inline void LuaVar ::InnerGet(lua_State* l, int index) { m_value = (float)lua_tonumber(l, index); } -template<> inline void LuaVar ::InnerGet(lua_State* l, int index) { m_value = (int32_t)lua_tointeger(l, index); } -template<> inline void LuaVar ::InnerGet(lua_State* l, int index) { m_value = lua_tointeger(l, index); } -template<> inline void LuaVar ::InnerGet(lua_State* l, int index) { m_value = lua_tounsigned(l, index); } - -template<> inline void LuaVar ::InnerPush(lua_State* l) { lua_pushstring(l, m_value.C()); } -template<> inline void LuaVar::InnerPush(lua_State* l) { lua_pushstring(l, m_value); } -template<> inline void LuaVar ::InnerPush(lua_State* l) { lua_pushnumber(l, m_value); } -template<> inline void LuaVar ::InnerPush(lua_State* l) { lua_pushnumber(l, m_value); } -template<> inline void LuaVar ::InnerPush(lua_State* l) { lua_pushinteger(l, m_value); } -template<> inline void LuaVar ::InnerPush(lua_State* l) { lua_pushinteger(l, m_value); } -template<> inline void LuaVar ::InnerPush(lua_State* l) { lua_pushunsigned(l, m_value); } +template<> inline void Var ::InnerInit() { m_value = String(); } +template<> inline void Var ::InnerGet(State* l, int index) { m_value = lua_tostring(l, index); } +template<> inline void Var::InnerGet(State* l, int index) { m_value = lua_tostring(l, index); } +template<> inline void Var ::InnerGet(State* l, int index) { m_value = lua_tonumber(l, index); } +template<> inline void Var ::InnerGet(State* l, int index) { m_value = (float)lua_tonumber(l, index); } +template<> inline void Var ::InnerGet(State* l, int index) { m_value = (int32_t)lua_tointeger(l, index); } +template<> inline void Var ::InnerGet(State* l, int index) { m_value = lua_tointeger(l, index); } +template<> inline void Var ::InnerGet(State* l, int index) { m_value = lua_tounsigned(l, index); } + +template<> inline void Var ::InnerPush(State* l) { lua_pushstring(l, m_value.C()); } +template<> inline void Var::InnerPush(State* l) { lua_pushstring(l, m_value); } +template<> inline void Var ::InnerPush(State* l) { lua_pushnumber(l, m_value); } +template<> inline void Var ::InnerPush(State* l) { lua_pushnumber(l, m_value); } +template<> inline void Var ::InnerPush(State* l) { lua_pushinteger(l, m_value); } +template<> inline void Var ::InnerPush(State* l) { lua_pushinteger(l, m_value); } +template<> inline void Var ::InnerPush(State* l) { lua_pushunsigned(l, m_value); } //----------------------------------------------------------------------------- -class LuaLoader +class Loader { public: - LuaLoader(); - virtual ~LuaLoader(); + Loader(); + virtual ~Loader(); bool ExecLua(String const &lua); @@ -124,7 +265,7 @@ public: T GetVar(String const &name) { lua_getglobal(m_lua_state, name.C()); - LuaVar var(m_lua_state, -1); + Var var(m_lua_state, -1); lua_pop(m_lua_state, 1); return var.V(); } @@ -138,10 +279,357 @@ public: } protected: - lua_State* GetLuaState(); + Lolua::State* GetLuaState(); private: - lua_State* m_lua_state; + Lolua::State* m_lua_state; }; +//----------------------------------------------------------------------------- +//class T definition +//class T +//{ +//public: +// int Ctor(lua_State* l) { return 0; } +// static const char* m_class_name; +// static const Class::Variable* m_variables; +// static const Class::Method* m_methods; +//}; +/* +//----------------------------------------------------------------------------- +template +class ClassTest +{ +public: + //----------------------------------------------------------------------------- + struct Variable + { + const char* m_name; + int(*Getter)(lua_State*); + int(*Setter)(lua_State*); + }; + + //----------------------------------------------------------------------------- + struct Method + { + const char* m_name; + int(*Func)(lua_State*); + }; + + //Register: Register class in Lua. Leave library empty to store class in global scope. + static void Register(lua_State* l, const char *library = NULL) + { + if (library && strlen(library)) + { + lua_getglobal(l, library); + //Create library if not present + if (lua_isnil(l, -1)) + { + lua_newtable(l); + //Duplicate table pointer since setglobal pops the value + lua_pushvalue(l, -1); + lua_setglobal(l, library); + } + //lua_pushcfunction(l, &Class::Ctor); + //lua_setfield(l, -2, T::m_class_name); + //lua_pop(l, 1); + } + else + { + //lua_pushcfunction(l, &Class::Ctor); + //lua_setglobal(l, T::m_class_name); + } + + luaL_newmetatable(l, T::m_class_name); + int metatable = lua_gettop(l); + + //Register all m_methods: Register Name for fun_call and number for choice + for (int i = 0; T::m_methods[i].m_name; i++) + { + lua_pushstring(l, T::m_methods[i].m_name); + lua_pushcfunction(l, T::m_methods[i].Func); + lua_settable(l, metatable); + } + + //lua_pushstring(l, "__gc"); + //lua_pushcfunction(l, &Class::Dtor); + //lua_settable(l, metatable); + + //lua_pushstring(l, "__tostring"); + //lua_pushcfunction(l, &Class::ToString); + //lua_settable(l, metatable); + + //lua_pushstring(l, "__eq"); + //lua_pushcfunction(l, &Class::Equals); + //lua_settable(l, metatable); + + //lua_pushstring(l, "__index"); + //lua_pushcfunction(l, &Class::Getter); + //lua_settable(l, metatable); + + //lua_pushstring(l, "__newindex"); + //lua_pushcfunction(l, &Class::Setter); + //lua_settable(l, metatable); + + ////Register all properties: Register Name for fun_call and number for choice + //for (int i = 0; T::m_variables[i].m_name; i++) + //{ + // lua_pushstring(l, T::m_variables[i].m_name); + // lua_pushnumber(l, i); + // lua_settable(l, metatable); + //} + + ////Register all m_methods: Register Name for fun_call and number for choice + //for (int i = 0; T::m_methods[i].m_name; i++) + //{ + // lua_pushstring(l, T::m_methods[i].m_name); + // //Add (1 << 8) to identify function on call + // lua_pushnumber(l, i | (1 << 8)); + // lua_settable(l, metatable); + //} + } + +}; + +//----------------------------------------------------------------------------- +template +class Class +{ +public: + //----------------------------------------------------------------------------- + struct Variable + { + const char* m_name; + int (T::*Getter)(lua_State*); + int (T::*Setter)(lua_State*); + }; + + //----------------------------------------------------------------------------- + struct Method + { + const char* m_name; + int (T::*Func)(lua_State*); + }; + + //----------------------------------------------------------------------------- + //Check: Raise an exception if FAIL + static T* Check(lua_State * l, int narg) + { + T** obj = static_cast (luaL_checkudata(l, narg, T::m_class_name)); + return !obj ? nullptr : *obj; + } + + //LightCheck: Returns nullptr if FAIL + static T* LightCheck(lua_State* l, int num_args) + { + T** obj = static_cast (luaL_testudata(l, num_args, T::m_class_name)); + return !obj ? nullptr : *obj; + } + + //Register: Register class in Lua. Leave library empty to store class in global scope. + static void Register(lua_State* l, const char *library = NULL) + { + if (library && strlen(library)) + { + lua_getglobal(l, library); + //Create library if not present + if (lua_isnil(l, -1)) + { + lua_newtable(l); + //Duplicate table pointer since setglobal pops the value + lua_pushvalue(l, -1); + lua_setglobal(l, library); + } + lua_pushcfunction(l, &Class::Ctor); + lua_setfield(l, -2, T::m_class_name); + lua_pop(l, 1); + } + else + { + lua_pushcfunction(l, &Class::Ctor); + lua_setglobal(l, T::m_class_name); + } + + luaL_newmetatable(l, T::m_class_name); + int metatable = lua_gettop(l); + + //lua_pushstring(l, "__gc"); + //lua_pushcfunction(l, &Class::Dtor); + //lua_settable(l, metatable); + + //lua_pushstring(l, "__tostring"); + //lua_pushcfunction(l, &Class::ToString); + //lua_settable(l, metatable); + + //lua_pushstring(l, "__eq"); + //lua_pushcfunction(l, &Class::Equals); + //lua_settable(l, metatable); + + lua_pushstring(l, "__index"); + lua_pushcfunction(l, &Class::Getter); + lua_settable(l, metatable); + + lua_pushstring(l, "__newindex"); + lua_pushcfunction(l, &Class::Setter); + lua_settable(l, metatable); + + //Register all properties: Register Name for fun_call and number for choice + for (int i = 0; T::m_variables[i].m_name; i++) + { + lua_pushstring(l, T::m_variables[i].m_name); + lua_pushnumber(l, i); + lua_settable(l, metatable); + } + + //Register all m_methods: Register Name for fun_call and number for choice + for (int i = 0; T::m_methods[i].m_name; i++) + { + lua_pushstring(l, T::m_methods[i].m_name); + //Add (1 << 8) to identify function on call + lua_pushnumber(l, i | (1 << 8)); + lua_settable(l, metatable); + } + } + +private: + //Ctor + static int Ctor(lua_State* l) + { + T* obj = new T(l); + T** lua_obj = static_cast(lua_newuserdata(l, sizeof(T*))); // Push value = userdata + *lua_obj = obj; + + luaL_getmetatable(l, T::m_class_name); // Fetch global metatable T::classname + lua_setmetatable(l, -2); + return 1; + } + + //Dtor + static int Dtor(lua_State* l) + { + T** lua_obj = static_cast(lua_touserdata(l, -1)); + if (lua_obj && *lua_obj) + delete(*lua_obj); + return 0; + } + + //AddInstance + static void AddInstance(lua_State* l, T* instance) + { + T** a = (T**)lua_newuserdata(l, sizeof(T*)); // Create userdata + *a = instance; + + luaL_getmetatable(l, T::m_class_name); + lua_setmetatable(l, -2); + } + + //---- + static void GetVarIndex(lua_State* l) + { + lua_getmetatable(l, 1); //Look up the index of a m_name + lua_pushvalue(l, 2); //Push the m_name + lua_rawget(l, -2); //Get the index + } + + //---- + static void PrepareGetSet(lua_State* l) + { + lua_pop(l, 2); // Pop metatable and idx + lua_remove(l, 1); // Remove userdata + lua_remove(l, 1); // Remove [key] + } + + //Getter: Call a func or a getter var + static int Getter(lua_State* l) + { + GetVarIndex(l); + //Check if we got a valid index + if (lua_isnumber(l, -1)) + { + int idx = lua_tonumber(l, -1); + T** obj = static_cast(lua_touserdata(l, 1)); + lua_pushvalue(l, 3); + + //It's a method + if (idx & (1 << 8)) + { + //Push the Method index and call the function + lua_pushnumber(l, idx ^ (1 << 8)); + lua_pushlightuserdata(l, obj); + lua_pushcclosure(l, &Class::CallMethod, 2); + // Return a Method + return 1; + } + else + { + PrepareGetSet(l); + return ((*obj)->*(T::m_variables[idx].Getter))(l); + } + } + return 1; + } + + //Getter: Class a setter var or error if func + static int Setter(lua_State* l) + { + GetVarIndex(l); + //Check if we got a valid index + if (lua_isnumber(l, -1)) + { + int idx = lua_tonumber(l, -1); + T** obj = static_cast(lua_touserdata(l, 1)); + if (!obj || !*obj) + { + luaL_error(l, "Internal error, no object given!"); + return 0; + } + + //Try to set a Method - FAIL + if (idx & (1 << 8)) + { + String s = String::Printf("Trying to set the method [%s] of class [%s]", (*obj)->T::m_methods[idx ^ (1 << 8)].m_name, T::m_class_name); + luaL_error(l, s.C()); + return 0; + } + else + { + PrepareGetSet(l); + return ((*obj)->*(T::m_variables[idx].Setter))(l); + } + } + return 0; + } + + //CallMethod: Actually calls the method on the object + static int CallMethod(lua_State* l) + { + int i = (int)lua_tonumber(l, lua_upvalueindex(1)); + T** obj = static_cast (lua_touserdata(l, lua_upvalueindex(2))); + return ((*obj)->*(T::m_methods[i].Func))(l); + } + + //ToString: + static int ToString(lua_State* l) + { + T** obj = static_cast(lua_touserdata(l, -1)); + if (obj) + lua_pushfstring(l, "%s (%p)", T::m_class_name, (void*)*obj); + else + lua_pushstring(l, "Empty object"); + return 1; + } + + //Equals: + static int Equals(lua_State* l) + { + T** obj1 = static_cast(lua_touserdata(l, -1)); + T** obj2 = static_cast(lua_touserdata(l, 1)); + lua_pushboolean(l, *obj1 == *obj2); + return 1; + } +}; +*/ + +} /* namespace Lolua */ + } /* namespace lol */ diff --git a/src/world.cpp b/src/world.cpp index a9181d4c..0075694b 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -14,8 +14,6 @@ #include #include -//#include "lua/lua.hpp" - namespace lol { @@ -36,21 +34,10 @@ World g_world; * Public World class */ -const luaL_Reg test1Lua::m_statics[] = { { "getTest", test1Lua::getTest }, { NULL, NULL } }; -const luaL_Reg test1Lua::m_methods[] = { { NULL, NULL } }; -const char test1Lua::m_class[] = "test1"; - World::World() - : LuaLoader() + : Lolua::Loader() { g_world_data.m_lua_state = GetLuaState(); - //------ DEBUG TEST - //m_test1.LoadTo(GetLuaState()); - //luaL_loadfile(GetLuaState(), "lua/init.lua"); - //LuaVar var(GetLuaState(), 1); - //test1Lua::Library m_test1(GetLuaState()); - //------ DEBUG TEST - } World::~World() diff --git a/src/world.h b/src/world.h index c2dca298..541a9ffc 100644 --- a/src/world.h +++ b/src/world.h @@ -18,51 +18,11 @@ namespace lol { -class test1 -{ -public: - test1() {} - static int getTest(int i1, String s2) - { - return -1; - } -}; - -class test1Lua : public LuaObject -{ -public: - test1Lua() - { - } - static test1* New(lua_State* L) - { - return new test1(); - } - static int getTest(lua_State* L) - { - LuaVar i1(L, 1); - LuaVar s2(L, 2); - LuaVar res = (int64_t)test1::getTest(i1.V(), s2.V()); - return res.Return(L); - } - -private: - static const luaL_Reg m_statics[]; - static const luaL_Reg m_methods[]; - static const char m_class[]; - -public: - typedef LuaLibrary Library; -}; - -class World : public LuaLoader +class World : public Lolua::Loader { public: World(); virtual ~World(); - -protected: - test1Lua::Library m_test1; }; extern World g_world;