# HG changeset patch # User Robert McIntyre # Date 1330905056 21600 # Node ID 59790d015f25037aa04a10935859c52dd35b1690 # Parent bf9169ad42224acc266e838f93c13406bd5e8296 checkpoint diff -r bf9169ad4222 -r 59790d015f25 src/common/Makefile.am --- a/src/common/Makefile.am Sun Mar 04 17:38:32 2012 -0600 +++ b/src/common/Makefile.am Sun Mar 04 17:50:56 2012 -0600 @@ -5,7 +5,6 @@ inputGlobal.h \ memgzio.h \ movie.h \ - nesvideos-piece.h \ System.h \ Text.h \ unzip.h \ @@ -16,7 +15,6 @@ lua-engine.cpp \ memgzio.c \ movie.cpp \ - nesvideos-piece.cpp \ Text.cpp \ unzip.cpp \ Util.cpp diff -r bf9169ad4222 -r 59790d015f25 src/common/lua-engine.cpp --- a/src/common/lua-engine.cpp Sun Mar 04 17:38:32 2012 -0600 +++ b/src/common/lua-engine.cpp Sun Mar 04 17:50:56 2012 -0600 @@ -15,20 +15,20 @@ using namespace std; #ifdef __linux - #include // for unlink - #include - #include +#include // for unlink +#include +#include #endif #if (defined(WIN32) && !defined(SDL)) - #include - #include "../win32/stdafx.h" - #include "../win32/Input.h" - #include "../win32/MainWnd.h" - #include "../win32/VBA.h" - #include "../win32/LuaOpenDialog.h" +#include +#include "../win32/stdafx.h" +#include "../win32/Input.h" +#include "../win32/MainWnd.h" +#include "../win32/VBA.h" +#include "../win32/LuaOpenDialog.h" #else - #define stricmp strcasecmp - #define strnicmp strncasecmp +#define stricmp strcasecmp +#define strnicmp strncasecmp #endif #include "../Port.h" @@ -64,7 +64,7 @@ static int info_uid; #ifndef countof - #define countof(a) (sizeof(a) / sizeof(a[0])) +#define countof(a) (sizeof(a) / sizeof(a[0])) #endif static lua_State *LUA; @@ -114,37 +114,37 @@ // Look in inputglobal.h for macros named like BUTTON_MASK_UP to determine the order. static const char *button_mappings[] = { - "A", "B", "select", "start", "right", "left", "up", "down", "R", "L" + "A", "B", "select", "start", "right", "left", "up", "down", "R", "L" }; #ifdef _MSC_VER - #define snprintf _snprintf - #define vscprintf _vscprintf +#define snprintf _snprintf +#define vscprintf _vscprintf #else - #define stricmp strcasecmp - #define strnicmp strncasecmp - #define __forceinline __attribute__((always_inline)) +#define stricmp strcasecmp +#define strnicmp strncasecmp +#define __forceinline __attribute__((always_inline)) #endif static const char *luaCallIDStrings[] = -{ - "CALL_BEFOREEMULATION", - "CALL_AFTEREMULATION", - "CALL_BEFOREEXIT" -}; + { + "CALL_BEFOREEMULATION", + "CALL_AFTEREMULATION", + "CALL_BEFOREEXIT" + }; //make sure we have the right number of strings CTASSERT(sizeof(luaCallIDStrings) / sizeof(*luaCallIDStrings) == LUACALL_COUNT) static const char *luaMemHookTypeStrings [] = { - "MEMHOOK_WRITE", - "MEMHOOK_READ", - "MEMHOOK_EXEC", - - "MEMHOOK_WRITE_SUB", - "MEMHOOK_READ_SUB", - "MEMHOOK_EXEC_SUB", + "MEMHOOK_WRITE", + "MEMHOOK_READ", + "MEMHOOK_EXEC", + + "MEMHOOK_WRITE_SUB", + "MEMHOOK_READ_SUB", + "MEMHOOK_EXEC_SUB", }; //make sure we have the right number of strings @@ -156,88 +156,88 @@ // GBA memory I/O functions copied from win32/MemoryViewerDlg.cpp static inline u8 CPUReadByteQuick(u32 addr) { - return ::map[addr >> 24].address[addr & ::map[addr >> 24].mask]; + return ::map[addr >> 24].address[addr & ::map[addr >> 24].mask]; } static inline void CPUWriteByteQuick(u32 addr, u8 b) { - ::map[addr >> 24].address[addr & ::map[addr >> 24].mask] = b; + ::map[addr >> 24].address[addr & ::map[addr >> 24].mask] = b; } static inline u16 CPUReadHalfWordQuick(u32 addr) { - return *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]); + return *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]); } static inline void CPUWriteHalfWordQuick(u32 addr, u16 b) { - *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b; + *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b; } static inline u32 CPUReadMemoryQuick(u32 addr) { - return *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]); + return *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]); } static inline void CPUWriteMemoryQuick(u32 addr, u32 b) { - *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b; + *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b; } // GB static inline u8 gbReadMemoryQuick8(u16 addr) { - return gbReadMemoryQuick(addr); + return gbReadMemoryQuick(addr); } static inline void gbWriteMemoryQuick8(u16 addr, u8 b) { - gbWriteMemoryQuick(addr, b); + gbWriteMemoryQuick(addr, b); } static inline u16 gbReadMemoryQuick16(u16 addr) { - return (gbReadMemoryQuick(addr + 1) << 8) | gbReadMemoryQuick(addr); + return (gbReadMemoryQuick(addr + 1) << 8) | gbReadMemoryQuick(addr); } static inline void gbWriteMemoryQuick16(u16 addr, u16 b) { - gbWriteMemoryQuick(addr, b & 0xff); - gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff); + gbWriteMemoryQuick(addr, b & 0xff); + gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff); } static inline u32 gbReadMemoryQuick32(u16 addr) { - return (gbReadMemoryQuick(addr + 3) << 24) | - (gbReadMemoryQuick(addr + 2) << 16) | - (gbReadMemoryQuick(addr + 1) << 8) | - gbReadMemoryQuick(addr); + return (gbReadMemoryQuick(addr + 3) << 24) | + (gbReadMemoryQuick(addr + 2) << 16) | + (gbReadMemoryQuick(addr + 1) << 8) | + gbReadMemoryQuick(addr); } static inline void gbWriteMemoryQuick32(u16 addr, u32 b) { - gbWriteMemoryQuick(addr, b & 0xff); - gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff); - gbWriteMemoryQuick(addr + 2, (b >> 16) & 0xff); - gbWriteMemoryQuick(addr + 1, (b >> 24) & 0xff); + gbWriteMemoryQuick(addr, b & 0xff); + gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff); + gbWriteMemoryQuick(addr + 2, (b >> 16) & 0xff); + gbWriteMemoryQuick(addr + 1, (b >> 24) & 0xff); } static inline u8 gbReadROMQuick8(u32 addr) { - return gbReadROMQuick(addr & gbRomSizeMask); + return gbReadROMQuick(addr & gbRomSizeMask); } static inline u8 gbReadROMQuick16(u32 addr) { - return (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) | gbReadROMQuick(addr & gbRomSizeMask); + return (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) | gbReadROMQuick(addr & gbRomSizeMask); } static inline u8 gbReadROMQuick32(u32 addr) { - return (gbReadROMQuick(addr+3 & gbRomSizeMask) << 24) | - (gbReadROMQuick(addr+2 & gbRomSizeMask) << 16) | - (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) | - gbReadROMQuick(addr & gbRomSizeMask); + return (gbReadROMQuick(addr+3 & gbRomSizeMask) << 24) | + (gbReadROMQuick(addr+2 & gbRomSizeMask) << 16) | + (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) | + gbReadROMQuick(addr & gbRomSizeMask); } typedef void (*GetColorFunc)(const uint8 *, uint8 *, uint8 *, uint8 *); @@ -245,81 +245,81 @@ static void getColor16(const uint8 *s, uint8 *r, uint8 *g, uint8 *b) { - u16 v = *(const uint16 *)s; - *r = ((v >> systemBlueShift) & 0x001f) << 3; - *g = ((v >> systemGreenShift) & 0x001f) << 3; - *b = ((v >> systemRedShift) & 0x001f) << 3; + u16 v = *(const uint16 *)s; + *r = ((v >> systemBlueShift) & 0x001f) << 3; + *g = ((v >> systemGreenShift) & 0x001f) << 3; + *b = ((v >> systemRedShift) & 0x001f) << 3; } static void getColor24(const uint8 *s, uint8 *r, uint8 *g, uint8 *b) { - if (systemRedShift > systemBlueShift) - *b = s[0], *g = s[1], *r = s[2]; - else - *r = s[0], *g = s[1], *b = s[2]; + if (systemRedShift > systemBlueShift) + *b = s[0], *g = s[1], *r = s[2]; + else + *r = s[0], *g = s[1], *b = s[2]; } static void getColor32(const uint8 *s, uint8 *r, uint8 *g, uint8 *b) { - u32 v = *(const uint32 *)s; - *b = ((v >> systemBlueShift) & 0x001f) << 3; - *g = ((v >> systemGreenShift) & 0x001f) << 3; - *r = ((v >> systemRedShift) & 0x001f) << 3; + u32 v = *(const uint32 *)s; + *b = ((v >> systemBlueShift) & 0x001f) << 3; + *g = ((v >> systemGreenShift) & 0x001f) << 3; + *r = ((v >> systemRedShift) & 0x001f) << 3; } static void setColor16(uint8 *s, uint8 r, uint8 g, uint8 b) { - *(uint16 *)s = ((b >> 3) & 0x01f) << - systemBlueShift | - ((g >> 3) & 0x01f) << - systemGreenShift | - ((r >> 3) & 0x01f) << - systemRedShift; + *(uint16 *)s = ((b >> 3) & 0x01f) << + systemBlueShift | + ((g >> 3) & 0x01f) << + systemGreenShift | + ((r >> 3) & 0x01f) << + systemRedShift; } static void setColor24(uint8 *s, uint8 r, uint8 g, uint8 b) { - if (systemRedShift > systemBlueShift) - s[0] = b, s[1] = g, s[2] = r; - else - s[0] = r, s[1] = g, s[2] = b; + if (systemRedShift > systemBlueShift) + s[0] = b, s[1] = g, s[2] = r; + else + s[0] = r, s[1] = g, s[2] = b; } static void setColor32(uint8 *s, uint8 r, uint8 g, uint8 b) { - *(uint32 *)s = ((b >> 3) & 0x01f) << - systemBlueShift | - ((g >> 3) & 0x01f) << - systemGreenShift | - ((r >> 3) & 0x01f) << - systemRedShift; + *(uint32 *)s = ((b >> 3) & 0x01f) << + systemBlueShift | + ((g >> 3) & 0x01f) << + systemGreenShift | + ((r >> 3) & 0x01f) << + systemRedShift; } static bool getColorIOFunc(int depth, GetColorFunc *getColor, SetColorFunc *setColor) { - switch (depth) - { - case 16: - if (getColor) - *getColor = getColor16; - if (setColor) - *setColor = setColor16; - return true; - case 24: - if (getColor) - *getColor = getColor24; - if (setColor) - *setColor = setColor24; - return true; - case 32: - if (getColor) - *getColor = getColor32; - if (setColor) - *setColor = setColor32; - return true; - default: - return false; - } + switch (depth) + { + case 16: + if (getColor) + *getColor = getColor16; + if (setColor) + *setColor = setColor16; + return true; + case 24: + if (getColor) + *getColor = getColor24; + if (setColor) + *setColor = setColor24; + return true; + case 32: + if (getColor) + *getColor = getColor32; + if (setColor) + *setColor = setColor32; + return true; + default: + return false; + } } /** @@ -327,11 +327,11 @@ */ static void VBALuaOnStop(void) { - luaRunning = false; - lua_joypads_used = 0; - gui_used = false; - //if (wasPaused) - // systemSetPause(true); + luaRunning = false; + lua_joypads_used = 0; + gui_used = false; + //if (wasPaused) + // systemSetPause(true); } /** @@ -342,41 +342,41 @@ */ int VBALuaSpeed(void) { - if (!LUA || !luaRunning) - return 0; - - //printf("%d\n", speedmode); - switch (speedmode) - { - /* - case SPEED_NORMAL: - return 0; - case SPEED_NOTHROTTLE: - IPPU.RenderThisFrame = true; - return 1; - - case SPEED_TURBO: - IPPU.SkippedFrames++; - if (IPPU.SkippedFrames >= 40) { - IPPU.SkippedFrames = 0; - IPPU.RenderThisFrame = true; - } - else - IPPU.RenderThisFrame = false; - return 1; - - // In mode 3, SkippedFrames is set to zero so that the frame - // skipping code doesn't try anything funny. - case SPEED_MAXIMUM: - IPPU.SkippedFrames=0; - IPPU.RenderThisFrame = false; - return 1; - */ - case 0: // FIXME: to get rid of the warning - default: - assert(false); - return 0; + if (!LUA || !luaRunning) + return 0; + + //printf("%d\n", speedmode); + switch (speedmode) + { + /* + case SPEED_NORMAL: + return 0; + case SPEED_NOTHROTTLE: + IPPU.RenderThisFrame = true; + return 1; + + case SPEED_TURBO: + IPPU.SkippedFrames++; + if (IPPU.SkippedFrames >= 40) { + IPPU.SkippedFrames = 0; + IPPU.RenderThisFrame = true; } + else + IPPU.RenderThisFrame = false; + return 1; + + // In mode 3, SkippedFrames is set to zero so that the frame + // skipping code doesn't try anything funny. + case SPEED_MAXIMUM: + IPPU.SkippedFrames=0; + IPPU.RenderThisFrame = false; + return 1; + */ + case 0: // FIXME: to get rid of the warning + default: + assert(false); + return 0; + } } /////////////////////////// @@ -390,29 +390,29 @@ // maximum renders no frames static int vba_speedmode(lua_State *L) { - const char *mode = luaL_checkstring(L, 1); - - if (strcasecmp(mode, "normal") == 0) - { - speedmode = SPEED_NORMAL; - } - else if (strcasecmp(mode, "nothrottle") == 0) - { - speedmode = SPEED_NOTHROTTLE; - } - else if (strcasecmp(mode, "turbo") == 0) - { - speedmode = SPEED_TURBO; - } - else if (strcasecmp(mode, "maximum") == 0) - { - speedmode = SPEED_MAXIMUM; - } - else - luaL_error(L, "Invalid mode %s to vba.speedmode", mode); - - //printf("new speed mode: %d\n", speedmode); - return 0; + const char *mode = luaL_checkstring(L, 1); + + if (strcasecmp(mode, "normal") == 0) + { + speedmode = SPEED_NORMAL; + } + else if (strcasecmp(mode, "nothrottle") == 0) + { + speedmode = SPEED_NOTHROTTLE; + } + else if (strcasecmp(mode, "turbo") == 0) + { + speedmode = SPEED_TURBO; + } + else if (strcasecmp(mode, "maximum") == 0) + { + speedmode = SPEED_MAXIMUM; + } + else + luaL_error(L, "Invalid mode %s to vba.speedmode", mode); + + //printf("new speed mode: %d\n", speedmode); + return 0; } // vba.frameadvnace() @@ -422,18 +422,18 @@ // when we break out. static int vba_frameadvance(lua_State *L) { - // We're going to sleep for a frame-advance. Take notes. - if (frameAdvanceWaiting) - return luaL_error(L, "can't call vba.frameadvance() from here"); - - frameAdvanceWaiting = true; - - // Don't do this! The user won't like us sending their emulator out of control! - // Settings.FrameAdvance = true; - // Now we can yield to the main - return lua_yield(L, 0); - - // It's actually rather disappointing... + // We're going to sleep for a frame-advance. Take notes. + if (frameAdvanceWaiting) + return luaL_error(L, "can't call vba.frameadvance() from here"); + + frameAdvanceWaiting = true; + + // Don't do this! The user won't like us sending their emulator out of control! + // Settings.FrameAdvance = true; + // Now we can yield to the main + return lua_yield(L, 0); + + // It's actually rather disappointing... } // vba.pause() @@ -444,62 +444,62 @@ // finishes executing anwyays. In this case, the function returns immediately. static int vba_pause(lua_State *L) { - systemSetPause(true); - speedmode = SPEED_NORMAL; - - // Return control if we're midway through a frame. We can't pause here. - if (frameAdvanceWaiting) - { - return 0; - } - - // If it's on a frame boundary, we also yield. - frameAdvanceWaiting = true; - return lua_yield(L, 0); + systemSetPause(true); + speedmode = SPEED_NORMAL; + + // Return control if we're midway through a frame. We can't pause here. + if (frameAdvanceWaiting) + { + return 0; + } + + // If it's on a frame boundary, we also yield. + frameAdvanceWaiting = true; + return lua_yield(L, 0); } static int vba_registerbefore(lua_State *L) { - if (!lua_isnil(L, 1)) - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_settop(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]); - lua_insert(L, 1); - lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]); - - //StopScriptIfFinished(luaStateToUIDMap[L]); - return 1; + if (!lua_isnil(L, 1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]); + lua_insert(L, 1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]); + + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; } static int vba_registerafter(lua_State *L) { - if (!lua_isnil(L, 1)) - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_settop(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]); - lua_insert(L, 1); - lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]); - - //StopScriptIfFinished(luaStateToUIDMap[L]); - return 1; + if (!lua_isnil(L, 1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]); + lua_insert(L, 1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]); + + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; } static int vba_registerexit(lua_State *L) { - if (!lua_isnil(L, 1)) - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_settop(L, 1); - lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); - lua_insert(L, 1); - lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); - - //StopScriptIfFinished(luaStateToUIDMap[L]); - return 1; + if (!lua_isnil(L, 1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); + lua_insert(L, 1); + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); + + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 1; } static inline bool isalphaorunderscore(char c) { - return isalpha(c) || c == '_'; + return isalpha(c) || c == '_'; } static std::vector s_tableAddressStack; // prevents infinite recursion of a table within a table (when cycle is @@ -512,541 +512,541 @@ #define END ); if (_n >= 0) { ptr += _n; remaining -= _n; } else { remaining = 0; } } static void toCStringConverter(lua_State *L, int i, char * &ptr, int &remaining) { - if (remaining <= 0) - return; - - const char *str = ptr; // for debugging - - // if there is a __tostring metamethod then call it - int usedMeta = luaL_callmeta(L, i, "__tostring"); - if (usedMeta) + if (remaining <= 0) + return; + + const char *str = ptr; // for debugging + + // if there is a __tostring metamethod then call it + int usedMeta = luaL_callmeta(L, i, "__tostring"); + if (usedMeta) { - std::vector::const_iterator foundCycleIter = std::find(s_metacallStack.begin(), s_metacallStack.end(), lua_topointer(L, i)); - if (foundCycleIter != s_metacallStack.end()) + std::vector::const_iterator foundCycleIter = std::find(s_metacallStack.begin(), s_metacallStack.end(), lua_topointer(L, i)); + if (foundCycleIter != s_metacallStack.end()) { - lua_pop(L, 1); - usedMeta = false; - } - else + lua_pop(L, 1); + usedMeta = false; + } + else { - s_metacallStack.push_back(lua_topointer(L, i)); - i = lua_gettop(L); - } + s_metacallStack.push_back(lua_topointer(L, i)); + i = lua_gettop(L); } - - switch (lua_type(L, i)) + } + + switch (lua_type(L, i)) { - case LUA_TNONE: - break; - case LUA_TNIL: - APPENDPRINT "nil" END break; - case LUA_TBOOLEAN: - APPENDPRINT lua_toboolean(L, i) ? "true" : "false" END break; - case LUA_TSTRING : APPENDPRINT "%s", lua_tostring(L, i) END break; - case LUA_TNUMBER: - APPENDPRINT "%.12Lg", lua_tonumber(L, i) END break; - case LUA_TFUNCTION: - if ((L->base + i - 1)->value.gc->cl.c.isC) - { - //lua_CFunction func = lua_tocfunction(L, i); - //std::map::iterator iter = s_cFuncInfoMap.find(func); - //if(iter == s_cFuncInfoMap.end()) - goto defcase; - //APPENDPRINT "function(%s)", iter->second END - } + case LUA_TNONE: + break; + case LUA_TNIL: + APPENDPRINT "nil" END break; + case LUA_TBOOLEAN: + APPENDPRINT lua_toboolean(L, i) ? "true" : "false" END break; + case LUA_TSTRING : APPENDPRINT "%s", lua_tostring(L, i) END break; + case LUA_TNUMBER: + APPENDPRINT "%.12Lg", lua_tonumber(L, i) END break; + case LUA_TFUNCTION: + if ((L->base + i - 1)->value.gc->cl.c.isC) + { + //lua_CFunction func = lua_tocfunction(L, i); + //std::map::iterator iter = s_cFuncInfoMap.find(func); + //if(iter == s_cFuncInfoMap.end()) + goto defcase; + //APPENDPRINT "function(%s)", iter->second END + } + else + { + APPENDPRINT "function(" END + Proto * p = (L->base + i - 1)->value.gc->cl.l.p; + int numParams = p->numparams + (p->is_vararg ? 1 : 0); + for (int n = 0; n < p->numparams; n++) + { + APPENDPRINT "%s", getstr(p->locvars[n].varname) END + if (n != numParams - 1) + APPENDPRINT "," END + } + if (p->is_vararg) + APPENDPRINT "..." END + APPENDPRINT ")" END + } + break; + defcase: default: + APPENDPRINT "%s:%p", luaL_typename(L, i), lua_topointer(L, i) END break; + case LUA_TTABLE: + { + // first make sure there's enough stack space + if (!lua_checkstack(L, 4)) + { + // note that even if lua_checkstack never returns false, + // that doesn't mean we didn't need to call it, + // because calling it retrieves stack space past LUA_MINSTACK + goto defcase; + } + + std::vector::const_iterator foundCycleIter = + std::find(s_tableAddressStack.begin(), s_tableAddressStack.end(), lua_topointer(L, i)); + if (foundCycleIter != s_tableAddressStack.end()) + { + int parentNum = s_tableAddressStack.end() - foundCycleIter; + if (parentNum > 1) + APPENDPRINT "%s:parent^%d", luaL_typename(L, i), parentNum END + else + APPENDPRINT "%s:parent", luaL_typename(L, i) END + } + else + { + s_tableAddressStack.push_back(lua_topointer(L, i)); + struct Scope { ~Scope(){ s_tableAddressStack. pop_back(); } } scope; + + APPENDPRINT "{" END + + lua_pushnil(L); // first key + int keyIndex = lua_gettop(L); + int valueIndex = keyIndex + 1; + bool first = true; + bool skipKey = true; // true if we're still in the "array part" of the table + lua_Number arrayIndex = (lua_Number)0; + while (lua_next(L, i)) + { + if (first) + first = false; else - { - APPENDPRINT "function(" END - Proto * p = (L->base + i - 1)->value.gc->cl.l.p; - int numParams = p->numparams + (p->is_vararg ? 1 : 0); - for (int n = 0; n < p->numparams; n++) - { - APPENDPRINT "%s", getstr(p->locvars[n].varname) END - if (n != numParams - 1) - APPENDPRINT "," END - } - if (p->is_vararg) - APPENDPRINT "..." END - APPENDPRINT ")" END - } - break; -defcase: default: - APPENDPRINT "%s:%p", luaL_typename(L, i), lua_topointer(L, i) END break; - case LUA_TTABLE: - { - // first make sure there's enough stack space - if (!lua_checkstack(L, 4)) - { - // note that even if lua_checkstack never returns false, - // that doesn't mean we didn't need to call it, - // because calling it retrieves stack space past LUA_MINSTACK - goto defcase; - } - - std::vector::const_iterator foundCycleIter = - std::find(s_tableAddressStack.begin(), s_tableAddressStack.end(), lua_topointer(L, i)); - if (foundCycleIter != s_tableAddressStack.end()) - { - int parentNum = s_tableAddressStack.end() - foundCycleIter; - if (parentNum > 1) - APPENDPRINT "%s:parent^%d", luaL_typename(L, i), parentNum END - else - APPENDPRINT "%s:parent", luaL_typename(L, i) END - } - else - { - s_tableAddressStack.push_back(lua_topointer(L, i)); - struct Scope { ~Scope(){ s_tableAddressStack. pop_back(); } } scope; - - APPENDPRINT "{" END - - lua_pushnil(L); // first key - int keyIndex = lua_gettop(L); - int valueIndex = keyIndex + 1; - bool first = true; - bool skipKey = true; // true if we're still in the "array part" of the table - lua_Number arrayIndex = (lua_Number)0; - while (lua_next(L, i)) - { - if (first) - first = false; - else - APPENDPRINT ", " END - if (skipKey) - { - arrayIndex += (lua_Number)1; - bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER); - skipKey = keyIsNumber && (lua_tonumber(L, keyIndex) == arrayIndex); - } - if (!skipKey) - { - bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING); - bool invalidLuaIdentifier = (!keyIsString || !isalphaorunderscore(*lua_tostring(L, keyIndex))); - if (invalidLuaIdentifier) - if (keyIsString) - APPENDPRINT "['" END - else - APPENDPRINT "[" END - - toCStringConverter(L, keyIndex, ptr, remaining); - // key - - if (invalidLuaIdentifier) - if (keyIsString) - APPENDPRINT "']=" END - else - APPENDPRINT "]=" END - else - APPENDPRINT "=" END - } - - bool valueIsString = (lua_type(L, valueIndex) == LUA_TSTRING); - if (valueIsString) - APPENDPRINT "'" END - - toCStringConverter(L, valueIndex, ptr, remaining); // value - - if (valueIsString) - APPENDPRINT "'" END - - lua_pop(L, 1); - - if (remaining <= 0) - { - lua_settop(L, keyIndex - 1); // stack might not be clean yet if we're breaking - // early - break; - } - } - APPENDPRINT "}" END - } - } - break; - } - - if (usedMeta) - { - s_metacallStack.pop_back(); - lua_pop(L, 1); - } - } - - static const int s_tempStrMaxLen = 64 * 1024; - static char s_tempStr [s_tempStrMaxLen]; - - static char *rawToCString(lua_State *L, int idx) - { - int a = idx > 0 ? idx : 1; - int n = idx > 0 ? idx : lua_gettop(L); - - char *ptr = s_tempStr; - *ptr = 0; - - int remaining = s_tempStrMaxLen; - for (int i = a; i <= n; i++) - { - toCStringConverter(L, i, ptr, remaining); - if (i != n) - APPENDPRINT " " END - } - - if (remaining < 3) - { - while (remaining < 6) - remaining++, ptr--; - APPENDPRINT "..." END - } - APPENDPRINT "\r\n" END - // the trailing newline is so print() can avoid having to do wasteful things to print its newline - // (string copying would be wasteful and calling info.print() twice can be extremely slow) - // at the cost of functions that don't want the newline needing to trim off the last two characters - // (which is a very fast operation and thus acceptable in this case) - - return s_tempStr; - } + APPENDPRINT ", " END + if (skipKey) + { + arrayIndex += (lua_Number)1; + bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER); + skipKey = keyIsNumber && (lua_tonumber(L, keyIndex) == arrayIndex); + } + if (!skipKey) + { + bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING); + bool invalidLuaIdentifier = (!keyIsString || !isalphaorunderscore(*lua_tostring(L, keyIndex))); + if (invalidLuaIdentifier) + if (keyIsString) + APPENDPRINT "['" END + else + APPENDPRINT "[" END + + toCStringConverter(L, keyIndex, ptr, remaining); + // key + + if (invalidLuaIdentifier) + if (keyIsString) + APPENDPRINT "']=" END + else + APPENDPRINT "]=" END + else + APPENDPRINT "=" END + } + + bool valueIsString = (lua_type(L, valueIndex) == LUA_TSTRING); + if (valueIsString) + APPENDPRINT "'" END + + toCStringConverter(L, valueIndex, ptr, remaining); // value + + if (valueIsString) + APPENDPRINT "'" END + + lua_pop(L, 1); + + if (remaining <= 0) + { + lua_settop(L, keyIndex - 1); // stack might not be clean yet if we're breaking + // early + break; + } + } + APPENDPRINT "}" END + } + } + break; + } + + if (usedMeta) + { + s_metacallStack.pop_back(); + lua_pop(L, 1); + } +} + +static const int s_tempStrMaxLen = 64 * 1024; +static char s_tempStr [s_tempStrMaxLen]; + +static char *rawToCString(lua_State *L, int idx) +{ + int a = idx > 0 ? idx : 1; + int n = idx > 0 ? idx : lua_gettop(L); + + char *ptr = s_tempStr; + *ptr = 0; + + int remaining = s_tempStrMaxLen; + for (int i = a; i <= n; i++) + { + toCStringConverter(L, i, ptr, remaining); + if (i != n) + APPENDPRINT " " END + } + + if (remaining < 3) + { + while (remaining < 6) + remaining++, ptr--; + APPENDPRINT "..." END + } + APPENDPRINT "\r\n" END + // the trailing newline is so print() can avoid having to do wasteful things to print its newline + // (string copying would be wasteful and calling info.print() twice can be extremely slow) + // at the cost of functions that don't want the newline needing to trim off the last two characters + // (which is a very fast operation and thus acceptable in this case) + + return s_tempStr; +} #undef APPENDPRINT #undef END // replacement for luaB_tostring() that is able to show the contents of tables (and formats numbers better, and show function // prototypes) // can be called directly from lua via tostring(), assuming tostring hasn't been reassigned - static int tostring(lua_State *L) - { - char *str = rawToCString(L); - str[strlen(str) - 2] = 0; // hack: trim off the \r\n (which is there to simplify the print function's - // task) - lua_pushstring(L, str); - return 1; - } +static int tostring(lua_State *L) +{ + char *str = rawToCString(L); + str[strlen(str) - 2] = 0; // hack: trim off the \r\n (which is there to simplify the print function's + // task) + lua_pushstring(L, str); + return 1; +} // like rawToCString, but will check if the global Lua function tostring() // has been replaced with a custom function, and call that instead if so - static const char *toCString(lua_State *L, int idx) - { - int a = idx > 0 ? idx : 1; - int n = idx > 0 ? idx : lua_gettop(L); - lua_getglobal(L, "tostring"); - lua_CFunction cf = lua_tocfunction(L, -1); - if (cf == tostring || lua_isnil(L, -1)) // optimization: if using our own C tostring function, we can - // bypass the call through Lua and all the string object - // allocation that would entail - { - lua_pop(L, 1); - return rawToCString(L, idx); - } - else // if the user overrided the tostring function, we have to actually call it and store the - // temporarily allocated string it returns - { - lua_pushstring(L, ""); - for (int i = a; i <= n; i++) - { - lua_pushvalue(L, -2); // function to be called - lua_pushvalue(L, i); // value to print - lua_call(L, 1, 1); - if (lua_tostring(L, -1) == NULL) - luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print")); - lua_pushstring(L, (i < n) ? " " : "\r\n"); - lua_concat(L, 3); - } - const char *str = lua_tostring(L, -1); - strncpy(s_tempStr, str, s_tempStrMaxLen); - s_tempStr[s_tempStrMaxLen - 1] = 0; - lua_pop(L, 2); - return s_tempStr; - } - } +static const char *toCString(lua_State *L, int idx) +{ + int a = idx > 0 ? idx : 1; + int n = idx > 0 ? idx : lua_gettop(L); + lua_getglobal(L, "tostring"); + lua_CFunction cf = lua_tocfunction(L, -1); + if (cf == tostring || lua_isnil(L, -1)) // optimization: if using our own C tostring function, we can + // bypass the call through Lua and all the string object + // allocation that would entail + { + lua_pop(L, 1); + return rawToCString(L, idx); + } + else // if the user overrided the tostring function, we have to actually call it and store the + // temporarily allocated string it returns + { + lua_pushstring(L, ""); + for (int i = a; i <= n; i++) + { + lua_pushvalue(L, -2); // function to be called + lua_pushvalue(L, i); // value to print + lua_call(L, 1, 1); + if (lua_tostring(L, -1) == NULL) + luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print")); + lua_pushstring(L, (i < n) ? " " : "\r\n"); + lua_concat(L, 3); + } + const char *str = lua_tostring(L, -1); + strncpy(s_tempStr, str, s_tempStrMaxLen); + s_tempStr[s_tempStrMaxLen - 1] = 0; + lua_pop(L, 2); + return s_tempStr; + } +} // replacement for luaB_print() that goes to the appropriate textbox instead of stdout - static int print(lua_State *L) - { - const char *str = toCString(L); - - int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread]; - //LuaContextInfo& info = GetCurrentInfo(); - - if (info_print) - info_print(uid, str); - else - puts(str); - - //worry(L, 100); - return 0; - } - - static int printerror(lua_State *L, int idx) - { - lua_checkstack(L, lua_gettop(L) + 4); - - if (idx < 0) - idx = lua_gettop(L) + 1 + idx; - - const char *str = rawToCString(L, idx); - - int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread]; - //LuaContextInfo& info = GetCurrentInfo(); - - if (info_print) - info_print(uid, str); - else - fputs(str, stderr); - - //worry(L, 100); - return 0; - } +static int print(lua_State *L) +{ + const char *str = toCString(L); + + int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread]; + //LuaContextInfo& info = GetCurrentInfo(); + + if (info_print) + info_print(uid, str); + else + puts(str); + + //worry(L, 100); + return 0; +} + +static int printerror(lua_State *L, int idx) +{ + lua_checkstack(L, lua_gettop(L) + 4); + + if (idx < 0) + idx = lua_gettop(L) + 1 + idx; + + const char *str = rawToCString(L, idx); + + int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread]; + //LuaContextInfo& info = GetCurrentInfo(); + + if (info_print) + info_print(uid, str); + else + fputs(str, stderr); + + //worry(L, 100); + return 0; +} // vba.message(string msg) // // Displays the given message on the screen. - static int vba_message(lua_State *L) - { - const char *msg = luaL_checkstring(L, 1); - systemScreenMessage(msg); - - return 0; - } +static int vba_message(lua_State *L) +{ + const char *msg = luaL_checkstring(L, 1); + systemScreenMessage(msg); + + return 0; +} // provides an easy way to copy a table from Lua // (simple assignment only makes an alias, but sometimes an independent table is desired) // currently this function only performs a shallow copy, // but I think it should be changed to do a deep copy (possibly of configurable depth?) // that maintains the internal table reference structure - static int copytable(lua_State *L) - { - int origIndex = 1; // we only care about the first argument - int origType = lua_type(L, origIndex); - if (origType == LUA_TNIL) - { - lua_pushnil(L); - return 1; - } - if (origType != LUA_TTABLE) - { - luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE)); - lua_pushnil(L); - return 1; - } - - lua_createtable(L, lua_objlen(L, 1), 0); - int copyIndex = lua_gettop(L); - - lua_pushnil(L); // first key - int keyIndex = lua_gettop(L); - int valueIndex = keyIndex + 1; - - while (lua_next(L, origIndex)) - { - lua_pushvalue(L, keyIndex); - lua_pushvalue(L, valueIndex); - lua_rawset(L, copyIndex); // copytable[key] = value - lua_pop(L, 1); - } - - // copy the reference to the metatable as well, if any - if (lua_getmetatable(L, origIndex)) - lua_setmetatable(L, copyIndex); - - return 1; // return the new table - } +static int copytable(lua_State *L) +{ + int origIndex = 1; // we only care about the first argument + int origType = lua_type(L, origIndex); + if (origType == LUA_TNIL) + { + lua_pushnil(L); + return 1; + } + if (origType != LUA_TTABLE) + { + luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE)); + lua_pushnil(L); + return 1; + } + + lua_createtable(L, lua_objlen(L, 1), 0); + int copyIndex = lua_gettop(L); + + lua_pushnil(L); // first key + int keyIndex = lua_gettop(L); + int valueIndex = keyIndex + 1; + + while (lua_next(L, origIndex)) + { + lua_pushvalue(L, keyIndex); + lua_pushvalue(L, valueIndex); + lua_rawset(L, copyIndex); // copytable[key] = value + lua_pop(L, 1); + } + + // copy the reference to the metatable as well, if any + if (lua_getmetatable(L, origIndex)) + lua_setmetatable(L, copyIndex); + + return 1; // return the new table +} // because print traditionally shows the address of tables, // and the print function I provide instead shows the contents of tables, // I also provide this function // (otherwise there would be no way to see a table's address, AFAICT) - static int addressof(lua_State *L) - { - const void *ptr = lua_topointer(L, -1); - lua_pushinteger(L, (lua_Integer)ptr); - return 1; - } - - struct registerPointerMap - { - const char * registerName; - unsigned int *pointer; - int dataSize; - }; - -#define RPM_ENTRY(name, var) \ - { name, (unsigned int *)&var, sizeof(var) \ - } \ - , - - extern gbRegister AF; - extern gbRegister BC; - extern gbRegister DE; - extern gbRegister HL; - extern gbRegister SP; - extern gbRegister PC; - extern u16 IFF; - - registerPointerMap regPointerMap [] = { - // gba registers - RPM_ENTRY("r0", reg[0].I) - RPM_ENTRY("r1", reg[1].I) - RPM_ENTRY("r2", reg[2].I) - RPM_ENTRY("r3", reg[3].I) - RPM_ENTRY("r4", reg[4].I) - RPM_ENTRY("r5", reg[5].I) - RPM_ENTRY("r6", reg[6].I) - RPM_ENTRY("r7", reg[7].I) - RPM_ENTRY("r8", reg[8].I) - RPM_ENTRY("r9", reg[9].I) - RPM_ENTRY("r10", reg[10].I) - RPM_ENTRY("r11", reg[11].I) - RPM_ENTRY("r12", reg[12].I) - RPM_ENTRY("r13", reg[13].I) - RPM_ENTRY("r14", reg[14].I) - RPM_ENTRY("r15", reg[15].I) - RPM_ENTRY("cpsr", reg[16].I) - RPM_ENTRY("spsr", reg[17].I) - // gb registers - RPM_ENTRY("a", AF.B.B1) - RPM_ENTRY("f", AF.B.B0) - RPM_ENTRY("b", BC.B.B1) - RPM_ENTRY("c", BC.B.B0) - RPM_ENTRY("d", DE.B.B1) - RPM_ENTRY("e", DE.B.B0) - RPM_ENTRY("h", HL.B.B1) - RPM_ENTRY("l", HL.B.B0) - RPM_ENTRY("af", AF.W) - RPM_ENTRY("bc", BC.W) - RPM_ENTRY("de", DE.W) - RPM_ENTRY("hl", HL.W) - RPM_ENTRY("sp", SP.W) - RPM_ENTRY("pc", PC.W) - {} - }; - - struct cpuToRegisterMap - { - const char *cpuName; - registerPointerMap *rpmap; - } - cpuToRegisterMaps [] = - { - { "", regPointerMap }, - }; +static int addressof(lua_State *L) +{ + const void *ptr = lua_topointer(L, -1); + lua_pushinteger(L, (lua_Integer)ptr); + return 1; +} + +struct registerPointerMap +{ + const char * registerName; + unsigned int *pointer; + int dataSize; +}; + +#define RPM_ENTRY(name, var) \ + { name, (unsigned int *)&var, sizeof(var) \ + } \ + , + +extern gbRegister AF; +extern gbRegister BC; +extern gbRegister DE; +extern gbRegister HL; +extern gbRegister SP; +extern gbRegister PC; +extern u16 IFF; + +registerPointerMap regPointerMap [] = { + // gba registers + RPM_ENTRY("r0", reg[0].I) + RPM_ENTRY("r1", reg[1].I) + RPM_ENTRY("r2", reg[2].I) + RPM_ENTRY("r3", reg[3].I) + RPM_ENTRY("r4", reg[4].I) + RPM_ENTRY("r5", reg[5].I) + RPM_ENTRY("r6", reg[6].I) + RPM_ENTRY("r7", reg[7].I) + RPM_ENTRY("r8", reg[8].I) + RPM_ENTRY("r9", reg[9].I) + RPM_ENTRY("r10", reg[10].I) + RPM_ENTRY("r11", reg[11].I) + RPM_ENTRY("r12", reg[12].I) + RPM_ENTRY("r13", reg[13].I) + RPM_ENTRY("r14", reg[14].I) + RPM_ENTRY("r15", reg[15].I) + RPM_ENTRY("cpsr", reg[16].I) + RPM_ENTRY("spsr", reg[17].I) + // gb registers + RPM_ENTRY("a", AF.B.B1) + RPM_ENTRY("f", AF.B.B0) + RPM_ENTRY("b", BC.B.B1) + RPM_ENTRY("c", BC.B.B0) + RPM_ENTRY("d", DE.B.B1) + RPM_ENTRY("e", DE.B.B0) + RPM_ENTRY("h", HL.B.B1) + RPM_ENTRY("l", HL.B.B0) + RPM_ENTRY("af", AF.W) + RPM_ENTRY("bc", BC.W) + RPM_ENTRY("de", DE.W) + RPM_ENTRY("hl", HL.W) + RPM_ENTRY("sp", SP.W) + RPM_ENTRY("pc", PC.W) + {} +}; + +struct cpuToRegisterMap +{ + const char *cpuName; + registerPointerMap *rpmap; +} + cpuToRegisterMaps [] = + { + { "", regPointerMap }, + }; //DEFINE_LUA_FUNCTION(memory_getregister, "cpu_dot_registername_string") - static int memory_getregister(lua_State *L) - { - const char *qualifiedRegisterName = luaL_checkstring(L, 1); - lua_settop(L, 0); - for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++) - { - cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu]; - int cpuNameLen = strlen(ctrm.cpuName); - if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen)) - { - qualifiedRegisterName += cpuNameLen; - for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++) - { - registerPointerMap rpm = ctrm.rpmap[reg]; - if (!stricmp(qualifiedRegisterName, rpm.registerName)) - { - switch (rpm.dataSize) - { - default: - case 1: - lua_pushinteger(L, *(unsigned char *)rpm.pointer); break; - case 2: - lua_pushinteger(L, *(unsigned short *)rpm.pointer); break; - case 4: - lua_pushinteger(L, *(unsigned long *)rpm.pointer); break; - } - return 1; - } - } - lua_pushnil(L); - return 1; - } - } - lua_pushnil(L); - return 1; - } +static int memory_getregister(lua_State *L) +{ + const char *qualifiedRegisterName = luaL_checkstring(L, 1); + lua_settop(L, 0); + for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++) + { + cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu]; + int cpuNameLen = strlen(ctrm.cpuName); + if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen)) + { + qualifiedRegisterName += cpuNameLen; + for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++) + { + registerPointerMap rpm = ctrm.rpmap[reg]; + if (!stricmp(qualifiedRegisterName, rpm.registerName)) + { + switch (rpm.dataSize) + { + default: + case 1: + lua_pushinteger(L, *(unsigned char *)rpm.pointer); break; + case 2: + lua_pushinteger(L, *(unsigned short *)rpm.pointer); break; + case 4: + lua_pushinteger(L, *(unsigned long *)rpm.pointer); break; + } + return 1; + } + } + lua_pushnil(L); + return 1; + } + } + lua_pushnil(L); + return 1; +} //DEFINE_LUA_FUNCTION(memory_setregister, "cpu_dot_registername_string,value") - static int memory_setregister(lua_State *L) - { - const char * qualifiedRegisterName = luaL_checkstring(L, 1); - unsigned long value = (unsigned long)(luaL_checkinteger(L, 2)); - lua_settop(L, 0); - for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++) - { - cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu]; - int cpuNameLen = strlen(ctrm.cpuName); - if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen)) - { - qualifiedRegisterName += cpuNameLen; - for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++) - { - registerPointerMap rpm = ctrm.rpmap[reg]; - if (!stricmp(qualifiedRegisterName, rpm.registerName)) - { - switch (rpm.dataSize) - { - default: - case 1: - *(unsigned char *)rpm.pointer = (unsigned char)(value & 0xFF); break; - case 2: - *(unsigned short *)rpm.pointer = (unsigned short)(value & 0xFFFF); break; - case 4: - *(unsigned long *)rpm.pointer = value; break; - } - return 0; - } - } - return 0; - } - } - return 0; - } - - void HandleCallbackError(lua_State *L) - { - if (L->errfunc || L->errorJmp) - luaL_error(L, "%s", lua_tostring(L, -1)); - else - { - lua_pushnil(LUA); - lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); - - // Error? -//#if (defined(WIN32) && !defined(SDL)) -// info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer(); -// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua run error", MB_OK | MB_ICONSTOP); -//#else -// fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(LUA, -1)); -//#endif - printerror(LUA, -1); - VBALuaStop(); - } - } - - void CallRegisteredLuaFunctions(LuaCallID calltype) - { - assert((unsigned int)calltype < (unsigned int)LUACALL_COUNT); - - const char *idstring = luaCallIDStrings[calltype]; - - if (!LUA) - return; - - lua_settop(LUA, 0); - lua_getfield(LUA, LUA_REGISTRYINDEX, idstring); - - int errorcode = 0; - if (lua_isfunction(LUA, -1)) - { - errorcode = lua_pcall(LUA, 0, 0, 0); - if (errorcode) - HandleCallbackError(LUA); - } - else - { - lua_pop(LUA, 1); - } - } +static int memory_setregister(lua_State *L) +{ + const char * qualifiedRegisterName = luaL_checkstring(L, 1); + unsigned long value = (unsigned long)(luaL_checkinteger(L, 2)); + lua_settop(L, 0); + for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++) + { + cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu]; + int cpuNameLen = strlen(ctrm.cpuName); + if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen)) + { + qualifiedRegisterName += cpuNameLen; + for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++) + { + registerPointerMap rpm = ctrm.rpmap[reg]; + if (!stricmp(qualifiedRegisterName, rpm.registerName)) + { + switch (rpm.dataSize) + { + default: + case 1: + *(unsigned char *)rpm.pointer = (unsigned char)(value & 0xFF); break; + case 2: + *(unsigned short *)rpm.pointer = (unsigned short)(value & 0xFFFF); break; + case 4: + *(unsigned long *)rpm.pointer = value; break; + } + return 0; + } + } + return 0; + } + } + return 0; +} + +void HandleCallbackError(lua_State *L) +{ + if (L->errfunc || L->errorJmp) + luaL_error(L, "%s", lua_tostring(L, -1)); + else + { + lua_pushnil(LUA); + lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); + + // Error? + //#if (defined(WIN32) && !defined(SDL)) + // info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer(); + // AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua run error", MB_OK | MB_ICONSTOP); + //#else + // fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(LUA, -1)); + //#endif + printerror(LUA, -1); + VBALuaStop(); + } +} + +void CallRegisteredLuaFunctions(LuaCallID calltype) +{ + assert((unsigned int)calltype < (unsigned int)LUACALL_COUNT); + + const char *idstring = luaCallIDStrings[calltype]; + + if (!LUA) + return; + + lua_settop(LUA, 0); + lua_getfield(LUA, LUA_REGISTRYINDEX, idstring); + + int errorcode = 0; + if (lua_isfunction(LUA, -1)) + { + errorcode = lua_pcall(LUA, 0, 0, 0); + if (errorcode) + HandleCallbackError(LUA); + } + else + { + lua_pop(LUA, 1); + } +} // the purpose of this structure is to provide a way of // QUICKLY determining whether a memory address range has a hook associated with it, @@ -1055,778 +1055,778 @@ // otherwise it would definitely be too slow.) // calculating the regions when a hook is added/removed may be slow, // but this is an intentional tradeoff to obtain a high speed of checking during later execution - struct TieredRegion - { - template - struct Region - { - struct Island - { - unsigned int start; - unsigned int end; - __forceinline bool Contains(unsigned int address, int size) const { return address < end && address + size > start; } - }; - std::vector islands; - - void Calculate(const std::vector &bytes) - { - islands. clear(); - - unsigned int lastEnd = ~0; - - std::vector::const_iterator iter = bytes.begin(); - std::vector::const_iterator end = bytes.end(); - for (; iter != end; ++iter) - { - unsigned int addr = *iter; - if (addr < lastEnd || addr > lastEnd + (long long)maxGap) - { - islands. push_back(Island()); - islands. back().start = addr; - } - islands.back(). end = addr + 1; - lastEnd = addr + 1; - } - } - - bool Contains(unsigned int address, int size) const - { - for (size_t i = 0; i != islands.size(); ++i) - { - if (islands[i].Contains(address, size)) - return true; - } - return false; - } - }; - - Region<0xFFFFFFFF> broad; - Region<0x1000> mid; - Region<0> narrow; - - void Calculate(std::vector &bytes) - { - std:: sort(bytes.begin(), bytes.end()); - - broad. Calculate(bytes); - mid. Calculate(bytes); - narrow. Calculate(bytes); - } - - TieredRegion() - { - std::vector temp; - Calculate(temp); - } - - __forceinline int NotEmpty() - { - return broad.islands.size(); - } - - // note: it is illegal to call this if NotEmpty() returns 0 - __forceinline bool Contains(unsigned int address, int size) - { - return broad.islands[0].Contains(address, size) && - mid.Contains(address, size) && - narrow.Contains(address, size); - } - }; - TieredRegion hookedRegions [LUAMEMHOOK_COUNT]; - - static void CalculateMemHookRegions(LuaMemHookType hookType) - { - std::vector hookedBytes; -// std::map::iterator iter = luaContextInfo.begin(); -// std::map::iterator end = luaContextInfo.end(); -// while(iter != end) -// { -// LuaContextInfo& info = *iter->second; - if (/*info.*/ numMemHooks) - { - lua_State *L = LUA /*info.L*/; - if (L) - { - lua_settop(L, 0); - lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); - lua_pushnil(L); - while (lua_next(L, -2)) - { - if (lua_isfunction(L, -1)) - { - unsigned int addr = lua_tointeger(L, -2); - hookedBytes.push_back(addr); - } - lua_pop(L, 1); - } - lua_settop(L, 0); - } - } -// ++iter; -// } - hookedRegions[hookType].Calculate(hookedBytes); - } - - static void CallRegisteredLuaMemHook_LuaMatch(unsigned int address, int size, unsigned int value, LuaMemHookType hookType) - { -// std::map::iterator iter = luaContextInfo.begin(); -// std::map::iterator end = luaContextInfo.end(); -// while(iter != end) -// { -// LuaContextInfo& info = *iter->second; - if (/*info.*/ numMemHooks) - { - lua_State *L = LUA /*info.L*/; - if (L /* && !info.panic*/) - { +struct TieredRegion +{ + template + struct Region + { + struct Island + { + unsigned int start; + unsigned int end; + __forceinline bool Contains(unsigned int address, int size) const { return address < end && address + size > start; } + }; + std::vector islands; + + void Calculate(const std::vector &bytes) + { + islands. clear(); + + unsigned int lastEnd = ~0; + + std::vector::const_iterator iter = bytes.begin(); + std::vector::const_iterator end = bytes.end(); + for (; iter != end; ++iter) + { + unsigned int addr = *iter; + if (addr < lastEnd || addr > lastEnd + (long long)maxGap) + { + islands. push_back(Island()); + islands. back().start = addr; + } + islands.back(). end = addr + 1; + lastEnd = addr + 1; + } + } + + bool Contains(unsigned int address, int size) const + { + for (size_t i = 0; i != islands.size(); ++i) + { + if (islands[i].Contains(address, size)) + return true; + } + return false; + } + }; + + Region<0xFFFFFFFF> broad; + Region<0x1000> mid; + Region<0> narrow; + + void Calculate(std::vector &bytes) + { + std:: sort(bytes.begin(), bytes.end()); + + broad. Calculate(bytes); + mid. Calculate(bytes); + narrow. Calculate(bytes); + } + + TieredRegion() + { + std::vector temp; + Calculate(temp); + } + + __forceinline int NotEmpty() + { + return broad.islands.size(); + } + + // note: it is illegal to call this if NotEmpty() returns 0 + __forceinline bool Contains(unsigned int address, int size) + { + return broad.islands[0].Contains(address, size) && + mid.Contains(address, size) && + narrow.Contains(address, size); + } +}; +TieredRegion hookedRegions [LUAMEMHOOK_COUNT]; + +static void CalculateMemHookRegions(LuaMemHookType hookType) +{ + std::vector hookedBytes; + // std::map::iterator iter = luaContextInfo.begin(); + // std::map::iterator end = luaContextInfo.end(); + // while(iter != end) + // { + // LuaContextInfo& info = *iter->second; + if (/*info.*/ numMemHooks) + { + lua_State *L = LUA /*info.L*/; + if (L) + { + lua_settop(L, 0); + lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); + lua_pushnil(L); + while (lua_next(L, -2)) + { + if (lua_isfunction(L, -1)) + { + unsigned int addr = lua_tointeger(L, -2); + hookedBytes.push_back(addr); + } + lua_pop(L, 1); + } + lua_settop(L, 0); + } + } + // ++iter; + // } + hookedRegions[hookType].Calculate(hookedBytes); +} + +static void CallRegisteredLuaMemHook_LuaMatch(unsigned int address, int size, unsigned int value, LuaMemHookType hookType) +{ + // std::map::iterator iter = luaContextInfo.begin(); + // std::map::iterator end = luaContextInfo.end(); + // while(iter != end) + // { + // LuaContextInfo& info = *iter->second; + if (/*info.*/ numMemHooks) + { + lua_State *L = LUA /*info.L*/; + if (L /* && !info.panic*/) + { #ifdef USE_INFO_STACK - infoStack.insert(infoStack.begin(), &info); - struct Scope { ~Scope(){ infoStack. erase(infoStack.begin()); } } scope; + infoStack.insert(infoStack.begin(), &info); + struct Scope { ~Scope(){ infoStack. erase(infoStack.begin()); } } scope; #endif - lua_settop(L, 0); - lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); - for (int i = address; i != address + size; i++) - { - lua_rawgeti(L, -1, i); - if (lua_isfunction(L, -1)) - { - bool wasRunning = (luaRunning != 0) /*info.running*/; - luaRunning /*info.running*/ = true; - //RefreshScriptSpeedStatus(); - lua_pushinteger(L, address); - lua_pushinteger(L, size); - int errorcode = lua_pcall(L, 2, 0, 0); - luaRunning /*info.running*/ = wasRunning; - //RefreshScriptSpeedStatus(); - if (errorcode) - { - HandleCallbackError(L); - //int uid = iter->first; - //HandleCallbackError(L,info,uid,true); - } - break; - } - else - { - lua_pop(L, 1); - } - } - lua_settop(L, 0); - } - } -// ++iter; -// } - } - - void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType) - { - // performance critical! (called VERY frequently) - // I suggest timing a large number of calls to this function in Release if you change anything in here, - // before and after, because even the most innocent change can make it become 30% to 400% slower. - // a good amount to test is: 100000000 calls with no hook set, and another 100000000 with a hook set. - // (on my system that consistently took 200 ms total in the former case and 350 ms total in the latter - // case) - if (hookedRegions[hookType].NotEmpty()) - { - //if((hookType <= LUAMEMHOOK_EXEC) && (address >= 0xE00000)) - // address |= 0xFF0000; // account for mirroring of RAM - if (hookedRegions[hookType].Contains(address, size)) - CallRegisteredLuaMemHook_LuaMatch(address, size, value, hookType); // something has hooked this - // specific address - } - } - - static int memory_registerHook(lua_State *L, LuaMemHookType hookType, int defaultSize) - { - // get first argument: address - unsigned int addr = luaL_checkinteger(L, 1); - //if((addr & ~0xFFFFFF) == ~0xFFFFFF) - // addr &= 0xFFFFFF; - - // get optional second argument: size - int size = defaultSize; - int funcIdx = 2; - if (lua_isnumber(L, 2)) - { - size = luaL_checkinteger(L, 2); - if (size < 0) - { - size = -size; - addr -= size; - } - funcIdx++; - } - - // check last argument: callback function - bool clearing = lua_isnil(L, funcIdx); - if (!clearing) - luaL_checktype(L, funcIdx, LUA_TFUNCTION); - lua_settop(L, funcIdx); - - // get the address-to-callback table for this hook type of the current script - lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); - - // count how many callback functions we'll be displacing - int numFuncsAfter = clearing ? 0 : size; - int numFuncsBefore = 0; - for (unsigned int i = addr; i != addr + size; i++) - { - lua_rawgeti(L, -1, i); - if (lua_isfunction(L, -1)) - numFuncsBefore++; - lua_pop(L, 1); - } - - // put the callback function in the address slots - for (unsigned int i = addr; i != addr + size; i++) - { - lua_pushvalue(L, -2); - lua_rawseti(L, -2, i); - } - - // adjust the count of active hooks - //LuaContextInfo& info = GetCurrentInfo(); - /*info.*/ numMemHooks += numFuncsAfter - numFuncsBefore; - - // re-cache regions of hooked memory across all scripts - CalculateMemHookRegions(hookType); - - //StopScriptIfFinished(luaStateToUIDMap[L]); - return 0; - } - - LuaMemHookType MatchHookTypeToCPU(lua_State *L, LuaMemHookType hookType) - { - int cpuID = 0; - - int cpunameIndex = 0; - if (lua_type(L, 2) == LUA_TSTRING) - cpunameIndex = 2; - else if (lua_type(L, 3) == LUA_TSTRING) - cpunameIndex = 3; - - if (cpunameIndex) - { - const char *cpuName = lua_tostring(L, cpunameIndex); - if (!stricmp(cpuName, "sub")) - cpuID = 1; - lua_remove(L, cpunameIndex); - } - - switch (cpuID) - { - case 0: - return hookType; - - case 1: - switch (hookType) - { - case LUAMEMHOOK_WRITE: - return LUAMEMHOOK_WRITE_SUB; - case LUAMEMHOOK_READ: - return LUAMEMHOOK_READ_SUB; - case LUAMEMHOOK_EXEC: - return LUAMEMHOOK_EXEC_SUB; - } - } - return hookType; - } - - static int memory_registerwrite(lua_State *L) - { - return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_WRITE), 1); - } - - static int memory_registerread(lua_State *L) - { - return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_READ), 1); - } - - static int memory_registerexec(lua_State *L) - { - return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_EXEC), 1); - } + lua_settop(L, 0); + lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); + for (int i = address; i != address + size; i++) + { + lua_rawgeti(L, -1, i); + if (lua_isfunction(L, -1)) + { + bool wasRunning = (luaRunning != 0) /*info.running*/; + luaRunning /*info.running*/ = true; + //RefreshScriptSpeedStatus(); + lua_pushinteger(L, address); + lua_pushinteger(L, size); + int errorcode = lua_pcall(L, 2, 0, 0); + luaRunning /*info.running*/ = wasRunning; + //RefreshScriptSpeedStatus(); + if (errorcode) + { + HandleCallbackError(L); + //int uid = iter->first; + //HandleCallbackError(L,info,uid,true); + } + break; + } + else + { + lua_pop(L, 1); + } + } + lua_settop(L, 0); + } + } + // ++iter; + // } +} + +void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType) +{ + // performance critical! (called VERY frequently) + // I suggest timing a large number of calls to this function in Release if you change anything in here, + // before and after, because even the most innocent change can make it become 30% to 400% slower. + // a good amount to test is: 100000000 calls with no hook set, and another 100000000 with a hook set. + // (on my system that consistently took 200 ms total in the former case and 350 ms total in the latter + // case) + if (hookedRegions[hookType].NotEmpty()) + { + //if((hookType <= LUAMEMHOOK_EXEC) && (address >= 0xE00000)) + // address |= 0xFF0000; // account for mirroring of RAM + if (hookedRegions[hookType].Contains(address, size)) + CallRegisteredLuaMemHook_LuaMatch(address, size, value, hookType); // something has hooked this + // specific address + } +} + +static int memory_registerHook(lua_State *L, LuaMemHookType hookType, int defaultSize) +{ + // get first argument: address + unsigned int addr = luaL_checkinteger(L, 1); + //if((addr & ~0xFFFFFF) == ~0xFFFFFF) + // addr &= 0xFFFFFF; + + // get optional second argument: size + int size = defaultSize; + int funcIdx = 2; + if (lua_isnumber(L, 2)) + { + size = luaL_checkinteger(L, 2); + if (size < 0) + { + size = -size; + addr -= size; + } + funcIdx++; + } + + // check last argument: callback function + bool clearing = lua_isnil(L, funcIdx); + if (!clearing) + luaL_checktype(L, funcIdx, LUA_TFUNCTION); + lua_settop(L, funcIdx); + + // get the address-to-callback table for this hook type of the current script + lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); + + // count how many callback functions we'll be displacing + int numFuncsAfter = clearing ? 0 : size; + int numFuncsBefore = 0; + for (unsigned int i = addr; i != addr + size; i++) + { + lua_rawgeti(L, -1, i); + if (lua_isfunction(L, -1)) + numFuncsBefore++; + lua_pop(L, 1); + } + + // put the callback function in the address slots + for (unsigned int i = addr; i != addr + size; i++) + { + lua_pushvalue(L, -2); + lua_rawseti(L, -2, i); + } + + // adjust the count of active hooks + //LuaContextInfo& info = GetCurrentInfo(); + /*info.*/ numMemHooks += numFuncsAfter - numFuncsBefore; + + // re-cache regions of hooked memory across all scripts + CalculateMemHookRegions(hookType); + + //StopScriptIfFinished(luaStateToUIDMap[L]); + return 0; +} + +LuaMemHookType MatchHookTypeToCPU(lua_State *L, LuaMemHookType hookType) +{ + int cpuID = 0; + + int cpunameIndex = 0; + if (lua_type(L, 2) == LUA_TSTRING) + cpunameIndex = 2; + else if (lua_type(L, 3) == LUA_TSTRING) + cpunameIndex = 3; + + if (cpunameIndex) + { + const char *cpuName = lua_tostring(L, cpunameIndex); + if (!stricmp(cpuName, "sub")) + cpuID = 1; + lua_remove(L, cpunameIndex); + } + + switch (cpuID) + { + case 0: + return hookType; + + case 1: + switch (hookType) + { + case LUAMEMHOOK_WRITE: + return LUAMEMHOOK_WRITE_SUB; + case LUAMEMHOOK_READ: + return LUAMEMHOOK_READ_SUB; + case LUAMEMHOOK_EXEC: + return LUAMEMHOOK_EXEC_SUB; + } + } + return hookType; +} + +static int memory_registerwrite(lua_State *L) +{ + return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_WRITE), 1); +} + +static int memory_registerread(lua_State *L) +{ + return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_READ), 1); +} + +static int memory_registerexec(lua_State *L) +{ + return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_EXEC), 1); +} //int vba.lagcount // //Returns the lagcounter variable - static int vba_getlagcount(lua_State *L) - { - lua_pushinteger(L, systemCounters.lagCount); - return 1; - } +static int vba_getlagcount(lua_State *L) +{ + lua_pushinteger(L, systemCounters.lagCount); + return 1; +} //int vba.lagged // //Returns true if the current frame is a lag frame - static int vba_lagged(lua_State *L) - { - lua_pushboolean(L, systemCounters.laggedLast); - return 1; - } +static int vba_lagged(lua_State *L) +{ + lua_pushboolean(L, systemCounters.laggedLast); + return 1; +} // boolean vba.emulating() - int vba_emulating(lua_State *L) - { - lua_pushboolean(L, systemIsEmulating()); - return 1; - } - - int movie_isactive(lua_State *L) - { - lua_pushboolean(L, VBAMovieActive()); - return 1; - } - - int movie_isrecording(lua_State *L) - { - lua_pushboolean(L, VBAMovieRecording()); - return 1; - } - - int movie_isplaying(lua_State *L) - { - lua_pushboolean(L, VBAMoviePlaying()); - return 1; - } - - int movie_getlength(lua_State *L) - { - if (VBAMovieActive()) - lua_pushinteger(L, VBAMovieGetLength()); - else - lua_pushinteger(L, 0); - return 1; - } - - static int memory_readbyte(lua_State *L) - { - u32 addr; - u8 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - val = CPUReadByteQuick(addr); - } - else - { - val = gbReadMemoryQuick8(addr); - } - - lua_pushinteger(L, val); - return 1; - } - - static int memory_readbytesigned(lua_State *L) - { - u32 addr; - s8 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - val = (s8) CPUReadByteQuick(addr); - } - else - { - val = (s8) gbReadMemoryQuick8(addr); - } - - lua_pushinteger(L, val); - return 1; - } - - static int memory_readword(lua_State *L) - { - u32 addr; - u16 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - val = CPUReadHalfWordQuick(addr); - } - else - { - val = gbReadMemoryQuick16(addr & 0x0000FFFF); - } - - lua_pushinteger(L, val); - return 1; - } - - static int memory_readwordsigned(lua_State *L) - { - u32 addr; - s16 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - val = (s16) CPUReadHalfWordQuick(addr); - } - else - { - val = (s16) gbReadMemoryQuick16(addr); - } - - lua_pushinteger(L, val); - return 1; - } - - static int memory_readdword(lua_State *L) - { - u32 addr; - u32 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - val = CPUReadMemoryQuick(addr); - } - else - { - val = gbReadMemoryQuick32(addr & 0x0000FFFF); - } - - // lua_pushinteger doesn't work properly for 32bit system, does it? - if (val >= 0x80000000 && sizeof(int) <= 4) - lua_pushnumber(L, val); - else - lua_pushinteger(L, val); - return 1; - } - - static int memory_readdwordsigned(lua_State *L) - { - u32 addr; - s32 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - val = (s32) CPUReadMemoryQuick(addr); - } - else - { - val = (s32) gbReadMemoryQuick32(addr); - } - - lua_pushinteger(L, val); - return 1; - } - - static int memory_readbyterange(lua_State *L) - { - uint32 address = luaL_checkinteger(L, 1); - int length = luaL_checkinteger(L, 2); - - if (length < 0) - { - address += length; - length = -length; - } - - // push the array - lua_createtable(L, abs(length), 0); - - // put all the values into the (1-based) array - for (int a = address, n = 1; n <= length; a++, n++) - { - unsigned char value; - - if (systemIsRunningGBA()) - { - value = CPUReadByteQuick(a); - } - else - { - value = gbReadMemoryQuick8(a); - } - - lua_pushinteger(L, value); - lua_rawseti(L, -2, n); - } - - return 1; - } - - static int memory_writebyte(lua_State *L) - { - u32 addr; - int val; - - addr = luaL_checkinteger(L, 1); - val = luaL_checkinteger(L, 2); - if (systemIsRunningGBA()) - { - CPUWriteByteQuick(addr, val); - } - else - { - gbWriteMemoryQuick8(addr, val); - } - - CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE); - return 0; - } - - static int memory_writeword(lua_State *L) - { - u32 addr; - int val; - - addr = luaL_checkinteger(L, 1); - val = luaL_checkinteger(L, 2); - if (systemIsRunningGBA()) - { - CPUWriteHalfWordQuick(addr, val); - } - else - { - gbWriteMemoryQuick16(addr, val); - } - - CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE); - return 0; - } - - static int memory_writedword(lua_State *L) - { - u32 addr; - int val; - - addr = luaL_checkinteger(L, 1); - val = luaL_checkinteger(L, 2); - if (systemIsRunningGBA()) - { - CPUWriteMemoryQuick(addr, val); - } - else - { - gbWriteMemoryQuick32(addr, val); - } - - CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE); - return 0; - } - - static int memory_gbromreadbyte(lua_State *L) - { - u32 addr; - u8 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - lua_pushnil(L); - return 1; - } - else - { - val = gbReadROMQuick8(addr); - } - - lua_pushinteger(L, val); - return 1; - } - - static int memory_gbromreadbytesigned(lua_State *L) - { - u32 addr; - s8 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - lua_pushnil(L); - return 1; - } - else - { - val = (s8) gbReadROMQuick8(addr); - } - - lua_pushinteger(L, val); - return 1; - } - - static int memory_gbromreadword(lua_State *L) - { - u32 addr; - u16 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - lua_pushnil(L); - return 1; - } - else - { - val = gbReadROMQuick16(addr); - } - - lua_pushinteger(L, val); - return 1; - } - - static int memory_gbromreadwordsigned(lua_State *L) - { - u32 addr; - s16 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - lua_pushnil(L); - return 1; - } - else - { - val = (s16) gbReadROMQuick16(addr); - } - - lua_pushinteger(L, val); - return 1; - } - - static int memory_gbromreaddword(lua_State *L) - { - u32 addr; - u32 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - lua_pushnil(L); - return 1; - } - else - { - val = gbReadROMQuick32(addr); - } - - // lua_pushinteger doesn't work properly for 32bit system, does it? - if (val >= 0x80000000 && sizeof(int) <= 4) - lua_pushnumber(L, val); - else - lua_pushinteger(L, val); - return 1; - } - - static int memory_gbromreaddwordsigned(lua_State *L) - { - u32 addr; - s32 val; - - addr = luaL_checkinteger(L, 1); - if (systemIsRunningGBA()) - { - lua_pushnil(L); - return 1; - } - else - { - val = (s32) gbReadROMQuick32(addr); - } - - lua_pushinteger(L, val); - return 1; - } - - static int memory_gbromreadbyterange(lua_State *L) - { - uint32 address = luaL_checkinteger(L, 1); - int length = luaL_checkinteger(L, 2); - - if (length < 0) - { - address += length; - length = -length; - } - - // push the array - lua_createtable(L, abs(length), 0); - - // put all the values into the (1-based) array - for (int a = address, n = 1; n <= length; a++, n++) - { - unsigned char value; - - if (systemIsRunningGBA()) - { - lua_pushnil(L); - return 1; - } - else - { - value = gbReadROMQuick8(a); - } - - lua_pushinteger(L, value); - lua_rawseti(L, -2, n); - } - - return 1; - } +int vba_emulating(lua_State *L) +{ + lua_pushboolean(L, systemIsEmulating()); + return 1; +} + +int movie_isactive(lua_State *L) +{ + lua_pushboolean(L, VBAMovieActive()); + return 1; +} + +int movie_isrecording(lua_State *L) +{ + lua_pushboolean(L, VBAMovieRecording()); + return 1; +} + +int movie_isplaying(lua_State *L) +{ + lua_pushboolean(L, VBAMoviePlaying()); + return 1; +} + +int movie_getlength(lua_State *L) +{ + if (VBAMovieActive()) + lua_pushinteger(L, VBAMovieGetLength()); + else + lua_pushinteger(L, 0); + return 1; +} + +static int memory_readbyte(lua_State *L) +{ + u32 addr; + u8 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + val = CPUReadByteQuick(addr); + } + else + { + val = gbReadMemoryQuick8(addr); + } + + lua_pushinteger(L, val); + return 1; +} + +static int memory_readbytesigned(lua_State *L) +{ + u32 addr; + s8 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + val = (s8) CPUReadByteQuick(addr); + } + else + { + val = (s8) gbReadMemoryQuick8(addr); + } + + lua_pushinteger(L, val); + return 1; +} + +static int memory_readword(lua_State *L) +{ + u32 addr; + u16 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + val = CPUReadHalfWordQuick(addr); + } + else + { + val = gbReadMemoryQuick16(addr & 0x0000FFFF); + } + + lua_pushinteger(L, val); + return 1; +} + +static int memory_readwordsigned(lua_State *L) +{ + u32 addr; + s16 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + val = (s16) CPUReadHalfWordQuick(addr); + } + else + { + val = (s16) gbReadMemoryQuick16(addr); + } + + lua_pushinteger(L, val); + return 1; +} + +static int memory_readdword(lua_State *L) +{ + u32 addr; + u32 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + val = CPUReadMemoryQuick(addr); + } + else + { + val = gbReadMemoryQuick32(addr & 0x0000FFFF); + } + + // lua_pushinteger doesn't work properly for 32bit system, does it? + if (val >= 0x80000000 && sizeof(int) <= 4) + lua_pushnumber(L, val); + else + lua_pushinteger(L, val); + return 1; +} + +static int memory_readdwordsigned(lua_State *L) +{ + u32 addr; + s32 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + val = (s32) CPUReadMemoryQuick(addr); + } + else + { + val = (s32) gbReadMemoryQuick32(addr); + } + + lua_pushinteger(L, val); + return 1; +} + +static int memory_readbyterange(lua_State *L) +{ + uint32 address = luaL_checkinteger(L, 1); + int length = luaL_checkinteger(L, 2); + + if (length < 0) + { + address += length; + length = -length; + } + + // push the array + lua_createtable(L, abs(length), 0); + + // put all the values into the (1-based) array + for (int a = address, n = 1; n <= length; a++, n++) + { + unsigned char value; + + if (systemIsRunningGBA()) + { + value = CPUReadByteQuick(a); + } + else + { + value = gbReadMemoryQuick8(a); + } + + lua_pushinteger(L, value); + lua_rawseti(L, -2, n); + } + + return 1; +} + +static int memory_writebyte(lua_State *L) +{ + u32 addr; + int val; + + addr = luaL_checkinteger(L, 1); + val = luaL_checkinteger(L, 2); + if (systemIsRunningGBA()) + { + CPUWriteByteQuick(addr, val); + } + else + { + gbWriteMemoryQuick8(addr, val); + } + + CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE); + return 0; +} + +static int memory_writeword(lua_State *L) +{ + u32 addr; + int val; + + addr = luaL_checkinteger(L, 1); + val = luaL_checkinteger(L, 2); + if (systemIsRunningGBA()) + { + CPUWriteHalfWordQuick(addr, val); + } + else + { + gbWriteMemoryQuick16(addr, val); + } + + CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE); + return 0; +} + +static int memory_writedword(lua_State *L) +{ + u32 addr; + int val; + + addr = luaL_checkinteger(L, 1); + val = luaL_checkinteger(L, 2); + if (systemIsRunningGBA()) + { + CPUWriteMemoryQuick(addr, val); + } + else + { + gbWriteMemoryQuick32(addr, val); + } + + CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE); + return 0; +} + +static int memory_gbromreadbyte(lua_State *L) +{ + u32 addr; + u8 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + lua_pushnil(L); + return 1; + } + else + { + val = gbReadROMQuick8(addr); + } + + lua_pushinteger(L, val); + return 1; +} + +static int memory_gbromreadbytesigned(lua_State *L) +{ + u32 addr; + s8 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + lua_pushnil(L); + return 1; + } + else + { + val = (s8) gbReadROMQuick8(addr); + } + + lua_pushinteger(L, val); + return 1; +} + +static int memory_gbromreadword(lua_State *L) +{ + u32 addr; + u16 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + lua_pushnil(L); + return 1; + } + else + { + val = gbReadROMQuick16(addr); + } + + lua_pushinteger(L, val); + return 1; +} + +static int memory_gbromreadwordsigned(lua_State *L) +{ + u32 addr; + s16 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + lua_pushnil(L); + return 1; + } + else + { + val = (s16) gbReadROMQuick16(addr); + } + + lua_pushinteger(L, val); + return 1; +} + +static int memory_gbromreaddword(lua_State *L) +{ + u32 addr; + u32 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + lua_pushnil(L); + return 1; + } + else + { + val = gbReadROMQuick32(addr); + } + + // lua_pushinteger doesn't work properly for 32bit system, does it? + if (val >= 0x80000000 && sizeof(int) <= 4) + lua_pushnumber(L, val); + else + lua_pushinteger(L, val); + return 1; +} + +static int memory_gbromreaddwordsigned(lua_State *L) +{ + u32 addr; + s32 val; + + addr = luaL_checkinteger(L, 1); + if (systemIsRunningGBA()) + { + lua_pushnil(L); + return 1; + } + else + { + val = (s32) gbReadROMQuick32(addr); + } + + lua_pushinteger(L, val); + return 1; +} + +static int memory_gbromreadbyterange(lua_State *L) +{ + uint32 address = luaL_checkinteger(L, 1); + int length = luaL_checkinteger(L, 2); + + if (length < 0) + { + address += length; + length = -length; + } + + // push the array + lua_createtable(L, abs(length), 0); + + // put all the values into the (1-based) array + for (int a = address, n = 1; n <= length; a++, n++) + { + unsigned char value; + + if (systemIsRunningGBA()) + { + lua_pushnil(L); + return 1; + } + else + { + value = gbReadROMQuick8(a); + } + + lua_pushinteger(L, value); + lua_rawseti(L, -2, n); + } + + return 1; +} // table joypad.get(int which = 1) // // Reads the joypads as inputted by the user. - static int joy_get_internal(lua_State *L, bool reportUp, bool reportDown) - { - // Reads the joypads as inputted by the user - int which = luaL_checkinteger(L, 1); - - if (which < 0 || which > 4) - { - luaL_error(L, "Invalid input port (valid range 0-4, specified %d)", which); - } - - uint32 buttons = systemGetOriginalJoypad(which - 1, false); - - lua_newtable(L); - - int i; - for (i = 0; i < 10; i++) - { - bool pressed = (buttons & (1 << i)) != 0; - if ((pressed && reportDown) || (!pressed && reportUp)) - { - lua_pushboolean(L, pressed); - lua_setfield(L, -2, button_mappings[i]); - } - } - - return 1; - } +static int joy_get_internal(lua_State *L, bool reportUp, bool reportDown) +{ + // Reads the joypads as inputted by the user + int which = luaL_checkinteger(L, 1); + + if (which < 0 || which > 4) + { + luaL_error(L, "Invalid input port (valid range 0-4, specified %d)", which); + } + + uint32 buttons = systemGetOriginalJoypad(which - 1, false); + + lua_newtable(L); + + int i; + for (i = 0; i < 10; i++) + { + bool pressed = (buttons & (1 << i)) != 0; + if ((pressed && reportDown) || (!pressed && reportUp)) + { + lua_pushboolean(L, pressed); + lua_setfield(L, -2, button_mappings[i]); + } + } + + return 1; +} // joypad.get(which) // returns a table of every game button, // true meaning currently-held and false meaning not-currently-held // (as of last frame boundary) // this WILL read input from a currently-playing movie - static int joypad_get(lua_State *L) - { - return joy_get_internal(L, true, true); - } +static int joypad_get(lua_State *L) +{ + return joy_get_internal(L, true, true); +} // joypad.getdown(which) // returns a table of every game button that is currently held - static int joypad_getdown(lua_State *L) - { - return joy_get_internal(L, false, true); - } +static int joypad_getdown(lua_State *L) +{ + return joy_get_internal(L, false, true); +} // joypad.getup(which) // returns a table of every game button that is not currently held - static int joypad_getup(lua_State *L) - { - return joy_get_internal(L, true, false); - } +static int joypad_getup(lua_State *L) +{ + return joy_get_internal(L, true, false); +} // joypad.set(int which, table buttons) // @@ -1834,83 +1834,83 @@ // frame advance. The table should have the right // keys (no pun intended) set. - static int joypad_set(lua_State *L) - { - // Which joypad we're tampering with - int which = luaL_checkinteger(L, 1); - if (which < 0 || which > 4) - { - luaL_error(L, "Invalid output port (valid range 0-4, specified %d)", which); - } - - if (which == 0) - which = systemGetDefaultJoypad(); - - // And the table of buttons. - luaL_checktype(L, 2, LUA_TTABLE); - - // Set up for taking control of the indicated controller - lua_joypads_used |= 1 << (which - 1); - lua_joypads[which - 1] = 0; - - for (int i = 0; i < 10; i++) - { - const char *name = button_mappings[i]; - lua_getfield(L, 2, name); - if (!lua_isnil(L, -1)) - { - bool pressed = lua_toboolean(L, -1) != 0; - if (pressed) - lua_joypads[which - 1] |= 1 << i; - else - lua_joypads[which - 1] &= ~(1 << i); - } - lua_pop(L, 1); - } - - return 0; - } +static int joypad_set(lua_State *L) +{ + // Which joypad we're tampering with + int which = luaL_checkinteger(L, 1); + if (which < 0 || which > 4) + { + luaL_error(L, "Invalid output port (valid range 0-4, specified %d)", which); + } + + if (which == 0) + which = systemGetDefaultJoypad(); + + // And the table of buttons. + luaL_checktype(L, 2, LUA_TTABLE); + + // Set up for taking control of the indicated controller + lua_joypads_used |= 1 << (which - 1); + lua_joypads[which - 1] = 0; + + for (int i = 0; i < 10; i++) + { + const char *name = button_mappings[i]; + lua_getfield(L, 2, name); + if (!lua_isnil(L, -1)) + { + bool pressed = lua_toboolean(L, -1) != 0; + if (pressed) + lua_joypads[which - 1] |= 1 << i; + else + lua_joypads[which - 1] &= ~(1 << i); + } + lua_pop(L, 1); + } + + return 0; +} // Helper function to convert a savestate object to the filename it represents. - static const char *savestateobj2filename(lua_State *L, int offset) - { - // First we get the metatable of the indicated object - int result = lua_getmetatable(L, offset); - - if (!result) - luaL_error(L, "object not a savestate object"); - - // Also check that the type entry is set - lua_getfield(L, -1, "__metatable"); - if (strcmp(lua_tostring(L, -1), "vba Savestate") != 0) - luaL_error(L, "object not a savestate object"); - lua_pop(L, 1); - - // Now, get the field we want - lua_getfield(L, -1, "filename"); - - // Return it - return lua_tostring(L, -1); - } +static const char *savestateobj2filename(lua_State *L, int offset) +{ + // First we get the metatable of the indicated object + int result = lua_getmetatable(L, offset); + + if (!result) + luaL_error(L, "object not a savestate object"); + + // Also check that the type entry is set + lua_getfield(L, -1, "__metatable"); + if (strcmp(lua_tostring(L, -1), "vba Savestate") != 0) + luaL_error(L, "object not a savestate object"); + lua_pop(L, 1); + + // Now, get the field we want + lua_getfield(L, -1, "filename"); + + // Return it + return lua_tostring(L, -1); +} // Helper function for garbage collection. - static int savestate_gc(lua_State *L) - { - // The object we're collecting is on top of the stack - lua_getmetatable(L, 1); - - // Get the filename - const char *filename; - lua_getfield(L, -1, "filename"); - filename = lua_tostring(L, -1); - - // Delete the file - remove(filename); - - // We exit, and the garbage collector takes care of the rest. - // Edit: Visual Studio needs a return value anyway, so returns 0. - return 0; - } +static int savestate_gc(lua_State *L) +{ + // The object we're collecting is on top of the stack + lua_getmetatable(L, 1); + + // Get the filename + const char *filename; + lua_getfield(L, -1, "filename"); + filename = lua_tostring(L, -1); + + // Delete the file + remove(filename); + + // We exit, and the garbage collector takes care of the rest. + // Edit: Visual Studio needs a return value anyway, so returns 0. + return 0; +} // object savestate.create(int which = nil) // @@ -1918,244 +1918,244 @@ // The object can be associated with a player-accessible savestate // ("which" between 1 and 12) or not (which == nil). - static int savestate_create(lua_State *L) - { - int which = -1; - if (lua_gettop(L) >= 1) - { - which = luaL_checkinteger(L, 1); - if (which < 1 || which > 12) - { - luaL_error(L, "invalid player's savestate %d", which); - } - } - - char stateName[2048]; - - if (which > 0) - { - // Find an appropriate filename. This is OS specific, unfortunately. +static int savestate_create(lua_State *L) +{ + int which = -1; + if (lua_gettop(L) >= 1) + { + which = luaL_checkinteger(L, 1); + if (which < 1 || which > 12) + { + luaL_error(L, "invalid player's savestate %d", which); + } + } + + char stateName[2048]; + + if (which > 0) + { + // Find an appropriate filename. This is OS specific, unfortunately. #if (defined(WIN32) && !defined(SDL)) - CString stateName = winGetSavestateFilename(theApp.gameFilename, which); + CString stateName = winGetSavestateFilename(theApp.gameFilename, which); #else - extern char saveDir[2048]; - extern char filename[2048]; - extern char *sdlGetFilename(char *name); - - if (saveDir[0]) - sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename), which); - else - sprintf(stateName, "%s%d.sgm", filename, which); + extern char saveDir[2048]; + extern char filename[2048]; + extern char *sdlGetFilename(char *name); + + if (saveDir[0]) + sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename), which); + else + sprintf(stateName, "%s%d.sgm", filename, which); #endif - } - else - { - char *stateNameTemp = tempnam(NULL, "snlua"); - strcpy(stateName, stateNameTemp); - if (stateNameTemp) - free(stateNameTemp); - } - - // Our "object". We don't care about the type, we just need the memory and GC services. - lua_newuserdata(L, 1); - - // The metatable we use, protected from Lua and contains garbage collection info and stuff. - lua_newtable(L); - - // First, we must protect it - lua_pushstring(L, "vba Savestate"); - lua_setfield(L, -2, "__metatable"); - - // Now we need to save the file itself. - lua_pushstring(L, stateName); - lua_setfield(L, -2, "filename"); - - // If it's an anonymous savestate, we must delete the file from disk should it be gargage collected - if (which < 0) - { - lua_pushcfunction(L, savestate_gc); - lua_setfield(L, -2, "__gc"); - } - - // Set the metatable - lua_setmetatable(L, -2); - - // Awesome. Return the object - return 1; - } + } + else + { + char *stateNameTemp = tempnam(NULL, "snlua"); + strcpy(stateName, stateNameTemp); + if (stateNameTemp) + free(stateNameTemp); + } + + // Our "object". We don't care about the type, we just need the memory and GC services. + lua_newuserdata(L, 1); + + // The metatable we use, protected from Lua and contains garbage collection info and stuff. + lua_newtable(L); + + // First, we must protect it + lua_pushstring(L, "vba Savestate"); + lua_setfield(L, -2, "__metatable"); + + // Now we need to save the file itself. + lua_pushstring(L, stateName); + lua_setfield(L, -2, "filename"); + + // If it's an anonymous savestate, we must delete the file from disk should it be gargage collected + if (which < 0) + { + lua_pushcfunction(L, savestate_gc); + lua_setfield(L, -2, "__gc"); + } + + // Set the metatable + lua_setmetatable(L, -2); + + // Awesome. Return the object + return 1; +} // savestate.save(object state) // // Saves a state to the given object. - static int savestate_save(lua_State *L) - { - const char *filename = savestateobj2filename(L, 1); - - // printf("saving %s\n", filename); - // Save states are very expensive. They take time. - numTries--; - - bool8 retvalue = theEmulator.emuWriteState ? theEmulator.emuWriteState(filename) : false; - if (!retvalue) - { - // Uh oh - luaL_error(L, "savestate failed"); - } - - return 0; - } +static int savestate_save(lua_State *L) +{ + const char *filename = savestateobj2filename(L, 1); + + // printf("saving %s\n", filename); + // Save states are very expensive. They take time. + numTries--; + + bool8 retvalue = theEmulator.emuWriteState ? theEmulator.emuWriteState(filename) : false; + if (!retvalue) + { + // Uh oh + luaL_error(L, "savestate failed"); + } + + return 0; +} // savestate.load(object state) // // Loads the given state - static int savestate_load(lua_State *L) - { - const char *filename = savestateobj2filename(L, 1); - - numTries--; - - // printf("loading %s\n", filename); - bool8 retvalue = theEmulator.emuReadState ? theEmulator.emuReadState(filename) : false; - if (!retvalue) - { - // Uh oh - luaL_error(L, "loadstate failed"); - } - - return 0; - } +static int savestate_load(lua_State *L) +{ + const char *filename = savestateobj2filename(L, 1); + + numTries--; + + // printf("loading %s\n", filename); + bool8 retvalue = theEmulator.emuReadState ? theEmulator.emuReadState(filename) : false; + if (!retvalue) + { + // Uh oh + luaL_error(L, "loadstate failed"); + } + + return 0; +} // int vba.framecount() // // Gets the frame counter for the movie, or the number of frames since last reset. - int vba_framecount(lua_State *L) - { - if (!VBAMovieActive()) - { - lua_pushinteger(L, systemCounters.frameCount); - } - else - { - lua_pushinteger(L, VBAMovieGetFrameCounter()); - } - - return 1; - } +int vba_framecount(lua_State *L) +{ + if (!VBAMovieActive()) + { + lua_pushinteger(L, systemCounters.frameCount); + } + else + { + lua_pushinteger(L, VBAMovieGetFrameCounter()); + } + + return 1; +} //string movie.getauthor // // returns author info field of .vbm file - int movie_getauthor(lua_State *L) - { - if (!VBAMovieActive()) - { - //lua_pushnil(L); - lua_pushstring(L, ""); - return 1; - } - - lua_pushstring(L, VBAMovieGetAuthorInfo().c_str()); - return 1; - } +int movie_getauthor(lua_State *L) +{ + if (!VBAMovieActive()) + { + //lua_pushnil(L); + lua_pushstring(L, ""); + return 1; + } + + lua_pushstring(L, VBAMovieGetAuthorInfo().c_str()); + return 1; +} //string movie.filename - int movie_getfilename(lua_State *L) - { - if (!VBAMovieActive()) - { - //lua_pushnil(L); - lua_pushstring(L, ""); - return 1; - } - - lua_pushstring(L, VBAMovieGetFilename().c_str()); - return 1; - } +int movie_getfilename(lua_State *L) +{ + if (!VBAMovieActive()) + { + //lua_pushnil(L); + lua_pushstring(L, ""); + return 1; + } + + lua_pushstring(L, VBAMovieGetFilename().c_str()); + return 1; +} // string movie.mode() // // "record", "playback" or nil - int movie_getmode(lua_State *L) - { - assert(!VBAMovieLoading()); - if (!VBAMovieActive()) - { - lua_pushnil(L); - return 1; - } - - if (VBAMovieRecording()) - lua_pushstring(L, "record"); - else - lua_pushstring(L, "playback"); - return 1; - } - - static int movie_rerecordcount(lua_State *L) - { - if (VBAMovieActive()) - lua_pushinteger(L, VBAMovieGetRerecordCount()); - else - lua_pushinteger(L, 0); - return 1; - } - - static int movie_setrerecordcount(lua_State *L) - { - if (VBAMovieActive()) - VBAMovieSetRerecordCount(luaL_checkinteger(L, 1)); - return 0; - } - - static int movie_rerecordcounting(lua_State *L) - { - if (lua_gettop(L) == 0) - luaL_error(L, "no parameters specified"); - - skipRerecords = lua_toboolean(L, 1); - return 0; - } +int movie_getmode(lua_State *L) +{ + assert(!VBAMovieLoading()); + if (!VBAMovieActive()) + { + lua_pushnil(L); + return 1; + } + + if (VBAMovieRecording()) + lua_pushstring(L, "record"); + else + lua_pushstring(L, "playback"); + return 1; +} + +static int movie_rerecordcount(lua_State *L) +{ + if (VBAMovieActive()) + lua_pushinteger(L, VBAMovieGetRerecordCount()); + else + lua_pushinteger(L, 0); + return 1; +} + +static int movie_setrerecordcount(lua_State *L) +{ + if (VBAMovieActive()) + VBAMovieSetRerecordCount(luaL_checkinteger(L, 1)); + return 0; +} + +static int movie_rerecordcounting(lua_State *L) +{ + if (lua_gettop(L) == 0) + luaL_error(L, "no parameters specified"); + + skipRerecords = lua_toboolean(L, 1); + return 0; +} // movie.stop() // // Stops movie playback/recording. Bombs out if movie is not running. - static int movie_stop(lua_State *L) - { - if (!VBAMovieActive()) - luaL_error(L, "no movie"); - - VBAMovieStop(false); - return 0; - } +static int movie_stop(lua_State *L) +{ + if (!VBAMovieActive()) + luaL_error(L, "no movie"); + + VBAMovieStop(false); + return 0; +} #define LUA_SCREEN_WIDTH 256 #define LUA_SCREEN_HEIGHT 239 // Common code by the gui library: make sure the screen array is ready - static void gui_prepare(void) - { - if (!gui_data) - gui_data = (uint8 *)malloc(LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4); - if (!gui_used) - memset(gui_data, 0, LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4); - gui_used = true; - } +static void gui_prepare(void) +{ + if (!gui_data) + gui_data = (uint8 *)malloc(LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4); + if (!gui_used) + memset(gui_data, 0, LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4); + gui_used = true; +} // pixform for lua graphics #define BUILD_PIXEL_ARGB8888(A, R, G, B) (((int)(A) << 24) | ((int)(R) << 16) | ((int)(G) << 8) | (int)(B)) -#define DECOMPOSE_PIXEL_ARGB8888(PIX, A, R, G, B) \ - { \ - (A) = ((PIX) >> 24) & 0xff; \ - (R) = ((PIX) >> 16) & 0xff; \ - (G) = ((PIX) >> 8) & 0xff; \ - (B) = (PIX) & 0xff; \ - } +#define DECOMPOSE_PIXEL_ARGB8888(PIX, A, R, G, B) \ + { \ + (A) = ((PIX) >> 24) & 0xff; \ + (R) = ((PIX) >> 16) & 0xff; \ + (G) = ((PIX) >> 8) & 0xff; \ + (B) = (PIX) & 0xff; \ + } #define LUA_BUILD_PIXEL BUILD_PIXEL_ARGB8888 #define LUA_DECOMPOSE_PIXEL DECOMPOSE_PIXEL_ARGB8888 #define LUA_PIXEL_A(PIX) (((PIX) >> 24) & 0xff) @@ -2163,387 +2163,387 @@ #define LUA_PIXEL_G(PIX) (((PIX) >> 8) & 0xff) #define LUA_PIXEL_B(PIX) ((PIX) & 0xff) - template - static void swap(T &one, T &two) - { - T temp = one; - one = two; - two = temp; - } +template +static void swap(T &one, T &two) +{ + T temp = one; + one = two; + two = temp; +} // write a pixel to buffer - static inline void blend32(uint32 *dstPixel, uint32 colour) - { - uint8 *dst = (uint8 *)dstPixel; - int a, r, g, b; - LUA_DECOMPOSE_PIXEL(colour, a, r, g, b); - - if (a == 255 || dst[3] == 0) - { - // direct copy - *(uint32 *) (dst) = colour; - } - else if (a == 0) - { - // do not copy - } - else - { - // alpha-blending - int a_dst = ((255 - a) * dst[3] + 128) / 255; - int a_new = a + a_dst; - - dst[0] = (uint8) (((dst[0] * a_dst + b * a) + (a_new / 2)) / a_new); - dst[1] = (uint8) (((dst[1] * a_dst + g * a) + (a_new / 2)) / a_new); - dst[2] = (uint8) (((dst[2] * a_dst + r * a) + (a_new / 2)) / a_new); - dst[3] = (uint8) a_new; - } - } +static inline void blend32(uint32 *dstPixel, uint32 colour) +{ + uint8 *dst = (uint8 *)dstPixel; + int a, r, g, b; + LUA_DECOMPOSE_PIXEL(colour, a, r, g, b); + + if (a == 255 || dst[3] == 0) + { + // direct copy + *(uint32 *) (dst) = colour; + } + else if (a == 0) + { + // do not copy + } + else + { + // alpha-blending + int a_dst = ((255 - a) * dst[3] + 128) / 255; + int a_new = a + a_dst; + + dst[0] = (uint8) (((dst[0] * a_dst + b * a) + (a_new / 2)) / a_new); + dst[1] = (uint8) (((dst[1] * a_dst + g * a) + (a_new / 2)) / a_new); + dst[2] = (uint8) (((dst[2] * a_dst + r * a) + (a_new / 2)) / a_new); + dst[3] = (uint8) a_new; + } +} // check if a pixel is in the lua canvas - static inline bool gui_check_boundary(int x, int y) - { - return !(x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= LUA_SCREEN_HEIGHT); - } +static inline bool gui_check_boundary(int x, int y) +{ + return !(x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= LUA_SCREEN_HEIGHT); +} // check if any part of a box is in the lua canvas - static inline bool gui_checkbox(int x1, int y1, int x2, int y2) - { - if ((x1 < 0 && x2 < 0) - || (x1 >= LUA_SCREEN_WIDTH && x2 >= LUA_SCREEN_WIDTH) - || (y1 < 0 && y2 < 0) - || (y1 >= LUA_SCREEN_HEIGHT && y2 >= LUA_SCREEN_HEIGHT)) - return false; - return true; - } +static inline bool gui_checkbox(int x1, int y1, int x2, int y2) +{ + if ((x1 < 0 && x2 < 0) + || (x1 >= LUA_SCREEN_WIDTH && x2 >= LUA_SCREEN_WIDTH) + || (y1 < 0 && y2 < 0) + || (y1 >= LUA_SCREEN_HEIGHT && y2 >= LUA_SCREEN_HEIGHT)) + return false; + return true; +} // write a pixel to gui_data (do not check boundaries for speedup) - static inline void gui_drawpixel_fast(int x, int y, uint32 colour) - { - //gui_prepare(); - blend32((uint32 *) &gui_data[(y * LUA_SCREEN_WIDTH + x) * 4], colour); - } +static inline void gui_drawpixel_fast(int x, int y, uint32 colour) +{ + //gui_prepare(); + blend32((uint32 *) &gui_data[(y * LUA_SCREEN_WIDTH + x) * 4], colour); +} // write a pixel to gui_data (check boundaries) - static inline void gui_drawpixel_internal(int x, int y, uint32 colour) - { - //gui_prepare(); - if (gui_check_boundary(x, y)) - gui_drawpixel_fast(x, y, colour); - } +static inline void gui_drawpixel_internal(int x, int y, uint32 colour) +{ + //gui_prepare(); + if (gui_check_boundary(x, y)) + gui_drawpixel_fast(x, y, colour); +} // draw a line on gui_data (checks boundaries) - static void gui_drawline_internal(int x1, int y1, int x2, int y2, bool lastPixel, uint32 colour) - { - //gui_prepare(); - // Note: New version of Bresenham's Line Algorithm - // - // - // http://groups.google.co.jp/group/rec.games.roguelike.development/browse_thread/thread/345f4c42c3b25858/29e07a3af3a450e6?show_docid=29e07a3af3a450e6 - int swappedx = 0; - int swappedy = 0; - - int xtemp = x1 - x2; - int ytemp = y1 - y2; - if (xtemp == 0 && ytemp == 0) - { - gui_drawpixel_internal(x1, y1, colour); - return; - } - - if (xtemp < 0) - { - xtemp = -xtemp; - swappedx = 1; - } - - if (ytemp < 0) - { - ytemp = -ytemp; - swappedy = 1; - } - - int delta_x = xtemp << 1; - int delta_y = ytemp << 1; - - signed char ix = x1 > x2 ? 1 : -1; - signed char iy = y1 > y2 ? 1 : -1; - - if (lastPixel) - gui_drawpixel_internal(x2, y2, colour); - - if (delta_x >= delta_y) - { - int error = delta_y - (delta_x >> 1); - - while (x2 != x1) - { - if (error == 0 && !swappedx) - gui_drawpixel_internal(x2 + ix, y2, colour); - if (error >= 0) - { - if (error || (ix > 0)) - { - y2 += iy; - error -= delta_x; - } - } - - x2 += ix; - gui_drawpixel_internal(x2, y2, colour); - if (error == 0 && swappedx) - gui_drawpixel_internal(x2, y2 + iy, colour); - error += delta_y; - } - } - else - { - int error = delta_x - (delta_y >> 1); - - while (y2 != y1) - { - if (error == 0 && !swappedy) - gui_drawpixel_internal(x2, y2 + iy, colour); - if (error >= 0) - { - if (error || (iy > 0)) - { - x2 += ix; - error -= delta_y; - } - } - - y2 += iy; - gui_drawpixel_internal(x2, y2, colour); - if (error == 0 && swappedy) - gui_drawpixel_internal(x2 + ix, y2, colour); - error += delta_x; - } - } - } +static void gui_drawline_internal(int x1, int y1, int x2, int y2, bool lastPixel, uint32 colour) +{ + //gui_prepare(); + // Note: New version of Bresenham's Line Algorithm + // + // + // http://groups.google.co.jp/group/rec.games.roguelike.development/browse_thread/thread/345f4c42c3b25858/29e07a3af3a450e6?show_docid=29e07a3af3a450e6 + int swappedx = 0; + int swappedy = 0; + + int xtemp = x1 - x2; + int ytemp = y1 - y2; + if (xtemp == 0 && ytemp == 0) + { + gui_drawpixel_internal(x1, y1, colour); + return; + } + + if (xtemp < 0) + { + xtemp = -xtemp; + swappedx = 1; + } + + if (ytemp < 0) + { + ytemp = -ytemp; + swappedy = 1; + } + + int delta_x = xtemp << 1; + int delta_y = ytemp << 1; + + signed char ix = x1 > x2 ? 1 : -1; + signed char iy = y1 > y2 ? 1 : -1; + + if (lastPixel) + gui_drawpixel_internal(x2, y2, colour); + + if (delta_x >= delta_y) + { + int error = delta_y - (delta_x >> 1); + + while (x2 != x1) + { + if (error == 0 && !swappedx) + gui_drawpixel_internal(x2 + ix, y2, colour); + if (error >= 0) + { + if (error || (ix > 0)) + { + y2 += iy; + error -= delta_x; + } + } + + x2 += ix; + gui_drawpixel_internal(x2, y2, colour); + if (error == 0 && swappedx) + gui_drawpixel_internal(x2, y2 + iy, colour); + error += delta_y; + } + } + else + { + int error = delta_x - (delta_y >> 1); + + while (y2 != y1) + { + if (error == 0 && !swappedy) + gui_drawpixel_internal(x2, y2 + iy, colour); + if (error >= 0) + { + if (error || (iy > 0)) + { + x2 += ix; + error -= delta_y; + } + } + + y2 += iy; + gui_drawpixel_internal(x2, y2, colour); + if (error == 0 && swappedy) + gui_drawpixel_internal(x2 + ix, y2, colour); + error += delta_x; + } + } +} // draw a rect on gui_data - static void gui_drawbox_internal(int x1, int y1, int x2, int y2, uint32 colour) - { - if (x1 > x2) - std::swap(x1, x2); - if (y1 > y2) - std::swap(y1, y2); - if (x1 < 0) - x1 = -1; - if (y1 < 0) - y1 = -1; - if (x2 >= LUA_SCREEN_WIDTH) - x2 = LUA_SCREEN_WIDTH; - if (y2 >= LUA_SCREEN_HEIGHT) - y2 = LUA_SCREEN_HEIGHT; - - if (!gui_checkbox(x1, y1, x2, y2)) - return; - - //gui_prepare(); - gui_drawline_internal(x1, y1, x2, y1, true, colour); - gui_drawline_internal(x1, y2, x2, y2, true, colour); - gui_drawline_internal(x1, y1, x1, y2, true, colour); - gui_drawline_internal(x2, y1, x2, y2, true, colour); - } +static void gui_drawbox_internal(int x1, int y1, int x2, int y2, uint32 colour) +{ + if (x1 > x2) + std::swap(x1, x2); + if (y1 > y2) + std::swap(y1, y2); + if (x1 < 0) + x1 = -1; + if (y1 < 0) + y1 = -1; + if (x2 >= LUA_SCREEN_WIDTH) + x2 = LUA_SCREEN_WIDTH; + if (y2 >= LUA_SCREEN_HEIGHT) + y2 = LUA_SCREEN_HEIGHT; + + if (!gui_checkbox(x1, y1, x2, y2)) + return; + + //gui_prepare(); + gui_drawline_internal(x1, y1, x2, y1, true, colour); + gui_drawline_internal(x1, y2, x2, y2, true, colour); + gui_drawline_internal(x1, y1, x1, y2, true, colour); + gui_drawline_internal(x2, y1, x2, y2, true, colour); +} // draw a circle on gui_data - static void gui_drawcircle_internal(int x0, int y0, int radius, uint32 colour) - { - //gui_prepare(); - if (radius < 0) - radius = -radius; - if (radius == 0) - return; - if (radius == 1) - { - gui_drawpixel_internal(x0, y0, colour); - return; - } - - // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm - int f = 1 - radius; - int ddF_x = 1; - int ddF_y = -2 * radius; - int x = 0; - int y = radius; - - if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius)) - return; - - gui_drawpixel_internal(x0, y0 + radius, colour); - gui_drawpixel_internal(x0, y0 - radius, colour); - gui_drawpixel_internal(x0 + radius, y0, colour); - gui_drawpixel_internal(x0 - radius, y0, colour); - - // same pixel shouldn't be drawed twice, - // because each pixel has opacity. - // so now the routine gets ugly. - while (true) - { - assert(ddF_x == 2 * x + 1); - assert(ddF_y == -2 * y); - assert(f == x * x + y * y - radius * radius + 2 * x - y + 1); - if (f >= 0) - { - y--; - ddF_y += 2; - f += ddF_y; - } - - x++; - ddF_x += 2; - f += ddF_x; - if (x < y) - { - gui_drawpixel_internal(x0 + x, y0 + y, colour); - gui_drawpixel_internal(x0 - x, y0 + y, colour); - gui_drawpixel_internal(x0 + x, y0 - y, colour); - gui_drawpixel_internal(x0 - x, y0 - y, colour); - gui_drawpixel_internal(x0 + y, y0 + x, colour); - gui_drawpixel_internal(x0 - y, y0 + x, colour); - gui_drawpixel_internal(x0 + y, y0 - x, colour); - gui_drawpixel_internal(x0 - y, y0 - x, colour); - } - else if (x == y) - { - gui_drawpixel_internal(x0 + x, y0 + y, colour); - gui_drawpixel_internal(x0 - x, y0 + y, colour); - gui_drawpixel_internal(x0 + x, y0 - y, colour); - gui_drawpixel_internal(x0 - x, y0 - y, colour); - break; - } - else - break; - } - } +static void gui_drawcircle_internal(int x0, int y0, int radius, uint32 colour) +{ + //gui_prepare(); + if (radius < 0) + radius = -radius; + if (radius == 0) + return; + if (radius == 1) + { + gui_drawpixel_internal(x0, y0, colour); + return; + } + + // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm + int f = 1 - radius; + int ddF_x = 1; + int ddF_y = -2 * radius; + int x = 0; + int y = radius; + + if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius)) + return; + + gui_drawpixel_internal(x0, y0 + radius, colour); + gui_drawpixel_internal(x0, y0 - radius, colour); + gui_drawpixel_internal(x0 + radius, y0, colour); + gui_drawpixel_internal(x0 - radius, y0, colour); + + // same pixel shouldn't be drawed twice, + // because each pixel has opacity. + // so now the routine gets ugly. + while (true) + { + assert(ddF_x == 2 * x + 1); + assert(ddF_y == -2 * y); + assert(f == x * x + y * y - radius * radius + 2 * x - y + 1); + if (f >= 0) + { + y--; + ddF_y += 2; + f += ddF_y; + } + + x++; + ddF_x += 2; + f += ddF_x; + if (x < y) + { + gui_drawpixel_internal(x0 + x, y0 + y, colour); + gui_drawpixel_internal(x0 - x, y0 + y, colour); + gui_drawpixel_internal(x0 + x, y0 - y, colour); + gui_drawpixel_internal(x0 - x, y0 - y, colour); + gui_drawpixel_internal(x0 + y, y0 + x, colour); + gui_drawpixel_internal(x0 - y, y0 + x, colour); + gui_drawpixel_internal(x0 + y, y0 - x, colour); + gui_drawpixel_internal(x0 - y, y0 - x, colour); + } + else if (x == y) + { + gui_drawpixel_internal(x0 + x, y0 + y, colour); + gui_drawpixel_internal(x0 - x, y0 + y, colour); + gui_drawpixel_internal(x0 + x, y0 - y, colour); + gui_drawpixel_internal(x0 - x, y0 - y, colour); + break; + } + else + break; + } +} // draw fill rect on gui_data - static void gui_fillbox_internal(int x1, int y1, int x2, int y2, uint32 colour) - { - if (x1 > x2) - std::swap(x1, x2); - if (y1 > y2) - std::swap(y1, y2); - if (x1 < 0) - x1 = 0; - if (y1 < 0) - y1 = 0; - if (x2 >= LUA_SCREEN_WIDTH) - x2 = LUA_SCREEN_WIDTH - 1; - if (y2 >= LUA_SCREEN_HEIGHT) - y2 = LUA_SCREEN_HEIGHT - 1; - - //gui_prepare(); - int ix, iy; - for (iy = y1; iy <= y2; iy++) - { - for (ix = x1; ix <= x2; ix++) - { - gui_drawpixel_fast(ix, iy, colour); - } - } - } +static void gui_fillbox_internal(int x1, int y1, int x2, int y2, uint32 colour) +{ + if (x1 > x2) + std::swap(x1, x2); + if (y1 > y2) + std::swap(y1, y2); + if (x1 < 0) + x1 = 0; + if (y1 < 0) + y1 = 0; + if (x2 >= LUA_SCREEN_WIDTH) + x2 = LUA_SCREEN_WIDTH - 1; + if (y2 >= LUA_SCREEN_HEIGHT) + y2 = LUA_SCREEN_HEIGHT - 1; + + //gui_prepare(); + int ix, iy; + for (iy = y1; iy <= y2; iy++) + { + for (ix = x1; ix <= x2; ix++) + { + gui_drawpixel_fast(ix, iy, colour); + } + } +} // fill a circle on gui_data - static void gui_fillcircle_internal(int x0, int y0, int radius, uint32 colour) - { - //gui_prepare(); - if (radius < 0) - radius = -radius; - if (radius == 0) - return; - if (radius == 1) - { - gui_drawpixel_internal(x0, y0, colour); - return; - } - - // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm - int f = 1 - radius; - int ddF_x = 1; - int ddF_y = -2 * radius; - int x = 0; - int y = radius; - - if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius)) - return; - - gui_drawline_internal(x0, y0 - radius, x0, y0 + radius, true, colour); - - while (true) - { - assert(ddF_x == 2 * x + 1); - assert(ddF_y == -2 * y); - assert(f == x * x + y * y - radius * radius + 2 * x - y + 1); - if (f >= 0) - { - y--; - ddF_y += 2; - f += ddF_y; - } - - x++; - ddF_x += 2; - f += ddF_x; - - if (x < y) - { - gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour); - gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour); - if (f >= 0) - { - gui_drawline_internal(x0 + y, y0 - x, x0 + y, y0 + x, true, colour); - gui_drawline_internal(x0 - y, y0 - x, x0 - y, y0 + x, true, colour); - } - } - else if (x == y) - { - gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour); - gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour); - break; - } - else - break; - } - } +static void gui_fillcircle_internal(int x0, int y0, int radius, uint32 colour) +{ + //gui_prepare(); + if (radius < 0) + radius = -radius; + if (radius == 0) + return; + if (radius == 1) + { + gui_drawpixel_internal(x0, y0, colour); + return; + } + + // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm + int f = 1 - radius; + int ddF_x = 1; + int ddF_y = -2 * radius; + int x = 0; + int y = radius; + + if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius)) + return; + + gui_drawline_internal(x0, y0 - radius, x0, y0 + radius, true, colour); + + while (true) + { + assert(ddF_x == 2 * x + 1); + assert(ddF_y == -2 * y); + assert(f == x * x + y * y - radius * radius + 2 * x - y + 1); + if (f >= 0) + { + y--; + ddF_y += 2; + f += ddF_y; + } + + x++; + ddF_x += 2; + f += ddF_x; + + if (x < y) + { + gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour); + gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour); + if (f >= 0) + { + gui_drawline_internal(x0 + y, y0 - x, x0 + y, y0 + x, true, colour); + gui_drawline_internal(x0 - y, y0 - x, x0 - y, y0 + x, true, colour); + } + } + else if (x == y) + { + gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour); + gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour); + break; + } + else + break; + } +} // Helper for a simple hex parser - static int hex2int(lua_State *L, char c) - { - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - return luaL_error(L, "invalid hex in colour"); - } - - static const struct ColorMapping - { - const char *name; - int value; - } - s_colorMapping[] = - { - { "white", 0xFFFFFFFF }, - { "black", 0x000000FF }, - { "clear", 0x00000000 }, - { "gray", 0x7F7F7FFF }, - { "grey", 0x7F7F7FFF }, - { "red", 0xFF0000FF }, - { "orange", 0xFF7F00FF }, - { "yellow", 0xFFFF00FF }, - { "chartreuse", 0x7FFF00FF }, - { "green", 0x00FF00FF }, - { "teal", 0x00FF7FFF }, - { "cyan", 0x00FFFFFF }, - { "blue", 0x0000FFFF }, - { "purple", 0x7F00FFFF }, - { "magenta", 0xFF00FFFF }, - }; +static int hex2int(lua_State *L, char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return luaL_error(L, "invalid hex in colour"); +} + +static const struct ColorMapping +{ + const char *name; + int value; +} + s_colorMapping[] = + { + { "white", 0xFFFFFFFF }, + { "black", 0x000000FF }, + { "clear", 0x00000000 }, + { "gray", 0x7F7F7FFF }, + { "grey", 0x7F7F7FFF }, + { "red", 0xFF0000FF }, + { "orange", 0xFF7F00FF }, + { "yellow", 0xFFFF00FF }, + { "chartreuse", 0x7FFF00FF }, + { "green", 0x00FF00FF }, + { "teal", 0x00FF7FFF }, + { "cyan", 0x00FFFFFF }, + { "blue", 0x0000FFFF }, + { "purple", 0x7F00FFFF }, + { "magenta", 0xFF00FFFF }, + }; /** * Converts an integer or a string on the stack at the given @@ -2551,358 +2551,358 @@ * The user may construct their own RGB value, given a simple colour name, * or an HTML-style "#09abcd" colour. 16 bit reduction doesn't occur at this time. */ - static inline bool str2colour(uint32 *colour, lua_State *L, const char *str) - { - if (str[0] == '#') - { - int color; - sscanf(str + 1, "%X", &color); - - int len = strlen(str + 1); - int missing = max(0, 8 - len); - color <<= missing << 2; - if (missing >= 2) - color |= 0xFF; - *colour = color; - return true; - } - else - { - if (!strnicmp(str, "rand", 4)) - { - *colour = gen_rand32() | 0xFF; //((rand()*255/RAND_MAX) << 8) | ((rand()*255/RAND_MAX) << 16) | - // ((rand()*255/RAND_MAX) << 24) | 0xFF; - return true; - } - - for (int i = 0; i < sizeof(s_colorMapping) / sizeof(*s_colorMapping); i++) - { - if (!stricmp(str, s_colorMapping[i].name)) - { - *colour = s_colorMapping[i].value; - return true; - } - } - } - - return false; - } - - static inline uint32 gui_getcolour_wrapped(lua_State *L, int offset, bool hasDefaultValue, uint32 defaultColour) - { - switch (lua_type(L, offset)) - { - case LUA_TSTRING: - { - const char *str = lua_tostring(L, offset); - uint32 colour; - - if (str2colour(&colour, L, str)) - return colour; - else - { - if (hasDefaultValue) - return defaultColour; - else - return luaL_error(L, "unknown colour %s", str); - } - } - - case LUA_TNUMBER: - { - uint32 colour = (uint32) lua_tointeger(L, offset); - return colour; - } - - case LUA_TTABLE: - { - int color = 0xFF; - lua_pushnil(L); // first key - int keyIndex = lua_gettop(L); - int valueIndex = keyIndex + 1; - bool first = true; - while (lua_next(L, offset)) - { - bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING); - bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER); - int key = keyIsString ? tolower(*lua_tostring(L, keyIndex)) : (keyIsNumber ? lua_tointeger(L, keyIndex) : 0); - int value = lua_tointeger(L, valueIndex); - if (value < 0) value = 0; - if (value > 255) value = 255; - switch (key) - { - case 1: - case 'r': - color |= value << 24; break; - case 2: - case 'g': - color |= value << 16; break; - case 3: - case 'b': - color |= value << 8; break; - case 4: - case 'a': - color = (color & ~0xFF) | value; break; - } - lua_pop(L, 1); - } - return color; - } break; - - case LUA_TFUNCTION: - luaL_error(L, "invalid colour"); // NYI - return 0; - - default: - if (hasDefaultValue) - return defaultColour; - else - return luaL_error(L, "invalid colour"); - } - } - - static uint32 gui_getcolour(lua_State *L, int offset) - { - uint32 colour; - int a, r, g, b; - - colour = gui_getcolour_wrapped(L, offset, false, 0); - a = ((colour & 0xff) * transparencyModifier) / 255; - if (a > 255) - a = 255; - b = (colour >> 8) & 0xff; - g = (colour >> 16) & 0xff; - r = (colour >> 24) & 0xff; - return LUA_BUILD_PIXEL(a, r, g, b); - } - - static uint32 gui_optcolour(lua_State *L, int offset, uint32 defaultColour) - { - uint32 colour; - int a, r, g, b; - uint8 defA, defB, defG, defR; - - LUA_DECOMPOSE_PIXEL(defaultColour, defA, defR, defG, defB); - defaultColour = (defR << 24) | (defG << 16) | (defB << 8) | defA; - - colour = gui_getcolour_wrapped(L, offset, true, defaultColour); - a = ((colour & 0xff) * transparencyModifier) / 255; - if (a > 255) - a = 255; - b = (colour >> 8) & 0xff; - g = (colour >> 16) & 0xff; - r = (colour >> 24) & 0xff; - return LUA_BUILD_PIXEL(a, r, g, b); - } +static inline bool str2colour(uint32 *colour, lua_State *L, const char *str) +{ + if (str[0] == '#') + { + int color; + sscanf(str + 1, "%X", &color); + + int len = strlen(str + 1); + int missing = max(0, 8 - len); + color <<= missing << 2; + if (missing >= 2) + color |= 0xFF; + *colour = color; + return true; + } + else + { + if (!strnicmp(str, "rand", 4)) + { + *colour = gen_rand32() | 0xFF; //((rand()*255/RAND_MAX) << 8) | ((rand()*255/RAND_MAX) << 16) | + // ((rand()*255/RAND_MAX) << 24) | 0xFF; + return true; + } + + for (int i = 0; i < sizeof(s_colorMapping) / sizeof(*s_colorMapping); i++) + { + if (!stricmp(str, s_colorMapping[i].name)) + { + *colour = s_colorMapping[i].value; + return true; + } + } + } + + return false; +} + +static inline uint32 gui_getcolour_wrapped(lua_State *L, int offset, bool hasDefaultValue, uint32 defaultColour) +{ + switch (lua_type(L, offset)) + { + case LUA_TSTRING: + { + const char *str = lua_tostring(L, offset); + uint32 colour; + + if (str2colour(&colour, L, str)) + return colour; + else + { + if (hasDefaultValue) + return defaultColour; + else + return luaL_error(L, "unknown colour %s", str); + } + } + + case LUA_TNUMBER: + { + uint32 colour = (uint32) lua_tointeger(L, offset); + return colour; + } + + case LUA_TTABLE: + { + int color = 0xFF; + lua_pushnil(L); // first key + int keyIndex = lua_gettop(L); + int valueIndex = keyIndex + 1; + bool first = true; + while (lua_next(L, offset)) + { + bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING); + bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER); + int key = keyIsString ? tolower(*lua_tostring(L, keyIndex)) : (keyIsNumber ? lua_tointeger(L, keyIndex) : 0); + int value = lua_tointeger(L, valueIndex); + if (value < 0) value = 0; + if (value > 255) value = 255; + switch (key) + { + case 1: + case 'r': + color |= value << 24; break; + case 2: + case 'g': + color |= value << 16; break; + case 3: + case 'b': + color |= value << 8; break; + case 4: + case 'a': + color = (color & ~0xFF) | value; break; + } + lua_pop(L, 1); + } + return color; + } break; + + case LUA_TFUNCTION: + luaL_error(L, "invalid colour"); // NYI + return 0; + + default: + if (hasDefaultValue) + return defaultColour; + else + return luaL_error(L, "invalid colour"); + } +} + +static uint32 gui_getcolour(lua_State *L, int offset) +{ + uint32 colour; + int a, r, g, b; + + colour = gui_getcolour_wrapped(L, offset, false, 0); + a = ((colour & 0xff) * transparencyModifier) / 255; + if (a > 255) + a = 255; + b = (colour >> 8) & 0xff; + g = (colour >> 16) & 0xff; + r = (colour >> 24) & 0xff; + return LUA_BUILD_PIXEL(a, r, g, b); +} + +static uint32 gui_optcolour(lua_State *L, int offset, uint32 defaultColour) +{ + uint32 colour; + int a, r, g, b; + uint8 defA, defB, defG, defR; + + LUA_DECOMPOSE_PIXEL(defaultColour, defA, defR, defG, defB); + defaultColour = (defR << 24) | (defG << 16) | (defB << 8) | defA; + + colour = gui_getcolour_wrapped(L, offset, true, defaultColour); + a = ((colour & 0xff) * transparencyModifier) / 255; + if (a > 255) + a = 255; + b = (colour >> 8) & 0xff; + g = (colour >> 16) & 0xff; + r = (colour >> 24) & 0xff; + return LUA_BUILD_PIXEL(a, r, g, b); +} // gui.drawpixel(x,y,colour) - static int gui_drawpixel(lua_State *L) - { - int x = luaL_checkinteger(L, 1); - int y = luaL_checkinteger(L, 2); - - uint32 colour = gui_getcolour(L, 3); - - // if (!gui_check_boundary(x, y)) - // luaL_error(L,"bad coordinates"); - gui_prepare(); - - gui_drawpixel_internal(x, y, colour); - - return 0; - } +static int gui_drawpixel(lua_State *L) +{ + int x = luaL_checkinteger(L, 1); + int y = luaL_checkinteger(L, 2); + + uint32 colour = gui_getcolour(L, 3); + + // if (!gui_check_boundary(x, y)) + // luaL_error(L,"bad coordinates"); + gui_prepare(); + + gui_drawpixel_internal(x, y, colour); + + return 0; +} // gui.drawline(x1,y1,x2,y2,color,skipFirst) - static int gui_drawline(lua_State *L) - { - int x1, y1, x2, y2; - uint32 color; - x1 = luaL_checkinteger(L, 1); - y1 = luaL_checkinteger(L, 2); - x2 = luaL_checkinteger(L, 3); - y2 = luaL_checkinteger(L, 4); - color = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 255, 255, 255)); - int skipFirst = lua_toboolean(L, 6); - - gui_prepare(); - - gui_drawline_internal(x2, y2, x1, y1, !skipFirst, color); - - return 0; - } +static int gui_drawline(lua_State *L) +{ + int x1, y1, x2, y2; + uint32 color; + x1 = luaL_checkinteger(L, 1); + y1 = luaL_checkinteger(L, 2); + x2 = luaL_checkinteger(L, 3); + y2 = luaL_checkinteger(L, 4); + color = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 255, 255, 255)); + int skipFirst = lua_toboolean(L, 6); + + gui_prepare(); + + gui_drawline_internal(x2, y2, x1, y1, !skipFirst, color); + + return 0; +} // gui.drawbox(x1, y1, x2, y2, fillcolor, outlinecolor) - static int gui_drawbox(lua_State *L) - { - int x1, y1, x2, y2; - uint32 fillcolor; - uint32 outlinecolor; - - x1 = luaL_checkinteger(L, 1); - y1 = luaL_checkinteger(L, 2); - x2 = luaL_checkinteger(L, 3); - y2 = luaL_checkinteger(L, 4); - fillcolor = gui_optcolour(L, 5, LUA_BUILD_PIXEL(63, 255, 255, 255)); - outlinecolor = gui_optcolour(L, 6, LUA_BUILD_PIXEL(255, LUA_PIXEL_R(fillcolor), LUA_PIXEL_G(fillcolor), LUA_PIXEL_B(fillcolor))); - - if (x1 > x2) - std::swap(x1, x2); - if (y1 > y2) - std::swap(y1, y2); - - gui_prepare(); - - gui_drawbox_internal(x1, y1, x2, y2, outlinecolor); - if ((x2 - x1) >= 2 && (y2 - y1) >= 2) - gui_fillbox_internal(x1 + 1, y1 + 1, x2 - 1, y2 - 1, fillcolor); - - return 0; - } +static int gui_drawbox(lua_State *L) +{ + int x1, y1, x2, y2; + uint32 fillcolor; + uint32 outlinecolor; + + x1 = luaL_checkinteger(L, 1); + y1 = luaL_checkinteger(L, 2); + x2 = luaL_checkinteger(L, 3); + y2 = luaL_checkinteger(L, 4); + fillcolor = gui_optcolour(L, 5, LUA_BUILD_PIXEL(63, 255, 255, 255)); + outlinecolor = gui_optcolour(L, 6, LUA_BUILD_PIXEL(255, LUA_PIXEL_R(fillcolor), LUA_PIXEL_G(fillcolor), LUA_PIXEL_B(fillcolor))); + + if (x1 > x2) + std::swap(x1, x2); + if (y1 > y2) + std::swap(y1, y2); + + gui_prepare(); + + gui_drawbox_internal(x1, y1, x2, y2, outlinecolor); + if ((x2 - x1) >= 2 && (y2 - y1) >= 2) + gui_fillbox_internal(x1 + 1, y1 + 1, x2 - 1, y2 - 1, fillcolor); + + return 0; +} // gui.drawcircle(x0, y0, radius, colour) - static int gui_drawcircle(lua_State *L) - { - int x, y, r; - uint32 colour; - - x = luaL_checkinteger(L, 1); - y = luaL_checkinteger(L, 2); - r = luaL_checkinteger(L, 3); - colour = gui_getcolour(L, 4); - - gui_prepare(); - - gui_drawcircle_internal(x, y, r, colour); - - return 0; - } +static int gui_drawcircle(lua_State *L) +{ + int x, y, r; + uint32 colour; + + x = luaL_checkinteger(L, 1); + y = luaL_checkinteger(L, 2); + r = luaL_checkinteger(L, 3); + colour = gui_getcolour(L, 4); + + gui_prepare(); + + gui_drawcircle_internal(x, y, r, colour); + + return 0; +} // gui.fillbox(x1, y1, x2, y2, colour) - static int gui_fillbox(lua_State *L) - { - int x1, y1, x2, y2; - uint32 colour; - - x1 = luaL_checkinteger(L, 1); - y1 = luaL_checkinteger(L, 2); - x2 = luaL_checkinteger(L, 3); - y2 = luaL_checkinteger(L, 4); - colour = gui_getcolour(L, 5); - - // if (!gui_check_boundary(x1, y1)) - // luaL_error(L,"bad coordinates"); - // - // if (!gui_check_boundary(x2, y2)) - // luaL_error(L,"bad coordinates"); - gui_prepare(); - - if (!gui_checkbox(x1, y1, x2, y2)) - return 0; - - gui_fillbox_internal(x1, y1, x2, y2, colour); - - return 0; - } +static int gui_fillbox(lua_State *L) +{ + int x1, y1, x2, y2; + uint32 colour; + + x1 = luaL_checkinteger(L, 1); + y1 = luaL_checkinteger(L, 2); + x2 = luaL_checkinteger(L, 3); + y2 = luaL_checkinteger(L, 4); + colour = gui_getcolour(L, 5); + + // if (!gui_check_boundary(x1, y1)) + // luaL_error(L,"bad coordinates"); + // + // if (!gui_check_boundary(x2, y2)) + // luaL_error(L,"bad coordinates"); + gui_prepare(); + + if (!gui_checkbox(x1, y1, x2, y2)) + return 0; + + gui_fillbox_internal(x1, y1, x2, y2, colour); + + return 0; +} // gui.fillcircle(x0, y0, radius, colour) - static int gui_fillcircle(lua_State *L) - { - int x, y, r; - uint32 colour; - - x = luaL_checkinteger(L, 1); - y = luaL_checkinteger(L, 2); - r = luaL_checkinteger(L, 3); - colour = gui_getcolour(L, 4); - - gui_prepare(); - - gui_fillcircle_internal(x, y, r, colour); - - return 0; - } - - static int gui_getpixel(lua_State *L) - { - int x = luaL_checkinteger(L, 1); - int y = luaL_checkinteger(L, 2); - - int pixWidth = 240, pixHeight = 160; - int scrWidth = 240, scrHeight = 160; - int scrOffsetX = 0, scrOffsetY = 0; - int pitch; - if (!systemIsRunningGBA()) - { - if (gbBorderOn) - { - pixWidth = 256, pixHeight = 224; - scrOffsetX = 48, scrOffsetY = 40; - } - else - { - pixWidth = 160, pixHeight = 144; - } - scrWidth = 160, scrHeight = 144; - } - pitch = pixWidth * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4); - scrOffsetY++; // don't know why it's needed - - if (!(x >= 0 && y >= 0 && x < scrWidth && y < scrHeight) /*!gui_check_boundary(x,y)*/) - { - lua_pushinteger(L, 0); - lua_pushinteger(L, 0); - lua_pushinteger(L, 0); - } - else - { - switch (systemColorDepth) - { - case 16: - { - uint16 *screen = (uint16 *) (&pix[scrOffsetY * pitch + scrOffsetX * 2]); - uint16 pixColor = screen[y * pitch / 2 + x]; - lua_pushinteger(L, (pixColor >> 8) & 0xF8); // red - lua_pushinteger(L, (pixColor >> 3) & 0xFC); // green - lua_pushinteger(L, (pixColor << 3) & 0xF8); // blue - } - break; - case 24: - { - uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 3]; - lua_pushinteger(L, screen[y * pitch + x * 3 + 2]); // red - lua_pushinteger(L, screen[y * pitch + x * 3 + 1]); // green - lua_pushinteger(L, screen[y * pitch + x * 3 + 0]); // blue - } - break; - case 32: - { - uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 4]; - lua_pushinteger(L, screen[y * pitch + x * 4 + 2]); // red - lua_pushinteger(L, screen[y * pitch + x * 4 + 1]); // green - lua_pushinteger(L, screen[y * pitch + x * 4 + 0]); // blue - } - break; - default: - lua_pushinteger(L, 0); - lua_pushinteger(L, 0); - lua_pushinteger(L, 0); - break; - } - } - return 3; - } - - static int gui_parsecolor(lua_State *L) - { - int r, g, b, a; - uint32 color = gui_getcolour(L, 1); - LUA_DECOMPOSE_PIXEL(color, a, r, g, b); - lua_pushinteger(L, r); - lua_pushinteger(L, g); - lua_pushinteger(L, b); - lua_pushinteger(L, a); - return 4; - } +static int gui_fillcircle(lua_State *L) +{ + int x, y, r; + uint32 colour; + + x = luaL_checkinteger(L, 1); + y = luaL_checkinteger(L, 2); + r = luaL_checkinteger(L, 3); + colour = gui_getcolour(L, 4); + + gui_prepare(); + + gui_fillcircle_internal(x, y, r, colour); + + return 0; +} + +static int gui_getpixel(lua_State *L) +{ + int x = luaL_checkinteger(L, 1); + int y = luaL_checkinteger(L, 2); + + int pixWidth = 240, pixHeight = 160; + int scrWidth = 240, scrHeight = 160; + int scrOffsetX = 0, scrOffsetY = 0; + int pitch; + if (!systemIsRunningGBA()) + { + if (gbBorderOn) + { + pixWidth = 256, pixHeight = 224; + scrOffsetX = 48, scrOffsetY = 40; + } + else + { + pixWidth = 160, pixHeight = 144; + } + scrWidth = 160, scrHeight = 144; + } + pitch = pixWidth * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4); + scrOffsetY++; // don't know why it's needed + + if (!(x >= 0 && y >= 0 && x < scrWidth && y < scrHeight) /*!gui_check_boundary(x,y)*/) + { + lua_pushinteger(L, 0); + lua_pushinteger(L, 0); + lua_pushinteger(L, 0); + } + else + { + switch (systemColorDepth) + { + case 16: + { + uint16 *screen = (uint16 *) (&pix[scrOffsetY * pitch + scrOffsetX * 2]); + uint16 pixColor = screen[y * pitch / 2 + x]; + lua_pushinteger(L, (pixColor >> 8) & 0xF8); // red + lua_pushinteger(L, (pixColor >> 3) & 0xFC); // green + lua_pushinteger(L, (pixColor << 3) & 0xF8); // blue + } + break; + case 24: + { + uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 3]; + lua_pushinteger(L, screen[y * pitch + x * 3 + 2]); // red + lua_pushinteger(L, screen[y * pitch + x * 3 + 1]); // green + lua_pushinteger(L, screen[y * pitch + x * 3 + 0]); // blue + } + break; + case 32: + { + uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 4]; + lua_pushinteger(L, screen[y * pitch + x * 4 + 2]); // red + lua_pushinteger(L, screen[y * pitch + x * 4 + 1]); // green + lua_pushinteger(L, screen[y * pitch + x * 4 + 0]); // blue + } + break; + default: + lua_pushinteger(L, 0); + lua_pushinteger(L, 0); + lua_pushinteger(L, 0); + break; + } + } + return 3; +} + +static int gui_parsecolor(lua_State *L) +{ + int r, g, b, a; + uint32 color = gui_getcolour(L, 1); + LUA_DECOMPOSE_PIXEL(color, a, r, g, b); + lua_pushinteger(L, r); + lua_pushinteger(L, g); + lua_pushinteger(L, b); + lua_pushinteger(L, a); + return 4; +} // gui.gdscreenshot() // @@ -2915,66 +2915,66 @@ // It really is easier that way. // example: gd.createFromGdStr(gui.gdscreenshot()):png("outputimage.png") - static int gui_gdscreenshot(lua_State *L) - { - int xofs = 0, yofs = 0, ppl = 240, width = 240, height = 160; - if (!systemIsRunningGBA()) - { - if (gbBorderOn) - xofs = 48, yofs = 40, ppl = 256; - else - ppl = 160; - width = 160, height = 144; - } - - yofs++; - - //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3; - int pitch = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4); - uint8 *screen = &pix[yofs * pitch + xofs * (systemColorDepth / 8)]; - - int size = 11 + width * height * 4; - char *str = new char[size + 1]; - str[size] = 0; - - unsigned char *ptr = (unsigned char *)str; - - // GD format header for truecolor image (11 bytes) - *ptr++ = (65534 >> 8) & 0xFF; - *ptr++ = (65534) & 0xFF; - *ptr++ = (width >> 8) & 0xFF; - *ptr++ = (width) & 0xFF; - *ptr++ = (height >> 8) & 0xFF; - *ptr++ = (height) & 0xFF; - *ptr++ = 1; - *ptr++ = 255; - *ptr++ = 255; - *ptr++ = 255; - *ptr++ = 255; - - GetColorFunc getColor; - getColorIOFunc(systemColorDepth, &getColor, NULL); - - int x, y; - for (y = 0; y < height; y++) - { - uint8 *s = &screen[y * pitch]; - for (x = 0; x < width; x++, s += systemColorDepth / 8) - { - uint8 r, g, b; - getColor(s, &r, &g, &b); - - *ptr++ = 0; - *ptr++ = r; - *ptr++ = g; - *ptr++ = b; - } - } - - lua_pushlstring(L, str, size); - delete[] str; - return 1; - } +static int gui_gdscreenshot(lua_State *L) +{ + int xofs = 0, yofs = 0, ppl = 240, width = 240, height = 160; + if (!systemIsRunningGBA()) + { + if (gbBorderOn) + xofs = 48, yofs = 40, ppl = 256; + else + ppl = 160; + width = 160, height = 144; + } + + yofs++; + + //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3; + int pitch = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4); + uint8 *screen = &pix[yofs * pitch + xofs * (systemColorDepth / 8)]; + + int size = 11 + width * height * 4; + char *str = new char[size + 1]; + str[size] = 0; + + unsigned char *ptr = (unsigned char *)str; + + // GD format header for truecolor image (11 bytes) + *ptr++ = (65534 >> 8) & 0xFF; + *ptr++ = (65534) & 0xFF; + *ptr++ = (width >> 8) & 0xFF; + *ptr++ = (width) & 0xFF; + *ptr++ = (height >> 8) & 0xFF; + *ptr++ = (height) & 0xFF; + *ptr++ = 1; + *ptr++ = 255; + *ptr++ = 255; + *ptr++ = 255; + *ptr++ = 255; + + GetColorFunc getColor; + getColorIOFunc(systemColorDepth, &getColor, NULL); + + int x, y; + for (y = 0; y < height; y++) + { + uint8 *s = &screen[y * pitch]; + for (x = 0; x < width; x++, s += systemColorDepth / 8) + { + uint8 r, g, b; + getColor(s, &r, &g, &b); + + *ptr++ = 0; + *ptr++ = r; + *ptr++ = g; + *ptr++ = b; + } + } + + lua_pushlstring(L, str, size); + delete[] str; + return 1; +} // gui.opacity(number alphaValue) // sets the transparency of subsequent draw calls @@ -2984,472 +2984,472 @@ // because you can provide an alpha value in the color argument of each draw call. // however, it can be convenient to be able to globally modify the drawing transparency - static int gui_setopacity(lua_State *L) - { - double opacF = luaL_checknumber(L, 1); - transparencyModifier = (int)(opacF * 255); - if (transparencyModifier < 0) - transparencyModifier = 0; - return 0; - } +static int gui_setopacity(lua_State *L) +{ + double opacF = luaL_checknumber(L, 1); + transparencyModifier = (int)(opacF * 255); + if (transparencyModifier < 0) + transparencyModifier = 0; + return 0; +} // gui.transparency(int strength) // // 0 = solid, - static int gui_transparency(lua_State *L) - { - double trans = luaL_checknumber(L, 1); - transparencyModifier = (int)((4.0 - trans) / 4.0 * 255); - if (transparencyModifier < 0) - transparencyModifier = 0; - return 0; - } - - static const uint32 Small_Font_Data[] = - { - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 32 - 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 33 ! - 0x00000000, 0x00040002, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 34 " - 0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 35 # - 0x00000000, 0x00040300, 0x00000403, 0x00000500, 0x00070600, 0x00000706, 0x00000000, // 36 $ - 0x00000000, 0x00000002, 0x00050000, 0x00000500, 0x00000005, 0x00080000, 0x00000000, // 37 % - 0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00080700, 0x00000000, // 38 & - 0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 39 ' - 0x00000000, 0x00000300, 0x00000003, 0x00000004, 0x00000005, 0x00000700, 0x00000000, // 40 ( - 0x00000000, 0x00000300, 0x00050000, 0x00060000, 0x00070000, 0x00000700, 0x00000000, // 41 ) - 0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00080006, 0x00000000, // 42 * - 0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00000000, 0x00000000, // 43 + - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000600, 0x00000700, 0x00000007, // 44 , - 0x00000000, 0x00000000, 0x00000000, 0x00060504, 0x00000000, 0x00000000, 0x00000000, // 45 - - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 46 . - 0x00030000, 0x00040000, 0x00000400, 0x00000500, 0x00000005, 0x00000006, 0x00000000, // 47 / - 0x00000000, 0x00000300, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 48 0 - 0x00000000, 0x00000300, 0x00000403, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 49 1 - 0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 50 2 - 0x00000000, 0x00000302, 0x00050000, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 51 3 - 0x00000000, 0x00000300, 0x00000003, 0x00060004, 0x00070605, 0x00080000, 0x00000000, // 52 4 - 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 53 5 - 0x00000000, 0x00000300, 0x00000003, 0x00000504, 0x00070005, 0x00000700, 0x00000000, // 54 6 - 0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 55 7 - 0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00000700, 0x00000000, // 56 8 - 0x00000000, 0x00000300, 0x00050003, 0x00060500, 0x00070000, 0x00000700, 0x00000000, // 57 9 - 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 58 : - 0x00000000, 0x00000000, 0x00000000, 0x00000500, 0x00000000, 0x00000700, 0x00000007, // 59 ; - 0x00000000, 0x00040000, 0x00000400, 0x00000004, 0x00000600, 0x00080000, 0x00000000, // 60 < - 0x00000000, 0x00000000, 0x00050403, 0x00000000, 0x00070605, 0x00000000, 0x00000000, // 61 = - 0x00000000, 0x00000002, 0x00000400, 0x00060000, 0x00000600, 0x00000006, 0x00000000, // 62 > - 0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 63 ? - 0x00000000, 0x00000300, 0x00050400, 0x00060004, 0x00070600, 0x00000000, 0x00000000, // 64 @ - 0x00000000, 0x00000300, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 65 A - 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 66 B - 0x00000000, 0x00040300, 0x00000003, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 67 C - 0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00000706, 0x00000000, // 68 D - 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00080706, 0x00000000, // 69 E - 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 70 F - 0x00000000, 0x00040300, 0x00000003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 71 G - 0x00000000, 0x00040002, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 72 H - 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 73 I - 0x00000000, 0x00040000, 0x00050000, 0x00060000, 0x00070005, 0x00000700, 0x00000000, // 74 J - 0x00000000, 0x00040002, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 75 K - 0x00000000, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00080706, 0x00000000, // 76 l - 0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 77 M - 0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 78 N - 0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 79 O - 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 80 P - 0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00090000, // 81 Q - 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 82 R - 0x00000000, 0x00040300, 0x00000003, 0x00000500, 0x00070000, 0x00000706, 0x00000000, // 83 S - 0x00000000, 0x00040302, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 84 T - 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 85 U - 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000000, // 86 V - 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 87 W - 0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 88 X - 0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 89 Y - 0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 90 Z - 0x00000000, 0x00040300, 0x00000400, 0x00000500, 0x00000600, 0x00080700, 0x00000000, // 91 [ - 0x00000000, 0x00000002, 0x00000400, 0x00000500, 0x00070000, 0x00080000, 0x00000000, // 92 '\' - 0x00000000, 0x00000302, 0x00000400, 0x00000500, 0x00000600, 0x00000706, 0x00000000, // 93 ] - 0x00000000, 0x00000300, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 94 ^ - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080706, 0x00000000, // 95 _ - 0x00000000, 0x00000002, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 96 ` - 0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 97 a - 0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 98 b - 0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 99 c - 0x00000000, 0x00040000, 0x00050000, 0x00060500, 0x00070005, 0x00080700, 0x00000000, // 100 d - 0x00000000, 0x00000000, 0x00050400, 0x00060504, 0x00000005, 0x00080700, 0x00000000, // 101 e - 0x00000000, 0x00040300, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 102 f - 0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070600, 0x00080000, 0x00000807, // 103 g - 0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 104 h - 0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 105 i - 0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000007, // 106 j - 0x00000000, 0x00000002, 0x00000003, 0x00060004, 0x00000605, 0x00080006, 0x00000000, // 107 k - 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 108 l - 0x00000000, 0x00000000, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 109 m - 0x00000000, 0x00000000, 0x00000403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 110 n - 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 111 o - 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00000605, 0x00000006, 0x00000007, // 112 p - 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070600, 0x00080000, 0x00090000, // 113 q - 0x00000000, 0x00000000, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 114 r - 0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00070600, 0x00000706, 0x00000000, // 115 s - 0x00000000, 0x00000300, 0x00050403, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 116 t - 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 117 u - 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 118 v - 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 119 w - 0x00000000, 0x00000000, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 120 x - 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000007, // 121 y - 0x00000000, 0x00000000, 0x00050403, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 122 z - 0x00000000, 0x00040300, 0x00000400, 0x00000504, 0x00000600, 0x00080700, 0x00000000, // 123 { - 0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000600, 0x00000700, 0x00000000, // 124 | - 0x00000000, 0x00000302, 0x00000400, 0x00060500, 0x00000600, 0x00000706, 0x00000000, // 125 } - 0x00000000, 0x00000302, 0x00050000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 126 ~ - 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070605, 0x00000000, 0x00000000, // 127  - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - }; - - static void PutTextInternal(const char *str, int len, short x, short y, int color, int backcolor) - { - int Opac = (color >> 24) & 0xFF; - int backOpac = (backcolor >> 24) & 0xFF; - int origX = x; - - if (!Opac && !backOpac) - return; - - while (*str && len && y < LUA_SCREEN_HEIGHT) - { - int c = *str++; - while (x > LUA_SCREEN_WIDTH && c != '\n') - { - c = *str; - if (c == '\0') - break; - str++; - } - - if (c == '\n') - { - x = origX; - y += 8; - continue; - } - else if (c == '\t') // just in case - { - const int tabSpace = 8; - x += (tabSpace - (((x - origX) / 4) % tabSpace)) * 4; - continue; - } - - if ((unsigned int)(c - 32) >= 96) - continue; - - const unsigned char *Cur_Glyph = (const unsigned char *) &Small_Font_Data + (c - 32) * 7 * 4; - - for (int y2 = 0; y2 < 8; y2++) - { - unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y2); - for (int x2 = -1; x2 < 4; x2++) - { - int shift = x2 << 3; - int mask = 0xFF << shift; - int intensity = (glyphLine & mask) >> shift; - - if (intensity && x2 >= 0 && y2 < 7) - { - //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2)); - //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2)); - //gui_drawpixel_fast(xdraw, ydraw, color); - gui_drawpixel_internal(x + x2, y + y2, color); - } - else if (backOpac) - { - for (int y3 = max(0, y2 - 1); y3 <= min(6, y2 + 1); y3++) - { - unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y3); - for (int x3 = max(0, x2 - 1); x3 <= min(3, x2 + 1); x3++) - { - int shift = x3 << 3; - int mask = 0xFF << shift; - intensity |= (glyphLine & mask) >> shift; - if (intensity) - goto draw_outline; // speedup? - } - } - -draw_outline: - if (intensity) - { - //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2)); - //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2)); - //gui_drawpixel_fast(xdraw, ydraw, backcolor); - gui_drawpixel_internal(x + x2, y + y2, backcolor); - } - } - } - } - - x += 4; - len--; - } - } - - static int strlinelen(const char *string) - { - const char *s = string; - while (*s && *s != '\n') - s++; - if (*s) - s++; - return s - string; - } - - static void LuaDisplayString(const char *string, int y, int x, uint32 color, uint32 outlineColor) - { - if (!string) - return; - - gui_prepare(); - - PutTextInternal(string, strlen(string), x, y, color, outlineColor); - - /* - const char* ptr = string; - while(*ptr && y < LUA_SCREEN_HEIGHT) - { - int len = strlinelen(ptr); - int skip = 0; - if(len < 1) len = 1; - - // break up the line if it's too long to display otherwise - if(len > 63) - { - len = 63; - const char* ptr2 = ptr + len-1; - for(int j = len-1; j; j--, ptr2--) - { - if(*ptr2 == ' ' || *ptr2 == '\t') - { - len = j; - skip = 1; - break; - } - } - } - - int xl = 0; - int yl = 0; - int xh = (LUA_SCREEN_WIDTH - 1 - 1) - 4*len; - int yh = LUA_SCREEN_HEIGHT - 1; - int x2 = min(max(x,xl),xh); - int y2 = min(max(y,yl),yh); - - PutTextInternal(ptr,len,x2,y2,color,outlineColor); - - ptr += len + skip; - y += 8; - } - */ - } +static int gui_transparency(lua_State *L) +{ + double trans = luaL_checknumber(L, 1); + transparencyModifier = (int)((4.0 - trans) / 4.0 * 255); + if (transparencyModifier < 0) + transparencyModifier = 0; + return 0; +} + +static const uint32 Small_Font_Data[] = + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 32 + 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 33 ! + 0x00000000, 0x00040002, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 34 " + 0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 35 # + 0x00000000, 0x00040300, 0x00000403, 0x00000500, 0x00070600, 0x00000706, 0x00000000, // 36 $ + 0x00000000, 0x00000002, 0x00050000, 0x00000500, 0x00000005, 0x00080000, 0x00000000, // 37 % + 0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00080700, 0x00000000, // 38 & + 0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 39 ' + 0x00000000, 0x00000300, 0x00000003, 0x00000004, 0x00000005, 0x00000700, 0x00000000, // 40 ( + 0x00000000, 0x00000300, 0x00050000, 0x00060000, 0x00070000, 0x00000700, 0x00000000, // 41 ) + 0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00080006, 0x00000000, // 42 * + 0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00000000, 0x00000000, // 43 + + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000600, 0x00000700, 0x00000007, // 44 , + 0x00000000, 0x00000000, 0x00000000, 0x00060504, 0x00000000, 0x00000000, 0x00000000, // 45 - + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 46 . + 0x00030000, 0x00040000, 0x00000400, 0x00000500, 0x00000005, 0x00000006, 0x00000000, // 47 / + 0x00000000, 0x00000300, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 48 0 + 0x00000000, 0x00000300, 0x00000403, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 49 1 + 0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 50 2 + 0x00000000, 0x00000302, 0x00050000, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 51 3 + 0x00000000, 0x00000300, 0x00000003, 0x00060004, 0x00070605, 0x00080000, 0x00000000, // 52 4 + 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 53 5 + 0x00000000, 0x00000300, 0x00000003, 0x00000504, 0x00070005, 0x00000700, 0x00000000, // 54 6 + 0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 55 7 + 0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00000700, 0x00000000, // 56 8 + 0x00000000, 0x00000300, 0x00050003, 0x00060500, 0x00070000, 0x00000700, 0x00000000, // 57 9 + 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 58 : + 0x00000000, 0x00000000, 0x00000000, 0x00000500, 0x00000000, 0x00000700, 0x00000007, // 59 ; + 0x00000000, 0x00040000, 0x00000400, 0x00000004, 0x00000600, 0x00080000, 0x00000000, // 60 < + 0x00000000, 0x00000000, 0x00050403, 0x00000000, 0x00070605, 0x00000000, 0x00000000, // 61 = + 0x00000000, 0x00000002, 0x00000400, 0x00060000, 0x00000600, 0x00000006, 0x00000000, // 62 > + 0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 63 ? + 0x00000000, 0x00000300, 0x00050400, 0x00060004, 0x00070600, 0x00000000, 0x00000000, // 64 @ + 0x00000000, 0x00000300, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 65 A + 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 66 B + 0x00000000, 0x00040300, 0x00000003, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 67 C + 0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00000706, 0x00000000, // 68 D + 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00080706, 0x00000000, // 69 E + 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 70 F + 0x00000000, 0x00040300, 0x00000003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 71 G + 0x00000000, 0x00040002, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 72 H + 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 73 I + 0x00000000, 0x00040000, 0x00050000, 0x00060000, 0x00070005, 0x00000700, 0x00000000, // 74 J + 0x00000000, 0x00040002, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 75 K + 0x00000000, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00080706, 0x00000000, // 76 l + 0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 77 M + 0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 78 N + 0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 79 O + 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 80 P + 0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00090000, // 81 Q + 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 82 R + 0x00000000, 0x00040300, 0x00000003, 0x00000500, 0x00070000, 0x00000706, 0x00000000, // 83 S + 0x00000000, 0x00040302, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 84 T + 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 85 U + 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000000, // 86 V + 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 87 W + 0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 88 X + 0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 89 Y + 0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 90 Z + 0x00000000, 0x00040300, 0x00000400, 0x00000500, 0x00000600, 0x00080700, 0x00000000, // 91 [ + 0x00000000, 0x00000002, 0x00000400, 0x00000500, 0x00070000, 0x00080000, 0x00000000, // 92 '\' + 0x00000000, 0x00000302, 0x00000400, 0x00000500, 0x00000600, 0x00000706, 0x00000000, // 93 ] + 0x00000000, 0x00000300, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 94 ^ + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080706, 0x00000000, // 95 _ + 0x00000000, 0x00000002, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 96 ` + 0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 97 a + 0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 98 b + 0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 99 c + 0x00000000, 0x00040000, 0x00050000, 0x00060500, 0x00070005, 0x00080700, 0x00000000, // 100 d + 0x00000000, 0x00000000, 0x00050400, 0x00060504, 0x00000005, 0x00080700, 0x00000000, // 101 e + 0x00000000, 0x00040300, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 102 f + 0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070600, 0x00080000, 0x00000807, // 103 g + 0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 104 h + 0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 105 i + 0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000007, // 106 j + 0x00000000, 0x00000002, 0x00000003, 0x00060004, 0x00000605, 0x00080006, 0x00000000, // 107 k + 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 108 l + 0x00000000, 0x00000000, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 109 m + 0x00000000, 0x00000000, 0x00000403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 110 n + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 111 o + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00000605, 0x00000006, 0x00000007, // 112 p + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070600, 0x00080000, 0x00090000, // 113 q + 0x00000000, 0x00000000, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 114 r + 0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00070600, 0x00000706, 0x00000000, // 115 s + 0x00000000, 0x00000300, 0x00050403, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 116 t + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 117 u + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 118 v + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 119 w + 0x00000000, 0x00000000, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 120 x + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000007, // 121 y + 0x00000000, 0x00000000, 0x00050403, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 122 z + 0x00000000, 0x00040300, 0x00000400, 0x00000504, 0x00000600, 0x00080700, 0x00000000, // 123 { + 0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000600, 0x00000700, 0x00000000, // 124 | + 0x00000000, 0x00000302, 0x00000400, 0x00060500, 0x00000600, 0x00000706, 0x00000000, // 125 } + 0x00000000, 0x00000302, 0x00050000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 126 ~ + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070605, 0x00000000, 0x00000000, // 127  + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + }; + +static void PutTextInternal(const char *str, int len, short x, short y, int color, int backcolor) +{ + int Opac = (color >> 24) & 0xFF; + int backOpac = (backcolor >> 24) & 0xFF; + int origX = x; + + if (!Opac && !backOpac) + return; + + while (*str && len && y < LUA_SCREEN_HEIGHT) + { + int c = *str++; + while (x > LUA_SCREEN_WIDTH && c != '\n') + { + c = *str; + if (c == '\0') + break; + str++; + } + + if (c == '\n') + { + x = origX; + y += 8; + continue; + } + else if (c == '\t') // just in case + { + const int tabSpace = 8; + x += (tabSpace - (((x - origX) / 4) % tabSpace)) * 4; + continue; + } + + if ((unsigned int)(c - 32) >= 96) + continue; + + const unsigned char *Cur_Glyph = (const unsigned char *) &Small_Font_Data + (c - 32) * 7 * 4; + + for (int y2 = 0; y2 < 8; y2++) + { + unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y2); + for (int x2 = -1; x2 < 4; x2++) + { + int shift = x2 << 3; + int mask = 0xFF << shift; + int intensity = (glyphLine & mask) >> shift; + + if (intensity && x2 >= 0 && y2 < 7) + { + //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2)); + //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2)); + //gui_drawpixel_fast(xdraw, ydraw, color); + gui_drawpixel_internal(x + x2, y + y2, color); + } + else if (backOpac) + { + for (int y3 = max(0, y2 - 1); y3 <= min(6, y2 + 1); y3++) + { + unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y3); + for (int x3 = max(0, x2 - 1); x3 <= min(3, x2 + 1); x3++) + { + int shift = x3 << 3; + int mask = 0xFF << shift; + intensity |= (glyphLine & mask) >> shift; + if (intensity) + goto draw_outline; // speedup? + } + } + + draw_outline: + if (intensity) + { + //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2)); + //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2)); + //gui_drawpixel_fast(xdraw, ydraw, backcolor); + gui_drawpixel_internal(x + x2, y + y2, backcolor); + } + } + } + } + + x += 4; + len--; + } +} + +static int strlinelen(const char *string) +{ + const char *s = string; + while (*s && *s != '\n') + s++; + if (*s) + s++; + return s - string; +} + +static void LuaDisplayString(const char *string, int y, int x, uint32 color, uint32 outlineColor) +{ + if (!string) + return; + + gui_prepare(); + + PutTextInternal(string, strlen(string), x, y, color, outlineColor); + + /* + const char* ptr = string; + while(*ptr && y < LUA_SCREEN_HEIGHT) + { + int len = strlinelen(ptr); + int skip = 0; + if(len < 1) len = 1; + + // break up the line if it's too long to display otherwise + if(len > 63) + { + len = 63; + const char* ptr2 = ptr + len-1; + for(int j = len-1; j; j--, ptr2--) + { + if(*ptr2 == ' ' || *ptr2 == '\t') + { + len = j; + skip = 1; + break; + } + } + } + + int xl = 0; + int yl = 0; + int xh = (LUA_SCREEN_WIDTH - 1 - 1) - 4*len; + int yh = LUA_SCREEN_HEIGHT - 1; + int x2 = min(max(x,xl),xh); + int y2 = min(max(y,yl),yh); + + PutTextInternal(ptr,len,x2,y2,color,outlineColor); + + ptr += len + skip; + y += 8; + } + */ +} // gui.text(int x, int y, string msg) // // Displays the given text on the screen, using the same font and techniques as the // main HUD. - static int gui_text(lua_State *L) - { - //extern int font_height; - const char *msg; - int x, y; - uint32 colour, borderColour; - - x = luaL_checkinteger(L, 1); - y = luaL_checkinteger(L, 2); - //msg = luaL_checkstring(L, 3); - msg = toCString(L, 3); - - // if (x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= (LUA_SCREEN_HEIGHT - font_height)) - // luaL_error(L,"bad coordinates"); - colour = gui_optcolour(L, 4, LUA_BUILD_PIXEL(255, 255, 255, 255)); - borderColour = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 0, 0, 0)); - - gui_prepare(); - - LuaDisplayString(msg, y, x, colour, borderColour); - - return 0; - } +static int gui_text(lua_State *L) +{ + //extern int font_height; + const char *msg; + int x, y; + uint32 colour, borderColour; + + x = luaL_checkinteger(L, 1); + y = luaL_checkinteger(L, 2); + //msg = luaL_checkstring(L, 3); + msg = toCString(L, 3); + + // if (x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= (LUA_SCREEN_HEIGHT - font_height)) + // luaL_error(L,"bad coordinates"); + colour = gui_optcolour(L, 4, LUA_BUILD_PIXEL(255, 255, 255, 255)); + borderColour = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 0, 0, 0)); + + gui_prepare(); + + LuaDisplayString(msg, y, x, colour, borderColour); + + return 0; +} // gui.gdoverlay([int dx=0, int dy=0,] string str [, sx=0, sy=0, sw, sh] [, float alphamul=1.0]) // // Overlays the given image on the screen. // example: gui.gdoverlay(gd.createFromPng("myimage.png"):gdStr()) - static int gui_gdoverlay(lua_State *L) - { - int argCount = lua_gettop(L); - - int xStartDst = 0; - int yStartDst = 0; - int xStartSrc = 0; - int yStartSrc = 0; - - int index = 1; - if (lua_type(L, index) == LUA_TNUMBER) - { - xStartDst = lua_tointeger(L, index++); - if (lua_type(L, index) == LUA_TNUMBER) - yStartDst = lua_tointeger(L, index++); - } - - luaL_checktype(L, index, LUA_TSTRING); - - const unsigned char *ptr = (const unsigned char *)lua_tostring(L, index++); - - if (ptr[0] != 255 || (ptr[1] != 254 && ptr[1] != 255)) - luaL_error(L, "bad image data"); - - bool trueColor = (ptr[1] == 254); - ptr += 2; - - int imgwidth = *ptr++ << 8; - imgwidth |= *ptr++; - - int width = imgwidth; - int imgheight = *ptr++ << 8; - imgheight |= *ptr++; - - int height = imgheight; - if ((!trueColor && *ptr) || (trueColor && !*ptr)) - luaL_error(L, "bad image data"); - ptr++; - - int pitch = imgwidth * (trueColor ? 4 : 1); - - if ((argCount - index + 1) >= 4) - { - xStartSrc = luaL_checkinteger(L, index++); - yStartSrc = luaL_checkinteger(L, index++); - width = luaL_checkinteger(L, index++); - height = luaL_checkinteger(L, index++); - } - - int alphaMul = transparencyModifier; - if (lua_isnumber(L, index)) - alphaMul = (int)(alphaMul * lua_tonumber(L, index++)); - if (alphaMul <= 0) - return 0; - - // since there aren't that many possible opacity levels, - // do the opacity modification calculations beforehand instead of per pixel - int opacMap[256]; - for (int i = 0; i < 128; i++) - { - int opac = 255 - ((i << 1) | (i & 1)); // gdAlphaMax = 127, not 255 - opac = (opac * alphaMul) / 255; - if (opac < 0) - opac = 0; - if (opac > 255) - opac = 255; - opacMap[i] = opac; - } - - for (int i = 128; i < 256; i++) - opacMap[i] = 0; // what should we do for them, actually? - int colorsTotal = 0; - if (!trueColor) - { - colorsTotal = *ptr++ << 8; - colorsTotal |= *ptr++; - } - - int transparent = *ptr++ << 24; - transparent |= *ptr++ << 16; - transparent |= *ptr++ << 8; - transparent |= *ptr++; - struct - { - uint8 r, g, b, a; - } pal[256]; - if (!trueColor) - for (int i = 0; i < 256; i++) - { - pal[i].r = *ptr++; - pal[i].g = *ptr++; - pal[i].b = *ptr++; - pal[i].a = opacMap[*ptr++]; - } - - // some of clippings - if (xStartSrc < 0) - { - width += xStartSrc; - xStartDst -= xStartSrc; - xStartSrc = 0; - } - - if (yStartSrc < 0) - { - height += yStartSrc; - yStartDst -= yStartSrc; - yStartSrc = 0; - } - - if (xStartSrc + width >= imgwidth) - width = imgwidth - xStartSrc; - if (yStartSrc + height >= imgheight) - height = imgheight - yStartSrc; - if (xStartDst < 0) - { - width += xStartDst; - if (width <= 0) - return 0; - xStartSrc = -xStartDst; - xStartDst = 0; - } - - if (yStartDst < 0) - { - height += yStartDst; - if (height <= 0) - return 0; - yStartSrc = -yStartDst; - yStartDst = 0; - } - - if (xStartDst + width >= LUA_SCREEN_WIDTH) - width = LUA_SCREEN_WIDTH - xStartDst; - if (yStartDst + height >= LUA_SCREEN_HEIGHT) - height = LUA_SCREEN_HEIGHT - yStartDst; - if (width <= 0 || height <= 0) - return 0; // out of screen or invalid size - gui_prepare(); - - const uint8 *pix = (const uint8 *)(&ptr[yStartSrc * pitch + (xStartSrc * (trueColor ? 4 : 1))]); - int bytesToNextLine = pitch - (width * (trueColor ? 4 : 1)); - if (trueColor) - { - for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine) - { - for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix += 4) - { - gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(opacMap[pix[0]], pix[1], pix[2], pix[3])); - } - } - } - else - { - for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine) - { - for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix++) - { - gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(pal[*pix].a, pal[*pix].r, pal[*pix].g, pal[*pix].b)); - } - } - } - - return 0; - } +static int gui_gdoverlay(lua_State *L) +{ + int argCount = lua_gettop(L); + + int xStartDst = 0; + int yStartDst = 0; + int xStartSrc = 0; + int yStartSrc = 0; + + int index = 1; + if (lua_type(L, index) == LUA_TNUMBER) + { + xStartDst = lua_tointeger(L, index++); + if (lua_type(L, index) == LUA_TNUMBER) + yStartDst = lua_tointeger(L, index++); + } + + luaL_checktype(L, index, LUA_TSTRING); + + const unsigned char *ptr = (const unsigned char *)lua_tostring(L, index++); + + if (ptr[0] != 255 || (ptr[1] != 254 && ptr[1] != 255)) + luaL_error(L, "bad image data"); + + bool trueColor = (ptr[1] == 254); + ptr += 2; + + int imgwidth = *ptr++ << 8; + imgwidth |= *ptr++; + + int width = imgwidth; + int imgheight = *ptr++ << 8; + imgheight |= *ptr++; + + int height = imgheight; + if ((!trueColor && *ptr) || (trueColor && !*ptr)) + luaL_error(L, "bad image data"); + ptr++; + + int pitch = imgwidth * (trueColor ? 4 : 1); + + if ((argCount - index + 1) >= 4) + { + xStartSrc = luaL_checkinteger(L, index++); + yStartSrc = luaL_checkinteger(L, index++); + width = luaL_checkinteger(L, index++); + height = luaL_checkinteger(L, index++); + } + + int alphaMul = transparencyModifier; + if (lua_isnumber(L, index)) + alphaMul = (int)(alphaMul * lua_tonumber(L, index++)); + if (alphaMul <= 0) + return 0; + + // since there aren't that many possible opacity levels, + // do the opacity modification calculations beforehand instead of per pixel + int opacMap[256]; + for (int i = 0; i < 128; i++) + { + int opac = 255 - ((i << 1) | (i & 1)); // gdAlphaMax = 127, not 255 + opac = (opac * alphaMul) / 255; + if (opac < 0) + opac = 0; + if (opac > 255) + opac = 255; + opacMap[i] = opac; + } + + for (int i = 128; i < 256; i++) + opacMap[i] = 0; // what should we do for them, actually? + int colorsTotal = 0; + if (!trueColor) + { + colorsTotal = *ptr++ << 8; + colorsTotal |= *ptr++; + } + + int transparent = *ptr++ << 24; + transparent |= *ptr++ << 16; + transparent |= *ptr++ << 8; + transparent |= *ptr++; + struct + { + uint8 r, g, b, a; + } pal[256]; + if (!trueColor) + for (int i = 0; i < 256; i++) + { + pal[i].r = *ptr++; + pal[i].g = *ptr++; + pal[i].b = *ptr++; + pal[i].a = opacMap[*ptr++]; + } + + // some of clippings + if (xStartSrc < 0) + { + width += xStartSrc; + xStartDst -= xStartSrc; + xStartSrc = 0; + } + + if (yStartSrc < 0) + { + height += yStartSrc; + yStartDst -= yStartSrc; + yStartSrc = 0; + } + + if (xStartSrc + width >= imgwidth) + width = imgwidth - xStartSrc; + if (yStartSrc + height >= imgheight) + height = imgheight - yStartSrc; + if (xStartDst < 0) + { + width += xStartDst; + if (width <= 0) + return 0; + xStartSrc = -xStartDst; + xStartDst = 0; + } + + if (yStartDst < 0) + { + height += yStartDst; + if (height <= 0) + return 0; + yStartSrc = -yStartDst; + yStartDst = 0; + } + + if (xStartDst + width >= LUA_SCREEN_WIDTH) + width = LUA_SCREEN_WIDTH - xStartDst; + if (yStartDst + height >= LUA_SCREEN_HEIGHT) + height = LUA_SCREEN_HEIGHT - yStartDst; + if (width <= 0 || height <= 0) + return 0; // out of screen or invalid size + gui_prepare(); + + const uint8 *pix = (const uint8 *)(&ptr[yStartSrc * pitch + (xStartSrc * (trueColor ? 4 : 1))]); + int bytesToNextLine = pitch - (width * (trueColor ? 4 : 1)); + if (trueColor) + { + for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine) + { + for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix += 4) + { + gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(opacMap[pix[0]], pix[1], pix[2], pix[3])); + } + } + } + else + { + for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine) + { + for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix++) + { + gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(pal[*pix].a, pal[*pix].r, pal[*pix].g, pal[*pix].b)); + } + } + } + + return 0; +} // function gui.register(function f) // @@ -3459,347 +3459,347 @@ // a previously registered function, and the previous function // (if any) is returned, or nil if none. - static int gui_register(lua_State *L) - { - // We'll do this straight up. - // First set up the stack. - lua_settop(L, 1); - - // Verify the validity of the entry - if (!lua_isnil(L, 1)) - luaL_checktype(L, 1, LUA_TFUNCTION); - - // Get the old value - lua_getfield(L, LUA_REGISTRYINDEX, guiCallbackTable); - - // Save the new value - lua_pushvalue(L, 1); - lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable); - - // The old value is on top of the stack. Return it. - return 1; - } +static int gui_register(lua_State *L) +{ + // We'll do this straight up. + // First set up the stack. + lua_settop(L, 1); + + // Verify the validity of the entry + if (!lua_isnil(L, 1)) + luaL_checktype(L, 1, LUA_TFUNCTION); + + // Get the old value + lua_getfield(L, LUA_REGISTRYINDEX, guiCallbackTable); + + // Save the new value + lua_pushvalue(L, 1); + lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable); + + // The old value is on top of the stack. Return it. + return 1; +} // string gui.popup(string message, [string type = "ok"]) // // Popup dialog! - int gui_popup(lua_State *L) - { - const char *message = luaL_checkstring(L, 1); - const char *type = luaL_optstring(L, 2, "ok"); +int gui_popup(lua_State *L) +{ + const char *message = luaL_checkstring(L, 1); + const char *type = luaL_optstring(L, 2, "ok"); #if (defined(WIN32) && !defined(SDL)) - int t; - if (strcmp(type, "ok") == 0) - t = MB_OK; - else if (strcmp(type, "yesno") == 0) - t = MB_YESNO; - else if (strcmp(type, "yesnocancel") == 0) - t = MB_YESNOCANCEL; - else - return luaL_error(L, "invalid popup type \"%s\"", type); - - theApp.winCheckFullscreen(); - systemSoundClearBuffer(); - int result = AfxGetApp()->m_pMainWnd->MessageBox(message, "Lua Script Pop-up", t); - - lua_settop(L, 1); - - if (t != MB_OK) - { - if (result == IDYES) - lua_pushstring(L, "yes"); - else if (result == IDNO) - lua_pushstring(L, "no"); - else if (result == IDCANCEL) - lua_pushstring(L, "cancel"); - else - luaL_error(L, "win32 unrecognized return value %d", result); - return 1; - } - - // else, we don't care. - return 0; + int t; + if (strcmp(type, "ok") == 0) + t = MB_OK; + else if (strcmp(type, "yesno") == 0) + t = MB_YESNO; + else if (strcmp(type, "yesnocancel") == 0) + t = MB_YESNOCANCEL; + else + return luaL_error(L, "invalid popup type \"%s\"", type); + + theApp.winCheckFullscreen(); + systemSoundClearBuffer(); + int result = AfxGetApp()->m_pMainWnd->MessageBox(message, "Lua Script Pop-up", t); + + lua_settop(L, 1); + + if (t != MB_OK) + { + if (result == IDYES) + lua_pushstring(L, "yes"); + else if (result == IDNO) + lua_pushstring(L, "no"); + else if (result == IDCANCEL) + lua_pushstring(L, "cancel"); + else + luaL_error(L, "win32 unrecognized return value %d", result); + return 1; + } + + // else, we don't care. + return 0; #else - char *t; - #ifdef __linux - // The Linux backend has a "FromPause" variable. - // If set to 1, assume some known external event has screwed with the flow of time. - // Since this pauses the emulator waiting for a response, we set it to 1. -// FIXME: Well, actually it doesn't -// extern int FromPause; -// FromPause = 1; - - int pid; // appease compiler - - // Before doing any work, verify the correctness of the parameters. - if (strcmp(type, "ok") == 0) - t = "OK:100"; - else if (strcmp(type, "yesno") == 0) - t = "Yes:100,No:101"; - else if (strcmp(type, "yesnocancel") == 0) - t = "Yes:100,No:101,Cancel:102"; - else - return luaL_error(L, "invalid popup type \"%s\"", type); - - // Can we find a copy of xmessage? Search the path. - char *path = strdup(getenv("PATH")); - - char *current = path; - - char *colon; - - int found = 0; - - while (current) - { - colon = strchr(current, ':'); - - // Clip off the colon. - *colon++ = 0; - - int len = strlen(current); - char *filename = (char *)malloc(len + 12); // always give excess - snprintf(filename, len + 12, "%s/xmessage", current); - - if (access(filename, X_OK) == 0) - { - free(filename); - found = 1; - break; - } - - // Failed, move on. - current = colon; - free(filename); - } - - free(path); - - // We've found it? - if (!found) - goto use_console; - - pid = fork(); - if (pid == 0) - { // I'm the virgin sacrifice - // I'm gonna be dead in a matter of microseconds anyways, so wasted memory doesn't matter to me. - // Go ahead and abuse strdup. - char *parameters[] = { "xmessage", "-buttons", t, strdup(message), NULL }; - - execvp("xmessage", parameters); - - // Aw shitty - perror("exec xmessage"); - exit(1); - } - else if (pid < 0) // something went wrong!!! Oh hell... use the console - goto use_console; - else - { - // We're the parent. Watch for the child. - int r; - int res = waitpid(pid, &r, 0); - if (res < 0) // wtf? - goto use_console; - - // The return value gets copmlicated... - if (!WIFEXITED(r)) - { - luaL_error(L, "don't screw with my xmessage process!"); - } - - r = WEXITSTATUS(r); - - // We assume it's worked. - if (r == 0) - { - return 0; // no parameters for an OK - } - - if (r == 100) - { - lua_pushstring(L, "yes"); - return 1; - } - - if (r == 101) - { - lua_pushstring(L, "no"); - return 1; - } - - if (r == 102) - { - lua_pushstring(L, "cancel"); - return 1; - } - - // Wtf? - return luaL_error(L, "popup failed due to unknown results involving xmessage (%d)", r); - } - -use_console: - #endif - - // All else has failed - if (strcmp(type, "ok") == 0) - t = ""; - else if (strcmp(type, "yesno") == 0) - t = "yn"; - else if (strcmp(type, "yesnocancel") == 0) - t = "ync"; - else - return luaL_error(L, "invalid popup type \"%s\"", type); - - fprintf(stderr, "Lua Message: %s\n", message); - - while (true) - { - char buffer[64]; - - // We don't want parameters - if (!t[0]) - { - fprintf(stderr, "[Press Enter]"); - fgets(buffer, sizeof(buffer), stdin); - - // We're done - return 0; - } - - fprintf(stderr, "(%s): ", t); - fgets(buffer, sizeof(buffer), stdin); - - // Check if the option is in the list - if (strchr(t, tolower(buffer[0]))) - { - switch (tolower(buffer[0])) - { - case 'y': - lua_pushstring(L, "yes"); - return 1; - case 'n': - lua_pushstring(L, "no"); - return 1; - case 'c': - lua_pushstring(L, "cancel"); - return 1; - default: - luaL_error(L, "internal logic error in console based prompts for gui.popup"); - } - } - - // We fell through, so we assume the user answered wrong and prompt again. - } - - // Nothing here, since the only way out is in the loop. + char *t; +#ifdef __linux + // The Linux backend has a "FromPause" variable. + // If set to 1, assume some known external event has screwed with the flow of time. + // Since this pauses the emulator waiting for a response, we set it to 1. + // FIXME: Well, actually it doesn't + // extern int FromPause; + // FromPause = 1; + + int pid; // appease compiler + + // Before doing any work, verify the correctness of the parameters. + if (strcmp(type, "ok") == 0) + t = "OK:100"; + else if (strcmp(type, "yesno") == 0) + t = "Yes:100,No:101"; + else if (strcmp(type, "yesnocancel") == 0) + t = "Yes:100,No:101,Cancel:102"; + else + return luaL_error(L, "invalid popup type \"%s\"", type); + + // Can we find a copy of xmessage? Search the path. + char *path = strdup(getenv("PATH")); + + char *current = path; + + char *colon; + + int found = 0; + + while (current) + { + colon = strchr(current, ':'); + + // Clip off the colon. + *colon++ = 0; + + int len = strlen(current); + char *filename = (char *)malloc(len + 12); // always give excess + snprintf(filename, len + 12, "%s/xmessage", current); + + if (access(filename, X_OK) == 0) + { + free(filename); + found = 1; + break; + } + + // Failed, move on. + current = colon; + free(filename); + } + + free(path); + + // We've found it? + if (!found) + goto use_console; + + pid = fork(); + if (pid == 0) + { // I'm the virgin sacrifice + // I'm gonna be dead in a matter of microseconds anyways, so wasted memory doesn't matter to me. + // Go ahead and abuse strdup. + char *parameters[] = { "xmessage", "-buttons", t, strdup(message), NULL }; + + execvp("xmessage", parameters); + + // Aw shitty + perror("exec xmessage"); + exit(1); + } + else if (pid < 0) // something went wrong!!! Oh hell... use the console + goto use_console; + else + { + // We're the parent. Watch for the child. + int r; + int res = waitpid(pid, &r, 0); + if (res < 0) // wtf? + goto use_console; + + // The return value gets copmlicated... + if (!WIFEXITED(r)) + { + luaL_error(L, "don't screw with my xmessage process!"); + } + + r = WEXITSTATUS(r); + + // We assume it's worked. + if (r == 0) + { + return 0; // no parameters for an OK + } + + if (r == 100) + { + lua_pushstring(L, "yes"); + return 1; + } + + if (r == 101) + { + lua_pushstring(L, "no"); + return 1; + } + + if (r == 102) + { + lua_pushstring(L, "cancel"); + return 1; + } + + // Wtf? + return luaL_error(L, "popup failed due to unknown results involving xmessage (%d)", r); + } + + use_console: #endif - } + + // All else has failed + if (strcmp(type, "ok") == 0) + t = ""; + else if (strcmp(type, "yesno") == 0) + t = "yn"; + else if (strcmp(type, "yesnocancel") == 0) + t = "ync"; + else + return luaL_error(L, "invalid popup type \"%s\"", type); + + fprintf(stderr, "Lua Message: %s\n", message); + + while (true) + { + char buffer[64]; + + // We don't want parameters + if (!t[0]) + { + fprintf(stderr, "[Press Enter]"); + fgets(buffer, sizeof(buffer), stdin); + + // We're done + return 0; + } + + fprintf(stderr, "(%s): ", t); + fgets(buffer, sizeof(buffer), stdin); + + // Check if the option is in the list + if (strchr(t, tolower(buffer[0]))) + { + switch (tolower(buffer[0])) + { + case 'y': + lua_pushstring(L, "yes"); + return 1; + case 'n': + lua_pushstring(L, "no"); + return 1; + case 'c': + lua_pushstring(L, "cancel"); + return 1; + default: + luaL_error(L, "internal logic error in console based prompts for gui.popup"); + } + } + + // We fell through, so we assume the user answered wrong and prompt again. + } + + // Nothing here, since the only way out is in the loop. +#endif +} #if (defined(WIN32) && !defined(SDL)) - const char *s_keyToName[256] = - { - NULL, - "leftclick", - "rightclick", - NULL, - "middleclick", - NULL, - NULL, - NULL, - "backspace", - "tab", - NULL, - NULL, - NULL, - "enter", - NULL, - NULL, - "shift", // 0x10 - "control", - "alt", - "pause", - "capslock", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "escape", - NULL, - NULL, - NULL, - NULL, - "space", // 0x20 - "pageup", - "pagedown", - "end", - "home", - "left", - "up", - "right", - "down", - NULL, - NULL, - NULL, - NULL, - "insert", - "delete", - NULL, - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", - NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", - "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", - "U", "V", "W", "X", "Y", "Z", - NULL, - NULL, - NULL, - NULL, - NULL, - "numpad0", "numpad1", "numpad2", "numpad3", "numpad4", "numpad5", "numpad6", "numpad7", "numpad8", "numpad9", - "numpad*", "numpad+", - NULL, - "numpad-", "numpad.", "numpad/", - "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", - "F12", - "F13", "F14", "F15", "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", - "F24", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "numlock", - "scrolllock", - NULL, // 0x92 - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, // 0xB9 - "semicolon", - "plus", - "comma", - "minus", - "period", - "slash", - "tilde", - NULL, // 0xC1 - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, // 0xDA - "leftbracket", - "backslash", - "rightbracket", - "quote", - }; +const char *s_keyToName[256] = + { + NULL, + "leftclick", + "rightclick", + NULL, + "middleclick", + NULL, + NULL, + NULL, + "backspace", + "tab", + NULL, + NULL, + NULL, + "enter", + NULL, + NULL, + "shift", // 0x10 + "control", + "alt", + "pause", + "capslock", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "escape", + NULL, + NULL, + NULL, + NULL, + "space", // 0x20 + "pageup", + "pagedown", + "end", + "home", + "left", + "up", + "right", + "down", + NULL, + NULL, + NULL, + NULL, + "insert", + "delete", + NULL, + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", + "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", + "U", "V", "W", "X", "Y", "Z", + NULL, + NULL, + NULL, + NULL, + NULL, + "numpad0", "numpad1", "numpad2", "numpad3", "numpad4", "numpad5", "numpad6", "numpad7", "numpad8", "numpad9", + "numpad*", "numpad+", + NULL, + "numpad-", "numpad.", "numpad/", + "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", + "F12", + "F13", "F14", "F15", "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", + "F24", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "numlock", + "scrolllock", + NULL, // 0x92 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, // 0xB9 + "semicolon", + "plus", + "comma", + "minus", + "period", + "slash", + "tilde", + NULL, // 0xC1 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, // 0xDA + "leftbracket", + "backslash", + "rightbracket", + "quote", + }; #endif // input.get() @@ -3810,412 +3810,412 @@ // and has the mouse at the bottom-right corner of the game screen, // then this would return {W=true, leftclick=true, xmouse=255, ymouse=223} - static int input_getcurrentinputstatus(lua_State *L) - { - lua_newtable(L); +static int input_getcurrentinputstatus(lua_State *L) +{ + lua_newtable(L); #if (defined(WIN32) && !defined(SDL)) - // keyboard and mouse button status - { - unsigned char keys[256]; - if (true /*!GUI.BackgroundInput*/) // TODO: background input - { - if (GetKeyboardState(keys)) - { - for (int i = 1; i < 255; i++) - { - int mask = (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) ? 0x01 : 0x80; - if (keys[i] & mask) - { - const char *name = s_keyToName[i]; - if (name) - { - lua_pushboolean(L, true); - lua_setfield(L, -2, name); - } - } - } - } - } - else // use a slightly different method that will detect background input: - { - for (int i = 1; i < 255; i++) - { - const char *name = s_keyToName[i]; - if (name) - { - int active; - if (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) - active = GetKeyState(i) & 0x01; - else - active = GetAsyncKeyState(i) & 0x8000; - if (active) - { - lua_pushboolean(L, true); - lua_setfield(L, -2, name); - } - } - } - } - } - - // mouse position in game screen pixel coordinates - { - POINT mouse; - - int xofs = 0, yofs = 0, width = 240, height = 160; - if (!systemIsRunningGBA()) - { - if (gbBorderOn) - width = 256, height = 224, xofs = 48, yofs = 40; - else - width = 160, height = 144; - } - - GetCursorPos(&mouse); - AfxGetApp()->m_pMainWnd->ScreenToClient(&mouse); - - // game screen is always fully stretched to window size, - // with no aspect rate correction, or something like that. - RECT clientRect; - AfxGetApp()->m_pMainWnd->GetClientRect(&clientRect); - - int wndWidth = clientRect.right - clientRect.left; - int wndHeight = clientRect.bottom - clientRect.top; - mouse.x = (LONG) (mouse.x * ((float)width / wndWidth)) - xofs; - mouse.y = (LONG) (mouse.y * ((float)height / wndHeight)) - yofs; - - lua_pushinteger(L, mouse.x); - lua_setfield(L, -2, "xmouse"); - lua_pushinteger(L, mouse.y); - lua_setfield(L, -2, "ymouse"); - } + // keyboard and mouse button status + { + unsigned char keys[256]; + if (true /*!GUI.BackgroundInput*/) // TODO: background input + { + if (GetKeyboardState(keys)) + { + for (int i = 1; i < 255; i++) + { + int mask = (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) ? 0x01 : 0x80; + if (keys[i] & mask) + { + const char *name = s_keyToName[i]; + if (name) + { + lua_pushboolean(L, true); + lua_setfield(L, -2, name); + } + } + } + } + } + else // use a slightly different method that will detect background input: + { + for (int i = 1; i < 255; i++) + { + const char *name = s_keyToName[i]; + if (name) + { + int active; + if (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) + active = GetKeyState(i) & 0x01; + else + active = GetAsyncKeyState(i) & 0x8000; + if (active) + { + lua_pushboolean(L, true); + lua_setfield(L, -2, name); + } + } + } + } + } + + // mouse position in game screen pixel coordinates + { + POINT mouse; + + int xofs = 0, yofs = 0, width = 240, height = 160; + if (!systemIsRunningGBA()) + { + if (gbBorderOn) + width = 256, height = 224, xofs = 48, yofs = 40; + else + width = 160, height = 144; + } + + GetCursorPos(&mouse); + AfxGetApp()->m_pMainWnd->ScreenToClient(&mouse); + + // game screen is always fully stretched to window size, + // with no aspect rate correction, or something like that. + RECT clientRect; + AfxGetApp()->m_pMainWnd->GetClientRect(&clientRect); + + int wndWidth = clientRect.right - clientRect.left; + int wndHeight = clientRect.bottom - clientRect.top; + mouse.x = (LONG) (mouse.x * ((float)width / wndWidth)) - xofs; + mouse.y = (LONG) (mouse.y * ((float)height / wndHeight)) - yofs; + + lua_pushinteger(L, mouse.x); + lua_setfield(L, -2, "xmouse"); + lua_pushinteger(L, mouse.y); + lua_setfield(L, -2, "ymouse"); + } #else - // NYI (well, return an empty table) + // NYI (well, return an empty table) #endif - return 1; - } - - static int avi_framecount(lua_State *L) - { - #ifdef WIN32 - if (theApp.aviRecorder != NULL) - { - lua_pushinteger(L, theApp.aviRecorder->videoFrames()); - } - else - #endif - { - lua_pushinteger(L, 0); - } - return 1; - } - - static int avi_pause(lua_State *L) - { - #ifdef WIN32 - if (theApp.aviRecorder != NULL) - theApp.aviRecorder->Pause(true); - #endif - return 1; - } - - static int avi_resume(lua_State *L) - { - #ifdef WIN32 - if (theApp.aviRecorder != NULL) - theApp.aviRecorder->Pause(false); - #endif - return 1; - } - - static int sound_get(lua_State *L) - { - extern int32 soundLevel1; - extern int32 soundLevel2; - extern int32 soundBalance; - extern int32 soundMasterOn; - extern int32 soundVIN; - extern int32 sound1On; - extern int32 sound1EnvelopeVolume; - extern int32 sound2On; - extern int32 sound2EnvelopeVolume; - extern int32 sound3On; - extern int32 sound3OutputLevel; - extern int32 sound3Bank; - extern int32 sound3DataSize; - extern int32 sound3ForcedOutput; - extern int32 sound4On; - extern int32 sound4EnvelopeVolume; - extern u8 sound3WaveRam[0x20]; - - int freqReg; - double freq; - double leftvolscale; - double rightvolscale; - double panpot; - bool gba = systemIsRunningGBA(); - u8* gbMem = gba ? ioMem : gbMemory; - const int rNR10 = gba ? 0x60 : 0xff10; - const int rNR11 = gba ? 0x62 : 0xff11; - const int rNR12 = gba ? 0x63 : 0xff12; - const int rNR13 = gba ? 0x64 : 0xff13; - const int rNR14 = gba ? 0x65 : 0xff14; - const int rNR21 = gba ? 0x68 : 0xff16; - const int rNR22 = gba ? 0x69 : 0xff17; - const int rNR23 = gba ? 0x6c : 0xff18; - const int rNR24 = gba ? 0x6d : 0xff19; - const int rNR30 = gba ? 0x70 : 0xff1a; - const int rNR31 = gba ? 0x72 : 0xff1b; - const int rNR32 = gba ? 0x73 : 0xff1c; - const int rNR33 = gba ? 0x74 : 0xff1d; - const int rNR34 = gba ? 0x75 : 0xff1e; - const int rNR41 = gba ? 0x78 : 0xff20; - const int rNR42 = gba ? 0x79 : 0xff21; - const int rNR43 = gba ? 0x7c : 0xff22; - const int rNR44 = gba ? 0x7d : 0xff23; - const int rNR50 = gba ? 0x80 : 0xff24; - const int rNR51 = gba ? 0x81 : 0xff25; - const int rNR52 = gba ? 0x84 : 0xff26; - const int rWAVE_RAM = gba ? 0x90 : 0xff30; - - const int32 _soundVIN = 0x88; // gba ? 0x88 : soundVIN; - const bool soundVINLeft = ((_soundVIN & 0x80) != 0); - const bool soundVINRight = ((_soundVIN & 0x08) != 0); - - lua_newtable(L); - - // square1 - lua_newtable(L); - if(sound1On == 0 || soundMasterOn == 0) - { - lua_pushnumber(L, 0.0); - panpot = 0.5; - } - else - { - double envVolume = sound1EnvelopeVolume / 15.0; - if (soundVINLeft && (soundBalance & 0x10) != 0) - leftvolscale = ((soundLevel2 / 7.0) * envVolume); - else - leftvolscale = 0.0; - if (soundVINRight && (soundBalance & 0x01) != 0) - rightvolscale = ((soundLevel1 / 7.0) * envVolume); - else - rightvolscale = 0.0; - if ((leftvolscale + rightvolscale) != 0) - panpot = rightvolscale / (leftvolscale + rightvolscale); - else - panpot = 0.5; - lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); - } - lua_setfield(L, -2, "volume"); - lua_pushnumber(L, panpot); - lua_setfield(L, -2, "panpot"); - freqReg = (((int)(gbMem[rNR14] & 7) << 8) | gbMem[rNR13]); - freq = 131072.0 / (2048 - freqReg); - lua_pushnumber(L, freq); - lua_setfield(L, -2, "frequency"); - lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); - lua_setfield(L, -2, "midikey"); - lua_pushinteger(L, (gbMem[rNR11] & 0xC0) >> 6); - lua_setfield(L, -2, "duty"); - lua_newtable(L); - lua_pushinteger(L, freqReg); - lua_setfield(L, -2, "frequency"); - lua_setfield(L, -2, "regs"); - lua_setfield(L, -2, "square1"); - // square2 - lua_newtable(L); - if(sound2On == 0 || soundMasterOn == 0) - { - lua_pushnumber(L, 0.0); - panpot = 0.5; - } - else - { - double envVolume = sound2EnvelopeVolume / 15.0; - if (soundVINLeft && (soundBalance & 0x20) != 0) - leftvolscale = ((soundLevel2 / 7.0) * envVolume); - else - leftvolscale = 0.0; - if (soundVINRight && (soundBalance & 0x02) != 0) - rightvolscale = ((soundLevel1 / 7.0) * envVolume); - else - rightvolscale = 0.0; - if ((leftvolscale + rightvolscale) != 0) - panpot = rightvolscale / (leftvolscale + rightvolscale); - else - panpot = 0.5; - lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); - } - lua_setfield(L, -2, "volume"); - lua_pushnumber(L, panpot); - lua_setfield(L, -2, "panpot"); - freqReg = (((int)(gbMem[rNR24] & 7) << 8) | gbMem[rNR23]); - freq = 131072.0 / (2048 - freqReg); - lua_pushnumber(L, freq); - lua_setfield(L, -2, "frequency"); - lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); - lua_setfield(L, -2, "midikey"); - lua_pushinteger(L, (gbMem[rNR21] & 0xC0) >> 6); - lua_setfield(L, -2, "duty"); - lua_newtable(L); - lua_pushinteger(L, freqReg); - lua_setfield(L, -2, "frequency"); - lua_setfield(L, -2, "regs"); - lua_setfield(L, -2, "square2"); - // wavememory - lua_newtable(L); - if(sound3On == 0 || soundMasterOn == 0) - { - lua_pushnumber(L, 0.0); - panpot = 0.5; - } - else - { - double envVolume; - if (gba && sound3ForcedOutput != 0) - envVolume = 0.75; - else - { - double volTable[4] = { 0.0, 1.0, 0.5, 0.25 }; - envVolume = volTable[sound3OutputLevel & 3]; - } - - if (soundVINLeft && (soundBalance & 0x40) != 0) - leftvolscale = ((soundLevel2 / 7.0) * envVolume); - else - leftvolscale = 0.0; - if (soundVINRight && (soundBalance & 0x04) != 0) - rightvolscale = ((soundLevel1 / 7.0) * envVolume); - else - rightvolscale = 0.0; - if ((leftvolscale + rightvolscale) != 0) - panpot = rightvolscale / (leftvolscale + rightvolscale); - else - panpot = 0.5; - lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); - } - lua_setfield(L, -2, "volume"); - lua_pushnumber(L, panpot); - lua_setfield(L, -2, "panpot"); - int waveMemSamples = 32; - if (gba) - { - lua_pushlstring(L, (const char *) &sound3WaveRam[sound3Bank * 0x10], sound3DataSize ? 0x20 : 0x10); - waveMemSamples = sound3DataSize ? 64 : 32; - } - else - { - lua_pushlstring(L, (const char *) &gbMem[rWAVE_RAM], 0x10); - } - lua_setfield(L, -2, "waveform"); - freqReg = (((int)(gbMem[rNR34] & 7) << 8) | gbMem[rNR33]); - freq = 2097152.0 / (waveMemSamples * (2048 - freqReg)); - lua_pushnumber(L, freq); - lua_setfield(L, -2, "frequency"); - lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); - lua_setfield(L, -2, "midikey"); - lua_newtable(L); - lua_pushinteger(L, freqReg); - lua_setfield(L, -2, "frequency"); - lua_setfield(L, -2, "regs"); - lua_setfield(L, -2, "wavememory"); - // noise - lua_newtable(L); - if(sound4On == 0 || soundMasterOn == 0) - { - lua_pushnumber(L, 0.0); - panpot = 0.5; - } - else - { - double envVolume = sound4EnvelopeVolume / 15.0; - if (soundVINLeft && (soundBalance & 0x80) != 0) - leftvolscale = ((soundLevel2 / 7.0) * envVolume); - else - leftvolscale = 0.0; - if (soundVINRight && (soundBalance & 0x08) != 0) - rightvolscale = ((soundLevel1 / 7.0) * envVolume); - else - rightvolscale = 0.0; - if ((leftvolscale + rightvolscale) != 0) - panpot = rightvolscale / (leftvolscale + rightvolscale); - else - panpot = 0.5; - lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); - } - lua_setfield(L, -2, "volume"); - lua_pushnumber(L, panpot); - lua_setfield(L, -2, "panpot"); - const int gbNoiseFreqTable[8] = { 1, 2, 4, 6, 8, 10, 12, 14 }; - freqReg = gbNoiseFreqTable[gbMem[rNR43] & 7] << (1 + (gbMem[rNR43] >> 4)); - lua_pushboolean(L, (gbMem[rNR43] & 8) != 0); - lua_setfield(L, -2, "short"); - freq = 1048576.0 / freqReg; - lua_pushnumber(L, freq); - lua_setfield(L, -2, "frequency"); - lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); - lua_setfield(L, -2, "midikey"); - lua_newtable(L); - lua_pushinteger(L, freqReg); - lua_setfield(L, -2, "frequency"); - lua_setfield(L, -2, "regs"); - lua_setfield(L, -2, "noise"); - - return 1; - } + return 1; +} + +static int avi_framecount(lua_State *L) +{ +#ifdef WIN32 + if (theApp.aviRecorder != NULL) + { + lua_pushinteger(L, theApp.aviRecorder->videoFrames()); + } + else +#endif + { + lua_pushinteger(L, 0); + } + return 1; +} + +static int avi_pause(lua_State *L) +{ +#ifdef WIN32 + if (theApp.aviRecorder != NULL) + theApp.aviRecorder->Pause(true); +#endif + return 1; +} + +static int avi_resume(lua_State *L) +{ +#ifdef WIN32 + if (theApp.aviRecorder != NULL) + theApp.aviRecorder->Pause(false); +#endif + return 1; +} + +static int sound_get(lua_State *L) +{ + extern int32 soundLevel1; + extern int32 soundLevel2; + extern int32 soundBalance; + extern int32 soundMasterOn; + extern int32 soundVIN; + extern int32 sound1On; + extern int32 sound1EnvelopeVolume; + extern int32 sound2On; + extern int32 sound2EnvelopeVolume; + extern int32 sound3On; + extern int32 sound3OutputLevel; + extern int32 sound3Bank; + extern int32 sound3DataSize; + extern int32 sound3ForcedOutput; + extern int32 sound4On; + extern int32 sound4EnvelopeVolume; + extern u8 sound3WaveRam[0x20]; + + int freqReg; + double freq; + double leftvolscale; + double rightvolscale; + double panpot; + bool gba = systemIsRunningGBA(); + u8* gbMem = gba ? ioMem : gbMemory; + const int rNR10 = gba ? 0x60 : 0xff10; + const int rNR11 = gba ? 0x62 : 0xff11; + const int rNR12 = gba ? 0x63 : 0xff12; + const int rNR13 = gba ? 0x64 : 0xff13; + const int rNR14 = gba ? 0x65 : 0xff14; + const int rNR21 = gba ? 0x68 : 0xff16; + const int rNR22 = gba ? 0x69 : 0xff17; + const int rNR23 = gba ? 0x6c : 0xff18; + const int rNR24 = gba ? 0x6d : 0xff19; + const int rNR30 = gba ? 0x70 : 0xff1a; + const int rNR31 = gba ? 0x72 : 0xff1b; + const int rNR32 = gba ? 0x73 : 0xff1c; + const int rNR33 = gba ? 0x74 : 0xff1d; + const int rNR34 = gba ? 0x75 : 0xff1e; + const int rNR41 = gba ? 0x78 : 0xff20; + const int rNR42 = gba ? 0x79 : 0xff21; + const int rNR43 = gba ? 0x7c : 0xff22; + const int rNR44 = gba ? 0x7d : 0xff23; + const int rNR50 = gba ? 0x80 : 0xff24; + const int rNR51 = gba ? 0x81 : 0xff25; + const int rNR52 = gba ? 0x84 : 0xff26; + const int rWAVE_RAM = gba ? 0x90 : 0xff30; + + const int32 _soundVIN = 0x88; // gba ? 0x88 : soundVIN; + const bool soundVINLeft = ((_soundVIN & 0x80) != 0); + const bool soundVINRight = ((_soundVIN & 0x08) != 0); + + lua_newtable(L); + + // square1 + lua_newtable(L); + if(sound1On == 0 || soundMasterOn == 0) + { + lua_pushnumber(L, 0.0); + panpot = 0.5; + } + else + { + double envVolume = sound1EnvelopeVolume / 15.0; + if (soundVINLeft && (soundBalance & 0x10) != 0) + leftvolscale = ((soundLevel2 / 7.0) * envVolume); + else + leftvolscale = 0.0; + if (soundVINRight && (soundBalance & 0x01) != 0) + rightvolscale = ((soundLevel1 / 7.0) * envVolume); + else + rightvolscale = 0.0; + if ((leftvolscale + rightvolscale) != 0) + panpot = rightvolscale / (leftvolscale + rightvolscale); + else + panpot = 0.5; + lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); + } + lua_setfield(L, -2, "volume"); + lua_pushnumber(L, panpot); + lua_setfield(L, -2, "panpot"); + freqReg = (((int)(gbMem[rNR14] & 7) << 8) | gbMem[rNR13]); + freq = 131072.0 / (2048 - freqReg); + lua_pushnumber(L, freq); + lua_setfield(L, -2, "frequency"); + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); + lua_setfield(L, -2, "midikey"); + lua_pushinteger(L, (gbMem[rNR11] & 0xC0) >> 6); + lua_setfield(L, -2, "duty"); + lua_newtable(L); + lua_pushinteger(L, freqReg); + lua_setfield(L, -2, "frequency"); + lua_setfield(L, -2, "regs"); + lua_setfield(L, -2, "square1"); + // square2 + lua_newtable(L); + if(sound2On == 0 || soundMasterOn == 0) + { + lua_pushnumber(L, 0.0); + panpot = 0.5; + } + else + { + double envVolume = sound2EnvelopeVolume / 15.0; + if (soundVINLeft && (soundBalance & 0x20) != 0) + leftvolscale = ((soundLevel2 / 7.0) * envVolume); + else + leftvolscale = 0.0; + if (soundVINRight && (soundBalance & 0x02) != 0) + rightvolscale = ((soundLevel1 / 7.0) * envVolume); + else + rightvolscale = 0.0; + if ((leftvolscale + rightvolscale) != 0) + panpot = rightvolscale / (leftvolscale + rightvolscale); + else + panpot = 0.5; + lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); + } + lua_setfield(L, -2, "volume"); + lua_pushnumber(L, panpot); + lua_setfield(L, -2, "panpot"); + freqReg = (((int)(gbMem[rNR24] & 7) << 8) | gbMem[rNR23]); + freq = 131072.0 / (2048 - freqReg); + lua_pushnumber(L, freq); + lua_setfield(L, -2, "frequency"); + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); + lua_setfield(L, -2, "midikey"); + lua_pushinteger(L, (gbMem[rNR21] & 0xC0) >> 6); + lua_setfield(L, -2, "duty"); + lua_newtable(L); + lua_pushinteger(L, freqReg); + lua_setfield(L, -2, "frequency"); + lua_setfield(L, -2, "regs"); + lua_setfield(L, -2, "square2"); + // wavememory + lua_newtable(L); + if(sound3On == 0 || soundMasterOn == 0) + { + lua_pushnumber(L, 0.0); + panpot = 0.5; + } + else + { + double envVolume; + if (gba && sound3ForcedOutput != 0) + envVolume = 0.75; + else + { + double volTable[4] = { 0.0, 1.0, 0.5, 0.25 }; + envVolume = volTable[sound3OutputLevel & 3]; + } + + if (soundVINLeft && (soundBalance & 0x40) != 0) + leftvolscale = ((soundLevel2 / 7.0) * envVolume); + else + leftvolscale = 0.0; + if (soundVINRight && (soundBalance & 0x04) != 0) + rightvolscale = ((soundLevel1 / 7.0) * envVolume); + else + rightvolscale = 0.0; + if ((leftvolscale + rightvolscale) != 0) + panpot = rightvolscale / (leftvolscale + rightvolscale); + else + panpot = 0.5; + lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); + } + lua_setfield(L, -2, "volume"); + lua_pushnumber(L, panpot); + lua_setfield(L, -2, "panpot"); + int waveMemSamples = 32; + if (gba) + { + lua_pushlstring(L, (const char *) &sound3WaveRam[sound3Bank * 0x10], sound3DataSize ? 0x20 : 0x10); + waveMemSamples = sound3DataSize ? 64 : 32; + } + else + { + lua_pushlstring(L, (const char *) &gbMem[rWAVE_RAM], 0x10); + } + lua_setfield(L, -2, "waveform"); + freqReg = (((int)(gbMem[rNR34] & 7) << 8) | gbMem[rNR33]); + freq = 2097152.0 / (waveMemSamples * (2048 - freqReg)); + lua_pushnumber(L, freq); + lua_setfield(L, -2, "frequency"); + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); + lua_setfield(L, -2, "midikey"); + lua_newtable(L); + lua_pushinteger(L, freqReg); + lua_setfield(L, -2, "frequency"); + lua_setfield(L, -2, "regs"); + lua_setfield(L, -2, "wavememory"); + // noise + lua_newtable(L); + if(sound4On == 0 || soundMasterOn == 0) + { + lua_pushnumber(L, 0.0); + panpot = 0.5; + } + else + { + double envVolume = sound4EnvelopeVolume / 15.0; + if (soundVINLeft && (soundBalance & 0x80) != 0) + leftvolscale = ((soundLevel2 / 7.0) * envVolume); + else + leftvolscale = 0.0; + if (soundVINRight && (soundBalance & 0x08) != 0) + rightvolscale = ((soundLevel1 / 7.0) * envVolume); + else + rightvolscale = 0.0; + if ((leftvolscale + rightvolscale) != 0) + panpot = rightvolscale / (leftvolscale + rightvolscale); + else + panpot = 0.5; + lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); + } + lua_setfield(L, -2, "volume"); + lua_pushnumber(L, panpot); + lua_setfield(L, -2, "panpot"); + const int gbNoiseFreqTable[8] = { 1, 2, 4, 6, 8, 10, 12, 14 }; + freqReg = gbNoiseFreqTable[gbMem[rNR43] & 7] << (1 + (gbMem[rNR43] >> 4)); + lua_pushboolean(L, (gbMem[rNR43] & 8) != 0); + lua_setfield(L, -2, "short"); + freq = 1048576.0 / freqReg; + lua_pushnumber(L, freq); + lua_setfield(L, -2, "frequency"); + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); + lua_setfield(L, -2, "midikey"); + lua_newtable(L); + lua_pushinteger(L, freqReg); + lua_setfield(L, -2, "frequency"); + lua_setfield(L, -2, "regs"); + lua_setfield(L, -2, "noise"); + + return 1; +} // same as math.random, but uses SFMT instead of C rand() // FIXME: this function doesn't care multi-instance, // original math.random either though (Lua 5.1) - static int sfmt_random(lua_State *L) - { - lua_Number r = (lua_Number) genrand_real2(); - switch (lua_gettop(L)) - { // check number of arguments - case 0: - { // no arguments - lua_pushnumber(L, r); // Number between 0 and 1 - break; - } - - case 1: - { // only upper limit - int u = luaL_checkint(L, 1); - luaL_argcheck(L, 1 <= u, 1, "interval is empty"); - lua_pushnumber(L, floor(r * u) + 1); // int between 1 and `u' - break; - } - - case 2: - { // lower and upper limits - int l = luaL_checkint(L, 1); - int u = luaL_checkint(L, 2); - luaL_argcheck(L, l <= u, 2, "interval is empty"); - lua_pushnumber(L, floor(r * (u - l + 1)) + l); // int between `l' and `u' - break; - } - - default: - return luaL_error(L, "wrong number of arguments"); - } - - return 1; - } +static int sfmt_random(lua_State *L) +{ + lua_Number r = (lua_Number) genrand_real2(); + switch (lua_gettop(L)) + { // check number of arguments + case 0: + { // no arguments + lua_pushnumber(L, r); // Number between 0 and 1 + break; + } + + case 1: + { // only upper limit + int u = luaL_checkint(L, 1); + luaL_argcheck(L, 1 <= u, 1, "interval is empty"); + lua_pushnumber(L, floor(r * u) + 1); // int between 1 and `u' + break; + } + + case 2: + { // lower and upper limits + int l = luaL_checkint(L, 1); + int u = luaL_checkint(L, 2); + luaL_argcheck(L, l <= u, 2, "interval is empty"); + lua_pushnumber(L, floor(r * (u - l + 1)) + l); // int between `l' and `u' + break; + } + + default: + return luaL_error(L, "wrong number of arguments"); + } + + return 1; +} // same as math.randomseed, but uses SFMT instead of C srand() // FIXME: this function doesn't care multi-instance, // original math.randomseed either though (Lua 5.1) - static int sfmt_randomseed(lua_State *L) - { - init_gen_rand(luaL_checkint(L, 1)); - return 0; - } +static int sfmt_randomseed(lua_State *L) +{ + init_gen_rand(luaL_checkint(L, 1)); + return 0; +} // the following bit operations are ported from LuaBitOp 1.0.1, // because it can handle the sign bit (bit 31) correctly. @@ -4250,123 +4250,123 @@ #ifdef _MSC_VER /* MSVC is stuck in the last century and doesn't have C99's stdint.h. */ - typedef __int32 int32_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int64 uint64_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; #else #include #endif - typedef int32_t SBits; - typedef uint32_t UBits; - - typedef union - { - lua_Number n; +typedef int32_t SBits; +typedef uint32_t UBits; + +typedef union +{ + lua_Number n; #ifdef LUA_NUMBER_DOUBLE - uint64_t b; + uint64_t b; #else - UBits b; + UBits b; #endif - } BitNum; +} BitNum; /* Convert argument to bit type. */ - static UBits barg(lua_State *L, int idx) - { - BitNum bn; - UBits b; - bn.n = lua_tonumber(L, idx); +static UBits barg(lua_State *L, int idx) +{ + BitNum bn; + UBits b; + bn.n = lua_tonumber(L, idx); #if defined(LUA_NUMBER_DOUBLE) - bn.n += 6755399441055744.0; /* 2^52+2^51 */ + bn.n += 6755399441055744.0; /* 2^52+2^51 */ #ifdef SWAPPED_DOUBLE - b = (UBits)(bn.b >> 32); + b = (UBits)(bn.b >> 32); #else - b = (UBits)(bn.b & 0xffffffff); + b = (UBits)(bn.b & 0xffffffff); #endif -#elif defined(LUA_NUMBER_INT) || defined(LUA_NUMBER_LONG) || \ - defined(LUA_NUMBER_LONGLONG) || defined(LUA_NUMBER_LONG_LONG) || \ - defined(LUA_NUMBER_LLONG) - if (sizeof(UBits) == sizeof(lua_Number)) - b = bn.b; - else - b = (UBits)(SBits)bn.n; +#elif defined(LUA_NUMBER_INT) || defined(LUA_NUMBER_LONG) || \ + defined(LUA_NUMBER_LONGLONG) || defined(LUA_NUMBER_LONG_LONG) || \ + defined(LUA_NUMBER_LLONG) + if (sizeof(UBits) == sizeof(lua_Number)) + b = bn.b; + else + b = (UBits)(SBits)bn.n; #elif defined(LUA_NUMBER_FLOAT) #error "A 'float' lua_Number type is incompatible with this library" #else #error "Unknown number type, check LUA_NUMBER_* in luaconf.h" #endif - if (b == 0 && !lua_isnumber(L, idx)) - luaL_typerror(L, idx, "number"); - return b; - } + if (b == 0 && !lua_isnumber(L, idx)) + luaL_typerror(L, idx, "number"); + return b; +} /* Return bit type. */ #define BRET(b) lua_pushnumber(L, (lua_Number)(SBits)(b)); return 1; - static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) } - static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) } - -#define BIT_OP(func, opr) \ - static int func(lua_State * L) { int i; UBits b = barg(L, 1); \ - for (i = lua_gettop(L); i > 1; i--) \ - b opr barg(L, i); BRET(b) } - BIT_OP(bit_band, &= ) - BIT_OP(bit_bor, |= ) - BIT_OP(bit_bxor, ^= ) +static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) } +static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) } + +#define BIT_OP(func, opr) \ + static int func(lua_State * L) { int i; UBits b = barg(L, 1); \ + for (i = lua_gettop(L); i > 1; i--) \ + b opr barg(L, i); BRET(b) } +BIT_OP(bit_band, &= ) +BIT_OP(bit_bor, |= ) +BIT_OP(bit_bxor, ^= ) #define bshl(b, n) (b << n) #define bshr(b, n) (b >> n) #define bsar(b, n) ((SBits)b >> n) #define brol(b, n) ((b << n) | (b >> (32 - n))) #define bror(b, n) ((b << (32 - n)) | (b >> n)) -#define BIT_SH(func, fn) \ - static int func(lua_State * L) { \ - UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) } - BIT_SH(bit_lshift, bshl) - BIT_SH(bit_rshift, bshr) - BIT_SH(bit_arshift, bsar) - BIT_SH(bit_rol, brol) - BIT_SH(bit_ror, bror) - - static int bit_bswap(lua_State *L) - { - UBits b = barg(L, 1); - b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24); - BRET(b) - } - - static int bit_tohex(lua_State *L) - { - UBits b = barg(L, 1); - SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2); - const char *hexdigits = "0123456789abcdef"; - char buf[8]; - int i; - if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; } - if (n > 8) n = 8; - for (i = (int)n; --i >= 0; ) - { - buf[i] = hexdigits[b & 15]; b >>= 4; - } - lua_pushlstring(L, buf, (size_t)n); - return 1; - } - - static const struct luaL_Reg bit_funcs[] = { - { "tobit", bit_tobit }, - { "bnot", bit_bnot }, - { "band", bit_band }, - { "bor", bit_bor }, - { "bxor", bit_bxor }, - { "lshift", bit_lshift }, - { "rshift", bit_rshift }, - { "arshift", bit_arshift }, - { "rol", bit_rol }, - { "ror", bit_ror }, - { "bswap", bit_bswap }, - { "tohex", bit_tohex }, - { NULL, NULL } - }; +#define BIT_SH(func, fn) \ + static int func(lua_State * L) { \ + UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) } +BIT_SH(bit_lshift, bshl) +BIT_SH(bit_rshift, bshr) +BIT_SH(bit_arshift, bsar) +BIT_SH(bit_rol, brol) +BIT_SH(bit_ror, bror) + +static int bit_bswap(lua_State *L) +{ + UBits b = barg(L, 1); + b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24); + BRET(b) + } + +static int bit_tohex(lua_State *L) +{ + UBits b = barg(L, 1); + SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2); + const char *hexdigits = "0123456789abcdef"; + char buf[8]; + int i; + if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; } + if (n > 8) n = 8; + for (i = (int)n; --i >= 0; ) + { + buf[i] = hexdigits[b & 15]; b >>= 4; + } + lua_pushlstring(L, buf, (size_t)n); + return 1; +} + +static const struct luaL_Reg bit_funcs[] = { + { "tobit", bit_tobit }, + { "bnot", bit_bnot }, + { "band", bit_band }, + { "bor", bit_bor }, + { "bxor", bit_bxor }, + { "lshift", bit_lshift }, + { "rshift", bit_rshift }, + { "arshift", bit_arshift }, + { "rol", bit_rol }, + { "ror", bit_ror }, + { "bswap", bit_bswap }, + { "tohex", bit_tohex }, + { NULL, NULL } +}; /* Signed right-shifts are implementation-defined per C89/C99. ** But the de facto standard are arithmetic right-shifts on two's @@ -4374,364 +4374,364 @@ */ #define BAD_SAR (bsar(-8, 2) != (SBits) - 2) - bool luabitop_validate(lua_State *L) // originally named as luaopen_bit - { - UBits b; - lua_pushnumber(L, (lua_Number)1437217655L); - b = barg(L, -1); - if (b != (UBits)1437217655L || BAD_SAR) /* Perform a simple self-test. */ - { - const char *msg = "compiled with incompatible luaconf.h"; +bool luabitop_validate(lua_State *L) // originally named as luaopen_bit +{ + UBits b; + lua_pushnumber(L, (lua_Number)1437217655L); + b = barg(L, -1); + if (b != (UBits)1437217655L || BAD_SAR) /* Perform a simple self-test. */ + { + const char *msg = "compiled with incompatible luaconf.h"; #ifdef LUA_NUMBER_DOUBLE #ifdef WIN32 - if (b == (UBits)1610612736L) - msg = "use D3DCREATE_FPU_PRESERVE with DirectX"; + if (b == (UBits)1610612736L) + msg = "use D3DCREATE_FPU_PRESERVE with DirectX"; #endif - if (b == (UBits)1127743488L) - msg = "not compiled with SWAPPED_DOUBLE"; + if (b == (UBits)1127743488L) + msg = "not compiled with SWAPPED_DOUBLE"; #endif - if (BAD_SAR) - msg = "arithmetic right-shift broken"; - luaL_error(L, "bit library self-test failed (%s)", msg); - return false; - } - return true; - } + if (BAD_SAR) + msg = "arithmetic right-shift broken"; + luaL_error(L, "bit library self-test failed (%s)", msg); + return false; + } + return true; +} // LuaBitOp ends here - static int bit_bshift_emulua(lua_State *L) - { - int shift = luaL_checkinteger(L, 2); - if (shift < 0) - { - lua_pushinteger(L, -shift); - lua_replace(L, 2); - return bit_lshift(L); - } - else - return bit_rshift(L); - } - - static int bitbit(lua_State *L) - { - int rv = 0; - int numArgs = lua_gettop(L); - for (int i = 1; i <= numArgs; i++) - { - int where = luaL_checkinteger(L, i); - if (where >= 0 && where < 32) - rv |= (1 << where); - } - lua_settop(L, 0); - BRET(rv); - } +static int bit_bshift_emulua(lua_State *L) +{ + int shift = luaL_checkinteger(L, 2); + if (shift < 0) + { + lua_pushinteger(L, -shift); + lua_replace(L, 2); + return bit_lshift(L); + } + else + return bit_rshift(L); +} + +static int bitbit(lua_State *L) +{ + int rv = 0; + int numArgs = lua_gettop(L); + for (int i = 1; i <= numArgs; i++) + { + int where = luaL_checkinteger(L, i); + if (where >= 0 && where < 32) + rv |= (1 << where); + } + lua_settop(L, 0); + BRET(rv); +} // The function called periodically to ensure Lua doesn't run amok. - static void VBALuaHookFunction(lua_State *L, lua_Debug *dbg) - { - if (numTries-- == 0) - { - int kill = 0; +static void VBALuaHookFunction(lua_State *L, lua_Debug *dbg) +{ + if (numTries-- == 0) + { + int kill = 0; #if (defined(WIN32) && !defined(SDL)) - // Uh oh - theApp.winCheckFullscreen(); - systemSoundClearBuffer(); - int ret = AfxGetApp()->m_pMainWnd->MessageBox( - "The Lua script running has been running a long time. It may have gone crazy. Kill it?\n\n(No = don't check anymore either)", - "Lua Script Gone Nuts?", - MB_YESNO); - - if (ret == IDYES) - { - kill = 1; - } + // Uh oh + theApp.winCheckFullscreen(); + systemSoundClearBuffer(); + int ret = AfxGetApp()->m_pMainWnd->MessageBox( + "The Lua script running has been running a long time. It may have gone crazy. Kill it?\n\n(No = don't check anymore either)", + "Lua Script Gone Nuts?", + MB_YESNO); + + if (ret == IDYES) + { + kill = 1; + } #else - fprintf( - stderr, - "The Lua script running has been running a long time.\nIt may have gone crazy. Kill it? (I won't ask again if you say No)\n"); - - char buffer[64]; - while (true) - { - fprintf(stderr, "(y/n): "); - fgets(buffer, sizeof(buffer), stdin); - if (buffer[0] == 'y' || buffer[0] == 'Y') - { - kill = 1; - break; - } - - if (buffer[0] == 'n' || buffer[0] == 'N') - break; - } + fprintf( + stderr, + "The Lua script running has been running a long time.\nIt may have gone crazy. Kill it? (I won't ask again if you say No)\n"); + + char buffer[64]; + while (true) + { + fprintf(stderr, "(y/n): "); + fgets(buffer, sizeof(buffer), stdin); + if (buffer[0] == 'y' || buffer[0] == 'Y') + { + kill = 1; + break; + } + + if (buffer[0] == 'n' || buffer[0] == 'N') + break; + } #endif - if (kill) - { - luaL_error(L, "Killed by user request."); - VBALuaOnStop(); - } - - // else, kill the debug hook. - lua_sethook(L, NULL, 0, 0); - } - } - - static const struct luaL_reg vbalib[] = { - // {"speedmode", vba_speedmode}, // TODO: NYI - { "frameadvance", vba_frameadvance }, - { "pause", vba_pause }, - { "framecount", vba_framecount }, - { "lagcount", vba_getlagcount }, - { "lagged", vba_lagged }, - { "emulating", vba_emulating }, - { "registerbefore", vba_registerbefore }, - { "registerafter", vba_registerafter }, - { "registerexit", vba_registerexit }, - { "message", vba_message }, - { "print", print }, // sure, why not - { NULL, NULL } - }; - - static const struct luaL_reg memorylib[] = { - { "readbyte", memory_readbyte }, - { "readbytesigned", memory_readbytesigned }, - { "readword", memory_readword }, - { "readwordsigned", memory_readwordsigned }, - { "readdword", memory_readdword }, - { "readdwordsigned", memory_readdwordsigned }, - { "readbyterange", memory_readbyterange }, - { "writebyte", memory_writebyte }, - { "writeword", memory_writeword }, - { "writedword", memory_writedword }, - { "getregister", memory_getregister }, - { "setregister", memory_setregister }, - { "gbromreadbyte", memory_gbromreadbyte }, - { "gbromreadbytesigned", memory_gbromreadbytesigned }, - { "gbromreadword", memory_gbromreadword }, - { "gbromreadwordsigned", memory_gbromreadwordsigned }, - { "gbromreaddword", memory_gbromreaddword }, - { "gbromreaddwordsigned", memory_gbromreaddwordsigned }, - { "gbromreadbyterange", memory_gbromreadbyterange }, - - // alternate naming scheme for word and double-word and unsigned - { "readbyteunsigned", memory_readbyte }, - { "readwordunsigned", memory_readword }, - { "readdwordunsigned", memory_readdword }, - { "readshort", memory_readword }, - { "readshortunsigned", memory_readword }, - { "readshortsigned", memory_readwordsigned }, - { "readlong", memory_readdword }, - { "readlongunsigned", memory_readdword }, - { "readlongsigned", memory_readdwordsigned }, - { "writeshort", memory_writeword }, - { "writelong", memory_writedword }, - { "gbromreadbyteunsigned", memory_gbromreadbyte }, - { "gbromreadwordunsigned", memory_gbromreadword }, - { "gbromreaddwordunsigned", memory_gbromreaddword }, - { "gbromreadshort", memory_gbromreadword }, - { "gbromreadshortunsigned", memory_gbromreadword }, - { "gbromreadshortsigned", memory_gbromreadwordsigned }, - { "gbromreadlong", memory_gbromreaddword }, - { "gbromreadlongunsigned", memory_gbromreaddword }, - { "gbromreadlongsigned", memory_gbromreaddwordsigned }, - - // memory hooks - { "registerwrite", memory_registerwrite }, - //{"registerread", memory_registerread}, - { "registerexec", memory_registerexec }, - // alternate names - { "register", memory_registerwrite }, - { "registerrun", memory_registerexec }, - { "registerexecute", memory_registerexec }, - - { NULL, NULL } - }; - - static const struct luaL_reg joypadlib[] = { - { "get", joypad_get }, - { "getdown", joypad_getdown }, - { "getup", joypad_getup }, - { "set", joypad_set }, - - // alternative names - { "read", joypad_get }, - { "write", joypad_set }, - { "readdown", joypad_getdown }, - { "readup", joypad_getup }, - { NULL, NULL } - }; - - static const struct luaL_reg savestatelib[] = { - { "create", savestate_create }, - { "save", savestate_save }, - { "load", savestate_load }, - - { NULL, NULL } - }; - - static const struct luaL_reg movielib[] = { - { "active", movie_isactive }, - { "recording", movie_isrecording }, - { "playing", movie_isplaying }, - { "mode", movie_getmode }, - - { "length", movie_getlength }, - { "author", movie_getauthor }, - { "name", movie_getfilename }, - { "rerecordcount", movie_rerecordcount }, - { "setrerecordcount", movie_setrerecordcount }, - - { "rerecordcounting", movie_rerecordcounting }, - { "framecount", vba_framecount }, // for those familiar with - // other emulators that have - // movie.framecount() - // instead of - // emulatorname.framecount() - - { "stop", movie_stop }, - - // alternative names - { "close", movie_stop }, - { "getauthor", movie_getauthor }, - { "getname", movie_getfilename }, - { NULL, NULL } - }; - - static const struct luaL_reg guilib[] = { - { "register", gui_register }, - { "text", gui_text }, - { "box", gui_drawbox }, - { "line", gui_drawline }, - { "pixel", gui_drawpixel }, - { "opacity", gui_setopacity }, - { "transparency", gui_transparency }, - { "popup", gui_popup }, - { "parsecolor", gui_parsecolor }, - { "gdscreenshot", gui_gdscreenshot }, - { "gdoverlay", gui_gdoverlay }, - { "getpixel", gui_getpixel }, - - // alternative names - { "drawtext", gui_text }, - { "drawbox", gui_drawbox }, - { "drawline", gui_drawline }, - { "drawpixel", gui_drawpixel }, - { "setpixel", gui_drawpixel }, - { "writepixel", gui_drawpixel }, - { "rect", gui_drawbox }, - { "drawrect", gui_drawbox }, - { "drawimage", gui_gdoverlay }, - { "image", gui_gdoverlay }, - { "readpixel", gui_getpixel }, - { NULL, NULL } - }; - - static const struct luaL_reg inputlib[] = { - { "get", input_getcurrentinputstatus }, - - // alternative names - { "read", input_getcurrentinputstatus }, - { NULL, NULL } - }; - - static const struct luaL_reg soundlib[] = { - { "get", sound_get }, - - // alternative names - { NULL, NULL } - }; + if (kill) + { + luaL_error(L, "Killed by user request."); + VBALuaOnStop(); + } + + // else, kill the debug hook. + lua_sethook(L, NULL, 0, 0); + } +} + +static const struct luaL_reg vbalib[] = { + // {"speedmode", vba_speedmode}, // TODO: NYI + { "frameadvance", vba_frameadvance }, + { "pause", vba_pause }, + { "framecount", vba_framecount }, + { "lagcount", vba_getlagcount }, + { "lagged", vba_lagged }, + { "emulating", vba_emulating }, + { "registerbefore", vba_registerbefore }, + { "registerafter", vba_registerafter }, + { "registerexit", vba_registerexit }, + { "message", vba_message }, + { "print", print }, // sure, why not + { NULL, NULL } +}; + +static const struct luaL_reg memorylib[] = { + { "readbyte", memory_readbyte }, + { "readbytesigned", memory_readbytesigned }, + { "readword", memory_readword }, + { "readwordsigned", memory_readwordsigned }, + { "readdword", memory_readdword }, + { "readdwordsigned", memory_readdwordsigned }, + { "readbyterange", memory_readbyterange }, + { "writebyte", memory_writebyte }, + { "writeword", memory_writeword }, + { "writedword", memory_writedword }, + { "getregister", memory_getregister }, + { "setregister", memory_setregister }, + { "gbromreadbyte", memory_gbromreadbyte }, + { "gbromreadbytesigned", memory_gbromreadbytesigned }, + { "gbromreadword", memory_gbromreadword }, + { "gbromreadwordsigned", memory_gbromreadwordsigned }, + { "gbromreaddword", memory_gbromreaddword }, + { "gbromreaddwordsigned", memory_gbromreaddwordsigned }, + { "gbromreadbyterange", memory_gbromreadbyterange }, + + // alternate naming scheme for word and double-word and unsigned + { "readbyteunsigned", memory_readbyte }, + { "readwordunsigned", memory_readword }, + { "readdwordunsigned", memory_readdword }, + { "readshort", memory_readword }, + { "readshortunsigned", memory_readword }, + { "readshortsigned", memory_readwordsigned }, + { "readlong", memory_readdword }, + { "readlongunsigned", memory_readdword }, + { "readlongsigned", memory_readdwordsigned }, + { "writeshort", memory_writeword }, + { "writelong", memory_writedword }, + { "gbromreadbyteunsigned", memory_gbromreadbyte }, + { "gbromreadwordunsigned", memory_gbromreadword }, + { "gbromreaddwordunsigned", memory_gbromreaddword }, + { "gbromreadshort", memory_gbromreadword }, + { "gbromreadshortunsigned", memory_gbromreadword }, + { "gbromreadshortsigned", memory_gbromreadwordsigned }, + { "gbromreadlong", memory_gbromreaddword }, + { "gbromreadlongunsigned", memory_gbromreaddword }, + { "gbromreadlongsigned", memory_gbromreaddwordsigned }, + + // memory hooks + { "registerwrite", memory_registerwrite }, + //{"registerread", memory_registerread}, + { "registerexec", memory_registerexec }, + // alternate names + { "register", memory_registerwrite }, + { "registerrun", memory_registerexec }, + { "registerexecute", memory_registerexec }, + + { NULL, NULL } +}; + +static const struct luaL_reg joypadlib[] = { + { "get", joypad_get }, + { "getdown", joypad_getdown }, + { "getup", joypad_getup }, + { "set", joypad_set }, + + // alternative names + { "read", joypad_get }, + { "write", joypad_set }, + { "readdown", joypad_getdown }, + { "readup", joypad_getup }, + { NULL, NULL } +}; + +static const struct luaL_reg savestatelib[] = { + { "create", savestate_create }, + { "save", savestate_save }, + { "load", savestate_load }, + + { NULL, NULL } +}; + +static const struct luaL_reg movielib[] = { + { "active", movie_isactive }, + { "recording", movie_isrecording }, + { "playing", movie_isplaying }, + { "mode", movie_getmode }, + + { "length", movie_getlength }, + { "author", movie_getauthor }, + { "name", movie_getfilename }, + { "rerecordcount", movie_rerecordcount }, + { "setrerecordcount", movie_setrerecordcount }, + + { "rerecordcounting", movie_rerecordcounting }, + { "framecount", vba_framecount }, // for those familiar with + // other emulators that have + // movie.framecount() + // instead of + // emulatorname.framecount() + + { "stop", movie_stop }, + + // alternative names + { "close", movie_stop }, + { "getauthor", movie_getauthor }, + { "getname", movie_getfilename }, + { NULL, NULL } +}; + +static const struct luaL_reg guilib[] = { + { "register", gui_register }, + { "text", gui_text }, + { "box", gui_drawbox }, + { "line", gui_drawline }, + { "pixel", gui_drawpixel }, + { "opacity", gui_setopacity }, + { "transparency", gui_transparency }, + { "popup", gui_popup }, + { "parsecolor", gui_parsecolor }, + { "gdscreenshot", gui_gdscreenshot }, + { "gdoverlay", gui_gdoverlay }, + { "getpixel", gui_getpixel }, + + // alternative names + { "drawtext", gui_text }, + { "drawbox", gui_drawbox }, + { "drawline", gui_drawline }, + { "drawpixel", gui_drawpixel }, + { "setpixel", gui_drawpixel }, + { "writepixel", gui_drawpixel }, + { "rect", gui_drawbox }, + { "drawrect", gui_drawbox }, + { "drawimage", gui_gdoverlay }, + { "image", gui_gdoverlay }, + { "readpixel", gui_getpixel }, + { NULL, NULL } +}; + +static const struct luaL_reg inputlib[] = { + { "get", input_getcurrentinputstatus }, + + // alternative names + { "read", input_getcurrentinputstatus }, + { NULL, NULL } +}; + +static const struct luaL_reg soundlib[] = { + { "get", sound_get }, + + // alternative names + { NULL, NULL } +}; // gocha: since vba dumps avi so badly, // I add avilib as a workaround for enhanced video encoding. - static const struct luaL_reg avilib[] = { - { "framecount", avi_framecount }, - { "pause", avi_pause }, - { "resume", avi_resume }, - { NULL, NULL } - }; - - void CallExitFunction(void) - { - if (!LUA) - return; - - lua_settop(LUA, 0); - lua_getfield(LUA, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); - - int errorcode = 0; - if (lua_isfunction(LUA, -1)) - { - errorcode = lua_pcall(LUA, 0, 0, 0); - } - - if (errorcode) - HandleCallbackError(LUA); - } - - void VBALuaFrameBoundary(void) - { - // printf("Lua Frame\n"); - - lua_joypads_used = 0; - - // HA! - if (!LUA || !luaRunning) - return; - - // Our function needs calling - lua_settop(LUA, 0); - lua_getfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread); - - lua_State *thread = lua_tothread(LUA, 1); - - // Lua calling C must know that we're busy inside a frame boundary - frameBoundary = true; - frameAdvanceWaiting = false; - - numTries = 1000; - - int result = lua_resume(thread, 0); - - if (result == LUA_YIELD) - { - // Okay, we're fine with that. - } - else if (result != 0) - { - // Done execution by bad causes - VBALuaOnStop(); - lua_pushnil(LUA); - lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread); - lua_pushnil(LUA); - lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); - - // Error? -//#if (defined(WIN32) && !defined(SDL)) -// info_print(info_uid, lua_tostring(thread, -1)); //Clear_Sound_Buffer(); -// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(thread, -1), "Lua run error", MB_OK | MB_ICONSTOP); -//#else -// fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(thread, -1)); -//#endif - printerror(thread, -1); - } - else - { - VBALuaOnStop(); - printf("Script died of natural causes.\n"); - } - - // Past here, VBA actually runs, so any Lua code is called mid-frame. We must - // not do anything too stupid, so let ourselves know. - frameBoundary = false; - - if (!frameAdvanceWaiting) - { - VBALuaOnStop(); - } - } +static const struct luaL_reg avilib[] = { + { "framecount", avi_framecount }, + { "pause", avi_pause }, + { "resume", avi_resume }, + { NULL, NULL } +}; + +void CallExitFunction(void) +{ + if (!LUA) + return; + + lua_settop(LUA, 0); + lua_getfield(LUA, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); + + int errorcode = 0; + if (lua_isfunction(LUA, -1)) + { + errorcode = lua_pcall(LUA, 0, 0, 0); + } + + if (errorcode) + HandleCallbackError(LUA); +} + +void VBALuaFrameBoundary(void) +{ + // printf("Lua Frame\n"); + + lua_joypads_used = 0; + + // HA! + if (!LUA || !luaRunning) + return; + + // Our function needs calling + lua_settop(LUA, 0); + lua_getfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread); + + lua_State *thread = lua_tothread(LUA, 1); + + // Lua calling C must know that we're busy inside a frame boundary + frameBoundary = true; + frameAdvanceWaiting = false; + + numTries = 1000; + + int result = lua_resume(thread, 0); + + if (result == LUA_YIELD) + { + // Okay, we're fine with that. + } + else if (result != 0) + { + // Done execution by bad causes + VBALuaOnStop(); + lua_pushnil(LUA); + lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread); + lua_pushnil(LUA); + lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); + + // Error? + //#if (defined(WIN32) && !defined(SDL)) + // info_print(info_uid, lua_tostring(thread, -1)); //Clear_Sound_Buffer(); + // AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(thread, -1), "Lua run error", MB_OK | MB_ICONSTOP); + //#else + // fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(thread, -1)); + //#endif + printerror(thread, -1); + } + else + { + VBALuaOnStop(); + printf("Script died of natural causes.\n"); + } + + // Past here, VBA actually runs, so any Lua code is called mid-frame. We must + // not do anything too stupid, so let ourselves know. + frameBoundary = false; + + if (!frameAdvanceWaiting) + { + VBALuaOnStop(); + } +} /** * Loads and runs the given Lua script. @@ -4740,165 +4740,165 @@ * * Returns true on success, false on failure. */ - int VBALoadLuaCode(const char *filename) - { - static bool sfmtInitialized = false; - if (!sfmtInitialized) - { - init_gen_rand((unsigned)time(NULL)); - sfmtInitialized = true; - } - - if (filename != luaScriptName) - { - if (luaScriptName) - free(luaScriptName); - luaScriptName = strdup(filename); - } - - //stop any lua we might already have had running - VBALuaStop(); - - // Set current directory from filename (for dofile) - char dir[_MAX_PATH]; - char *slash, *backslash; - strcpy(dir, filename); - slash = strrchr(dir, '/'); - backslash = strrchr(dir, '\\'); - if (!slash || (backslash && backslash < slash)) - slash = backslash; - if (slash) - { - slash[1] = '\0'; // keep slash itself for some reasons - chdir(dir); - } - - if (!LUA) - { - LUA = lua_open(); - luaL_openlibs(LUA); - - luaL_register(LUA, "emu", vbalib); // added for better cross-emulator compatibility - luaL_register(LUA, "vba", vbalib); // kept for backward compatibility - luaL_register(LUA, "memory", memorylib); - luaL_register(LUA, "joypad", joypadlib); - luaL_register(LUA, "savestate", savestatelib); - luaL_register(LUA, "movie", movielib); - luaL_register(LUA, "gui", guilib); - luaL_register(LUA, "input", inputlib); - luaL_register(LUA, "sound", soundlib); - luaL_register(LUA, "bit", bit_funcs); // LuaBitOp library - luaL_register(LUA, "avi", avilib); // workaround for enhanced video encoding - lua_settop(LUA, 0); // clean the stack, because each call to luaL_register leaves a table on top - - // register a few utility functions outside of libraries (in the global namespace) - lua_register(LUA, "print", print); - lua_register(LUA, "tostring", tostring); - lua_register(LUA, "addressof", addressof); - lua_register(LUA, "copytable", copytable); - - // old bit operation functions - lua_register(LUA, "AND", bit_band); - lua_register(LUA, "OR", bit_bor); - lua_register(LUA, "XOR", bit_bxor); - lua_register(LUA, "SHIFT", bit_bshift_emulua); - lua_register(LUA, "BIT", bitbit); - - luabitop_validate(LUA); - - lua_pushstring(LUA, "math"); - lua_gettable(LUA, LUA_GLOBALSINDEX); - lua_pushcfunction(LUA, sfmt_random); - lua_setfield(LUA, -2, "random"); - lua_pushcfunction(LUA, sfmt_randomseed); - lua_setfield(LUA, -2, "randomseed"); - lua_settop(LUA, 0); - - // push arrays for storing hook functions in - for (int i = 0; i < LUAMEMHOOK_COUNT; i++) - { - lua_newtable(LUA); - lua_setfield(LUA, LUA_REGISTRYINDEX, luaMemHookTypeStrings[i]); - } - } - - // We make our thread NOW because we want it at the bottom of the stack. - // If all goes wrong, we let the garbage collector remove it. - lua_State *thread = lua_newthread(LUA); - - // Load the data - int result = luaL_loadfile(LUA, filename); - - if (result) - { -//#if (defined(WIN32) && !defined(SDL)) -// info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer(); -// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua load error", MB_OK | MB_ICONSTOP); -//#else -// fprintf(stderr, "Failed to compile file: %s\n", lua_tostring(LUA, -1)); -//#endif - printerror(LUA, -1); - - // Wipe the stack. Our thread - lua_settop(LUA, 0); - return 0; // Oh shit. - } - - // Get our function into it - lua_xmove(LUA, thread, 1); - - // Save the thread to the registry. This is why I make the thread FIRST. - lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread); - - // Initialize settings - luaRunning = true; - skipRerecords = false; - numMemHooks = 0; - transparencyModifier = 255; // opaque - lua_joypads_used = 0; // not used - //wasPaused = systemIsPaused(); - //systemSetPause(false); - - // Set up our protection hook to be executed once every 10,000 bytecode instructions. - lua_sethook(thread, VBALuaHookFunction, LUA_MASKCOUNT, 10000); +int VBALoadLuaCode(const char *filename) +{ + static bool sfmtInitialized = false; + if (!sfmtInitialized) + { + init_gen_rand((unsigned)time(NULL)); + sfmtInitialized = true; + } + + if (filename != luaScriptName) + { + if (luaScriptName) + free(luaScriptName); + luaScriptName = strdup(filename); + } + + //stop any lua we might already have had running + VBALuaStop(); + + // Set current directory from filename (for dofile) + char dir[_MAX_PATH]; + char *slash, *backslash; + strcpy(dir, filename); + slash = strrchr(dir, '/'); + backslash = strrchr(dir, '\\'); + if (!slash || (backslash && backslash < slash)) + slash = backslash; + if (slash) + { + slash[1] = '\0'; // keep slash itself for some reasons + chdir(dir); + } + + if (!LUA) + { + LUA = lua_open(); + luaL_openlibs(LUA); + + luaL_register(LUA, "emu", vbalib); // added for better cross-emulator compatibility + luaL_register(LUA, "vba", vbalib); // kept for backward compatibility + luaL_register(LUA, "memory", memorylib); + luaL_register(LUA, "joypad", joypadlib); + luaL_register(LUA, "savestate", savestatelib); + luaL_register(LUA, "movie", movielib); + luaL_register(LUA, "gui", guilib); + luaL_register(LUA, "input", inputlib); + luaL_register(LUA, "sound", soundlib); + luaL_register(LUA, "bit", bit_funcs); // LuaBitOp library + luaL_register(LUA, "avi", avilib); // workaround for enhanced video encoding + lua_settop(LUA, 0); // clean the stack, because each call to luaL_register leaves a table on top + + // register a few utility functions outside of libraries (in the global namespace) + lua_register(LUA, "print", print); + lua_register(LUA, "tostring", tostring); + lua_register(LUA, "addressof", addressof); + lua_register(LUA, "copytable", copytable); + + // old bit operation functions + lua_register(LUA, "AND", bit_band); + lua_register(LUA, "OR", bit_bor); + lua_register(LUA, "XOR", bit_bxor); + lua_register(LUA, "SHIFT", bit_bshift_emulua); + lua_register(LUA, "BIT", bitbit); + + luabitop_validate(LUA); + + lua_pushstring(LUA, "math"); + lua_gettable(LUA, LUA_GLOBALSINDEX); + lua_pushcfunction(LUA, sfmt_random); + lua_setfield(LUA, -2, "random"); + lua_pushcfunction(LUA, sfmt_randomseed); + lua_setfield(LUA, -2, "randomseed"); + lua_settop(LUA, 0); + + // push arrays for storing hook functions in + for (int i = 0; i < LUAMEMHOOK_COUNT; i++) + { + lua_newtable(LUA); + lua_setfield(LUA, LUA_REGISTRYINDEX, luaMemHookTypeStrings[i]); + } + } + + // We make our thread NOW because we want it at the bottom of the stack. + // If all goes wrong, we let the garbage collector remove it. + lua_State *thread = lua_newthread(LUA); + + // Load the data + int result = luaL_loadfile(LUA, filename); + + if (result) + { + //#if (defined(WIN32) && !defined(SDL)) + // info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer(); + // AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua load error", MB_OK | MB_ICONSTOP); + //#else + // fprintf(stderr, "Failed to compile file: %s\n", lua_tostring(LUA, -1)); + //#endif + printerror(LUA, -1); + + // Wipe the stack. Our thread + lua_settop(LUA, 0); + return 0; // Oh shit. + } + + // Get our function into it + lua_xmove(LUA, thread, 1); + + // Save the thread to the registry. This is why I make the thread FIRST. + lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread); + + // Initialize settings + luaRunning = true; + skipRerecords = false; + numMemHooks = 0; + transparencyModifier = 255; // opaque + lua_joypads_used = 0; // not used + //wasPaused = systemIsPaused(); + //systemSetPause(false); + + // Set up our protection hook to be executed once every 10,000 bytecode instructions. + lua_sethook(thread, VBALuaHookFunction, LUA_MASKCOUNT, 10000); #ifdef WIN32 - info_print = PrintToWindowConsole; - info_onstart = WinLuaOnStart; - info_onstop = WinLuaOnStop; - if (!LuaConsoleHWnd) - LuaConsoleHWnd = CreateDialog(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDD_LUA), - AfxGetMainWnd()->GetSafeHwnd(), (DLGPROC) DlgLuaScriptDialog); - info_uid = (int)LuaConsoleHWnd; + info_print = PrintToWindowConsole; + info_onstart = WinLuaOnStart; + info_onstop = WinLuaOnStop; + if (!LuaConsoleHWnd) + LuaConsoleHWnd = CreateDialog(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDD_LUA), + AfxGetMainWnd()->GetSafeHwnd(), (DLGPROC) DlgLuaScriptDialog); + info_uid = (int)LuaConsoleHWnd; #else - info_print = NULL; - info_onstart = NULL; - info_onstop = NULL; + info_print = NULL; + info_onstart = NULL; + info_onstop = NULL; #endif - if (info_onstart) - info_onstart(info_uid); - - // And run it right now. :) - VBALuaFrameBoundary(); - systemRenderFrame(); - - // We're done. - return 1; - } + if (info_onstart) + info_onstart(info_uid); + + // And run it right now. :) + VBALuaFrameBoundary(); + systemRenderFrame(); + + // We're done. + return 1; +} /** * Equivalent to repeating the last VBALoadLuaCode() call. */ - int VBAReloadLuaCode(void) - { - if (!luaScriptName) - { - systemScreenMessage("There's no script to reload."); - return 0; - } - else - return VBALoadLuaCode(luaScriptName); - } +int VBAReloadLuaCode(void) +{ + if (!luaScriptName) + { + systemScreenMessage("There's no script to reload."); + return 0; + } + else + return VBALoadLuaCode(luaScriptName); +} /** * Terminates a running Lua script by killing the whole Lua engine. @@ -4906,55 +4906,55 @@ * Always safe to call, except from within a lua call itself (duh). * */ - void VBALuaStop(void) - { - //already killed - if (!LUA) - return; - - //execute the user's shutdown callbacks - CallExitFunction(); - - /*info.*/ numMemHooks = 0; - for (int i = 0; i < LUAMEMHOOK_COUNT; i++) - CalculateMemHookRegions((LuaMemHookType)i); - - //sometimes iup uninitializes com - //MBG TODO - test whether this is really necessary. i dont think it is +void VBALuaStop(void) +{ + //already killed + if (!LUA) + return; + + //execute the user's shutdown callbacks + CallExitFunction(); + + /*info.*/ numMemHooks = 0; + for (int i = 0; i < LUAMEMHOOK_COUNT; i++) + CalculateMemHookRegions((LuaMemHookType)i); + + //sometimes iup uninitializes com + //MBG TODO - test whether this is really necessary. i dont think it is #if (defined(WIN32) && !defined(SDL)) - CoInitialize(0); + CoInitialize(0); #endif - if (info_onstop) - info_onstop(info_uid); - - //lua_gc(LUA,LUA_GCCOLLECT,0); - lua_close(LUA); // this invokes our garbage collectors for us - LUA = NULL; - VBALuaOnStop(); - } + if (info_onstop) + info_onstop(info_uid); + + //lua_gc(LUA,LUA_GCCOLLECT,0); + lua_close(LUA); // this invokes our garbage collectors for us + LUA = NULL; + VBALuaOnStop(); +} /** * Returns true if there is a Lua script running. * */ - int VBALuaRunning(void) - { - // FIXME: return false when no callback functions are registered. - return (int) (LUA != NULL); // should return true if callback functions are active. - } +int VBALuaRunning(void) +{ + // FIXME: return false when no callback functions are registered. + return (int) (LUA != NULL); // should return true if callback functions are active. +} /** * Returns true if Lua would like to steal the given joypad control. * * Range is 0 through 3 */ - int VBALuaUsingJoypad(int which) - { - if (which < 0 || which > 3) - which = systemGetDefaultJoypad(); - return lua_joypads_used & (1 << which); - } +int VBALuaUsingJoypad(int which) +{ + if (which < 0 || which > 3) + which = systemGetDefaultJoypad(); + return lua_joypads_used & (1 << which); +} /** * Reads the buttons Lua is feeding for the given joypad, in the same @@ -4963,14 +4963,14 @@ * This function must not be called more than once per frame. Ideally exactly once * per frame (if VBALuaUsingJoypad says it's safe to do so) */ - int VBALuaReadJoypad(int which) - { - if (which < 0 || which > 3) - which = systemGetDefaultJoypad(); - - //lua_joypads_used &= ~(1 << which); - return lua_joypads[which]; - } +int VBALuaReadJoypad(int which) +{ + if (which < 0 || which > 3) + which = systemGetDefaultJoypad(); + + //lua_joypads_used &= ~(1 << which); + return lua_joypads[which]; +} /** * If this function returns true, the movie code should NOT increment @@ -4978,125 +4978,125 @@ * * This function will not return true if a script is not running. */ - bool8 VBALuaRerecordCountSkip(void) - { - // FIXME: return true if (there are any active callback functions && skipRerecords) - return LUA && luaRunning && skipRerecords; - } +bool8 VBALuaRerecordCountSkip(void) +{ + // FIXME: return true if (there are any active callback functions && skipRerecords) + return LUA && luaRunning && skipRerecords; +} /** * Given a screen with the indicated resolution, * draw the current GUI onto it. */ - void VBALuaGui(uint8 *screen, int ppl, int width, int height) - { - if (!LUA /* || !luaRunning*/) - return; - - // First, check if we're being called by anybody - lua_getfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); - - if (lua_isfunction(LUA, -1)) - { - // We call it now - numTries = 1000; - - int ret = lua_pcall(LUA, 0, 0, 0); - if (ret != 0) - { - // This is grounds for trashing the function - // Note: This must be done before the messagebox pops up, - // otherwise the messagebox will cause a paint event which causes a weird - // infinite call sequence that makes Snes9x silently exit with error code 3, - // if a Lua GUI function crashes. (nitsuja) - lua_pushnil(LUA); - lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); - -//#if (defined(WIN32) && !defined(SDL)) -// info_print(info_uid, lua_tostring(LUA, -1)); //AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua Error -// in GUI function", MB_OK); -//#else -// fprintf(stderr, "Lua error in gui.register function: %s\n", lua_tostring(LUA, -1)); -//#endif - printerror(LUA, -1); - } - } - - // And wreak the stack - lua_settop(LUA, 0); - - if (!gui_used) - return; - - gui_used = false; - - int x, y; - - //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3; - int pitch = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4); - - if (width > LUA_SCREEN_WIDTH) - width = LUA_SCREEN_WIDTH; - if (height > LUA_SCREEN_HEIGHT) - height = LUA_SCREEN_HEIGHT; - - GetColorFunc getColor; - SetColorFunc setColor; - getColorIOFunc(systemColorDepth, &getColor, &setColor); - - for (y = 0; y < height; y++) - { - uint8 *scr = &screen[y * pitch]; - for (x = 0; x < width; x++, scr += systemColorDepth / 8) - { - const uint8 gui_alpha = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 3]; - if (gui_alpha == 0) - { - // do nothing - continue; - } - - const uint8 gui_red = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 2]; - const uint8 gui_green = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 1]; - const uint8 gui_blue = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4]; - int red, green, blue; - - if (gui_alpha == 255) - { - // direct copy - red = gui_red; - green = gui_green; - blue = gui_blue; - } - else - { - // alpha-blending - uint8 scr_red, scr_green, scr_blue; - getColor(scr, &scr_red, &scr_green, &scr_blue); - red = (((int)gui_red - scr_red) * gui_alpha / 255 + scr_red) & 255; - green = (((int)gui_green - scr_green) * gui_alpha / 255 + scr_green) & 255; - blue = (((int)gui_blue - scr_blue) * gui_alpha / 255 + scr_blue) & 255; - } - - setColor(scr, (uint8) red, (uint8) green, (uint8) blue); - } - } - - return; - } - - void VBALuaClearGui(void) - { - gui_used = false; - } - - lua_State *VBAGetLuaState() - { - return LUA; - } - - char *VBAGetLuaScriptName() - { - return luaScriptName; - } - +void VBALuaGui(uint8 *screen, int ppl, int width, int height) +{ + if (!LUA /* || !luaRunning*/) + return; + + // First, check if we're being called by anybody + lua_getfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); + + if (lua_isfunction(LUA, -1)) + { + // We call it now + numTries = 1000; + + int ret = lua_pcall(LUA, 0, 0, 0); + if (ret != 0) + { + // This is grounds for trashing the function + // Note: This must be done before the messagebox pops up, + // otherwise the messagebox will cause a paint event which causes a weird + // infinite call sequence that makes Snes9x silently exit with error code 3, + // if a Lua GUI function crashes. (nitsuja) + lua_pushnil(LUA); + lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); + + //#if (defined(WIN32) && !defined(SDL)) + // info_print(info_uid, lua_tostring(LUA, -1)); //AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua Error + // in GUI function", MB_OK); + //#else + // fprintf(stderr, "Lua error in gui.register function: %s\n", lua_tostring(LUA, -1)); + //#endif + printerror(LUA, -1); + } + } + + // And wreak the stack + lua_settop(LUA, 0); + + if (!gui_used) + return; + + gui_used = false; + + int x, y; + + //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3; + int pitch = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4); + + if (width > LUA_SCREEN_WIDTH) + width = LUA_SCREEN_WIDTH; + if (height > LUA_SCREEN_HEIGHT) + height = LUA_SCREEN_HEIGHT; + + GetColorFunc getColor; + SetColorFunc setColor; + getColorIOFunc(systemColorDepth, &getColor, &setColor); + + for (y = 0; y < height; y++) + { + uint8 *scr = &screen[y * pitch]; + for (x = 0; x < width; x++, scr += systemColorDepth / 8) + { + const uint8 gui_alpha = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 3]; + if (gui_alpha == 0) + { + // do nothing + continue; + } + + const uint8 gui_red = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 2]; + const uint8 gui_green = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 1]; + const uint8 gui_blue = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4]; + int red, green, blue; + + if (gui_alpha == 255) + { + // direct copy + red = gui_red; + green = gui_green; + blue = gui_blue; + } + else + { + // alpha-blending + uint8 scr_red, scr_green, scr_blue; + getColor(scr, &scr_red, &scr_green, &scr_blue); + red = (((int)gui_red - scr_red) * gui_alpha / 255 + scr_red) & 255; + green = (((int)gui_green - scr_green) * gui_alpha / 255 + scr_green) & 255; + blue = (((int)gui_blue - scr_blue) * gui_alpha / 255 + scr_blue) & 255; + } + + setColor(scr, (uint8) red, (uint8) green, (uint8) blue); + } + } + + return; +} + +void VBALuaClearGui(void) +{ + gui_used = false; +} + +lua_State *VBAGetLuaState() +{ + return LUA; +} + +char *VBAGetLuaScriptName() +{ + return luaScriptName; +} +