Mercurial > vba-linux
diff src/common/lua-engine.cpp @ 19:5e8e5083da94
brought in common and gba, fixed problems with outdated Makefile.am files in both of these packages
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sun, 04 Mar 2012 14:33:52 -0600 |
parents | f9f4f1b99eed |
children | bf9169ad4222 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/common/lua-engine.cpp Sun Mar 04 14:33:52 2012 -0600 1.3 @@ -0,0 +1,5102 @@ 1.4 +#include <cstdio> 1.5 +#include <cstdlib> 1.6 +#include <malloc.h> 1.7 +#include <string> 1.8 +#include <cassert> 1.9 +#include <cctype> 1.10 +#include <cmath> 1.11 +#include <ctime> 1.12 + 1.13 +#include <vector> 1.14 +#include <map> 1.15 +#include <string> 1.16 +#include <algorithm> 1.17 + 1.18 +using namespace std; 1.19 + 1.20 +#ifdef __linux 1.21 + #include <unistd.h> // for unlink 1.22 + #include <sys/types.h> 1.23 + #include <sys/wait.h> 1.24 +#endif 1.25 +#if (defined(WIN32) && !defined(SDL)) 1.26 + #include <direct.h> 1.27 + #include "../win32/stdafx.h" 1.28 + #include "../win32/Input.h" 1.29 + #include "../win32/MainWnd.h" 1.30 + #include "../win32/VBA.h" 1.31 + #include "../win32/LuaOpenDialog.h" 1.32 +#else 1.33 + #define stricmp strcasecmp 1.34 + #define strnicmp strncasecmp 1.35 +#endif 1.36 + 1.37 +#include "../Port.h" 1.38 +#include "System.h" 1.39 +#include "movie.h" 1.40 +#include "../gba/GBA.h" 1.41 +#include "../gba/GBAGlobals.h" 1.42 +#include "../gb/GB.h" 1.43 +#include "../gb/gbGlobals.h" 1.44 +#include "../gba/GBASound.h" 1.45 + 1.46 +#ifdef _WIN32 1.47 +#include "../win32/Sound.h" 1.48 +//#include "../win32/WinMiscUtil.h" 1.49 +extern CString winGetSavestateFilename(const CString &LogicalRomName, int nID); 1.50 +#else 1.51 +#endif 1.52 + 1.53 +extern "C" 1.54 +{ 1.55 +#include "../lua/src/lua.h" 1.56 +#include "../lua/src/lauxlib.h" 1.57 +#include "../lua/src/lualib.h" 1.58 +#include "../lua/src/lstate.h" 1.59 +} 1.60 +#include "vbalua.h" 1.61 + 1.62 +#include "../SFMT/SFMT.c" 1.63 + 1.64 +static void (*info_print)(int uid, const char *str); 1.65 +static void (*info_onstart)(int uid); 1.66 +static void (*info_onstop)(int uid); 1.67 +static int info_uid; 1.68 + 1.69 +#ifndef countof 1.70 + #define countof(a) (sizeof(a) / sizeof(a[0])) 1.71 +#endif 1.72 + 1.73 +static lua_State *LUA; 1.74 + 1.75 +// Are we running any code right now? 1.76 +static char *luaScriptName = NULL; 1.77 + 1.78 +// Are we running any code right now? 1.79 +static bool8 luaRunning = false; 1.80 + 1.81 +// True at the frame boundary, false otherwise. 1.82 +static bool8 frameBoundary = false; 1.83 + 1.84 +// The execution speed we're running at. 1.85 +static enum { SPEED_NORMAL, SPEED_NOTHROTTLE, SPEED_TURBO, SPEED_MAXIMUM } speedmode = SPEED_NORMAL; 1.86 + 1.87 +// Rerecord count skip mode 1.88 +static bool8 skipRerecords = false; 1.89 + 1.90 +// Used by the registry to find our functions 1.91 +static const char *frameAdvanceThread = "VBA.FrameAdvance"; 1.92 +static const char *guiCallbackTable = "VBA.GUI"; 1.93 + 1.94 +// True if there's a thread waiting to run after a run of frame-advance. 1.95 +static bool8 frameAdvanceWaiting = false; 1.96 + 1.97 +// We save our pause status in the case of a natural death. 1.98 +//static bool8 wasPaused = false; 1.99 + 1.100 +// Transparency strength. 255=opaque, 0=so transparent it's invisible 1.101 +static int transparencyModifier = 255; 1.102 + 1.103 +// Our joypads. 1.104 +static uint32 lua_joypads[4]; 1.105 +static uint8 lua_joypads_used = 0; 1.106 + 1.107 +static bool8 gui_used = false; 1.108 +static uint8 *gui_data = NULL; // BGRA 1.109 + 1.110 +// Protects Lua calls from going nuts. 1.111 +// We set this to a big number like 1000 and decrement it 1.112 +// over time. The script gets knifed once this reaches zero. 1.113 +static int numTries; 1.114 + 1.115 +// number of registered memory functions (1 per hooked byte) 1.116 +static unsigned int numMemHooks; 1.117 + 1.118 +// Look in inputglobal.h for macros named like BUTTON_MASK_UP to determine the order. 1.119 +static const char *button_mappings[] = { 1.120 + "A", "B", "select", "start", "right", "left", "up", "down", "R", "L" 1.121 +}; 1.122 + 1.123 +#ifdef _MSC_VER 1.124 + #define snprintf _snprintf 1.125 + #define vscprintf _vscprintf 1.126 +#else 1.127 + #define stricmp strcasecmp 1.128 + #define strnicmp strncasecmp 1.129 + #define __forceinline __attribute__((always_inline)) 1.130 +#endif 1.131 + 1.132 +static const char *luaCallIDStrings[] = 1.133 +{ 1.134 + "CALL_BEFOREEMULATION", 1.135 + "CALL_AFTEREMULATION", 1.136 + "CALL_BEFOREEXIT" 1.137 +}; 1.138 + 1.139 +//make sure we have the right number of strings 1.140 +CTASSERT(sizeof(luaCallIDStrings) / sizeof(*luaCallIDStrings) == LUACALL_COUNT) 1.141 + 1.142 +static const char *luaMemHookTypeStrings [] = 1.143 +{ 1.144 + "MEMHOOK_WRITE", 1.145 + "MEMHOOK_READ", 1.146 + "MEMHOOK_EXEC", 1.147 + 1.148 + "MEMHOOK_WRITE_SUB", 1.149 + "MEMHOOK_READ_SUB", 1.150 + "MEMHOOK_EXEC_SUB", 1.151 +}; 1.152 + 1.153 +//make sure we have the right number of strings 1.154 +CTASSERT(sizeof(luaMemHookTypeStrings) / sizeof(*luaMemHookTypeStrings) == LUAMEMHOOK_COUNT) 1.155 + 1.156 +static char *rawToCString(lua_State * L, int idx = 0); 1.157 +static const char *toCString(lua_State *L, int idx = 0); 1.158 + 1.159 +// GBA memory I/O functions copied from win32/MemoryViewerDlg.cpp 1.160 +static inline u8 CPUReadByteQuick(u32 addr) 1.161 +{ 1.162 + return ::map[addr >> 24].address[addr & ::map[addr >> 24].mask]; 1.163 +} 1.164 + 1.165 +static inline void CPUWriteByteQuick(u32 addr, u8 b) 1.166 +{ 1.167 + ::map[addr >> 24].address[addr & ::map[addr >> 24].mask] = b; 1.168 +} 1.169 + 1.170 +static inline u16 CPUReadHalfWordQuick(u32 addr) 1.171 +{ 1.172 + return *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]); 1.173 +} 1.174 + 1.175 +static inline void CPUWriteHalfWordQuick(u32 addr, u16 b) 1.176 +{ 1.177 + *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b; 1.178 +} 1.179 + 1.180 +static inline u32 CPUReadMemoryQuick(u32 addr) 1.181 +{ 1.182 + return *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]); 1.183 +} 1.184 + 1.185 +static inline void CPUWriteMemoryQuick(u32 addr, u32 b) 1.186 +{ 1.187 + *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b; 1.188 +} 1.189 + 1.190 +// GB 1.191 +static inline u8 gbReadMemoryQuick8(u16 addr) 1.192 +{ 1.193 + return gbReadMemoryQuick(addr); 1.194 +} 1.195 + 1.196 +static inline void gbWriteMemoryQuick8(u16 addr, u8 b) 1.197 +{ 1.198 + gbWriteMemoryQuick(addr, b); 1.199 +} 1.200 + 1.201 +static inline u16 gbReadMemoryQuick16(u16 addr) 1.202 +{ 1.203 + return (gbReadMemoryQuick(addr + 1) << 8) | gbReadMemoryQuick(addr); 1.204 +} 1.205 + 1.206 +static inline void gbWriteMemoryQuick16(u16 addr, u16 b) 1.207 +{ 1.208 + gbWriteMemoryQuick(addr, b & 0xff); 1.209 + gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff); 1.210 +} 1.211 + 1.212 +static inline u32 gbReadMemoryQuick32(u16 addr) 1.213 +{ 1.214 + return (gbReadMemoryQuick(addr + 3) << 24) | 1.215 + (gbReadMemoryQuick(addr + 2) << 16) | 1.216 + (gbReadMemoryQuick(addr + 1) << 8) | 1.217 + gbReadMemoryQuick(addr); 1.218 +} 1.219 + 1.220 +static inline void gbWriteMemoryQuick32(u16 addr, u32 b) 1.221 +{ 1.222 + gbWriteMemoryQuick(addr, b & 0xff); 1.223 + gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff); 1.224 + gbWriteMemoryQuick(addr + 2, (b >> 16) & 0xff); 1.225 + gbWriteMemoryQuick(addr + 1, (b >> 24) & 0xff); 1.226 +} 1.227 + 1.228 +static inline u8 gbReadROMQuick8(u32 addr) 1.229 +{ 1.230 + return gbReadROMQuick(addr & gbRomSizeMask); 1.231 +} 1.232 + 1.233 +static inline u8 gbReadROMQuick16(u32 addr) 1.234 +{ 1.235 + return (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) | gbReadROMQuick(addr & gbRomSizeMask); 1.236 +} 1.237 + 1.238 +static inline u8 gbReadROMQuick32(u32 addr) 1.239 +{ 1.240 + return (gbReadROMQuick(addr+3 & gbRomSizeMask) << 24) | 1.241 + (gbReadROMQuick(addr+2 & gbRomSizeMask) << 16) | 1.242 + (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) | 1.243 + gbReadROMQuick(addr & gbRomSizeMask); 1.244 +} 1.245 + 1.246 +typedef void (*GetColorFunc)(const uint8 *, uint8 *, uint8 *, uint8 *); 1.247 +typedef void (*SetColorFunc)(uint8 *, uint8, uint8, uint8); 1.248 + 1.249 +static void getColor16(const uint8 *s, uint8 *r, uint8 *g, uint8 *b) 1.250 +{ 1.251 + u16 v = *(const uint16 *)s; 1.252 + *r = ((v >> systemBlueShift) & 0x001f) << 3; 1.253 + *g = ((v >> systemGreenShift) & 0x001f) << 3; 1.254 + *b = ((v >> systemRedShift) & 0x001f) << 3; 1.255 +} 1.256 + 1.257 +static void getColor24(const uint8 *s, uint8 *r, uint8 *g, uint8 *b) 1.258 +{ 1.259 + if (systemRedShift > systemBlueShift) 1.260 + *b = s[0], *g = s[1], *r = s[2]; 1.261 + else 1.262 + *r = s[0], *g = s[1], *b = s[2]; 1.263 +} 1.264 + 1.265 +static void getColor32(const uint8 *s, uint8 *r, uint8 *g, uint8 *b) 1.266 +{ 1.267 + u32 v = *(const uint32 *)s; 1.268 + *b = ((v >> systemBlueShift) & 0x001f) << 3; 1.269 + *g = ((v >> systemGreenShift) & 0x001f) << 3; 1.270 + *r = ((v >> systemRedShift) & 0x001f) << 3; 1.271 +} 1.272 + 1.273 +static void setColor16(uint8 *s, uint8 r, uint8 g, uint8 b) 1.274 +{ 1.275 + *(uint16 *)s = ((b >> 3) & 0x01f) << 1.276 + systemBlueShift | 1.277 + ((g >> 3) & 0x01f) << 1.278 + systemGreenShift | 1.279 + ((r >> 3) & 0x01f) << 1.280 + systemRedShift; 1.281 +} 1.282 + 1.283 +static void setColor24(uint8 *s, uint8 r, uint8 g, uint8 b) 1.284 +{ 1.285 + if (systemRedShift > systemBlueShift) 1.286 + s[0] = b, s[1] = g, s[2] = r; 1.287 + else 1.288 + s[0] = r, s[1] = g, s[2] = b; 1.289 +} 1.290 + 1.291 +static void setColor32(uint8 *s, uint8 r, uint8 g, uint8 b) 1.292 +{ 1.293 + *(uint32 *)s = ((b >> 3) & 0x01f) << 1.294 + systemBlueShift | 1.295 + ((g >> 3) & 0x01f) << 1.296 + systemGreenShift | 1.297 + ((r >> 3) & 0x01f) << 1.298 + systemRedShift; 1.299 +} 1.300 + 1.301 +static bool getColorIOFunc(int depth, GetColorFunc *getColor, SetColorFunc *setColor) 1.302 +{ 1.303 + switch (depth) 1.304 + { 1.305 + case 16: 1.306 + if (getColor) 1.307 + *getColor = getColor16; 1.308 + if (setColor) 1.309 + *setColor = setColor16; 1.310 + return true; 1.311 + case 24: 1.312 + if (getColor) 1.313 + *getColor = getColor24; 1.314 + if (setColor) 1.315 + *setColor = setColor24; 1.316 + return true; 1.317 + case 32: 1.318 + if (getColor) 1.319 + *getColor = getColor32; 1.320 + if (setColor) 1.321 + *setColor = setColor32; 1.322 + return true; 1.323 + default: 1.324 + return false; 1.325 + } 1.326 +} 1.327 + 1.328 +/** 1.329 + * Resets emulator speed / pause states after script exit. 1.330 + */ 1.331 +static void VBALuaOnStop(void) 1.332 +{ 1.333 + luaRunning = false; 1.334 + lua_joypads_used = 0; 1.335 + gui_used = false; 1.336 + //if (wasPaused) 1.337 + // systemSetPause(true); 1.338 +} 1.339 + 1.340 +/** 1.341 + * Asks Lua if it wants control of the emulator's speed. 1.342 + * Returns 0 if no, 1 if yes. If yes, we also tamper with the 1.343 + * IPPU's settings for speed ourselves, so the calling code 1.344 + * need not do anything. 1.345 + */ 1.346 +int VBALuaSpeed(void) 1.347 +{ 1.348 + if (!LUA || !luaRunning) 1.349 + return 0; 1.350 + 1.351 + //printf("%d\n", speedmode); 1.352 + switch (speedmode) 1.353 + { 1.354 + /* 1.355 + case SPEED_NORMAL: 1.356 + return 0; 1.357 + case SPEED_NOTHROTTLE: 1.358 + IPPU.RenderThisFrame = true; 1.359 + return 1; 1.360 + 1.361 + case SPEED_TURBO: 1.362 + IPPU.SkippedFrames++; 1.363 + if (IPPU.SkippedFrames >= 40) { 1.364 + IPPU.SkippedFrames = 0; 1.365 + IPPU.RenderThisFrame = true; 1.366 + } 1.367 + else 1.368 + IPPU.RenderThisFrame = false; 1.369 + return 1; 1.370 + 1.371 + // In mode 3, SkippedFrames is set to zero so that the frame 1.372 + // skipping code doesn't try anything funny. 1.373 + case SPEED_MAXIMUM: 1.374 + IPPU.SkippedFrames=0; 1.375 + IPPU.RenderThisFrame = false; 1.376 + return 1; 1.377 + */ 1.378 + case 0: // FIXME: to get rid of the warning 1.379 + default: 1.380 + assert(false); 1.381 + return 0; 1.382 + } 1.383 +} 1.384 + 1.385 +/////////////////////////// 1.386 +// vba.speedmode(string mode) 1.387 +// 1.388 +// Takes control of the emulation speed 1.389 +// of the system. Normal is normal speed (60fps, 50 for PAL), 1.390 +// nothrottle disables speed control but renders every frame, 1.391 +// turbo renders only a few frames in order to speed up emulation, 1.392 + 1.393 +// maximum renders no frames 1.394 +static int vba_speedmode(lua_State *L) 1.395 +{ 1.396 + const char *mode = luaL_checkstring(L, 1); 1.397 + 1.398 + if (strcasecmp(mode, "normal") == 0) 1.399 + { 1.400 + speedmode = SPEED_NORMAL; 1.401 + } 1.402 + else if (strcasecmp(mode, "nothrottle") == 0) 1.403 + { 1.404 + speedmode = SPEED_NOTHROTTLE; 1.405 + } 1.406 + else if (strcasecmp(mode, "turbo") == 0) 1.407 + { 1.408 + speedmode = SPEED_TURBO; 1.409 + } 1.410 + else if (strcasecmp(mode, "maximum") == 0) 1.411 + { 1.412 + speedmode = SPEED_MAXIMUM; 1.413 + } 1.414 + else 1.415 + luaL_error(L, "Invalid mode %s to vba.speedmode", mode); 1.416 + 1.417 + //printf("new speed mode: %d\n", speedmode); 1.418 + return 0; 1.419 +} 1.420 + 1.421 +// vba.frameadvnace() 1.422 +// 1.423 +// Executes a frame advance. Occurs by yielding the coroutine, then re-running 1.424 + 1.425 +// when we break out. 1.426 +static int vba_frameadvance(lua_State *L) 1.427 +{ 1.428 + // We're going to sleep for a frame-advance. Take notes. 1.429 + if (frameAdvanceWaiting) 1.430 + return luaL_error(L, "can't call vba.frameadvance() from here"); 1.431 + 1.432 + frameAdvanceWaiting = true; 1.433 + 1.434 + // Don't do this! The user won't like us sending their emulator out of control! 1.435 + // Settings.FrameAdvance = true; 1.436 + // Now we can yield to the main 1.437 + return lua_yield(L, 0); 1.438 + 1.439 + // It's actually rather disappointing... 1.440 +} 1.441 + 1.442 +// vba.pause() 1.443 +// 1.444 +// Pauses the emulator, function "waits" until the user unpauses. 1.445 +// This function MAY be called from a non-frame boundary, but the frame 1.446 + 1.447 +// finishes executing anwyays. In this case, the function returns immediately. 1.448 +static int vba_pause(lua_State *L) 1.449 +{ 1.450 + systemSetPause(true); 1.451 + speedmode = SPEED_NORMAL; 1.452 + 1.453 + // Return control if we're midway through a frame. We can't pause here. 1.454 + if (frameAdvanceWaiting) 1.455 + { 1.456 + return 0; 1.457 + } 1.458 + 1.459 + // If it's on a frame boundary, we also yield. 1.460 + frameAdvanceWaiting = true; 1.461 + return lua_yield(L, 0); 1.462 +} 1.463 + 1.464 +static int vba_registerbefore(lua_State *L) 1.465 +{ 1.466 + if (!lua_isnil(L, 1)) 1.467 + luaL_checktype(L, 1, LUA_TFUNCTION); 1.468 + lua_settop(L, 1); 1.469 + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]); 1.470 + lua_insert(L, 1); 1.471 + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]); 1.472 + 1.473 + //StopScriptIfFinished(luaStateToUIDMap[L]); 1.474 + return 1; 1.475 +} 1.476 + 1.477 +static int vba_registerafter(lua_State *L) 1.478 +{ 1.479 + if (!lua_isnil(L, 1)) 1.480 + luaL_checktype(L, 1, LUA_TFUNCTION); 1.481 + lua_settop(L, 1); 1.482 + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]); 1.483 + lua_insert(L, 1); 1.484 + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]); 1.485 + 1.486 + //StopScriptIfFinished(luaStateToUIDMap[L]); 1.487 + return 1; 1.488 +} 1.489 + 1.490 +static int vba_registerexit(lua_State *L) 1.491 +{ 1.492 + if (!lua_isnil(L, 1)) 1.493 + luaL_checktype(L, 1, LUA_TFUNCTION); 1.494 + lua_settop(L, 1); 1.495 + lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); 1.496 + lua_insert(L, 1); 1.497 + lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); 1.498 + 1.499 + //StopScriptIfFinished(luaStateToUIDMap[L]); 1.500 + return 1; 1.501 +} 1.502 + 1.503 +static inline bool isalphaorunderscore(char c) 1.504 +{ 1.505 + return isalpha(c) || c == '_'; 1.506 +} 1.507 + 1.508 +static std::vector<const void *> s_tableAddressStack; // prevents infinite recursion of a table within a table (when cycle is 1.509 + // found, print something like table:parent) 1.510 +static std::vector<const void *> s_metacallStack; // prevents infinite recursion if something's __tostring returns another table 1.511 + // that contains that something (when cycle is found, print the inner result 1.512 + // without using __tostring) 1.513 + 1.514 +#define APPENDPRINT { int _n = snprintf(ptr, remaining, 1.515 +#define END ); if (_n >= 0) { ptr += _n; remaining -= _n; } else { remaining = 0; } } 1.516 +static void toCStringConverter(lua_State *L, int i, char * &ptr, int &remaining) 1.517 +{ 1.518 + if (remaining <= 0) 1.519 + return; 1.520 + 1.521 + const char *str = ptr; // for debugging 1.522 + 1.523 + // if there is a __tostring metamethod then call it 1.524 + int usedMeta = luaL_callmeta(L, i, "__tostring"); 1.525 + if (usedMeta) 1.526 + { 1.527 + std::vector<const void *>::const_iterator foundCycleIter = std::find(s_metacallStack.begin(), s_metacallStack.end(), lua_topointer(L, i)); 1.528 + if (foundCycleIter != s_metacallStack.end()) 1.529 + { 1.530 + lua_pop(L, 1); 1.531 + usedMeta = false; 1.532 + } 1.533 + else 1.534 + { 1.535 + s_metacallStack.push_back(lua_topointer(L, i)); 1.536 + i = lua_gettop(L); 1.537 + } 1.538 + } 1.539 + 1.540 + switch (lua_type(L, i)) 1.541 + { 1.542 + case LUA_TNONE: 1.543 + break; 1.544 + case LUA_TNIL: 1.545 + APPENDPRINT "nil" END break; 1.546 + case LUA_TBOOLEAN: 1.547 + APPENDPRINT lua_toboolean(L, i) ? "true" : "false" END break; 1.548 + case LUA_TSTRING : APPENDPRINT "%s", lua_tostring(L, i) END break; 1.549 + case LUA_TNUMBER: 1.550 + APPENDPRINT "%.12Lg", lua_tonumber(L, i) END break; 1.551 + case LUA_TFUNCTION: 1.552 + if ((L->base + i - 1)->value.gc->cl.c.isC) 1.553 + { 1.554 + //lua_CFunction func = lua_tocfunction(L, i); 1.555 + //std::map<lua_CFunction, const char*>::iterator iter = s_cFuncInfoMap.find(func); 1.556 + //if(iter == s_cFuncInfoMap.end()) 1.557 + goto defcase; 1.558 + //APPENDPRINT "function(%s)", iter->second END 1.559 + } 1.560 + else 1.561 + { 1.562 + APPENDPRINT "function(" END 1.563 + Proto * p = (L->base + i - 1)->value.gc->cl.l.p; 1.564 + int numParams = p->numparams + (p->is_vararg ? 1 : 0); 1.565 + for (int n = 0; n < p->numparams; n++) 1.566 + { 1.567 + APPENDPRINT "%s", getstr(p->locvars[n].varname) END 1.568 + if (n != numParams - 1) 1.569 + APPENDPRINT "," END 1.570 + } 1.571 + if (p->is_vararg) 1.572 + APPENDPRINT "..." END 1.573 + APPENDPRINT ")" END 1.574 + } 1.575 + break; 1.576 +defcase: default: 1.577 + APPENDPRINT "%s:%p", luaL_typename(L, i), lua_topointer(L, i) END break; 1.578 + case LUA_TTABLE: 1.579 + { 1.580 + // first make sure there's enough stack space 1.581 + if (!lua_checkstack(L, 4)) 1.582 + { 1.583 + // note that even if lua_checkstack never returns false, 1.584 + // that doesn't mean we didn't need to call it, 1.585 + // because calling it retrieves stack space past LUA_MINSTACK 1.586 + goto defcase; 1.587 + } 1.588 + 1.589 + std::vector<const void *>::const_iterator foundCycleIter = 1.590 + std::find(s_tableAddressStack.begin(), s_tableAddressStack.end(), lua_topointer(L, i)); 1.591 + if (foundCycleIter != s_tableAddressStack.end()) 1.592 + { 1.593 + int parentNum = s_tableAddressStack.end() - foundCycleIter; 1.594 + if (parentNum > 1) 1.595 + APPENDPRINT "%s:parent^%d", luaL_typename(L, i), parentNum END 1.596 + else 1.597 + APPENDPRINT "%s:parent", luaL_typename(L, i) END 1.598 + } 1.599 + else 1.600 + { 1.601 + s_tableAddressStack.push_back(lua_topointer(L, i)); 1.602 + struct Scope { ~Scope(){ s_tableAddressStack. pop_back(); } } scope; 1.603 + 1.604 + APPENDPRINT "{" END 1.605 + 1.606 + lua_pushnil(L); // first key 1.607 + int keyIndex = lua_gettop(L); 1.608 + int valueIndex = keyIndex + 1; 1.609 + bool first = true; 1.610 + bool skipKey = true; // true if we're still in the "array part" of the table 1.611 + lua_Number arrayIndex = (lua_Number)0; 1.612 + while (lua_next(L, i)) 1.613 + { 1.614 + if (first) 1.615 + first = false; 1.616 + else 1.617 + APPENDPRINT ", " END 1.618 + if (skipKey) 1.619 + { 1.620 + arrayIndex += (lua_Number)1; 1.621 + bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER); 1.622 + skipKey = keyIsNumber && (lua_tonumber(L, keyIndex) == arrayIndex); 1.623 + } 1.624 + if (!skipKey) 1.625 + { 1.626 + bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING); 1.627 + bool invalidLuaIdentifier = (!keyIsString || !isalphaorunderscore(*lua_tostring(L, keyIndex))); 1.628 + if (invalidLuaIdentifier) 1.629 + if (keyIsString) 1.630 + APPENDPRINT "['" END 1.631 + else 1.632 + APPENDPRINT "[" END 1.633 + 1.634 + toCStringConverter(L, keyIndex, ptr, remaining); 1.635 + // key 1.636 + 1.637 + if (invalidLuaIdentifier) 1.638 + if (keyIsString) 1.639 + APPENDPRINT "']=" END 1.640 + else 1.641 + APPENDPRINT "]=" END 1.642 + else 1.643 + APPENDPRINT "=" END 1.644 + } 1.645 + 1.646 + bool valueIsString = (lua_type(L, valueIndex) == LUA_TSTRING); 1.647 + if (valueIsString) 1.648 + APPENDPRINT "'" END 1.649 + 1.650 + toCStringConverter(L, valueIndex, ptr, remaining); // value 1.651 + 1.652 + if (valueIsString) 1.653 + APPENDPRINT "'" END 1.654 + 1.655 + lua_pop(L, 1); 1.656 + 1.657 + if (remaining <= 0) 1.658 + { 1.659 + lua_settop(L, keyIndex - 1); // stack might not be clean yet if we're breaking 1.660 + // early 1.661 + break; 1.662 + } 1.663 + } 1.664 + APPENDPRINT "}" END 1.665 + } 1.666 + } 1.667 + break; 1.668 + } 1.669 + 1.670 + if (usedMeta) 1.671 + { 1.672 + s_metacallStack.pop_back(); 1.673 + lua_pop(L, 1); 1.674 + } 1.675 + } 1.676 + 1.677 + static const int s_tempStrMaxLen = 64 * 1024; 1.678 + static char s_tempStr [s_tempStrMaxLen]; 1.679 + 1.680 + static char *rawToCString(lua_State *L, int idx) 1.681 + { 1.682 + int a = idx > 0 ? idx : 1; 1.683 + int n = idx > 0 ? idx : lua_gettop(L); 1.684 + 1.685 + char *ptr = s_tempStr; 1.686 + *ptr = 0; 1.687 + 1.688 + int remaining = s_tempStrMaxLen; 1.689 + for (int i = a; i <= n; i++) 1.690 + { 1.691 + toCStringConverter(L, i, ptr, remaining); 1.692 + if (i != n) 1.693 + APPENDPRINT " " END 1.694 + } 1.695 + 1.696 + if (remaining < 3) 1.697 + { 1.698 + while (remaining < 6) 1.699 + remaining++, ptr--; 1.700 + APPENDPRINT "..." END 1.701 + } 1.702 + APPENDPRINT "\r\n" END 1.703 + // the trailing newline is so print() can avoid having to do wasteful things to print its newline 1.704 + // (string copying would be wasteful and calling info.print() twice can be extremely slow) 1.705 + // at the cost of functions that don't want the newline needing to trim off the last two characters 1.706 + // (which is a very fast operation and thus acceptable in this case) 1.707 + 1.708 + return s_tempStr; 1.709 + } 1.710 +#undef APPENDPRINT 1.711 +#undef END 1.712 + 1.713 +// replacement for luaB_tostring() that is able to show the contents of tables (and formats numbers better, and show function 1.714 +// prototypes) 1.715 +// can be called directly from lua via tostring(), assuming tostring hasn't been reassigned 1.716 + static int tostring(lua_State *L) 1.717 + { 1.718 + char *str = rawToCString(L); 1.719 + str[strlen(str) - 2] = 0; // hack: trim off the \r\n (which is there to simplify the print function's 1.720 + // task) 1.721 + lua_pushstring(L, str); 1.722 + return 1; 1.723 + } 1.724 + 1.725 +// like rawToCString, but will check if the global Lua function tostring() 1.726 +// has been replaced with a custom function, and call that instead if so 1.727 + static const char *toCString(lua_State *L, int idx) 1.728 + { 1.729 + int a = idx > 0 ? idx : 1; 1.730 + int n = idx > 0 ? idx : lua_gettop(L); 1.731 + lua_getglobal(L, "tostring"); 1.732 + lua_CFunction cf = lua_tocfunction(L, -1); 1.733 + if (cf == tostring || lua_isnil(L, -1)) // optimization: if using our own C tostring function, we can 1.734 + // bypass the call through Lua and all the string object 1.735 + // allocation that would entail 1.736 + { 1.737 + lua_pop(L, 1); 1.738 + return rawToCString(L, idx); 1.739 + } 1.740 + else // if the user overrided the tostring function, we have to actually call it and store the 1.741 + // temporarily allocated string it returns 1.742 + { 1.743 + lua_pushstring(L, ""); 1.744 + for (int i = a; i <= n; i++) 1.745 + { 1.746 + lua_pushvalue(L, -2); // function to be called 1.747 + lua_pushvalue(L, i); // value to print 1.748 + lua_call(L, 1, 1); 1.749 + if (lua_tostring(L, -1) == NULL) 1.750 + luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print")); 1.751 + lua_pushstring(L, (i < n) ? " " : "\r\n"); 1.752 + lua_concat(L, 3); 1.753 + } 1.754 + const char *str = lua_tostring(L, -1); 1.755 + strncpy(s_tempStr, str, s_tempStrMaxLen); 1.756 + s_tempStr[s_tempStrMaxLen - 1] = 0; 1.757 + lua_pop(L, 2); 1.758 + return s_tempStr; 1.759 + } 1.760 + } 1.761 + 1.762 +// replacement for luaB_print() that goes to the appropriate textbox instead of stdout 1.763 + static int print(lua_State *L) 1.764 + { 1.765 + const char *str = toCString(L); 1.766 + 1.767 + int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread]; 1.768 + //LuaContextInfo& info = GetCurrentInfo(); 1.769 + 1.770 + if (info_print) 1.771 + info_print(uid, str); 1.772 + else 1.773 + puts(str); 1.774 + 1.775 + //worry(L, 100); 1.776 + return 0; 1.777 + } 1.778 + 1.779 + static int printerror(lua_State *L, int idx) 1.780 + { 1.781 + lua_checkstack(L, lua_gettop(L) + 4); 1.782 + 1.783 + if (idx < 0) 1.784 + idx = lua_gettop(L) + 1 + idx; 1.785 + 1.786 + const char *str = rawToCString(L, idx); 1.787 + 1.788 + int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread]; 1.789 + //LuaContextInfo& info = GetCurrentInfo(); 1.790 + 1.791 + if (info_print) 1.792 + info_print(uid, str); 1.793 + else 1.794 + fputs(str, stderr); 1.795 + 1.796 + //worry(L, 100); 1.797 + return 0; 1.798 + } 1.799 + 1.800 +// vba.message(string msg) 1.801 +// 1.802 +// Displays the given message on the screen. 1.803 + static int vba_message(lua_State *L) 1.804 + { 1.805 + const char *msg = luaL_checkstring(L, 1); 1.806 + systemScreenMessage(msg); 1.807 + 1.808 + return 0; 1.809 + } 1.810 + 1.811 +// provides an easy way to copy a table from Lua 1.812 +// (simple assignment only makes an alias, but sometimes an independent table is desired) 1.813 +// currently this function only performs a shallow copy, 1.814 +// but I think it should be changed to do a deep copy (possibly of configurable depth?) 1.815 +// that maintains the internal table reference structure 1.816 + static int copytable(lua_State *L) 1.817 + { 1.818 + int origIndex = 1; // we only care about the first argument 1.819 + int origType = lua_type(L, origIndex); 1.820 + if (origType == LUA_TNIL) 1.821 + { 1.822 + lua_pushnil(L); 1.823 + return 1; 1.824 + } 1.825 + if (origType != LUA_TTABLE) 1.826 + { 1.827 + luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE)); 1.828 + lua_pushnil(L); 1.829 + return 1; 1.830 + } 1.831 + 1.832 + lua_createtable(L, lua_objlen(L, 1), 0); 1.833 + int copyIndex = lua_gettop(L); 1.834 + 1.835 + lua_pushnil(L); // first key 1.836 + int keyIndex = lua_gettop(L); 1.837 + int valueIndex = keyIndex + 1; 1.838 + 1.839 + while (lua_next(L, origIndex)) 1.840 + { 1.841 + lua_pushvalue(L, keyIndex); 1.842 + lua_pushvalue(L, valueIndex); 1.843 + lua_rawset(L, copyIndex); // copytable[key] = value 1.844 + lua_pop(L, 1); 1.845 + } 1.846 + 1.847 + // copy the reference to the metatable as well, if any 1.848 + if (lua_getmetatable(L, origIndex)) 1.849 + lua_setmetatable(L, copyIndex); 1.850 + 1.851 + return 1; // return the new table 1.852 + } 1.853 + 1.854 +// because print traditionally shows the address of tables, 1.855 +// and the print function I provide instead shows the contents of tables, 1.856 +// I also provide this function 1.857 +// (otherwise there would be no way to see a table's address, AFAICT) 1.858 + static int addressof(lua_State *L) 1.859 + { 1.860 + const void *ptr = lua_topointer(L, -1); 1.861 + lua_pushinteger(L, (lua_Integer)ptr); 1.862 + return 1; 1.863 + } 1.864 + 1.865 + struct registerPointerMap 1.866 + { 1.867 + const char * registerName; 1.868 + unsigned int *pointer; 1.869 + int dataSize; 1.870 + }; 1.871 + 1.872 +#define RPM_ENTRY(name, var) \ 1.873 + { name, (unsigned int *)&var, sizeof(var) \ 1.874 + } \ 1.875 + , 1.876 + 1.877 + extern gbRegister AF; 1.878 + extern gbRegister BC; 1.879 + extern gbRegister DE; 1.880 + extern gbRegister HL; 1.881 + extern gbRegister SP; 1.882 + extern gbRegister PC; 1.883 + extern u16 IFF; 1.884 + 1.885 + registerPointerMap regPointerMap [] = { 1.886 + // gba registers 1.887 + RPM_ENTRY("r0", reg[0].I) 1.888 + RPM_ENTRY("r1", reg[1].I) 1.889 + RPM_ENTRY("r2", reg[2].I) 1.890 + RPM_ENTRY("r3", reg[3].I) 1.891 + RPM_ENTRY("r4", reg[4].I) 1.892 + RPM_ENTRY("r5", reg[5].I) 1.893 + RPM_ENTRY("r6", reg[6].I) 1.894 + RPM_ENTRY("r7", reg[7].I) 1.895 + RPM_ENTRY("r8", reg[8].I) 1.896 + RPM_ENTRY("r9", reg[9].I) 1.897 + RPM_ENTRY("r10", reg[10].I) 1.898 + RPM_ENTRY("r11", reg[11].I) 1.899 + RPM_ENTRY("r12", reg[12].I) 1.900 + RPM_ENTRY("r13", reg[13].I) 1.901 + RPM_ENTRY("r14", reg[14].I) 1.902 + RPM_ENTRY("r15", reg[15].I) 1.903 + RPM_ENTRY("cpsr", reg[16].I) 1.904 + RPM_ENTRY("spsr", reg[17].I) 1.905 + // gb registers 1.906 + RPM_ENTRY("a", AF.B.B1) 1.907 + RPM_ENTRY("f", AF.B.B0) 1.908 + RPM_ENTRY("b", BC.B.B1) 1.909 + RPM_ENTRY("c", BC.B.B0) 1.910 + RPM_ENTRY("d", DE.B.B1) 1.911 + RPM_ENTRY("e", DE.B.B0) 1.912 + RPM_ENTRY("h", HL.B.B1) 1.913 + RPM_ENTRY("l", HL.B.B0) 1.914 + RPM_ENTRY("af", AF.W) 1.915 + RPM_ENTRY("bc", BC.W) 1.916 + RPM_ENTRY("de", DE.W) 1.917 + RPM_ENTRY("hl", HL.W) 1.918 + RPM_ENTRY("sp", SP.W) 1.919 + RPM_ENTRY("pc", PC.W) 1.920 + {} 1.921 + }; 1.922 + 1.923 + struct cpuToRegisterMap 1.924 + { 1.925 + const char *cpuName; 1.926 + registerPointerMap *rpmap; 1.927 + } 1.928 + cpuToRegisterMaps [] = 1.929 + { 1.930 + { "", regPointerMap }, 1.931 + }; 1.932 + 1.933 +//DEFINE_LUA_FUNCTION(memory_getregister, "cpu_dot_registername_string") 1.934 + static int memory_getregister(lua_State *L) 1.935 + { 1.936 + const char *qualifiedRegisterName = luaL_checkstring(L, 1); 1.937 + lua_settop(L, 0); 1.938 + for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++) 1.939 + { 1.940 + cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu]; 1.941 + int cpuNameLen = strlen(ctrm.cpuName); 1.942 + if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen)) 1.943 + { 1.944 + qualifiedRegisterName += cpuNameLen; 1.945 + for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++) 1.946 + { 1.947 + registerPointerMap rpm = ctrm.rpmap[reg]; 1.948 + if (!stricmp(qualifiedRegisterName, rpm.registerName)) 1.949 + { 1.950 + switch (rpm.dataSize) 1.951 + { 1.952 + default: 1.953 + case 1: 1.954 + lua_pushinteger(L, *(unsigned char *)rpm.pointer); break; 1.955 + case 2: 1.956 + lua_pushinteger(L, *(unsigned short *)rpm.pointer); break; 1.957 + case 4: 1.958 + lua_pushinteger(L, *(unsigned long *)rpm.pointer); break; 1.959 + } 1.960 + return 1; 1.961 + } 1.962 + } 1.963 + lua_pushnil(L); 1.964 + return 1; 1.965 + } 1.966 + } 1.967 + lua_pushnil(L); 1.968 + return 1; 1.969 + } 1.970 + 1.971 +//DEFINE_LUA_FUNCTION(memory_setregister, "cpu_dot_registername_string,value") 1.972 + static int memory_setregister(lua_State *L) 1.973 + { 1.974 + const char * qualifiedRegisterName = luaL_checkstring(L, 1); 1.975 + unsigned long value = (unsigned long)(luaL_checkinteger(L, 2)); 1.976 + lua_settop(L, 0); 1.977 + for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++) 1.978 + { 1.979 + cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu]; 1.980 + int cpuNameLen = strlen(ctrm.cpuName); 1.981 + if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen)) 1.982 + { 1.983 + qualifiedRegisterName += cpuNameLen; 1.984 + for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++) 1.985 + { 1.986 + registerPointerMap rpm = ctrm.rpmap[reg]; 1.987 + if (!stricmp(qualifiedRegisterName, rpm.registerName)) 1.988 + { 1.989 + switch (rpm.dataSize) 1.990 + { 1.991 + default: 1.992 + case 1: 1.993 + *(unsigned char *)rpm.pointer = (unsigned char)(value & 0xFF); break; 1.994 + case 2: 1.995 + *(unsigned short *)rpm.pointer = (unsigned short)(value & 0xFFFF); break; 1.996 + case 4: 1.997 + *(unsigned long *)rpm.pointer = value; break; 1.998 + } 1.999 + return 0; 1.1000 + } 1.1001 + } 1.1002 + return 0; 1.1003 + } 1.1004 + } 1.1005 + return 0; 1.1006 + } 1.1007 + 1.1008 + void HandleCallbackError(lua_State *L) 1.1009 + { 1.1010 + if (L->errfunc || L->errorJmp) 1.1011 + luaL_error(L, "%s", lua_tostring(L, -1)); 1.1012 + else 1.1013 + { 1.1014 + lua_pushnil(LUA); 1.1015 + lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); 1.1016 + 1.1017 + // Error? 1.1018 +//#if (defined(WIN32) && !defined(SDL)) 1.1019 +// info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer(); 1.1020 +// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua run error", MB_OK | MB_ICONSTOP); 1.1021 +//#else 1.1022 +// fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(LUA, -1)); 1.1023 +//#endif 1.1024 + printerror(LUA, -1); 1.1025 + VBALuaStop(); 1.1026 + } 1.1027 + } 1.1028 + 1.1029 + void CallRegisteredLuaFunctions(LuaCallID calltype) 1.1030 + { 1.1031 + assert((unsigned int)calltype < (unsigned int)LUACALL_COUNT); 1.1032 + 1.1033 + const char *idstring = luaCallIDStrings[calltype]; 1.1034 + 1.1035 + if (!LUA) 1.1036 + return; 1.1037 + 1.1038 + lua_settop(LUA, 0); 1.1039 + lua_getfield(LUA, LUA_REGISTRYINDEX, idstring); 1.1040 + 1.1041 + int errorcode = 0; 1.1042 + if (lua_isfunction(LUA, -1)) 1.1043 + { 1.1044 + errorcode = lua_pcall(LUA, 0, 0, 0); 1.1045 + if (errorcode) 1.1046 + HandleCallbackError(LUA); 1.1047 + } 1.1048 + else 1.1049 + { 1.1050 + lua_pop(LUA, 1); 1.1051 + } 1.1052 + } 1.1053 + 1.1054 +// the purpose of this structure is to provide a way of 1.1055 +// QUICKLY determining whether a memory address range has a hook associated with it, 1.1056 +// with a bias toward fast rejection because the majority of addresses will not be hooked. 1.1057 +// (it must not use any part of Lua or perform any per-script operations, 1.1058 +// otherwise it would definitely be too slow.) 1.1059 +// calculating the regions when a hook is added/removed may be slow, 1.1060 +// but this is an intentional tradeoff to obtain a high speed of checking during later execution 1.1061 + struct TieredRegion 1.1062 + { 1.1063 + template<unsigned int maxGap> 1.1064 + struct Region 1.1065 + { 1.1066 + struct Island 1.1067 + { 1.1068 + unsigned int start; 1.1069 + unsigned int end; 1.1070 + __forceinline bool Contains(unsigned int address, int size) const { return address < end && address + size > start; } 1.1071 + }; 1.1072 + std::vector<Island> islands; 1.1073 + 1.1074 + void Calculate(const std::vector<unsigned int> &bytes) 1.1075 + { 1.1076 + islands. clear(); 1.1077 + 1.1078 + unsigned int lastEnd = ~0; 1.1079 + 1.1080 + std::vector<unsigned int>::const_iterator iter = bytes.begin(); 1.1081 + std::vector<unsigned int>::const_iterator end = bytes.end(); 1.1082 + for (; iter != end; ++iter) 1.1083 + { 1.1084 + unsigned int addr = *iter; 1.1085 + if (addr < lastEnd || addr > lastEnd + (long long)maxGap) 1.1086 + { 1.1087 + islands. push_back(Island()); 1.1088 + islands. back().start = addr; 1.1089 + } 1.1090 + islands.back(). end = addr + 1; 1.1091 + lastEnd = addr + 1; 1.1092 + } 1.1093 + } 1.1094 + 1.1095 + bool Contains(unsigned int address, int size) const 1.1096 + { 1.1097 + for (size_t i = 0; i != islands.size(); ++i) 1.1098 + { 1.1099 + if (islands[i].Contains(address, size)) 1.1100 + return true; 1.1101 + } 1.1102 + return false; 1.1103 + } 1.1104 + }; 1.1105 + 1.1106 + Region<0xFFFFFFFF> broad; 1.1107 + Region<0x1000> mid; 1.1108 + Region<0> narrow; 1.1109 + 1.1110 + void Calculate(std::vector<unsigned int> &bytes) 1.1111 + { 1.1112 + std:: sort(bytes.begin(), bytes.end()); 1.1113 + 1.1114 + broad. Calculate(bytes); 1.1115 + mid. Calculate(bytes); 1.1116 + narrow. Calculate(bytes); 1.1117 + } 1.1118 + 1.1119 + TieredRegion() 1.1120 + { 1.1121 + std::vector <unsigned int> temp; 1.1122 + Calculate(temp); 1.1123 + } 1.1124 + 1.1125 + __forceinline int NotEmpty() 1.1126 + { 1.1127 + return broad.islands.size(); 1.1128 + } 1.1129 + 1.1130 + // note: it is illegal to call this if NotEmpty() returns 0 1.1131 + __forceinline bool Contains(unsigned int address, int size) 1.1132 + { 1.1133 + return broad.islands[0].Contains(address, size) && 1.1134 + mid.Contains(address, size) && 1.1135 + narrow.Contains(address, size); 1.1136 + } 1.1137 + }; 1.1138 + TieredRegion hookedRegions [LUAMEMHOOK_COUNT]; 1.1139 + 1.1140 + static void CalculateMemHookRegions(LuaMemHookType hookType) 1.1141 + { 1.1142 + std::vector<unsigned int> hookedBytes; 1.1143 +// std::map<int, LuaContextInfo*>::iterator iter = luaContextInfo.begin(); 1.1144 +// std::map<int, LuaContextInfo*>::iterator end = luaContextInfo.end(); 1.1145 +// while(iter != end) 1.1146 +// { 1.1147 +// LuaContextInfo& info = *iter->second; 1.1148 + if (/*info.*/ numMemHooks) 1.1149 + { 1.1150 + lua_State *L = LUA /*info.L*/; 1.1151 + if (L) 1.1152 + { 1.1153 + lua_settop(L, 0); 1.1154 + lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); 1.1155 + lua_pushnil(L); 1.1156 + while (lua_next(L, -2)) 1.1157 + { 1.1158 + if (lua_isfunction(L, -1)) 1.1159 + { 1.1160 + unsigned int addr = lua_tointeger(L, -2); 1.1161 + hookedBytes.push_back(addr); 1.1162 + } 1.1163 + lua_pop(L, 1); 1.1164 + } 1.1165 + lua_settop(L, 0); 1.1166 + } 1.1167 + } 1.1168 +// ++iter; 1.1169 +// } 1.1170 + hookedRegions[hookType].Calculate(hookedBytes); 1.1171 + } 1.1172 + 1.1173 + static void CallRegisteredLuaMemHook_LuaMatch(unsigned int address, int size, unsigned int value, LuaMemHookType hookType) 1.1174 + { 1.1175 +// std::map<int, LuaContextInfo*>::iterator iter = luaContextInfo.begin(); 1.1176 +// std::map<int, LuaContextInfo*>::iterator end = luaContextInfo.end(); 1.1177 +// while(iter != end) 1.1178 +// { 1.1179 +// LuaContextInfo& info = *iter->second; 1.1180 + if (/*info.*/ numMemHooks) 1.1181 + { 1.1182 + lua_State *L = LUA /*info.L*/; 1.1183 + if (L /* && !info.panic*/) 1.1184 + { 1.1185 +#ifdef USE_INFO_STACK 1.1186 + infoStack.insert(infoStack.begin(), &info); 1.1187 + struct Scope { ~Scope(){ infoStack. erase(infoStack.begin()); } } scope; 1.1188 +#endif 1.1189 + lua_settop(L, 0); 1.1190 + lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); 1.1191 + for (int i = address; i != address + size; i++) 1.1192 + { 1.1193 + lua_rawgeti(L, -1, i); 1.1194 + if (lua_isfunction(L, -1)) 1.1195 + { 1.1196 + bool wasRunning = (luaRunning != 0) /*info.running*/; 1.1197 + luaRunning /*info.running*/ = true; 1.1198 + //RefreshScriptSpeedStatus(); 1.1199 + lua_pushinteger(L, address); 1.1200 + lua_pushinteger(L, size); 1.1201 + int errorcode = lua_pcall(L, 2, 0, 0); 1.1202 + luaRunning /*info.running*/ = wasRunning; 1.1203 + //RefreshScriptSpeedStatus(); 1.1204 + if (errorcode) 1.1205 + { 1.1206 + HandleCallbackError(L); 1.1207 + //int uid = iter->first; 1.1208 + //HandleCallbackError(L,info,uid,true); 1.1209 + } 1.1210 + break; 1.1211 + } 1.1212 + else 1.1213 + { 1.1214 + lua_pop(L, 1); 1.1215 + } 1.1216 + } 1.1217 + lua_settop(L, 0); 1.1218 + } 1.1219 + } 1.1220 +// ++iter; 1.1221 +// } 1.1222 + } 1.1223 + 1.1224 + void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType) 1.1225 + { 1.1226 + // performance critical! (called VERY frequently) 1.1227 + // I suggest timing a large number of calls to this function in Release if you change anything in here, 1.1228 + // before and after, because even the most innocent change can make it become 30% to 400% slower. 1.1229 + // a good amount to test is: 100000000 calls with no hook set, and another 100000000 with a hook set. 1.1230 + // (on my system that consistently took 200 ms total in the former case and 350 ms total in the latter 1.1231 + // case) 1.1232 + if (hookedRegions[hookType].NotEmpty()) 1.1233 + { 1.1234 + //if((hookType <= LUAMEMHOOK_EXEC) && (address >= 0xE00000)) 1.1235 + // address |= 0xFF0000; // account for mirroring of RAM 1.1236 + if (hookedRegions[hookType].Contains(address, size)) 1.1237 + CallRegisteredLuaMemHook_LuaMatch(address, size, value, hookType); // something has hooked this 1.1238 + // specific address 1.1239 + } 1.1240 + } 1.1241 + 1.1242 + static int memory_registerHook(lua_State *L, LuaMemHookType hookType, int defaultSize) 1.1243 + { 1.1244 + // get first argument: address 1.1245 + unsigned int addr = luaL_checkinteger(L, 1); 1.1246 + //if((addr & ~0xFFFFFF) == ~0xFFFFFF) 1.1247 + // addr &= 0xFFFFFF; 1.1248 + 1.1249 + // get optional second argument: size 1.1250 + int size = defaultSize; 1.1251 + int funcIdx = 2; 1.1252 + if (lua_isnumber(L, 2)) 1.1253 + { 1.1254 + size = luaL_checkinteger(L, 2); 1.1255 + if (size < 0) 1.1256 + { 1.1257 + size = -size; 1.1258 + addr -= size; 1.1259 + } 1.1260 + funcIdx++; 1.1261 + } 1.1262 + 1.1263 + // check last argument: callback function 1.1264 + bool clearing = lua_isnil(L, funcIdx); 1.1265 + if (!clearing) 1.1266 + luaL_checktype(L, funcIdx, LUA_TFUNCTION); 1.1267 + lua_settop(L, funcIdx); 1.1268 + 1.1269 + // get the address-to-callback table for this hook type of the current script 1.1270 + lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]); 1.1271 + 1.1272 + // count how many callback functions we'll be displacing 1.1273 + int numFuncsAfter = clearing ? 0 : size; 1.1274 + int numFuncsBefore = 0; 1.1275 + for (unsigned int i = addr; i != addr + size; i++) 1.1276 + { 1.1277 + lua_rawgeti(L, -1, i); 1.1278 + if (lua_isfunction(L, -1)) 1.1279 + numFuncsBefore++; 1.1280 + lua_pop(L, 1); 1.1281 + } 1.1282 + 1.1283 + // put the callback function in the address slots 1.1284 + for (unsigned int i = addr; i != addr + size; i++) 1.1285 + { 1.1286 + lua_pushvalue(L, -2); 1.1287 + lua_rawseti(L, -2, i); 1.1288 + } 1.1289 + 1.1290 + // adjust the count of active hooks 1.1291 + //LuaContextInfo& info = GetCurrentInfo(); 1.1292 + /*info.*/ numMemHooks += numFuncsAfter - numFuncsBefore; 1.1293 + 1.1294 + // re-cache regions of hooked memory across all scripts 1.1295 + CalculateMemHookRegions(hookType); 1.1296 + 1.1297 + //StopScriptIfFinished(luaStateToUIDMap[L]); 1.1298 + return 0; 1.1299 + } 1.1300 + 1.1301 + LuaMemHookType MatchHookTypeToCPU(lua_State *L, LuaMemHookType hookType) 1.1302 + { 1.1303 + int cpuID = 0; 1.1304 + 1.1305 + int cpunameIndex = 0; 1.1306 + if (lua_type(L, 2) == LUA_TSTRING) 1.1307 + cpunameIndex = 2; 1.1308 + else if (lua_type(L, 3) == LUA_TSTRING) 1.1309 + cpunameIndex = 3; 1.1310 + 1.1311 + if (cpunameIndex) 1.1312 + { 1.1313 + const char *cpuName = lua_tostring(L, cpunameIndex); 1.1314 + if (!stricmp(cpuName, "sub")) 1.1315 + cpuID = 1; 1.1316 + lua_remove(L, cpunameIndex); 1.1317 + } 1.1318 + 1.1319 + switch (cpuID) 1.1320 + { 1.1321 + case 0: 1.1322 + return hookType; 1.1323 + 1.1324 + case 1: 1.1325 + switch (hookType) 1.1326 + { 1.1327 + case LUAMEMHOOK_WRITE: 1.1328 + return LUAMEMHOOK_WRITE_SUB; 1.1329 + case LUAMEMHOOK_READ: 1.1330 + return LUAMEMHOOK_READ_SUB; 1.1331 + case LUAMEMHOOK_EXEC: 1.1332 + return LUAMEMHOOK_EXEC_SUB; 1.1333 + } 1.1334 + } 1.1335 + return hookType; 1.1336 + } 1.1337 + 1.1338 + static int memory_registerwrite(lua_State *L) 1.1339 + { 1.1340 + return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_WRITE), 1); 1.1341 + } 1.1342 + 1.1343 + static int memory_registerread(lua_State *L) 1.1344 + { 1.1345 + return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_READ), 1); 1.1346 + } 1.1347 + 1.1348 + static int memory_registerexec(lua_State *L) 1.1349 + { 1.1350 + return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_EXEC), 1); 1.1351 + } 1.1352 + 1.1353 +//int vba.lagcount 1.1354 +// 1.1355 + 1.1356 +//Returns the lagcounter variable 1.1357 + static int vba_getlagcount(lua_State *L) 1.1358 + { 1.1359 + lua_pushinteger(L, systemCounters.lagCount); 1.1360 + return 1; 1.1361 + } 1.1362 + 1.1363 +//int vba.lagged 1.1364 +// 1.1365 +//Returns true if the current frame is a lag frame 1.1366 + static int vba_lagged(lua_State *L) 1.1367 + { 1.1368 + lua_pushboolean(L, systemCounters.laggedLast); 1.1369 + return 1; 1.1370 + } 1.1371 + 1.1372 +// boolean vba.emulating() 1.1373 + int vba_emulating(lua_State *L) 1.1374 + { 1.1375 + lua_pushboolean(L, systemIsEmulating()); 1.1376 + return 1; 1.1377 + } 1.1378 + 1.1379 + int movie_isactive(lua_State *L) 1.1380 + { 1.1381 + lua_pushboolean(L, VBAMovieActive()); 1.1382 + return 1; 1.1383 + } 1.1384 + 1.1385 + int movie_isrecording(lua_State *L) 1.1386 + { 1.1387 + lua_pushboolean(L, VBAMovieRecording()); 1.1388 + return 1; 1.1389 + } 1.1390 + 1.1391 + int movie_isplaying(lua_State *L) 1.1392 + { 1.1393 + lua_pushboolean(L, VBAMoviePlaying()); 1.1394 + return 1; 1.1395 + } 1.1396 + 1.1397 + int movie_getlength(lua_State *L) 1.1398 + { 1.1399 + if (VBAMovieActive()) 1.1400 + lua_pushinteger(L, VBAMovieGetLength()); 1.1401 + else 1.1402 + lua_pushinteger(L, 0); 1.1403 + return 1; 1.1404 + } 1.1405 + 1.1406 + static int memory_readbyte(lua_State *L) 1.1407 + { 1.1408 + u32 addr; 1.1409 + u8 val; 1.1410 + 1.1411 + addr = luaL_checkinteger(L, 1); 1.1412 + if (systemIsRunningGBA()) 1.1413 + { 1.1414 + val = CPUReadByteQuick(addr); 1.1415 + } 1.1416 + else 1.1417 + { 1.1418 + val = gbReadMemoryQuick8(addr); 1.1419 + } 1.1420 + 1.1421 + lua_pushinteger(L, val); 1.1422 + return 1; 1.1423 + } 1.1424 + 1.1425 + static int memory_readbytesigned(lua_State *L) 1.1426 + { 1.1427 + u32 addr; 1.1428 + s8 val; 1.1429 + 1.1430 + addr = luaL_checkinteger(L, 1); 1.1431 + if (systemIsRunningGBA()) 1.1432 + { 1.1433 + val = (s8) CPUReadByteQuick(addr); 1.1434 + } 1.1435 + else 1.1436 + { 1.1437 + val = (s8) gbReadMemoryQuick8(addr); 1.1438 + } 1.1439 + 1.1440 + lua_pushinteger(L, val); 1.1441 + return 1; 1.1442 + } 1.1443 + 1.1444 + static int memory_readword(lua_State *L) 1.1445 + { 1.1446 + u32 addr; 1.1447 + u16 val; 1.1448 + 1.1449 + addr = luaL_checkinteger(L, 1); 1.1450 + if (systemIsRunningGBA()) 1.1451 + { 1.1452 + val = CPUReadHalfWordQuick(addr); 1.1453 + } 1.1454 + else 1.1455 + { 1.1456 + val = gbReadMemoryQuick16(addr & 0x0000FFFF); 1.1457 + } 1.1458 + 1.1459 + lua_pushinteger(L, val); 1.1460 + return 1; 1.1461 + } 1.1462 + 1.1463 + static int memory_readwordsigned(lua_State *L) 1.1464 + { 1.1465 + u32 addr; 1.1466 + s16 val; 1.1467 + 1.1468 + addr = luaL_checkinteger(L, 1); 1.1469 + if (systemIsRunningGBA()) 1.1470 + { 1.1471 + val = (s16) CPUReadHalfWordQuick(addr); 1.1472 + } 1.1473 + else 1.1474 + { 1.1475 + val = (s16) gbReadMemoryQuick16(addr); 1.1476 + } 1.1477 + 1.1478 + lua_pushinteger(L, val); 1.1479 + return 1; 1.1480 + } 1.1481 + 1.1482 + static int memory_readdword(lua_State *L) 1.1483 + { 1.1484 + u32 addr; 1.1485 + u32 val; 1.1486 + 1.1487 + addr = luaL_checkinteger(L, 1); 1.1488 + if (systemIsRunningGBA()) 1.1489 + { 1.1490 + val = CPUReadMemoryQuick(addr); 1.1491 + } 1.1492 + else 1.1493 + { 1.1494 + val = gbReadMemoryQuick32(addr & 0x0000FFFF); 1.1495 + } 1.1496 + 1.1497 + // lua_pushinteger doesn't work properly for 32bit system, does it? 1.1498 + if (val >= 0x80000000 && sizeof(int) <= 4) 1.1499 + lua_pushnumber(L, val); 1.1500 + else 1.1501 + lua_pushinteger(L, val); 1.1502 + return 1; 1.1503 + } 1.1504 + 1.1505 + static int memory_readdwordsigned(lua_State *L) 1.1506 + { 1.1507 + u32 addr; 1.1508 + s32 val; 1.1509 + 1.1510 + addr = luaL_checkinteger(L, 1); 1.1511 + if (systemIsRunningGBA()) 1.1512 + { 1.1513 + val = (s32) CPUReadMemoryQuick(addr); 1.1514 + } 1.1515 + else 1.1516 + { 1.1517 + val = (s32) gbReadMemoryQuick32(addr); 1.1518 + } 1.1519 + 1.1520 + lua_pushinteger(L, val); 1.1521 + return 1; 1.1522 + } 1.1523 + 1.1524 + static int memory_readbyterange(lua_State *L) 1.1525 + { 1.1526 + uint32 address = luaL_checkinteger(L, 1); 1.1527 + int length = luaL_checkinteger(L, 2); 1.1528 + 1.1529 + if (length < 0) 1.1530 + { 1.1531 + address += length; 1.1532 + length = -length; 1.1533 + } 1.1534 + 1.1535 + // push the array 1.1536 + lua_createtable(L, abs(length), 0); 1.1537 + 1.1538 + // put all the values into the (1-based) array 1.1539 + for (int a = address, n = 1; n <= length; a++, n++) 1.1540 + { 1.1541 + unsigned char value; 1.1542 + 1.1543 + if (systemIsRunningGBA()) 1.1544 + { 1.1545 + value = CPUReadByteQuick(a); 1.1546 + } 1.1547 + else 1.1548 + { 1.1549 + value = gbReadMemoryQuick8(a); 1.1550 + } 1.1551 + 1.1552 + lua_pushinteger(L, value); 1.1553 + lua_rawseti(L, -2, n); 1.1554 + } 1.1555 + 1.1556 + return 1; 1.1557 + } 1.1558 + 1.1559 + static int memory_writebyte(lua_State *L) 1.1560 + { 1.1561 + u32 addr; 1.1562 + int val; 1.1563 + 1.1564 + addr = luaL_checkinteger(L, 1); 1.1565 + val = luaL_checkinteger(L, 2); 1.1566 + if (systemIsRunningGBA()) 1.1567 + { 1.1568 + CPUWriteByteQuick(addr, val); 1.1569 + } 1.1570 + else 1.1571 + { 1.1572 + gbWriteMemoryQuick8(addr, val); 1.1573 + } 1.1574 + 1.1575 + CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE); 1.1576 + return 0; 1.1577 + } 1.1578 + 1.1579 + static int memory_writeword(lua_State *L) 1.1580 + { 1.1581 + u32 addr; 1.1582 + int val; 1.1583 + 1.1584 + addr = luaL_checkinteger(L, 1); 1.1585 + val = luaL_checkinteger(L, 2); 1.1586 + if (systemIsRunningGBA()) 1.1587 + { 1.1588 + CPUWriteHalfWordQuick(addr, val); 1.1589 + } 1.1590 + else 1.1591 + { 1.1592 + gbWriteMemoryQuick16(addr, val); 1.1593 + } 1.1594 + 1.1595 + CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE); 1.1596 + return 0; 1.1597 + } 1.1598 + 1.1599 + static int memory_writedword(lua_State *L) 1.1600 + { 1.1601 + u32 addr; 1.1602 + int val; 1.1603 + 1.1604 + addr = luaL_checkinteger(L, 1); 1.1605 + val = luaL_checkinteger(L, 2); 1.1606 + if (systemIsRunningGBA()) 1.1607 + { 1.1608 + CPUWriteMemoryQuick(addr, val); 1.1609 + } 1.1610 + else 1.1611 + { 1.1612 + gbWriteMemoryQuick32(addr, val); 1.1613 + } 1.1614 + 1.1615 + CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE); 1.1616 + return 0; 1.1617 + } 1.1618 + 1.1619 + static int memory_gbromreadbyte(lua_State *L) 1.1620 + { 1.1621 + u32 addr; 1.1622 + u8 val; 1.1623 + 1.1624 + addr = luaL_checkinteger(L, 1); 1.1625 + if (systemIsRunningGBA()) 1.1626 + { 1.1627 + lua_pushnil(L); 1.1628 + return 1; 1.1629 + } 1.1630 + else 1.1631 + { 1.1632 + val = gbReadROMQuick8(addr); 1.1633 + } 1.1634 + 1.1635 + lua_pushinteger(L, val); 1.1636 + return 1; 1.1637 + } 1.1638 + 1.1639 + static int memory_gbromreadbytesigned(lua_State *L) 1.1640 + { 1.1641 + u32 addr; 1.1642 + s8 val; 1.1643 + 1.1644 + addr = luaL_checkinteger(L, 1); 1.1645 + if (systemIsRunningGBA()) 1.1646 + { 1.1647 + lua_pushnil(L); 1.1648 + return 1; 1.1649 + } 1.1650 + else 1.1651 + { 1.1652 + val = (s8) gbReadROMQuick8(addr); 1.1653 + } 1.1654 + 1.1655 + lua_pushinteger(L, val); 1.1656 + return 1; 1.1657 + } 1.1658 + 1.1659 + static int memory_gbromreadword(lua_State *L) 1.1660 + { 1.1661 + u32 addr; 1.1662 + u16 val; 1.1663 + 1.1664 + addr = luaL_checkinteger(L, 1); 1.1665 + if (systemIsRunningGBA()) 1.1666 + { 1.1667 + lua_pushnil(L); 1.1668 + return 1; 1.1669 + } 1.1670 + else 1.1671 + { 1.1672 + val = gbReadROMQuick16(addr); 1.1673 + } 1.1674 + 1.1675 + lua_pushinteger(L, val); 1.1676 + return 1; 1.1677 + } 1.1678 + 1.1679 + static int memory_gbromreadwordsigned(lua_State *L) 1.1680 + { 1.1681 + u32 addr; 1.1682 + s16 val; 1.1683 + 1.1684 + addr = luaL_checkinteger(L, 1); 1.1685 + if (systemIsRunningGBA()) 1.1686 + { 1.1687 + lua_pushnil(L); 1.1688 + return 1; 1.1689 + } 1.1690 + else 1.1691 + { 1.1692 + val = (s16) gbReadROMQuick16(addr); 1.1693 + } 1.1694 + 1.1695 + lua_pushinteger(L, val); 1.1696 + return 1; 1.1697 + } 1.1698 + 1.1699 + static int memory_gbromreaddword(lua_State *L) 1.1700 + { 1.1701 + u32 addr; 1.1702 + u32 val; 1.1703 + 1.1704 + addr = luaL_checkinteger(L, 1); 1.1705 + if (systemIsRunningGBA()) 1.1706 + { 1.1707 + lua_pushnil(L); 1.1708 + return 1; 1.1709 + } 1.1710 + else 1.1711 + { 1.1712 + val = gbReadROMQuick32(addr); 1.1713 + } 1.1714 + 1.1715 + // lua_pushinteger doesn't work properly for 32bit system, does it? 1.1716 + if (val >= 0x80000000 && sizeof(int) <= 4) 1.1717 + lua_pushnumber(L, val); 1.1718 + else 1.1719 + lua_pushinteger(L, val); 1.1720 + return 1; 1.1721 + } 1.1722 + 1.1723 + static int memory_gbromreaddwordsigned(lua_State *L) 1.1724 + { 1.1725 + u32 addr; 1.1726 + s32 val; 1.1727 + 1.1728 + addr = luaL_checkinteger(L, 1); 1.1729 + if (systemIsRunningGBA()) 1.1730 + { 1.1731 + lua_pushnil(L); 1.1732 + return 1; 1.1733 + } 1.1734 + else 1.1735 + { 1.1736 + val = (s32) gbReadROMQuick32(addr); 1.1737 + } 1.1738 + 1.1739 + lua_pushinteger(L, val); 1.1740 + return 1; 1.1741 + } 1.1742 + 1.1743 + static int memory_gbromreadbyterange(lua_State *L) 1.1744 + { 1.1745 + uint32 address = luaL_checkinteger(L, 1); 1.1746 + int length = luaL_checkinteger(L, 2); 1.1747 + 1.1748 + if (length < 0) 1.1749 + { 1.1750 + address += length; 1.1751 + length = -length; 1.1752 + } 1.1753 + 1.1754 + // push the array 1.1755 + lua_createtable(L, abs(length), 0); 1.1756 + 1.1757 + // put all the values into the (1-based) array 1.1758 + for (int a = address, n = 1; n <= length; a++, n++) 1.1759 + { 1.1760 + unsigned char value; 1.1761 + 1.1762 + if (systemIsRunningGBA()) 1.1763 + { 1.1764 + lua_pushnil(L); 1.1765 + return 1; 1.1766 + } 1.1767 + else 1.1768 + { 1.1769 + value = gbReadROMQuick8(a); 1.1770 + } 1.1771 + 1.1772 + lua_pushinteger(L, value); 1.1773 + lua_rawseti(L, -2, n); 1.1774 + } 1.1775 + 1.1776 + return 1; 1.1777 + } 1.1778 + 1.1779 +// table joypad.get(int which = 1) 1.1780 +// 1.1781 +// Reads the joypads as inputted by the user. 1.1782 + static int joy_get_internal(lua_State *L, bool reportUp, bool reportDown) 1.1783 + { 1.1784 + // Reads the joypads as inputted by the user 1.1785 + int which = luaL_checkinteger(L, 1); 1.1786 + 1.1787 + if (which < 0 || which > 4) 1.1788 + { 1.1789 + luaL_error(L, "Invalid input port (valid range 0-4, specified %d)", which); 1.1790 + } 1.1791 + 1.1792 + uint32 buttons = systemGetOriginalJoypad(which - 1, false); 1.1793 + 1.1794 + lua_newtable(L); 1.1795 + 1.1796 + int i; 1.1797 + for (i = 0; i < 10; i++) 1.1798 + { 1.1799 + bool pressed = (buttons & (1 << i)) != 0; 1.1800 + if ((pressed && reportDown) || (!pressed && reportUp)) 1.1801 + { 1.1802 + lua_pushboolean(L, pressed); 1.1803 + lua_setfield(L, -2, button_mappings[i]); 1.1804 + } 1.1805 + } 1.1806 + 1.1807 + return 1; 1.1808 + } 1.1809 + 1.1810 +// joypad.get(which) 1.1811 +// returns a table of every game button, 1.1812 +// true meaning currently-held and false meaning not-currently-held 1.1813 +// (as of last frame boundary) 1.1814 +// this WILL read input from a currently-playing movie 1.1815 + static int joypad_get(lua_State *L) 1.1816 + { 1.1817 + return joy_get_internal(L, true, true); 1.1818 + } 1.1819 + 1.1820 +// joypad.getdown(which) 1.1821 +// returns a table of every game button that is currently held 1.1822 + static int joypad_getdown(lua_State *L) 1.1823 + { 1.1824 + return joy_get_internal(L, false, true); 1.1825 + } 1.1826 + 1.1827 +// joypad.getup(which) 1.1828 +// returns a table of every game button that is not currently held 1.1829 + static int joypad_getup(lua_State *L) 1.1830 + { 1.1831 + return joy_get_internal(L, true, false); 1.1832 + } 1.1833 + 1.1834 +// joypad.set(int which, table buttons) 1.1835 +// 1.1836 +// Sets the given buttons to be pressed during the next 1.1837 +// frame advance. The table should have the right 1.1838 + 1.1839 +// keys (no pun intended) set. 1.1840 + static int joypad_set(lua_State *L) 1.1841 + { 1.1842 + // Which joypad we're tampering with 1.1843 + int which = luaL_checkinteger(L, 1); 1.1844 + if (which < 0 || which > 4) 1.1845 + { 1.1846 + luaL_error(L, "Invalid output port (valid range 0-4, specified %d)", which); 1.1847 + } 1.1848 + 1.1849 + if (which == 0) 1.1850 + which = systemGetDefaultJoypad(); 1.1851 + 1.1852 + // And the table of buttons. 1.1853 + luaL_checktype(L, 2, LUA_TTABLE); 1.1854 + 1.1855 + // Set up for taking control of the indicated controller 1.1856 + lua_joypads_used |= 1 << (which - 1); 1.1857 + lua_joypads[which - 1] = 0; 1.1858 + 1.1859 + for (int i = 0; i < 10; i++) 1.1860 + { 1.1861 + const char *name = button_mappings[i]; 1.1862 + lua_getfield(L, 2, name); 1.1863 + if (!lua_isnil(L, -1)) 1.1864 + { 1.1865 + bool pressed = lua_toboolean(L, -1) != 0; 1.1866 + if (pressed) 1.1867 + lua_joypads[which - 1] |= 1 << i; 1.1868 + else 1.1869 + lua_joypads[which - 1] &= ~(1 << i); 1.1870 + } 1.1871 + lua_pop(L, 1); 1.1872 + } 1.1873 + 1.1874 + return 0; 1.1875 + } 1.1876 + 1.1877 +// Helper function to convert a savestate object to the filename it represents. 1.1878 + static const char *savestateobj2filename(lua_State *L, int offset) 1.1879 + { 1.1880 + // First we get the metatable of the indicated object 1.1881 + int result = lua_getmetatable(L, offset); 1.1882 + 1.1883 + if (!result) 1.1884 + luaL_error(L, "object not a savestate object"); 1.1885 + 1.1886 + // Also check that the type entry is set 1.1887 + lua_getfield(L, -1, "__metatable"); 1.1888 + if (strcmp(lua_tostring(L, -1), "vba Savestate") != 0) 1.1889 + luaL_error(L, "object not a savestate object"); 1.1890 + lua_pop(L, 1); 1.1891 + 1.1892 + // Now, get the field we want 1.1893 + lua_getfield(L, -1, "filename"); 1.1894 + 1.1895 + // Return it 1.1896 + return lua_tostring(L, -1); 1.1897 + } 1.1898 + 1.1899 +// Helper function for garbage collection. 1.1900 + static int savestate_gc(lua_State *L) 1.1901 + { 1.1902 + // The object we're collecting is on top of the stack 1.1903 + lua_getmetatable(L, 1); 1.1904 + 1.1905 + // Get the filename 1.1906 + const char *filename; 1.1907 + lua_getfield(L, -1, "filename"); 1.1908 + filename = lua_tostring(L, -1); 1.1909 + 1.1910 + // Delete the file 1.1911 + remove(filename); 1.1912 + 1.1913 + // We exit, and the garbage collector takes care of the rest. 1.1914 + // Edit: Visual Studio needs a return value anyway, so returns 0. 1.1915 + return 0; 1.1916 + } 1.1917 + 1.1918 +// object savestate.create(int which = nil) 1.1919 +// 1.1920 +// Creates an object used for savestates. 1.1921 +// The object can be associated with a player-accessible savestate 1.1922 + 1.1923 +// ("which" between 1 and 12) or not (which == nil). 1.1924 + static int savestate_create(lua_State *L) 1.1925 + { 1.1926 + int which = -1; 1.1927 + if (lua_gettop(L) >= 1) 1.1928 + { 1.1929 + which = luaL_checkinteger(L, 1); 1.1930 + if (which < 1 || which > 12) 1.1931 + { 1.1932 + luaL_error(L, "invalid player's savestate %d", which); 1.1933 + } 1.1934 + } 1.1935 + 1.1936 + char stateName[2048]; 1.1937 + 1.1938 + if (which > 0) 1.1939 + { 1.1940 + // Find an appropriate filename. This is OS specific, unfortunately. 1.1941 +#if (defined(WIN32) && !defined(SDL)) 1.1942 + CString stateName = winGetSavestateFilename(theApp.gameFilename, which); 1.1943 +#else 1.1944 + extern char saveDir[2048]; 1.1945 + extern char filename[2048]; 1.1946 + extern char *sdlGetFilename(char *name); 1.1947 + 1.1948 + if (saveDir[0]) 1.1949 + sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename), which); 1.1950 + else 1.1951 + sprintf(stateName, "%s%d.sgm", filename, which); 1.1952 +#endif 1.1953 + } 1.1954 + else 1.1955 + { 1.1956 + char *stateNameTemp = tempnam(NULL, "snlua"); 1.1957 + strcpy(stateName, stateNameTemp); 1.1958 + if (stateNameTemp) 1.1959 + free(stateNameTemp); 1.1960 + } 1.1961 + 1.1962 + // Our "object". We don't care about the type, we just need the memory and GC services. 1.1963 + lua_newuserdata(L, 1); 1.1964 + 1.1965 + // The metatable we use, protected from Lua and contains garbage collection info and stuff. 1.1966 + lua_newtable(L); 1.1967 + 1.1968 + // First, we must protect it 1.1969 + lua_pushstring(L, "vba Savestate"); 1.1970 + lua_setfield(L, -2, "__metatable"); 1.1971 + 1.1972 + // Now we need to save the file itself. 1.1973 + lua_pushstring(L, stateName); 1.1974 + lua_setfield(L, -2, "filename"); 1.1975 + 1.1976 + // If it's an anonymous savestate, we must delete the file from disk should it be gargage collected 1.1977 + if (which < 0) 1.1978 + { 1.1979 + lua_pushcfunction(L, savestate_gc); 1.1980 + lua_setfield(L, -2, "__gc"); 1.1981 + } 1.1982 + 1.1983 + // Set the metatable 1.1984 + lua_setmetatable(L, -2); 1.1985 + 1.1986 + // Awesome. Return the object 1.1987 + return 1; 1.1988 + } 1.1989 + 1.1990 +// savestate.save(object state) 1.1991 +// 1.1992 + 1.1993 +// Saves a state to the given object. 1.1994 + static int savestate_save(lua_State *L) 1.1995 + { 1.1996 + const char *filename = savestateobj2filename(L, 1); 1.1997 + 1.1998 + // printf("saving %s\n", filename); 1.1999 + // Save states are very expensive. They take time. 1.2000 + numTries--; 1.2001 + 1.2002 + bool8 retvalue = theEmulator.emuWriteState ? theEmulator.emuWriteState(filename) : false; 1.2003 + if (!retvalue) 1.2004 + { 1.2005 + // Uh oh 1.2006 + luaL_error(L, "savestate failed"); 1.2007 + } 1.2008 + 1.2009 + return 0; 1.2010 + } 1.2011 + 1.2012 +// savestate.load(object state) 1.2013 +// 1.2014 + 1.2015 +// Loads the given state 1.2016 + static int savestate_load(lua_State *L) 1.2017 + { 1.2018 + const char *filename = savestateobj2filename(L, 1); 1.2019 + 1.2020 + numTries--; 1.2021 + 1.2022 + // printf("loading %s\n", filename); 1.2023 + bool8 retvalue = theEmulator.emuReadState ? theEmulator.emuReadState(filename) : false; 1.2024 + if (!retvalue) 1.2025 + { 1.2026 + // Uh oh 1.2027 + luaL_error(L, "loadstate failed"); 1.2028 + } 1.2029 + 1.2030 + return 0; 1.2031 + } 1.2032 + 1.2033 +// int vba.framecount() 1.2034 +// 1.2035 + 1.2036 +// Gets the frame counter for the movie, or the number of frames since last reset. 1.2037 + int vba_framecount(lua_State *L) 1.2038 + { 1.2039 + if (!VBAMovieActive()) 1.2040 + { 1.2041 + lua_pushinteger(L, systemCounters.frameCount); 1.2042 + } 1.2043 + else 1.2044 + { 1.2045 + lua_pushinteger(L, VBAMovieGetFrameCounter()); 1.2046 + } 1.2047 + 1.2048 + return 1; 1.2049 + } 1.2050 + 1.2051 +//string movie.getauthor 1.2052 +// 1.2053 + 1.2054 +// returns author info field of .vbm file 1.2055 + int movie_getauthor(lua_State *L) 1.2056 + { 1.2057 + if (!VBAMovieActive()) 1.2058 + { 1.2059 + //lua_pushnil(L); 1.2060 + lua_pushstring(L, ""); 1.2061 + return 1; 1.2062 + } 1.2063 + 1.2064 + lua_pushstring(L, VBAMovieGetAuthorInfo().c_str()); 1.2065 + return 1; 1.2066 + } 1.2067 + 1.2068 +//string movie.filename 1.2069 + int movie_getfilename(lua_State *L) 1.2070 + { 1.2071 + if (!VBAMovieActive()) 1.2072 + { 1.2073 + //lua_pushnil(L); 1.2074 + lua_pushstring(L, ""); 1.2075 + return 1; 1.2076 + } 1.2077 + 1.2078 + lua_pushstring(L, VBAMovieGetFilename().c_str()); 1.2079 + return 1; 1.2080 + } 1.2081 + 1.2082 +// string movie.mode() 1.2083 +// 1.2084 + 1.2085 +// "record", "playback" or nil 1.2086 + int movie_getmode(lua_State *L) 1.2087 + { 1.2088 + assert(!VBAMovieLoading()); 1.2089 + if (!VBAMovieActive()) 1.2090 + { 1.2091 + lua_pushnil(L); 1.2092 + return 1; 1.2093 + } 1.2094 + 1.2095 + if (VBAMovieRecording()) 1.2096 + lua_pushstring(L, "record"); 1.2097 + else 1.2098 + lua_pushstring(L, "playback"); 1.2099 + return 1; 1.2100 + } 1.2101 + 1.2102 + static int movie_rerecordcount(lua_State *L) 1.2103 + { 1.2104 + if (VBAMovieActive()) 1.2105 + lua_pushinteger(L, VBAMovieGetRerecordCount()); 1.2106 + else 1.2107 + lua_pushinteger(L, 0); 1.2108 + return 1; 1.2109 + } 1.2110 + 1.2111 + static int movie_setrerecordcount(lua_State *L) 1.2112 + { 1.2113 + if (VBAMovieActive()) 1.2114 + VBAMovieSetRerecordCount(luaL_checkinteger(L, 1)); 1.2115 + return 0; 1.2116 + } 1.2117 + 1.2118 + static int movie_rerecordcounting(lua_State *L) 1.2119 + { 1.2120 + if (lua_gettop(L) == 0) 1.2121 + luaL_error(L, "no parameters specified"); 1.2122 + 1.2123 + skipRerecords = lua_toboolean(L, 1); 1.2124 + return 0; 1.2125 + } 1.2126 + 1.2127 +// movie.stop() 1.2128 +// 1.2129 + 1.2130 +// Stops movie playback/recording. Bombs out if movie is not running. 1.2131 + static int movie_stop(lua_State *L) 1.2132 + { 1.2133 + if (!VBAMovieActive()) 1.2134 + luaL_error(L, "no movie"); 1.2135 + 1.2136 + VBAMovieStop(false); 1.2137 + return 0; 1.2138 + } 1.2139 + 1.2140 +#define LUA_SCREEN_WIDTH 256 1.2141 +#define LUA_SCREEN_HEIGHT 239 1.2142 + 1.2143 +// Common code by the gui library: make sure the screen array is ready 1.2144 + static void gui_prepare(void) 1.2145 + { 1.2146 + if (!gui_data) 1.2147 + gui_data = (uint8 *)malloc(LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4); 1.2148 + if (!gui_used) 1.2149 + memset(gui_data, 0, LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4); 1.2150 + gui_used = true; 1.2151 + } 1.2152 + 1.2153 +// pixform for lua graphics 1.2154 +#define BUILD_PIXEL_ARGB8888(A, R, G, B) (((int)(A) << 24) | ((int)(R) << 16) | ((int)(G) << 8) | (int)(B)) 1.2155 +#define DECOMPOSE_PIXEL_ARGB8888(PIX, A, R, G, B) \ 1.2156 + { \ 1.2157 + (A) = ((PIX) >> 24) & 0xff; \ 1.2158 + (R) = ((PIX) >> 16) & 0xff; \ 1.2159 + (G) = ((PIX) >> 8) & 0xff; \ 1.2160 + (B) = (PIX) & 0xff; \ 1.2161 + } 1.2162 +#define LUA_BUILD_PIXEL BUILD_PIXEL_ARGB8888 1.2163 +#define LUA_DECOMPOSE_PIXEL DECOMPOSE_PIXEL_ARGB8888 1.2164 +#define LUA_PIXEL_A(PIX) (((PIX) >> 24) & 0xff) 1.2165 +#define LUA_PIXEL_R(PIX) (((PIX) >> 16) & 0xff) 1.2166 +#define LUA_PIXEL_G(PIX) (((PIX) >> 8) & 0xff) 1.2167 +#define LUA_PIXEL_B(PIX) ((PIX) & 0xff) 1.2168 + 1.2169 + template<class T> 1.2170 + static void swap(T &one, T &two) 1.2171 + { 1.2172 + T temp = one; 1.2173 + one = two; 1.2174 + two = temp; 1.2175 + } 1.2176 + 1.2177 +// write a pixel to buffer 1.2178 + static inline void blend32(uint32 *dstPixel, uint32 colour) 1.2179 + { 1.2180 + uint8 *dst = (uint8 *)dstPixel; 1.2181 + int a, r, g, b; 1.2182 + LUA_DECOMPOSE_PIXEL(colour, a, r, g, b); 1.2183 + 1.2184 + if (a == 255 || dst[3] == 0) 1.2185 + { 1.2186 + // direct copy 1.2187 + *(uint32 *) (dst) = colour; 1.2188 + } 1.2189 + else if (a == 0) 1.2190 + { 1.2191 + // do not copy 1.2192 + } 1.2193 + else 1.2194 + { 1.2195 + // alpha-blending 1.2196 + int a_dst = ((255 - a) * dst[3] + 128) / 255; 1.2197 + int a_new = a + a_dst; 1.2198 + 1.2199 + dst[0] = (uint8) (((dst[0] * a_dst + b * a) + (a_new / 2)) / a_new); 1.2200 + dst[1] = (uint8) (((dst[1] * a_dst + g * a) + (a_new / 2)) / a_new); 1.2201 + dst[2] = (uint8) (((dst[2] * a_dst + r * a) + (a_new / 2)) / a_new); 1.2202 + dst[3] = (uint8) a_new; 1.2203 + } 1.2204 + } 1.2205 + 1.2206 +// check if a pixel is in the lua canvas 1.2207 + static inline bool gui_check_boundary(int x, int y) 1.2208 + { 1.2209 + return !(x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= LUA_SCREEN_HEIGHT); 1.2210 + } 1.2211 + 1.2212 +// check if any part of a box is in the lua canvas 1.2213 + static inline bool gui_checkbox(int x1, int y1, int x2, int y2) 1.2214 + { 1.2215 + if ((x1 < 0 && x2 < 0) 1.2216 + || (x1 >= LUA_SCREEN_WIDTH && x2 >= LUA_SCREEN_WIDTH) 1.2217 + || (y1 < 0 && y2 < 0) 1.2218 + || (y1 >= LUA_SCREEN_HEIGHT && y2 >= LUA_SCREEN_HEIGHT)) 1.2219 + return false; 1.2220 + return true; 1.2221 + } 1.2222 + 1.2223 +// write a pixel to gui_data (do not check boundaries for speedup) 1.2224 + static inline void gui_drawpixel_fast(int x, int y, uint32 colour) 1.2225 + { 1.2226 + //gui_prepare(); 1.2227 + blend32((uint32 *) &gui_data[(y * LUA_SCREEN_WIDTH + x) * 4], colour); 1.2228 + } 1.2229 + 1.2230 +// write a pixel to gui_data (check boundaries) 1.2231 + static inline void gui_drawpixel_internal(int x, int y, uint32 colour) 1.2232 + { 1.2233 + //gui_prepare(); 1.2234 + if (gui_check_boundary(x, y)) 1.2235 + gui_drawpixel_fast(x, y, colour); 1.2236 + } 1.2237 + 1.2238 +// draw a line on gui_data (checks boundaries) 1.2239 + static void gui_drawline_internal(int x1, int y1, int x2, int y2, bool lastPixel, uint32 colour) 1.2240 + { 1.2241 + //gui_prepare(); 1.2242 + // Note: New version of Bresenham's Line Algorithm 1.2243 + // 1.2244 + // 1.2245 + // http://groups.google.co.jp/group/rec.games.roguelike.development/browse_thread/thread/345f4c42c3b25858/29e07a3af3a450e6?show_docid=29e07a3af3a450e6 1.2246 + int swappedx = 0; 1.2247 + int swappedy = 0; 1.2248 + 1.2249 + int xtemp = x1 - x2; 1.2250 + int ytemp = y1 - y2; 1.2251 + if (xtemp == 0 && ytemp == 0) 1.2252 + { 1.2253 + gui_drawpixel_internal(x1, y1, colour); 1.2254 + return; 1.2255 + } 1.2256 + 1.2257 + if (xtemp < 0) 1.2258 + { 1.2259 + xtemp = -xtemp; 1.2260 + swappedx = 1; 1.2261 + } 1.2262 + 1.2263 + if (ytemp < 0) 1.2264 + { 1.2265 + ytemp = -ytemp; 1.2266 + swappedy = 1; 1.2267 + } 1.2268 + 1.2269 + int delta_x = xtemp << 1; 1.2270 + int delta_y = ytemp << 1; 1.2271 + 1.2272 + signed char ix = x1 > x2 ? 1 : -1; 1.2273 + signed char iy = y1 > y2 ? 1 : -1; 1.2274 + 1.2275 + if (lastPixel) 1.2276 + gui_drawpixel_internal(x2, y2, colour); 1.2277 + 1.2278 + if (delta_x >= delta_y) 1.2279 + { 1.2280 + int error = delta_y - (delta_x >> 1); 1.2281 + 1.2282 + while (x2 != x1) 1.2283 + { 1.2284 + if (error == 0 && !swappedx) 1.2285 + gui_drawpixel_internal(x2 + ix, y2, colour); 1.2286 + if (error >= 0) 1.2287 + { 1.2288 + if (error || (ix > 0)) 1.2289 + { 1.2290 + y2 += iy; 1.2291 + error -= delta_x; 1.2292 + } 1.2293 + } 1.2294 + 1.2295 + x2 += ix; 1.2296 + gui_drawpixel_internal(x2, y2, colour); 1.2297 + if (error == 0 && swappedx) 1.2298 + gui_drawpixel_internal(x2, y2 + iy, colour); 1.2299 + error += delta_y; 1.2300 + } 1.2301 + } 1.2302 + else 1.2303 + { 1.2304 + int error = delta_x - (delta_y >> 1); 1.2305 + 1.2306 + while (y2 != y1) 1.2307 + { 1.2308 + if (error == 0 && !swappedy) 1.2309 + gui_drawpixel_internal(x2, y2 + iy, colour); 1.2310 + if (error >= 0) 1.2311 + { 1.2312 + if (error || (iy > 0)) 1.2313 + { 1.2314 + x2 += ix; 1.2315 + error -= delta_y; 1.2316 + } 1.2317 + } 1.2318 + 1.2319 + y2 += iy; 1.2320 + gui_drawpixel_internal(x2, y2, colour); 1.2321 + if (error == 0 && swappedy) 1.2322 + gui_drawpixel_internal(x2 + ix, y2, colour); 1.2323 + error += delta_x; 1.2324 + } 1.2325 + } 1.2326 + } 1.2327 + 1.2328 +// draw a rect on gui_data 1.2329 + static void gui_drawbox_internal(int x1, int y1, int x2, int y2, uint32 colour) 1.2330 + { 1.2331 + if (x1 > x2) 1.2332 + std::swap(x1, x2); 1.2333 + if (y1 > y2) 1.2334 + std::swap(y1, y2); 1.2335 + if (x1 < 0) 1.2336 + x1 = -1; 1.2337 + if (y1 < 0) 1.2338 + y1 = -1; 1.2339 + if (x2 >= LUA_SCREEN_WIDTH) 1.2340 + x2 = LUA_SCREEN_WIDTH; 1.2341 + if (y2 >= LUA_SCREEN_HEIGHT) 1.2342 + y2 = LUA_SCREEN_HEIGHT; 1.2343 + 1.2344 + if (!gui_checkbox(x1, y1, x2, y2)) 1.2345 + return; 1.2346 + 1.2347 + //gui_prepare(); 1.2348 + gui_drawline_internal(x1, y1, x2, y1, true, colour); 1.2349 + gui_drawline_internal(x1, y2, x2, y2, true, colour); 1.2350 + gui_drawline_internal(x1, y1, x1, y2, true, colour); 1.2351 + gui_drawline_internal(x2, y1, x2, y2, true, colour); 1.2352 + } 1.2353 + 1.2354 +// draw a circle on gui_data 1.2355 + static void gui_drawcircle_internal(int x0, int y0, int radius, uint32 colour) 1.2356 + { 1.2357 + //gui_prepare(); 1.2358 + if (radius < 0) 1.2359 + radius = -radius; 1.2360 + if (radius == 0) 1.2361 + return; 1.2362 + if (radius == 1) 1.2363 + { 1.2364 + gui_drawpixel_internal(x0, y0, colour); 1.2365 + return; 1.2366 + } 1.2367 + 1.2368 + // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm 1.2369 + int f = 1 - radius; 1.2370 + int ddF_x = 1; 1.2371 + int ddF_y = -2 * radius; 1.2372 + int x = 0; 1.2373 + int y = radius; 1.2374 + 1.2375 + if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius)) 1.2376 + return; 1.2377 + 1.2378 + gui_drawpixel_internal(x0, y0 + radius, colour); 1.2379 + gui_drawpixel_internal(x0, y0 - radius, colour); 1.2380 + gui_drawpixel_internal(x0 + radius, y0, colour); 1.2381 + gui_drawpixel_internal(x0 - radius, y0, colour); 1.2382 + 1.2383 + // same pixel shouldn't be drawed twice, 1.2384 + // because each pixel has opacity. 1.2385 + // so now the routine gets ugly. 1.2386 + while (true) 1.2387 + { 1.2388 + assert(ddF_x == 2 * x + 1); 1.2389 + assert(ddF_y == -2 * y); 1.2390 + assert(f == x * x + y * y - radius * radius + 2 * x - y + 1); 1.2391 + if (f >= 0) 1.2392 + { 1.2393 + y--; 1.2394 + ddF_y += 2; 1.2395 + f += ddF_y; 1.2396 + } 1.2397 + 1.2398 + x++; 1.2399 + ddF_x += 2; 1.2400 + f += ddF_x; 1.2401 + if (x < y) 1.2402 + { 1.2403 + gui_drawpixel_internal(x0 + x, y0 + y, colour); 1.2404 + gui_drawpixel_internal(x0 - x, y0 + y, colour); 1.2405 + gui_drawpixel_internal(x0 + x, y0 - y, colour); 1.2406 + gui_drawpixel_internal(x0 - x, y0 - y, colour); 1.2407 + gui_drawpixel_internal(x0 + y, y0 + x, colour); 1.2408 + gui_drawpixel_internal(x0 - y, y0 + x, colour); 1.2409 + gui_drawpixel_internal(x0 + y, y0 - x, colour); 1.2410 + gui_drawpixel_internal(x0 - y, y0 - x, colour); 1.2411 + } 1.2412 + else if (x == y) 1.2413 + { 1.2414 + gui_drawpixel_internal(x0 + x, y0 + y, colour); 1.2415 + gui_drawpixel_internal(x0 - x, y0 + y, colour); 1.2416 + gui_drawpixel_internal(x0 + x, y0 - y, colour); 1.2417 + gui_drawpixel_internal(x0 - x, y0 - y, colour); 1.2418 + break; 1.2419 + } 1.2420 + else 1.2421 + break; 1.2422 + } 1.2423 + } 1.2424 + 1.2425 +// draw fill rect on gui_data 1.2426 + static void gui_fillbox_internal(int x1, int y1, int x2, int y2, uint32 colour) 1.2427 + { 1.2428 + if (x1 > x2) 1.2429 + std::swap(x1, x2); 1.2430 + if (y1 > y2) 1.2431 + std::swap(y1, y2); 1.2432 + if (x1 < 0) 1.2433 + x1 = 0; 1.2434 + if (y1 < 0) 1.2435 + y1 = 0; 1.2436 + if (x2 >= LUA_SCREEN_WIDTH) 1.2437 + x2 = LUA_SCREEN_WIDTH - 1; 1.2438 + if (y2 >= LUA_SCREEN_HEIGHT) 1.2439 + y2 = LUA_SCREEN_HEIGHT - 1; 1.2440 + 1.2441 + //gui_prepare(); 1.2442 + int ix, iy; 1.2443 + for (iy = y1; iy <= y2; iy++) 1.2444 + { 1.2445 + for (ix = x1; ix <= x2; ix++) 1.2446 + { 1.2447 + gui_drawpixel_fast(ix, iy, colour); 1.2448 + } 1.2449 + } 1.2450 + } 1.2451 + 1.2452 +// fill a circle on gui_data 1.2453 + static void gui_fillcircle_internal(int x0, int y0, int radius, uint32 colour) 1.2454 + { 1.2455 + //gui_prepare(); 1.2456 + if (radius < 0) 1.2457 + radius = -radius; 1.2458 + if (radius == 0) 1.2459 + return; 1.2460 + if (radius == 1) 1.2461 + { 1.2462 + gui_drawpixel_internal(x0, y0, colour); 1.2463 + return; 1.2464 + } 1.2465 + 1.2466 + // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm 1.2467 + int f = 1 - radius; 1.2468 + int ddF_x = 1; 1.2469 + int ddF_y = -2 * radius; 1.2470 + int x = 0; 1.2471 + int y = radius; 1.2472 + 1.2473 + if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius)) 1.2474 + return; 1.2475 + 1.2476 + gui_drawline_internal(x0, y0 - radius, x0, y0 + radius, true, colour); 1.2477 + 1.2478 + while (true) 1.2479 + { 1.2480 + assert(ddF_x == 2 * x + 1); 1.2481 + assert(ddF_y == -2 * y); 1.2482 + assert(f == x * x + y * y - radius * radius + 2 * x - y + 1); 1.2483 + if (f >= 0) 1.2484 + { 1.2485 + y--; 1.2486 + ddF_y += 2; 1.2487 + f += ddF_y; 1.2488 + } 1.2489 + 1.2490 + x++; 1.2491 + ddF_x += 2; 1.2492 + f += ddF_x; 1.2493 + 1.2494 + if (x < y) 1.2495 + { 1.2496 + gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour); 1.2497 + gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour); 1.2498 + if (f >= 0) 1.2499 + { 1.2500 + gui_drawline_internal(x0 + y, y0 - x, x0 + y, y0 + x, true, colour); 1.2501 + gui_drawline_internal(x0 - y, y0 - x, x0 - y, y0 + x, true, colour); 1.2502 + } 1.2503 + } 1.2504 + else if (x == y) 1.2505 + { 1.2506 + gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour); 1.2507 + gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour); 1.2508 + break; 1.2509 + } 1.2510 + else 1.2511 + break; 1.2512 + } 1.2513 + } 1.2514 + 1.2515 +// Helper for a simple hex parser 1.2516 + static int hex2int(lua_State *L, char c) 1.2517 + { 1.2518 + if (c >= '0' && c <= '9') 1.2519 + return c - '0'; 1.2520 + if (c >= 'a' && c <= 'f') 1.2521 + return c - 'a' + 10; 1.2522 + if (c >= 'A' && c <= 'F') 1.2523 + return c - 'A' + 10; 1.2524 + return luaL_error(L, "invalid hex in colour"); 1.2525 + } 1.2526 + 1.2527 + static const struct ColorMapping 1.2528 + { 1.2529 + const char *name; 1.2530 + int value; 1.2531 + } 1.2532 + s_colorMapping[] = 1.2533 + { 1.2534 + { "white", 0xFFFFFFFF }, 1.2535 + { "black", 0x000000FF }, 1.2536 + { "clear", 0x00000000 }, 1.2537 + { "gray", 0x7F7F7FFF }, 1.2538 + { "grey", 0x7F7F7FFF }, 1.2539 + { "red", 0xFF0000FF }, 1.2540 + { "orange", 0xFF7F00FF }, 1.2541 + { "yellow", 0xFFFF00FF }, 1.2542 + { "chartreuse", 0x7FFF00FF }, 1.2543 + { "green", 0x00FF00FF }, 1.2544 + { "teal", 0x00FF7FFF }, 1.2545 + { "cyan", 0x00FFFFFF }, 1.2546 + { "blue", 0x0000FFFF }, 1.2547 + { "purple", 0x7F00FFFF }, 1.2548 + { "magenta", 0xFF00FFFF }, 1.2549 + }; 1.2550 + 1.2551 +/** 1.2552 + * Converts an integer or a string on the stack at the given 1.2553 + * offset to a RGB32 colour. Several encodings are supported. 1.2554 + * The user may construct their own RGB value, given a simple colour name, 1.2555 + * or an HTML-style "#09abcd" colour. 16 bit reduction doesn't occur at this time. 1.2556 + */ 1.2557 + static inline bool str2colour(uint32 *colour, lua_State *L, const char *str) 1.2558 + { 1.2559 + if (str[0] == '#') 1.2560 + { 1.2561 + int color; 1.2562 + sscanf(str + 1, "%X", &color); 1.2563 + 1.2564 + int len = strlen(str + 1); 1.2565 + int missing = max(0, 8 - len); 1.2566 + color <<= missing << 2; 1.2567 + if (missing >= 2) 1.2568 + color |= 0xFF; 1.2569 + *colour = color; 1.2570 + return true; 1.2571 + } 1.2572 + else 1.2573 + { 1.2574 + if (!strnicmp(str, "rand", 4)) 1.2575 + { 1.2576 + *colour = gen_rand32() | 0xFF; //((rand()*255/RAND_MAX) << 8) | ((rand()*255/RAND_MAX) << 16) | 1.2577 + // ((rand()*255/RAND_MAX) << 24) | 0xFF; 1.2578 + return true; 1.2579 + } 1.2580 + 1.2581 + for (int i = 0; i < sizeof(s_colorMapping) / sizeof(*s_colorMapping); i++) 1.2582 + { 1.2583 + if (!stricmp(str, s_colorMapping[i].name)) 1.2584 + { 1.2585 + *colour = s_colorMapping[i].value; 1.2586 + return true; 1.2587 + } 1.2588 + } 1.2589 + } 1.2590 + 1.2591 + return false; 1.2592 + } 1.2593 + 1.2594 + static inline uint32 gui_getcolour_wrapped(lua_State *L, int offset, bool hasDefaultValue, uint32 defaultColour) 1.2595 + { 1.2596 + switch (lua_type(L, offset)) 1.2597 + { 1.2598 + case LUA_TSTRING: 1.2599 + { 1.2600 + const char *str = lua_tostring(L, offset); 1.2601 + uint32 colour; 1.2602 + 1.2603 + if (str2colour(&colour, L, str)) 1.2604 + return colour; 1.2605 + else 1.2606 + { 1.2607 + if (hasDefaultValue) 1.2608 + return defaultColour; 1.2609 + else 1.2610 + return luaL_error(L, "unknown colour %s", str); 1.2611 + } 1.2612 + } 1.2613 + 1.2614 + case LUA_TNUMBER: 1.2615 + { 1.2616 + uint32 colour = (uint32) lua_tointeger(L, offset); 1.2617 + return colour; 1.2618 + } 1.2619 + 1.2620 + case LUA_TTABLE: 1.2621 + { 1.2622 + int color = 0xFF; 1.2623 + lua_pushnil(L); // first key 1.2624 + int keyIndex = lua_gettop(L); 1.2625 + int valueIndex = keyIndex + 1; 1.2626 + bool first = true; 1.2627 + while (lua_next(L, offset)) 1.2628 + { 1.2629 + bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING); 1.2630 + bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER); 1.2631 + int key = keyIsString ? tolower(*lua_tostring(L, keyIndex)) : (keyIsNumber ? lua_tointeger(L, keyIndex) : 0); 1.2632 + int value = lua_tointeger(L, valueIndex); 1.2633 + if (value < 0) value = 0; 1.2634 + if (value > 255) value = 255; 1.2635 + switch (key) 1.2636 + { 1.2637 + case 1: 1.2638 + case 'r': 1.2639 + color |= value << 24; break; 1.2640 + case 2: 1.2641 + case 'g': 1.2642 + color |= value << 16; break; 1.2643 + case 3: 1.2644 + case 'b': 1.2645 + color |= value << 8; break; 1.2646 + case 4: 1.2647 + case 'a': 1.2648 + color = (color & ~0xFF) | value; break; 1.2649 + } 1.2650 + lua_pop(L, 1); 1.2651 + } 1.2652 + return color; 1.2653 + } break; 1.2654 + 1.2655 + case LUA_TFUNCTION: 1.2656 + luaL_error(L, "invalid colour"); // NYI 1.2657 + return 0; 1.2658 + 1.2659 + default: 1.2660 + if (hasDefaultValue) 1.2661 + return defaultColour; 1.2662 + else 1.2663 + return luaL_error(L, "invalid colour"); 1.2664 + } 1.2665 + } 1.2666 + 1.2667 + static uint32 gui_getcolour(lua_State *L, int offset) 1.2668 + { 1.2669 + uint32 colour; 1.2670 + int a, r, g, b; 1.2671 + 1.2672 + colour = gui_getcolour_wrapped(L, offset, false, 0); 1.2673 + a = ((colour & 0xff) * transparencyModifier) / 255; 1.2674 + if (a > 255) 1.2675 + a = 255; 1.2676 + b = (colour >> 8) & 0xff; 1.2677 + g = (colour >> 16) & 0xff; 1.2678 + r = (colour >> 24) & 0xff; 1.2679 + return LUA_BUILD_PIXEL(a, r, g, b); 1.2680 + } 1.2681 + 1.2682 + static uint32 gui_optcolour(lua_State *L, int offset, uint32 defaultColour) 1.2683 + { 1.2684 + uint32 colour; 1.2685 + int a, r, g, b; 1.2686 + uint8 defA, defB, defG, defR; 1.2687 + 1.2688 + LUA_DECOMPOSE_PIXEL(defaultColour, defA, defR, defG, defB); 1.2689 + defaultColour = (defR << 24) | (defG << 16) | (defB << 8) | defA; 1.2690 + 1.2691 + colour = gui_getcolour_wrapped(L, offset, true, defaultColour); 1.2692 + a = ((colour & 0xff) * transparencyModifier) / 255; 1.2693 + if (a > 255) 1.2694 + a = 255; 1.2695 + b = (colour >> 8) & 0xff; 1.2696 + g = (colour >> 16) & 0xff; 1.2697 + r = (colour >> 24) & 0xff; 1.2698 + return LUA_BUILD_PIXEL(a, r, g, b); 1.2699 + } 1.2700 + 1.2701 +// gui.drawpixel(x,y,colour) 1.2702 + static int gui_drawpixel(lua_State *L) 1.2703 + { 1.2704 + int x = luaL_checkinteger(L, 1); 1.2705 + int y = luaL_checkinteger(L, 2); 1.2706 + 1.2707 + uint32 colour = gui_getcolour(L, 3); 1.2708 + 1.2709 + // if (!gui_check_boundary(x, y)) 1.2710 + // luaL_error(L,"bad coordinates"); 1.2711 + gui_prepare(); 1.2712 + 1.2713 + gui_drawpixel_internal(x, y, colour); 1.2714 + 1.2715 + return 0; 1.2716 + } 1.2717 + 1.2718 +// gui.drawline(x1,y1,x2,y2,color,skipFirst) 1.2719 + static int gui_drawline(lua_State *L) 1.2720 + { 1.2721 + int x1, y1, x2, y2; 1.2722 + uint32 color; 1.2723 + x1 = luaL_checkinteger(L, 1); 1.2724 + y1 = luaL_checkinteger(L, 2); 1.2725 + x2 = luaL_checkinteger(L, 3); 1.2726 + y2 = luaL_checkinteger(L, 4); 1.2727 + color = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 255, 255, 255)); 1.2728 + int skipFirst = lua_toboolean(L, 6); 1.2729 + 1.2730 + gui_prepare(); 1.2731 + 1.2732 + gui_drawline_internal(x2, y2, x1, y1, !skipFirst, color); 1.2733 + 1.2734 + return 0; 1.2735 + } 1.2736 + 1.2737 +// gui.drawbox(x1, y1, x2, y2, fillcolor, outlinecolor) 1.2738 + static int gui_drawbox(lua_State *L) 1.2739 + { 1.2740 + int x1, y1, x2, y2; 1.2741 + uint32 fillcolor; 1.2742 + uint32 outlinecolor; 1.2743 + 1.2744 + x1 = luaL_checkinteger(L, 1); 1.2745 + y1 = luaL_checkinteger(L, 2); 1.2746 + x2 = luaL_checkinteger(L, 3); 1.2747 + y2 = luaL_checkinteger(L, 4); 1.2748 + fillcolor = gui_optcolour(L, 5, LUA_BUILD_PIXEL(63, 255, 255, 255)); 1.2749 + outlinecolor = gui_optcolour(L, 6, LUA_BUILD_PIXEL(255, LUA_PIXEL_R(fillcolor), LUA_PIXEL_G(fillcolor), LUA_PIXEL_B(fillcolor))); 1.2750 + 1.2751 + if (x1 > x2) 1.2752 + std::swap(x1, x2); 1.2753 + if (y1 > y2) 1.2754 + std::swap(y1, y2); 1.2755 + 1.2756 + gui_prepare(); 1.2757 + 1.2758 + gui_drawbox_internal(x1, y1, x2, y2, outlinecolor); 1.2759 + if ((x2 - x1) >= 2 && (y2 - y1) >= 2) 1.2760 + gui_fillbox_internal(x1 + 1, y1 + 1, x2 - 1, y2 - 1, fillcolor); 1.2761 + 1.2762 + return 0; 1.2763 + } 1.2764 + 1.2765 +// gui.drawcircle(x0, y0, radius, colour) 1.2766 + static int gui_drawcircle(lua_State *L) 1.2767 + { 1.2768 + int x, y, r; 1.2769 + uint32 colour; 1.2770 + 1.2771 + x = luaL_checkinteger(L, 1); 1.2772 + y = luaL_checkinteger(L, 2); 1.2773 + r = luaL_checkinteger(L, 3); 1.2774 + colour = gui_getcolour(L, 4); 1.2775 + 1.2776 + gui_prepare(); 1.2777 + 1.2778 + gui_drawcircle_internal(x, y, r, colour); 1.2779 + 1.2780 + return 0; 1.2781 + } 1.2782 + 1.2783 +// gui.fillbox(x1, y1, x2, y2, colour) 1.2784 + static int gui_fillbox(lua_State *L) 1.2785 + { 1.2786 + int x1, y1, x2, y2; 1.2787 + uint32 colour; 1.2788 + 1.2789 + x1 = luaL_checkinteger(L, 1); 1.2790 + y1 = luaL_checkinteger(L, 2); 1.2791 + x2 = luaL_checkinteger(L, 3); 1.2792 + y2 = luaL_checkinteger(L, 4); 1.2793 + colour = gui_getcolour(L, 5); 1.2794 + 1.2795 + // if (!gui_check_boundary(x1, y1)) 1.2796 + // luaL_error(L,"bad coordinates"); 1.2797 + // 1.2798 + // if (!gui_check_boundary(x2, y2)) 1.2799 + // luaL_error(L,"bad coordinates"); 1.2800 + gui_prepare(); 1.2801 + 1.2802 + if (!gui_checkbox(x1, y1, x2, y2)) 1.2803 + return 0; 1.2804 + 1.2805 + gui_fillbox_internal(x1, y1, x2, y2, colour); 1.2806 + 1.2807 + return 0; 1.2808 + } 1.2809 + 1.2810 +// gui.fillcircle(x0, y0, radius, colour) 1.2811 + static int gui_fillcircle(lua_State *L) 1.2812 + { 1.2813 + int x, y, r; 1.2814 + uint32 colour; 1.2815 + 1.2816 + x = luaL_checkinteger(L, 1); 1.2817 + y = luaL_checkinteger(L, 2); 1.2818 + r = luaL_checkinteger(L, 3); 1.2819 + colour = gui_getcolour(L, 4); 1.2820 + 1.2821 + gui_prepare(); 1.2822 + 1.2823 + gui_fillcircle_internal(x, y, r, colour); 1.2824 + 1.2825 + return 0; 1.2826 + } 1.2827 + 1.2828 + static int gui_getpixel(lua_State *L) 1.2829 + { 1.2830 + int x = luaL_checkinteger(L, 1); 1.2831 + int y = luaL_checkinteger(L, 2); 1.2832 + 1.2833 + int pixWidth = 240, pixHeight = 160; 1.2834 + int scrWidth = 240, scrHeight = 160; 1.2835 + int scrOffsetX = 0, scrOffsetY = 0; 1.2836 + int pitch; 1.2837 + if (!systemIsRunningGBA()) 1.2838 + { 1.2839 + if (gbBorderOn) 1.2840 + { 1.2841 + pixWidth = 256, pixHeight = 224; 1.2842 + scrOffsetX = 48, scrOffsetY = 40; 1.2843 + } 1.2844 + else 1.2845 + { 1.2846 + pixWidth = 160, pixHeight = 144; 1.2847 + } 1.2848 + scrWidth = 160, scrHeight = 144; 1.2849 + } 1.2850 + pitch = pixWidth * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4); 1.2851 + scrOffsetY++; // don't know why it's needed 1.2852 + 1.2853 + if (!(x >= 0 && y >= 0 && x < scrWidth && y < scrHeight) /*!gui_check_boundary(x,y)*/) 1.2854 + { 1.2855 + lua_pushinteger(L, 0); 1.2856 + lua_pushinteger(L, 0); 1.2857 + lua_pushinteger(L, 0); 1.2858 + } 1.2859 + else 1.2860 + { 1.2861 + switch (systemColorDepth) 1.2862 + { 1.2863 + case 16: 1.2864 + { 1.2865 + uint16 *screen = (uint16 *) (&pix[scrOffsetY * pitch + scrOffsetX * 2]); 1.2866 + uint16 pixColor = screen[y * pitch / 2 + x]; 1.2867 + lua_pushinteger(L, (pixColor >> 8) & 0xF8); // red 1.2868 + lua_pushinteger(L, (pixColor >> 3) & 0xFC); // green 1.2869 + lua_pushinteger(L, (pixColor << 3) & 0xF8); // blue 1.2870 + } 1.2871 + break; 1.2872 + case 24: 1.2873 + { 1.2874 + uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 3]; 1.2875 + lua_pushinteger(L, screen[y * pitch + x * 3 + 2]); // red 1.2876 + lua_pushinteger(L, screen[y * pitch + x * 3 + 1]); // green 1.2877 + lua_pushinteger(L, screen[y * pitch + x * 3 + 0]); // blue 1.2878 + } 1.2879 + break; 1.2880 + case 32: 1.2881 + { 1.2882 + uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 4]; 1.2883 + lua_pushinteger(L, screen[y * pitch + x * 4 + 2]); // red 1.2884 + lua_pushinteger(L, screen[y * pitch + x * 4 + 1]); // green 1.2885 + lua_pushinteger(L, screen[y * pitch + x * 4 + 0]); // blue 1.2886 + } 1.2887 + break; 1.2888 + default: 1.2889 + lua_pushinteger(L, 0); 1.2890 + lua_pushinteger(L, 0); 1.2891 + lua_pushinteger(L, 0); 1.2892 + break; 1.2893 + } 1.2894 + } 1.2895 + return 3; 1.2896 + } 1.2897 + 1.2898 + static int gui_parsecolor(lua_State *L) 1.2899 + { 1.2900 + int r, g, b, a; 1.2901 + uint32 color = gui_getcolour(L, 1); 1.2902 + LUA_DECOMPOSE_PIXEL(color, a, r, g, b); 1.2903 + lua_pushinteger(L, r); 1.2904 + lua_pushinteger(L, g); 1.2905 + lua_pushinteger(L, b); 1.2906 + lua_pushinteger(L, a); 1.2907 + return 4; 1.2908 + } 1.2909 + 1.2910 +// gui.gdscreenshot() 1.2911 +// 1.2912 +// Returns a screen shot as a string in gd's v1 file format. 1.2913 +// This allows us to make screen shots available without gd installed locally. 1.2914 +// Users can also just grab pixels via substring selection. 1.2915 +// 1.2916 +// I think... Does lua support grabbing byte values from a string? // yes, string.byte(str,offset) 1.2917 +// Well, either way, just install gd and do what you like with it. 1.2918 +// It really is easier that way. 1.2919 + 1.2920 +// example: gd.createFromGdStr(gui.gdscreenshot()):png("outputimage.png") 1.2921 + static int gui_gdscreenshot(lua_State *L) 1.2922 + { 1.2923 + int xofs = 0, yofs = 0, ppl = 240, width = 240, height = 160; 1.2924 + if (!systemIsRunningGBA()) 1.2925 + { 1.2926 + if (gbBorderOn) 1.2927 + xofs = 48, yofs = 40, ppl = 256; 1.2928 + else 1.2929 + ppl = 160; 1.2930 + width = 160, height = 144; 1.2931 + } 1.2932 + 1.2933 + yofs++; 1.2934 + 1.2935 + //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3; 1.2936 + int pitch = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4); 1.2937 + uint8 *screen = &pix[yofs * pitch + xofs * (systemColorDepth / 8)]; 1.2938 + 1.2939 + int size = 11 + width * height * 4; 1.2940 + char *str = new char[size + 1]; 1.2941 + str[size] = 0; 1.2942 + 1.2943 + unsigned char *ptr = (unsigned char *)str; 1.2944 + 1.2945 + // GD format header for truecolor image (11 bytes) 1.2946 + *ptr++ = (65534 >> 8) & 0xFF; 1.2947 + *ptr++ = (65534) & 0xFF; 1.2948 + *ptr++ = (width >> 8) & 0xFF; 1.2949 + *ptr++ = (width) & 0xFF; 1.2950 + *ptr++ = (height >> 8) & 0xFF; 1.2951 + *ptr++ = (height) & 0xFF; 1.2952 + *ptr++ = 1; 1.2953 + *ptr++ = 255; 1.2954 + *ptr++ = 255; 1.2955 + *ptr++ = 255; 1.2956 + *ptr++ = 255; 1.2957 + 1.2958 + GetColorFunc getColor; 1.2959 + getColorIOFunc(systemColorDepth, &getColor, NULL); 1.2960 + 1.2961 + int x, y; 1.2962 + for (y = 0; y < height; y++) 1.2963 + { 1.2964 + uint8 *s = &screen[y * pitch]; 1.2965 + for (x = 0; x < width; x++, s += systemColorDepth / 8) 1.2966 + { 1.2967 + uint8 r, g, b; 1.2968 + getColor(s, &r, &g, &b); 1.2969 + 1.2970 + *ptr++ = 0; 1.2971 + *ptr++ = r; 1.2972 + *ptr++ = g; 1.2973 + *ptr++ = b; 1.2974 + } 1.2975 + } 1.2976 + 1.2977 + lua_pushlstring(L, str, size); 1.2978 + delete[] str; 1.2979 + return 1; 1.2980 + } 1.2981 + 1.2982 +// gui.opacity(number alphaValue) 1.2983 +// sets the transparency of subsequent draw calls 1.2984 +// 0.0 is completely transparent, 1.0 is completely opaque 1.2985 +// non-integer values are supported and meaningful, as are values greater than 1.0 1.2986 +// it is not necessary to use this function to get transparency (or the less-recommended gui.transparency() either), 1.2987 +// because you can provide an alpha value in the color argument of each draw call. 1.2988 + 1.2989 +// however, it can be convenient to be able to globally modify the drawing transparency 1.2990 + static int gui_setopacity(lua_State *L) 1.2991 + { 1.2992 + double opacF = luaL_checknumber(L, 1); 1.2993 + transparencyModifier = (int)(opacF * 255); 1.2994 + if (transparencyModifier < 0) 1.2995 + transparencyModifier = 0; 1.2996 + return 0; 1.2997 + } 1.2998 + 1.2999 +// gui.transparency(int strength) 1.3000 +// 1.3001 + 1.3002 +// 0 = solid, 1.3003 + static int gui_transparency(lua_State *L) 1.3004 + { 1.3005 + double trans = luaL_checknumber(L, 1); 1.3006 + transparencyModifier = (int)((4.0 - trans) / 4.0 * 255); 1.3007 + if (transparencyModifier < 0) 1.3008 + transparencyModifier = 0; 1.3009 + return 0; 1.3010 + } 1.3011 + 1.3012 + static const uint32 Small_Font_Data[] = 1.3013 + { 1.3014 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 32 1.3015 + 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 33 ! 1.3016 + 0x00000000, 0x00040002, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 34 " 1.3017 + 0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 35 # 1.3018 + 0x00000000, 0x00040300, 0x00000403, 0x00000500, 0x00070600, 0x00000706, 0x00000000, // 36 $ 1.3019 + 0x00000000, 0x00000002, 0x00050000, 0x00000500, 0x00000005, 0x00080000, 0x00000000, // 37 % 1.3020 + 0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00080700, 0x00000000, // 38 & 1.3021 + 0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 39 ' 1.3022 + 0x00000000, 0x00000300, 0x00000003, 0x00000004, 0x00000005, 0x00000700, 0x00000000, // 40 ( 1.3023 + 0x00000000, 0x00000300, 0x00050000, 0x00060000, 0x00070000, 0x00000700, 0x00000000, // 41 ) 1.3024 + 0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00080006, 0x00000000, // 42 * 1.3025 + 0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00000000, 0x00000000, // 43 + 1.3026 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000600, 0x00000700, 0x00000007, // 44 , 1.3027 + 0x00000000, 0x00000000, 0x00000000, 0x00060504, 0x00000000, 0x00000000, 0x00000000, // 45 - 1.3028 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 46 . 1.3029 + 0x00030000, 0x00040000, 0x00000400, 0x00000500, 0x00000005, 0x00000006, 0x00000000, // 47 / 1.3030 + 0x00000000, 0x00000300, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 48 0 1.3031 + 0x00000000, 0x00000300, 0x00000403, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 49 1 1.3032 + 0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 50 2 1.3033 + 0x00000000, 0x00000302, 0x00050000, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 51 3 1.3034 + 0x00000000, 0x00000300, 0x00000003, 0x00060004, 0x00070605, 0x00080000, 0x00000000, // 52 4 1.3035 + 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 53 5 1.3036 + 0x00000000, 0x00000300, 0x00000003, 0x00000504, 0x00070005, 0x00000700, 0x00000000, // 54 6 1.3037 + 0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 55 7 1.3038 + 0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00000700, 0x00000000, // 56 8 1.3039 + 0x00000000, 0x00000300, 0x00050003, 0x00060500, 0x00070000, 0x00000700, 0x00000000, // 57 9 1.3040 + 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 58 : 1.3041 + 0x00000000, 0x00000000, 0x00000000, 0x00000500, 0x00000000, 0x00000700, 0x00000007, // 59 ; 1.3042 + 0x00000000, 0x00040000, 0x00000400, 0x00000004, 0x00000600, 0x00080000, 0x00000000, // 60 < 1.3043 + 0x00000000, 0x00000000, 0x00050403, 0x00000000, 0x00070605, 0x00000000, 0x00000000, // 61 = 1.3044 + 0x00000000, 0x00000002, 0x00000400, 0x00060000, 0x00000600, 0x00000006, 0x00000000, // 62 > 1.3045 + 0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 63 ? 1.3046 + 0x00000000, 0x00000300, 0x00050400, 0x00060004, 0x00070600, 0x00000000, 0x00000000, // 64 @ 1.3047 + 0x00000000, 0x00000300, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 65 A 1.3048 + 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 66 B 1.3049 + 0x00000000, 0x00040300, 0x00000003, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 67 C 1.3050 + 0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00000706, 0x00000000, // 68 D 1.3051 + 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00080706, 0x00000000, // 69 E 1.3052 + 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 70 F 1.3053 + 0x00000000, 0x00040300, 0x00000003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 71 G 1.3054 + 0x00000000, 0x00040002, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 72 H 1.3055 + 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 73 I 1.3056 + 0x00000000, 0x00040000, 0x00050000, 0x00060000, 0x00070005, 0x00000700, 0x00000000, // 74 J 1.3057 + 0x00000000, 0x00040002, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 75 K 1.3058 + 0x00000000, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00080706, 0x00000000, // 76 l 1.3059 + 0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 77 M 1.3060 + 0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 78 N 1.3061 + 0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 79 O 1.3062 + 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 80 P 1.3063 + 0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00090000, // 81 Q 1.3064 + 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 82 R 1.3065 + 0x00000000, 0x00040300, 0x00000003, 0x00000500, 0x00070000, 0x00000706, 0x00000000, // 83 S 1.3066 + 0x00000000, 0x00040302, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 84 T 1.3067 + 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 85 U 1.3068 + 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000000, // 86 V 1.3069 + 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 87 W 1.3070 + 0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 88 X 1.3071 + 0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 89 Y 1.3072 + 0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 90 Z 1.3073 + 0x00000000, 0x00040300, 0x00000400, 0x00000500, 0x00000600, 0x00080700, 0x00000000, // 91 [ 1.3074 + 0x00000000, 0x00000002, 0x00000400, 0x00000500, 0x00070000, 0x00080000, 0x00000000, // 92 '\' 1.3075 + 0x00000000, 0x00000302, 0x00000400, 0x00000500, 0x00000600, 0x00000706, 0x00000000, // 93 ] 1.3076 + 0x00000000, 0x00000300, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 94 ^ 1.3077 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080706, 0x00000000, // 95 _ 1.3078 + 0x00000000, 0x00000002, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 96 ` 1.3079 + 0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 97 a 1.3080 + 0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 98 b 1.3081 + 0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 99 c 1.3082 + 0x00000000, 0x00040000, 0x00050000, 0x00060500, 0x00070005, 0x00080700, 0x00000000, // 100 d 1.3083 + 0x00000000, 0x00000000, 0x00050400, 0x00060504, 0x00000005, 0x00080700, 0x00000000, // 101 e 1.3084 + 0x00000000, 0x00040300, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 102 f 1.3085 + 0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070600, 0x00080000, 0x00000807, // 103 g 1.3086 + 0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 104 h 1.3087 + 0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 105 i 1.3088 + 0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000007, // 106 j 1.3089 + 0x00000000, 0x00000002, 0x00000003, 0x00060004, 0x00000605, 0x00080006, 0x00000000, // 107 k 1.3090 + 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 108 l 1.3091 + 0x00000000, 0x00000000, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 109 m 1.3092 + 0x00000000, 0x00000000, 0x00000403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 110 n 1.3093 + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 111 o 1.3094 + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00000605, 0x00000006, 0x00000007, // 112 p 1.3095 + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070600, 0x00080000, 0x00090000, // 113 q 1.3096 + 0x00000000, 0x00000000, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 114 r 1.3097 + 0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00070600, 0x00000706, 0x00000000, // 115 s 1.3098 + 0x00000000, 0x00000300, 0x00050403, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 116 t 1.3099 + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 117 u 1.3100 + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 118 v 1.3101 + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 119 w 1.3102 + 0x00000000, 0x00000000, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 120 x 1.3103 + 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000007, // 121 y 1.3104 + 0x00000000, 0x00000000, 0x00050403, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 122 z 1.3105 + 0x00000000, 0x00040300, 0x00000400, 0x00000504, 0x00000600, 0x00080700, 0x00000000, // 123 { 1.3106 + 0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000600, 0x00000700, 0x00000000, // 124 | 1.3107 + 0x00000000, 0x00000302, 0x00000400, 0x00060500, 0x00000600, 0x00000706, 0x00000000, // 125 } 1.3108 + 0x00000000, 0x00000302, 0x00050000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 126 ~ 1.3109 + 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070605, 0x00000000, 0x00000000, // 127 1.3110 + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 1.3111 + }; 1.3112 + 1.3113 + static void PutTextInternal(const char *str, int len, short x, short y, int color, int backcolor) 1.3114 + { 1.3115 + int Opac = (color >> 24) & 0xFF; 1.3116 + int backOpac = (backcolor >> 24) & 0xFF; 1.3117 + int origX = x; 1.3118 + 1.3119 + if (!Opac && !backOpac) 1.3120 + return; 1.3121 + 1.3122 + while (*str && len && y < LUA_SCREEN_HEIGHT) 1.3123 + { 1.3124 + int c = *str++; 1.3125 + while (x > LUA_SCREEN_WIDTH && c != '\n') 1.3126 + { 1.3127 + c = *str; 1.3128 + if (c == '\0') 1.3129 + break; 1.3130 + str++; 1.3131 + } 1.3132 + 1.3133 + if (c == '\n') 1.3134 + { 1.3135 + x = origX; 1.3136 + y += 8; 1.3137 + continue; 1.3138 + } 1.3139 + else if (c == '\t') // just in case 1.3140 + { 1.3141 + const int tabSpace = 8; 1.3142 + x += (tabSpace - (((x - origX) / 4) % tabSpace)) * 4; 1.3143 + continue; 1.3144 + } 1.3145 + 1.3146 + if ((unsigned int)(c - 32) >= 96) 1.3147 + continue; 1.3148 + 1.3149 + const unsigned char *Cur_Glyph = (const unsigned char *) &Small_Font_Data + (c - 32) * 7 * 4; 1.3150 + 1.3151 + for (int y2 = 0; y2 < 8; y2++) 1.3152 + { 1.3153 + unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y2); 1.3154 + for (int x2 = -1; x2 < 4; x2++) 1.3155 + { 1.3156 + int shift = x2 << 3; 1.3157 + int mask = 0xFF << shift; 1.3158 + int intensity = (glyphLine & mask) >> shift; 1.3159 + 1.3160 + if (intensity && x2 >= 0 && y2 < 7) 1.3161 + { 1.3162 + //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2)); 1.3163 + //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2)); 1.3164 + //gui_drawpixel_fast(xdraw, ydraw, color); 1.3165 + gui_drawpixel_internal(x + x2, y + y2, color); 1.3166 + } 1.3167 + else if (backOpac) 1.3168 + { 1.3169 + for (int y3 = max(0, y2 - 1); y3 <= min(6, y2 + 1); y3++) 1.3170 + { 1.3171 + unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y3); 1.3172 + for (int x3 = max(0, x2 - 1); x3 <= min(3, x2 + 1); x3++) 1.3173 + { 1.3174 + int shift = x3 << 3; 1.3175 + int mask = 0xFF << shift; 1.3176 + intensity |= (glyphLine & mask) >> shift; 1.3177 + if (intensity) 1.3178 + goto draw_outline; // speedup? 1.3179 + } 1.3180 + } 1.3181 + 1.3182 +draw_outline: 1.3183 + if (intensity) 1.3184 + { 1.3185 + //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2)); 1.3186 + //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2)); 1.3187 + //gui_drawpixel_fast(xdraw, ydraw, backcolor); 1.3188 + gui_drawpixel_internal(x + x2, y + y2, backcolor); 1.3189 + } 1.3190 + } 1.3191 + } 1.3192 + } 1.3193 + 1.3194 + x += 4; 1.3195 + len--; 1.3196 + } 1.3197 + } 1.3198 + 1.3199 + static int strlinelen(const char *string) 1.3200 + { 1.3201 + const char *s = string; 1.3202 + while (*s && *s != '\n') 1.3203 + s++; 1.3204 + if (*s) 1.3205 + s++; 1.3206 + return s - string; 1.3207 + } 1.3208 + 1.3209 + static void LuaDisplayString(const char *string, int y, int x, uint32 color, uint32 outlineColor) 1.3210 + { 1.3211 + if (!string) 1.3212 + return; 1.3213 + 1.3214 + gui_prepare(); 1.3215 + 1.3216 + PutTextInternal(string, strlen(string), x, y, color, outlineColor); 1.3217 + 1.3218 + /* 1.3219 + const char* ptr = string; 1.3220 + while(*ptr && y < LUA_SCREEN_HEIGHT) 1.3221 + { 1.3222 + int len = strlinelen(ptr); 1.3223 + int skip = 0; 1.3224 + if(len < 1) len = 1; 1.3225 + 1.3226 + // break up the line if it's too long to display otherwise 1.3227 + if(len > 63) 1.3228 + { 1.3229 + len = 63; 1.3230 + const char* ptr2 = ptr + len-1; 1.3231 + for(int j = len-1; j; j--, ptr2--) 1.3232 + { 1.3233 + if(*ptr2 == ' ' || *ptr2 == '\t') 1.3234 + { 1.3235 + len = j; 1.3236 + skip = 1; 1.3237 + break; 1.3238 + } 1.3239 + } 1.3240 + } 1.3241 + 1.3242 + int xl = 0; 1.3243 + int yl = 0; 1.3244 + int xh = (LUA_SCREEN_WIDTH - 1 - 1) - 4*len; 1.3245 + int yh = LUA_SCREEN_HEIGHT - 1; 1.3246 + int x2 = min(max(x,xl),xh); 1.3247 + int y2 = min(max(y,yl),yh); 1.3248 + 1.3249 + PutTextInternal(ptr,len,x2,y2,color,outlineColor); 1.3250 + 1.3251 + ptr += len + skip; 1.3252 + y += 8; 1.3253 + } 1.3254 + */ 1.3255 + } 1.3256 + 1.3257 +// gui.text(int x, int y, string msg) 1.3258 +// 1.3259 +// Displays the given text on the screen, using the same font and techniques as the 1.3260 + 1.3261 +// main HUD. 1.3262 + static int gui_text(lua_State *L) 1.3263 + { 1.3264 + //extern int font_height; 1.3265 + const char *msg; 1.3266 + int x, y; 1.3267 + uint32 colour, borderColour; 1.3268 + 1.3269 + x = luaL_checkinteger(L, 1); 1.3270 + y = luaL_checkinteger(L, 2); 1.3271 + //msg = luaL_checkstring(L, 3); 1.3272 + msg = toCString(L, 3); 1.3273 + 1.3274 + // if (x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= (LUA_SCREEN_HEIGHT - font_height)) 1.3275 + // luaL_error(L,"bad coordinates"); 1.3276 + colour = gui_optcolour(L, 4, LUA_BUILD_PIXEL(255, 255, 255, 255)); 1.3277 + borderColour = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 0, 0, 0)); 1.3278 + 1.3279 + gui_prepare(); 1.3280 + 1.3281 + LuaDisplayString(msg, y, x, colour, borderColour); 1.3282 + 1.3283 + return 0; 1.3284 + } 1.3285 + 1.3286 +// gui.gdoverlay([int dx=0, int dy=0,] string str [, sx=0, sy=0, sw, sh] [, float alphamul=1.0]) 1.3287 +// 1.3288 +// Overlays the given image on the screen. 1.3289 + 1.3290 +// example: gui.gdoverlay(gd.createFromPng("myimage.png"):gdStr()) 1.3291 + static int gui_gdoverlay(lua_State *L) 1.3292 + { 1.3293 + int argCount = lua_gettop(L); 1.3294 + 1.3295 + int xStartDst = 0; 1.3296 + int yStartDst = 0; 1.3297 + int xStartSrc = 0; 1.3298 + int yStartSrc = 0; 1.3299 + 1.3300 + int index = 1; 1.3301 + if (lua_type(L, index) == LUA_TNUMBER) 1.3302 + { 1.3303 + xStartDst = lua_tointeger(L, index++); 1.3304 + if (lua_type(L, index) == LUA_TNUMBER) 1.3305 + yStartDst = lua_tointeger(L, index++); 1.3306 + } 1.3307 + 1.3308 + luaL_checktype(L, index, LUA_TSTRING); 1.3309 + 1.3310 + const unsigned char *ptr = (const unsigned char *)lua_tostring(L, index++); 1.3311 + 1.3312 + if (ptr[0] != 255 || (ptr[1] != 254 && ptr[1] != 255)) 1.3313 + luaL_error(L, "bad image data"); 1.3314 + 1.3315 + bool trueColor = (ptr[1] == 254); 1.3316 + ptr += 2; 1.3317 + 1.3318 + int imgwidth = *ptr++ << 8; 1.3319 + imgwidth |= *ptr++; 1.3320 + 1.3321 + int width = imgwidth; 1.3322 + int imgheight = *ptr++ << 8; 1.3323 + imgheight |= *ptr++; 1.3324 + 1.3325 + int height = imgheight; 1.3326 + if ((!trueColor && *ptr) || (trueColor && !*ptr)) 1.3327 + luaL_error(L, "bad image data"); 1.3328 + ptr++; 1.3329 + 1.3330 + int pitch = imgwidth * (trueColor ? 4 : 1); 1.3331 + 1.3332 + if ((argCount - index + 1) >= 4) 1.3333 + { 1.3334 + xStartSrc = luaL_checkinteger(L, index++); 1.3335 + yStartSrc = luaL_checkinteger(L, index++); 1.3336 + width = luaL_checkinteger(L, index++); 1.3337 + height = luaL_checkinteger(L, index++); 1.3338 + } 1.3339 + 1.3340 + int alphaMul = transparencyModifier; 1.3341 + if (lua_isnumber(L, index)) 1.3342 + alphaMul = (int)(alphaMul * lua_tonumber(L, index++)); 1.3343 + if (alphaMul <= 0) 1.3344 + return 0; 1.3345 + 1.3346 + // since there aren't that many possible opacity levels, 1.3347 + // do the opacity modification calculations beforehand instead of per pixel 1.3348 + int opacMap[256]; 1.3349 + for (int i = 0; i < 128; i++) 1.3350 + { 1.3351 + int opac = 255 - ((i << 1) | (i & 1)); // gdAlphaMax = 127, not 255 1.3352 + opac = (opac * alphaMul) / 255; 1.3353 + if (opac < 0) 1.3354 + opac = 0; 1.3355 + if (opac > 255) 1.3356 + opac = 255; 1.3357 + opacMap[i] = opac; 1.3358 + } 1.3359 + 1.3360 + for (int i = 128; i < 256; i++) 1.3361 + opacMap[i] = 0; // what should we do for them, actually? 1.3362 + int colorsTotal = 0; 1.3363 + if (!trueColor) 1.3364 + { 1.3365 + colorsTotal = *ptr++ << 8; 1.3366 + colorsTotal |= *ptr++; 1.3367 + } 1.3368 + 1.3369 + int transparent = *ptr++ << 24; 1.3370 + transparent |= *ptr++ << 16; 1.3371 + transparent |= *ptr++ << 8; 1.3372 + transparent |= *ptr++; 1.3373 + struct 1.3374 + { 1.3375 + uint8 r, g, b, a; 1.3376 + } pal[256]; 1.3377 + if (!trueColor) 1.3378 + for (int i = 0; i < 256; i++) 1.3379 + { 1.3380 + pal[i].r = *ptr++; 1.3381 + pal[i].g = *ptr++; 1.3382 + pal[i].b = *ptr++; 1.3383 + pal[i].a = opacMap[*ptr++]; 1.3384 + } 1.3385 + 1.3386 + // some of clippings 1.3387 + if (xStartSrc < 0) 1.3388 + { 1.3389 + width += xStartSrc; 1.3390 + xStartDst -= xStartSrc; 1.3391 + xStartSrc = 0; 1.3392 + } 1.3393 + 1.3394 + if (yStartSrc < 0) 1.3395 + { 1.3396 + height += yStartSrc; 1.3397 + yStartDst -= yStartSrc; 1.3398 + yStartSrc = 0; 1.3399 + } 1.3400 + 1.3401 + if (xStartSrc + width >= imgwidth) 1.3402 + width = imgwidth - xStartSrc; 1.3403 + if (yStartSrc + height >= imgheight) 1.3404 + height = imgheight - yStartSrc; 1.3405 + if (xStartDst < 0) 1.3406 + { 1.3407 + width += xStartDst; 1.3408 + if (width <= 0) 1.3409 + return 0; 1.3410 + xStartSrc = -xStartDst; 1.3411 + xStartDst = 0; 1.3412 + } 1.3413 + 1.3414 + if (yStartDst < 0) 1.3415 + { 1.3416 + height += yStartDst; 1.3417 + if (height <= 0) 1.3418 + return 0; 1.3419 + yStartSrc = -yStartDst; 1.3420 + yStartDst = 0; 1.3421 + } 1.3422 + 1.3423 + if (xStartDst + width >= LUA_SCREEN_WIDTH) 1.3424 + width = LUA_SCREEN_WIDTH - xStartDst; 1.3425 + if (yStartDst + height >= LUA_SCREEN_HEIGHT) 1.3426 + height = LUA_SCREEN_HEIGHT - yStartDst; 1.3427 + if (width <= 0 || height <= 0) 1.3428 + return 0; // out of screen or invalid size 1.3429 + gui_prepare(); 1.3430 + 1.3431 + const uint8 *pix = (const uint8 *)(&ptr[yStartSrc * pitch + (xStartSrc * (trueColor ? 4 : 1))]); 1.3432 + int bytesToNextLine = pitch - (width * (trueColor ? 4 : 1)); 1.3433 + if (trueColor) 1.3434 + { 1.3435 + for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine) 1.3436 + { 1.3437 + for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix += 4) 1.3438 + { 1.3439 + gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(opacMap[pix[0]], pix[1], pix[2], pix[3])); 1.3440 + } 1.3441 + } 1.3442 + } 1.3443 + else 1.3444 + { 1.3445 + for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine) 1.3446 + { 1.3447 + for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix++) 1.3448 + { 1.3449 + gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(pal[*pix].a, pal[*pix].r, pal[*pix].g, pal[*pix].b)); 1.3450 + } 1.3451 + } 1.3452 + } 1.3453 + 1.3454 + return 0; 1.3455 + } 1.3456 + 1.3457 +// function gui.register(function f) 1.3458 +// 1.3459 +// This function will be called just before a graphical update. 1.3460 +// More complicated, but doesn't suffer any frame delays. 1.3461 +// Nil will be accepted in place of a function to erase 1.3462 +// a previously registered function, and the previous function 1.3463 + 1.3464 +// (if any) is returned, or nil if none. 1.3465 + static int gui_register(lua_State *L) 1.3466 + { 1.3467 + // We'll do this straight up. 1.3468 + // First set up the stack. 1.3469 + lua_settop(L, 1); 1.3470 + 1.3471 + // Verify the validity of the entry 1.3472 + if (!lua_isnil(L, 1)) 1.3473 + luaL_checktype(L, 1, LUA_TFUNCTION); 1.3474 + 1.3475 + // Get the old value 1.3476 + lua_getfield(L, LUA_REGISTRYINDEX, guiCallbackTable); 1.3477 + 1.3478 + // Save the new value 1.3479 + lua_pushvalue(L, 1); 1.3480 + lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable); 1.3481 + 1.3482 + // The old value is on top of the stack. Return it. 1.3483 + return 1; 1.3484 + } 1.3485 + 1.3486 +// string gui.popup(string message, [string type = "ok"]) 1.3487 +// 1.3488 + 1.3489 +// Popup dialog! 1.3490 + int gui_popup(lua_State *L) 1.3491 + { 1.3492 + const char *message = luaL_checkstring(L, 1); 1.3493 + const char *type = luaL_optstring(L, 2, "ok"); 1.3494 + 1.3495 +#if (defined(WIN32) && !defined(SDL)) 1.3496 + int t; 1.3497 + if (strcmp(type, "ok") == 0) 1.3498 + t = MB_OK; 1.3499 + else if (strcmp(type, "yesno") == 0) 1.3500 + t = MB_YESNO; 1.3501 + else if (strcmp(type, "yesnocancel") == 0) 1.3502 + t = MB_YESNOCANCEL; 1.3503 + else 1.3504 + return luaL_error(L, "invalid popup type \"%s\"", type); 1.3505 + 1.3506 + theApp.winCheckFullscreen(); 1.3507 + systemSoundClearBuffer(); 1.3508 + int result = AfxGetApp()->m_pMainWnd->MessageBox(message, "Lua Script Pop-up", t); 1.3509 + 1.3510 + lua_settop(L, 1); 1.3511 + 1.3512 + if (t != MB_OK) 1.3513 + { 1.3514 + if (result == IDYES) 1.3515 + lua_pushstring(L, "yes"); 1.3516 + else if (result == IDNO) 1.3517 + lua_pushstring(L, "no"); 1.3518 + else if (result == IDCANCEL) 1.3519 + lua_pushstring(L, "cancel"); 1.3520 + else 1.3521 + luaL_error(L, "win32 unrecognized return value %d", result); 1.3522 + return 1; 1.3523 + } 1.3524 + 1.3525 + // else, we don't care. 1.3526 + return 0; 1.3527 +#else 1.3528 + char *t; 1.3529 + #ifdef __linux 1.3530 + // The Linux backend has a "FromPause" variable. 1.3531 + // If set to 1, assume some known external event has screwed with the flow of time. 1.3532 + // Since this pauses the emulator waiting for a response, we set it to 1. 1.3533 +// FIXME: Well, actually it doesn't 1.3534 +// extern int FromPause; 1.3535 +// FromPause = 1; 1.3536 + 1.3537 + int pid; // appease compiler 1.3538 + 1.3539 + // Before doing any work, verify the correctness of the parameters. 1.3540 + if (strcmp(type, "ok") == 0) 1.3541 + t = "OK:100"; 1.3542 + else if (strcmp(type, "yesno") == 0) 1.3543 + t = "Yes:100,No:101"; 1.3544 + else if (strcmp(type, "yesnocancel") == 0) 1.3545 + t = "Yes:100,No:101,Cancel:102"; 1.3546 + else 1.3547 + return luaL_error(L, "invalid popup type \"%s\"", type); 1.3548 + 1.3549 + // Can we find a copy of xmessage? Search the path. 1.3550 + char *path = strdup(getenv("PATH")); 1.3551 + 1.3552 + char *current = path; 1.3553 + 1.3554 + char *colon; 1.3555 + 1.3556 + int found = 0; 1.3557 + 1.3558 + while (current) 1.3559 + { 1.3560 + colon = strchr(current, ':'); 1.3561 + 1.3562 + // Clip off the colon. 1.3563 + *colon++ = 0; 1.3564 + 1.3565 + int len = strlen(current); 1.3566 + char *filename = (char *)malloc(len + 12); // always give excess 1.3567 + snprintf(filename, len + 12, "%s/xmessage", current); 1.3568 + 1.3569 + if (access(filename, X_OK) == 0) 1.3570 + { 1.3571 + free(filename); 1.3572 + found = 1; 1.3573 + break; 1.3574 + } 1.3575 + 1.3576 + // Failed, move on. 1.3577 + current = colon; 1.3578 + free(filename); 1.3579 + } 1.3580 + 1.3581 + free(path); 1.3582 + 1.3583 + // We've found it? 1.3584 + if (!found) 1.3585 + goto use_console; 1.3586 + 1.3587 + pid = fork(); 1.3588 + if (pid == 0) 1.3589 + { // I'm the virgin sacrifice 1.3590 + // I'm gonna be dead in a matter of microseconds anyways, so wasted memory doesn't matter to me. 1.3591 + // Go ahead and abuse strdup. 1.3592 + char *parameters[] = { "xmessage", "-buttons", t, strdup(message), NULL }; 1.3593 + 1.3594 + execvp("xmessage", parameters); 1.3595 + 1.3596 + // Aw shitty 1.3597 + perror("exec xmessage"); 1.3598 + exit(1); 1.3599 + } 1.3600 + else if (pid < 0) // something went wrong!!! Oh hell... use the console 1.3601 + goto use_console; 1.3602 + else 1.3603 + { 1.3604 + // We're the parent. Watch for the child. 1.3605 + int r; 1.3606 + int res = waitpid(pid, &r, 0); 1.3607 + if (res < 0) // wtf? 1.3608 + goto use_console; 1.3609 + 1.3610 + // The return value gets copmlicated... 1.3611 + if (!WIFEXITED(r)) 1.3612 + { 1.3613 + luaL_error(L, "don't screw with my xmessage process!"); 1.3614 + } 1.3615 + 1.3616 + r = WEXITSTATUS(r); 1.3617 + 1.3618 + // We assume it's worked. 1.3619 + if (r == 0) 1.3620 + { 1.3621 + return 0; // no parameters for an OK 1.3622 + } 1.3623 + 1.3624 + if (r == 100) 1.3625 + { 1.3626 + lua_pushstring(L, "yes"); 1.3627 + return 1; 1.3628 + } 1.3629 + 1.3630 + if (r == 101) 1.3631 + { 1.3632 + lua_pushstring(L, "no"); 1.3633 + return 1; 1.3634 + } 1.3635 + 1.3636 + if (r == 102) 1.3637 + { 1.3638 + lua_pushstring(L, "cancel"); 1.3639 + return 1; 1.3640 + } 1.3641 + 1.3642 + // Wtf? 1.3643 + return luaL_error(L, "popup failed due to unknown results involving xmessage (%d)", r); 1.3644 + } 1.3645 + 1.3646 +use_console: 1.3647 + #endif 1.3648 + 1.3649 + // All else has failed 1.3650 + if (strcmp(type, "ok") == 0) 1.3651 + t = ""; 1.3652 + else if (strcmp(type, "yesno") == 0) 1.3653 + t = "yn"; 1.3654 + else if (strcmp(type, "yesnocancel") == 0) 1.3655 + t = "ync"; 1.3656 + else 1.3657 + return luaL_error(L, "invalid popup type \"%s\"", type); 1.3658 + 1.3659 + fprintf(stderr, "Lua Message: %s\n", message); 1.3660 + 1.3661 + while (true) 1.3662 + { 1.3663 + char buffer[64]; 1.3664 + 1.3665 + // We don't want parameters 1.3666 + if (!t[0]) 1.3667 + { 1.3668 + fprintf(stderr, "[Press Enter]"); 1.3669 + fgets(buffer, sizeof(buffer), stdin); 1.3670 + 1.3671 + // We're done 1.3672 + return 0; 1.3673 + } 1.3674 + 1.3675 + fprintf(stderr, "(%s): ", t); 1.3676 + fgets(buffer, sizeof(buffer), stdin); 1.3677 + 1.3678 + // Check if the option is in the list 1.3679 + if (strchr(t, tolower(buffer[0]))) 1.3680 + { 1.3681 + switch (tolower(buffer[0])) 1.3682 + { 1.3683 + case 'y': 1.3684 + lua_pushstring(L, "yes"); 1.3685 + return 1; 1.3686 + case 'n': 1.3687 + lua_pushstring(L, "no"); 1.3688 + return 1; 1.3689 + case 'c': 1.3690 + lua_pushstring(L, "cancel"); 1.3691 + return 1; 1.3692 + default: 1.3693 + luaL_error(L, "internal logic error in console based prompts for gui.popup"); 1.3694 + } 1.3695 + } 1.3696 + 1.3697 + // We fell through, so we assume the user answered wrong and prompt again. 1.3698 + } 1.3699 + 1.3700 + // Nothing here, since the only way out is in the loop. 1.3701 +#endif 1.3702 + } 1.3703 + 1.3704 +#if (defined(WIN32) && !defined(SDL)) 1.3705 + const char *s_keyToName[256] = 1.3706 + { 1.3707 + NULL, 1.3708 + "leftclick", 1.3709 + "rightclick", 1.3710 + NULL, 1.3711 + "middleclick", 1.3712 + NULL, 1.3713 + NULL, 1.3714 + NULL, 1.3715 + "backspace", 1.3716 + "tab", 1.3717 + NULL, 1.3718 + NULL, 1.3719 + NULL, 1.3720 + "enter", 1.3721 + NULL, 1.3722 + NULL, 1.3723 + "shift", // 0x10 1.3724 + "control", 1.3725 + "alt", 1.3726 + "pause", 1.3727 + "capslock", 1.3728 + NULL, 1.3729 + NULL, 1.3730 + NULL, 1.3731 + NULL, 1.3732 + NULL, 1.3733 + NULL, 1.3734 + "escape", 1.3735 + NULL, 1.3736 + NULL, 1.3737 + NULL, 1.3738 + NULL, 1.3739 + "space", // 0x20 1.3740 + "pageup", 1.3741 + "pagedown", 1.3742 + "end", 1.3743 + "home", 1.3744 + "left", 1.3745 + "up", 1.3746 + "right", 1.3747 + "down", 1.3748 + NULL, 1.3749 + NULL, 1.3750 + NULL, 1.3751 + NULL, 1.3752 + "insert", 1.3753 + "delete", 1.3754 + NULL, 1.3755 + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 1.3756 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1.3757 + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", 1.3758 + "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", 1.3759 + "U", "V", "W", "X", "Y", "Z", 1.3760 + NULL, 1.3761 + NULL, 1.3762 + NULL, 1.3763 + NULL, 1.3764 + NULL, 1.3765 + "numpad0", "numpad1", "numpad2", "numpad3", "numpad4", "numpad5", "numpad6", "numpad7", "numpad8", "numpad9", 1.3766 + "numpad*", "numpad+", 1.3767 + NULL, 1.3768 + "numpad-", "numpad.", "numpad/", 1.3769 + "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", 1.3770 + "F12", 1.3771 + "F13", "F14", "F15", "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", 1.3772 + "F24", 1.3773 + NULL, 1.3774 + NULL, 1.3775 + NULL, 1.3776 + NULL, 1.3777 + NULL, 1.3778 + NULL, 1.3779 + NULL, 1.3780 + NULL, 1.3781 + "numlock", 1.3782 + "scrolllock", 1.3783 + NULL, // 0x92 1.3784 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1.3785 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1.3786 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1.3787 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1.3788 + NULL, // 0xB9 1.3789 + "semicolon", 1.3790 + "plus", 1.3791 + "comma", 1.3792 + "minus", 1.3793 + "period", 1.3794 + "slash", 1.3795 + "tilde", 1.3796 + NULL, // 0xC1 1.3797 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1.3798 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1.3799 + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1.3800 + NULL, // 0xDA 1.3801 + "leftbracket", 1.3802 + "backslash", 1.3803 + "rightbracket", 1.3804 + "quote", 1.3805 + }; 1.3806 +#endif 1.3807 + 1.3808 +// input.get() 1.3809 +// takes no input, returns a lua table of entries representing the current input state, 1.3810 +// independent of the joypad buttons the emulated game thinks are pressed 1.3811 +// for example: 1.3812 +// if the user is holding the W key and the left mouse button 1.3813 +// and has the mouse at the bottom-right corner of the game screen, 1.3814 + 1.3815 +// then this would return {W=true, leftclick=true, xmouse=255, ymouse=223} 1.3816 + static int input_getcurrentinputstatus(lua_State *L) 1.3817 + { 1.3818 + lua_newtable(L); 1.3819 + 1.3820 +#if (defined(WIN32) && !defined(SDL)) 1.3821 + // keyboard and mouse button status 1.3822 + { 1.3823 + unsigned char keys[256]; 1.3824 + if (true /*!GUI.BackgroundInput*/) // TODO: background input 1.3825 + { 1.3826 + if (GetKeyboardState(keys)) 1.3827 + { 1.3828 + for (int i = 1; i < 255; i++) 1.3829 + { 1.3830 + int mask = (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) ? 0x01 : 0x80; 1.3831 + if (keys[i] & mask) 1.3832 + { 1.3833 + const char *name = s_keyToName[i]; 1.3834 + if (name) 1.3835 + { 1.3836 + lua_pushboolean(L, true); 1.3837 + lua_setfield(L, -2, name); 1.3838 + } 1.3839 + } 1.3840 + } 1.3841 + } 1.3842 + } 1.3843 + else // use a slightly different method that will detect background input: 1.3844 + { 1.3845 + for (int i = 1; i < 255; i++) 1.3846 + { 1.3847 + const char *name = s_keyToName[i]; 1.3848 + if (name) 1.3849 + { 1.3850 + int active; 1.3851 + if (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) 1.3852 + active = GetKeyState(i) & 0x01; 1.3853 + else 1.3854 + active = GetAsyncKeyState(i) & 0x8000; 1.3855 + if (active) 1.3856 + { 1.3857 + lua_pushboolean(L, true); 1.3858 + lua_setfield(L, -2, name); 1.3859 + } 1.3860 + } 1.3861 + } 1.3862 + } 1.3863 + } 1.3864 + 1.3865 + // mouse position in game screen pixel coordinates 1.3866 + { 1.3867 + POINT mouse; 1.3868 + 1.3869 + int xofs = 0, yofs = 0, width = 240, height = 160; 1.3870 + if (!systemIsRunningGBA()) 1.3871 + { 1.3872 + if (gbBorderOn) 1.3873 + width = 256, height = 224, xofs = 48, yofs = 40; 1.3874 + else 1.3875 + width = 160, height = 144; 1.3876 + } 1.3877 + 1.3878 + GetCursorPos(&mouse); 1.3879 + AfxGetApp()->m_pMainWnd->ScreenToClient(&mouse); 1.3880 + 1.3881 + // game screen is always fully stretched to window size, 1.3882 + // with no aspect rate correction, or something like that. 1.3883 + RECT clientRect; 1.3884 + AfxGetApp()->m_pMainWnd->GetClientRect(&clientRect); 1.3885 + 1.3886 + int wndWidth = clientRect.right - clientRect.left; 1.3887 + int wndHeight = clientRect.bottom - clientRect.top; 1.3888 + mouse.x = (LONG) (mouse.x * ((float)width / wndWidth)) - xofs; 1.3889 + mouse.y = (LONG) (mouse.y * ((float)height / wndHeight)) - yofs; 1.3890 + 1.3891 + lua_pushinteger(L, mouse.x); 1.3892 + lua_setfield(L, -2, "xmouse"); 1.3893 + lua_pushinteger(L, mouse.y); 1.3894 + lua_setfield(L, -2, "ymouse"); 1.3895 + } 1.3896 + 1.3897 +#else 1.3898 + // NYI (well, return an empty table) 1.3899 +#endif 1.3900 + return 1; 1.3901 + } 1.3902 + 1.3903 + static int avi_framecount(lua_State *L) 1.3904 + { 1.3905 + #ifdef WIN32 1.3906 + if (theApp.aviRecorder != NULL) 1.3907 + { 1.3908 + lua_pushinteger(L, theApp.aviRecorder->videoFrames()); 1.3909 + } 1.3910 + else 1.3911 + #endif 1.3912 + { 1.3913 + lua_pushinteger(L, 0); 1.3914 + } 1.3915 + return 1; 1.3916 + } 1.3917 + 1.3918 + static int avi_pause(lua_State *L) 1.3919 + { 1.3920 + #ifdef WIN32 1.3921 + if (theApp.aviRecorder != NULL) 1.3922 + theApp.aviRecorder->Pause(true); 1.3923 + #endif 1.3924 + return 1; 1.3925 + } 1.3926 + 1.3927 + static int avi_resume(lua_State *L) 1.3928 + { 1.3929 + #ifdef WIN32 1.3930 + if (theApp.aviRecorder != NULL) 1.3931 + theApp.aviRecorder->Pause(false); 1.3932 + #endif 1.3933 + return 1; 1.3934 + } 1.3935 + 1.3936 + static int sound_get(lua_State *L) 1.3937 + { 1.3938 + extern int32 soundLevel1; 1.3939 + extern int32 soundLevel2; 1.3940 + extern int32 soundBalance; 1.3941 + extern int32 soundMasterOn; 1.3942 + extern int32 soundVIN; 1.3943 + extern int32 sound1On; 1.3944 + extern int32 sound1EnvelopeVolume; 1.3945 + extern int32 sound2On; 1.3946 + extern int32 sound2EnvelopeVolume; 1.3947 + extern int32 sound3On; 1.3948 + extern int32 sound3OutputLevel; 1.3949 + extern int32 sound3Bank; 1.3950 + extern int32 sound3DataSize; 1.3951 + extern int32 sound3ForcedOutput; 1.3952 + extern int32 sound4On; 1.3953 + extern int32 sound4EnvelopeVolume; 1.3954 + extern u8 sound3WaveRam[0x20]; 1.3955 + 1.3956 + int freqReg; 1.3957 + double freq; 1.3958 + double leftvolscale; 1.3959 + double rightvolscale; 1.3960 + double panpot; 1.3961 + bool gba = systemIsRunningGBA(); 1.3962 + u8* gbMem = gba ? ioMem : gbMemory; 1.3963 + const int rNR10 = gba ? 0x60 : 0xff10; 1.3964 + const int rNR11 = gba ? 0x62 : 0xff11; 1.3965 + const int rNR12 = gba ? 0x63 : 0xff12; 1.3966 + const int rNR13 = gba ? 0x64 : 0xff13; 1.3967 + const int rNR14 = gba ? 0x65 : 0xff14; 1.3968 + const int rNR21 = gba ? 0x68 : 0xff16; 1.3969 + const int rNR22 = gba ? 0x69 : 0xff17; 1.3970 + const int rNR23 = gba ? 0x6c : 0xff18; 1.3971 + const int rNR24 = gba ? 0x6d : 0xff19; 1.3972 + const int rNR30 = gba ? 0x70 : 0xff1a; 1.3973 + const int rNR31 = gba ? 0x72 : 0xff1b; 1.3974 + const int rNR32 = gba ? 0x73 : 0xff1c; 1.3975 + const int rNR33 = gba ? 0x74 : 0xff1d; 1.3976 + const int rNR34 = gba ? 0x75 : 0xff1e; 1.3977 + const int rNR41 = gba ? 0x78 : 0xff20; 1.3978 + const int rNR42 = gba ? 0x79 : 0xff21; 1.3979 + const int rNR43 = gba ? 0x7c : 0xff22; 1.3980 + const int rNR44 = gba ? 0x7d : 0xff23; 1.3981 + const int rNR50 = gba ? 0x80 : 0xff24; 1.3982 + const int rNR51 = gba ? 0x81 : 0xff25; 1.3983 + const int rNR52 = gba ? 0x84 : 0xff26; 1.3984 + const int rWAVE_RAM = gba ? 0x90 : 0xff30; 1.3985 + 1.3986 + const int32 _soundVIN = 0x88; // gba ? 0x88 : soundVIN; 1.3987 + const bool soundVINLeft = ((_soundVIN & 0x80) != 0); 1.3988 + const bool soundVINRight = ((_soundVIN & 0x08) != 0); 1.3989 + 1.3990 + lua_newtable(L); 1.3991 + 1.3992 + // square1 1.3993 + lua_newtable(L); 1.3994 + if(sound1On == 0 || soundMasterOn == 0) 1.3995 + { 1.3996 + lua_pushnumber(L, 0.0); 1.3997 + panpot = 0.5; 1.3998 + } 1.3999 + else 1.4000 + { 1.4001 + double envVolume = sound1EnvelopeVolume / 15.0; 1.4002 + if (soundVINLeft && (soundBalance & 0x10) != 0) 1.4003 + leftvolscale = ((soundLevel2 / 7.0) * envVolume); 1.4004 + else 1.4005 + leftvolscale = 0.0; 1.4006 + if (soundVINRight && (soundBalance & 0x01) != 0) 1.4007 + rightvolscale = ((soundLevel1 / 7.0) * envVolume); 1.4008 + else 1.4009 + rightvolscale = 0.0; 1.4010 + if ((leftvolscale + rightvolscale) != 0) 1.4011 + panpot = rightvolscale / (leftvolscale + rightvolscale); 1.4012 + else 1.4013 + panpot = 0.5; 1.4014 + lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); 1.4015 + } 1.4016 + lua_setfield(L, -2, "volume"); 1.4017 + lua_pushnumber(L, panpot); 1.4018 + lua_setfield(L, -2, "panpot"); 1.4019 + freqReg = (((int)(gbMem[rNR14] & 7) << 8) | gbMem[rNR13]); 1.4020 + freq = 131072.0 / (2048 - freqReg); 1.4021 + lua_pushnumber(L, freq); 1.4022 + lua_setfield(L, -2, "frequency"); 1.4023 + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); 1.4024 + lua_setfield(L, -2, "midikey"); 1.4025 + lua_pushinteger(L, (gbMem[rNR11] & 0xC0) >> 6); 1.4026 + lua_setfield(L, -2, "duty"); 1.4027 + lua_newtable(L); 1.4028 + lua_pushinteger(L, freqReg); 1.4029 + lua_setfield(L, -2, "frequency"); 1.4030 + lua_setfield(L, -2, "regs"); 1.4031 + lua_setfield(L, -2, "square1"); 1.4032 + // square2 1.4033 + lua_newtable(L); 1.4034 + if(sound2On == 0 || soundMasterOn == 0) 1.4035 + { 1.4036 + lua_pushnumber(L, 0.0); 1.4037 + panpot = 0.5; 1.4038 + } 1.4039 + else 1.4040 + { 1.4041 + double envVolume = sound2EnvelopeVolume / 15.0; 1.4042 + if (soundVINLeft && (soundBalance & 0x20) != 0) 1.4043 + leftvolscale = ((soundLevel2 / 7.0) * envVolume); 1.4044 + else 1.4045 + leftvolscale = 0.0; 1.4046 + if (soundVINRight && (soundBalance & 0x02) != 0) 1.4047 + rightvolscale = ((soundLevel1 / 7.0) * envVolume); 1.4048 + else 1.4049 + rightvolscale = 0.0; 1.4050 + if ((leftvolscale + rightvolscale) != 0) 1.4051 + panpot = rightvolscale / (leftvolscale + rightvolscale); 1.4052 + else 1.4053 + panpot = 0.5; 1.4054 + lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); 1.4055 + } 1.4056 + lua_setfield(L, -2, "volume"); 1.4057 + lua_pushnumber(L, panpot); 1.4058 + lua_setfield(L, -2, "panpot"); 1.4059 + freqReg = (((int)(gbMem[rNR24] & 7) << 8) | gbMem[rNR23]); 1.4060 + freq = 131072.0 / (2048 - freqReg); 1.4061 + lua_pushnumber(L, freq); 1.4062 + lua_setfield(L, -2, "frequency"); 1.4063 + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); 1.4064 + lua_setfield(L, -2, "midikey"); 1.4065 + lua_pushinteger(L, (gbMem[rNR21] & 0xC0) >> 6); 1.4066 + lua_setfield(L, -2, "duty"); 1.4067 + lua_newtable(L); 1.4068 + lua_pushinteger(L, freqReg); 1.4069 + lua_setfield(L, -2, "frequency"); 1.4070 + lua_setfield(L, -2, "regs"); 1.4071 + lua_setfield(L, -2, "square2"); 1.4072 + // wavememory 1.4073 + lua_newtable(L); 1.4074 + if(sound3On == 0 || soundMasterOn == 0) 1.4075 + { 1.4076 + lua_pushnumber(L, 0.0); 1.4077 + panpot = 0.5; 1.4078 + } 1.4079 + else 1.4080 + { 1.4081 + double envVolume; 1.4082 + if (gba && sound3ForcedOutput != 0) 1.4083 + envVolume = 0.75; 1.4084 + else 1.4085 + { 1.4086 + double volTable[4] = { 0.0, 1.0, 0.5, 0.25 }; 1.4087 + envVolume = volTable[sound3OutputLevel & 3]; 1.4088 + } 1.4089 + 1.4090 + if (soundVINLeft && (soundBalance & 0x40) != 0) 1.4091 + leftvolscale = ((soundLevel2 / 7.0) * envVolume); 1.4092 + else 1.4093 + leftvolscale = 0.0; 1.4094 + if (soundVINRight && (soundBalance & 0x04) != 0) 1.4095 + rightvolscale = ((soundLevel1 / 7.0) * envVolume); 1.4096 + else 1.4097 + rightvolscale = 0.0; 1.4098 + if ((leftvolscale + rightvolscale) != 0) 1.4099 + panpot = rightvolscale / (leftvolscale + rightvolscale); 1.4100 + else 1.4101 + panpot = 0.5; 1.4102 + lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); 1.4103 + } 1.4104 + lua_setfield(L, -2, "volume"); 1.4105 + lua_pushnumber(L, panpot); 1.4106 + lua_setfield(L, -2, "panpot"); 1.4107 + int waveMemSamples = 32; 1.4108 + if (gba) 1.4109 + { 1.4110 + lua_pushlstring(L, (const char *) &sound3WaveRam[sound3Bank * 0x10], sound3DataSize ? 0x20 : 0x10); 1.4111 + waveMemSamples = sound3DataSize ? 64 : 32; 1.4112 + } 1.4113 + else 1.4114 + { 1.4115 + lua_pushlstring(L, (const char *) &gbMem[rWAVE_RAM], 0x10); 1.4116 + } 1.4117 + lua_setfield(L, -2, "waveform"); 1.4118 + freqReg = (((int)(gbMem[rNR34] & 7) << 8) | gbMem[rNR33]); 1.4119 + freq = 2097152.0 / (waveMemSamples * (2048 - freqReg)); 1.4120 + lua_pushnumber(L, freq); 1.4121 + lua_setfield(L, -2, "frequency"); 1.4122 + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); 1.4123 + lua_setfield(L, -2, "midikey"); 1.4124 + lua_newtable(L); 1.4125 + lua_pushinteger(L, freqReg); 1.4126 + lua_setfield(L, -2, "frequency"); 1.4127 + lua_setfield(L, -2, "regs"); 1.4128 + lua_setfield(L, -2, "wavememory"); 1.4129 + // noise 1.4130 + lua_newtable(L); 1.4131 + if(sound4On == 0 || soundMasterOn == 0) 1.4132 + { 1.4133 + lua_pushnumber(L, 0.0); 1.4134 + panpot = 0.5; 1.4135 + } 1.4136 + else 1.4137 + { 1.4138 + double envVolume = sound4EnvelopeVolume / 15.0; 1.4139 + if (soundVINLeft && (soundBalance & 0x80) != 0) 1.4140 + leftvolscale = ((soundLevel2 / 7.0) * envVolume); 1.4141 + else 1.4142 + leftvolscale = 0.0; 1.4143 + if (soundVINRight && (soundBalance & 0x08) != 0) 1.4144 + rightvolscale = ((soundLevel1 / 7.0) * envVolume); 1.4145 + else 1.4146 + rightvolscale = 0.0; 1.4147 + if ((leftvolscale + rightvolscale) != 0) 1.4148 + panpot = rightvolscale / (leftvolscale + rightvolscale); 1.4149 + else 1.4150 + panpot = 0.5; 1.4151 + lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0); 1.4152 + } 1.4153 + lua_setfield(L, -2, "volume"); 1.4154 + lua_pushnumber(L, panpot); 1.4155 + lua_setfield(L, -2, "panpot"); 1.4156 + const int gbNoiseFreqTable[8] = { 1, 2, 4, 6, 8, 10, 12, 14 }; 1.4157 + freqReg = gbNoiseFreqTable[gbMem[rNR43] & 7] << (1 + (gbMem[rNR43] >> 4)); 1.4158 + lua_pushboolean(L, (gbMem[rNR43] & 8) != 0); 1.4159 + lua_setfield(L, -2, "short"); 1.4160 + freq = 1048576.0 / freqReg; 1.4161 + lua_pushnumber(L, freq); 1.4162 + lua_setfield(L, -2, "frequency"); 1.4163 + lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69); 1.4164 + lua_setfield(L, -2, "midikey"); 1.4165 + lua_newtable(L); 1.4166 + lua_pushinteger(L, freqReg); 1.4167 + lua_setfield(L, -2, "frequency"); 1.4168 + lua_setfield(L, -2, "regs"); 1.4169 + lua_setfield(L, -2, "noise"); 1.4170 + 1.4171 + return 1; 1.4172 + } 1.4173 + 1.4174 +// same as math.random, but uses SFMT instead of C rand() 1.4175 +// FIXME: this function doesn't care multi-instance, 1.4176 + 1.4177 +// original math.random either though (Lua 5.1) 1.4178 + static int sfmt_random(lua_State *L) 1.4179 + { 1.4180 + lua_Number r = (lua_Number) genrand_real2(); 1.4181 + switch (lua_gettop(L)) 1.4182 + { // check number of arguments 1.4183 + case 0: 1.4184 + { // no arguments 1.4185 + lua_pushnumber(L, r); // Number between 0 and 1 1.4186 + break; 1.4187 + } 1.4188 + 1.4189 + case 1: 1.4190 + { // only upper limit 1.4191 + int u = luaL_checkint(L, 1); 1.4192 + luaL_argcheck(L, 1 <= u, 1, "interval is empty"); 1.4193 + lua_pushnumber(L, floor(r * u) + 1); // int between 1 and `u' 1.4194 + break; 1.4195 + } 1.4196 + 1.4197 + case 2: 1.4198 + { // lower and upper limits 1.4199 + int l = luaL_checkint(L, 1); 1.4200 + int u = luaL_checkint(L, 2); 1.4201 + luaL_argcheck(L, l <= u, 2, "interval is empty"); 1.4202 + lua_pushnumber(L, floor(r * (u - l + 1)) + l); // int between `l' and `u' 1.4203 + break; 1.4204 + } 1.4205 + 1.4206 + default: 1.4207 + return luaL_error(L, "wrong number of arguments"); 1.4208 + } 1.4209 + 1.4210 + return 1; 1.4211 + } 1.4212 + 1.4213 +// same as math.randomseed, but uses SFMT instead of C srand() 1.4214 +// FIXME: this function doesn't care multi-instance, 1.4215 + 1.4216 +// original math.randomseed either though (Lua 5.1) 1.4217 + static int sfmt_randomseed(lua_State *L) 1.4218 + { 1.4219 + init_gen_rand(luaL_checkint(L, 1)); 1.4220 + return 0; 1.4221 + } 1.4222 + 1.4223 +// the following bit operations are ported from LuaBitOp 1.0.1, 1.4224 +// because it can handle the sign bit (bit 31) correctly. 1.4225 + 1.4226 +/* 1.4227 +** Lua BitOp -- a bit operations library for Lua 5.1. 1.4228 +** http://bitop.luajit.org/ 1.4229 +** 1.4230 +** Copyright (C) 2008-2009 Mike Pall. All rights reserved. 1.4231 +** 1.4232 +** Permission is hereby granted, free of charge, to any person obtaining 1.4233 +** a copy of this software and associated documentation files (the 1.4234 +** "Software"), to deal in the Software without restriction, including 1.4235 +** without limitation the rights to use, copy, modify, merge, publish, 1.4236 +** distribute, sublicense, and/or sell copies of the Software, and to 1.4237 +** permit persons to whom the Software is furnished to do so, subject to 1.4238 +** the following conditions: 1.4239 +** 1.4240 +** The above copyright notice and this permission notice shall be 1.4241 +** included in all copies or substantial portions of the Software. 1.4242 +** 1.4243 +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1.4244 +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1.4245 +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1.4246 +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 1.4247 +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 1.4248 +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 1.4249 +** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1.4250 +** 1.4251 +** [ MIT license: http://www.opensource.org/licenses/mit-license.php ] 1.4252 +*/ 1.4253 + 1.4254 +#ifdef _MSC_VER 1.4255 +/* MSVC is stuck in the last century and doesn't have C99's stdint.h. */ 1.4256 + typedef __int32 int32_t; 1.4257 + typedef unsigned __int32 uint32_t; 1.4258 + typedef unsigned __int64 uint64_t; 1.4259 +#else 1.4260 +#include <stdint.h> 1.4261 +#endif 1.4262 + 1.4263 + typedef int32_t SBits; 1.4264 + typedef uint32_t UBits; 1.4265 + 1.4266 + typedef union 1.4267 + { 1.4268 + lua_Number n; 1.4269 +#ifdef LUA_NUMBER_DOUBLE 1.4270 + uint64_t b; 1.4271 +#else 1.4272 + UBits b; 1.4273 +#endif 1.4274 + } BitNum; 1.4275 + 1.4276 +/* Convert argument to bit type. */ 1.4277 + static UBits barg(lua_State *L, int idx) 1.4278 + { 1.4279 + BitNum bn; 1.4280 + UBits b; 1.4281 + bn.n = lua_tonumber(L, idx); 1.4282 +#if defined(LUA_NUMBER_DOUBLE) 1.4283 + bn.n += 6755399441055744.0; /* 2^52+2^51 */ 1.4284 +#ifdef SWAPPED_DOUBLE 1.4285 + b = (UBits)(bn.b >> 32); 1.4286 +#else 1.4287 + b = (UBits)(bn.b & 0xffffffff); 1.4288 +#endif 1.4289 +#elif defined(LUA_NUMBER_INT) || defined(LUA_NUMBER_LONG) || \ 1.4290 + defined(LUA_NUMBER_LONGLONG) || defined(LUA_NUMBER_LONG_LONG) || \ 1.4291 + defined(LUA_NUMBER_LLONG) 1.4292 + if (sizeof(UBits) == sizeof(lua_Number)) 1.4293 + b = bn.b; 1.4294 + else 1.4295 + b = (UBits)(SBits)bn.n; 1.4296 +#elif defined(LUA_NUMBER_FLOAT) 1.4297 +#error "A 'float' lua_Number type is incompatible with this library" 1.4298 +#else 1.4299 +#error "Unknown number type, check LUA_NUMBER_* in luaconf.h" 1.4300 +#endif 1.4301 + if (b == 0 && !lua_isnumber(L, idx)) 1.4302 + luaL_typerror(L, idx, "number"); 1.4303 + return b; 1.4304 + } 1.4305 + 1.4306 +/* Return bit type. */ 1.4307 +#define BRET(b) lua_pushnumber(L, (lua_Number)(SBits)(b)); return 1; 1.4308 + 1.4309 + static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) } 1.4310 + static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) } 1.4311 + 1.4312 +#define BIT_OP(func, opr) \ 1.4313 + static int func(lua_State * L) { int i; UBits b = barg(L, 1); \ 1.4314 + for (i = lua_gettop(L); i > 1; i--) \ 1.4315 + b opr barg(L, i); BRET(b) } 1.4316 + BIT_OP(bit_band, &= ) 1.4317 + BIT_OP(bit_bor, |= ) 1.4318 + BIT_OP(bit_bxor, ^= ) 1.4319 + 1.4320 +#define bshl(b, n) (b << n) 1.4321 +#define bshr(b, n) (b >> n) 1.4322 +#define bsar(b, n) ((SBits)b >> n) 1.4323 +#define brol(b, n) ((b << n) | (b >> (32 - n))) 1.4324 +#define bror(b, n) ((b << (32 - n)) | (b >> n)) 1.4325 +#define BIT_SH(func, fn) \ 1.4326 + static int func(lua_State * L) { \ 1.4327 + UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) } 1.4328 + BIT_SH(bit_lshift, bshl) 1.4329 + BIT_SH(bit_rshift, bshr) 1.4330 + BIT_SH(bit_arshift, bsar) 1.4331 + BIT_SH(bit_rol, brol) 1.4332 + BIT_SH(bit_ror, bror) 1.4333 + 1.4334 + static int bit_bswap(lua_State *L) 1.4335 + { 1.4336 + UBits b = barg(L, 1); 1.4337 + b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24); 1.4338 + BRET(b) 1.4339 + } 1.4340 + 1.4341 + static int bit_tohex(lua_State *L) 1.4342 + { 1.4343 + UBits b = barg(L, 1); 1.4344 + SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2); 1.4345 + const char *hexdigits = "0123456789abcdef"; 1.4346 + char buf[8]; 1.4347 + int i; 1.4348 + if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; } 1.4349 + if (n > 8) n = 8; 1.4350 + for (i = (int)n; --i >= 0; ) 1.4351 + { 1.4352 + buf[i] = hexdigits[b & 15]; b >>= 4; 1.4353 + } 1.4354 + lua_pushlstring(L, buf, (size_t)n); 1.4355 + return 1; 1.4356 + } 1.4357 + 1.4358 + static const struct luaL_Reg bit_funcs[] = { 1.4359 + { "tobit", bit_tobit }, 1.4360 + { "bnot", bit_bnot }, 1.4361 + { "band", bit_band }, 1.4362 + { "bor", bit_bor }, 1.4363 + { "bxor", bit_bxor }, 1.4364 + { "lshift", bit_lshift }, 1.4365 + { "rshift", bit_rshift }, 1.4366 + { "arshift", bit_arshift }, 1.4367 + { "rol", bit_rol }, 1.4368 + { "ror", bit_ror }, 1.4369 + { "bswap", bit_bswap }, 1.4370 + { "tohex", bit_tohex }, 1.4371 + { NULL, NULL } 1.4372 + }; 1.4373 + 1.4374 +/* Signed right-shifts are implementation-defined per C89/C99. 1.4375 +** But the de facto standard are arithmetic right-shifts on two's 1.4376 +** complement CPUs. This behaviour is required here, so test for it. 1.4377 +*/ 1.4378 +#define BAD_SAR (bsar(-8, 2) != (SBits) - 2) 1.4379 + 1.4380 + bool luabitop_validate(lua_State *L) // originally named as luaopen_bit 1.4381 + { 1.4382 + UBits b; 1.4383 + lua_pushnumber(L, (lua_Number)1437217655L); 1.4384 + b = barg(L, -1); 1.4385 + if (b != (UBits)1437217655L || BAD_SAR) /* Perform a simple self-test. */ 1.4386 + { 1.4387 + const char *msg = "compiled with incompatible luaconf.h"; 1.4388 +#ifdef LUA_NUMBER_DOUBLE 1.4389 +#ifdef WIN32 1.4390 + if (b == (UBits)1610612736L) 1.4391 + msg = "use D3DCREATE_FPU_PRESERVE with DirectX"; 1.4392 +#endif 1.4393 + if (b == (UBits)1127743488L) 1.4394 + msg = "not compiled with SWAPPED_DOUBLE"; 1.4395 +#endif 1.4396 + if (BAD_SAR) 1.4397 + msg = "arithmetic right-shift broken"; 1.4398 + luaL_error(L, "bit library self-test failed (%s)", msg); 1.4399 + return false; 1.4400 + } 1.4401 + return true; 1.4402 + } 1.4403 + 1.4404 +// LuaBitOp ends here 1.4405 + 1.4406 + static int bit_bshift_emulua(lua_State *L) 1.4407 + { 1.4408 + int shift = luaL_checkinteger(L, 2); 1.4409 + if (shift < 0) 1.4410 + { 1.4411 + lua_pushinteger(L, -shift); 1.4412 + lua_replace(L, 2); 1.4413 + return bit_lshift(L); 1.4414 + } 1.4415 + else 1.4416 + return bit_rshift(L); 1.4417 + } 1.4418 + 1.4419 + static int bitbit(lua_State *L) 1.4420 + { 1.4421 + int rv = 0; 1.4422 + int numArgs = lua_gettop(L); 1.4423 + for (int i = 1; i <= numArgs; i++) 1.4424 + { 1.4425 + int where = luaL_checkinteger(L, i); 1.4426 + if (where >= 0 && where < 32) 1.4427 + rv |= (1 << where); 1.4428 + } 1.4429 + lua_settop(L, 0); 1.4430 + BRET(rv); 1.4431 + } 1.4432 + 1.4433 +// The function called periodically to ensure Lua doesn't run amok. 1.4434 + static void VBALuaHookFunction(lua_State *L, lua_Debug *dbg) 1.4435 + { 1.4436 + if (numTries-- == 0) 1.4437 + { 1.4438 + int kill = 0; 1.4439 + 1.4440 +#if (defined(WIN32) && !defined(SDL)) 1.4441 + // Uh oh 1.4442 + theApp.winCheckFullscreen(); 1.4443 + systemSoundClearBuffer(); 1.4444 + int ret = AfxGetApp()->m_pMainWnd->MessageBox( 1.4445 + "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)", 1.4446 + "Lua Script Gone Nuts?", 1.4447 + MB_YESNO); 1.4448 + 1.4449 + if (ret == IDYES) 1.4450 + { 1.4451 + kill = 1; 1.4452 + } 1.4453 + 1.4454 +#else 1.4455 + fprintf( 1.4456 + stderr, 1.4457 + "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"); 1.4458 + 1.4459 + char buffer[64]; 1.4460 + while (true) 1.4461 + { 1.4462 + fprintf(stderr, "(y/n): "); 1.4463 + fgets(buffer, sizeof(buffer), stdin); 1.4464 + if (buffer[0] == 'y' || buffer[0] == 'Y') 1.4465 + { 1.4466 + kill = 1; 1.4467 + break; 1.4468 + } 1.4469 + 1.4470 + if (buffer[0] == 'n' || buffer[0] == 'N') 1.4471 + break; 1.4472 + } 1.4473 +#endif 1.4474 + if (kill) 1.4475 + { 1.4476 + luaL_error(L, "Killed by user request."); 1.4477 + VBALuaOnStop(); 1.4478 + } 1.4479 + 1.4480 + // else, kill the debug hook. 1.4481 + lua_sethook(L, NULL, 0, 0); 1.4482 + } 1.4483 + } 1.4484 + 1.4485 + static const struct luaL_reg vbalib[] = { 1.4486 + // {"speedmode", vba_speedmode}, // TODO: NYI 1.4487 + { "frameadvance", vba_frameadvance }, 1.4488 + { "pause", vba_pause }, 1.4489 + { "framecount", vba_framecount }, 1.4490 + { "lagcount", vba_getlagcount }, 1.4491 + { "lagged", vba_lagged }, 1.4492 + { "emulating", vba_emulating }, 1.4493 + { "registerbefore", vba_registerbefore }, 1.4494 + { "registerafter", vba_registerafter }, 1.4495 + { "registerexit", vba_registerexit }, 1.4496 + { "message", vba_message }, 1.4497 + { "print", print }, // sure, why not 1.4498 + { NULL, NULL } 1.4499 + }; 1.4500 + 1.4501 + static const struct luaL_reg memorylib[] = { 1.4502 + { "readbyte", memory_readbyte }, 1.4503 + { "readbytesigned", memory_readbytesigned }, 1.4504 + { "readword", memory_readword }, 1.4505 + { "readwordsigned", memory_readwordsigned }, 1.4506 + { "readdword", memory_readdword }, 1.4507 + { "readdwordsigned", memory_readdwordsigned }, 1.4508 + { "readbyterange", memory_readbyterange }, 1.4509 + { "writebyte", memory_writebyte }, 1.4510 + { "writeword", memory_writeword }, 1.4511 + { "writedword", memory_writedword }, 1.4512 + { "getregister", memory_getregister }, 1.4513 + { "setregister", memory_setregister }, 1.4514 + { "gbromreadbyte", memory_gbromreadbyte }, 1.4515 + { "gbromreadbytesigned", memory_gbromreadbytesigned }, 1.4516 + { "gbromreadword", memory_gbromreadword }, 1.4517 + { "gbromreadwordsigned", memory_gbromreadwordsigned }, 1.4518 + { "gbromreaddword", memory_gbromreaddword }, 1.4519 + { "gbromreaddwordsigned", memory_gbromreaddwordsigned }, 1.4520 + { "gbromreadbyterange", memory_gbromreadbyterange }, 1.4521 + 1.4522 + // alternate naming scheme for word and double-word and unsigned 1.4523 + { "readbyteunsigned", memory_readbyte }, 1.4524 + { "readwordunsigned", memory_readword }, 1.4525 + { "readdwordunsigned", memory_readdword }, 1.4526 + { "readshort", memory_readword }, 1.4527 + { "readshortunsigned", memory_readword }, 1.4528 + { "readshortsigned", memory_readwordsigned }, 1.4529 + { "readlong", memory_readdword }, 1.4530 + { "readlongunsigned", memory_readdword }, 1.4531 + { "readlongsigned", memory_readdwordsigned }, 1.4532 + { "writeshort", memory_writeword }, 1.4533 + { "writelong", memory_writedword }, 1.4534 + { "gbromreadbyteunsigned", memory_gbromreadbyte }, 1.4535 + { "gbromreadwordunsigned", memory_gbromreadword }, 1.4536 + { "gbromreaddwordunsigned", memory_gbromreaddword }, 1.4537 + { "gbromreadshort", memory_gbromreadword }, 1.4538 + { "gbromreadshortunsigned", memory_gbromreadword }, 1.4539 + { "gbromreadshortsigned", memory_gbromreadwordsigned }, 1.4540 + { "gbromreadlong", memory_gbromreaddword }, 1.4541 + { "gbromreadlongunsigned", memory_gbromreaddword }, 1.4542 + { "gbromreadlongsigned", memory_gbromreaddwordsigned }, 1.4543 + 1.4544 + // memory hooks 1.4545 + { "registerwrite", memory_registerwrite }, 1.4546 + //{"registerread", memory_registerread}, 1.4547 + { "registerexec", memory_registerexec }, 1.4548 + // alternate names 1.4549 + { "register", memory_registerwrite }, 1.4550 + { "registerrun", memory_registerexec }, 1.4551 + { "registerexecute", memory_registerexec }, 1.4552 + 1.4553 + { NULL, NULL } 1.4554 + }; 1.4555 + 1.4556 + static const struct luaL_reg joypadlib[] = { 1.4557 + { "get", joypad_get }, 1.4558 + { "getdown", joypad_getdown }, 1.4559 + { "getup", joypad_getup }, 1.4560 + { "set", joypad_set }, 1.4561 + 1.4562 + // alternative names 1.4563 + { "read", joypad_get }, 1.4564 + { "write", joypad_set }, 1.4565 + { "readdown", joypad_getdown }, 1.4566 + { "readup", joypad_getup }, 1.4567 + { NULL, NULL } 1.4568 + }; 1.4569 + 1.4570 + static const struct luaL_reg savestatelib[] = { 1.4571 + { "create", savestate_create }, 1.4572 + { "save", savestate_save }, 1.4573 + { "load", savestate_load }, 1.4574 + 1.4575 + { NULL, NULL } 1.4576 + }; 1.4577 + 1.4578 + static const struct luaL_reg movielib[] = { 1.4579 + { "active", movie_isactive }, 1.4580 + { "recording", movie_isrecording }, 1.4581 + { "playing", movie_isplaying }, 1.4582 + { "mode", movie_getmode }, 1.4583 + 1.4584 + { "length", movie_getlength }, 1.4585 + { "author", movie_getauthor }, 1.4586 + { "name", movie_getfilename }, 1.4587 + { "rerecordcount", movie_rerecordcount }, 1.4588 + { "setrerecordcount", movie_setrerecordcount }, 1.4589 + 1.4590 + { "rerecordcounting", movie_rerecordcounting }, 1.4591 + { "framecount", vba_framecount }, // for those familiar with 1.4592 + // other emulators that have 1.4593 + // movie.framecount() 1.4594 + // instead of 1.4595 + // emulatorname.framecount() 1.4596 + 1.4597 + { "stop", movie_stop }, 1.4598 + 1.4599 + // alternative names 1.4600 + { "close", movie_stop }, 1.4601 + { "getauthor", movie_getauthor }, 1.4602 + { "getname", movie_getfilename }, 1.4603 + { NULL, NULL } 1.4604 + }; 1.4605 + 1.4606 + static const struct luaL_reg guilib[] = { 1.4607 + { "register", gui_register }, 1.4608 + { "text", gui_text }, 1.4609 + { "box", gui_drawbox }, 1.4610 + { "line", gui_drawline }, 1.4611 + { "pixel", gui_drawpixel }, 1.4612 + { "opacity", gui_setopacity }, 1.4613 + { "transparency", gui_transparency }, 1.4614 + { "popup", gui_popup }, 1.4615 + { "parsecolor", gui_parsecolor }, 1.4616 + { "gdscreenshot", gui_gdscreenshot }, 1.4617 + { "gdoverlay", gui_gdoverlay }, 1.4618 + { "getpixel", gui_getpixel }, 1.4619 + 1.4620 + // alternative names 1.4621 + { "drawtext", gui_text }, 1.4622 + { "drawbox", gui_drawbox }, 1.4623 + { "drawline", gui_drawline }, 1.4624 + { "drawpixel", gui_drawpixel }, 1.4625 + { "setpixel", gui_drawpixel }, 1.4626 + { "writepixel", gui_drawpixel }, 1.4627 + { "rect", gui_drawbox }, 1.4628 + { "drawrect", gui_drawbox }, 1.4629 + { "drawimage", gui_gdoverlay }, 1.4630 + { "image", gui_gdoverlay }, 1.4631 + { "readpixel", gui_getpixel }, 1.4632 + { NULL, NULL } 1.4633 + }; 1.4634 + 1.4635 + static const struct luaL_reg inputlib[] = { 1.4636 + { "get", input_getcurrentinputstatus }, 1.4637 + 1.4638 + // alternative names 1.4639 + { "read", input_getcurrentinputstatus }, 1.4640 + { NULL, NULL } 1.4641 + }; 1.4642 + 1.4643 + static const struct luaL_reg soundlib[] = { 1.4644 + { "get", sound_get }, 1.4645 + 1.4646 + // alternative names 1.4647 + { NULL, NULL } 1.4648 + }; 1.4649 + 1.4650 +// gocha: since vba dumps avi so badly, 1.4651 +// I add avilib as a workaround for enhanced video encoding. 1.4652 + static const struct luaL_reg avilib[] = { 1.4653 + { "framecount", avi_framecount }, 1.4654 + { "pause", avi_pause }, 1.4655 + { "resume", avi_resume }, 1.4656 + { NULL, NULL } 1.4657 + }; 1.4658 + 1.4659 + void CallExitFunction(void) 1.4660 + { 1.4661 + if (!LUA) 1.4662 + return; 1.4663 + 1.4664 + lua_settop(LUA, 0); 1.4665 + lua_getfield(LUA, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]); 1.4666 + 1.4667 + int errorcode = 0; 1.4668 + if (lua_isfunction(LUA, -1)) 1.4669 + { 1.4670 + errorcode = lua_pcall(LUA, 0, 0, 0); 1.4671 + } 1.4672 + 1.4673 + if (errorcode) 1.4674 + HandleCallbackError(LUA); 1.4675 + } 1.4676 + 1.4677 + void VBALuaFrameBoundary(void) 1.4678 + { 1.4679 + // printf("Lua Frame\n"); 1.4680 + 1.4681 + lua_joypads_used = 0; 1.4682 + 1.4683 + // HA! 1.4684 + if (!LUA || !luaRunning) 1.4685 + return; 1.4686 + 1.4687 + // Our function needs calling 1.4688 + lua_settop(LUA, 0); 1.4689 + lua_getfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread); 1.4690 + 1.4691 + lua_State *thread = lua_tothread(LUA, 1); 1.4692 + 1.4693 + // Lua calling C must know that we're busy inside a frame boundary 1.4694 + frameBoundary = true; 1.4695 + frameAdvanceWaiting = false; 1.4696 + 1.4697 + numTries = 1000; 1.4698 + 1.4699 + int result = lua_resume(thread, 0); 1.4700 + 1.4701 + if (result == LUA_YIELD) 1.4702 + { 1.4703 + // Okay, we're fine with that. 1.4704 + } 1.4705 + else if (result != 0) 1.4706 + { 1.4707 + // Done execution by bad causes 1.4708 + VBALuaOnStop(); 1.4709 + lua_pushnil(LUA); 1.4710 + lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread); 1.4711 + lua_pushnil(LUA); 1.4712 + lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); 1.4713 + 1.4714 + // Error? 1.4715 +//#if (defined(WIN32) && !defined(SDL)) 1.4716 +// info_print(info_uid, lua_tostring(thread, -1)); //Clear_Sound_Buffer(); 1.4717 +// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(thread, -1), "Lua run error", MB_OK | MB_ICONSTOP); 1.4718 +//#else 1.4719 +// fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(thread, -1)); 1.4720 +//#endif 1.4721 + printerror(thread, -1); 1.4722 + } 1.4723 + else 1.4724 + { 1.4725 + VBALuaOnStop(); 1.4726 + printf("Script died of natural causes.\n"); 1.4727 + } 1.4728 + 1.4729 + // Past here, VBA actually runs, so any Lua code is called mid-frame. We must 1.4730 + // not do anything too stupid, so let ourselves know. 1.4731 + frameBoundary = false; 1.4732 + 1.4733 + if (!frameAdvanceWaiting) 1.4734 + { 1.4735 + VBALuaOnStop(); 1.4736 + } 1.4737 + } 1.4738 + 1.4739 +/** 1.4740 + * Loads and runs the given Lua script. 1.4741 + * The emulator MUST be paused for this function to be 1.4742 + * called. Otherwise, all frame boundary assumptions go out the window. 1.4743 + * 1.4744 + * Returns true on success, false on failure. 1.4745 + */ 1.4746 + int VBALoadLuaCode(const char *filename) 1.4747 + { 1.4748 + static bool sfmtInitialized = false; 1.4749 + if (!sfmtInitialized) 1.4750 + { 1.4751 + init_gen_rand((unsigned)time(NULL)); 1.4752 + sfmtInitialized = true; 1.4753 + } 1.4754 + 1.4755 + if (filename != luaScriptName) 1.4756 + { 1.4757 + if (luaScriptName) 1.4758 + free(luaScriptName); 1.4759 + luaScriptName = strdup(filename); 1.4760 + } 1.4761 + 1.4762 + //stop any lua we might already have had running 1.4763 + VBALuaStop(); 1.4764 + 1.4765 + // Set current directory from filename (for dofile) 1.4766 + char dir[_MAX_PATH]; 1.4767 + char *slash, *backslash; 1.4768 + strcpy(dir, filename); 1.4769 + slash = strrchr(dir, '/'); 1.4770 + backslash = strrchr(dir, '\\'); 1.4771 + if (!slash || (backslash && backslash < slash)) 1.4772 + slash = backslash; 1.4773 + if (slash) 1.4774 + { 1.4775 + slash[1] = '\0'; // keep slash itself for some reasons 1.4776 + chdir(dir); 1.4777 + } 1.4778 + 1.4779 + if (!LUA) 1.4780 + { 1.4781 + LUA = lua_open(); 1.4782 + luaL_openlibs(LUA); 1.4783 + 1.4784 + luaL_register(LUA, "emu", vbalib); // added for better cross-emulator compatibility 1.4785 + luaL_register(LUA, "vba", vbalib); // kept for backward compatibility 1.4786 + luaL_register(LUA, "memory", memorylib); 1.4787 + luaL_register(LUA, "joypad", joypadlib); 1.4788 + luaL_register(LUA, "savestate", savestatelib); 1.4789 + luaL_register(LUA, "movie", movielib); 1.4790 + luaL_register(LUA, "gui", guilib); 1.4791 + luaL_register(LUA, "input", inputlib); 1.4792 + luaL_register(LUA, "sound", soundlib); 1.4793 + luaL_register(LUA, "bit", bit_funcs); // LuaBitOp library 1.4794 + luaL_register(LUA, "avi", avilib); // workaround for enhanced video encoding 1.4795 + lua_settop(LUA, 0); // clean the stack, because each call to luaL_register leaves a table on top 1.4796 + 1.4797 + // register a few utility functions outside of libraries (in the global namespace) 1.4798 + lua_register(LUA, "print", print); 1.4799 + lua_register(LUA, "tostring", tostring); 1.4800 + lua_register(LUA, "addressof", addressof); 1.4801 + lua_register(LUA, "copytable", copytable); 1.4802 + 1.4803 + // old bit operation functions 1.4804 + lua_register(LUA, "AND", bit_band); 1.4805 + lua_register(LUA, "OR", bit_bor); 1.4806 + lua_register(LUA, "XOR", bit_bxor); 1.4807 + lua_register(LUA, "SHIFT", bit_bshift_emulua); 1.4808 + lua_register(LUA, "BIT", bitbit); 1.4809 + 1.4810 + luabitop_validate(LUA); 1.4811 + 1.4812 + lua_pushstring(LUA, "math"); 1.4813 + lua_gettable(LUA, LUA_GLOBALSINDEX); 1.4814 + lua_pushcfunction(LUA, sfmt_random); 1.4815 + lua_setfield(LUA, -2, "random"); 1.4816 + lua_pushcfunction(LUA, sfmt_randomseed); 1.4817 + lua_setfield(LUA, -2, "randomseed"); 1.4818 + lua_settop(LUA, 0); 1.4819 + 1.4820 + // push arrays for storing hook functions in 1.4821 + for (int i = 0; i < LUAMEMHOOK_COUNT; i++) 1.4822 + { 1.4823 + lua_newtable(LUA); 1.4824 + lua_setfield(LUA, LUA_REGISTRYINDEX, luaMemHookTypeStrings[i]); 1.4825 + } 1.4826 + } 1.4827 + 1.4828 + // We make our thread NOW because we want it at the bottom of the stack. 1.4829 + // If all goes wrong, we let the garbage collector remove it. 1.4830 + lua_State *thread = lua_newthread(LUA); 1.4831 + 1.4832 + // Load the data 1.4833 + int result = luaL_loadfile(LUA, filename); 1.4834 + 1.4835 + if (result) 1.4836 + { 1.4837 +//#if (defined(WIN32) && !defined(SDL)) 1.4838 +// info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer(); 1.4839 +// AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua load error", MB_OK | MB_ICONSTOP); 1.4840 +//#else 1.4841 +// fprintf(stderr, "Failed to compile file: %s\n", lua_tostring(LUA, -1)); 1.4842 +//#endif 1.4843 + printerror(LUA, -1); 1.4844 + 1.4845 + // Wipe the stack. Our thread 1.4846 + lua_settop(LUA, 0); 1.4847 + return 0; // Oh shit. 1.4848 + } 1.4849 + 1.4850 + // Get our function into it 1.4851 + lua_xmove(LUA, thread, 1); 1.4852 + 1.4853 + // Save the thread to the registry. This is why I make the thread FIRST. 1.4854 + lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread); 1.4855 + 1.4856 + // Initialize settings 1.4857 + luaRunning = true; 1.4858 + skipRerecords = false; 1.4859 + numMemHooks = 0; 1.4860 + transparencyModifier = 255; // opaque 1.4861 + lua_joypads_used = 0; // not used 1.4862 + //wasPaused = systemIsPaused(); 1.4863 + //systemSetPause(false); 1.4864 + 1.4865 + // Set up our protection hook to be executed once every 10,000 bytecode instructions. 1.4866 + lua_sethook(thread, VBALuaHookFunction, LUA_MASKCOUNT, 10000); 1.4867 + 1.4868 +#ifdef WIN32 1.4869 + info_print = PrintToWindowConsole; 1.4870 + info_onstart = WinLuaOnStart; 1.4871 + info_onstop = WinLuaOnStop; 1.4872 + if (!LuaConsoleHWnd) 1.4873 + LuaConsoleHWnd = CreateDialog(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDD_LUA), 1.4874 + AfxGetMainWnd()->GetSafeHwnd(), (DLGPROC) DlgLuaScriptDialog); 1.4875 + info_uid = (int)LuaConsoleHWnd; 1.4876 +#else 1.4877 + info_print = NULL; 1.4878 + info_onstart = NULL; 1.4879 + info_onstop = NULL; 1.4880 +#endif 1.4881 + if (info_onstart) 1.4882 + info_onstart(info_uid); 1.4883 + 1.4884 + // And run it right now. :) 1.4885 + VBALuaFrameBoundary(); 1.4886 + systemRenderFrame(); 1.4887 + 1.4888 + // We're done. 1.4889 + return 1; 1.4890 + } 1.4891 + 1.4892 +/** 1.4893 + * Equivalent to repeating the last VBALoadLuaCode() call. 1.4894 + */ 1.4895 + int VBAReloadLuaCode(void) 1.4896 + { 1.4897 + if (!luaScriptName) 1.4898 + { 1.4899 + systemScreenMessage("There's no script to reload."); 1.4900 + return 0; 1.4901 + } 1.4902 + else 1.4903 + return VBALoadLuaCode(luaScriptName); 1.4904 + } 1.4905 + 1.4906 +/** 1.4907 + * Terminates a running Lua script by killing the whole Lua engine. 1.4908 + * 1.4909 + * Always safe to call, except from within a lua call itself (duh). 1.4910 + * 1.4911 + */ 1.4912 + void VBALuaStop(void) 1.4913 + { 1.4914 + //already killed 1.4915 + if (!LUA) 1.4916 + return; 1.4917 + 1.4918 + //execute the user's shutdown callbacks 1.4919 + CallExitFunction(); 1.4920 + 1.4921 + /*info.*/ numMemHooks = 0; 1.4922 + for (int i = 0; i < LUAMEMHOOK_COUNT; i++) 1.4923 + CalculateMemHookRegions((LuaMemHookType)i); 1.4924 + 1.4925 + //sometimes iup uninitializes com 1.4926 + //MBG TODO - test whether this is really necessary. i dont think it is 1.4927 +#if (defined(WIN32) && !defined(SDL)) 1.4928 + CoInitialize(0); 1.4929 +#endif 1.4930 + 1.4931 + if (info_onstop) 1.4932 + info_onstop(info_uid); 1.4933 + 1.4934 + //lua_gc(LUA,LUA_GCCOLLECT,0); 1.4935 + lua_close(LUA); // this invokes our garbage collectors for us 1.4936 + LUA = NULL; 1.4937 + VBALuaOnStop(); 1.4938 + } 1.4939 + 1.4940 +/** 1.4941 + * Returns true if there is a Lua script running. 1.4942 + * 1.4943 + */ 1.4944 + int VBALuaRunning(void) 1.4945 + { 1.4946 + // FIXME: return false when no callback functions are registered. 1.4947 + return (int) (LUA != NULL); // should return true if callback functions are active. 1.4948 + } 1.4949 + 1.4950 +/** 1.4951 + * Returns true if Lua would like to steal the given joypad control. 1.4952 + * 1.4953 + * Range is 0 through 3 1.4954 + */ 1.4955 + int VBALuaUsingJoypad(int which) 1.4956 + { 1.4957 + if (which < 0 || which > 3) 1.4958 + which = systemGetDefaultJoypad(); 1.4959 + return lua_joypads_used & (1 << which); 1.4960 + } 1.4961 + 1.4962 +/** 1.4963 + * Reads the buttons Lua is feeding for the given joypad, in the same 1.4964 + * format as the OS-specific code. 1.4965 + * 1.4966 + * <del>This function must not be called more than once per frame. </del>Ideally exactly once 1.4967 + * per frame (if VBALuaUsingJoypad says it's safe to do so) 1.4968 + */ 1.4969 + int VBALuaReadJoypad(int which) 1.4970 + { 1.4971 + if (which < 0 || which > 3) 1.4972 + which = systemGetDefaultJoypad(); 1.4973 + 1.4974 + //lua_joypads_used &= ~(1 << which); 1.4975 + return lua_joypads[which]; 1.4976 + } 1.4977 + 1.4978 +/** 1.4979 + * If this function returns true, the movie code should NOT increment 1.4980 + * the rerecord count for a load-state. 1.4981 + * 1.4982 + * This function will not return true if a script is not running. 1.4983 + */ 1.4984 + bool8 VBALuaRerecordCountSkip(void) 1.4985 + { 1.4986 + // FIXME: return true if (there are any active callback functions && skipRerecords) 1.4987 + return LUA && luaRunning && skipRerecords; 1.4988 + } 1.4989 + 1.4990 +/** 1.4991 + * Given a screen with the indicated resolution, 1.4992 + * draw the current GUI onto it. 1.4993 + */ 1.4994 + void VBALuaGui(uint8 *screen, int ppl, int width, int height) 1.4995 + { 1.4996 + if (!LUA /* || !luaRunning*/) 1.4997 + return; 1.4998 + 1.4999 + // First, check if we're being called by anybody 1.5000 + lua_getfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); 1.5001 + 1.5002 + if (lua_isfunction(LUA, -1)) 1.5003 + { 1.5004 + // We call it now 1.5005 + numTries = 1000; 1.5006 + 1.5007 + int ret = lua_pcall(LUA, 0, 0, 0); 1.5008 + if (ret != 0) 1.5009 + { 1.5010 + // This is grounds for trashing the function 1.5011 + // Note: This must be done before the messagebox pops up, 1.5012 + // otherwise the messagebox will cause a paint event which causes a weird 1.5013 + // infinite call sequence that makes Snes9x silently exit with error code 3, 1.5014 + // if a Lua GUI function crashes. (nitsuja) 1.5015 + lua_pushnil(LUA); 1.5016 + lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable); 1.5017 + 1.5018 +//#if (defined(WIN32) && !defined(SDL)) 1.5019 +// info_print(info_uid, lua_tostring(LUA, -1)); //AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua Error 1.5020 +// in GUI function", MB_OK); 1.5021 +//#else 1.5022 +// fprintf(stderr, "Lua error in gui.register function: %s\n", lua_tostring(LUA, -1)); 1.5023 +//#endif 1.5024 + printerror(LUA, -1); 1.5025 + } 1.5026 + } 1.5027 + 1.5028 + // And wreak the stack 1.5029 + lua_settop(LUA, 0); 1.5030 + 1.5031 + if (!gui_used) 1.5032 + return; 1.5033 + 1.5034 + gui_used = false; 1.5035 + 1.5036 + int x, y; 1.5037 + 1.5038 + //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3; 1.5039 + int pitch = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4); 1.5040 + 1.5041 + if (width > LUA_SCREEN_WIDTH) 1.5042 + width = LUA_SCREEN_WIDTH; 1.5043 + if (height > LUA_SCREEN_HEIGHT) 1.5044 + height = LUA_SCREEN_HEIGHT; 1.5045 + 1.5046 + GetColorFunc getColor; 1.5047 + SetColorFunc setColor; 1.5048 + getColorIOFunc(systemColorDepth, &getColor, &setColor); 1.5049 + 1.5050 + for (y = 0; y < height; y++) 1.5051 + { 1.5052 + uint8 *scr = &screen[y * pitch]; 1.5053 + for (x = 0; x < width; x++, scr += systemColorDepth / 8) 1.5054 + { 1.5055 + const uint8 gui_alpha = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 3]; 1.5056 + if (gui_alpha == 0) 1.5057 + { 1.5058 + // do nothing 1.5059 + continue; 1.5060 + } 1.5061 + 1.5062 + const uint8 gui_red = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 2]; 1.5063 + const uint8 gui_green = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 1]; 1.5064 + const uint8 gui_blue = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4]; 1.5065 + int red, green, blue; 1.5066 + 1.5067 + if (gui_alpha == 255) 1.5068 + { 1.5069 + // direct copy 1.5070 + red = gui_red; 1.5071 + green = gui_green; 1.5072 + blue = gui_blue; 1.5073 + } 1.5074 + else 1.5075 + { 1.5076 + // alpha-blending 1.5077 + uint8 scr_red, scr_green, scr_blue; 1.5078 + getColor(scr, &scr_red, &scr_green, &scr_blue); 1.5079 + red = (((int)gui_red - scr_red) * gui_alpha / 255 + scr_red) & 255; 1.5080 + green = (((int)gui_green - scr_green) * gui_alpha / 255 + scr_green) & 255; 1.5081 + blue = (((int)gui_blue - scr_blue) * gui_alpha / 255 + scr_blue) & 255; 1.5082 + } 1.5083 + 1.5084 + setColor(scr, (uint8) red, (uint8) green, (uint8) blue); 1.5085 + } 1.5086 + } 1.5087 + 1.5088 + return; 1.5089 + } 1.5090 + 1.5091 + void VBALuaClearGui(void) 1.5092 + { 1.5093 + gui_used = false; 1.5094 + } 1.5095 + 1.5096 + lua_State *VBAGetLuaState() 1.5097 + { 1.5098 + return LUA; 1.5099 + } 1.5100 + 1.5101 + char *VBAGetLuaScriptName() 1.5102 + { 1.5103 + return luaScriptName; 1.5104 + } 1.5105 +