lugre_scripting.cpp

Go to the documentation of this file.
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 //#define PROFILE_LUACALLCOUNT
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     // see l_TRACEBACK() : leaves a string containing the stacktrace at the top of the stack
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             // see l_TRACEBACK() : leaves a string containing the stacktrace at the top of the stack
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 // ***** ***** global functionals exported to lua ***** *****
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  /* size of the first part of the stack */
00141 #define LEVELS2 10  /* size of the second part of the stack */
00142 static int l_TRACEBACK (lua_State *L) { PROFILE
00143   int level = 1;  /* skip level 0 (it's this function) */
00144   int firstpart = 1;  /* still before eventual `...' */
00145   lua_Debug ar;
00146   if (lua_gettop(L) == 0)
00147     lua_pushliteral(L, "");
00148   else if (!lua_isstring(L, 1)) return 1;  /* no string message */
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       /* no more than `LEVELS2' more levels? */
00154       if (!lua_getstack(L, level+LEVELS2, &ar))
00155         level--;  /* keep going */
00156       else {
00157         lua_pushliteral(L, "\n\t...");  /* too many levels */
00158         while (lua_getstack(L, level+LEVELS2, &ar))  /* find last levels */
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':  /* global */ 
00171       case 'l':  /* local */
00172       case 'f':  /* field */
00173       case 'm':  /* method */
00174         lua_pushfstring(L, " in function `%s'", ar.name);
00175         break;
00176       default: {
00177         if (*ar.what == 'm')  /* main? */
00178           lua_pushfstring(L, " in main chunk");
00179         else if (*ar.what == 'C' || *ar.what == 't')
00180           lua_pushliteral(L, " ?");  /* C function or tail call */
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 // ***** ***** utilities and error handling ***** *****
00195 
00196 
00200 int     PCallWithErrFuncWrapper (lua_State *L,int narg, int nret) { PROFILE
00201     int status;
00202     int base = lua_gettop(L) - narg;  // function index 
00203     lua_pushliteral(L, "_TRACEBACK");
00204     lua_rawget(L, LUA_GLOBALSINDEX); // get traceback function 
00205     lua_insert(L, base);  // put it under chunk and args 
00206     // signal(SIGINT, laction); // copyed from example, no idea what this is good for =(
00207     status = lua_pcall(L, narg, (nret==-1) ? LUA_MULTRET : nret, base);
00208     
00209     //printf("pcall end, cleaning up....\n");
00210     
00211     // signal(SIGINT, SIG_DFL); // copyed from example, no idea what this is good for =(
00212     lua_remove(L, base);  // remove traceback function // TODO : this might crash if error handler closed the lua state 
00213     
00214     //printf("pcall end\n");
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     //lua_close(L);
00238     MyCrash(mystr.c_str());
00239     // todo : attempt recovery in case of protected function call ?
00240     // todo : deinit ogre to free mouse here
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;  /* number of arguments and results */
00284 
00285     va_start(vl, sig);
00286     lua_getglobal(L, func);  /* get function */
00287 
00288     /* push arguments */
00289     narg = 0;
00290     while (*sig) {  /* push arguments */
00291         bool endwhile = false;
00292         switch (*sig++) {
00293           case 'f':  /* float/double argument */
00294             lua_pushnumber(L, va_arg(vl, double));
00295             break;
00296 
00297           case 'i':  /* int argument (ansi printf : also use %d) */
00298             lua_pushnumber(L, va_arg(vl, int));
00299             break;
00300 
00301           case 's':  /* string argument */
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     /* do the call */
00319     nres = strlen(sig);  /* number of expected results */
00320     // todo : push lua error handler function here ?!?
00321     if (PCallWithErrFuncWrapper(L,narg, nres) != 0) {
00322     //if (lua_pcall(L, narg, nres, 0) != 0)  { // old
00323         /* do the call */
00324         LuaErrorHandler(L, "error running function `%s': %s",func, lua_tostring(L, -1));
00325         
00326         /*
00327         doku for lua_pcall last argument (errorfunc)
00328         if 0 ... else that argument should be the index in the stack where the error handler function is located. Notice that, in such cases, the handler must be pushed in the stack before the function to be called and its arguments.
00329         */
00330         result = false;
00331     } else {
00332         /* retrieve results */
00333         int popamount = nres;
00334         nres = -nres;  /* stack index of first result */
00335         while (*sig) {  /* get results */
00336             switch (*sig++) {
00337 
00338               case 'f':  /* float / double result */
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':  /* int result */
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':  /* string result */
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); // return as std::string, as pure lua pointer becomes invalid with pop
00362                 }
00363                 break;
00364 
00365               default:
00366                 LuaErrorHandler(L, "invalid option (%c)", *(sig - 1));
00367                 break;
00368             }
00369             nres++;
00370         }
00371         // pop stack    
00372         lua_pop(L, popamount);
00373     }
00374     va_end(vl);
00375     return result;
00376 }
00377 
00378 #if USE_NEDMALLOC_FOR_LUA == 1
00379 // nedmalloc allocator wrapper
00380 // see http://pgl.yoyo.org/luai/i/lua_Alloc
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 // first tests to use nedalloc as the lua allocator
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     //~ luaopen_base(L);
00431     //~ luaopen_table(L);
00432     //~ luaopen_io(L);
00433     //~ luaopen_string(L);
00434     //~ luaopen_math(L);
00435     //~ luaopen_debug(L);
00436     
00437     // sqlite lua module
00438 #ifdef ENABLE_SQLITE_LUA
00439     {
00440         // Table for exported sqlite related functions
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 // checks if luajit is used instead of the normal lua
00450 #ifdef LUA_JITLIBNAME
00451     printf("setting up luajit\n");
00452     // call this after all other lualib open functions  
00453     luaopen_jit(L);
00454     
00455     // calls the lua code require("jit.opt").start() to include all needed extra lua modules
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     // file paths for init
00467     std::string sLuaUDataPath = sLugreLuaPath + "/udata.lua";
00468 
00469     // check if lua files exist (otherwise working directory probably wrong)
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()); //  lua:  os.getenv('PWD')
00473         exit(34);
00474     }
00475     myFileStream.close();
00476     
00477     // load utils
00478     int res;
00479     res = luaL_dofile(L,sLuaUDataPath.c_str()); // loads function used for registering udatatypes
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     // load sqlite lua code
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 };

Generated on Wed May 23 06:00:15 2012 for cpp by  doxygen 1.5.6