00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef LUGRE_LUABIND_H
00025 #define LUGRE_LUABIND_H
00026
00027 #include <map>
00028 #include <vector>
00029 #include "lugre_gfx3D.h"
00030 #include "lugre_gfx2D.h"
00031 #include "lugre_smartptr.h"
00032 #include "lugre_robstring.h"
00033 #include <OgreVector3.h>
00034 #include <OgreVector2.h>
00035 #include <OgreQuaternion.h>
00036 #include <OgreColourValue.h>
00037
00038 extern "C" {
00039 #include "lua.h"
00040 #include "lauxlib.h"
00041 #include "lualib.h"
00042 }
00043
00044 namespace Lugre {
00045
00046 #define luaL_checkbool(L,i) (lua_isboolean(L,i) ? lua_toboolean(L,i) : luaL_checkint(L,i))
00047
00048
00049 int PCallWithErrFuncWrapper (lua_State *L,int narg, int nret);
00050 void LuaErrorHandler (lua_State *L, const char *fmt, ...);
00051 struct luaL_reg make_luaL_reg (const char *name,lua_CFunction func);
00052
00053
00054
00055 #define cMemberVar_REGISTER(prototype,vartype,name,flags) mlMemberVar[#name] = new cMemberVar(vartype,((char*)&prototype->name) - ((char*)prototype),flags)
00056 template<class _T> class cLuaBind { public:
00058 struct udata { cSmartPtr<_T>* pSmartPtr; };
00059
00060
00061 enum {
00062 kVarType_int,
00063 kVarType_size_t,
00064 kVarType_bool,
00065 kVarType_Float,
00066 kVarType_Real,
00067 kVarType_Vector2,
00068 kVarType_Vector3,
00069 kVarType_Colour,
00070 kVarType_Quaternion,
00071 kVarType_String,
00072 kVarType_Gfx3D,
00073 kVarType_Gfx2D,
00074 kVarType_ObjSmartPtr,
00075 };
00076
00077 enum {
00078 kVarFlag_Readonly = (1<<0),
00079 kVarFlag_NotifyChange = (1<<1),
00080 };
00081
00082 class cMemberVar { public:
00083 size_t miType;
00084 size_t miOffset;
00085 size_t miFlags;
00086 cMemberVar(size_t iType,size_t iOffset,size_t iFlags) : miType(iType), miOffset(iOffset), miFlags(iFlags) { PROFILE}
00087 };
00088
00089
00090 std::map<std::string,cMemberVar*> mlMemberVar;
00091 std::vector<struct luaL_reg> mlMethod;
00092 std::string msError_X_expected;
00093 std::string msError_dead_X_ptr;
00094 const char* mszError_X_expected;
00095 const char* mszError_dead_X_ptr;
00096
00097 static cLuaBind<_T>* GetSingletonPtr (cLuaBind<_T>* prototype=0) { PROFILE
00098 static cLuaBind<_T>* pSingleton = 0;
00099 if (pSingleton) return pSingleton;
00100 pSingleton = prototype;
00101 assert(pSingleton);
00102 pSingleton->msError_X_expected = strprintf("`%s' expected",pSingleton->GetLuaTypeName());
00103 pSingleton->msError_dead_X_ptr = strprintf("dead `%s' pointer",pSingleton->GetLuaTypeName());
00104 pSingleton->mszError_X_expected = pSingleton->msError_X_expected.c_str();
00105 pSingleton->mszError_dead_X_ptr = pSingleton->msError_dead_X_ptr.c_str();
00106 return pSingleton;
00107 }
00108
00109
00110 virtual const char* GetLuaTypeName () = 0;
00111
00113
00114 void LuaRegister (lua_State *L) { PROFILE
00115 mlMethod.clear();
00116
00117
00118 mlMethod.push_back(make_luaL_reg("Get", cLuaBind<_T>::l_Get));
00119 mlMethod.push_back(make_luaL_reg("Set", cLuaBind<_T>::l_Set));
00120 mlMethod.push_back(make_luaL_reg("IsAlive", cLuaBind<_T>::IsAlive));
00121 mlMethod.push_back(make_luaL_reg("__gc", cLuaBind<_T>::LuaGC));
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131 RegisterMethods(L);
00132 RegisterMembers();
00133
00134 struct luaL_reg* pMethodBuffer = new luaL_reg[mlMethod.size()+1];
00135 unsigned int i; for (i=0;i<mlMethod.size();++i) pMethodBuffer[i] = mlMethod[i];
00136 pMethodBuffer[i] = make_luaL_reg(0,0);
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 const char* luafunc_RegisterUDataType = "RegisterUDataType";
00151 lua_getglobal(L,luafunc_RegisterUDataType);
00152
00153
00154 const char* myLuaTypeName = GetLuaTypeName();
00155 assert(myLuaTypeName);
00156 lua_pushstring(L,myLuaTypeName);
00157
00158
00159
00160 if (luaL_newmetatable(L,myLuaTypeName) == 0) {
00161
00162 assert(0 && "WARNING ! every luabind-type must have a unique name, see GetLuaTypeName()");
00163 }
00164
00165
00166
00167
00168
00169 lua_pushstring(L,"methods");
00170
00171
00172
00173
00174
00175
00176 lua_newtable(L);
00177 luaL_openlib(L, NULL, pMethodBuffer, 0);
00178
00179
00180
00181
00182
00183
00184
00185 lua_settable(L,-3);
00186
00187
00188
00189
00190
00191 int narg = 2;
00192 if (PCallWithErrFuncWrapper(L,narg, 0) != 0)
00193 LuaErrorHandler(L, "error running function `%s': %s",luafunc_RegisterUDataType, lua_tostring(L, -1));
00194
00195
00196 delete [] pMethodBuffer;
00197 }
00198
00201 virtual ~cLuaBind(){};
00202
00204 virtual void NotifyGC (lua_State *L,_T* target) { PROFILE }
00205
00207 virtual void RegisterMethods (lua_State *L) { PROFILE }
00208
00209
00210
00213 virtual void RegisterMembers () { PROFILE}
00214
00215
00216
00217
00218
00219
00220
00221
00222
00224 virtual void NotifyChange (_T* pObj,const char* sMemberVarName) { PROFILE}
00225
00226
00227
00228
00229
00230
00231
00233
00235 static int CreateUData (lua_State *L,_T* target) { PROFILE
00236 const char* myLuaTypeName = GetSingletonPtr()->GetLuaTypeName();
00237 const char* luafunc_WrapUData = "WrapUData";
00238 lua_getglobal(L,luafunc_WrapUData);
00239
00240
00241 udata *o = (udata*)lua_newuserdata(L,sizeof(udata));
00242 o->pSmartPtr = new cSmartPtr<_T>(target);
00243 luaL_getmetatable(L, myLuaTypeName);
00244 lua_setmetatable(L, -2);
00245
00246
00247
00248
00249 int narg = 1;
00250 int nres = 1;
00251 if (PCallWithErrFuncWrapper(L,narg, nres) != 0) {
00252 LuaErrorHandler(L, "error running function `%s': %s",luafunc_WrapUData, lua_tostring(L, -1));
00253 return 0;
00254 }
00255
00256 return nres;
00257 }
00258
00260 static int CreateUDataOrNil (lua_State *L,_T* target) { PROFILE
00261 if(target)return CreateUData(L,target);
00262 else return 0;
00263 }
00264
00266 inline static _T* checkudata (lua_State *L,int index=1) { PROFILE
00267 udata* o;
00268 cLuaBind<_T>* pSingleton = GetSingletonPtr();
00269 if (lua_istable(L,index)) {
00270
00271 lua_pushstring(L,"udata");
00272 lua_rawget(L,index-((index<0)?1:0));
00273
00274 o = (udata*)luaL_checkudata(L, -1, pSingleton->GetLuaTypeName());
00275 lua_pop(L,1);
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285 } else {
00286 o = (udata*)luaL_checkudata(L, index, pSingleton->GetLuaTypeName());
00287 }
00288 luaL_argcheck(L, o != NULL, index,pSingleton->mszError_X_expected);
00289 if (!o->pSmartPtr) return 0;
00290 return *(*o->pSmartPtr);
00291 }
00292
00294 inline static _T* checkudata_alive (lua_State *L,int index=1) { PROFILE
00295 _T* res = checkudata(L,index);
00296 luaL_argcheck(L, res != NULL, index,GetSingletonPtr()->mszError_dead_X_ptr);
00297 return res;
00298 }
00299
00301
00305 static int LuaGC (lua_State *L) { PROFILE
00306 cLuaBind<_T>* pSingleton = GetSingletonPtr();
00307 udata* o = (udata*)luaL_checkudata(L, 1, pSingleton->GetLuaTypeName());
00308 luaL_argcheck(L, o != NULL, 1,pSingleton->mszError_X_expected);
00309 pSingleton->NotifyGC(L,**o->pSmartPtr);
00310 if (o->pSmartPtr) delete o->pSmartPtr;
00311 o->pSmartPtr = 0;
00312 return 0;
00313 }
00314
00315
00316
00317
00319 static int l_Get (lua_State *L) { PROFILE
00320 _T* pObj = checkudata(L);
00321 if (!pObj) return 0;
00322 const char *sMemberVarName = luaL_checkstring(L,2);
00323 return GetSingletonPtr()->Get(pObj,sMemberVarName,L);
00324 }
00325
00327 static int l_Set (lua_State *L) { PROFILE
00328 _T* pObj = checkudata(L);
00329 if (!pObj) return 0;
00330 const char *sMemberVarName = luaL_checkstring(L,2);
00331 return GetSingletonPtr()->Set(pObj,sMemberVarName,L,3);
00332 }
00333
00335 static int IsAlive (lua_State *L) { PROFILE
00336 lua_pushboolean(L,checkudata(L) ? 1 : 0);
00337 return 1;
00338 }
00339
00341
00344 int Set (_T* pObj,const char* sMemberVarName,lua_State *L,size_t index=3) { PROFILE
00345
00346 if (!pObj) { lua_pushstring(L,"pObj=0"); return 1; }
00347 if (!sMemberVarName) { lua_pushstring(L,"sMemberVarName=0"); return 1; }
00348 cMemberVar* mv = mlMemberVar[sMemberVarName];
00349 if (!mv) { lua_pushstring(L,"not found"); return 1; }
00350 if (mv->miFlags & kVarFlag_Readonly) { lua_pushstring(L,"readonly"); return 1; }
00351
00352 char* myptr = ((char*)pObj) + mv->miOffset;
00353 switch (mv->miType) {
00354 case kVarType_String: *(std::string*)myptr = luaL_checkstring(L,index); break;
00355 case kVarType_int: *(int*)myptr = luaL_checkint(L,index); break;
00356 case kVarType_size_t: *(size_t*)myptr = luaL_checkint(L,index); break;
00357 case kVarType_bool:
00358 if (lua_isboolean(L,index))
00359 *(bool*)myptr = lua_toboolean(L,index);
00360 else *(bool*)myptr = luaL_checkint(L,index);
00361 break;
00362 case kVarType_Float: *(float*)myptr = luaL_checknumber(L,index); break;
00363 case kVarType_Real: *(Ogre::Real*)myptr = luaL_checknumber(L,index); break;
00364 case kVarType_Colour: {
00365
00366 if (lua_istable(L,index)) {
00367
00368
00369
00370
00371 lua_rawgeti(L,index,3);
00372 lua_rawgeti(L,index,2);
00373 lua_rawgeti(L,index,1);
00374 (*(Ogre::ColourValue*)myptr).r = luaL_checknumber(L,-1);
00375 (*(Ogre::ColourValue*)myptr).g = luaL_checknumber(L,-2);
00376 (*(Ogre::ColourValue*)myptr).b = luaL_checknumber(L,-3);
00377 lua_pop(L,3);
00378 } else {
00379 (*(Ogre::ColourValue*)myptr).r = luaL_checknumber(L,index);
00380 (*(Ogre::ColourValue*)myptr).g = luaL_checknumber(L,index+1);
00381 (*(Ogre::ColourValue*)myptr).b = luaL_checknumber(L,index+2);
00382 }
00383 } break;
00384 case kVarType_Vector2: {
00385 if (lua_istable(L,index)) {
00386
00387
00388
00389
00390 lua_rawgeti(L,index,2);
00391 lua_rawgeti(L,index,1);
00392 (*(Ogre::Vector2*)myptr).x = luaL_checknumber(L,-1);
00393 (*(Ogre::Vector2*)myptr).y = luaL_checknumber(L,-2);
00394 lua_pop(L,2);
00395 } else {
00396 (*(Ogre::Vector2*)myptr).x = luaL_checknumber(L,index);
00397 (*(Ogre::Vector2*)myptr).y = luaL_checknumber(L,index+1);
00398 }
00399 } break;
00400 case kVarType_Vector3: {
00401 if (lua_istable(L,index)) {
00402
00403
00404
00405
00406 lua_rawgeti(L,index,3);
00407 lua_rawgeti(L,index,2);
00408 lua_rawgeti(L,index,1);
00409 (*(Ogre::Vector3*)myptr).x = luaL_checknumber(L,-1);
00410 (*(Ogre::Vector3*)myptr).y = luaL_checknumber(L,-2);
00411 (*(Ogre::Vector3*)myptr).z = luaL_checknumber(L,-3);
00412 lua_pop(L,3);
00413 } else {
00414 (*(Ogre::Vector3*)myptr).x = luaL_checknumber(L,index);
00415 (*(Ogre::Vector3*)myptr).y = luaL_checknumber(L,index+1);
00416 (*(Ogre::Vector3*)myptr).z = luaL_checknumber(L,index+2);
00417 }
00418 } break;
00419 case kVarType_Quaternion: {
00420 if (lua_istable(L,index)) {
00421
00422
00423
00424
00425 lua_rawgeti(L,index,4);
00426 lua_rawgeti(L,index,3);
00427 lua_rawgeti(L,index,2);
00428 lua_rawgeti(L,index,1);
00429 (*(Ogre::Quaternion*)myptr).w = luaL_checknumber(L,-1);
00430 (*(Ogre::Quaternion*)myptr).x = luaL_checknumber(L,-2);
00431 (*(Ogre::Quaternion*)myptr).y = luaL_checknumber(L,-3);
00432 (*(Ogre::Quaternion*)myptr).z = luaL_checknumber(L,-4);
00433 lua_pop(L,4);
00434 } else {
00435 (*(Ogre::Quaternion*)myptr).w = luaL_checknumber(L,index);
00436 (*(Ogre::Quaternion*)myptr).x = luaL_checknumber(L,index+1);
00437 (*(Ogre::Quaternion*)myptr).y = luaL_checknumber(L,index+2);
00438 (*(Ogre::Quaternion*)myptr).z = luaL_checknumber(L,index+3);
00439 }
00440 } break;
00441
00442
00443
00444
00445
00446
00447 }
00448
00449 if (mv->miFlags & kVarFlag_NotifyChange) NotifyChange(pObj,sMemberVarName);
00450 return 0;
00451 }
00452
00456 int Get (_T* pObj,const char* sMemberVarName,lua_State *L) { PROFILE
00457 if (!pObj) return 0;
00458 if (!sMemberVarName) return 0;
00459 cMemberVar* mv = mlMemberVar[sMemberVarName];
00460 if (!mv) return 0;
00461
00462 char* myptr = ((char*)pObj) + mv->miOffset;
00463 switch (mv->miType) {
00464 case kVarType_String: lua_pushstring(L,(*(std::string*)myptr).c_str()); return 1;break;
00465 case kVarType_int: lua_pushnumber(L,*(int*)myptr); return 1;break;
00466 case kVarType_size_t: lua_pushnumber(L,*(size_t*)myptr); return 1;break;
00467 case kVarType_bool: lua_pushboolean(L,*(bool*)myptr); return 1;break;
00468 case kVarType_Float: lua_pushnumber(L,*(float*)myptr); return 1;break;
00469 case kVarType_Real: lua_pushnumber(L,*(Ogre::Real*)myptr); return 1;break;
00470 case kVarType_Vector2: {
00471
00472
00473
00474
00475 lua_newtable(L);
00476 lua_pushnumber(L,(*(Ogre::Vector2*)myptr).x); lua_rawseti(L,-2,1);
00477 lua_pushnumber(L,(*(Ogre::Vector2*)myptr).y); lua_rawseti(L,-2,2);
00478 return 1;
00479 } break;
00480 case kVarType_Vector3: {
00481
00482
00483
00484
00485 lua_newtable(L);
00486 lua_pushnumber(L,(*(Ogre::Vector3*)myptr).x); lua_rawseti(L,-2,1);
00487 lua_pushnumber(L,(*(Ogre::Vector3*)myptr).y); lua_rawseti(L,-2,2);
00488 lua_pushnumber(L,(*(Ogre::Vector3*)myptr).z); lua_rawseti(L,-2,3);
00489 return 1;
00490 } break;
00491 case kVarType_Colour: {
00492 lua_newtable(L);
00493 lua_pushnumber(L,(*(Ogre::ColourValue*)myptr).r); lua_rawseti(L,-2,1);
00494 lua_pushnumber(L,(*(Ogre::ColourValue*)myptr).g); lua_rawseti(L,-2,2);
00495 lua_pushnumber(L,(*(Ogre::ColourValue*)myptr).b); lua_rawseti(L,-2,3);
00496 return 1;
00497 } break;
00498 case kVarType_Quaternion: {
00499 lua_newtable(L);
00500 lua_pushnumber(L,(*(Ogre::Quaternion*)myptr).w); lua_rawseti(L,-2,1);
00501 lua_pushnumber(L,(*(Ogre::Quaternion*)myptr).x); lua_rawseti(L,-2,2);
00502 lua_pushnumber(L,(*(Ogre::Quaternion*)myptr).y); lua_rawseti(L,-2,3);
00503 lua_pushnumber(L,(*(Ogre::Quaternion*)myptr).z); lua_rawseti(L,-2,4);
00504 return 1;
00505 } break;
00506 case kVarType_Gfx3D: {
00507 return cLuaBind<cGfx3D>::CreateUData(L,*(cGfx3D**)myptr);
00508 } break;
00509 case kVarType_Gfx2D: {
00510 return cLuaBind<cGfx2D>::CreateUData(L,*(cGfx2D**)myptr);
00511 } break;
00512
00513
00514
00515
00516
00517
00518
00519 }
00520 return 0;
00521 }
00522 };
00523
00524
00525
00526
00527
00528
00529 inline Ogre::Vector3 luaSFZ_checkVector3 (lua_State *L,const size_t index) { PROFILE
00530 return Ogre::Vector3(luaL_checknumber(L,index),luaL_checknumber(L,index+1),luaL_checknumber(L,index+2));
00531 }
00532
00533
00534 inline Ogre::ColourValue luaSFZ_checkColour3 (lua_State *L,size_t& index) { PROFILE
00535 if (lua_istable(L,index)) {
00536
00537
00538
00539
00540 lua_rawgeti(L,index,3);
00541 lua_rawgeti(L,index,2);
00542 lua_rawgeti(L,index,1);
00543 Ogre::ColourValue res(luaL_checknumber(L,-1),luaL_checknumber(L,-2),luaL_checknumber(L,-3));
00544 lua_pop(L,3);
00545 index += 1;
00546 return res;
00547 } else {
00548 Ogre::ColourValue res(luaL_checknumber(L,index),luaL_checknumber(L,index+1),luaL_checknumber(L,index+2));
00549 index += 3;
00550 return res;
00551 }
00552 }
00553
00554
00555 inline Ogre::ColourValue luaSFZ_checkColour4 (lua_State *L,const int index) { PROFILE
00556 if (lua_istable(L,index)) {
00557
00558
00559
00560
00561 lua_rawgeti(L,index,4);
00562 lua_rawgeti(L,index,3);
00563 lua_rawgeti(L,index,2);
00564 lua_rawgeti(L,index,1);
00565 Ogre::ColourValue res(luaL_checknumber(L,-1),luaL_checknumber(L,-2),luaL_checknumber(L,-3),luaL_checknumber(L,-4));
00566 lua_pop(L,4);
00567
00568 return res;
00569 } else {
00570 Ogre::ColourValue res(luaL_checknumber(L,index),luaL_checknumber(L,index+1),luaL_checknumber(L,index+2),luaL_checknumber(L,index+3));
00571
00572 return res;
00573 }
00574 }
00575
00576
00577
00578
00579
00580
00581
00582 };
00583
00584 #endif