00001 #include "lugre_prefix.h"
00002 #include <assert.h>
00003 #include <stdarg.h>
00004 #include <stdio.h>
00005 #include <stdlib.h>
00006 #include "lugre_net.h"
00007 #include "lugre_fifo.h"
00008 #include "lugre_game.h"
00009 #include "lugre_listener.h"
00010 #include "lugre_scripting.h"
00011 #include "lugre_input.h"
00012 #include "lugre_robstring.h"
00013 #include "lugre_gfx3D.h"
00014 #include "lugre_gfx2D.h"
00015 #include "lugre_widget.h"
00016 #include "lugre_luabind.h"
00017 #include "lugre_shell.h"
00018 #include "lugre_timer.h"
00019 #include "lugre_ogrewrapper.h"
00020 #include "lugre_bitmask.h"
00021 #include "lugre_camera.h"
00022 #include "lugre_viewport.h"
00023 #include "lugre_rendertexture.h"
00024 #include "lugre_sound.h"
00025 #include <Ogre.h>
00026 #include <OgreResourceManager.h>
00027 #include <OgreFontManager.h>
00028 #include <OgreTextAreaOverlayElement.h>
00029 #include <OgreMeshSerializer.h>
00030 #include <OgreCompositorManager.h>
00031 #include "lugre_luaxml.h"
00032 #include "lugre_meshshape.h"
00033
00034
00035 #define USE_NEDMALLOC_FOR_LUA 0
00036
00037 #if USE_NEDMALLOC_FOR_LUA == 1
00038 #include "nedmalloc.h"
00039 #endif
00040
00041 #ifdef WIN32
00042 #include <windows.h>
00043 #else
00044 #include <unistd.h>
00045 #endif
00046
00047 extern "C" {
00048 #include "lua.h"
00049 #include "lauxlib.h"
00050 #include "lualib.h"
00051 int luaopen_sqlite3(lua_State * L);
00052 }
00053
00054
00055 using namespace Lugre;
00056
00057 void RegisterLua_General_GlobalFunctions (lua_State* L);
00058 void RegisterLua_General_Classes (lua_State* L);
00059 void RegisterLua_Ogre_GlobalFunctions (lua_State* L);
00060 void RegisterLua_Ogre_Classes (lua_State* L);
00061
00062 namespace Lugre {
00063
00064 void printdebug (const char *szCategory, const char *szFormat, ...) { PROFILE
00065 va_list ap;
00066 va_start(ap,szFormat);
00067 gRobStringBuffer[0] = 0;
00068 vsnprintf(gRobStringBuffer,kRobStringBufferSize-1,szFormat,ap);
00069 cScripting::GetSingletonPtr()->LuaCall("printdebug","ss",szCategory,gRobStringBuffer);
00070 va_end(ap);
00071 }
00072
00073
00074
00075 #ifdef PROFILE_LUACALLCOUNT
00076 std::map<const char*,int> gPROFILE_LUACALLCOUNT;
00077 struct cPROFILE_LUACALLCOUNTSetCmp {
00078 inline bool operator() (const std::pair<const char*,int>& x,const std::pair<const char*,int>& y) const {
00079 return x.second > y.second;
00080 }
00081 };
00082 #endif
00083
00084 extern std::string sLuaMainPath;
00085 extern std::string sLugreLuaPath;
00086
00087 void DisplayNotice (const char* szMsg);
00088 void DisplayErrorMessage (const char* szMsg);
00089 void Material_LuaRegister (void *L);
00090 void Beam_LuaRegister (void *L);
00091 void PrintLuaStackTrace ();
00092 void ProfileDumpCallCount ();
00093
00094 void PrintLuaStackTrace () { PROFILE
00095 if (!Lugre_IsMainThread()) { printf("PrintLuaStackTrace() called from non-main-thread!\n"); return; }
00096
00097 printf("PrintLuaStackTrace:\n");
00098
00099 std::string sMyStackTrace;
00100 cScripting::GetSingletonPtr()->LuaCall("_TRACEBACK",">s",&sMyStackTrace);
00101 printf("%s\n",sMyStackTrace.c_str());
00102 }
00103
00104 void PrintLuaStackTrace (const char *filename) { PROFILE
00105 FILE *f = fopen(filename,"a");
00106 if(f){
00107 if (!Lugre_IsMainThread()) {
00108 fprintf(f,"PrintLuaStackTrace(file) called from non-main-thread!\n");
00109 } else {
00110 fprintf(f,"PrintLuaStackTrace:\n");
00111
00112 std::string sMyStackTrace;
00113 cScripting::GetSingletonPtr()->LuaCall("_TRACEBACK",">s",&sMyStackTrace);
00114 fprintf(f,"%s\n",sMyStackTrace.c_str());
00115 }
00116 fclose(f);
00117 }
00118 }
00119
00120
00121
00122 std::list<cScriptingPlugin*> cScripting::mlPlugins;
00123 extern bool gbLugreStarted;
00124 void cScripting::RegisterPlugin (cScriptingPlugin* pPlugin) {
00125 assert(pPlugin);
00126 assert(!gbLugreStarted && "plugins must be registered BEFORE Lugre_Run()");
00127 mlPlugins.push_back(pPlugin);
00128 }
00129
00130 cScripting* cScripting::GetSingletonPtr (cScripting* p) {
00131 static cScripting* pSingleton = 0;
00132 if (p) pSingleton = p;
00133 return pSingleton;
00134 }
00135
00140 #define LEVELS1 12
00141 #define LEVELS2 10
00142 static int l_TRACEBACK (lua_State *L) { PROFILE
00143 int level = 1;
00144 int firstpart = 1;
00145 lua_Debug ar;
00146 if (lua_gettop(L) == 0)
00147 lua_pushliteral(L, "");
00148 else if (!lua_isstring(L, 1)) return 1;
00149 else lua_pushliteral(L, "\n");
00150 lua_pushliteral(L, "LuaStackTrace:\n");
00151 while (lua_getstack(L, level++, &ar)) {
00152 if (level > LEVELS1 && firstpart) {
00153
00154 if (!lua_getstack(L, level+LEVELS2, &ar))
00155 level--;
00156 else {
00157 lua_pushliteral(L, "\n\t...");
00158 while (lua_getstack(L, level+LEVELS2, &ar))
00159 level++;
00160 }
00161 firstpart = 0;
00162 continue;
00163 }
00164 lua_pushliteral(L, "\n\t");
00165 lua_getinfo(L, "Snl", &ar);
00166 lua_pushfstring(L, "%s:", ar.short_src);
00167 if (ar.currentline > 0)
00168 lua_pushfstring(L, "%d:", ar.currentline);
00169 switch (*ar.namewhat) {
00170 case 'g':
00171 case 'l':
00172 case 'f':
00173 case 'm':
00174 lua_pushfstring(L, " in function `%s'", ar.name);
00175 break;
00176 default: {
00177 if (*ar.what == 'm')
00178 lua_pushfstring(L, " in main chunk");
00179 else if (*ar.what == 'C' || *ar.what == 't')
00180 lua_pushliteral(L, " ?");
00181 else
00182 lua_pushfstring(L, " in function <%s:%d>",
00183 ar.short_src, ar.linedefined);
00184 }
00185 }
00186 lua_concat(L, lua_gettop(L));
00187 }
00188 lua_concat(L, lua_gettop(L));
00189 return 1;
00190 }
00191
00192
00193
00194
00195
00196
00200 int PCallWithErrFuncWrapper (lua_State *L,int narg, int nret) { PROFILE
00201 int status;
00202 int base = lua_gettop(L) - narg;
00203 lua_pushliteral(L, "_TRACEBACK");
00204 lua_rawget(L, LUA_GLOBALSINDEX);
00205 lua_insert(L, base);
00206
00207 status = lua_pcall(L, narg, (nret==-1) ? LUA_MULTRET : nret, base);
00208
00209
00210
00211
00212 lua_remove(L, base);
00213
00214
00215
00216 return status;
00217 }
00218
00219
00220 void MyCrash (const char* szMessage);
00221
00222 void LuaErrorHandler (lua_State *L, const char *fmt, ...) { PROFILE
00223 printf("LuaErrorHandler start\n");
00224
00225 va_list argp;
00226 va_start(argp, fmt);
00227 gRobStringBuffer[0] = 0;
00228 vsnprintf(gRobStringBuffer,kRobStringBufferSize-1,fmt, argp);
00229 std::string s(gRobStringBuffer);
00230 va_end(argp);
00231
00232 std::string mystr("LuaError\n");
00233 mystr += s;
00234
00235 printf("\nLuaErrorHandler end\n");
00236
00237
00238 MyCrash(mystr.c_str());
00239
00240
00241 }
00242
00243
00244 struct luaL_reg make_luaL_reg (const char *name,lua_CFunction func) {
00245 struct luaL_reg s;
00246 s.name = name;
00247 s.func = func;
00248 return s;
00249 }
00250
00251 void cScripting::Notify_KeyPress (const unsigned char iKey,const int iLetter) {
00252 LuaCall("KeyDown","ii",(int)iKey,(int)iLetter);
00253 }
00254 void cScripting::Notify_KeyRepeat (const unsigned char iKey,const int iLetter) {}
00255 void cScripting::Notify_KeyRelease (const unsigned char iKey) {
00256 LuaCall("KeyUp","i",(int)iKey);
00257 }
00258
00259 int cScripting::GetGlobal (const char* name) { PROFILE
00260 lua_getglobal(L,name);
00261 if (!lua_isnumber(L,-1)) { lua_pop(L,1); return 0; }
00262 return (int)lua_tonumber(L,-1);
00263 }
00264
00265 void cScripting::SetGlobal (lua_State *L,const char* name,int value) { PROFILE
00266 lua_pushnumber(L,value);
00267 lua_setglobal(L,name);
00268 }
00269
00276 bool cScripting::LuaCall (const char *func, const char *sig, ...) { PROFILE
00277 #ifdef PROFILE_LUACALLCOUNT
00278 ++gPROFILE_LUACALLCOUNT[func];
00279 #endif
00280
00281 bool result = true;
00282 va_list vl;
00283 int narg, nres;
00284
00285 va_start(vl, sig);
00286 lua_getglobal(L, func);
00287
00288
00289 narg = 0;
00290 while (*sig) {
00291 bool endwhile = false;
00292 switch (*sig++) {
00293 case 'f':
00294 lua_pushnumber(L, va_arg(vl, double));
00295 break;
00296
00297 case 'i':
00298 lua_pushnumber(L, va_arg(vl, int));
00299 break;
00300
00301 case 's':
00302 lua_pushstring(L, va_arg(vl, char *));
00303 break;
00304
00305 case '>':
00306 endwhile = true;
00307 break;
00308 default:
00309 LuaErrorHandler(L, "invalid option (%c)", *(sig - 1));
00310 lua_pushnil(L);
00311 break;
00312 }
00313 if (endwhile) break;
00314 narg++;
00315 luaL_checkstack(L, 1, "too many arguments");
00316 }
00317
00318
00319 nres = strlen(sig);
00320
00321 if (PCallWithErrFuncWrapper(L,narg, nres) != 0) {
00322
00323
00324 LuaErrorHandler(L, "error running function `%s': %s",func, lua_tostring(L, -1));
00325
00326
00327
00328
00329
00330 result = false;
00331 } else {
00332
00333 int popamount = nres;
00334 nres = -nres;
00335 while (*sig) {
00336 switch (*sig++) {
00337
00338 case 'f':
00339 if (!lua_isnumber(L, nres)) {
00340 LuaErrorHandler(L, "wrong result type");
00341 *va_arg(vl, double *) = 0;
00342 } else {
00343 *va_arg(vl, double *) = lua_tonumber(L, nres);
00344 }
00345 break;
00346
00347 case 'i':
00348 if (!lua_isnumber(L, nres)) {
00349 LuaErrorHandler(L, "wrong result type");
00350 *va_arg(vl, int *) = 0;
00351 } else {
00352 *va_arg(vl, int *) = (int)lua_tonumber(L, nres);
00353 }
00354 break;
00355
00356 case 's':
00357 if (!lua_isstring(L, nres)) {
00358 LuaErrorHandler(L, "wrong result type");
00359 *va_arg(vl,std::string*) = "";
00360 } else {
00361 *va_arg(vl,std::string*) = lua_tostring(L, nres);
00362 }
00363 break;
00364
00365 default:
00366 LuaErrorHandler(L, "invalid option (%c)", *(sig - 1));
00367 break;
00368 }
00369 nres++;
00370 }
00371
00372 lua_pop(L, popamount);
00373 }
00374 va_end(vl);
00375 return result;
00376 }
00377
00378 #if USE_NEDMALLOC_FOR_LUA == 1
00379
00380
00381 static void *l_nedalloc (void *ud, void *ptr, size_t osize, size_t nsize) {
00382 (void)ud;
00383 (void)osize;
00384 if (nsize == 0) {
00385 if(ptr != 0){
00386 nedfree(ptr);
00387 }
00388 return NULL;
00389 } else {
00390 return nedrealloc(ptr, nsize);
00391 }
00392 }
00393 #endif
00394
00395
00396 cScripting::cScripting () : L(0) {}
00397
00398 void cScripting::Init () { PROFILE
00399 if (sizeof(lua_Number) <= 4) {
00400 printf("sizeof(lua_Number) = %d, but must be greater than 4 (32 bit) for bitwise ops\n",sizeof(lua_Number));
00401 DisplayErrorMessage("ERROR : lua-precision wrong");
00402 exit(43);
00403 }
00404
00405
00406 #if USE_NEDMALLOC_FOR_LUA == 1
00407 L = lua_newstate(l_nedalloc, NULL);
00408 #else
00409 L = lua_open();
00410 #endif
00411
00412 assert(L);
00413
00414 InitLugreLuaEnvironment(L);
00415
00416 cInput::RegisterListener(this);
00417
00418 int res = luaL_dofile(L,sLuaMainPath.c_str());
00419 if (res) {
00420 fprintf(stderr,"%s\n",lua_tostring(L,-1));
00421 MyCrash("error in main script-initialisation\n");
00422 exit(-1);
00423 }
00424 }
00425
00426
00427
00428 void cScripting::InitLugreLuaEnvironment (lua_State* L) { PROFILE
00429 luaL_openlibs(L);
00430
00431
00432
00433
00434
00435
00436
00437
00438 #ifdef ENABLE_SQLITE_LUA
00439 {
00440
00441 static const luaL_reg s_sqlite3_methods[] = {
00442 {"init", luaopen_sqlite3 },
00443 {0, 0}
00444 };
00445 luaL_register(L, "libsqlite3", s_sqlite3_methods);
00446 }
00447 #endif
00448
00449
00450 #ifdef LUA_JITLIBNAME
00451 printf("setting up luajit\n");
00452
00453 luaopen_jit(L);
00454
00455
00456 luaL_dostring(L, "require(\"jit.opt\").start()");
00457 #endif
00458
00459 lua_register(L,"_TRACEBACK", l_TRACEBACK);
00460
00461 RegisterLua_General_GlobalFunctions(L);
00462 RegisterLua_Ogre_GlobalFunctions(L);
00463 { for (std::list<cScriptingPlugin*>::iterator itor=mlPlugins.begin();itor!=mlPlugins.end();++itor)
00464 (*itor)->RegisterLua_GlobalFunctions(L); }
00465
00466
00467 std::string sLuaUDataPath = sLugreLuaPath + "/udata.lua";
00468
00469
00470 std::ifstream myFileStream(sLuaMainPath.c_str());
00471 if (!myFileStream) {
00472 MyCrash(strprintf("%s cannot be found, probably the working directory is wrong",sLuaMainPath.c_str()).c_str());
00473 exit(34);
00474 }
00475 myFileStream.close();
00476
00477
00478 int res;
00479 res = luaL_dofile(L,sLuaUDataPath.c_str());
00480 if (res) {
00481 fprintf(stderr,"%s\n",lua_tostring(L,-1));
00482 MyCrash("error in udata script-initialisation\n");
00483 exit(44);
00484 }
00485
00486 #ifdef ENABLE_SQLITE_LUA
00487
00488 {
00489 std::string sSQLitePath = sLugreLuaPath + "/../lib/sqlite/lua/sqlite3.lua";
00490 int res;
00491 res = luaL_dofile(L,sSQLitePath.c_str());
00492 if (res) {
00493 fprintf(stderr,"%s\n",lua_tostring(L,-1));
00494 MyCrash("error in sqlite3 script-initialisation\n");
00495 exit(44);
00496 }
00497 }
00498 #endif
00499
00500 RegisterLua_General_Classes(L);
00501 RegisterLua_Ogre_Classes(L);
00502 { for (std::list<cScriptingPlugin*>::iterator itor=mlPlugins.begin();itor!=mlPlugins.end();++itor)
00503 (*itor)->RegisterLua_Classes(L); }
00504 }
00505
00506 cScripting::~cScripting () { PROFILE
00507 assert(L);
00508 lua_close(L);
00509 L = 0;
00510 }
00511
00512 };