view src/common/lua-engine.cpp @ 336:25b7bb7da3b1

Fixed two major bugs related to restart events which were causing desync. The entire video now syncs properly.
author Robert McIntyre <rlm@mit.edu>
date Sat, 07 Apr 2012 07:31:59 -0500
parents 59790d015f25
children
line wrap: on
line source
1 #include <cstdio>
2 #include <cstdlib>
3 #include <malloc.h>
4 #include <string>
5 #include <cassert>
6 #include <cctype>
7 #include <cmath>
8 #include <ctime>
10 #include <vector>
11 #include <map>
12 #include <string>
13 #include <algorithm>
15 using namespace std;
17 #ifdef __linux
18 #include <unistd.h> // for unlink
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #endif
22 #if (defined(WIN32) && !defined(SDL))
23 #include <direct.h>
24 #include "../win32/stdafx.h"
25 #include "../win32/Input.h"
26 #include "../win32/MainWnd.h"
27 #include "../win32/VBA.h"
28 #include "../win32/LuaOpenDialog.h"
29 #else
30 #define stricmp strcasecmp
31 #define strnicmp strncasecmp
32 #endif
34 #include "../Port.h"
35 #include "System.h"
36 #include "movie.h"
37 #include "../gba/GBA.h"
38 #include "../gba/GBAGlobals.h"
39 #include "../gb/GB.h"
40 #include "../gb/gbGlobals.h"
41 #include "../gba/GBASound.h"
43 #ifdef _WIN32
44 #include "../win32/Sound.h"
45 //#include "../win32/WinMiscUtil.h"
46 extern CString winGetSavestateFilename(const CString &LogicalRomName, int nID);
47 #else
48 #endif
50 extern "C"
51 {
52 #include "../lua/lua.h"
53 #include "../lua/lauxlib.h"
54 #include "../lua/lualib.h"
55 #include "../lua/lstate.h"
56 }
57 #include "vbalua.h"
59 #include "../SFMT/SFMT.c"
61 static void (*info_print)(int uid, const char *str);
62 static void (*info_onstart)(int uid);
63 static void (*info_onstop)(int uid);
64 static int info_uid;
66 #ifndef countof
67 #define countof(a) (sizeof(a) / sizeof(a[0]))
68 #endif
70 static lua_State *LUA;
72 // Are we running any code right now?
73 static char *luaScriptName = NULL;
75 // Are we running any code right now?
76 static bool8 luaRunning = false;
78 // True at the frame boundary, false otherwise.
79 static bool8 frameBoundary = false;
81 // The execution speed we're running at.
82 static enum { SPEED_NORMAL, SPEED_NOTHROTTLE, SPEED_TURBO, SPEED_MAXIMUM } speedmode = SPEED_NORMAL;
84 // Rerecord count skip mode
85 static bool8 skipRerecords = false;
87 // Used by the registry to find our functions
88 static const char *frameAdvanceThread = "VBA.FrameAdvance";
89 static const char *guiCallbackTable = "VBA.GUI";
91 // True if there's a thread waiting to run after a run of frame-advance.
92 static bool8 frameAdvanceWaiting = false;
94 // We save our pause status in the case of a natural death.
95 //static bool8 wasPaused = false;
97 // Transparency strength. 255=opaque, 0=so transparent it's invisible
98 static int transparencyModifier = 255;
100 // Our joypads.
101 static uint32 lua_joypads[4];
102 static uint8 lua_joypads_used = 0;
104 static bool8 gui_used = false;
105 static uint8 *gui_data = NULL; // BGRA
107 // Protects Lua calls from going nuts.
108 // We set this to a big number like 1000 and decrement it
109 // over time. The script gets knifed once this reaches zero.
110 static int numTries;
112 // number of registered memory functions (1 per hooked byte)
113 static unsigned int numMemHooks;
115 // Look in inputglobal.h for macros named like BUTTON_MASK_UP to determine the order.
116 static const char *button_mappings[] = {
117 "A", "B", "select", "start", "right", "left", "up", "down", "R", "L"
118 };
120 #ifdef _MSC_VER
121 #define snprintf _snprintf
122 #define vscprintf _vscprintf
123 #else
124 #define stricmp strcasecmp
125 #define strnicmp strncasecmp
126 #define __forceinline __attribute__((always_inline))
127 #endif
129 static const char *luaCallIDStrings[] =
130 {
131 "CALL_BEFOREEMULATION",
132 "CALL_AFTEREMULATION",
133 "CALL_BEFOREEXIT"
134 };
136 //make sure we have the right number of strings
137 CTASSERT(sizeof(luaCallIDStrings) / sizeof(*luaCallIDStrings) == LUACALL_COUNT)
139 static const char *luaMemHookTypeStrings [] =
140 {
141 "MEMHOOK_WRITE",
142 "MEMHOOK_READ",
143 "MEMHOOK_EXEC",
145 "MEMHOOK_WRITE_SUB",
146 "MEMHOOK_READ_SUB",
147 "MEMHOOK_EXEC_SUB",
148 };
150 //make sure we have the right number of strings
151 CTASSERT(sizeof(luaMemHookTypeStrings) / sizeof(*luaMemHookTypeStrings) == LUAMEMHOOK_COUNT)
153 static char *rawToCString(lua_State * L, int idx = 0);
154 static const char *toCString(lua_State *L, int idx = 0);
156 // GBA memory I/O functions copied from win32/MemoryViewerDlg.cpp
157 static inline u8 CPUReadByteQuick(u32 addr)
158 {
159 return ::map[addr >> 24].address[addr & ::map[addr >> 24].mask];
160 }
162 static inline void CPUWriteByteQuick(u32 addr, u8 b)
163 {
164 ::map[addr >> 24].address[addr & ::map[addr >> 24].mask] = b;
165 }
167 static inline u16 CPUReadHalfWordQuick(u32 addr)
168 {
169 return *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]);
170 }
172 static inline void CPUWriteHalfWordQuick(u32 addr, u16 b)
173 {
174 *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b;
175 }
177 static inline u32 CPUReadMemoryQuick(u32 addr)
178 {
179 return *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]);
180 }
182 static inline void CPUWriteMemoryQuick(u32 addr, u32 b)
183 {
184 *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b;
185 }
187 // GB
188 static inline u8 gbReadMemoryQuick8(u16 addr)
189 {
190 return gbReadMemoryQuick(addr);
191 }
193 static inline void gbWriteMemoryQuick8(u16 addr, u8 b)
194 {
195 gbWriteMemoryQuick(addr, b);
196 }
198 static inline u16 gbReadMemoryQuick16(u16 addr)
199 {
200 return (gbReadMemoryQuick(addr + 1) << 8) | gbReadMemoryQuick(addr);
201 }
203 static inline void gbWriteMemoryQuick16(u16 addr, u16 b)
204 {
205 gbWriteMemoryQuick(addr, b & 0xff);
206 gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff);
207 }
209 static inline u32 gbReadMemoryQuick32(u16 addr)
210 {
211 return (gbReadMemoryQuick(addr + 3) << 24) |
212 (gbReadMemoryQuick(addr + 2) << 16) |
213 (gbReadMemoryQuick(addr + 1) << 8) |
214 gbReadMemoryQuick(addr);
215 }
217 static inline void gbWriteMemoryQuick32(u16 addr, u32 b)
218 {
219 gbWriteMemoryQuick(addr, b & 0xff);
220 gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff);
221 gbWriteMemoryQuick(addr + 2, (b >> 16) & 0xff);
222 gbWriteMemoryQuick(addr + 1, (b >> 24) & 0xff);
223 }
225 static inline u8 gbReadROMQuick8(u32 addr)
226 {
227 return gbReadROMQuick(addr & gbRomSizeMask);
228 }
230 static inline u8 gbReadROMQuick16(u32 addr)
231 {
232 return (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) | gbReadROMQuick(addr & gbRomSizeMask);
233 }
235 static inline u8 gbReadROMQuick32(u32 addr)
236 {
237 return (gbReadROMQuick(addr+3 & gbRomSizeMask) << 24) |
238 (gbReadROMQuick(addr+2 & gbRomSizeMask) << 16) |
239 (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) |
240 gbReadROMQuick(addr & gbRomSizeMask);
241 }
243 typedef void (*GetColorFunc)(const uint8 *, uint8 *, uint8 *, uint8 *);
244 typedef void (*SetColorFunc)(uint8 *, uint8, uint8, uint8);
246 static void getColor16(const uint8 *s, uint8 *r, uint8 *g, uint8 *b)
247 {
248 u16 v = *(const uint16 *)s;
249 *r = ((v >> systemBlueShift) & 0x001f) << 3;
250 *g = ((v >> systemGreenShift) & 0x001f) << 3;
251 *b = ((v >> systemRedShift) & 0x001f) << 3;
252 }
254 static void getColor24(const uint8 *s, uint8 *r, uint8 *g, uint8 *b)
255 {
256 if (systemRedShift > systemBlueShift)
257 *b = s[0], *g = s[1], *r = s[2];
258 else
259 *r = s[0], *g = s[1], *b = s[2];
260 }
262 static void getColor32(const uint8 *s, uint8 *r, uint8 *g, uint8 *b)
263 {
264 u32 v = *(const uint32 *)s;
265 *b = ((v >> systemBlueShift) & 0x001f) << 3;
266 *g = ((v >> systemGreenShift) & 0x001f) << 3;
267 *r = ((v >> systemRedShift) & 0x001f) << 3;
268 }
270 static void setColor16(uint8 *s, uint8 r, uint8 g, uint8 b)
271 {
272 *(uint16 *)s = ((b >> 3) & 0x01f) <<
273 systemBlueShift |
274 ((g >> 3) & 0x01f) <<
275 systemGreenShift |
276 ((r >> 3) & 0x01f) <<
277 systemRedShift;
278 }
280 static void setColor24(uint8 *s, uint8 r, uint8 g, uint8 b)
281 {
282 if (systemRedShift > systemBlueShift)
283 s[0] = b, s[1] = g, s[2] = r;
284 else
285 s[0] = r, s[1] = g, s[2] = b;
286 }
288 static void setColor32(uint8 *s, uint8 r, uint8 g, uint8 b)
289 {
290 *(uint32 *)s = ((b >> 3) & 0x01f) <<
291 systemBlueShift |
292 ((g >> 3) & 0x01f) <<
293 systemGreenShift |
294 ((r >> 3) & 0x01f) <<
295 systemRedShift;
296 }
298 static bool getColorIOFunc(int depth, GetColorFunc *getColor, SetColorFunc *setColor)
299 {
300 switch (depth)
301 {
302 case 16:
303 if (getColor)
304 *getColor = getColor16;
305 if (setColor)
306 *setColor = setColor16;
307 return true;
308 case 24:
309 if (getColor)
310 *getColor = getColor24;
311 if (setColor)
312 *setColor = setColor24;
313 return true;
314 case 32:
315 if (getColor)
316 *getColor = getColor32;
317 if (setColor)
318 *setColor = setColor32;
319 return true;
320 default:
321 return false;
322 }
323 }
325 /**
326 * Resets emulator speed / pause states after script exit.
327 */
328 static void VBALuaOnStop(void)
329 {
330 luaRunning = false;
331 lua_joypads_used = 0;
332 gui_used = false;
333 //if (wasPaused)
334 // systemSetPause(true);
335 }
337 /**
338 * Asks Lua if it wants control of the emulator's speed.
339 * Returns 0 if no, 1 if yes. If yes, we also tamper with the
340 * IPPU's settings for speed ourselves, so the calling code
341 * need not do anything.
342 */
343 int VBALuaSpeed(void)
344 {
345 if (!LUA || !luaRunning)
346 return 0;
348 //printf("%d\n", speedmode);
349 switch (speedmode)
350 {
351 /*
352 case SPEED_NORMAL:
353 return 0;
354 case SPEED_NOTHROTTLE:
355 IPPU.RenderThisFrame = true;
356 return 1;
358 case SPEED_TURBO:
359 IPPU.SkippedFrames++;
360 if (IPPU.SkippedFrames >= 40) {
361 IPPU.SkippedFrames = 0;
362 IPPU.RenderThisFrame = true;
363 }
364 else
365 IPPU.RenderThisFrame = false;
366 return 1;
368 // In mode 3, SkippedFrames is set to zero so that the frame
369 // skipping code doesn't try anything funny.
370 case SPEED_MAXIMUM:
371 IPPU.SkippedFrames=0;
372 IPPU.RenderThisFrame = false;
373 return 1;
374 */
375 case 0: // FIXME: to get rid of the warning
376 default:
377 assert(false);
378 return 0;
379 }
380 }
382 ///////////////////////////
383 // vba.speedmode(string mode)
384 //
385 // Takes control of the emulation speed
386 // of the system. Normal is normal speed (60fps, 50 for PAL),
387 // nothrottle disables speed control but renders every frame,
388 // turbo renders only a few frames in order to speed up emulation,
390 // maximum renders no frames
391 static int vba_speedmode(lua_State *L)
392 {
393 const char *mode = luaL_checkstring(L, 1);
395 if (strcasecmp(mode, "normal") == 0)
396 {
397 speedmode = SPEED_NORMAL;
398 }
399 else if (strcasecmp(mode, "nothrottle") == 0)
400 {
401 speedmode = SPEED_NOTHROTTLE;
402 }
403 else if (strcasecmp(mode, "turbo") == 0)
404 {
405 speedmode = SPEED_TURBO;
406 }
407 else if (strcasecmp(mode, "maximum") == 0)
408 {
409 speedmode = SPEED_MAXIMUM;
410 }
411 else
412 luaL_error(L, "Invalid mode %s to vba.speedmode", mode);
414 //printf("new speed mode: %d\n", speedmode);
415 return 0;
416 }
418 // vba.frameadvnace()
419 //
420 // Executes a frame advance. Occurs by yielding the coroutine, then re-running
422 // when we break out.
423 static int vba_frameadvance(lua_State *L)
424 {
425 // We're going to sleep for a frame-advance. Take notes.
426 if (frameAdvanceWaiting)
427 return luaL_error(L, "can't call vba.frameadvance() from here");
429 frameAdvanceWaiting = true;
431 // Don't do this! The user won't like us sending their emulator out of control!
432 // Settings.FrameAdvance = true;
433 // Now we can yield to the main
434 return lua_yield(L, 0);
436 // It's actually rather disappointing...
437 }
439 // vba.pause()
440 //
441 // Pauses the emulator, function "waits" until the user unpauses.
442 // This function MAY be called from a non-frame boundary, but the frame
444 // finishes executing anwyays. In this case, the function returns immediately.
445 static int vba_pause(lua_State *L)
446 {
447 systemSetPause(true);
448 speedmode = SPEED_NORMAL;
450 // Return control if we're midway through a frame. We can't pause here.
451 if (frameAdvanceWaiting)
452 {
453 return 0;
454 }
456 // If it's on a frame boundary, we also yield.
457 frameAdvanceWaiting = true;
458 return lua_yield(L, 0);
459 }
461 static int vba_registerbefore(lua_State *L)
462 {
463 if (!lua_isnil(L, 1))
464 luaL_checktype(L, 1, LUA_TFUNCTION);
465 lua_settop(L, 1);
466 lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]);
467 lua_insert(L, 1);
468 lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]);
470 //StopScriptIfFinished(luaStateToUIDMap[L]);
471 return 1;
472 }
474 static int vba_registerafter(lua_State *L)
475 {
476 if (!lua_isnil(L, 1))
477 luaL_checktype(L, 1, LUA_TFUNCTION);
478 lua_settop(L, 1);
479 lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]);
480 lua_insert(L, 1);
481 lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]);
483 //StopScriptIfFinished(luaStateToUIDMap[L]);
484 return 1;
485 }
487 static int vba_registerexit(lua_State *L)
488 {
489 if (!lua_isnil(L, 1))
490 luaL_checktype(L, 1, LUA_TFUNCTION);
491 lua_settop(L, 1);
492 lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
493 lua_insert(L, 1);
494 lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
496 //StopScriptIfFinished(luaStateToUIDMap[L]);
497 return 1;
498 }
500 static inline bool isalphaorunderscore(char c)
501 {
502 return isalpha(c) || c == '_';
503 }
505 static std::vector<const void *> s_tableAddressStack; // prevents infinite recursion of a table within a table (when cycle is
506 // found, print something like table:parent)
507 static std::vector<const void *> s_metacallStack; // prevents infinite recursion if something's __tostring returns another table
508 // that contains that something (when cycle is found, print the inner result
509 // without using __tostring)
511 #define APPENDPRINT { int _n = snprintf(ptr, remaining,
512 #define END ); if (_n >= 0) { ptr += _n; remaining -= _n; } else { remaining = 0; } }
513 static void toCStringConverter(lua_State *L, int i, char * &ptr, int &remaining)
514 {
515 if (remaining <= 0)
516 return;
518 const char *str = ptr; // for debugging
520 // if there is a __tostring metamethod then call it
521 int usedMeta = luaL_callmeta(L, i, "__tostring");
522 if (usedMeta)
523 {
524 std::vector<const void *>::const_iterator foundCycleIter = std::find(s_metacallStack.begin(), s_metacallStack.end(), lua_topointer(L, i));
525 if (foundCycleIter != s_metacallStack.end())
526 {
527 lua_pop(L, 1);
528 usedMeta = false;
529 }
530 else
531 {
532 s_metacallStack.push_back(lua_topointer(L, i));
533 i = lua_gettop(L);
534 }
535 }
537 switch (lua_type(L, i))
538 {
539 case LUA_TNONE:
540 break;
541 case LUA_TNIL:
542 APPENDPRINT "nil" END break;
543 case LUA_TBOOLEAN:
544 APPENDPRINT lua_toboolean(L, i) ? "true" : "false" END break;
545 case LUA_TSTRING : APPENDPRINT "%s", lua_tostring(L, i) END break;
546 case LUA_TNUMBER:
547 APPENDPRINT "%.12Lg", lua_tonumber(L, i) END break;
548 case LUA_TFUNCTION:
549 if ((L->base + i - 1)->value.gc->cl.c.isC)
550 {
551 //lua_CFunction func = lua_tocfunction(L, i);
552 //std::map<lua_CFunction, const char*>::iterator iter = s_cFuncInfoMap.find(func);
553 //if(iter == s_cFuncInfoMap.end())
554 goto defcase;
555 //APPENDPRINT "function(%s)", iter->second END
556 }
557 else
558 {
559 APPENDPRINT "function(" END
560 Proto * p = (L->base + i - 1)->value.gc->cl.l.p;
561 int numParams = p->numparams + (p->is_vararg ? 1 : 0);
562 for (int n = 0; n < p->numparams; n++)
563 {
564 APPENDPRINT "%s", getstr(p->locvars[n].varname) END
565 if (n != numParams - 1)
566 APPENDPRINT "," END
567 }
568 if (p->is_vararg)
569 APPENDPRINT "..." END
570 APPENDPRINT ")" END
571 }
572 break;
573 defcase: default:
574 APPENDPRINT "%s:%p", luaL_typename(L, i), lua_topointer(L, i) END break;
575 case LUA_TTABLE:
576 {
577 // first make sure there's enough stack space
578 if (!lua_checkstack(L, 4))
579 {
580 // note that even if lua_checkstack never returns false,
581 // that doesn't mean we didn't need to call it,
582 // because calling it retrieves stack space past LUA_MINSTACK
583 goto defcase;
584 }
586 std::vector<const void *>::const_iterator foundCycleIter =
587 std::find(s_tableAddressStack.begin(), s_tableAddressStack.end(), lua_topointer(L, i));
588 if (foundCycleIter != s_tableAddressStack.end())
589 {
590 int parentNum = s_tableAddressStack.end() - foundCycleIter;
591 if (parentNum > 1)
592 APPENDPRINT "%s:parent^%d", luaL_typename(L, i), parentNum END
593 else
594 APPENDPRINT "%s:parent", luaL_typename(L, i) END
595 }
596 else
597 {
598 s_tableAddressStack.push_back(lua_topointer(L, i));
599 struct Scope { ~Scope(){ s_tableAddressStack. pop_back(); } } scope;
601 APPENDPRINT "{" END
603 lua_pushnil(L); // first key
604 int keyIndex = lua_gettop(L);
605 int valueIndex = keyIndex + 1;
606 bool first = true;
607 bool skipKey = true; // true if we're still in the "array part" of the table
608 lua_Number arrayIndex = (lua_Number)0;
609 while (lua_next(L, i))
610 {
611 if (first)
612 first = false;
613 else
614 APPENDPRINT ", " END
615 if (skipKey)
616 {
617 arrayIndex += (lua_Number)1;
618 bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER);
619 skipKey = keyIsNumber && (lua_tonumber(L, keyIndex) == arrayIndex);
620 }
621 if (!skipKey)
622 {
623 bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING);
624 bool invalidLuaIdentifier = (!keyIsString || !isalphaorunderscore(*lua_tostring(L, keyIndex)));
625 if (invalidLuaIdentifier)
626 if (keyIsString)
627 APPENDPRINT "['" END
628 else
629 APPENDPRINT "[" END
631 toCStringConverter(L, keyIndex, ptr, remaining);
632 // key
634 if (invalidLuaIdentifier)
635 if (keyIsString)
636 APPENDPRINT "']=" END
637 else
638 APPENDPRINT "]=" END
639 else
640 APPENDPRINT "=" END
641 }
643 bool valueIsString = (lua_type(L, valueIndex) == LUA_TSTRING);
644 if (valueIsString)
645 APPENDPRINT "'" END
647 toCStringConverter(L, valueIndex, ptr, remaining); // value
649 if (valueIsString)
650 APPENDPRINT "'" END
652 lua_pop(L, 1);
654 if (remaining <= 0)
655 {
656 lua_settop(L, keyIndex - 1); // stack might not be clean yet if we're breaking
657 // early
658 break;
659 }
660 }
661 APPENDPRINT "}" END
662 }
663 }
664 break;
665 }
667 if (usedMeta)
668 {
669 s_metacallStack.pop_back();
670 lua_pop(L, 1);
671 }
672 }
674 static const int s_tempStrMaxLen = 64 * 1024;
675 static char s_tempStr [s_tempStrMaxLen];
677 static char *rawToCString(lua_State *L, int idx)
678 {
679 int a = idx > 0 ? idx : 1;
680 int n = idx > 0 ? idx : lua_gettop(L);
682 char *ptr = s_tempStr;
683 *ptr = 0;
685 int remaining = s_tempStrMaxLen;
686 for (int i = a; i <= n; i++)
687 {
688 toCStringConverter(L, i, ptr, remaining);
689 if (i != n)
690 APPENDPRINT " " END
691 }
693 if (remaining < 3)
694 {
695 while (remaining < 6)
696 remaining++, ptr--;
697 APPENDPRINT "..." END
698 }
699 APPENDPRINT "\r\n" END
700 // the trailing newline is so print() can avoid having to do wasteful things to print its newline
701 // (string copying would be wasteful and calling info.print() twice can be extremely slow)
702 // at the cost of functions that don't want the newline needing to trim off the last two characters
703 // (which is a very fast operation and thus acceptable in this case)
705 return s_tempStr;
706 }
707 #undef APPENDPRINT
708 #undef END
710 // replacement for luaB_tostring() that is able to show the contents of tables (and formats numbers better, and show function
711 // prototypes)
712 // can be called directly from lua via tostring(), assuming tostring hasn't been reassigned
713 static int tostring(lua_State *L)
714 {
715 char *str = rawToCString(L);
716 str[strlen(str) - 2] = 0; // hack: trim off the \r\n (which is there to simplify the print function's
717 // task)
718 lua_pushstring(L, str);
719 return 1;
720 }
722 // like rawToCString, but will check if the global Lua function tostring()
723 // has been replaced with a custom function, and call that instead if so
724 static const char *toCString(lua_State *L, int idx)
725 {
726 int a = idx > 0 ? idx : 1;
727 int n = idx > 0 ? idx : lua_gettop(L);
728 lua_getglobal(L, "tostring");
729 lua_CFunction cf = lua_tocfunction(L, -1);
730 if (cf == tostring || lua_isnil(L, -1)) // optimization: if using our own C tostring function, we can
731 // bypass the call through Lua and all the string object
732 // allocation that would entail
733 {
734 lua_pop(L, 1);
735 return rawToCString(L, idx);
736 }
737 else // if the user overrided the tostring function, we have to actually call it and store the
738 // temporarily allocated string it returns
739 {
740 lua_pushstring(L, "");
741 for (int i = a; i <= n; i++)
742 {
743 lua_pushvalue(L, -2); // function to be called
744 lua_pushvalue(L, i); // value to print
745 lua_call(L, 1, 1);
746 if (lua_tostring(L, -1) == NULL)
747 luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print"));
748 lua_pushstring(L, (i < n) ? " " : "\r\n");
749 lua_concat(L, 3);
750 }
751 const char *str = lua_tostring(L, -1);
752 strncpy(s_tempStr, str, s_tempStrMaxLen);
753 s_tempStr[s_tempStrMaxLen - 1] = 0;
754 lua_pop(L, 2);
755 return s_tempStr;
756 }
757 }
759 // replacement for luaB_print() that goes to the appropriate textbox instead of stdout
760 static int print(lua_State *L)
761 {
762 const char *str = toCString(L);
764 int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread];
765 //LuaContextInfo& info = GetCurrentInfo();
767 if (info_print)
768 info_print(uid, str);
769 else
770 puts(str);
772 //worry(L, 100);
773 return 0;
774 }
776 static int printerror(lua_State *L, int idx)
777 {
778 lua_checkstack(L, lua_gettop(L) + 4);
780 if (idx < 0)
781 idx = lua_gettop(L) + 1 + idx;
783 const char *str = rawToCString(L, idx);
785 int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread];
786 //LuaContextInfo& info = GetCurrentInfo();
788 if (info_print)
789 info_print(uid, str);
790 else
791 fputs(str, stderr);
793 //worry(L, 100);
794 return 0;
795 }
797 // vba.message(string msg)
798 //
799 // Displays the given message on the screen.
800 static int vba_message(lua_State *L)
801 {
802 const char *msg = luaL_checkstring(L, 1);
803 systemScreenMessage(msg);
805 return 0;
806 }
808 // provides an easy way to copy a table from Lua
809 // (simple assignment only makes an alias, but sometimes an independent table is desired)
810 // currently this function only performs a shallow copy,
811 // but I think it should be changed to do a deep copy (possibly of configurable depth?)
812 // that maintains the internal table reference structure
813 static int copytable(lua_State *L)
814 {
815 int origIndex = 1; // we only care about the first argument
816 int origType = lua_type(L, origIndex);
817 if (origType == LUA_TNIL)
818 {
819 lua_pushnil(L);
820 return 1;
821 }
822 if (origType != LUA_TTABLE)
823 {
824 luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE));
825 lua_pushnil(L);
826 return 1;
827 }
829 lua_createtable(L, lua_objlen(L, 1), 0);
830 int copyIndex = lua_gettop(L);
832 lua_pushnil(L); // first key
833 int keyIndex = lua_gettop(L);
834 int valueIndex = keyIndex + 1;
836 while (lua_next(L, origIndex))
837 {
838 lua_pushvalue(L, keyIndex);
839 lua_pushvalue(L, valueIndex);
840 lua_rawset(L, copyIndex); // copytable[key] = value
841 lua_pop(L, 1);
842 }
844 // copy the reference to the metatable as well, if any
845 if (lua_getmetatable(L, origIndex))
846 lua_setmetatable(L, copyIndex);
848 return 1; // return the new table
849 }
851 // because print traditionally shows the address of tables,
852 // and the print function I provide instead shows the contents of tables,
853 // I also provide this function
854 // (otherwise there would be no way to see a table's address, AFAICT)
855 static int addressof(lua_State *L)
856 {
857 const void *ptr = lua_topointer(L, -1);
858 lua_pushinteger(L, (lua_Integer)ptr);
859 return 1;
860 }
862 struct registerPointerMap
863 {
864 const char * registerName;
865 unsigned int *pointer;
866 int dataSize;
867 };
869 #define RPM_ENTRY(name, var) \
870 { name, (unsigned int *)&var, sizeof(var) \
871 } \
872 ,
874 extern gbRegister AF;
875 extern gbRegister BC;
876 extern gbRegister DE;
877 extern gbRegister HL;
878 extern gbRegister SP;
879 extern gbRegister PC;
880 extern u16 IFF;
882 registerPointerMap regPointerMap [] = {
883 // gba registers
884 RPM_ENTRY("r0", reg[0].I)
885 RPM_ENTRY("r1", reg[1].I)
886 RPM_ENTRY("r2", reg[2].I)
887 RPM_ENTRY("r3", reg[3].I)
888 RPM_ENTRY("r4", reg[4].I)
889 RPM_ENTRY("r5", reg[5].I)
890 RPM_ENTRY("r6", reg[6].I)
891 RPM_ENTRY("r7", reg[7].I)
892 RPM_ENTRY("r8", reg[8].I)
893 RPM_ENTRY("r9", reg[9].I)
894 RPM_ENTRY("r10", reg[10].I)
895 RPM_ENTRY("r11", reg[11].I)
896 RPM_ENTRY("r12", reg[12].I)
897 RPM_ENTRY("r13", reg[13].I)
898 RPM_ENTRY("r14", reg[14].I)
899 RPM_ENTRY("r15", reg[15].I)
900 RPM_ENTRY("cpsr", reg[16].I)
901 RPM_ENTRY("spsr", reg[17].I)
902 // gb registers
903 RPM_ENTRY("a", AF.B.B1)
904 RPM_ENTRY("f", AF.B.B0)
905 RPM_ENTRY("b", BC.B.B1)
906 RPM_ENTRY("c", BC.B.B0)
907 RPM_ENTRY("d", DE.B.B1)
908 RPM_ENTRY("e", DE.B.B0)
909 RPM_ENTRY("h", HL.B.B1)
910 RPM_ENTRY("l", HL.B.B0)
911 RPM_ENTRY("af", AF.W)
912 RPM_ENTRY("bc", BC.W)
913 RPM_ENTRY("de", DE.W)
914 RPM_ENTRY("hl", HL.W)
915 RPM_ENTRY("sp", SP.W)
916 RPM_ENTRY("pc", PC.W)
917 {}
918 };
920 struct cpuToRegisterMap
921 {
922 const char *cpuName;
923 registerPointerMap *rpmap;
924 }
925 cpuToRegisterMaps [] =
926 {
927 { "", regPointerMap },
928 };
930 //DEFINE_LUA_FUNCTION(memory_getregister, "cpu_dot_registername_string")
931 static int memory_getregister(lua_State *L)
932 {
933 const char *qualifiedRegisterName = luaL_checkstring(L, 1);
934 lua_settop(L, 0);
935 for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++)
936 {
937 cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
938 int cpuNameLen = strlen(ctrm.cpuName);
939 if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen))
940 {
941 qualifiedRegisterName += cpuNameLen;
942 for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++)
943 {
944 registerPointerMap rpm = ctrm.rpmap[reg];
945 if (!stricmp(qualifiedRegisterName, rpm.registerName))
946 {
947 switch (rpm.dataSize)
948 {
949 default:
950 case 1:
951 lua_pushinteger(L, *(unsigned char *)rpm.pointer); break;
952 case 2:
953 lua_pushinteger(L, *(unsigned short *)rpm.pointer); break;
954 case 4:
955 lua_pushinteger(L, *(unsigned long *)rpm.pointer); break;
956 }
957 return 1;
958 }
959 }
960 lua_pushnil(L);
961 return 1;
962 }
963 }
964 lua_pushnil(L);
965 return 1;
966 }
968 //DEFINE_LUA_FUNCTION(memory_setregister, "cpu_dot_registername_string,value")
969 static int memory_setregister(lua_State *L)
970 {
971 const char * qualifiedRegisterName = luaL_checkstring(L, 1);
972 unsigned long value = (unsigned long)(luaL_checkinteger(L, 2));
973 lua_settop(L, 0);
974 for (int cpu = 0; cpu < sizeof(cpuToRegisterMaps) / sizeof(*cpuToRegisterMaps); cpu++)
975 {
976 cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
977 int cpuNameLen = strlen(ctrm.cpuName);
978 if (!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen))
979 {
980 qualifiedRegisterName += cpuNameLen;
981 for (int reg = 0; ctrm.rpmap[reg].dataSize; reg++)
982 {
983 registerPointerMap rpm = ctrm.rpmap[reg];
984 if (!stricmp(qualifiedRegisterName, rpm.registerName))
985 {
986 switch (rpm.dataSize)
987 {
988 default:
989 case 1:
990 *(unsigned char *)rpm.pointer = (unsigned char)(value & 0xFF); break;
991 case 2:
992 *(unsigned short *)rpm.pointer = (unsigned short)(value & 0xFFFF); break;
993 case 4:
994 *(unsigned long *)rpm.pointer = value; break;
995 }
996 return 0;
997 }
998 }
999 return 0;
1002 return 0;
1005 void HandleCallbackError(lua_State *L)
1007 if (L->errfunc || L->errorJmp)
1008 luaL_error(L, "%s", lua_tostring(L, -1));
1009 else
1011 lua_pushnil(LUA);
1012 lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
1014 // Error?
1015 //#if (defined(WIN32) && !defined(SDL))
1016 // info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer();
1017 // AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua run error", MB_OK | MB_ICONSTOP);
1018 //#else
1019 // fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(LUA, -1));
1020 //#endif
1021 printerror(LUA, -1);
1022 VBALuaStop();
1026 void CallRegisteredLuaFunctions(LuaCallID calltype)
1028 assert((unsigned int)calltype < (unsigned int)LUACALL_COUNT);
1030 const char *idstring = luaCallIDStrings[calltype];
1032 if (!LUA)
1033 return;
1035 lua_settop(LUA, 0);
1036 lua_getfield(LUA, LUA_REGISTRYINDEX, idstring);
1038 int errorcode = 0;
1039 if (lua_isfunction(LUA, -1))
1041 errorcode = lua_pcall(LUA, 0, 0, 0);
1042 if (errorcode)
1043 HandleCallbackError(LUA);
1045 else
1047 lua_pop(LUA, 1);
1051 // the purpose of this structure is to provide a way of
1052 // QUICKLY determining whether a memory address range has a hook associated with it,
1053 // with a bias toward fast rejection because the majority of addresses will not be hooked.
1054 // (it must not use any part of Lua or perform any per-script operations,
1055 // otherwise it would definitely be too slow.)
1056 // calculating the regions when a hook is added/removed may be slow,
1057 // but this is an intentional tradeoff to obtain a high speed of checking during later execution
1058 struct TieredRegion
1060 template<unsigned int maxGap>
1061 struct Region
1063 struct Island
1065 unsigned int start;
1066 unsigned int end;
1067 __forceinline bool Contains(unsigned int address, int size) const { return address < end && address + size > start; }
1068 };
1069 std::vector<Island> islands;
1071 void Calculate(const std::vector<unsigned int> &bytes)
1073 islands. clear();
1075 unsigned int lastEnd = ~0;
1077 std::vector<unsigned int>::const_iterator iter = bytes.begin();
1078 std::vector<unsigned int>::const_iterator end = bytes.end();
1079 for (; iter != end; ++iter)
1081 unsigned int addr = *iter;
1082 if (addr < lastEnd || addr > lastEnd + (long long)maxGap)
1084 islands. push_back(Island());
1085 islands. back().start = addr;
1087 islands.back(). end = addr + 1;
1088 lastEnd = addr + 1;
1092 bool Contains(unsigned int address, int size) const
1094 for (size_t i = 0; i != islands.size(); ++i)
1096 if (islands[i].Contains(address, size))
1097 return true;
1099 return false;
1101 };
1103 Region<0xFFFFFFFF> broad;
1104 Region<0x1000> mid;
1105 Region<0> narrow;
1107 void Calculate(std::vector<unsigned int> &bytes)
1109 std:: sort(bytes.begin(), bytes.end());
1111 broad. Calculate(bytes);
1112 mid. Calculate(bytes);
1113 narrow. Calculate(bytes);
1116 TieredRegion()
1118 std::vector <unsigned int> temp;
1119 Calculate(temp);
1122 __forceinline int NotEmpty()
1124 return broad.islands.size();
1127 // note: it is illegal to call this if NotEmpty() returns 0
1128 __forceinline bool Contains(unsigned int address, int size)
1130 return broad.islands[0].Contains(address, size) &&
1131 mid.Contains(address, size) &&
1132 narrow.Contains(address, size);
1134 };
1135 TieredRegion hookedRegions [LUAMEMHOOK_COUNT];
1137 static void CalculateMemHookRegions(LuaMemHookType hookType)
1139 std::vector<unsigned int> hookedBytes;
1140 // std::map<int, LuaContextInfo*>::iterator iter = luaContextInfo.begin();
1141 // std::map<int, LuaContextInfo*>::iterator end = luaContextInfo.end();
1142 // while(iter != end)
1143 // {
1144 // LuaContextInfo& info = *iter->second;
1145 if (/*info.*/ numMemHooks)
1147 lua_State *L = LUA /*info.L*/;
1148 if (L)
1150 lua_settop(L, 0);
1151 lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
1152 lua_pushnil(L);
1153 while (lua_next(L, -2))
1155 if (lua_isfunction(L, -1))
1157 unsigned int addr = lua_tointeger(L, -2);
1158 hookedBytes.push_back(addr);
1160 lua_pop(L, 1);
1162 lua_settop(L, 0);
1165 // ++iter;
1166 // }
1167 hookedRegions[hookType].Calculate(hookedBytes);
1170 static void CallRegisteredLuaMemHook_LuaMatch(unsigned int address, int size, unsigned int value, LuaMemHookType hookType)
1172 // std::map<int, LuaContextInfo*>::iterator iter = luaContextInfo.begin();
1173 // std::map<int, LuaContextInfo*>::iterator end = luaContextInfo.end();
1174 // while(iter != end)
1175 // {
1176 // LuaContextInfo& info = *iter->second;
1177 if (/*info.*/ numMemHooks)
1179 lua_State *L = LUA /*info.L*/;
1180 if (L /* && !info.panic*/)
1182 #ifdef USE_INFO_STACK
1183 infoStack.insert(infoStack.begin(), &info);
1184 struct Scope { ~Scope(){ infoStack. erase(infoStack.begin()); } } scope;
1185 #endif
1186 lua_settop(L, 0);
1187 lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
1188 for (int i = address; i != address + size; i++)
1190 lua_rawgeti(L, -1, i);
1191 if (lua_isfunction(L, -1))
1193 bool wasRunning = (luaRunning != 0) /*info.running*/;
1194 luaRunning /*info.running*/ = true;
1195 //RefreshScriptSpeedStatus();
1196 lua_pushinteger(L, address);
1197 lua_pushinteger(L, size);
1198 int errorcode = lua_pcall(L, 2, 0, 0);
1199 luaRunning /*info.running*/ = wasRunning;
1200 //RefreshScriptSpeedStatus();
1201 if (errorcode)
1203 HandleCallbackError(L);
1204 //int uid = iter->first;
1205 //HandleCallbackError(L,info,uid,true);
1207 break;
1209 else
1211 lua_pop(L, 1);
1214 lua_settop(L, 0);
1217 // ++iter;
1218 // }
1221 void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType)
1223 // performance critical! (called VERY frequently)
1224 // I suggest timing a large number of calls to this function in Release if you change anything in here,
1225 // before and after, because even the most innocent change can make it become 30% to 400% slower.
1226 // a good amount to test is: 100000000 calls with no hook set, and another 100000000 with a hook set.
1227 // (on my system that consistently took 200 ms total in the former case and 350 ms total in the latter
1228 // case)
1229 if (hookedRegions[hookType].NotEmpty())
1231 //if((hookType <= LUAMEMHOOK_EXEC) && (address >= 0xE00000))
1232 // address |= 0xFF0000; // account for mirroring of RAM
1233 if (hookedRegions[hookType].Contains(address, size))
1234 CallRegisteredLuaMemHook_LuaMatch(address, size, value, hookType); // something has hooked this
1235 // specific address
1239 static int memory_registerHook(lua_State *L, LuaMemHookType hookType, int defaultSize)
1241 // get first argument: address
1242 unsigned int addr = luaL_checkinteger(L, 1);
1243 //if((addr & ~0xFFFFFF) == ~0xFFFFFF)
1244 // addr &= 0xFFFFFF;
1246 // get optional second argument: size
1247 int size = defaultSize;
1248 int funcIdx = 2;
1249 if (lua_isnumber(L, 2))
1251 size = luaL_checkinteger(L, 2);
1252 if (size < 0)
1254 size = -size;
1255 addr -= size;
1257 funcIdx++;
1260 // check last argument: callback function
1261 bool clearing = lua_isnil(L, funcIdx);
1262 if (!clearing)
1263 luaL_checktype(L, funcIdx, LUA_TFUNCTION);
1264 lua_settop(L, funcIdx);
1266 // get the address-to-callback table for this hook type of the current script
1267 lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
1269 // count how many callback functions we'll be displacing
1270 int numFuncsAfter = clearing ? 0 : size;
1271 int numFuncsBefore = 0;
1272 for (unsigned int i = addr; i != addr + size; i++)
1274 lua_rawgeti(L, -1, i);
1275 if (lua_isfunction(L, -1))
1276 numFuncsBefore++;
1277 lua_pop(L, 1);
1280 // put the callback function in the address slots
1281 for (unsigned int i = addr; i != addr + size; i++)
1283 lua_pushvalue(L, -2);
1284 lua_rawseti(L, -2, i);
1287 // adjust the count of active hooks
1288 //LuaContextInfo& info = GetCurrentInfo();
1289 /*info.*/ numMemHooks += numFuncsAfter - numFuncsBefore;
1291 // re-cache regions of hooked memory across all scripts
1292 CalculateMemHookRegions(hookType);
1294 //StopScriptIfFinished(luaStateToUIDMap[L]);
1295 return 0;
1298 LuaMemHookType MatchHookTypeToCPU(lua_State *L, LuaMemHookType hookType)
1300 int cpuID = 0;
1302 int cpunameIndex = 0;
1303 if (lua_type(L, 2) == LUA_TSTRING)
1304 cpunameIndex = 2;
1305 else if (lua_type(L, 3) == LUA_TSTRING)
1306 cpunameIndex = 3;
1308 if (cpunameIndex)
1310 const char *cpuName = lua_tostring(L, cpunameIndex);
1311 if (!stricmp(cpuName, "sub"))
1312 cpuID = 1;
1313 lua_remove(L, cpunameIndex);
1316 switch (cpuID)
1318 case 0:
1319 return hookType;
1321 case 1:
1322 switch (hookType)
1324 case LUAMEMHOOK_WRITE:
1325 return LUAMEMHOOK_WRITE_SUB;
1326 case LUAMEMHOOK_READ:
1327 return LUAMEMHOOK_READ_SUB;
1328 case LUAMEMHOOK_EXEC:
1329 return LUAMEMHOOK_EXEC_SUB;
1332 return hookType;
1335 static int memory_registerwrite(lua_State *L)
1337 return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_WRITE), 1);
1340 static int memory_registerread(lua_State *L)
1342 return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_READ), 1);
1345 static int memory_registerexec(lua_State *L)
1347 return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_EXEC), 1);
1350 //int vba.lagcount
1351 //
1353 //Returns the lagcounter variable
1354 static int vba_getlagcount(lua_State *L)
1356 lua_pushinteger(L, systemCounters.lagCount);
1357 return 1;
1360 //int vba.lagged
1361 //
1362 //Returns true if the current frame is a lag frame
1363 static int vba_lagged(lua_State *L)
1365 lua_pushboolean(L, systemCounters.laggedLast);
1366 return 1;
1369 // boolean vba.emulating()
1370 int vba_emulating(lua_State *L)
1372 lua_pushboolean(L, systemIsEmulating());
1373 return 1;
1376 int movie_isactive(lua_State *L)
1378 lua_pushboolean(L, VBAMovieActive());
1379 return 1;
1382 int movie_isrecording(lua_State *L)
1384 lua_pushboolean(L, VBAMovieRecording());
1385 return 1;
1388 int movie_isplaying(lua_State *L)
1390 lua_pushboolean(L, VBAMoviePlaying());
1391 return 1;
1394 int movie_getlength(lua_State *L)
1396 if (VBAMovieActive())
1397 lua_pushinteger(L, VBAMovieGetLength());
1398 else
1399 lua_pushinteger(L, 0);
1400 return 1;
1403 static int memory_readbyte(lua_State *L)
1405 u32 addr;
1406 u8 val;
1408 addr = luaL_checkinteger(L, 1);
1409 if (systemIsRunningGBA())
1411 val = CPUReadByteQuick(addr);
1413 else
1415 val = gbReadMemoryQuick8(addr);
1418 lua_pushinteger(L, val);
1419 return 1;
1422 static int memory_readbytesigned(lua_State *L)
1424 u32 addr;
1425 s8 val;
1427 addr = luaL_checkinteger(L, 1);
1428 if (systemIsRunningGBA())
1430 val = (s8) CPUReadByteQuick(addr);
1432 else
1434 val = (s8) gbReadMemoryQuick8(addr);
1437 lua_pushinteger(L, val);
1438 return 1;
1441 static int memory_readword(lua_State *L)
1443 u32 addr;
1444 u16 val;
1446 addr = luaL_checkinteger(L, 1);
1447 if (systemIsRunningGBA())
1449 val = CPUReadHalfWordQuick(addr);
1451 else
1453 val = gbReadMemoryQuick16(addr & 0x0000FFFF);
1456 lua_pushinteger(L, val);
1457 return 1;
1460 static int memory_readwordsigned(lua_State *L)
1462 u32 addr;
1463 s16 val;
1465 addr = luaL_checkinteger(L, 1);
1466 if (systemIsRunningGBA())
1468 val = (s16) CPUReadHalfWordQuick(addr);
1470 else
1472 val = (s16) gbReadMemoryQuick16(addr);
1475 lua_pushinteger(L, val);
1476 return 1;
1479 static int memory_readdword(lua_State *L)
1481 u32 addr;
1482 u32 val;
1484 addr = luaL_checkinteger(L, 1);
1485 if (systemIsRunningGBA())
1487 val = CPUReadMemoryQuick(addr);
1489 else
1491 val = gbReadMemoryQuick32(addr & 0x0000FFFF);
1494 // lua_pushinteger doesn't work properly for 32bit system, does it?
1495 if (val >= 0x80000000 && sizeof(int) <= 4)
1496 lua_pushnumber(L, val);
1497 else
1498 lua_pushinteger(L, val);
1499 return 1;
1502 static int memory_readdwordsigned(lua_State *L)
1504 u32 addr;
1505 s32 val;
1507 addr = luaL_checkinteger(L, 1);
1508 if (systemIsRunningGBA())
1510 val = (s32) CPUReadMemoryQuick(addr);
1512 else
1514 val = (s32) gbReadMemoryQuick32(addr);
1517 lua_pushinteger(L, val);
1518 return 1;
1521 static int memory_readbyterange(lua_State *L)
1523 uint32 address = luaL_checkinteger(L, 1);
1524 int length = luaL_checkinteger(L, 2);
1526 if (length < 0)
1528 address += length;
1529 length = -length;
1532 // push the array
1533 lua_createtable(L, abs(length), 0);
1535 // put all the values into the (1-based) array
1536 for (int a = address, n = 1; n <= length; a++, n++)
1538 unsigned char value;
1540 if (systemIsRunningGBA())
1542 value = CPUReadByteQuick(a);
1544 else
1546 value = gbReadMemoryQuick8(a);
1549 lua_pushinteger(L, value);
1550 lua_rawseti(L, -2, n);
1553 return 1;
1556 static int memory_writebyte(lua_State *L)
1558 u32 addr;
1559 int val;
1561 addr = luaL_checkinteger(L, 1);
1562 val = luaL_checkinteger(L, 2);
1563 if (systemIsRunningGBA())
1565 CPUWriteByteQuick(addr, val);
1567 else
1569 gbWriteMemoryQuick8(addr, val);
1572 CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE);
1573 return 0;
1576 static int memory_writeword(lua_State *L)
1578 u32 addr;
1579 int val;
1581 addr = luaL_checkinteger(L, 1);
1582 val = luaL_checkinteger(L, 2);
1583 if (systemIsRunningGBA())
1585 CPUWriteHalfWordQuick(addr, val);
1587 else
1589 gbWriteMemoryQuick16(addr, val);
1592 CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE);
1593 return 0;
1596 static int memory_writedword(lua_State *L)
1598 u32 addr;
1599 int val;
1601 addr = luaL_checkinteger(L, 1);
1602 val = luaL_checkinteger(L, 2);
1603 if (systemIsRunningGBA())
1605 CPUWriteMemoryQuick(addr, val);
1607 else
1609 gbWriteMemoryQuick32(addr, val);
1612 CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE);
1613 return 0;
1616 static int memory_gbromreadbyte(lua_State *L)
1618 u32 addr;
1619 u8 val;
1621 addr = luaL_checkinteger(L, 1);
1622 if (systemIsRunningGBA())
1624 lua_pushnil(L);
1625 return 1;
1627 else
1629 val = gbReadROMQuick8(addr);
1632 lua_pushinteger(L, val);
1633 return 1;
1636 static int memory_gbromreadbytesigned(lua_State *L)
1638 u32 addr;
1639 s8 val;
1641 addr = luaL_checkinteger(L, 1);
1642 if (systemIsRunningGBA())
1644 lua_pushnil(L);
1645 return 1;
1647 else
1649 val = (s8) gbReadROMQuick8(addr);
1652 lua_pushinteger(L, val);
1653 return 1;
1656 static int memory_gbromreadword(lua_State *L)
1658 u32 addr;
1659 u16 val;
1661 addr = luaL_checkinteger(L, 1);
1662 if (systemIsRunningGBA())
1664 lua_pushnil(L);
1665 return 1;
1667 else
1669 val = gbReadROMQuick16(addr);
1672 lua_pushinteger(L, val);
1673 return 1;
1676 static int memory_gbromreadwordsigned(lua_State *L)
1678 u32 addr;
1679 s16 val;
1681 addr = luaL_checkinteger(L, 1);
1682 if (systemIsRunningGBA())
1684 lua_pushnil(L);
1685 return 1;
1687 else
1689 val = (s16) gbReadROMQuick16(addr);
1692 lua_pushinteger(L, val);
1693 return 1;
1696 static int memory_gbromreaddword(lua_State *L)
1698 u32 addr;
1699 u32 val;
1701 addr = luaL_checkinteger(L, 1);
1702 if (systemIsRunningGBA())
1704 lua_pushnil(L);
1705 return 1;
1707 else
1709 val = gbReadROMQuick32(addr);
1712 // lua_pushinteger doesn't work properly for 32bit system, does it?
1713 if (val >= 0x80000000 && sizeof(int) <= 4)
1714 lua_pushnumber(L, val);
1715 else
1716 lua_pushinteger(L, val);
1717 return 1;
1720 static int memory_gbromreaddwordsigned(lua_State *L)
1722 u32 addr;
1723 s32 val;
1725 addr = luaL_checkinteger(L, 1);
1726 if (systemIsRunningGBA())
1728 lua_pushnil(L);
1729 return 1;
1731 else
1733 val = (s32) gbReadROMQuick32(addr);
1736 lua_pushinteger(L, val);
1737 return 1;
1740 static int memory_gbromreadbyterange(lua_State *L)
1742 uint32 address = luaL_checkinteger(L, 1);
1743 int length = luaL_checkinteger(L, 2);
1745 if (length < 0)
1747 address += length;
1748 length = -length;
1751 // push the array
1752 lua_createtable(L, abs(length), 0);
1754 // put all the values into the (1-based) array
1755 for (int a = address, n = 1; n <= length; a++, n++)
1757 unsigned char value;
1759 if (systemIsRunningGBA())
1761 lua_pushnil(L);
1762 return 1;
1764 else
1766 value = gbReadROMQuick8(a);
1769 lua_pushinteger(L, value);
1770 lua_rawseti(L, -2, n);
1773 return 1;
1776 // table joypad.get(int which = 1)
1777 //
1778 // Reads the joypads as inputted by the user.
1779 static int joy_get_internal(lua_State *L, bool reportUp, bool reportDown)
1781 // Reads the joypads as inputted by the user
1782 int which = luaL_checkinteger(L, 1);
1784 if (which < 0 || which > 4)
1786 luaL_error(L, "Invalid input port (valid range 0-4, specified %d)", which);
1789 uint32 buttons = systemGetOriginalJoypad(which - 1, false);
1791 lua_newtable(L);
1793 int i;
1794 for (i = 0; i < 10; i++)
1796 bool pressed = (buttons & (1 << i)) != 0;
1797 if ((pressed && reportDown) || (!pressed && reportUp))
1799 lua_pushboolean(L, pressed);
1800 lua_setfield(L, -2, button_mappings[i]);
1804 return 1;
1807 // joypad.get(which)
1808 // returns a table of every game button,
1809 // true meaning currently-held and false meaning not-currently-held
1810 // (as of last frame boundary)
1811 // this WILL read input from a currently-playing movie
1812 static int joypad_get(lua_State *L)
1814 return joy_get_internal(L, true, true);
1817 // joypad.getdown(which)
1818 // returns a table of every game button that is currently held
1819 static int joypad_getdown(lua_State *L)
1821 return joy_get_internal(L, false, true);
1824 // joypad.getup(which)
1825 // returns a table of every game button that is not currently held
1826 static int joypad_getup(lua_State *L)
1828 return joy_get_internal(L, true, false);
1831 // joypad.set(int which, table buttons)
1832 //
1833 // Sets the given buttons to be pressed during the next
1834 // frame advance. The table should have the right
1836 // keys (no pun intended) set.
1837 static int joypad_set(lua_State *L)
1839 // Which joypad we're tampering with
1840 int which = luaL_checkinteger(L, 1);
1841 if (which < 0 || which > 4)
1843 luaL_error(L, "Invalid output port (valid range 0-4, specified %d)", which);
1846 if (which == 0)
1847 which = systemGetDefaultJoypad();
1849 // And the table of buttons.
1850 luaL_checktype(L, 2, LUA_TTABLE);
1852 // Set up for taking control of the indicated controller
1853 lua_joypads_used |= 1 << (which - 1);
1854 lua_joypads[which - 1] = 0;
1856 for (int i = 0; i < 10; i++)
1858 const char *name = button_mappings[i];
1859 lua_getfield(L, 2, name);
1860 if (!lua_isnil(L, -1))
1862 bool pressed = lua_toboolean(L, -1) != 0;
1863 if (pressed)
1864 lua_joypads[which - 1] |= 1 << i;
1865 else
1866 lua_joypads[which - 1] &= ~(1 << i);
1868 lua_pop(L, 1);
1871 return 0;
1874 // Helper function to convert a savestate object to the filename it represents.
1875 static const char *savestateobj2filename(lua_State *L, int offset)
1877 // First we get the metatable of the indicated object
1878 int result = lua_getmetatable(L, offset);
1880 if (!result)
1881 luaL_error(L, "object not a savestate object");
1883 // Also check that the type entry is set
1884 lua_getfield(L, -1, "__metatable");
1885 if (strcmp(lua_tostring(L, -1), "vba Savestate") != 0)
1886 luaL_error(L, "object not a savestate object");
1887 lua_pop(L, 1);
1889 // Now, get the field we want
1890 lua_getfield(L, -1, "filename");
1892 // Return it
1893 return lua_tostring(L, -1);
1896 // Helper function for garbage collection.
1897 static int savestate_gc(lua_State *L)
1899 // The object we're collecting is on top of the stack
1900 lua_getmetatable(L, 1);
1902 // Get the filename
1903 const char *filename;
1904 lua_getfield(L, -1, "filename");
1905 filename = lua_tostring(L, -1);
1907 // Delete the file
1908 remove(filename);
1910 // We exit, and the garbage collector takes care of the rest.
1911 // Edit: Visual Studio needs a return value anyway, so returns 0.
1912 return 0;
1915 // object savestate.create(int which = nil)
1916 //
1917 // Creates an object used for savestates.
1918 // The object can be associated with a player-accessible savestate
1920 // ("which" between 1 and 12) or not (which == nil).
1921 static int savestate_create(lua_State *L)
1923 int which = -1;
1924 if (lua_gettop(L) >= 1)
1926 which = luaL_checkinteger(L, 1);
1927 if (which < 1 || which > 12)
1929 luaL_error(L, "invalid player's savestate %d", which);
1933 char stateName[2048];
1935 if (which > 0)
1937 // Find an appropriate filename. This is OS specific, unfortunately.
1938 #if (defined(WIN32) && !defined(SDL))
1939 CString stateName = winGetSavestateFilename(theApp.gameFilename, which);
1940 #else
1941 extern char saveDir[2048];
1942 extern char filename[2048];
1943 extern char *sdlGetFilename(char *name);
1945 if (saveDir[0])
1946 sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename), which);
1947 else
1948 sprintf(stateName, "%s%d.sgm", filename, which);
1949 #endif
1951 else
1953 char *stateNameTemp = tempnam(NULL, "snlua");
1954 strcpy(stateName, stateNameTemp);
1955 if (stateNameTemp)
1956 free(stateNameTemp);
1959 // Our "object". We don't care about the type, we just need the memory and GC services.
1960 lua_newuserdata(L, 1);
1962 // The metatable we use, protected from Lua and contains garbage collection info and stuff.
1963 lua_newtable(L);
1965 // First, we must protect it
1966 lua_pushstring(L, "vba Savestate");
1967 lua_setfield(L, -2, "__metatable");
1969 // Now we need to save the file itself.
1970 lua_pushstring(L, stateName);
1971 lua_setfield(L, -2, "filename");
1973 // If it's an anonymous savestate, we must delete the file from disk should it be gargage collected
1974 if (which < 0)
1976 lua_pushcfunction(L, savestate_gc);
1977 lua_setfield(L, -2, "__gc");
1980 // Set the metatable
1981 lua_setmetatable(L, -2);
1983 // Awesome. Return the object
1984 return 1;
1987 // savestate.save(object state)
1988 //
1990 // Saves a state to the given object.
1991 static int savestate_save(lua_State *L)
1993 const char *filename = savestateobj2filename(L, 1);
1995 // printf("saving %s\n", filename);
1996 // Save states are very expensive. They take time.
1997 numTries--;
1999 bool8 retvalue = theEmulator.emuWriteState ? theEmulator.emuWriteState(filename) : false;
2000 if (!retvalue)
2002 // Uh oh
2003 luaL_error(L, "savestate failed");
2006 return 0;
2009 // savestate.load(object state)
2010 //
2012 // Loads the given state
2013 static int savestate_load(lua_State *L)
2015 const char *filename = savestateobj2filename(L, 1);
2017 numTries--;
2019 // printf("loading %s\n", filename);
2020 bool8 retvalue = theEmulator.emuReadState ? theEmulator.emuReadState(filename) : false;
2021 if (!retvalue)
2023 // Uh oh
2024 luaL_error(L, "loadstate failed");
2027 return 0;
2030 // int vba.framecount()
2031 //
2033 // Gets the frame counter for the movie, or the number of frames since last reset.
2034 int vba_framecount(lua_State *L)
2036 if (!VBAMovieActive())
2038 lua_pushinteger(L, systemCounters.frameCount);
2040 else
2042 lua_pushinteger(L, VBAMovieGetFrameCounter());
2045 return 1;
2048 //string movie.getauthor
2049 //
2051 // returns author info field of .vbm file
2052 int movie_getauthor(lua_State *L)
2054 if (!VBAMovieActive())
2056 //lua_pushnil(L);
2057 lua_pushstring(L, "");
2058 return 1;
2061 lua_pushstring(L, VBAMovieGetAuthorInfo().c_str());
2062 return 1;
2065 //string movie.filename
2066 int movie_getfilename(lua_State *L)
2068 if (!VBAMovieActive())
2070 //lua_pushnil(L);
2071 lua_pushstring(L, "");
2072 return 1;
2075 lua_pushstring(L, VBAMovieGetFilename().c_str());
2076 return 1;
2079 // string movie.mode()
2080 //
2082 // "record", "playback" or nil
2083 int movie_getmode(lua_State *L)
2085 assert(!VBAMovieLoading());
2086 if (!VBAMovieActive())
2088 lua_pushnil(L);
2089 return 1;
2092 if (VBAMovieRecording())
2093 lua_pushstring(L, "record");
2094 else
2095 lua_pushstring(L, "playback");
2096 return 1;
2099 static int movie_rerecordcount(lua_State *L)
2101 if (VBAMovieActive())
2102 lua_pushinteger(L, VBAMovieGetRerecordCount());
2103 else
2104 lua_pushinteger(L, 0);
2105 return 1;
2108 static int movie_setrerecordcount(lua_State *L)
2110 if (VBAMovieActive())
2111 VBAMovieSetRerecordCount(luaL_checkinteger(L, 1));
2112 return 0;
2115 static int movie_rerecordcounting(lua_State *L)
2117 if (lua_gettop(L) == 0)
2118 luaL_error(L, "no parameters specified");
2120 skipRerecords = lua_toboolean(L, 1);
2121 return 0;
2124 // movie.stop()
2125 //
2127 // Stops movie playback/recording. Bombs out if movie is not running.
2128 static int movie_stop(lua_State *L)
2130 if (!VBAMovieActive())
2131 luaL_error(L, "no movie");
2133 VBAMovieStop(false);
2134 return 0;
2137 #define LUA_SCREEN_WIDTH 256
2138 #define LUA_SCREEN_HEIGHT 239
2140 // Common code by the gui library: make sure the screen array is ready
2141 static void gui_prepare(void)
2143 if (!gui_data)
2144 gui_data = (uint8 *)malloc(LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4);
2145 if (!gui_used)
2146 memset(gui_data, 0, LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4);
2147 gui_used = true;
2150 // pixform for lua graphics
2151 #define BUILD_PIXEL_ARGB8888(A, R, G, B) (((int)(A) << 24) | ((int)(R) << 16) | ((int)(G) << 8) | (int)(B))
2152 #define DECOMPOSE_PIXEL_ARGB8888(PIX, A, R, G, B) \
2153 { \
2154 (A) = ((PIX) >> 24) & 0xff; \
2155 (R) = ((PIX) >> 16) & 0xff; \
2156 (G) = ((PIX) >> 8) & 0xff; \
2157 (B) = (PIX) & 0xff; \
2159 #define LUA_BUILD_PIXEL BUILD_PIXEL_ARGB8888
2160 #define LUA_DECOMPOSE_PIXEL DECOMPOSE_PIXEL_ARGB8888
2161 #define LUA_PIXEL_A(PIX) (((PIX) >> 24) & 0xff)
2162 #define LUA_PIXEL_R(PIX) (((PIX) >> 16) & 0xff)
2163 #define LUA_PIXEL_G(PIX) (((PIX) >> 8) & 0xff)
2164 #define LUA_PIXEL_B(PIX) ((PIX) & 0xff)
2166 template<class T>
2167 static void swap(T &one, T &two)
2169 T temp = one;
2170 one = two;
2171 two = temp;
2174 // write a pixel to buffer
2175 static inline void blend32(uint32 *dstPixel, uint32 colour)
2177 uint8 *dst = (uint8 *)dstPixel;
2178 int a, r, g, b;
2179 LUA_DECOMPOSE_PIXEL(colour, a, r, g, b);
2181 if (a == 255 || dst[3] == 0)
2183 // direct copy
2184 *(uint32 *) (dst) = colour;
2186 else if (a == 0)
2188 // do not copy
2190 else
2192 // alpha-blending
2193 int a_dst = ((255 - a) * dst[3] + 128) / 255;
2194 int a_new = a + a_dst;
2196 dst[0] = (uint8) (((dst[0] * a_dst + b * a) + (a_new / 2)) / a_new);
2197 dst[1] = (uint8) (((dst[1] * a_dst + g * a) + (a_new / 2)) / a_new);
2198 dst[2] = (uint8) (((dst[2] * a_dst + r * a) + (a_new / 2)) / a_new);
2199 dst[3] = (uint8) a_new;
2203 // check if a pixel is in the lua canvas
2204 static inline bool gui_check_boundary(int x, int y)
2206 return !(x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= LUA_SCREEN_HEIGHT);
2209 // check if any part of a box is in the lua canvas
2210 static inline bool gui_checkbox(int x1, int y1, int x2, int y2)
2212 if ((x1 < 0 && x2 < 0)
2213 || (x1 >= LUA_SCREEN_WIDTH && x2 >= LUA_SCREEN_WIDTH)
2214 || (y1 < 0 && y2 < 0)
2215 || (y1 >= LUA_SCREEN_HEIGHT && y2 >= LUA_SCREEN_HEIGHT))
2216 return false;
2217 return true;
2220 // write a pixel to gui_data (do not check boundaries for speedup)
2221 static inline void gui_drawpixel_fast(int x, int y, uint32 colour)
2223 //gui_prepare();
2224 blend32((uint32 *) &gui_data[(y * LUA_SCREEN_WIDTH + x) * 4], colour);
2227 // write a pixel to gui_data (check boundaries)
2228 static inline void gui_drawpixel_internal(int x, int y, uint32 colour)
2230 //gui_prepare();
2231 if (gui_check_boundary(x, y))
2232 gui_drawpixel_fast(x, y, colour);
2235 // draw a line on gui_data (checks boundaries)
2236 static void gui_drawline_internal(int x1, int y1, int x2, int y2, bool lastPixel, uint32 colour)
2238 //gui_prepare();
2239 // Note: New version of Bresenham's Line Algorithm
2240 //
2241 //
2242 // http://groups.google.co.jp/group/rec.games.roguelike.development/browse_thread/thread/345f4c42c3b25858/29e07a3af3a450e6?show_docid=29e07a3af3a450e6
2243 int swappedx = 0;
2244 int swappedy = 0;
2246 int xtemp = x1 - x2;
2247 int ytemp = y1 - y2;
2248 if (xtemp == 0 && ytemp == 0)
2250 gui_drawpixel_internal(x1, y1, colour);
2251 return;
2254 if (xtemp < 0)
2256 xtemp = -xtemp;
2257 swappedx = 1;
2260 if (ytemp < 0)
2262 ytemp = -ytemp;
2263 swappedy = 1;
2266 int delta_x = xtemp << 1;
2267 int delta_y = ytemp << 1;
2269 signed char ix = x1 > x2 ? 1 : -1;
2270 signed char iy = y1 > y2 ? 1 : -1;
2272 if (lastPixel)
2273 gui_drawpixel_internal(x2, y2, colour);
2275 if (delta_x >= delta_y)
2277 int error = delta_y - (delta_x >> 1);
2279 while (x2 != x1)
2281 if (error == 0 && !swappedx)
2282 gui_drawpixel_internal(x2 + ix, y2, colour);
2283 if (error >= 0)
2285 if (error || (ix > 0))
2287 y2 += iy;
2288 error -= delta_x;
2292 x2 += ix;
2293 gui_drawpixel_internal(x2, y2, colour);
2294 if (error == 0 && swappedx)
2295 gui_drawpixel_internal(x2, y2 + iy, colour);
2296 error += delta_y;
2299 else
2301 int error = delta_x - (delta_y >> 1);
2303 while (y2 != y1)
2305 if (error == 0 && !swappedy)
2306 gui_drawpixel_internal(x2, y2 + iy, colour);
2307 if (error >= 0)
2309 if (error || (iy > 0))
2311 x2 += ix;
2312 error -= delta_y;
2316 y2 += iy;
2317 gui_drawpixel_internal(x2, y2, colour);
2318 if (error == 0 && swappedy)
2319 gui_drawpixel_internal(x2 + ix, y2, colour);
2320 error += delta_x;
2325 // draw a rect on gui_data
2326 static void gui_drawbox_internal(int x1, int y1, int x2, int y2, uint32 colour)
2328 if (x1 > x2)
2329 std::swap(x1, x2);
2330 if (y1 > y2)
2331 std::swap(y1, y2);
2332 if (x1 < 0)
2333 x1 = -1;
2334 if (y1 < 0)
2335 y1 = -1;
2336 if (x2 >= LUA_SCREEN_WIDTH)
2337 x2 = LUA_SCREEN_WIDTH;
2338 if (y2 >= LUA_SCREEN_HEIGHT)
2339 y2 = LUA_SCREEN_HEIGHT;
2341 if (!gui_checkbox(x1, y1, x2, y2))
2342 return;
2344 //gui_prepare();
2345 gui_drawline_internal(x1, y1, x2, y1, true, colour);
2346 gui_drawline_internal(x1, y2, x2, y2, true, colour);
2347 gui_drawline_internal(x1, y1, x1, y2, true, colour);
2348 gui_drawline_internal(x2, y1, x2, y2, true, colour);
2351 // draw a circle on gui_data
2352 static void gui_drawcircle_internal(int x0, int y0, int radius, uint32 colour)
2354 //gui_prepare();
2355 if (radius < 0)
2356 radius = -radius;
2357 if (radius == 0)
2358 return;
2359 if (radius == 1)
2361 gui_drawpixel_internal(x0, y0, colour);
2362 return;
2365 // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
2366 int f = 1 - radius;
2367 int ddF_x = 1;
2368 int ddF_y = -2 * radius;
2369 int x = 0;
2370 int y = radius;
2372 if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius))
2373 return;
2375 gui_drawpixel_internal(x0, y0 + radius, colour);
2376 gui_drawpixel_internal(x0, y0 - radius, colour);
2377 gui_drawpixel_internal(x0 + radius, y0, colour);
2378 gui_drawpixel_internal(x0 - radius, y0, colour);
2380 // same pixel shouldn't be drawed twice,
2381 // because each pixel has opacity.
2382 // so now the routine gets ugly.
2383 while (true)
2385 assert(ddF_x == 2 * x + 1);
2386 assert(ddF_y == -2 * y);
2387 assert(f == x * x + y * y - radius * radius + 2 * x - y + 1);
2388 if (f >= 0)
2390 y--;
2391 ddF_y += 2;
2392 f += ddF_y;
2395 x++;
2396 ddF_x += 2;
2397 f += ddF_x;
2398 if (x < y)
2400 gui_drawpixel_internal(x0 + x, y0 + y, colour);
2401 gui_drawpixel_internal(x0 - x, y0 + y, colour);
2402 gui_drawpixel_internal(x0 + x, y0 - y, colour);
2403 gui_drawpixel_internal(x0 - x, y0 - y, colour);
2404 gui_drawpixel_internal(x0 + y, y0 + x, colour);
2405 gui_drawpixel_internal(x0 - y, y0 + x, colour);
2406 gui_drawpixel_internal(x0 + y, y0 - x, colour);
2407 gui_drawpixel_internal(x0 - y, y0 - x, colour);
2409 else if (x == y)
2411 gui_drawpixel_internal(x0 + x, y0 + y, colour);
2412 gui_drawpixel_internal(x0 - x, y0 + y, colour);
2413 gui_drawpixel_internal(x0 + x, y0 - y, colour);
2414 gui_drawpixel_internal(x0 - x, y0 - y, colour);
2415 break;
2417 else
2418 break;
2422 // draw fill rect on gui_data
2423 static void gui_fillbox_internal(int x1, int y1, int x2, int y2, uint32 colour)
2425 if (x1 > x2)
2426 std::swap(x1, x2);
2427 if (y1 > y2)
2428 std::swap(y1, y2);
2429 if (x1 < 0)
2430 x1 = 0;
2431 if (y1 < 0)
2432 y1 = 0;
2433 if (x2 >= LUA_SCREEN_WIDTH)
2434 x2 = LUA_SCREEN_WIDTH - 1;
2435 if (y2 >= LUA_SCREEN_HEIGHT)
2436 y2 = LUA_SCREEN_HEIGHT - 1;
2438 //gui_prepare();
2439 int ix, iy;
2440 for (iy = y1; iy <= y2; iy++)
2442 for (ix = x1; ix <= x2; ix++)
2444 gui_drawpixel_fast(ix, iy, colour);
2449 // fill a circle on gui_data
2450 static void gui_fillcircle_internal(int x0, int y0, int radius, uint32 colour)
2452 //gui_prepare();
2453 if (radius < 0)
2454 radius = -radius;
2455 if (radius == 0)
2456 return;
2457 if (radius == 1)
2459 gui_drawpixel_internal(x0, y0, colour);
2460 return;
2463 // http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
2464 int f = 1 - radius;
2465 int ddF_x = 1;
2466 int ddF_y = -2 * radius;
2467 int x = 0;
2468 int y = radius;
2470 if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius))
2471 return;
2473 gui_drawline_internal(x0, y0 - radius, x0, y0 + radius, true, colour);
2475 while (true)
2477 assert(ddF_x == 2 * x + 1);
2478 assert(ddF_y == -2 * y);
2479 assert(f == x * x + y * y - radius * radius + 2 * x - y + 1);
2480 if (f >= 0)
2482 y--;
2483 ddF_y += 2;
2484 f += ddF_y;
2487 x++;
2488 ddF_x += 2;
2489 f += ddF_x;
2491 if (x < y)
2493 gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour);
2494 gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour);
2495 if (f >= 0)
2497 gui_drawline_internal(x0 + y, y0 - x, x0 + y, y0 + x, true, colour);
2498 gui_drawline_internal(x0 - y, y0 - x, x0 - y, y0 + x, true, colour);
2501 else if (x == y)
2503 gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, true, colour);
2504 gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, true, colour);
2505 break;
2507 else
2508 break;
2512 // Helper for a simple hex parser
2513 static int hex2int(lua_State *L, char c)
2515 if (c >= '0' && c <= '9')
2516 return c - '0';
2517 if (c >= 'a' && c <= 'f')
2518 return c - 'a' + 10;
2519 if (c >= 'A' && c <= 'F')
2520 return c - 'A' + 10;
2521 return luaL_error(L, "invalid hex in colour");
2524 static const struct ColorMapping
2526 const char *name;
2527 int value;
2529 s_colorMapping[] =
2531 { "white", 0xFFFFFFFF },
2532 { "black", 0x000000FF },
2533 { "clear", 0x00000000 },
2534 { "gray", 0x7F7F7FFF },
2535 { "grey", 0x7F7F7FFF },
2536 { "red", 0xFF0000FF },
2537 { "orange", 0xFF7F00FF },
2538 { "yellow", 0xFFFF00FF },
2539 { "chartreuse", 0x7FFF00FF },
2540 { "green", 0x00FF00FF },
2541 { "teal", 0x00FF7FFF },
2542 { "cyan", 0x00FFFFFF },
2543 { "blue", 0x0000FFFF },
2544 { "purple", 0x7F00FFFF },
2545 { "magenta", 0xFF00FFFF },
2546 };
2548 /**
2549 * Converts an integer or a string on the stack at the given
2550 * offset to a RGB32 colour. Several encodings are supported.
2551 * The user may construct their own RGB value, given a simple colour name,
2552 * or an HTML-style "#09abcd" colour. 16 bit reduction doesn't occur at this time.
2553 */
2554 static inline bool str2colour(uint32 *colour, lua_State *L, const char *str)
2556 if (str[0] == '#')
2558 int color;
2559 sscanf(str + 1, "%X", &color);
2561 int len = strlen(str + 1);
2562 int missing = max(0, 8 - len);
2563 color <<= missing << 2;
2564 if (missing >= 2)
2565 color |= 0xFF;
2566 *colour = color;
2567 return true;
2569 else
2571 if (!strnicmp(str, "rand", 4))
2573 *colour = gen_rand32() | 0xFF; //((rand()*255/RAND_MAX) << 8) | ((rand()*255/RAND_MAX) << 16) |
2574 // ((rand()*255/RAND_MAX) << 24) | 0xFF;
2575 return true;
2578 for (int i = 0; i < sizeof(s_colorMapping) / sizeof(*s_colorMapping); i++)
2580 if (!stricmp(str, s_colorMapping[i].name))
2582 *colour = s_colorMapping[i].value;
2583 return true;
2588 return false;
2591 static inline uint32 gui_getcolour_wrapped(lua_State *L, int offset, bool hasDefaultValue, uint32 defaultColour)
2593 switch (lua_type(L, offset))
2595 case LUA_TSTRING:
2597 const char *str = lua_tostring(L, offset);
2598 uint32 colour;
2600 if (str2colour(&colour, L, str))
2601 return colour;
2602 else
2604 if (hasDefaultValue)
2605 return defaultColour;
2606 else
2607 return luaL_error(L, "unknown colour %s", str);
2611 case LUA_TNUMBER:
2613 uint32 colour = (uint32) lua_tointeger(L, offset);
2614 return colour;
2617 case LUA_TTABLE:
2619 int color = 0xFF;
2620 lua_pushnil(L); // first key
2621 int keyIndex = lua_gettop(L);
2622 int valueIndex = keyIndex + 1;
2623 bool first = true;
2624 while (lua_next(L, offset))
2626 bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING);
2627 bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER);
2628 int key = keyIsString ? tolower(*lua_tostring(L, keyIndex)) : (keyIsNumber ? lua_tointeger(L, keyIndex) : 0);
2629 int value = lua_tointeger(L, valueIndex);
2630 if (value < 0) value = 0;
2631 if (value > 255) value = 255;
2632 switch (key)
2634 case 1:
2635 case 'r':
2636 color |= value << 24; break;
2637 case 2:
2638 case 'g':
2639 color |= value << 16; break;
2640 case 3:
2641 case 'b':
2642 color |= value << 8; break;
2643 case 4:
2644 case 'a':
2645 color = (color & ~0xFF) | value; break;
2647 lua_pop(L, 1);
2649 return color;
2650 } break;
2652 case LUA_TFUNCTION:
2653 luaL_error(L, "invalid colour"); // NYI
2654 return 0;
2656 default:
2657 if (hasDefaultValue)
2658 return defaultColour;
2659 else
2660 return luaL_error(L, "invalid colour");
2664 static uint32 gui_getcolour(lua_State *L, int offset)
2666 uint32 colour;
2667 int a, r, g, b;
2669 colour = gui_getcolour_wrapped(L, offset, false, 0);
2670 a = ((colour & 0xff) * transparencyModifier) / 255;
2671 if (a > 255)
2672 a = 255;
2673 b = (colour >> 8) & 0xff;
2674 g = (colour >> 16) & 0xff;
2675 r = (colour >> 24) & 0xff;
2676 return LUA_BUILD_PIXEL(a, r, g, b);
2679 static uint32 gui_optcolour(lua_State *L, int offset, uint32 defaultColour)
2681 uint32 colour;
2682 int a, r, g, b;
2683 uint8 defA, defB, defG, defR;
2685 LUA_DECOMPOSE_PIXEL(defaultColour, defA, defR, defG, defB);
2686 defaultColour = (defR << 24) | (defG << 16) | (defB << 8) | defA;
2688 colour = gui_getcolour_wrapped(L, offset, true, defaultColour);
2689 a = ((colour & 0xff) * transparencyModifier) / 255;
2690 if (a > 255)
2691 a = 255;
2692 b = (colour >> 8) & 0xff;
2693 g = (colour >> 16) & 0xff;
2694 r = (colour >> 24) & 0xff;
2695 return LUA_BUILD_PIXEL(a, r, g, b);
2698 // gui.drawpixel(x,y,colour)
2699 static int gui_drawpixel(lua_State *L)
2701 int x = luaL_checkinteger(L, 1);
2702 int y = luaL_checkinteger(L, 2);
2704 uint32 colour = gui_getcolour(L, 3);
2706 // if (!gui_check_boundary(x, y))
2707 // luaL_error(L,"bad coordinates");
2708 gui_prepare();
2710 gui_drawpixel_internal(x, y, colour);
2712 return 0;
2715 // gui.drawline(x1,y1,x2,y2,color,skipFirst)
2716 static int gui_drawline(lua_State *L)
2718 int x1, y1, x2, y2;
2719 uint32 color;
2720 x1 = luaL_checkinteger(L, 1);
2721 y1 = luaL_checkinteger(L, 2);
2722 x2 = luaL_checkinteger(L, 3);
2723 y2 = luaL_checkinteger(L, 4);
2724 color = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 255, 255, 255));
2725 int skipFirst = lua_toboolean(L, 6);
2727 gui_prepare();
2729 gui_drawline_internal(x2, y2, x1, y1, !skipFirst, color);
2731 return 0;
2734 // gui.drawbox(x1, y1, x2, y2, fillcolor, outlinecolor)
2735 static int gui_drawbox(lua_State *L)
2737 int x1, y1, x2, y2;
2738 uint32 fillcolor;
2739 uint32 outlinecolor;
2741 x1 = luaL_checkinteger(L, 1);
2742 y1 = luaL_checkinteger(L, 2);
2743 x2 = luaL_checkinteger(L, 3);
2744 y2 = luaL_checkinteger(L, 4);
2745 fillcolor = gui_optcolour(L, 5, LUA_BUILD_PIXEL(63, 255, 255, 255));
2746 outlinecolor = gui_optcolour(L, 6, LUA_BUILD_PIXEL(255, LUA_PIXEL_R(fillcolor), LUA_PIXEL_G(fillcolor), LUA_PIXEL_B(fillcolor)));
2748 if (x1 > x2)
2749 std::swap(x1, x2);
2750 if (y1 > y2)
2751 std::swap(y1, y2);
2753 gui_prepare();
2755 gui_drawbox_internal(x1, y1, x2, y2, outlinecolor);
2756 if ((x2 - x1) >= 2 && (y2 - y1) >= 2)
2757 gui_fillbox_internal(x1 + 1, y1 + 1, x2 - 1, y2 - 1, fillcolor);
2759 return 0;
2762 // gui.drawcircle(x0, y0, radius, colour)
2763 static int gui_drawcircle(lua_State *L)
2765 int x, y, r;
2766 uint32 colour;
2768 x = luaL_checkinteger(L, 1);
2769 y = luaL_checkinteger(L, 2);
2770 r = luaL_checkinteger(L, 3);
2771 colour = gui_getcolour(L, 4);
2773 gui_prepare();
2775 gui_drawcircle_internal(x, y, r, colour);
2777 return 0;
2780 // gui.fillbox(x1, y1, x2, y2, colour)
2781 static int gui_fillbox(lua_State *L)
2783 int x1, y1, x2, y2;
2784 uint32 colour;
2786 x1 = luaL_checkinteger(L, 1);
2787 y1 = luaL_checkinteger(L, 2);
2788 x2 = luaL_checkinteger(L, 3);
2789 y2 = luaL_checkinteger(L, 4);
2790 colour = gui_getcolour(L, 5);
2792 // if (!gui_check_boundary(x1, y1))
2793 // luaL_error(L,"bad coordinates");
2794 //
2795 // if (!gui_check_boundary(x2, y2))
2796 // luaL_error(L,"bad coordinates");
2797 gui_prepare();
2799 if (!gui_checkbox(x1, y1, x2, y2))
2800 return 0;
2802 gui_fillbox_internal(x1, y1, x2, y2, colour);
2804 return 0;
2807 // gui.fillcircle(x0, y0, radius, colour)
2808 static int gui_fillcircle(lua_State *L)
2810 int x, y, r;
2811 uint32 colour;
2813 x = luaL_checkinteger(L, 1);
2814 y = luaL_checkinteger(L, 2);
2815 r = luaL_checkinteger(L, 3);
2816 colour = gui_getcolour(L, 4);
2818 gui_prepare();
2820 gui_fillcircle_internal(x, y, r, colour);
2822 return 0;
2825 static int gui_getpixel(lua_State *L)
2827 int x = luaL_checkinteger(L, 1);
2828 int y = luaL_checkinteger(L, 2);
2830 int pixWidth = 240, pixHeight = 160;
2831 int scrWidth = 240, scrHeight = 160;
2832 int scrOffsetX = 0, scrOffsetY = 0;
2833 int pitch;
2834 if (!systemIsRunningGBA())
2836 if (gbBorderOn)
2838 pixWidth = 256, pixHeight = 224;
2839 scrOffsetX = 48, scrOffsetY = 40;
2841 else
2843 pixWidth = 160, pixHeight = 144;
2845 scrWidth = 160, scrHeight = 144;
2847 pitch = pixWidth * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4);
2848 scrOffsetY++; // don't know why it's needed
2850 if (!(x >= 0 && y >= 0 && x < scrWidth && y < scrHeight) /*!gui_check_boundary(x,y)*/)
2852 lua_pushinteger(L, 0);
2853 lua_pushinteger(L, 0);
2854 lua_pushinteger(L, 0);
2856 else
2858 switch (systemColorDepth)
2860 case 16:
2862 uint16 *screen = (uint16 *) (&pix[scrOffsetY * pitch + scrOffsetX * 2]);
2863 uint16 pixColor = screen[y * pitch / 2 + x];
2864 lua_pushinteger(L, (pixColor >> 8) & 0xF8); // red
2865 lua_pushinteger(L, (pixColor >> 3) & 0xFC); // green
2866 lua_pushinteger(L, (pixColor << 3) & 0xF8); // blue
2868 break;
2869 case 24:
2871 uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 3];
2872 lua_pushinteger(L, screen[y * pitch + x * 3 + 2]); // red
2873 lua_pushinteger(L, screen[y * pitch + x * 3 + 1]); // green
2874 lua_pushinteger(L, screen[y * pitch + x * 3 + 0]); // blue
2876 break;
2877 case 32:
2879 uint8 *screen = &pix[scrOffsetY * pitch + scrOffsetX * 4];
2880 lua_pushinteger(L, screen[y * pitch + x * 4 + 2]); // red
2881 lua_pushinteger(L, screen[y * pitch + x * 4 + 1]); // green
2882 lua_pushinteger(L, screen[y * pitch + x * 4 + 0]); // blue
2884 break;
2885 default:
2886 lua_pushinteger(L, 0);
2887 lua_pushinteger(L, 0);
2888 lua_pushinteger(L, 0);
2889 break;
2892 return 3;
2895 static int gui_parsecolor(lua_State *L)
2897 int r, g, b, a;
2898 uint32 color = gui_getcolour(L, 1);
2899 LUA_DECOMPOSE_PIXEL(color, a, r, g, b);
2900 lua_pushinteger(L, r);
2901 lua_pushinteger(L, g);
2902 lua_pushinteger(L, b);
2903 lua_pushinteger(L, a);
2904 return 4;
2907 // gui.gdscreenshot()
2908 //
2909 // Returns a screen shot as a string in gd's v1 file format.
2910 // This allows us to make screen shots available without gd installed locally.
2911 // Users can also just grab pixels via substring selection.
2912 //
2913 // I think... Does lua support grabbing byte values from a string? // yes, string.byte(str,offset)
2914 // Well, either way, just install gd and do what you like with it.
2915 // It really is easier that way.
2917 // example: gd.createFromGdStr(gui.gdscreenshot()):png("outputimage.png")
2918 static int gui_gdscreenshot(lua_State *L)
2920 int xofs = 0, yofs = 0, ppl = 240, width = 240, height = 160;
2921 if (!systemIsRunningGBA())
2923 if (gbBorderOn)
2924 xofs = 48, yofs = 40, ppl = 256;
2925 else
2926 ppl = 160;
2927 width = 160, height = 144;
2930 yofs++;
2932 //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3;
2933 int pitch = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4);
2934 uint8 *screen = &pix[yofs * pitch + xofs * (systemColorDepth / 8)];
2936 int size = 11 + width * height * 4;
2937 char *str = new char[size + 1];
2938 str[size] = 0;
2940 unsigned char *ptr = (unsigned char *)str;
2942 // GD format header for truecolor image (11 bytes)
2943 *ptr++ = (65534 >> 8) & 0xFF;
2944 *ptr++ = (65534) & 0xFF;
2945 *ptr++ = (width >> 8) & 0xFF;
2946 *ptr++ = (width) & 0xFF;
2947 *ptr++ = (height >> 8) & 0xFF;
2948 *ptr++ = (height) & 0xFF;
2949 *ptr++ = 1;
2950 *ptr++ = 255;
2951 *ptr++ = 255;
2952 *ptr++ = 255;
2953 *ptr++ = 255;
2955 GetColorFunc getColor;
2956 getColorIOFunc(systemColorDepth, &getColor, NULL);
2958 int x, y;
2959 for (y = 0; y < height; y++)
2961 uint8 *s = &screen[y * pitch];
2962 for (x = 0; x < width; x++, s += systemColorDepth / 8)
2964 uint8 r, g, b;
2965 getColor(s, &r, &g, &b);
2967 *ptr++ = 0;
2968 *ptr++ = r;
2969 *ptr++ = g;
2970 *ptr++ = b;
2974 lua_pushlstring(L, str, size);
2975 delete[] str;
2976 return 1;
2979 // gui.opacity(number alphaValue)
2980 // sets the transparency of subsequent draw calls
2981 // 0.0 is completely transparent, 1.0 is completely opaque
2982 // non-integer values are supported and meaningful, as are values greater than 1.0
2983 // it is not necessary to use this function to get transparency (or the less-recommended gui.transparency() either),
2984 // because you can provide an alpha value in the color argument of each draw call.
2986 // however, it can be convenient to be able to globally modify the drawing transparency
2987 static int gui_setopacity(lua_State *L)
2989 double opacF = luaL_checknumber(L, 1);
2990 transparencyModifier = (int)(opacF * 255);
2991 if (transparencyModifier < 0)
2992 transparencyModifier = 0;
2993 return 0;
2996 // gui.transparency(int strength)
2997 //
2999 // 0 = solid,
3000 static int gui_transparency(lua_State *L)
3002 double trans = luaL_checknumber(L, 1);
3003 transparencyModifier = (int)((4.0 - trans) / 4.0 * 255);
3004 if (transparencyModifier < 0)
3005 transparencyModifier = 0;
3006 return 0;
3009 static const uint32 Small_Font_Data[] =
3011 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 32
3012 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 33 !
3013 0x00000000, 0x00040002, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 34 "
3014 0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 35 #
3015 0x00000000, 0x00040300, 0x00000403, 0x00000500, 0x00070600, 0x00000706, 0x00000000, // 36 $
3016 0x00000000, 0x00000002, 0x00050000, 0x00000500, 0x00000005, 0x00080000, 0x00000000, // 37 %
3017 0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00080700, 0x00000000, // 38 &
3018 0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 39 '
3019 0x00000000, 0x00000300, 0x00000003, 0x00000004, 0x00000005, 0x00000700, 0x00000000, // 40 (
3020 0x00000000, 0x00000300, 0x00050000, 0x00060000, 0x00070000, 0x00000700, 0x00000000, // 41 )
3021 0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00080006, 0x00000000, // 42 *
3022 0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00000000, 0x00000000, // 43 +
3023 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000600, 0x00000700, 0x00000007, // 44 ,
3024 0x00000000, 0x00000000, 0x00000000, 0x00060504, 0x00000000, 0x00000000, 0x00000000, // 45 -
3025 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 46 .
3026 0x00030000, 0x00040000, 0x00000400, 0x00000500, 0x00000005, 0x00000006, 0x00000000, // 47 /
3027 0x00000000, 0x00000300, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 48 0
3028 0x00000000, 0x00000300, 0x00000403, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 49 1
3029 0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 50 2
3030 0x00000000, 0x00000302, 0x00050000, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 51 3
3031 0x00000000, 0x00000300, 0x00000003, 0x00060004, 0x00070605, 0x00080000, 0x00000000, // 52 4
3032 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00070000, 0x00000706, 0x00000000, // 53 5
3033 0x00000000, 0x00000300, 0x00000003, 0x00000504, 0x00070005, 0x00000700, 0x00000000, // 54 6
3034 0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 55 7
3035 0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00000700, 0x00000000, // 56 8
3036 0x00000000, 0x00000300, 0x00050003, 0x00060500, 0x00070000, 0x00000700, 0x00000000, // 57 9
3037 0x00000000, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000700, 0x00000000, // 58 :
3038 0x00000000, 0x00000000, 0x00000000, 0x00000500, 0x00000000, 0x00000700, 0x00000007, // 59 ;
3039 0x00000000, 0x00040000, 0x00000400, 0x00000004, 0x00000600, 0x00080000, 0x00000000, // 60 <
3040 0x00000000, 0x00000000, 0x00050403, 0x00000000, 0x00070605, 0x00000000, 0x00000000, // 61 =
3041 0x00000000, 0x00000002, 0x00000400, 0x00060000, 0x00000600, 0x00000006, 0x00000000, // 62 >
3042 0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000000, 0x00000700, 0x00000000, // 63 ?
3043 0x00000000, 0x00000300, 0x00050400, 0x00060004, 0x00070600, 0x00000000, 0x00000000, // 64 @
3044 0x00000000, 0x00000300, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 65 A
3045 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 66 B
3046 0x00000000, 0x00040300, 0x00000003, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 67 C
3047 0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00000706, 0x00000000, // 68 D
3048 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00080706, 0x00000000, // 69 E
3049 0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 70 F
3050 0x00000000, 0x00040300, 0x00000003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 71 G
3051 0x00000000, 0x00040002, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 72 H
3052 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 73 I
3053 0x00000000, 0x00040000, 0x00050000, 0x00060000, 0x00070005, 0x00000700, 0x00000000, // 74 J
3054 0x00000000, 0x00040002, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 75 K
3055 0x00000000, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00080706, 0x00000000, // 76 l
3056 0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 77 M
3057 0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 78 N
3058 0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 79 O
3059 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 80 P
3060 0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00090000, // 81 Q
3061 0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 82 R
3062 0x00000000, 0x00040300, 0x00000003, 0x00000500, 0x00070000, 0x00000706, 0x00000000, // 83 S
3063 0x00000000, 0x00040302, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 84 T
3064 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000, // 85 U
3065 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000000, // 86 V
3066 0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 87 W
3067 0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 88 X
3068 0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 89 Y
3069 0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 90 Z
3070 0x00000000, 0x00040300, 0x00000400, 0x00000500, 0x00000600, 0x00080700, 0x00000000, // 91 [
3071 0x00000000, 0x00000002, 0x00000400, 0x00000500, 0x00070000, 0x00080000, 0x00000000, // 92 '\'
3072 0x00000000, 0x00000302, 0x00000400, 0x00000500, 0x00000600, 0x00000706, 0x00000000, // 93 ]
3073 0x00000000, 0x00000300, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 94 ^
3074 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080706, 0x00000000, // 95 _
3075 0x00000000, 0x00000002, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 96 `
3076 0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 97 a
3077 0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00000706, 0x00000000, // 98 b
3078 0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00000005, 0x00080700, 0x00000000, // 99 c
3079 0x00000000, 0x00040000, 0x00050000, 0x00060500, 0x00070005, 0x00080700, 0x00000000, // 100 d
3080 0x00000000, 0x00000000, 0x00050400, 0x00060504, 0x00000005, 0x00080700, 0x00000000, // 101 e
3081 0x00000000, 0x00040300, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 102 f
3082 0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070600, 0x00080000, 0x00000807, // 103 g
3083 0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00080006, 0x00000000, // 104 h
3084 0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000000, // 105 i
3085 0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000007, // 106 j
3086 0x00000000, 0x00000002, 0x00000003, 0x00060004, 0x00000605, 0x00080006, 0x00000000, // 107 k
3087 0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 108 l
3088 0x00000000, 0x00000000, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000, // 109 m
3089 0x00000000, 0x00000000, 0x00000403, 0x00060004, 0x00070005, 0x00080006, 0x00000000, // 110 n
3090 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 111 o
3091 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00000605, 0x00000006, 0x00000007, // 112 p
3092 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070600, 0x00080000, 0x00090000, // 113 q
3093 0x00000000, 0x00000000, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000, // 114 r
3094 0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00070600, 0x00000706, 0x00000000, // 115 s
3095 0x00000000, 0x00000300, 0x00050403, 0x00000500, 0x00000600, 0x00080000, 0x00000000, // 116 t
3096 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00080700, 0x00000000, // 117 u
3097 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000, // 118 v
3098 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000, // 119 w
3099 0x00000000, 0x00000000, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000, // 120 x
3100 0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000007, // 121 y
3101 0x00000000, 0x00000000, 0x00050403, 0x00000500, 0x00000005, 0x00080706, 0x00000000, // 122 z
3102 0x00000000, 0x00040300, 0x00000400, 0x00000504, 0x00000600, 0x00080700, 0x00000000, // 123 {
3103 0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000600, 0x00000700, 0x00000000, // 124 |
3104 0x00000000, 0x00000302, 0x00000400, 0x00060500, 0x00000600, 0x00000706, 0x00000000, // 125 }
3105 0x00000000, 0x00000302, 0x00050000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // 126 ~
3106 0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070605, 0x00000000, 0x00000000, // 127 
3107 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
3108 };
3110 static void PutTextInternal(const char *str, int len, short x, short y, int color, int backcolor)
3112 int Opac = (color >> 24) & 0xFF;
3113 int backOpac = (backcolor >> 24) & 0xFF;
3114 int origX = x;
3116 if (!Opac && !backOpac)
3117 return;
3119 while (*str && len && y < LUA_SCREEN_HEIGHT)
3121 int c = *str++;
3122 while (x > LUA_SCREEN_WIDTH && c != '\n')
3124 c = *str;
3125 if (c == '\0')
3126 break;
3127 str++;
3130 if (c == '\n')
3132 x = origX;
3133 y += 8;
3134 continue;
3136 else if (c == '\t') // just in case
3138 const int tabSpace = 8;
3139 x += (tabSpace - (((x - origX) / 4) % tabSpace)) * 4;
3140 continue;
3143 if ((unsigned int)(c - 32) >= 96)
3144 continue;
3146 const unsigned char *Cur_Glyph = (const unsigned char *) &Small_Font_Data + (c - 32) * 7 * 4;
3148 for (int y2 = 0; y2 < 8; y2++)
3150 unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y2);
3151 for (int x2 = -1; x2 < 4; x2++)
3153 int shift = x2 << 3;
3154 int mask = 0xFF << shift;
3155 int intensity = (glyphLine & mask) >> shift;
3157 if (intensity && x2 >= 0 && y2 < 7)
3159 //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2));
3160 //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2));
3161 //gui_drawpixel_fast(xdraw, ydraw, color);
3162 gui_drawpixel_internal(x + x2, y + y2, color);
3164 else if (backOpac)
3166 for (int y3 = max(0, y2 - 1); y3 <= min(6, y2 + 1); y3++)
3168 unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y3);
3169 for (int x3 = max(0, x2 - 1); x3 <= min(3, x2 + 1); x3++)
3171 int shift = x3 << 3;
3172 int mask = 0xFF << shift;
3173 intensity |= (glyphLine & mask) >> shift;
3174 if (intensity)
3175 goto draw_outline; // speedup?
3179 draw_outline:
3180 if (intensity)
3182 //int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2));
3183 //int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2));
3184 //gui_drawpixel_fast(xdraw, ydraw, backcolor);
3185 gui_drawpixel_internal(x + x2, y + y2, backcolor);
3191 x += 4;
3192 len--;
3196 static int strlinelen(const char *string)
3198 const char *s = string;
3199 while (*s && *s != '\n')
3200 s++;
3201 if (*s)
3202 s++;
3203 return s - string;
3206 static void LuaDisplayString(const char *string, int y, int x, uint32 color, uint32 outlineColor)
3208 if (!string)
3209 return;
3211 gui_prepare();
3213 PutTextInternal(string, strlen(string), x, y, color, outlineColor);
3215 /*
3216 const char* ptr = string;
3217 while(*ptr && y < LUA_SCREEN_HEIGHT)
3219 int len = strlinelen(ptr);
3220 int skip = 0;
3221 if(len < 1) len = 1;
3223 // break up the line if it's too long to display otherwise
3224 if(len > 63)
3226 len = 63;
3227 const char* ptr2 = ptr + len-1;
3228 for(int j = len-1; j; j--, ptr2--)
3230 if(*ptr2 == ' ' || *ptr2 == '\t')
3232 len = j;
3233 skip = 1;
3234 break;
3239 int xl = 0;
3240 int yl = 0;
3241 int xh = (LUA_SCREEN_WIDTH - 1 - 1) - 4*len;
3242 int yh = LUA_SCREEN_HEIGHT - 1;
3243 int x2 = min(max(x,xl),xh);
3244 int y2 = min(max(y,yl),yh);
3246 PutTextInternal(ptr,len,x2,y2,color,outlineColor);
3248 ptr += len + skip;
3249 y += 8;
3251 */
3254 // gui.text(int x, int y, string msg)
3255 //
3256 // Displays the given text on the screen, using the same font and techniques as the
3258 // main HUD.
3259 static int gui_text(lua_State *L)
3261 //extern int font_height;
3262 const char *msg;
3263 int x, y;
3264 uint32 colour, borderColour;
3266 x = luaL_checkinteger(L, 1);
3267 y = luaL_checkinteger(L, 2);
3268 //msg = luaL_checkstring(L, 3);
3269 msg = toCString(L, 3);
3271 // if (x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= (LUA_SCREEN_HEIGHT - font_height))
3272 // luaL_error(L,"bad coordinates");
3273 colour = gui_optcolour(L, 4, LUA_BUILD_PIXEL(255, 255, 255, 255));
3274 borderColour = gui_optcolour(L, 5, LUA_BUILD_PIXEL(255, 0, 0, 0));
3276 gui_prepare();
3278 LuaDisplayString(msg, y, x, colour, borderColour);
3280 return 0;
3283 // gui.gdoverlay([int dx=0, int dy=0,] string str [, sx=0, sy=0, sw, sh] [, float alphamul=1.0])
3284 //
3285 // Overlays the given image on the screen.
3287 // example: gui.gdoverlay(gd.createFromPng("myimage.png"):gdStr())
3288 static int gui_gdoverlay(lua_State *L)
3290 int argCount = lua_gettop(L);
3292 int xStartDst = 0;
3293 int yStartDst = 0;
3294 int xStartSrc = 0;
3295 int yStartSrc = 0;
3297 int index = 1;
3298 if (lua_type(L, index) == LUA_TNUMBER)
3300 xStartDst = lua_tointeger(L, index++);
3301 if (lua_type(L, index) == LUA_TNUMBER)
3302 yStartDst = lua_tointeger(L, index++);
3305 luaL_checktype(L, index, LUA_TSTRING);
3307 const unsigned char *ptr = (const unsigned char *)lua_tostring(L, index++);
3309 if (ptr[0] != 255 || (ptr[1] != 254 && ptr[1] != 255))
3310 luaL_error(L, "bad image data");
3312 bool trueColor = (ptr[1] == 254);
3313 ptr += 2;
3315 int imgwidth = *ptr++ << 8;
3316 imgwidth |= *ptr++;
3318 int width = imgwidth;
3319 int imgheight = *ptr++ << 8;
3320 imgheight |= *ptr++;
3322 int height = imgheight;
3323 if ((!trueColor && *ptr) || (trueColor && !*ptr))
3324 luaL_error(L, "bad image data");
3325 ptr++;
3327 int pitch = imgwidth * (trueColor ? 4 : 1);
3329 if ((argCount - index + 1) >= 4)
3331 xStartSrc = luaL_checkinteger(L, index++);
3332 yStartSrc = luaL_checkinteger(L, index++);
3333 width = luaL_checkinteger(L, index++);
3334 height = luaL_checkinteger(L, index++);
3337 int alphaMul = transparencyModifier;
3338 if (lua_isnumber(L, index))
3339 alphaMul = (int)(alphaMul * lua_tonumber(L, index++));
3340 if (alphaMul <= 0)
3341 return 0;
3343 // since there aren't that many possible opacity levels,
3344 // do the opacity modification calculations beforehand instead of per pixel
3345 int opacMap[256];
3346 for (int i = 0; i < 128; i++)
3348 int opac = 255 - ((i << 1) | (i & 1)); // gdAlphaMax = 127, not 255
3349 opac = (opac * alphaMul) / 255;
3350 if (opac < 0)
3351 opac = 0;
3352 if (opac > 255)
3353 opac = 255;
3354 opacMap[i] = opac;
3357 for (int i = 128; i < 256; i++)
3358 opacMap[i] = 0; // what should we do for them, actually?
3359 int colorsTotal = 0;
3360 if (!trueColor)
3362 colorsTotal = *ptr++ << 8;
3363 colorsTotal |= *ptr++;
3366 int transparent = *ptr++ << 24;
3367 transparent |= *ptr++ << 16;
3368 transparent |= *ptr++ << 8;
3369 transparent |= *ptr++;
3370 struct
3372 uint8 r, g, b, a;
3373 } pal[256];
3374 if (!trueColor)
3375 for (int i = 0; i < 256; i++)
3377 pal[i].r = *ptr++;
3378 pal[i].g = *ptr++;
3379 pal[i].b = *ptr++;
3380 pal[i].a = opacMap[*ptr++];
3383 // some of clippings
3384 if (xStartSrc < 0)
3386 width += xStartSrc;
3387 xStartDst -= xStartSrc;
3388 xStartSrc = 0;
3391 if (yStartSrc < 0)
3393 height += yStartSrc;
3394 yStartDst -= yStartSrc;
3395 yStartSrc = 0;
3398 if (xStartSrc + width >= imgwidth)
3399 width = imgwidth - xStartSrc;
3400 if (yStartSrc + height >= imgheight)
3401 height = imgheight - yStartSrc;
3402 if (xStartDst < 0)
3404 width += xStartDst;
3405 if (width <= 0)
3406 return 0;
3407 xStartSrc = -xStartDst;
3408 xStartDst = 0;
3411 if (yStartDst < 0)
3413 height += yStartDst;
3414 if (height <= 0)
3415 return 0;
3416 yStartSrc = -yStartDst;
3417 yStartDst = 0;
3420 if (xStartDst + width >= LUA_SCREEN_WIDTH)
3421 width = LUA_SCREEN_WIDTH - xStartDst;
3422 if (yStartDst + height >= LUA_SCREEN_HEIGHT)
3423 height = LUA_SCREEN_HEIGHT - yStartDst;
3424 if (width <= 0 || height <= 0)
3425 return 0; // out of screen or invalid size
3426 gui_prepare();
3428 const uint8 *pix = (const uint8 *)(&ptr[yStartSrc * pitch + (xStartSrc * (trueColor ? 4 : 1))]);
3429 int bytesToNextLine = pitch - (width * (trueColor ? 4 : 1));
3430 if (trueColor)
3432 for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine)
3434 for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix += 4)
3436 gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(opacMap[pix[0]], pix[1], pix[2], pix[3]));
3440 else
3442 for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine)
3444 for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix++)
3446 gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(pal[*pix].a, pal[*pix].r, pal[*pix].g, pal[*pix].b));
3451 return 0;
3454 // function gui.register(function f)
3455 //
3456 // This function will be called just before a graphical update.
3457 // More complicated, but doesn't suffer any frame delays.
3458 // Nil will be accepted in place of a function to erase
3459 // a previously registered function, and the previous function
3461 // (if any) is returned, or nil if none.
3462 static int gui_register(lua_State *L)
3464 // We'll do this straight up.
3465 // First set up the stack.
3466 lua_settop(L, 1);
3468 // Verify the validity of the entry
3469 if (!lua_isnil(L, 1))
3470 luaL_checktype(L, 1, LUA_TFUNCTION);
3472 // Get the old value
3473 lua_getfield(L, LUA_REGISTRYINDEX, guiCallbackTable);
3475 // Save the new value
3476 lua_pushvalue(L, 1);
3477 lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable);
3479 // The old value is on top of the stack. Return it.
3480 return 1;
3483 // string gui.popup(string message, [string type = "ok"])
3484 //
3486 // Popup dialog!
3487 int gui_popup(lua_State *L)
3489 const char *message = luaL_checkstring(L, 1);
3490 const char *type = luaL_optstring(L, 2, "ok");
3492 #if (defined(WIN32) && !defined(SDL))
3493 int t;
3494 if (strcmp(type, "ok") == 0)
3495 t = MB_OK;
3496 else if (strcmp(type, "yesno") == 0)
3497 t = MB_YESNO;
3498 else if (strcmp(type, "yesnocancel") == 0)
3499 t = MB_YESNOCANCEL;
3500 else
3501 return luaL_error(L, "invalid popup type \"%s\"", type);
3503 theApp.winCheckFullscreen();
3504 systemSoundClearBuffer();
3505 int result = AfxGetApp()->m_pMainWnd->MessageBox(message, "Lua Script Pop-up", t);
3507 lua_settop(L, 1);
3509 if (t != MB_OK)
3511 if (result == IDYES)
3512 lua_pushstring(L, "yes");
3513 else if (result == IDNO)
3514 lua_pushstring(L, "no");
3515 else if (result == IDCANCEL)
3516 lua_pushstring(L, "cancel");
3517 else
3518 luaL_error(L, "win32 unrecognized return value %d", result);
3519 return 1;
3522 // else, we don't care.
3523 return 0;
3524 #else
3525 char *t;
3526 #ifdef __linux
3527 // The Linux backend has a "FromPause" variable.
3528 // If set to 1, assume some known external event has screwed with the flow of time.
3529 // Since this pauses the emulator waiting for a response, we set it to 1.
3530 // FIXME: Well, actually it doesn't
3531 // extern int FromPause;
3532 // FromPause = 1;
3534 int pid; // appease compiler
3536 // Before doing any work, verify the correctness of the parameters.
3537 if (strcmp(type, "ok") == 0)
3538 t = "OK:100";
3539 else if (strcmp(type, "yesno") == 0)
3540 t = "Yes:100,No:101";
3541 else if (strcmp(type, "yesnocancel") == 0)
3542 t = "Yes:100,No:101,Cancel:102";
3543 else
3544 return luaL_error(L, "invalid popup type \"%s\"", type);
3546 // Can we find a copy of xmessage? Search the path.
3547 char *path = strdup(getenv("PATH"));
3549 char *current = path;
3551 char *colon;
3553 int found = 0;
3555 while (current)
3557 colon = strchr(current, ':');
3559 // Clip off the colon.
3560 *colon++ = 0;
3562 int len = strlen(current);
3563 char *filename = (char *)malloc(len + 12); // always give excess
3564 snprintf(filename, len + 12, "%s/xmessage", current);
3566 if (access(filename, X_OK) == 0)
3568 free(filename);
3569 found = 1;
3570 break;
3573 // Failed, move on.
3574 current = colon;
3575 free(filename);
3578 free(path);
3580 // We've found it?
3581 if (!found)
3582 goto use_console;
3584 pid = fork();
3585 if (pid == 0)
3586 { // I'm the virgin sacrifice
3587 // I'm gonna be dead in a matter of microseconds anyways, so wasted memory doesn't matter to me.
3588 // Go ahead and abuse strdup.
3589 char *parameters[] = { "xmessage", "-buttons", t, strdup(message), NULL };
3591 execvp("xmessage", parameters);
3593 // Aw shitty
3594 perror("exec xmessage");
3595 exit(1);
3597 else if (pid < 0) // something went wrong!!! Oh hell... use the console
3598 goto use_console;
3599 else
3601 // We're the parent. Watch for the child.
3602 int r;
3603 int res = waitpid(pid, &r, 0);
3604 if (res < 0) // wtf?
3605 goto use_console;
3607 // The return value gets copmlicated...
3608 if (!WIFEXITED(r))
3610 luaL_error(L, "don't screw with my xmessage process!");
3613 r = WEXITSTATUS(r);
3615 // We assume it's worked.
3616 if (r == 0)
3618 return 0; // no parameters for an OK
3621 if (r == 100)
3623 lua_pushstring(L, "yes");
3624 return 1;
3627 if (r == 101)
3629 lua_pushstring(L, "no");
3630 return 1;
3633 if (r == 102)
3635 lua_pushstring(L, "cancel");
3636 return 1;
3639 // Wtf?
3640 return luaL_error(L, "popup failed due to unknown results involving xmessage (%d)", r);
3643 use_console:
3644 #endif
3646 // All else has failed
3647 if (strcmp(type, "ok") == 0)
3648 t = "";
3649 else if (strcmp(type, "yesno") == 0)
3650 t = "yn";
3651 else if (strcmp(type, "yesnocancel") == 0)
3652 t = "ync";
3653 else
3654 return luaL_error(L, "invalid popup type \"%s\"", type);
3656 fprintf(stderr, "Lua Message: %s\n", message);
3658 while (true)
3660 char buffer[64];
3662 // We don't want parameters
3663 if (!t[0])
3665 fprintf(stderr, "[Press Enter]");
3666 fgets(buffer, sizeof(buffer), stdin);
3668 // We're done
3669 return 0;
3672 fprintf(stderr, "(%s): ", t);
3673 fgets(buffer, sizeof(buffer), stdin);
3675 // Check if the option is in the list
3676 if (strchr(t, tolower(buffer[0])))
3678 switch (tolower(buffer[0]))
3680 case 'y':
3681 lua_pushstring(L, "yes");
3682 return 1;
3683 case 'n':
3684 lua_pushstring(L, "no");
3685 return 1;
3686 case 'c':
3687 lua_pushstring(L, "cancel");
3688 return 1;
3689 default:
3690 luaL_error(L, "internal logic error in console based prompts for gui.popup");
3694 // We fell through, so we assume the user answered wrong and prompt again.
3697 // Nothing here, since the only way out is in the loop.
3698 #endif
3701 #if (defined(WIN32) && !defined(SDL))
3702 const char *s_keyToName[256] =
3704 NULL,
3705 "leftclick",
3706 "rightclick",
3707 NULL,
3708 "middleclick",
3709 NULL,
3710 NULL,
3711 NULL,
3712 "backspace",
3713 "tab",
3714 NULL,
3715 NULL,
3716 NULL,
3717 "enter",
3718 NULL,
3719 NULL,
3720 "shift", // 0x10
3721 "control",
3722 "alt",
3723 "pause",
3724 "capslock",
3725 NULL,
3726 NULL,
3727 NULL,
3728 NULL,
3729 NULL,
3730 NULL,
3731 "escape",
3732 NULL,
3733 NULL,
3734 NULL,
3735 NULL,
3736 "space", // 0x20
3737 "pageup",
3738 "pagedown",
3739 "end",
3740 "home",
3741 "left",
3742 "up",
3743 "right",
3744 "down",
3745 NULL,
3746 NULL,
3747 NULL,
3748 NULL,
3749 "insert",
3750 "delete",
3751 NULL,
3752 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
3753 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3754 "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
3755 "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
3756 "U", "V", "W", "X", "Y", "Z",
3757 NULL,
3758 NULL,
3759 NULL,
3760 NULL,
3761 NULL,
3762 "numpad0", "numpad1", "numpad2", "numpad3", "numpad4", "numpad5", "numpad6", "numpad7", "numpad8", "numpad9",
3763 "numpad*", "numpad+",
3764 NULL,
3765 "numpad-", "numpad.", "numpad/",
3766 "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11",
3767 "F12",
3768 "F13", "F14", "F15", "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
3769 "F24",
3770 NULL,
3771 NULL,
3772 NULL,
3773 NULL,
3774 NULL,
3775 NULL,
3776 NULL,
3777 NULL,
3778 "numlock",
3779 "scrolllock",
3780 NULL, // 0x92
3781 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3782 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3783 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3784 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3785 NULL, // 0xB9
3786 "semicolon",
3787 "plus",
3788 "comma",
3789 "minus",
3790 "period",
3791 "slash",
3792 "tilde",
3793 NULL, // 0xC1
3794 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3795 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3796 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3797 NULL, // 0xDA
3798 "leftbracket",
3799 "backslash",
3800 "rightbracket",
3801 "quote",
3802 };
3803 #endif
3805 // input.get()
3806 // takes no input, returns a lua table of entries representing the current input state,
3807 // independent of the joypad buttons the emulated game thinks are pressed
3808 // for example:
3809 // if the user is holding the W key and the left mouse button
3810 // and has the mouse at the bottom-right corner of the game screen,
3812 // then this would return {W=true, leftclick=true, xmouse=255, ymouse=223}
3813 static int input_getcurrentinputstatus(lua_State *L)
3815 lua_newtable(L);
3817 #if (defined(WIN32) && !defined(SDL))
3818 // keyboard and mouse button status
3820 unsigned char keys[256];
3821 if (true /*!GUI.BackgroundInput*/) // TODO: background input
3823 if (GetKeyboardState(keys))
3825 for (int i = 1; i < 255; i++)
3827 int mask = (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) ? 0x01 : 0x80;
3828 if (keys[i] & mask)
3830 const char *name = s_keyToName[i];
3831 if (name)
3833 lua_pushboolean(L, true);
3834 lua_setfield(L, -2, name);
3840 else // use a slightly different method that will detect background input:
3842 for (int i = 1; i < 255; i++)
3844 const char *name = s_keyToName[i];
3845 if (name)
3847 int active;
3848 if (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL)
3849 active = GetKeyState(i) & 0x01;
3850 else
3851 active = GetAsyncKeyState(i) & 0x8000;
3852 if (active)
3854 lua_pushboolean(L, true);
3855 lua_setfield(L, -2, name);
3862 // mouse position in game screen pixel coordinates
3864 POINT mouse;
3866 int xofs = 0, yofs = 0, width = 240, height = 160;
3867 if (!systemIsRunningGBA())
3869 if (gbBorderOn)
3870 width = 256, height = 224, xofs = 48, yofs = 40;
3871 else
3872 width = 160, height = 144;
3875 GetCursorPos(&mouse);
3876 AfxGetApp()->m_pMainWnd->ScreenToClient(&mouse);
3878 // game screen is always fully stretched to window size,
3879 // with no aspect rate correction, or something like that.
3880 RECT clientRect;
3881 AfxGetApp()->m_pMainWnd->GetClientRect(&clientRect);
3883 int wndWidth = clientRect.right - clientRect.left;
3884 int wndHeight = clientRect.bottom - clientRect.top;
3885 mouse.x = (LONG) (mouse.x * ((float)width / wndWidth)) - xofs;
3886 mouse.y = (LONG) (mouse.y * ((float)height / wndHeight)) - yofs;
3888 lua_pushinteger(L, mouse.x);
3889 lua_setfield(L, -2, "xmouse");
3890 lua_pushinteger(L, mouse.y);
3891 lua_setfield(L, -2, "ymouse");
3894 #else
3895 // NYI (well, return an empty table)
3896 #endif
3897 return 1;
3900 static int avi_framecount(lua_State *L)
3902 #ifdef WIN32
3903 if (theApp.aviRecorder != NULL)
3905 lua_pushinteger(L, theApp.aviRecorder->videoFrames());
3907 else
3908 #endif
3910 lua_pushinteger(L, 0);
3912 return 1;
3915 static int avi_pause(lua_State *L)
3917 #ifdef WIN32
3918 if (theApp.aviRecorder != NULL)
3919 theApp.aviRecorder->Pause(true);
3920 #endif
3921 return 1;
3924 static int avi_resume(lua_State *L)
3926 #ifdef WIN32
3927 if (theApp.aviRecorder != NULL)
3928 theApp.aviRecorder->Pause(false);
3929 #endif
3930 return 1;
3933 static int sound_get(lua_State *L)
3935 extern int32 soundLevel1;
3936 extern int32 soundLevel2;
3937 extern int32 soundBalance;
3938 extern int32 soundMasterOn;
3939 extern int32 soundVIN;
3940 extern int32 sound1On;
3941 extern int32 sound1EnvelopeVolume;
3942 extern int32 sound2On;
3943 extern int32 sound2EnvelopeVolume;
3944 extern int32 sound3On;
3945 extern int32 sound3OutputLevel;
3946 extern int32 sound3Bank;
3947 extern int32 sound3DataSize;
3948 extern int32 sound3ForcedOutput;
3949 extern int32 sound4On;
3950 extern int32 sound4EnvelopeVolume;
3951 extern u8 sound3WaveRam[0x20];
3953 int freqReg;
3954 double freq;
3955 double leftvolscale;
3956 double rightvolscale;
3957 double panpot;
3958 bool gba = systemIsRunningGBA();
3959 u8* gbMem = gba ? ioMem : gbMemory;
3960 const int rNR10 = gba ? 0x60 : 0xff10;
3961 const int rNR11 = gba ? 0x62 : 0xff11;
3962 const int rNR12 = gba ? 0x63 : 0xff12;
3963 const int rNR13 = gba ? 0x64 : 0xff13;
3964 const int rNR14 = gba ? 0x65 : 0xff14;
3965 const int rNR21 = gba ? 0x68 : 0xff16;
3966 const int rNR22 = gba ? 0x69 : 0xff17;
3967 const int rNR23 = gba ? 0x6c : 0xff18;
3968 const int rNR24 = gba ? 0x6d : 0xff19;
3969 const int rNR30 = gba ? 0x70 : 0xff1a;
3970 const int rNR31 = gba ? 0x72 : 0xff1b;
3971 const int rNR32 = gba ? 0x73 : 0xff1c;
3972 const int rNR33 = gba ? 0x74 : 0xff1d;
3973 const int rNR34 = gba ? 0x75 : 0xff1e;
3974 const int rNR41 = gba ? 0x78 : 0xff20;
3975 const int rNR42 = gba ? 0x79 : 0xff21;
3976 const int rNR43 = gba ? 0x7c : 0xff22;
3977 const int rNR44 = gba ? 0x7d : 0xff23;
3978 const int rNR50 = gba ? 0x80 : 0xff24;
3979 const int rNR51 = gba ? 0x81 : 0xff25;
3980 const int rNR52 = gba ? 0x84 : 0xff26;
3981 const int rWAVE_RAM = gba ? 0x90 : 0xff30;
3983 const int32 _soundVIN = 0x88; // gba ? 0x88 : soundVIN;
3984 const bool soundVINLeft = ((_soundVIN & 0x80) != 0);
3985 const bool soundVINRight = ((_soundVIN & 0x08) != 0);
3987 lua_newtable(L);
3989 // square1
3990 lua_newtable(L);
3991 if(sound1On == 0 || soundMasterOn == 0)
3993 lua_pushnumber(L, 0.0);
3994 panpot = 0.5;
3996 else
3998 double envVolume = sound1EnvelopeVolume / 15.0;
3999 if (soundVINLeft && (soundBalance & 0x10) != 0)
4000 leftvolscale = ((soundLevel2 / 7.0) * envVolume);
4001 else
4002 leftvolscale = 0.0;
4003 if (soundVINRight && (soundBalance & 0x01) != 0)
4004 rightvolscale = ((soundLevel1 / 7.0) * envVolume);
4005 else
4006 rightvolscale = 0.0;
4007 if ((leftvolscale + rightvolscale) != 0)
4008 panpot = rightvolscale / (leftvolscale + rightvolscale);
4009 else
4010 panpot = 0.5;
4011 lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
4013 lua_setfield(L, -2, "volume");
4014 lua_pushnumber(L, panpot);
4015 lua_setfield(L, -2, "panpot");
4016 freqReg = (((int)(gbMem[rNR14] & 7) << 8) | gbMem[rNR13]);
4017 freq = 131072.0 / (2048 - freqReg);
4018 lua_pushnumber(L, freq);
4019 lua_setfield(L, -2, "frequency");
4020 lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
4021 lua_setfield(L, -2, "midikey");
4022 lua_pushinteger(L, (gbMem[rNR11] & 0xC0) >> 6);
4023 lua_setfield(L, -2, "duty");
4024 lua_newtable(L);
4025 lua_pushinteger(L, freqReg);
4026 lua_setfield(L, -2, "frequency");
4027 lua_setfield(L, -2, "regs");
4028 lua_setfield(L, -2, "square1");
4029 // square2
4030 lua_newtable(L);
4031 if(sound2On == 0 || soundMasterOn == 0)
4033 lua_pushnumber(L, 0.0);
4034 panpot = 0.5;
4036 else
4038 double envVolume = sound2EnvelopeVolume / 15.0;
4039 if (soundVINLeft && (soundBalance & 0x20) != 0)
4040 leftvolscale = ((soundLevel2 / 7.0) * envVolume);
4041 else
4042 leftvolscale = 0.0;
4043 if (soundVINRight && (soundBalance & 0x02) != 0)
4044 rightvolscale = ((soundLevel1 / 7.0) * envVolume);
4045 else
4046 rightvolscale = 0.0;
4047 if ((leftvolscale + rightvolscale) != 0)
4048 panpot = rightvolscale / (leftvolscale + rightvolscale);
4049 else
4050 panpot = 0.5;
4051 lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
4053 lua_setfield(L, -2, "volume");
4054 lua_pushnumber(L, panpot);
4055 lua_setfield(L, -2, "panpot");
4056 freqReg = (((int)(gbMem[rNR24] & 7) << 8) | gbMem[rNR23]);
4057 freq = 131072.0 / (2048 - freqReg);
4058 lua_pushnumber(L, freq);
4059 lua_setfield(L, -2, "frequency");
4060 lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
4061 lua_setfield(L, -2, "midikey");
4062 lua_pushinteger(L, (gbMem[rNR21] & 0xC0) >> 6);
4063 lua_setfield(L, -2, "duty");
4064 lua_newtable(L);
4065 lua_pushinteger(L, freqReg);
4066 lua_setfield(L, -2, "frequency");
4067 lua_setfield(L, -2, "regs");
4068 lua_setfield(L, -2, "square2");
4069 // wavememory
4070 lua_newtable(L);
4071 if(sound3On == 0 || soundMasterOn == 0)
4073 lua_pushnumber(L, 0.0);
4074 panpot = 0.5;
4076 else
4078 double envVolume;
4079 if (gba && sound3ForcedOutput != 0)
4080 envVolume = 0.75;
4081 else
4083 double volTable[4] = { 0.0, 1.0, 0.5, 0.25 };
4084 envVolume = volTable[sound3OutputLevel & 3];
4087 if (soundVINLeft && (soundBalance & 0x40) != 0)
4088 leftvolscale = ((soundLevel2 / 7.0) * envVolume);
4089 else
4090 leftvolscale = 0.0;
4091 if (soundVINRight && (soundBalance & 0x04) != 0)
4092 rightvolscale = ((soundLevel1 / 7.0) * envVolume);
4093 else
4094 rightvolscale = 0.0;
4095 if ((leftvolscale + rightvolscale) != 0)
4096 panpot = rightvolscale / (leftvolscale + rightvolscale);
4097 else
4098 panpot = 0.5;
4099 lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
4101 lua_setfield(L, -2, "volume");
4102 lua_pushnumber(L, panpot);
4103 lua_setfield(L, -2, "panpot");
4104 int waveMemSamples = 32;
4105 if (gba)
4107 lua_pushlstring(L, (const char *) &sound3WaveRam[sound3Bank * 0x10], sound3DataSize ? 0x20 : 0x10);
4108 waveMemSamples = sound3DataSize ? 64 : 32;
4110 else
4112 lua_pushlstring(L, (const char *) &gbMem[rWAVE_RAM], 0x10);
4114 lua_setfield(L, -2, "waveform");
4115 freqReg = (((int)(gbMem[rNR34] & 7) << 8) | gbMem[rNR33]);
4116 freq = 2097152.0 / (waveMemSamples * (2048 - freqReg));
4117 lua_pushnumber(L, freq);
4118 lua_setfield(L, -2, "frequency");
4119 lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
4120 lua_setfield(L, -2, "midikey");
4121 lua_newtable(L);
4122 lua_pushinteger(L, freqReg);
4123 lua_setfield(L, -2, "frequency");
4124 lua_setfield(L, -2, "regs");
4125 lua_setfield(L, -2, "wavememory");
4126 // noise
4127 lua_newtable(L);
4128 if(sound4On == 0 || soundMasterOn == 0)
4130 lua_pushnumber(L, 0.0);
4131 panpot = 0.5;
4133 else
4135 double envVolume = sound4EnvelopeVolume / 15.0;
4136 if (soundVINLeft && (soundBalance & 0x80) != 0)
4137 leftvolscale = ((soundLevel2 / 7.0) * envVolume);
4138 else
4139 leftvolscale = 0.0;
4140 if (soundVINRight && (soundBalance & 0x08) != 0)
4141 rightvolscale = ((soundLevel1 / 7.0) * envVolume);
4142 else
4143 rightvolscale = 0.0;
4144 if ((leftvolscale + rightvolscale) != 0)
4145 panpot = rightvolscale / (leftvolscale + rightvolscale);
4146 else
4147 panpot = 0.5;
4148 lua_pushnumber(L, (leftvolscale + rightvolscale) / 2.0);
4150 lua_setfield(L, -2, "volume");
4151 lua_pushnumber(L, panpot);
4152 lua_setfield(L, -2, "panpot");
4153 const int gbNoiseFreqTable[8] = { 1, 2, 4, 6, 8, 10, 12, 14 };
4154 freqReg = gbNoiseFreqTable[gbMem[rNR43] & 7] << (1 + (gbMem[rNR43] >> 4));
4155 lua_pushboolean(L, (gbMem[rNR43] & 8) != 0);
4156 lua_setfield(L, -2, "short");
4157 freq = 1048576.0 / freqReg;
4158 lua_pushnumber(L, freq);
4159 lua_setfield(L, -2, "frequency");
4160 lua_pushnumber(L, (log(freq / 440.0) * 12 / log(2.0)) + 69);
4161 lua_setfield(L, -2, "midikey");
4162 lua_newtable(L);
4163 lua_pushinteger(L, freqReg);
4164 lua_setfield(L, -2, "frequency");
4165 lua_setfield(L, -2, "regs");
4166 lua_setfield(L, -2, "noise");
4168 return 1;
4171 // same as math.random, but uses SFMT instead of C rand()
4172 // FIXME: this function doesn't care multi-instance,
4174 // original math.random either though (Lua 5.1)
4175 static int sfmt_random(lua_State *L)
4177 lua_Number r = (lua_Number) genrand_real2();
4178 switch (lua_gettop(L))
4179 { // check number of arguments
4180 case 0:
4181 { // no arguments
4182 lua_pushnumber(L, r); // Number between 0 and 1
4183 break;
4186 case 1:
4187 { // only upper limit
4188 int u = luaL_checkint(L, 1);
4189 luaL_argcheck(L, 1 <= u, 1, "interval is empty");
4190 lua_pushnumber(L, floor(r * u) + 1); // int between 1 and `u'
4191 break;
4194 case 2:
4195 { // lower and upper limits
4196 int l = luaL_checkint(L, 1);
4197 int u = luaL_checkint(L, 2);
4198 luaL_argcheck(L, l <= u, 2, "interval is empty");
4199 lua_pushnumber(L, floor(r * (u - l + 1)) + l); // int between `l' and `u'
4200 break;
4203 default:
4204 return luaL_error(L, "wrong number of arguments");
4207 return 1;
4210 // same as math.randomseed, but uses SFMT instead of C srand()
4211 // FIXME: this function doesn't care multi-instance,
4213 // original math.randomseed either though (Lua 5.1)
4214 static int sfmt_randomseed(lua_State *L)
4216 init_gen_rand(luaL_checkint(L, 1));
4217 return 0;
4220 // the following bit operations are ported from LuaBitOp 1.0.1,
4221 // because it can handle the sign bit (bit 31) correctly.
4223 /*
4224 ** Lua BitOp -- a bit operations library for Lua 5.1.
4225 ** http://bitop.luajit.org/
4226 **
4227 ** Copyright (C) 2008-2009 Mike Pall. All rights reserved.
4228 **
4229 ** Permission is hereby granted, free of charge, to any person obtaining
4230 ** a copy of this software and associated documentation files (the
4231 ** "Software"), to deal in the Software without restriction, including
4232 ** without limitation the rights to use, copy, modify, merge, publish,
4233 ** distribute, sublicense, and/or sell copies of the Software, and to
4234 ** permit persons to whom the Software is furnished to do so, subject to
4235 ** the following conditions:
4236 **
4237 ** The above copyright notice and this permission notice shall be
4238 ** included in all copies or substantial portions of the Software.
4239 **
4240 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4241 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4242 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
4243 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
4244 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
4245 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
4246 ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4247 **
4248 ** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
4249 */
4251 #ifdef _MSC_VER
4252 /* MSVC is stuck in the last century and doesn't have C99's stdint.h. */
4253 typedef __int32 int32_t;
4254 typedef unsigned __int32 uint32_t;
4255 typedef unsigned __int64 uint64_t;
4256 #else
4257 #include <stdint.h>
4258 #endif
4260 typedef int32_t SBits;
4261 typedef uint32_t UBits;
4263 typedef union
4265 lua_Number n;
4266 #ifdef LUA_NUMBER_DOUBLE
4267 uint64_t b;
4268 #else
4269 UBits b;
4270 #endif
4271 } BitNum;
4273 /* Convert argument to bit type. */
4274 static UBits barg(lua_State *L, int idx)
4276 BitNum bn;
4277 UBits b;
4278 bn.n = lua_tonumber(L, idx);
4279 #if defined(LUA_NUMBER_DOUBLE)
4280 bn.n += 6755399441055744.0; /* 2^52+2^51 */
4281 #ifdef SWAPPED_DOUBLE
4282 b = (UBits)(bn.b >> 32);
4283 #else
4284 b = (UBits)(bn.b & 0xffffffff);
4285 #endif
4286 #elif defined(LUA_NUMBER_INT) || defined(LUA_NUMBER_LONG) || \
4287 defined(LUA_NUMBER_LONGLONG) || defined(LUA_NUMBER_LONG_LONG) || \
4288 defined(LUA_NUMBER_LLONG)
4289 if (sizeof(UBits) == sizeof(lua_Number))
4290 b = bn.b;
4291 else
4292 b = (UBits)(SBits)bn.n;
4293 #elif defined(LUA_NUMBER_FLOAT)
4294 #error "A 'float' lua_Number type is incompatible with this library"
4295 #else
4296 #error "Unknown number type, check LUA_NUMBER_* in luaconf.h"
4297 #endif
4298 if (b == 0 && !lua_isnumber(L, idx))
4299 luaL_typerror(L, idx, "number");
4300 return b;
4303 /* Return bit type. */
4304 #define BRET(b) lua_pushnumber(L, (lua_Number)(SBits)(b)); return 1;
4306 static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) }
4307 static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) }
4309 #define BIT_OP(func, opr) \
4310 static int func(lua_State * L) { int i; UBits b = barg(L, 1); \
4311 for (i = lua_gettop(L); i > 1; i--) \
4312 b opr barg(L, i); BRET(b) }
4313 BIT_OP(bit_band, &= )
4314 BIT_OP(bit_bor, |= )
4315 BIT_OP(bit_bxor, ^= )
4317 #define bshl(b, n) (b << n)
4318 #define bshr(b, n) (b >> n)
4319 #define bsar(b, n) ((SBits)b >> n)
4320 #define brol(b, n) ((b << n) | (b >> (32 - n)))
4321 #define bror(b, n) ((b << (32 - n)) | (b >> n))
4322 #define BIT_SH(func, fn) \
4323 static int func(lua_State * L) { \
4324 UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) }
4325 BIT_SH(bit_lshift, bshl)
4326 BIT_SH(bit_rshift, bshr)
4327 BIT_SH(bit_arshift, bsar)
4328 BIT_SH(bit_rol, brol)
4329 BIT_SH(bit_ror, bror)
4331 static int bit_bswap(lua_State *L)
4333 UBits b = barg(L, 1);
4334 b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24);
4335 BRET(b)
4338 static int bit_tohex(lua_State *L)
4340 UBits b = barg(L, 1);
4341 SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2);
4342 const char *hexdigits = "0123456789abcdef";
4343 char buf[8];
4344 int i;
4345 if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
4346 if (n > 8) n = 8;
4347 for (i = (int)n; --i >= 0; )
4349 buf[i] = hexdigits[b & 15]; b >>= 4;
4351 lua_pushlstring(L, buf, (size_t)n);
4352 return 1;
4355 static const struct luaL_Reg bit_funcs[] = {
4356 { "tobit", bit_tobit },
4357 { "bnot", bit_bnot },
4358 { "band", bit_band },
4359 { "bor", bit_bor },
4360 { "bxor", bit_bxor },
4361 { "lshift", bit_lshift },
4362 { "rshift", bit_rshift },
4363 { "arshift", bit_arshift },
4364 { "rol", bit_rol },
4365 { "ror", bit_ror },
4366 { "bswap", bit_bswap },
4367 { "tohex", bit_tohex },
4368 { NULL, NULL }
4369 };
4371 /* Signed right-shifts are implementation-defined per C89/C99.
4372 ** But the de facto standard are arithmetic right-shifts on two's
4373 ** complement CPUs. This behaviour is required here, so test for it.
4374 */
4375 #define BAD_SAR (bsar(-8, 2) != (SBits) - 2)
4377 bool luabitop_validate(lua_State *L) // originally named as luaopen_bit
4379 UBits b;
4380 lua_pushnumber(L, (lua_Number)1437217655L);
4381 b = barg(L, -1);
4382 if (b != (UBits)1437217655L || BAD_SAR) /* Perform a simple self-test. */
4384 const char *msg = "compiled with incompatible luaconf.h";
4385 #ifdef LUA_NUMBER_DOUBLE
4386 #ifdef WIN32
4387 if (b == (UBits)1610612736L)
4388 msg = "use D3DCREATE_FPU_PRESERVE with DirectX";
4389 #endif
4390 if (b == (UBits)1127743488L)
4391 msg = "not compiled with SWAPPED_DOUBLE";
4392 #endif
4393 if (BAD_SAR)
4394 msg = "arithmetic right-shift broken";
4395 luaL_error(L, "bit library self-test failed (%s)", msg);
4396 return false;
4398 return true;
4401 // LuaBitOp ends here
4403 static int bit_bshift_emulua(lua_State *L)
4405 int shift = luaL_checkinteger(L, 2);
4406 if (shift < 0)
4408 lua_pushinteger(L, -shift);
4409 lua_replace(L, 2);
4410 return bit_lshift(L);
4412 else
4413 return bit_rshift(L);
4416 static int bitbit(lua_State *L)
4418 int rv = 0;
4419 int numArgs = lua_gettop(L);
4420 for (int i = 1; i <= numArgs; i++)
4422 int where = luaL_checkinteger(L, i);
4423 if (where >= 0 && where < 32)
4424 rv |= (1 << where);
4426 lua_settop(L, 0);
4427 BRET(rv);
4430 // The function called periodically to ensure Lua doesn't run amok.
4431 static void VBALuaHookFunction(lua_State *L, lua_Debug *dbg)
4433 if (numTries-- == 0)
4435 int kill = 0;
4437 #if (defined(WIN32) && !defined(SDL))
4438 // Uh oh
4439 theApp.winCheckFullscreen();
4440 systemSoundClearBuffer();
4441 int ret = AfxGetApp()->m_pMainWnd->MessageBox(
4442 "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)",
4443 "Lua Script Gone Nuts?",
4444 MB_YESNO);
4446 if (ret == IDYES)
4448 kill = 1;
4451 #else
4452 fprintf(
4453 stderr,
4454 "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");
4456 char buffer[64];
4457 while (true)
4459 fprintf(stderr, "(y/n): ");
4460 fgets(buffer, sizeof(buffer), stdin);
4461 if (buffer[0] == 'y' || buffer[0] == 'Y')
4463 kill = 1;
4464 break;
4467 if (buffer[0] == 'n' || buffer[0] == 'N')
4468 break;
4470 #endif
4471 if (kill)
4473 luaL_error(L, "Killed by user request.");
4474 VBALuaOnStop();
4477 // else, kill the debug hook.
4478 lua_sethook(L, NULL, 0, 0);
4482 static const struct luaL_reg vbalib[] = {
4483 // {"speedmode", vba_speedmode}, // TODO: NYI
4484 { "frameadvance", vba_frameadvance },
4485 { "pause", vba_pause },
4486 { "framecount", vba_framecount },
4487 { "lagcount", vba_getlagcount },
4488 { "lagged", vba_lagged },
4489 { "emulating", vba_emulating },
4490 { "registerbefore", vba_registerbefore },
4491 { "registerafter", vba_registerafter },
4492 { "registerexit", vba_registerexit },
4493 { "message", vba_message },
4494 { "print", print }, // sure, why not
4495 { NULL, NULL }
4496 };
4498 static const struct luaL_reg memorylib[] = {
4499 { "readbyte", memory_readbyte },
4500 { "readbytesigned", memory_readbytesigned },
4501 { "readword", memory_readword },
4502 { "readwordsigned", memory_readwordsigned },
4503 { "readdword", memory_readdword },
4504 { "readdwordsigned", memory_readdwordsigned },
4505 { "readbyterange", memory_readbyterange },
4506 { "writebyte", memory_writebyte },
4507 { "writeword", memory_writeword },
4508 { "writedword", memory_writedword },
4509 { "getregister", memory_getregister },
4510 { "setregister", memory_setregister },
4511 { "gbromreadbyte", memory_gbromreadbyte },
4512 { "gbromreadbytesigned", memory_gbromreadbytesigned },
4513 { "gbromreadword", memory_gbromreadword },
4514 { "gbromreadwordsigned", memory_gbromreadwordsigned },
4515 { "gbromreaddword", memory_gbromreaddword },
4516 { "gbromreaddwordsigned", memory_gbromreaddwordsigned },
4517 { "gbromreadbyterange", memory_gbromreadbyterange },
4519 // alternate naming scheme for word and double-word and unsigned
4520 { "readbyteunsigned", memory_readbyte },
4521 { "readwordunsigned", memory_readword },
4522 { "readdwordunsigned", memory_readdword },
4523 { "readshort", memory_readword },
4524 { "readshortunsigned", memory_readword },
4525 { "readshortsigned", memory_readwordsigned },
4526 { "readlong", memory_readdword },
4527 { "readlongunsigned", memory_readdword },
4528 { "readlongsigned", memory_readdwordsigned },
4529 { "writeshort", memory_writeword },
4530 { "writelong", memory_writedword },
4531 { "gbromreadbyteunsigned", memory_gbromreadbyte },
4532 { "gbromreadwordunsigned", memory_gbromreadword },
4533 { "gbromreaddwordunsigned", memory_gbromreaddword },
4534 { "gbromreadshort", memory_gbromreadword },
4535 { "gbromreadshortunsigned", memory_gbromreadword },
4536 { "gbromreadshortsigned", memory_gbromreadwordsigned },
4537 { "gbromreadlong", memory_gbromreaddword },
4538 { "gbromreadlongunsigned", memory_gbromreaddword },
4539 { "gbromreadlongsigned", memory_gbromreaddwordsigned },
4541 // memory hooks
4542 { "registerwrite", memory_registerwrite },
4543 //{"registerread", memory_registerread},
4544 { "registerexec", memory_registerexec },
4545 // alternate names
4546 { "register", memory_registerwrite },
4547 { "registerrun", memory_registerexec },
4548 { "registerexecute", memory_registerexec },
4550 { NULL, NULL }
4551 };
4553 static const struct luaL_reg joypadlib[] = {
4554 { "get", joypad_get },
4555 { "getdown", joypad_getdown },
4556 { "getup", joypad_getup },
4557 { "set", joypad_set },
4559 // alternative names
4560 { "read", joypad_get },
4561 { "write", joypad_set },
4562 { "readdown", joypad_getdown },
4563 { "readup", joypad_getup },
4564 { NULL, NULL }
4565 };
4567 static const struct luaL_reg savestatelib[] = {
4568 { "create", savestate_create },
4569 { "save", savestate_save },
4570 { "load", savestate_load },
4572 { NULL, NULL }
4573 };
4575 static const struct luaL_reg movielib[] = {
4576 { "active", movie_isactive },
4577 { "recording", movie_isrecording },
4578 { "playing", movie_isplaying },
4579 { "mode", movie_getmode },
4581 { "length", movie_getlength },
4582 { "author", movie_getauthor },
4583 { "name", movie_getfilename },
4584 { "rerecordcount", movie_rerecordcount },
4585 { "setrerecordcount", movie_setrerecordcount },
4587 { "rerecordcounting", movie_rerecordcounting },
4588 { "framecount", vba_framecount }, // for those familiar with
4589 // other emulators that have
4590 // movie.framecount()
4591 // instead of
4592 // emulatorname.framecount()
4594 { "stop", movie_stop },
4596 // alternative names
4597 { "close", movie_stop },
4598 { "getauthor", movie_getauthor },
4599 { "getname", movie_getfilename },
4600 { NULL, NULL }
4601 };
4603 static const struct luaL_reg guilib[] = {
4604 { "register", gui_register },
4605 { "text", gui_text },
4606 { "box", gui_drawbox },
4607 { "line", gui_drawline },
4608 { "pixel", gui_drawpixel },
4609 { "opacity", gui_setopacity },
4610 { "transparency", gui_transparency },
4611 { "popup", gui_popup },
4612 { "parsecolor", gui_parsecolor },
4613 { "gdscreenshot", gui_gdscreenshot },
4614 { "gdoverlay", gui_gdoverlay },
4615 { "getpixel", gui_getpixel },
4617 // alternative names
4618 { "drawtext", gui_text },
4619 { "drawbox", gui_drawbox },
4620 { "drawline", gui_drawline },
4621 { "drawpixel", gui_drawpixel },
4622 { "setpixel", gui_drawpixel },
4623 { "writepixel", gui_drawpixel },
4624 { "rect", gui_drawbox },
4625 { "drawrect", gui_drawbox },
4626 { "drawimage", gui_gdoverlay },
4627 { "image", gui_gdoverlay },
4628 { "readpixel", gui_getpixel },
4629 { NULL, NULL }
4630 };
4632 static const struct luaL_reg inputlib[] = {
4633 { "get", input_getcurrentinputstatus },
4635 // alternative names
4636 { "read", input_getcurrentinputstatus },
4637 { NULL, NULL }
4638 };
4640 static const struct luaL_reg soundlib[] = {
4641 { "get", sound_get },
4643 // alternative names
4644 { NULL, NULL }
4645 };
4647 // gocha: since vba dumps avi so badly,
4648 // I add avilib as a workaround for enhanced video encoding.
4649 static const struct luaL_reg avilib[] = {
4650 { "framecount", avi_framecount },
4651 { "pause", avi_pause },
4652 { "resume", avi_resume },
4653 { NULL, NULL }
4654 };
4656 void CallExitFunction(void)
4658 if (!LUA)
4659 return;
4661 lua_settop(LUA, 0);
4662 lua_getfield(LUA, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
4664 int errorcode = 0;
4665 if (lua_isfunction(LUA, -1))
4667 errorcode = lua_pcall(LUA, 0, 0, 0);
4670 if (errorcode)
4671 HandleCallbackError(LUA);
4674 void VBALuaFrameBoundary(void)
4676 // printf("Lua Frame\n");
4678 lua_joypads_used = 0;
4680 // HA!
4681 if (!LUA || !luaRunning)
4682 return;
4684 // Our function needs calling
4685 lua_settop(LUA, 0);
4686 lua_getfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
4688 lua_State *thread = lua_tothread(LUA, 1);
4690 // Lua calling C must know that we're busy inside a frame boundary
4691 frameBoundary = true;
4692 frameAdvanceWaiting = false;
4694 numTries = 1000;
4696 int result = lua_resume(thread, 0);
4698 if (result == LUA_YIELD)
4700 // Okay, we're fine with that.
4702 else if (result != 0)
4704 // Done execution by bad causes
4705 VBALuaOnStop();
4706 lua_pushnil(LUA);
4707 lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
4708 lua_pushnil(LUA);
4709 lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
4711 // Error?
4712 //#if (defined(WIN32) && !defined(SDL))
4713 // info_print(info_uid, lua_tostring(thread, -1)); //Clear_Sound_Buffer();
4714 // AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(thread, -1), "Lua run error", MB_OK | MB_ICONSTOP);
4715 //#else
4716 // fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(thread, -1));
4717 //#endif
4718 printerror(thread, -1);
4720 else
4722 VBALuaOnStop();
4723 printf("Script died of natural causes.\n");
4726 // Past here, VBA actually runs, so any Lua code is called mid-frame. We must
4727 // not do anything too stupid, so let ourselves know.
4728 frameBoundary = false;
4730 if (!frameAdvanceWaiting)
4732 VBALuaOnStop();
4736 /**
4737 * Loads and runs the given Lua script.
4738 * The emulator MUST be paused for this function to be
4739 * called. Otherwise, all frame boundary assumptions go out the window.
4741 * Returns true on success, false on failure.
4742 */
4743 int VBALoadLuaCode(const char *filename)
4745 static bool sfmtInitialized = false;
4746 if (!sfmtInitialized)
4748 init_gen_rand((unsigned)time(NULL));
4749 sfmtInitialized = true;
4752 if (filename != luaScriptName)
4754 if (luaScriptName)
4755 free(luaScriptName);
4756 luaScriptName = strdup(filename);
4759 //stop any lua we might already have had running
4760 VBALuaStop();
4762 // Set current directory from filename (for dofile)
4763 char dir[_MAX_PATH];
4764 char *slash, *backslash;
4765 strcpy(dir, filename);
4766 slash = strrchr(dir, '/');
4767 backslash = strrchr(dir, '\\');
4768 if (!slash || (backslash && backslash < slash))
4769 slash = backslash;
4770 if (slash)
4772 slash[1] = '\0'; // keep slash itself for some reasons
4773 chdir(dir);
4776 if (!LUA)
4778 LUA = lua_open();
4779 luaL_openlibs(LUA);
4781 luaL_register(LUA, "emu", vbalib); // added for better cross-emulator compatibility
4782 luaL_register(LUA, "vba", vbalib); // kept for backward compatibility
4783 luaL_register(LUA, "memory", memorylib);
4784 luaL_register(LUA, "joypad", joypadlib);
4785 luaL_register(LUA, "savestate", savestatelib);
4786 luaL_register(LUA, "movie", movielib);
4787 luaL_register(LUA, "gui", guilib);
4788 luaL_register(LUA, "input", inputlib);
4789 luaL_register(LUA, "sound", soundlib);
4790 luaL_register(LUA, "bit", bit_funcs); // LuaBitOp library
4791 luaL_register(LUA, "avi", avilib); // workaround for enhanced video encoding
4792 lua_settop(LUA, 0); // clean the stack, because each call to luaL_register leaves a table on top
4794 // register a few utility functions outside of libraries (in the global namespace)
4795 lua_register(LUA, "print", print);
4796 lua_register(LUA, "tostring", tostring);
4797 lua_register(LUA, "addressof", addressof);
4798 lua_register(LUA, "copytable", copytable);
4800 // old bit operation functions
4801 lua_register(LUA, "AND", bit_band);
4802 lua_register(LUA, "OR", bit_bor);
4803 lua_register(LUA, "XOR", bit_bxor);
4804 lua_register(LUA, "SHIFT", bit_bshift_emulua);
4805 lua_register(LUA, "BIT", bitbit);
4807 luabitop_validate(LUA);
4809 lua_pushstring(LUA, "math");
4810 lua_gettable(LUA, LUA_GLOBALSINDEX);
4811 lua_pushcfunction(LUA, sfmt_random);
4812 lua_setfield(LUA, -2, "random");
4813 lua_pushcfunction(LUA, sfmt_randomseed);
4814 lua_setfield(LUA, -2, "randomseed");
4815 lua_settop(LUA, 0);
4817 // push arrays for storing hook functions in
4818 for (int i = 0; i < LUAMEMHOOK_COUNT; i++)
4820 lua_newtable(LUA);
4821 lua_setfield(LUA, LUA_REGISTRYINDEX, luaMemHookTypeStrings[i]);
4825 // We make our thread NOW because we want it at the bottom of the stack.
4826 // If all goes wrong, we let the garbage collector remove it.
4827 lua_State *thread = lua_newthread(LUA);
4829 // Load the data
4830 int result = luaL_loadfile(LUA, filename);
4832 if (result)
4834 //#if (defined(WIN32) && !defined(SDL))
4835 // info_print(info_uid, lua_tostring(LUA, -1)); //Clear_Sound_Buffer();
4836 // AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua load error", MB_OK | MB_ICONSTOP);
4837 //#else
4838 // fprintf(stderr, "Failed to compile file: %s\n", lua_tostring(LUA, -1));
4839 //#endif
4840 printerror(LUA, -1);
4842 // Wipe the stack. Our thread
4843 lua_settop(LUA, 0);
4844 return 0; // Oh shit.
4847 // Get our function into it
4848 lua_xmove(LUA, thread, 1);
4850 // Save the thread to the registry. This is why I make the thread FIRST.
4851 lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
4853 // Initialize settings
4854 luaRunning = true;
4855 skipRerecords = false;
4856 numMemHooks = 0;
4857 transparencyModifier = 255; // opaque
4858 lua_joypads_used = 0; // not used
4859 //wasPaused = systemIsPaused();
4860 //systemSetPause(false);
4862 // Set up our protection hook to be executed once every 10,000 bytecode instructions.
4863 lua_sethook(thread, VBALuaHookFunction, LUA_MASKCOUNT, 10000);
4865 #ifdef WIN32
4866 info_print = PrintToWindowConsole;
4867 info_onstart = WinLuaOnStart;
4868 info_onstop = WinLuaOnStop;
4869 if (!LuaConsoleHWnd)
4870 LuaConsoleHWnd = CreateDialog(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDD_LUA),
4871 AfxGetMainWnd()->GetSafeHwnd(), (DLGPROC) DlgLuaScriptDialog);
4872 info_uid = (int)LuaConsoleHWnd;
4873 #else
4874 info_print = NULL;
4875 info_onstart = NULL;
4876 info_onstop = NULL;
4877 #endif
4878 if (info_onstart)
4879 info_onstart(info_uid);
4881 // And run it right now. :)
4882 VBALuaFrameBoundary();
4883 systemRenderFrame();
4885 // We're done.
4886 return 1;
4889 /**
4890 * Equivalent to repeating the last VBALoadLuaCode() call.
4891 */
4892 int VBAReloadLuaCode(void)
4894 if (!luaScriptName)
4896 systemScreenMessage("There's no script to reload.");
4897 return 0;
4899 else
4900 return VBALoadLuaCode(luaScriptName);
4903 /**
4904 * Terminates a running Lua script by killing the whole Lua engine.
4906 * Always safe to call, except from within a lua call itself (duh).
4908 */
4909 void VBALuaStop(void)
4911 //already killed
4912 if (!LUA)
4913 return;
4915 //execute the user's shutdown callbacks
4916 CallExitFunction();
4918 /*info.*/ numMemHooks = 0;
4919 for (int i = 0; i < LUAMEMHOOK_COUNT; i++)
4920 CalculateMemHookRegions((LuaMemHookType)i);
4922 //sometimes iup uninitializes com
4923 //MBG TODO - test whether this is really necessary. i dont think it is
4924 #if (defined(WIN32) && !defined(SDL))
4925 CoInitialize(0);
4926 #endif
4928 if (info_onstop)
4929 info_onstop(info_uid);
4931 //lua_gc(LUA,LUA_GCCOLLECT,0);
4932 lua_close(LUA); // this invokes our garbage collectors for us
4933 LUA = NULL;
4934 VBALuaOnStop();
4937 /**
4938 * Returns true if there is a Lua script running.
4940 */
4941 int VBALuaRunning(void)
4943 // FIXME: return false when no callback functions are registered.
4944 return (int) (LUA != NULL); // should return true if callback functions are active.
4947 /**
4948 * Returns true if Lua would like to steal the given joypad control.
4950 * Range is 0 through 3
4951 */
4952 int VBALuaUsingJoypad(int which)
4954 if (which < 0 || which > 3)
4955 which = systemGetDefaultJoypad();
4956 return lua_joypads_used & (1 << which);
4959 /**
4960 * Reads the buttons Lua is feeding for the given joypad, in the same
4961 * format as the OS-specific code.
4963 * <del>This function must not be called more than once per frame. </del>Ideally exactly once
4964 * per frame (if VBALuaUsingJoypad says it's safe to do so)
4965 */
4966 int VBALuaReadJoypad(int which)
4968 if (which < 0 || which > 3)
4969 which = systemGetDefaultJoypad();
4971 //lua_joypads_used &= ~(1 << which);
4972 return lua_joypads[which];
4975 /**
4976 * If this function returns true, the movie code should NOT increment
4977 * the rerecord count for a load-state.
4979 * This function will not return true if a script is not running.
4980 */
4981 bool8 VBALuaRerecordCountSkip(void)
4983 // FIXME: return true if (there are any active callback functions && skipRerecords)
4984 return LUA && luaRunning && skipRerecords;
4987 /**
4988 * Given a screen with the indicated resolution,
4989 * draw the current GUI onto it.
4990 */
4991 void VBALuaGui(uint8 *screen, int ppl, int width, int height)
4993 if (!LUA /* || !luaRunning*/)
4994 return;
4996 // First, check if we're being called by anybody
4997 lua_getfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
4999 if (lua_isfunction(LUA, -1))
5001 // We call it now
5002 numTries = 1000;
5004 int ret = lua_pcall(LUA, 0, 0, 0);
5005 if (ret != 0)
5007 // This is grounds for trashing the function
5008 // Note: This must be done before the messagebox pops up,
5009 // otherwise the messagebox will cause a paint event which causes a weird
5010 // infinite call sequence that makes Snes9x silently exit with error code 3,
5011 // if a Lua GUI function crashes. (nitsuja)
5012 lua_pushnil(LUA);
5013 lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
5015 //#if (defined(WIN32) && !defined(SDL))
5016 // info_print(info_uid, lua_tostring(LUA, -1)); //AfxGetApp()->m_pMainWnd->MessageBox(lua_tostring(LUA, -1), "Lua Error
5017 // in GUI function", MB_OK);
5018 //#else
5019 // fprintf(stderr, "Lua error in gui.register function: %s\n", lua_tostring(LUA, -1));
5020 //#endif
5021 printerror(LUA, -1);
5025 // And wreak the stack
5026 lua_settop(LUA, 0);
5028 if (!gui_used)
5029 return;
5031 gui_used = false;
5033 int x, y;
5035 //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3;
5036 int pitch = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4);
5038 if (width > LUA_SCREEN_WIDTH)
5039 width = LUA_SCREEN_WIDTH;
5040 if (height > LUA_SCREEN_HEIGHT)
5041 height = LUA_SCREEN_HEIGHT;
5043 GetColorFunc getColor;
5044 SetColorFunc setColor;
5045 getColorIOFunc(systemColorDepth, &getColor, &setColor);
5047 for (y = 0; y < height; y++)
5049 uint8 *scr = &screen[y * pitch];
5050 for (x = 0; x < width; x++, scr += systemColorDepth / 8)
5052 const uint8 gui_alpha = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 3];
5053 if (gui_alpha == 0)
5055 // do nothing
5056 continue;
5059 const uint8 gui_red = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 2];
5060 const uint8 gui_green = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 1];
5061 const uint8 gui_blue = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4];
5062 int red, green, blue;
5064 if (gui_alpha == 255)
5066 // direct copy
5067 red = gui_red;
5068 green = gui_green;
5069 blue = gui_blue;
5071 else
5073 // alpha-blending
5074 uint8 scr_red, scr_green, scr_blue;
5075 getColor(scr, &scr_red, &scr_green, &scr_blue);
5076 red = (((int)gui_red - scr_red) * gui_alpha / 255 + scr_red) & 255;
5077 green = (((int)gui_green - scr_green) * gui_alpha / 255 + scr_green) & 255;
5078 blue = (((int)gui_blue - scr_blue) * gui_alpha / 255 + scr_blue) & 255;
5081 setColor(scr, (uint8) red, (uint8) green, (uint8) blue);
5085 return;
5088 void VBALuaClearGui(void)
5090 gui_used = false;
5093 lua_State *VBAGetLuaState()
5095 return LUA;
5098 char *VBAGetLuaScriptName()
5100 return luaScriptName;