comparison src/common/lua-engine.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children bf9169ad4222
comparison
equal deleted inserted replaced
0:8ced16adf2e1 1:f9f4f1b99eed
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>
9
10 #include <vector>
11 #include <map>
12 #include <string>
13 #include <algorithm>
14
15 using namespace std;
16
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
33
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"
42
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
49
50 extern "C"
51 {
52 #include "../lua/src/lua.h"
53 #include "../lua/src/lauxlib.h"
54 #include "../lua/src/lualib.h"
55 #include "../lua/src/lstate.h"
56 }
57 #include "vbalua.h"
58
59 #include "../SFMT/SFMT.c"
60
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;
65
66 #ifndef countof
67 #define countof(a) (sizeof(a) / sizeof(a[0]))
68 #endif
69
70 static lua_State *LUA;
71
72 // Are we running any code right now?
73 static char *luaScriptName = NULL;
74
75 // Are we running any code right now?
76 static bool8 luaRunning = false;
77
78 // True at the frame boundary, false otherwise.
79 static bool8 frameBoundary = false;
80
81 // The execution speed we're running at.
82 static enum { SPEED_NORMAL, SPEED_NOTHROTTLE, SPEED_TURBO, SPEED_MAXIMUM } speedmode = SPEED_NORMAL;
83
84 // Rerecord count skip mode
85 static bool8 skipRerecords = false;
86
87 // Used by the registry to find our functions
88 static const char *frameAdvanceThread = "VBA.FrameAdvance";
89 static const char *guiCallbackTable = "VBA.GUI";
90
91 // True if there's a thread waiting to run after a run of frame-advance.
92 static bool8 frameAdvanceWaiting = false;
93
94 // We save our pause status in the case of a natural death.
95 //static bool8 wasPaused = false;
96
97 // Transparency strength. 255=opaque, 0=so transparent it's invisible
98 static int transparencyModifier = 255;
99
100 // Our joypads.
101 static uint32 lua_joypads[4];
102 static uint8 lua_joypads_used = 0;
103
104 static bool8 gui_used = false;
105 static uint8 *gui_data = NULL; // BGRA
106
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;
111
112 // number of registered memory functions (1 per hooked byte)
113 static unsigned int numMemHooks;
114
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 };
119
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
128
129 static const char *luaCallIDStrings[] =
130 {
131 "CALL_BEFOREEMULATION",
132 "CALL_AFTEREMULATION",
133 "CALL_BEFOREEXIT"
134 };
135
136 //make sure we have the right number of strings
137 CTASSERT(sizeof(luaCallIDStrings) / sizeof(*luaCallIDStrings) == LUACALL_COUNT)
138
139 static const char *luaMemHookTypeStrings [] =
140 {
141 "MEMHOOK_WRITE",
142 "MEMHOOK_READ",
143 "MEMHOOK_EXEC",
144
145 "MEMHOOK_WRITE_SUB",
146 "MEMHOOK_READ_SUB",
147 "MEMHOOK_EXEC_SUB",
148 };
149
150 //make sure we have the right number of strings
151 CTASSERT(sizeof(luaMemHookTypeStrings) / sizeof(*luaMemHookTypeStrings) == LUAMEMHOOK_COUNT)
152
153 static char *rawToCString(lua_State * L, int idx = 0);
154 static const char *toCString(lua_State *L, int idx = 0);
155
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 }
161
162 static inline void CPUWriteByteQuick(u32 addr, u8 b)
163 {
164 ::map[addr >> 24].address[addr & ::map[addr >> 24].mask] = b;
165 }
166
167 static inline u16 CPUReadHalfWordQuick(u32 addr)
168 {
169 return *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]);
170 }
171
172 static inline void CPUWriteHalfWordQuick(u32 addr, u16 b)
173 {
174 *((u16 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b;
175 }
176
177 static inline u32 CPUReadMemoryQuick(u32 addr)
178 {
179 return *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]);
180 }
181
182 static inline void CPUWriteMemoryQuick(u32 addr, u32 b)
183 {
184 *((u32 *) &::map[addr >> 24].address[addr & ::map[addr >> 24].mask]) = b;
185 }
186
187 // GB
188 static inline u8 gbReadMemoryQuick8(u16 addr)
189 {
190 return gbReadMemoryQuick(addr);
191 }
192
193 static inline void gbWriteMemoryQuick8(u16 addr, u8 b)
194 {
195 gbWriteMemoryQuick(addr, b);
196 }
197
198 static inline u16 gbReadMemoryQuick16(u16 addr)
199 {
200 return (gbReadMemoryQuick(addr + 1) << 8) | gbReadMemoryQuick(addr);
201 }
202
203 static inline void gbWriteMemoryQuick16(u16 addr, u16 b)
204 {
205 gbWriteMemoryQuick(addr, b & 0xff);
206 gbWriteMemoryQuick(addr + 1, (b >> 8) & 0xff);
207 }
208
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 }
216
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 }
224
225 static inline u8 gbReadROMQuick8(u32 addr)
226 {
227 return gbReadROMQuick(addr & gbRomSizeMask);
228 }
229
230 static inline u8 gbReadROMQuick16(u32 addr)
231 {
232 return (gbReadROMQuick(addr+1 & gbRomSizeMask) << 8) | gbReadROMQuick(addr & gbRomSizeMask);
233 }
234
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 }
242
243 typedef void (*GetColorFunc)(const uint8 *, uint8 *, uint8 *, uint8 *);
244 typedef void (*SetColorFunc)(uint8 *, uint8, uint8, uint8);
245
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 }
253
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 }
261
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 }
269
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 }
279
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 }
287
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 }
297
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 }
324
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 }
336
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;
347
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;
357
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;
367
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 }
381
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,
389
390 // maximum renders no frames
391 static int vba_speedmode(lua_State *L)
392 {
393 const char *mode = luaL_checkstring(L, 1);
394
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);
413
414 //printf("new speed mode: %d\n", speedmode);
415 return 0;
416 }
417
418 // vba.frameadvnace()
419 //
420 // Executes a frame advance. Occurs by yielding the coroutine, then re-running
421
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");
428
429 frameAdvanceWaiting = true;
430
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);
435
436 // It's actually rather disappointing...
437 }
438
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
443
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;
449
450 // Return control if we're midway through a frame. We can't pause here.
451 if (frameAdvanceWaiting)
452 {
453 return 0;
454 }
455
456 // If it's on a frame boundary, we also yield.
457 frameAdvanceWaiting = true;
458 return lua_yield(L, 0);
459 }
460
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]);
469
470 //StopScriptIfFinished(luaStateToUIDMap[L]);
471 return 1;
472 }
473
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]);
482
483 //StopScriptIfFinished(luaStateToUIDMap[L]);
484 return 1;
485 }
486
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]);
495
496 //StopScriptIfFinished(luaStateToUIDMap[L]);
497 return 1;
498 }
499
500 static inline bool isalphaorunderscore(char c)
501 {
502 return isalpha(c) || c == '_';
503 }
504
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)
510
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;
517
518 const char *str = ptr; // for debugging
519
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 }
536
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 }
585
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;
600
601 APPENDPRINT "{" END
602
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
630
631 toCStringConverter(L, keyIndex, ptr, remaining);
632 // key
633
634 if (invalidLuaIdentifier)
635 if (keyIsString)
636 APPENDPRINT "']=" END
637 else
638 APPENDPRINT "]=" END
639 else
640 APPENDPRINT "=" END
641 }
642
643 bool valueIsString = (lua_type(L, valueIndex) == LUA_TSTRING);
644 if (valueIsString)
645 APPENDPRINT "'" END
646
647 toCStringConverter(L, valueIndex, ptr, remaining); // value
648
649 if (valueIsString)
650 APPENDPRINT "'" END
651
652 lua_pop(L, 1);
653
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 }
666
667 if (usedMeta)
668 {
669 s_metacallStack.pop_back();
670 lua_pop(L, 1);
671 }
672 }
673
674 static const int s_tempStrMaxLen = 64 * 1024;
675 static char s_tempStr [s_tempStrMaxLen];
676
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);
681
682 char *ptr = s_tempStr;
683 *ptr = 0;
684
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 }
692
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)
704
705 return s_tempStr;
706 }
707 #undef APPENDPRINT
708 #undef END
709
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 }
721
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 }
758
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);
763
764 int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread];
765 //LuaContextInfo& info = GetCurrentInfo();
766
767 if (info_print)
768 info_print(uid, str);
769 else
770 puts(str);
771
772 //worry(L, 100);
773 return 0;
774 }
775
776 static int printerror(lua_State *L, int idx)
777 {
778 lua_checkstack(L, lua_gettop(L) + 4);
779
780 if (idx < 0)
781 idx = lua_gettop(L) + 1 + idx;
782
783 const char *str = rawToCString(L, idx);
784
785 int uid = info_uid; //luaStateToUIDMap[L->l_G->mainthread];
786 //LuaContextInfo& info = GetCurrentInfo();
787
788 if (info_print)
789 info_print(uid, str);
790 else
791 fputs(str, stderr);
792
793 //worry(L, 100);
794 return 0;
795 }
796
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);
804
805 return 0;
806 }
807
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 }
828
829 lua_createtable(L, lua_objlen(L, 1), 0);
830 int copyIndex = lua_gettop(L);
831
832 lua_pushnil(L); // first key
833 int keyIndex = lua_gettop(L);
834 int valueIndex = keyIndex + 1;
835
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 }
843
844 // copy the reference to the metatable as well, if any
845 if (lua_getmetatable(L, origIndex))
846 lua_setmetatable(L, copyIndex);
847
848 return 1; // return the new table
849 }
850
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 }
861
862 struct registerPointerMap
863 {
864 const char * registerName;
865 unsigned int *pointer;
866 int dataSize;
867 };
868
869 #define RPM_ENTRY(name, var) \
870 { name, (unsigned int *)&var, sizeof(var) \
871 } \
872 ,
873
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;
881
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 };
919
920 struct cpuToRegisterMap
921 {
922 const char *cpuName;
923 registerPointerMap *rpmap;
924 }
925 cpuToRegisterMaps [] =
926 {
927 { "", regPointerMap },
928 };
929
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 }
967
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;
1000 }
1001 }
1002 return 0;
1003 }
1004
1005 void HandleCallbackError(lua_State *L)
1006 {
1007 if (L->errfunc || L->errorJmp)
1008 luaL_error(L, "%s", lua_tostring(L, -1));
1009 else
1010 {
1011 lua_pushnil(LUA);
1012 lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
1013
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();
1023 }
1024 }
1025
1026 void CallRegisteredLuaFunctions(LuaCallID calltype)
1027 {
1028 assert((unsigned int)calltype < (unsigned int)LUACALL_COUNT);
1029
1030 const char *idstring = luaCallIDStrings[calltype];
1031
1032 if (!LUA)
1033 return;
1034
1035 lua_settop(LUA, 0);
1036 lua_getfield(LUA, LUA_REGISTRYINDEX, idstring);
1037
1038 int errorcode = 0;
1039 if (lua_isfunction(LUA, -1))
1040 {
1041 errorcode = lua_pcall(LUA, 0, 0, 0);
1042 if (errorcode)
1043 HandleCallbackError(LUA);
1044 }
1045 else
1046 {
1047 lua_pop(LUA, 1);
1048 }
1049 }
1050
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
1059 {
1060 template<unsigned int maxGap>
1061 struct Region
1062 {
1063 struct Island
1064 {
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;
1070
1071 void Calculate(const std::vector<unsigned int> &bytes)
1072 {
1073 islands. clear();
1074
1075 unsigned int lastEnd = ~0;
1076
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)
1080 {
1081 unsigned int addr = *iter;
1082 if (addr < lastEnd || addr > lastEnd + (long long)maxGap)
1083 {
1084 islands. push_back(Island());
1085 islands. back().start = addr;
1086 }
1087 islands.back(). end = addr + 1;
1088 lastEnd = addr + 1;
1089 }
1090 }
1091
1092 bool Contains(unsigned int address, int size) const
1093 {
1094 for (size_t i = 0; i != islands.size(); ++i)
1095 {
1096 if (islands[i].Contains(address, size))
1097 return true;
1098 }
1099 return false;
1100 }
1101 };
1102
1103 Region<0xFFFFFFFF> broad;
1104 Region<0x1000> mid;
1105 Region<0> narrow;
1106
1107 void Calculate(std::vector<unsigned int> &bytes)
1108 {
1109 std:: sort(bytes.begin(), bytes.end());
1110
1111 broad. Calculate(bytes);
1112 mid. Calculate(bytes);
1113 narrow. Calculate(bytes);
1114 }
1115
1116 TieredRegion()
1117 {
1118 std::vector <unsigned int> temp;
1119 Calculate(temp);
1120 }
1121
1122 __forceinline int NotEmpty()
1123 {
1124 return broad.islands.size();
1125 }
1126
1127 // note: it is illegal to call this if NotEmpty() returns 0
1128 __forceinline bool Contains(unsigned int address, int size)
1129 {
1130 return broad.islands[0].Contains(address, size) &&
1131 mid.Contains(address, size) &&
1132 narrow.Contains(address, size);
1133 }
1134 };
1135 TieredRegion hookedRegions [LUAMEMHOOK_COUNT];
1136
1137 static void CalculateMemHookRegions(LuaMemHookType hookType)
1138 {
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)
1146 {
1147 lua_State *L = LUA /*info.L*/;
1148 if (L)
1149 {
1150 lua_settop(L, 0);
1151 lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
1152 lua_pushnil(L);
1153 while (lua_next(L, -2))
1154 {
1155 if (lua_isfunction(L, -1))
1156 {
1157 unsigned int addr = lua_tointeger(L, -2);
1158 hookedBytes.push_back(addr);
1159 }
1160 lua_pop(L, 1);
1161 }
1162 lua_settop(L, 0);
1163 }
1164 }
1165 // ++iter;
1166 // }
1167 hookedRegions[hookType].Calculate(hookedBytes);
1168 }
1169
1170 static void CallRegisteredLuaMemHook_LuaMatch(unsigned int address, int size, unsigned int value, LuaMemHookType hookType)
1171 {
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)
1178 {
1179 lua_State *L = LUA /*info.L*/;
1180 if (L /* && !info.panic*/)
1181 {
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++)
1189 {
1190 lua_rawgeti(L, -1, i);
1191 if (lua_isfunction(L, -1))
1192 {
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)
1202 {
1203 HandleCallbackError(L);
1204 //int uid = iter->first;
1205 //HandleCallbackError(L,info,uid,true);
1206 }
1207 break;
1208 }
1209 else
1210 {
1211 lua_pop(L, 1);
1212 }
1213 }
1214 lua_settop(L, 0);
1215 }
1216 }
1217 // ++iter;
1218 // }
1219 }
1220
1221 void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType)
1222 {
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())
1230 {
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
1236 }
1237 }
1238
1239 static int memory_registerHook(lua_State *L, LuaMemHookType hookType, int defaultSize)
1240 {
1241 // get first argument: address
1242 unsigned int addr = luaL_checkinteger(L, 1);
1243 //if((addr & ~0xFFFFFF) == ~0xFFFFFF)
1244 // addr &= 0xFFFFFF;
1245
1246 // get optional second argument: size
1247 int size = defaultSize;
1248 int funcIdx = 2;
1249 if (lua_isnumber(L, 2))
1250 {
1251 size = luaL_checkinteger(L, 2);
1252 if (size < 0)
1253 {
1254 size = -size;
1255 addr -= size;
1256 }
1257 funcIdx++;
1258 }
1259
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);
1265
1266 // get the address-to-callback table for this hook type of the current script
1267 lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
1268
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++)
1273 {
1274 lua_rawgeti(L, -1, i);
1275 if (lua_isfunction(L, -1))
1276 numFuncsBefore++;
1277 lua_pop(L, 1);
1278 }
1279
1280 // put the callback function in the address slots
1281 for (unsigned int i = addr; i != addr + size; i++)
1282 {
1283 lua_pushvalue(L, -2);
1284 lua_rawseti(L, -2, i);
1285 }
1286
1287 // adjust the count of active hooks
1288 //LuaContextInfo& info = GetCurrentInfo();
1289 /*info.*/ numMemHooks += numFuncsAfter - numFuncsBefore;
1290
1291 // re-cache regions of hooked memory across all scripts
1292 CalculateMemHookRegions(hookType);
1293
1294 //StopScriptIfFinished(luaStateToUIDMap[L]);
1295 return 0;
1296 }
1297
1298 LuaMemHookType MatchHookTypeToCPU(lua_State *L, LuaMemHookType hookType)
1299 {
1300 int cpuID = 0;
1301
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;
1307
1308 if (cpunameIndex)
1309 {
1310 const char *cpuName = lua_tostring(L, cpunameIndex);
1311 if (!stricmp(cpuName, "sub"))
1312 cpuID = 1;
1313 lua_remove(L, cpunameIndex);
1314 }
1315
1316 switch (cpuID)
1317 {
1318 case 0:
1319 return hookType;
1320
1321 case 1:
1322 switch (hookType)
1323 {
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;
1330 }
1331 }
1332 return hookType;
1333 }
1334
1335 static int memory_registerwrite(lua_State *L)
1336 {
1337 return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_WRITE), 1);
1338 }
1339
1340 static int memory_registerread(lua_State *L)
1341 {
1342 return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_READ), 1);
1343 }
1344
1345 static int memory_registerexec(lua_State *L)
1346 {
1347 return memory_registerHook(L, MatchHookTypeToCPU(L, LUAMEMHOOK_EXEC), 1);
1348 }
1349
1350 //int vba.lagcount
1351 //
1352
1353 //Returns the lagcounter variable
1354 static int vba_getlagcount(lua_State *L)
1355 {
1356 lua_pushinteger(L, systemCounters.lagCount);
1357 return 1;
1358 }
1359
1360 //int vba.lagged
1361 //
1362 //Returns true if the current frame is a lag frame
1363 static int vba_lagged(lua_State *L)
1364 {
1365 lua_pushboolean(L, systemCounters.laggedLast);
1366 return 1;
1367 }
1368
1369 // boolean vba.emulating()
1370 int vba_emulating(lua_State *L)
1371 {
1372 lua_pushboolean(L, systemIsEmulating());
1373 return 1;
1374 }
1375
1376 int movie_isactive(lua_State *L)
1377 {
1378 lua_pushboolean(L, VBAMovieActive());
1379 return 1;
1380 }
1381
1382 int movie_isrecording(lua_State *L)
1383 {
1384 lua_pushboolean(L, VBAMovieRecording());
1385 return 1;
1386 }
1387
1388 int movie_isplaying(lua_State *L)
1389 {
1390 lua_pushboolean(L, VBAMoviePlaying());
1391 return 1;
1392 }
1393
1394 int movie_getlength(lua_State *L)
1395 {
1396 if (VBAMovieActive())
1397 lua_pushinteger(L, VBAMovieGetLength());
1398 else
1399 lua_pushinteger(L, 0);
1400 return 1;
1401 }
1402
1403 static int memory_readbyte(lua_State *L)
1404 {
1405 u32 addr;
1406 u8 val;
1407
1408 addr = luaL_checkinteger(L, 1);
1409 if (systemIsRunningGBA())
1410 {
1411 val = CPUReadByteQuick(addr);
1412 }
1413 else
1414 {
1415 val = gbReadMemoryQuick8(addr);
1416 }
1417
1418 lua_pushinteger(L, val);
1419 return 1;
1420 }
1421
1422 static int memory_readbytesigned(lua_State *L)
1423 {
1424 u32 addr;
1425 s8 val;
1426
1427 addr = luaL_checkinteger(L, 1);
1428 if (systemIsRunningGBA())
1429 {
1430 val = (s8) CPUReadByteQuick(addr);
1431 }
1432 else
1433 {
1434 val = (s8) gbReadMemoryQuick8(addr);
1435 }
1436
1437 lua_pushinteger(L, val);
1438 return 1;
1439 }
1440
1441 static int memory_readword(lua_State *L)
1442 {
1443 u32 addr;
1444 u16 val;
1445
1446 addr = luaL_checkinteger(L, 1);
1447 if (systemIsRunningGBA())
1448 {
1449 val = CPUReadHalfWordQuick(addr);
1450 }
1451 else
1452 {
1453 val = gbReadMemoryQuick16(addr & 0x0000FFFF);
1454 }
1455
1456 lua_pushinteger(L, val);
1457 return 1;
1458 }
1459
1460 static int memory_readwordsigned(lua_State *L)
1461 {
1462 u32 addr;
1463 s16 val;
1464
1465 addr = luaL_checkinteger(L, 1);
1466 if (systemIsRunningGBA())
1467 {
1468 val = (s16) CPUReadHalfWordQuick(addr);
1469 }
1470 else
1471 {
1472 val = (s16) gbReadMemoryQuick16(addr);
1473 }
1474
1475 lua_pushinteger(L, val);
1476 return 1;
1477 }
1478
1479 static int memory_readdword(lua_State *L)
1480 {
1481 u32 addr;
1482 u32 val;
1483
1484 addr = luaL_checkinteger(L, 1);
1485 if (systemIsRunningGBA())
1486 {
1487 val = CPUReadMemoryQuick(addr);
1488 }
1489 else
1490 {
1491 val = gbReadMemoryQuick32(addr & 0x0000FFFF);
1492 }
1493
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;
1500 }
1501
1502 static int memory_readdwordsigned(lua_State *L)
1503 {
1504 u32 addr;
1505 s32 val;
1506
1507 addr = luaL_checkinteger(L, 1);
1508 if (systemIsRunningGBA())
1509 {
1510 val = (s32) CPUReadMemoryQuick(addr);
1511 }
1512 else
1513 {
1514 val = (s32) gbReadMemoryQuick32(addr);
1515 }
1516
1517 lua_pushinteger(L, val);
1518 return 1;
1519 }
1520
1521 static int memory_readbyterange(lua_State *L)
1522 {
1523 uint32 address = luaL_checkinteger(L, 1);
1524 int length = luaL_checkinteger(L, 2);
1525
1526 if (length < 0)
1527 {
1528 address += length;
1529 length = -length;
1530 }
1531
1532 // push the array
1533 lua_createtable(L, abs(length), 0);
1534
1535 // put all the values into the (1-based) array
1536 for (int a = address, n = 1; n <= length; a++, n++)
1537 {
1538 unsigned char value;
1539
1540 if (systemIsRunningGBA())
1541 {
1542 value = CPUReadByteQuick(a);
1543 }
1544 else
1545 {
1546 value = gbReadMemoryQuick8(a);
1547 }
1548
1549 lua_pushinteger(L, value);
1550 lua_rawseti(L, -2, n);
1551 }
1552
1553 return 1;
1554 }
1555
1556 static int memory_writebyte(lua_State *L)
1557 {
1558 u32 addr;
1559 int val;
1560
1561 addr = luaL_checkinteger(L, 1);
1562 val = luaL_checkinteger(L, 2);
1563 if (systemIsRunningGBA())
1564 {
1565 CPUWriteByteQuick(addr, val);
1566 }
1567 else
1568 {
1569 gbWriteMemoryQuick8(addr, val);
1570 }
1571
1572 CallRegisteredLuaMemHook(addr, 1, val, LUAMEMHOOK_WRITE);
1573 return 0;
1574 }
1575
1576 static int memory_writeword(lua_State *L)
1577 {
1578 u32 addr;
1579 int val;
1580
1581 addr = luaL_checkinteger(L, 1);
1582 val = luaL_checkinteger(L, 2);
1583 if (systemIsRunningGBA())
1584 {
1585 CPUWriteHalfWordQuick(addr, val);
1586 }
1587 else
1588 {
1589 gbWriteMemoryQuick16(addr, val);
1590 }
1591
1592 CallRegisteredLuaMemHook(addr, 2, val, LUAMEMHOOK_WRITE);
1593 return 0;
1594 }
1595
1596 static int memory_writedword(lua_State *L)
1597 {
1598 u32 addr;
1599 int val;
1600
1601 addr = luaL_checkinteger(L, 1);
1602 val = luaL_checkinteger(L, 2);
1603 if (systemIsRunningGBA())
1604 {
1605 CPUWriteMemoryQuick(addr, val);
1606 }
1607 else
1608 {
1609 gbWriteMemoryQuick32(addr, val);
1610 }
1611
1612 CallRegisteredLuaMemHook(addr, 4, val, LUAMEMHOOK_WRITE);
1613 return 0;
1614 }
1615
1616 static int memory_gbromreadbyte(lua_State *L)
1617 {
1618 u32 addr;
1619 u8 val;
1620
1621 addr = luaL_checkinteger(L, 1);
1622 if (systemIsRunningGBA())
1623 {
1624 lua_pushnil(L);
1625 return 1;
1626 }
1627 else
1628 {
1629 val = gbReadROMQuick8(addr);
1630 }
1631
1632 lua_pushinteger(L, val);
1633 return 1;
1634 }
1635
1636 static int memory_gbromreadbytesigned(lua_State *L)
1637 {
1638 u32 addr;
1639 s8 val;
1640
1641 addr = luaL_checkinteger(L, 1);
1642 if (systemIsRunningGBA())
1643 {
1644 lua_pushnil(L);
1645 return 1;
1646 }
1647 else
1648 {
1649 val = (s8) gbReadROMQuick8(addr);
1650 }
1651
1652 lua_pushinteger(L, val);
1653 return 1;
1654 }
1655
1656 static int memory_gbromreadword(lua_State *L)
1657 {
1658 u32 addr;
1659 u16 val;
1660
1661 addr = luaL_checkinteger(L, 1);
1662 if (systemIsRunningGBA())
1663 {
1664 lua_pushnil(L);
1665 return 1;
1666 }
1667 else
1668 {
1669 val = gbReadROMQuick16(addr);
1670 }
1671
1672 lua_pushinteger(L, val);
1673 return 1;
1674 }
1675
1676 static int memory_gbromreadwordsigned(lua_State *L)
1677 {
1678 u32 addr;
1679 s16 val;
1680
1681 addr = luaL_checkinteger(L, 1);
1682 if (systemIsRunningGBA())
1683 {
1684 lua_pushnil(L);
1685 return 1;
1686 }
1687 else
1688 {
1689 val = (s16) gbReadROMQuick16(addr);
1690 }
1691
1692 lua_pushinteger(L, val);
1693 return 1;
1694 }
1695
1696 static int memory_gbromreaddword(lua_State *L)
1697 {
1698 u32 addr;
1699 u32 val;
1700
1701 addr = luaL_checkinteger(L, 1);
1702 if (systemIsRunningGBA())
1703 {
1704 lua_pushnil(L);
1705 return 1;
1706 }
1707 else
1708 {
1709 val = gbReadROMQuick32(addr);
1710 }
1711
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;
1718 }
1719
1720 static int memory_gbromreaddwordsigned(lua_State *L)
1721 {
1722 u32 addr;
1723 s32 val;
1724
1725 addr = luaL_checkinteger(L, 1);
1726 if (systemIsRunningGBA())
1727 {
1728 lua_pushnil(L);
1729 return 1;
1730 }
1731 else
1732 {
1733 val = (s32) gbReadROMQuick32(addr);
1734 }
1735
1736 lua_pushinteger(L, val);
1737 return 1;
1738 }
1739
1740 static int memory_gbromreadbyterange(lua_State *L)
1741 {
1742 uint32 address = luaL_checkinteger(L, 1);
1743 int length = luaL_checkinteger(L, 2);
1744
1745 if (length < 0)
1746 {
1747 address += length;
1748 length = -length;
1749 }
1750
1751 // push the array
1752 lua_createtable(L, abs(length), 0);
1753
1754 // put all the values into the (1-based) array
1755 for (int a = address, n = 1; n <= length; a++, n++)
1756 {
1757 unsigned char value;
1758
1759 if (systemIsRunningGBA())
1760 {
1761 lua_pushnil(L);
1762 return 1;
1763 }
1764 else
1765 {
1766 value = gbReadROMQuick8(a);
1767 }
1768
1769 lua_pushinteger(L, value);
1770 lua_rawseti(L, -2, n);
1771 }
1772
1773 return 1;
1774 }
1775
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)
1780 {
1781 // Reads the joypads as inputted by the user
1782 int which = luaL_checkinteger(L, 1);
1783
1784 if (which < 0 || which > 4)
1785 {
1786 luaL_error(L, "Invalid input port (valid range 0-4, specified %d)", which);
1787 }
1788
1789 uint32 buttons = systemGetOriginalJoypad(which - 1, false);
1790
1791 lua_newtable(L);
1792
1793 int i;
1794 for (i = 0; i < 10; i++)
1795 {
1796 bool pressed = (buttons & (1 << i)) != 0;
1797 if ((pressed && reportDown) || (!pressed && reportUp))
1798 {
1799 lua_pushboolean(L, pressed);
1800 lua_setfield(L, -2, button_mappings[i]);
1801 }
1802 }
1803
1804 return 1;
1805 }
1806
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)
1813 {
1814 return joy_get_internal(L, true, true);
1815 }
1816
1817 // joypad.getdown(which)
1818 // returns a table of every game button that is currently held
1819 static int joypad_getdown(lua_State *L)
1820 {
1821 return joy_get_internal(L, false, true);
1822 }
1823
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)
1827 {
1828 return joy_get_internal(L, true, false);
1829 }
1830
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
1835
1836 // keys (no pun intended) set.
1837 static int joypad_set(lua_State *L)
1838 {
1839 // Which joypad we're tampering with
1840 int which = luaL_checkinteger(L, 1);
1841 if (which < 0 || which > 4)
1842 {
1843 luaL_error(L, "Invalid output port (valid range 0-4, specified %d)", which);
1844 }
1845
1846 if (which == 0)
1847 which = systemGetDefaultJoypad();
1848
1849 // And the table of buttons.
1850 luaL_checktype(L, 2, LUA_TTABLE);
1851
1852 // Set up for taking control of the indicated controller
1853 lua_joypads_used |= 1 << (which - 1);
1854 lua_joypads[which - 1] = 0;
1855
1856 for (int i = 0; i < 10; i++)
1857 {
1858 const char *name = button_mappings[i];
1859 lua_getfield(L, 2, name);
1860 if (!lua_isnil(L, -1))
1861 {
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);
1867 }
1868 lua_pop(L, 1);
1869 }
1870
1871 return 0;
1872 }
1873
1874 // Helper function to convert a savestate object to the filename it represents.
1875 static const char *savestateobj2filename(lua_State *L, int offset)
1876 {
1877 // First we get the metatable of the indicated object
1878 int result = lua_getmetatable(L, offset);
1879
1880 if (!result)
1881 luaL_error(L, "object not a savestate object");
1882
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);
1888
1889 // Now, get the field we want
1890 lua_getfield(L, -1, "filename");
1891
1892 // Return it
1893 return lua_tostring(L, -1);
1894 }
1895
1896 // Helper function for garbage collection.
1897 static int savestate_gc(lua_State *L)
1898 {
1899 // The object we're collecting is on top of the stack
1900 lua_getmetatable(L, 1);
1901
1902 // Get the filename
1903 const char *filename;
1904 lua_getfield(L, -1, "filename");
1905 filename = lua_tostring(L, -1);
1906
1907 // Delete the file
1908 remove(filename);
1909
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;
1913 }
1914
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
1919
1920 // ("which" between 1 and 12) or not (which == nil).
1921 static int savestate_create(lua_State *L)
1922 {
1923 int which = -1;
1924 if (lua_gettop(L) >= 1)
1925 {
1926 which = luaL_checkinteger(L, 1);
1927 if (which < 1 || which > 12)
1928 {
1929 luaL_error(L, "invalid player's savestate %d", which);
1930 }
1931 }
1932
1933 char stateName[2048];
1934
1935 if (which > 0)
1936 {
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);
1944
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
1950 }
1951 else
1952 {
1953 char *stateNameTemp = tempnam(NULL, "snlua");
1954 strcpy(stateName, stateNameTemp);
1955 if (stateNameTemp)
1956 free(stateNameTemp);
1957 }
1958
1959 // Our "object". We don't care about the type, we just need the memory and GC services.
1960 lua_newuserdata(L, 1);
1961
1962 // The metatable we use, protected from Lua and contains garbage collection info and stuff.
1963 lua_newtable(L);
1964
1965 // First, we must protect it
1966 lua_pushstring(L, "vba Savestate");
1967 lua_setfield(L, -2, "__metatable");
1968
1969 // Now we need to save the file itself.
1970 lua_pushstring(L, stateName);
1971 lua_setfield(L, -2, "filename");
1972
1973 // If it's an anonymous savestate, we must delete the file from disk should it be gargage collected
1974 if (which < 0)
1975 {
1976 lua_pushcfunction(L, savestate_gc);
1977 lua_setfield(L, -2, "__gc");
1978 }
1979
1980 // Set the metatable
1981 lua_setmetatable(L, -2);
1982
1983 // Awesome. Return the object
1984 return 1;
1985 }
1986
1987 // savestate.save(object state)
1988 //
1989
1990 // Saves a state to the given object.
1991 static int savestate_save(lua_State *L)
1992 {
1993 const char *filename = savestateobj2filename(L, 1);
1994
1995 // printf("saving %s\n", filename);
1996 // Save states are very expensive. They take time.
1997 numTries--;
1998
1999 bool8 retvalue = theEmulator.emuWriteState ? theEmulator.emuWriteState(filename) : false;
2000 if (!retvalue)
2001 {
2002 // Uh oh
2003 luaL_error(L, "savestate failed");
2004 }
2005
2006 return 0;
2007 }
2008
2009 // savestate.load(object state)
2010 //
2011
2012 // Loads the given state
2013 static int savestate_load(lua_State *L)
2014 {
2015 const char *filename = savestateobj2filename(L, 1);
2016
2017 numTries--;
2018
2019 // printf("loading %s\n", filename);
2020 bool8 retvalue = theEmulator.emuReadState ? theEmulator.emuReadState(filename) : false;
2021 if (!retvalue)
2022 {
2023 // Uh oh
2024 luaL_error(L, "loadstate failed");
2025 }
2026
2027 return 0;
2028 }
2029
2030 // int vba.framecount()
2031 //
2032
2033 // Gets the frame counter for the movie, or the number of frames since last reset.
2034 int vba_framecount(lua_State *L)
2035 {
2036 if (!VBAMovieActive())
2037 {
2038 lua_pushinteger(L, systemCounters.frameCount);
2039 }
2040 else
2041 {
2042 lua_pushinteger(L, VBAMovieGetFrameCounter());
2043 }
2044
2045 return 1;
2046 }
2047
2048 //string movie.getauthor
2049 //
2050
2051 // returns author info field of .vbm file
2052 int movie_getauthor(lua_State *L)
2053 {
2054 if (!VBAMovieActive())
2055 {
2056 //lua_pushnil(L);
2057 lua_pushstring(L, "");
2058 return 1;
2059 }
2060
2061 lua_pushstring(L, VBAMovieGetAuthorInfo().c_str());
2062 return 1;
2063 }
2064
2065 //string movie.filename
2066 int movie_getfilename(lua_State *L)
2067 {
2068 if (!VBAMovieActive())
2069 {
2070 //lua_pushnil(L);
2071 lua_pushstring(L, "");
2072 return 1;
2073 }
2074
2075 lua_pushstring(L, VBAMovieGetFilename().c_str());
2076 return 1;
2077 }
2078
2079 // string movie.mode()
2080 //
2081
2082 // "record", "playback" or nil
2083 int movie_getmode(lua_State *L)
2084 {
2085 assert(!VBAMovieLoading());
2086 if (!VBAMovieActive())
2087 {
2088 lua_pushnil(L);
2089 return 1;
2090 }
2091
2092 if (VBAMovieRecording())
2093 lua_pushstring(L, "record");
2094 else
2095 lua_pushstring(L, "playback");
2096 return 1;
2097 }
2098
2099 static int movie_rerecordcount(lua_State *L)
2100 {
2101 if (VBAMovieActive())
2102 lua_pushinteger(L, VBAMovieGetRerecordCount());
2103 else
2104 lua_pushinteger(L, 0);
2105 return 1;
2106 }
2107
2108 static int movie_setrerecordcount(lua_State *L)
2109 {
2110 if (VBAMovieActive())
2111 VBAMovieSetRerecordCount(luaL_checkinteger(L, 1));
2112 return 0;
2113 }
2114
2115 static int movie_rerecordcounting(lua_State *L)
2116 {
2117 if (lua_gettop(L) == 0)
2118 luaL_error(L, "no parameters specified");
2119
2120 skipRerecords = lua_toboolean(L, 1);
2121 return 0;
2122 }
2123
2124 // movie.stop()
2125 //
2126
2127 // Stops movie playback/recording. Bombs out if movie is not running.
2128 static int movie_stop(lua_State *L)
2129 {
2130 if (!VBAMovieActive())
2131 luaL_error(L, "no movie");
2132
2133 VBAMovieStop(false);
2134 return 0;
2135 }
2136
2137 #define LUA_SCREEN_WIDTH 256
2138 #define LUA_SCREEN_HEIGHT 239
2139
2140 // Common code by the gui library: make sure the screen array is ready
2141 static void gui_prepare(void)
2142 {
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;
2148 }
2149
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; \
2158 }
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)
2165
2166 template<class T>
2167 static void swap(T &one, T &two)
2168 {
2169 T temp = one;
2170 one = two;
2171 two = temp;
2172 }
2173
2174 // write a pixel to buffer
2175 static inline void blend32(uint32 *dstPixel, uint32 colour)
2176 {
2177 uint8 *dst = (uint8 *)dstPixel;
2178 int a, r, g, b;
2179 LUA_DECOMPOSE_PIXEL(colour, a, r, g, b);
2180
2181 if (a == 255 || dst[3] == 0)
2182 {
2183 // direct copy
2184 *(uint32 *) (dst) = colour;
2185 }
2186 else if (a == 0)
2187 {
2188 // do not copy
2189 }
2190 else
2191 {
2192 // alpha-blending
2193 int a_dst = ((255 - a) * dst[3] + 128) / 255;
2194 int a_new = a + a_dst;
2195
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;
2200 }
2201 }
2202
2203 // check if a pixel is in the lua canvas
2204 static inline bool gui_check_boundary(int x, int y)
2205 {
2206 return !(x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= LUA_SCREEN_HEIGHT);
2207 }
2208
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)
2211 {
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;
2218 }
2219
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)
2222 {
2223 //gui_prepare();
2224 blend32((uint32 *) &gui_data[(y * LUA_SCREEN_WIDTH + x) * 4], colour);
2225 }
2226
2227 // write a pixel to gui_data (check boundaries)
2228 static inline void gui_drawpixel_internal(int x, int y, uint32 colour)
2229 {
2230 //gui_prepare();
2231 if (gui_check_boundary(x, y))
2232 gui_drawpixel_fast(x, y, colour);
2233 }
2234
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)
2237 {
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;
2245
2246 int xtemp = x1 - x2;
2247 int ytemp = y1 - y2;
2248 if (xtemp == 0 && ytemp == 0)
2249 {
2250 gui_drawpixel_internal(x1, y1, colour);
2251 return;
2252 }
2253
2254 if (xtemp < 0)
2255 {
2256 xtemp = -xtemp;
2257 swappedx = 1;
2258 }
2259
2260 if (ytemp < 0)
2261 {
2262 ytemp = -ytemp;
2263 swappedy = 1;
2264 }
2265
2266 int delta_x = xtemp << 1;
2267 int delta_y = ytemp << 1;
2268
2269 signed char ix = x1 > x2 ? 1 : -1;
2270 signed char iy = y1 > y2 ? 1 : -1;
2271
2272 if (lastPixel)
2273 gui_drawpixel_internal(x2, y2, colour);
2274
2275 if (delta_x >= delta_y)
2276 {
2277 int error = delta_y - (delta_x >> 1);
2278
2279 while (x2 != x1)
2280 {
2281 if (error == 0 && !swappedx)
2282 gui_drawpixel_internal(x2 + ix, y2, colour);
2283 if (error >= 0)
2284 {
2285 if (error || (ix > 0))
2286 {
2287 y2 += iy;
2288 error -= delta_x;
2289 }
2290 }
2291
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;
2297 }
2298 }
2299 else
2300 {
2301 int error = delta_x - (delta_y >> 1);
2302
2303 while (y2 != y1)
2304 {
2305 if (error == 0 && !swappedy)
2306 gui_drawpixel_internal(x2, y2 + iy, colour);
2307 if (error >= 0)
2308 {
2309 if (error || (iy > 0))
2310 {
2311 x2 += ix;
2312 error -= delta_y;
2313 }
2314 }
2315
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;
2321 }
2322 }
2323 }
2324
2325 // draw a rect on gui_data
2326 static void gui_drawbox_internal(int x1, int y1, int x2, int y2, uint32 colour)
2327 {
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;
2340
2341 if (!gui_checkbox(x1, y1, x2, y2))
2342 return;
2343
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);
2349 }
2350
2351 // draw a circle on gui_data
2352 static void gui_drawcircle_internal(int x0, int y0, int radius, uint32 colour)
2353 {
2354 //gui_prepare();
2355 if (radius < 0)
2356 radius = -radius;
2357 if (radius == 0)
2358 return;
2359 if (radius == 1)
2360 {
2361 gui_drawpixel_internal(x0, y0, colour);
2362 return;
2363 }
2364
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;
2371
2372 if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius))
2373 return;
2374
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);
2379
2380 // same pixel shouldn't be drawed twice,
2381 // because each pixel has opacity.
2382 // so now the routine gets ugly.
2383 while (true)
2384 {
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)
2389 {
2390 y--;
2391 ddF_y += 2;
2392 f += ddF_y;
2393 }
2394
2395 x++;
2396 ddF_x += 2;
2397 f += ddF_x;
2398 if (x < y)
2399 {
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);
2408 }
2409 else if (x == y)
2410 {
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;
2416 }
2417 else
2418 break;
2419 }
2420 }
2421
2422 // draw fill rect on gui_data
2423 static void gui_fillbox_internal(int x1, int y1, int x2, int y2, uint32 colour)
2424 {
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;
2437
2438 //gui_prepare();
2439 int ix, iy;
2440 for (iy = y1; iy <= y2; iy++)
2441 {
2442 for (ix = x1; ix <= x2; ix++)
2443 {
2444 gui_drawpixel_fast(ix, iy, colour);
2445 }
2446 }
2447 }
2448
2449 // fill a circle on gui_data
2450 static void gui_fillcircle_internal(int x0, int y0, int radius, uint32 colour)
2451 {
2452 //gui_prepare();
2453 if (radius < 0)
2454 radius = -radius;
2455 if (radius == 0)
2456 return;
2457 if (radius == 1)
2458 {
2459 gui_drawpixel_internal(x0, y0, colour);
2460 return;
2461 }
2462
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;
2469
2470 if (!gui_checkbox(x0 - radius, y0 - radius, x0 + radius, y0 + radius))
2471 return;
2472
2473 gui_drawline_internal(x0, y0 - radius, x0, y0 + radius, true, colour);
2474
2475 while (true)
2476 {
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)
2481 {
2482 y--;
2483 ddF_y += 2;
2484 f += ddF_y;
2485 }
2486
2487 x++;
2488 ddF_x += 2;
2489 f += ddF_x;
2490
2491 if (x < y)
2492 {
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)
2496 {
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);
2499 }
2500 }
2501 else if (x == y)
2502 {
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;
2506 }
2507 else
2508 break;
2509 }
2510 }
2511
2512 // Helper for a simple hex parser
2513 static int hex2int(lua_State *L, char c)
2514 {
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");
2522 }
2523
2524 static const struct ColorMapping
2525 {
2526 const char *name;
2527 int value;
2528 }
2529 s_colorMapping[] =
2530 {
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 };
2547
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)
2555 {
2556 if (str[0] == '#')
2557 {
2558 int color;
2559 sscanf(str + 1, "%X", &color);
2560
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;
2568 }
2569 else
2570 {
2571 if (!strnicmp(str, "rand", 4))
2572 {
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;
2576 }
2577
2578 for (int i = 0; i < sizeof(s_colorMapping) / sizeof(*s_colorMapping); i++)
2579 {
2580 if (!stricmp(str, s_colorMapping[i].name))
2581 {
2582 *colour = s_colorMapping[i].value;
2583 return true;
2584 }
2585 }
2586 }
2587
2588 return false;
2589 }
2590
2591 static inline uint32 gui_getcolour_wrapped(lua_State *L, int offset, bool hasDefaultValue, uint32 defaultColour)
2592 {
2593 switch (lua_type(L, offset))
2594 {
2595 case LUA_TSTRING:
2596 {
2597 const char *str = lua_tostring(L, offset);
2598 uint32 colour;
2599
2600 if (str2colour(&colour, L, str))
2601 return colour;
2602 else
2603 {
2604 if (hasDefaultValue)
2605 return defaultColour;
2606 else
2607 return luaL_error(L, "unknown colour %s", str);
2608 }
2609 }
2610
2611 case LUA_TNUMBER:
2612 {
2613 uint32 colour = (uint32) lua_tointeger(L, offset);
2614 return colour;
2615 }
2616
2617 case LUA_TTABLE:
2618 {
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))
2625 {
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)
2633 {
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;
2646 }
2647 lua_pop(L, 1);
2648 }
2649 return color;
2650 } break;
2651
2652 case LUA_TFUNCTION:
2653 luaL_error(L, "invalid colour"); // NYI
2654 return 0;
2655
2656 default:
2657 if (hasDefaultValue)
2658 return defaultColour;
2659 else
2660 return luaL_error(L, "invalid colour");
2661 }
2662 }
2663
2664 static uint32 gui_getcolour(lua_State *L, int offset)
2665 {
2666 uint32 colour;
2667 int a, r, g, b;
2668
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);
2677 }
2678
2679 static uint32 gui_optcolour(lua_State *L, int offset, uint32 defaultColour)
2680 {
2681 uint32 colour;
2682 int a, r, g, b;
2683 uint8 defA, defB, defG, defR;
2684
2685 LUA_DECOMPOSE_PIXEL(defaultColour, defA, defR, defG, defB);
2686 defaultColour = (defR << 24) | (defG << 16) | (defB << 8) | defA;
2687
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);
2696 }
2697
2698 // gui.drawpixel(x,y,colour)
2699 static int gui_drawpixel(lua_State *L)
2700 {
2701 int x = luaL_checkinteger(L, 1);
2702 int y = luaL_checkinteger(L, 2);
2703
2704 uint32 colour = gui_getcolour(L, 3);
2705
2706 // if (!gui_check_boundary(x, y))
2707 // luaL_error(L,"bad coordinates");
2708 gui_prepare();
2709
2710 gui_drawpixel_internal(x, y, colour);
2711
2712 return 0;
2713 }
2714
2715 // gui.drawline(x1,y1,x2,y2,color,skipFirst)
2716 static int gui_drawline(lua_State *L)
2717 {
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);
2726
2727 gui_prepare();
2728
2729 gui_drawline_internal(x2, y2, x1, y1, !skipFirst, color);
2730
2731 return 0;
2732 }
2733
2734 // gui.drawbox(x1, y1, x2, y2, fillcolor, outlinecolor)
2735 static int gui_drawbox(lua_State *L)
2736 {
2737 int x1, y1, x2, y2;
2738 uint32 fillcolor;
2739 uint32 outlinecolor;
2740
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)));
2747
2748 if (x1 > x2)
2749 std::swap(x1, x2);
2750 if (y1 > y2)
2751 std::swap(y1, y2);
2752
2753 gui_prepare();
2754
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);
2758
2759 return 0;
2760 }
2761
2762 // gui.drawcircle(x0, y0, radius, colour)
2763 static int gui_drawcircle(lua_State *L)
2764 {
2765 int x, y, r;
2766 uint32 colour;
2767
2768 x = luaL_checkinteger(L, 1);
2769 y = luaL_checkinteger(L, 2);
2770 r = luaL_checkinteger(L, 3);
2771 colour = gui_getcolour(L, 4);
2772
2773 gui_prepare();
2774
2775 gui_drawcircle_internal(x, y, r, colour);
2776
2777 return 0;
2778 }
2779
2780 // gui.fillbox(x1, y1, x2, y2, colour)
2781 static int gui_fillbox(lua_State *L)
2782 {
2783 int x1, y1, x2, y2;
2784 uint32 colour;
2785
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);
2791
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();
2798
2799 if (!gui_checkbox(x1, y1, x2, y2))
2800 return 0;
2801
2802 gui_fillbox_internal(x1, y1, x2, y2, colour);
2803
2804 return 0;
2805 }
2806
2807 // gui.fillcircle(x0, y0, radius, colour)
2808 static int gui_fillcircle(lua_State *L)
2809 {
2810 int x, y, r;
2811 uint32 colour;
2812
2813 x = luaL_checkinteger(L, 1);
2814 y = luaL_checkinteger(L, 2);
2815 r = luaL_checkinteger(L, 3);
2816 colour = gui_getcolour(L, 4);
2817
2818 gui_prepare();
2819
2820 gui_fillcircle_internal(x, y, r, colour);
2821
2822 return 0;
2823 }
2824
2825 static int gui_getpixel(lua_State *L)
2826 {
2827 int x = luaL_checkinteger(L, 1);
2828 int y = luaL_checkinteger(L, 2);
2829
2830 int pixWidth = 240, pixHeight = 160;
2831 int scrWidth = 240, scrHeight = 160;
2832 int scrOffsetX = 0, scrOffsetY = 0;
2833 int pitch;
2834 if (!systemIsRunningGBA())
2835 {
2836 if (gbBorderOn)
2837 {
2838 pixWidth = 256, pixHeight = 224;
2839 scrOffsetX = 48, scrOffsetY = 40;
2840 }
2841 else
2842 {
2843 pixWidth = 160, pixHeight = 144;
2844 }
2845 scrWidth = 160, scrHeight = 144;
2846 }
2847 pitch = pixWidth * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4);
2848 scrOffsetY++; // don't know why it's needed
2849
2850 if (!(x >= 0 && y >= 0 && x < scrWidth && y < scrHeight) /*!gui_check_boundary(x,y)*/)
2851 {
2852 lua_pushinteger(L, 0);
2853 lua_pushinteger(L, 0);
2854 lua_pushinteger(L, 0);
2855 }
2856 else
2857 {
2858 switch (systemColorDepth)
2859 {
2860 case 16:
2861 {
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
2867 }
2868 break;
2869 case 24:
2870 {
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
2875 }
2876 break;
2877 case 32:
2878 {
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
2883 }
2884 break;
2885 default:
2886 lua_pushinteger(L, 0);
2887 lua_pushinteger(L, 0);
2888 lua_pushinteger(L, 0);
2889 break;
2890 }
2891 }
2892 return 3;
2893 }
2894
2895 static int gui_parsecolor(lua_State *L)
2896 {
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;
2905 }
2906
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.
2916
2917 // example: gd.createFromGdStr(gui.gdscreenshot()):png("outputimage.png")
2918 static int gui_gdscreenshot(lua_State *L)
2919 {
2920 int xofs = 0, yofs = 0, ppl = 240, width = 240, height = 160;
2921 if (!systemIsRunningGBA())
2922 {
2923 if (gbBorderOn)
2924 xofs = 48, yofs = 40, ppl = 256;
2925 else
2926 ppl = 160;
2927 width = 160, height = 144;
2928 }
2929
2930 yofs++;
2931
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)];
2935
2936 int size = 11 + width * height * 4;
2937 char *str = new char[size + 1];
2938 str[size] = 0;
2939
2940 unsigned char *ptr = (unsigned char *)str;
2941
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;
2954
2955 GetColorFunc getColor;
2956 getColorIOFunc(systemColorDepth, &getColor, NULL);
2957
2958 int x, y;
2959 for (y = 0; y < height; y++)
2960 {
2961 uint8 *s = &screen[y * pitch];
2962 for (x = 0; x < width; x++, s += systemColorDepth / 8)
2963 {
2964 uint8 r, g, b;
2965 getColor(s, &r, &g, &b);
2966
2967 *ptr++ = 0;
2968 *ptr++ = r;
2969 *ptr++ = g;
2970 *ptr++ = b;
2971 }
2972 }
2973
2974 lua_pushlstring(L, str, size);
2975 delete[] str;
2976 return 1;
2977 }
2978
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.
2985
2986 // however, it can be convenient to be able to globally modify the drawing transparency
2987 static int gui_setopacity(lua_State *L)
2988 {
2989 double opacF = luaL_checknumber(L, 1);
2990 transparencyModifier = (int)(opacF * 255);
2991 if (transparencyModifier < 0)
2992 transparencyModifier = 0;
2993 return 0;
2994 }
2995
2996 // gui.transparency(int strength)
2997 //
2998
2999 // 0 = solid,
3000 static int gui_transparency(lua_State *L)
3001 {
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;
3007 }
3008
3009 static const uint32 Small_Font_Data[] =
3010 {
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 };
3109
3110 static void PutTextInternal(const char *str, int len, short x, short y, int color, int backcolor)
3111 {
3112 int Opac = (color >> 24) & 0xFF;
3113 int backOpac = (backcolor >> 24) & 0xFF;
3114 int origX = x;
3115
3116 if (!Opac && !backOpac)
3117 return;
3118
3119 while (*str && len && y < LUA_SCREEN_HEIGHT)
3120 {
3121 int c = *str++;
3122 while (x > LUA_SCREEN_WIDTH && c != '\n')
3123 {
3124 c = *str;
3125 if (c == '\0')
3126 break;
3127 str++;
3128 }
3129
3130 if (c == '\n')
3131 {
3132 x = origX;
3133 y += 8;
3134 continue;
3135 }
3136 else if (c == '\t') // just in case
3137 {
3138 const int tabSpace = 8;
3139 x += (tabSpace - (((x - origX) / 4) % tabSpace)) * 4;
3140 continue;
3141 }
3142
3143 if ((unsigned int)(c - 32) >= 96)
3144 continue;
3145
3146 const unsigned char *Cur_Glyph = (const unsigned char *) &Small_Font_Data + (c - 32) * 7 * 4;
3147
3148 for (int y2 = 0; y2 < 8; y2++)
3149 {
3150 unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y2);
3151 for (int x2 = -1; x2 < 4; x2++)
3152 {
3153 int shift = x2 << 3;
3154 int mask = 0xFF << shift;
3155 int intensity = (glyphLine & mask) >> shift;
3156
3157 if (intensity && x2 >= 0 && y2 < 7)
3158 {
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);
3163 }
3164 else if (backOpac)
3165 {
3166 for (int y3 = max(0, y2 - 1); y3 <= min(6, y2 + 1); y3++)
3167 {
3168 unsigned int glyphLine = *((unsigned int *)Cur_Glyph + y3);
3169 for (int x3 = max(0, x2 - 1); x3 <= min(3, x2 + 1); x3++)
3170 {
3171 int shift = x3 << 3;
3172 int mask = 0xFF << shift;
3173 intensity |= (glyphLine & mask) >> shift;
3174 if (intensity)
3175 goto draw_outline; // speedup?
3176 }
3177 }
3178
3179 draw_outline:
3180 if (intensity)
3181 {
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);
3186 }
3187 }
3188 }
3189 }
3190
3191 x += 4;
3192 len--;
3193 }
3194 }
3195
3196 static int strlinelen(const char *string)
3197 {
3198 const char *s = string;
3199 while (*s && *s != '\n')
3200 s++;
3201 if (*s)
3202 s++;
3203 return s - string;
3204 }
3205
3206 static void LuaDisplayString(const char *string, int y, int x, uint32 color, uint32 outlineColor)
3207 {
3208 if (!string)
3209 return;
3210
3211 gui_prepare();
3212
3213 PutTextInternal(string, strlen(string), x, y, color, outlineColor);
3214
3215 /*
3216 const char* ptr = string;
3217 while(*ptr && y < LUA_SCREEN_HEIGHT)
3218 {
3219 int len = strlinelen(ptr);
3220 int skip = 0;
3221 if(len < 1) len = 1;
3222
3223 // break up the line if it's too long to display otherwise
3224 if(len > 63)
3225 {
3226 len = 63;
3227 const char* ptr2 = ptr + len-1;
3228 for(int j = len-1; j; j--, ptr2--)
3229 {
3230 if(*ptr2 == ' ' || *ptr2 == '\t')
3231 {
3232 len = j;
3233 skip = 1;
3234 break;
3235 }
3236 }
3237 }
3238
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);
3245
3246 PutTextInternal(ptr,len,x2,y2,color,outlineColor);
3247
3248 ptr += len + skip;
3249 y += 8;
3250 }
3251 */
3252 }
3253
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
3257
3258 // main HUD.
3259 static int gui_text(lua_State *L)
3260 {
3261 //extern int font_height;
3262 const char *msg;
3263 int x, y;
3264 uint32 colour, borderColour;
3265
3266 x = luaL_checkinteger(L, 1);
3267 y = luaL_checkinteger(L, 2);
3268 //msg = luaL_checkstring(L, 3);
3269 msg = toCString(L, 3);
3270
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));
3275
3276 gui_prepare();
3277
3278 LuaDisplayString(msg, y, x, colour, borderColour);
3279
3280 return 0;
3281 }
3282
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.
3286
3287 // example: gui.gdoverlay(gd.createFromPng("myimage.png"):gdStr())
3288 static int gui_gdoverlay(lua_State *L)
3289 {
3290 int argCount = lua_gettop(L);
3291
3292 int xStartDst = 0;
3293 int yStartDst = 0;
3294 int xStartSrc = 0;
3295 int yStartSrc = 0;
3296
3297 int index = 1;
3298 if (lua_type(L, index) == LUA_TNUMBER)
3299 {
3300 xStartDst = lua_tointeger(L, index++);
3301 if (lua_type(L, index) == LUA_TNUMBER)
3302 yStartDst = lua_tointeger(L, index++);
3303 }
3304
3305 luaL_checktype(L, index, LUA_TSTRING);
3306
3307 const unsigned char *ptr = (const unsigned char *)lua_tostring(L, index++);
3308
3309 if (ptr[0] != 255 || (ptr[1] != 254 && ptr[1] != 255))
3310 luaL_error(L, "bad image data");
3311
3312 bool trueColor = (ptr[1] == 254);
3313 ptr += 2;
3314
3315 int imgwidth = *ptr++ << 8;
3316 imgwidth |= *ptr++;
3317
3318 int width = imgwidth;
3319 int imgheight = *ptr++ << 8;
3320 imgheight |= *ptr++;
3321
3322 int height = imgheight;
3323 if ((!trueColor && *ptr) || (trueColor && !*ptr))
3324 luaL_error(L, "bad image data");
3325 ptr++;
3326
3327 int pitch = imgwidth * (trueColor ? 4 : 1);
3328
3329 if ((argCount - index + 1) >= 4)
3330 {
3331 xStartSrc = luaL_checkinteger(L, index++);
3332 yStartSrc = luaL_checkinteger(L, index++);
3333 width = luaL_checkinteger(L, index++);
3334 height = luaL_checkinteger(L, index++);
3335 }
3336
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;
3342
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++)
3347 {
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;
3355 }
3356
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)
3361 {
3362 colorsTotal = *ptr++ << 8;
3363 colorsTotal |= *ptr++;
3364 }
3365
3366 int transparent = *ptr++ << 24;
3367 transparent |= *ptr++ << 16;
3368 transparent |= *ptr++ << 8;
3369 transparent |= *ptr++;
3370 struct
3371 {
3372 uint8 r, g, b, a;
3373 } pal[256];
3374 if (!trueColor)
3375 for (int i = 0; i < 256; i++)
3376 {
3377 pal[i].r = *ptr++;
3378 pal[i].g = *ptr++;
3379 pal[i].b = *ptr++;
3380 pal[i].a = opacMap[*ptr++];
3381 }
3382
3383 // some of clippings
3384 if (xStartSrc < 0)
3385 {
3386 width += xStartSrc;
3387 xStartDst -= xStartSrc;
3388 xStartSrc = 0;
3389 }
3390
3391 if (yStartSrc < 0)
3392 {
3393 height += yStartSrc;
3394 yStartDst -= yStartSrc;
3395 yStartSrc = 0;
3396 }
3397
3398 if (xStartSrc + width >= imgwidth)
3399 width = imgwidth - xStartSrc;
3400 if (yStartSrc + height >= imgheight)
3401 height = imgheight - yStartSrc;
3402 if (xStartDst < 0)
3403 {
3404 width += xStartDst;
3405 if (width <= 0)
3406 return 0;
3407 xStartSrc = -xStartDst;
3408 xStartDst = 0;
3409 }
3410
3411 if (yStartDst < 0)
3412 {
3413 height += yStartDst;
3414 if (height <= 0)
3415 return 0;
3416 yStartSrc = -yStartDst;
3417 yStartDst = 0;
3418 }
3419
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();
3427
3428 const uint8 *pix = (const uint8 *)(&ptr[yStartSrc * pitch + (xStartSrc * (trueColor ? 4 : 1))]);
3429 int bytesToNextLine = pitch - (width * (trueColor ? 4 : 1));
3430 if (trueColor)
3431 {
3432 for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine)
3433 {
3434 for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix += 4)
3435 {
3436 gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(opacMap[pix[0]], pix[1], pix[2], pix[3]));
3437 }
3438 }
3439 }
3440 else
3441 {
3442 for (int y = yStartDst; y < height + yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine)
3443 {
3444 for (int x = xStartDst; x < width + xStartDst && x < LUA_SCREEN_WIDTH; x++, pix++)
3445 {
3446 gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(pal[*pix].a, pal[*pix].r, pal[*pix].g, pal[*pix].b));
3447 }
3448 }
3449 }
3450
3451 return 0;
3452 }
3453
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
3460
3461 // (if any) is returned, or nil if none.
3462 static int gui_register(lua_State *L)
3463 {
3464 // We'll do this straight up.
3465 // First set up the stack.
3466 lua_settop(L, 1);
3467
3468 // Verify the validity of the entry
3469 if (!lua_isnil(L, 1))
3470 luaL_checktype(L, 1, LUA_TFUNCTION);
3471
3472 // Get the old value
3473 lua_getfield(L, LUA_REGISTRYINDEX, guiCallbackTable);
3474
3475 // Save the new value
3476 lua_pushvalue(L, 1);
3477 lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable);
3478
3479 // The old value is on top of the stack. Return it.
3480 return 1;
3481 }
3482
3483 // string gui.popup(string message, [string type = "ok"])
3484 //
3485
3486 // Popup dialog!
3487 int gui_popup(lua_State *L)
3488 {
3489 const char *message = luaL_checkstring(L, 1);
3490 const char *type = luaL_optstring(L, 2, "ok");
3491
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);
3502
3503 theApp.winCheckFullscreen();
3504 systemSoundClearBuffer();
3505 int result = AfxGetApp()->m_pMainWnd->MessageBox(message, "Lua Script Pop-up", t);
3506
3507 lua_settop(L, 1);
3508
3509 if (t != MB_OK)
3510 {
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;
3520 }
3521
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;
3533
3534 int pid; // appease compiler
3535
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);
3545
3546 // Can we find a copy of xmessage? Search the path.
3547 char *path = strdup(getenv("PATH"));
3548
3549 char *current = path;
3550
3551 char *colon;
3552
3553 int found = 0;
3554
3555 while (current)
3556 {
3557 colon = strchr(current, ':');
3558
3559 // Clip off the colon.
3560 *colon++ = 0;
3561
3562 int len = strlen(current);
3563 char *filename = (char *)malloc(len + 12); // always give excess
3564 snprintf(filename, len + 12, "%s/xmessage", current);
3565
3566 if (access(filename, X_OK) == 0)
3567 {
3568 free(filename);
3569 found = 1;
3570 break;
3571 }
3572
3573 // Failed, move on.
3574 current = colon;
3575 free(filename);
3576 }
3577
3578 free(path);
3579
3580 // We've found it?
3581 if (!found)
3582 goto use_console;
3583
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 };
3590
3591 execvp("xmessage", parameters);
3592
3593 // Aw shitty
3594 perror("exec xmessage");
3595 exit(1);
3596 }
3597 else if (pid < 0) // something went wrong!!! Oh hell... use the console
3598 goto use_console;
3599 else
3600 {
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;
3606
3607 // The return value gets copmlicated...
3608 if (!WIFEXITED(r))
3609 {
3610 luaL_error(L, "don't screw with my xmessage process!");
3611 }
3612
3613 r = WEXITSTATUS(r);
3614
3615 // We assume it's worked.
3616 if (r == 0)
3617 {
3618 return 0; // no parameters for an OK
3619 }
3620
3621 if (r == 100)
3622 {
3623 lua_pushstring(L, "yes");
3624 return 1;
3625 }
3626
3627 if (r == 101)
3628 {
3629 lua_pushstring(L, "no");
3630 return 1;
3631 }
3632
3633 if (r == 102)
3634 {
3635 lua_pushstring(L, "cancel");
3636 return 1;
3637 }
3638
3639 // Wtf?
3640 return luaL_error(L, "popup failed due to unknown results involving xmessage (%d)", r);
3641 }
3642
3643 use_console:
3644 #endif
3645
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);
3655
3656 fprintf(stderr, "Lua Message: %s\n", message);
3657
3658 while (true)
3659 {
3660 char buffer[64];
3661
3662 // We don't want parameters
3663 if (!t[0])
3664 {
3665 fprintf(stderr, "[Press Enter]");
3666 fgets(buffer, sizeof(buffer), stdin);
3667
3668 // We're done
3669 return 0;
3670 }
3671
3672 fprintf(stderr, "(%s): ", t);
3673 fgets(buffer, sizeof(buffer), stdin);
3674
3675 // Check if the option is in the list
3676 if (strchr(t, tolower(buffer[0])))
3677 {
3678 switch (tolower(buffer[0]))
3679 {
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");
3691 }
3692 }
3693
3694 // We fell through, so we assume the user answered wrong and prompt again.
3695 }
3696
3697 // Nothing here, since the only way out is in the loop.
3698 #endif
3699 }
3700
3701 #if (defined(WIN32) && !defined(SDL))
3702 const char *s_keyToName[256] =
3703 {
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
3804
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,
3811
3812 // then this would return {W=true, leftclick=true, xmouse=255, ymouse=223}
3813 static int input_getcurrentinputstatus(lua_State *L)
3814 {
3815 lua_newtable(L);
3816
3817 #if (defined(WIN32) && !defined(SDL))
3818 // keyboard and mouse button status
3819 {
3820 unsigned char keys[256];
3821 if (true /*!GUI.BackgroundInput*/) // TODO: background input
3822 {
3823 if (GetKeyboardState(keys))
3824 {
3825 for (int i = 1; i < 255; i++)
3826 {
3827 int mask = (i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL) ? 0x01 : 0x80;
3828 if (keys[i] & mask)
3829 {
3830 const char *name = s_keyToName[i];
3831 if (name)
3832 {
3833 lua_pushboolean(L, true);
3834 lua_setfield(L, -2, name);
3835 }
3836 }
3837 }
3838 }
3839 }
3840 else // use a slightly different method that will detect background input:
3841 {
3842 for (int i = 1; i < 255; i++)
3843 {
3844 const char *name = s_keyToName[i];
3845 if (name)
3846 {
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)
3853 {
3854 lua_pushboolean(L, true);
3855 lua_setfield(L, -2, name);
3856 }
3857 }
3858 }
3859 }
3860 }
3861
3862 // mouse position in game screen pixel coordinates
3863 {
3864 POINT mouse;
3865
3866 int xofs = 0, yofs = 0, width = 240, height = 160;
3867 if (!systemIsRunningGBA())
3868 {
3869 if (gbBorderOn)
3870 width = 256, height = 224, xofs = 48, yofs = 40;
3871 else
3872 width = 160, height = 144;
3873 }
3874
3875 GetCursorPos(&mouse);
3876 AfxGetApp()->m_pMainWnd->ScreenToClient(&mouse);
3877
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);
3882
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;
3887
3888 lua_pushinteger(L, mouse.x);
3889 lua_setfield(L, -2, "xmouse");
3890 lua_pushinteger(L, mouse.y);
3891 lua_setfield(L, -2, "ymouse");
3892 }
3893
3894 #else
3895 // NYI (well, return an empty table)
3896 #endif
3897 return 1;
3898 }
3899
3900 static int avi_framecount(lua_State *L)
3901 {
3902 #ifdef WIN32
3903 if (theApp.aviRecorder != NULL)
3904 {
3905 lua_pushinteger(L, theApp.aviRecorder->videoFrames());
3906 }
3907 else
3908 #endif
3909 {
3910 lua_pushinteger(L, 0);
3911 }
3912 return 1;
3913 }
3914
3915 static int avi_pause(lua_State *L)
3916 {
3917 #ifdef WIN32
3918 if (theApp.aviRecorder != NULL)
3919 theApp.aviRecorder->Pause(true);
3920 #endif
3921 return 1;
3922 }
3923
3924 static int avi_resume(lua_State *L)
3925 {
3926 #ifdef WIN32
3927 if (theApp.aviRecorder != NULL)
3928 theApp.aviRecorder->Pause(false);
3929 #endif
3930 return 1;
3931 }
3932
3933 static int sound_get(lua_State *L)
3934 {
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];
3952
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;
3982
3983 const int32 _soundVIN = 0x88; // gba ? 0x88 : soundVIN;
3984 const bool soundVINLeft = ((_soundVIN & 0x80) != 0);
3985 const bool soundVINRight = ((_soundVIN & 0x08) != 0);
3986
3987 lua_newtable(L);
3988
3989 // square1
3990 lua_newtable(L);
3991 if(sound1On == 0 || soundMasterOn == 0)
3992 {
3993 lua_pushnumber(L, 0.0);
3994 panpot = 0.5;
3995 }
3996 else
3997 {
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);
4012 }
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)
4032 {
4033 lua_pushnumber(L, 0.0);
4034 panpot = 0.5;
4035 }
4036 else
4037 {
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);
4052 }
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)
4072 {
4073 lua_pushnumber(L, 0.0);
4074 panpot = 0.5;
4075 }
4076 else
4077 {
4078 double envVolume;
4079 if (gba && sound3ForcedOutput != 0)
4080 envVolume = 0.75;
4081 else
4082 {
4083 double volTable[4] = { 0.0, 1.0, 0.5, 0.25 };
4084 envVolume = volTable[sound3OutputLevel & 3];
4085 }
4086
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);
4100 }
4101 lua_setfield(L, -2, "volume");
4102 lua_pushnumber(L, panpot);
4103 lua_setfield(L, -2, "panpot");
4104 int waveMemSamples = 32;
4105 if (gba)
4106 {
4107 lua_pushlstring(L, (const char *) &sound3WaveRam[sound3Bank * 0x10], sound3DataSize ? 0x20 : 0x10);
4108 waveMemSamples = sound3DataSize ? 64 : 32;
4109 }
4110 else
4111 {
4112 lua_pushlstring(L, (const char *) &gbMem[rWAVE_RAM], 0x10);
4113 }
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)
4129 {
4130 lua_pushnumber(L, 0.0);
4131 panpot = 0.5;
4132 }
4133 else
4134 {
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);
4149 }
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");
4167
4168 return 1;
4169 }
4170
4171 // same as math.random, but uses SFMT instead of C rand()
4172 // FIXME: this function doesn't care multi-instance,
4173
4174 // original math.random either though (Lua 5.1)
4175 static int sfmt_random(lua_State *L)
4176 {
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;
4184 }
4185
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;
4192 }
4193
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;
4201 }
4202
4203 default:
4204 return luaL_error(L, "wrong number of arguments");
4205 }
4206
4207 return 1;
4208 }
4209
4210 // same as math.randomseed, but uses SFMT instead of C srand()
4211 // FIXME: this function doesn't care multi-instance,
4212
4213 // original math.randomseed either though (Lua 5.1)
4214 static int sfmt_randomseed(lua_State *L)
4215 {
4216 init_gen_rand(luaL_checkint(L, 1));
4217 return 0;
4218 }
4219
4220 // the following bit operations are ported from LuaBitOp 1.0.1,
4221 // because it can handle the sign bit (bit 31) correctly.
4222
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 */
4250
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
4259
4260 typedef int32_t SBits;
4261 typedef uint32_t UBits;
4262
4263 typedef union
4264 {
4265 lua_Number n;
4266 #ifdef LUA_NUMBER_DOUBLE
4267 uint64_t b;
4268 #else
4269 UBits b;
4270 #endif
4271 } BitNum;
4272
4273 /* Convert argument to bit type. */
4274 static UBits barg(lua_State *L, int idx)
4275 {
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;
4301 }
4302
4303 /* Return bit type. */
4304 #define BRET(b) lua_pushnumber(L, (lua_Number)(SBits)(b)); return 1;
4305
4306 static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) }
4307 static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) }
4308
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, ^= )
4316
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)
4330
4331 static int bit_bswap(lua_State *L)
4332 {
4333 UBits b = barg(L, 1);
4334 b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24);
4335 BRET(b)
4336 }
4337
4338 static int bit_tohex(lua_State *L)
4339 {
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; )
4348 {
4349 buf[i] = hexdigits[b & 15]; b >>= 4;
4350 }
4351 lua_pushlstring(L, buf, (size_t)n);
4352 return 1;
4353 }
4354
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 };
4370
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)
4376
4377 bool luabitop_validate(lua_State *L) // originally named as luaopen_bit
4378 {
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. */
4383 {
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;
4397 }
4398 return true;
4399 }
4400
4401 // LuaBitOp ends here
4402
4403 static int bit_bshift_emulua(lua_State *L)
4404 {
4405 int shift = luaL_checkinteger(L, 2);
4406 if (shift < 0)
4407 {
4408 lua_pushinteger(L, -shift);
4409 lua_replace(L, 2);
4410 return bit_lshift(L);
4411 }
4412 else
4413 return bit_rshift(L);
4414 }
4415
4416 static int bitbit(lua_State *L)
4417 {
4418 int rv = 0;
4419 int numArgs = lua_gettop(L);
4420 for (int i = 1; i <= numArgs; i++)
4421 {
4422 int where = luaL_checkinteger(L, i);
4423 if (where >= 0 && where < 32)
4424 rv |= (1 << where);
4425 }
4426 lua_settop(L, 0);
4427 BRET(rv);
4428 }
4429
4430 // The function called periodically to ensure Lua doesn't run amok.
4431 static void VBALuaHookFunction(lua_State *L, lua_Debug *dbg)
4432 {
4433 if (numTries-- == 0)
4434 {
4435 int kill = 0;
4436
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);
4445
4446 if (ret == IDYES)
4447 {
4448 kill = 1;
4449 }
4450
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");
4455
4456 char buffer[64];
4457 while (true)
4458 {
4459 fprintf(stderr, "(y/n): ");
4460 fgets(buffer, sizeof(buffer), stdin);
4461 if (buffer[0] == 'y' || buffer[0] == 'Y')
4462 {
4463 kill = 1;
4464 break;
4465 }
4466
4467 if (buffer[0] == 'n' || buffer[0] == 'N')
4468 break;
4469 }
4470 #endif
4471 if (kill)
4472 {
4473 luaL_error(L, "Killed by user request.");
4474 VBALuaOnStop();
4475 }
4476
4477 // else, kill the debug hook.
4478 lua_sethook(L, NULL, 0, 0);
4479 }
4480 }
4481
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 };
4497
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 },
4518
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 },
4540
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 },
4549
4550 { NULL, NULL }
4551 };
4552
4553 static const struct luaL_reg joypadlib[] = {
4554 { "get", joypad_get },
4555 { "getdown", joypad_getdown },
4556 { "getup", joypad_getup },
4557 { "set", joypad_set },
4558
4559 // alternative names
4560 { "read", joypad_get },
4561 { "write", joypad_set },
4562 { "readdown", joypad_getdown },
4563 { "readup", joypad_getup },
4564 { NULL, NULL }
4565 };
4566
4567 static const struct luaL_reg savestatelib[] = {
4568 { "create", savestate_create },
4569 { "save", savestate_save },
4570 { "load", savestate_load },
4571
4572 { NULL, NULL }
4573 };
4574
4575 static const struct luaL_reg movielib[] = {
4576 { "active", movie_isactive },
4577 { "recording", movie_isrecording },
4578 { "playing", movie_isplaying },
4579 { "mode", movie_getmode },
4580
4581 { "length", movie_getlength },
4582 { "author", movie_getauthor },
4583 { "name", movie_getfilename },
4584 { "rerecordcount", movie_rerecordcount },
4585 { "setrerecordcount", movie_setrerecordcount },
4586
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()
4593
4594 { "stop", movie_stop },
4595
4596 // alternative names
4597 { "close", movie_stop },
4598 { "getauthor", movie_getauthor },
4599 { "getname", movie_getfilename },
4600 { NULL, NULL }
4601 };
4602
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 },
4616
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 };
4631
4632 static const struct luaL_reg inputlib[] = {
4633 { "get", input_getcurrentinputstatus },
4634
4635 // alternative names
4636 { "read", input_getcurrentinputstatus },
4637 { NULL, NULL }
4638 };
4639
4640 static const struct luaL_reg soundlib[] = {
4641 { "get", sound_get },
4642
4643 // alternative names
4644 { NULL, NULL }
4645 };
4646
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 };
4655
4656 void CallExitFunction(void)
4657 {
4658 if (!LUA)
4659 return;
4660
4661 lua_settop(LUA, 0);
4662 lua_getfield(LUA, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
4663
4664 int errorcode = 0;
4665 if (lua_isfunction(LUA, -1))
4666 {
4667 errorcode = lua_pcall(LUA, 0, 0, 0);
4668 }
4669
4670 if (errorcode)
4671 HandleCallbackError(LUA);
4672 }
4673
4674 void VBALuaFrameBoundary(void)
4675 {
4676 // printf("Lua Frame\n");
4677
4678 lua_joypads_used = 0;
4679
4680 // HA!
4681 if (!LUA || !luaRunning)
4682 return;
4683
4684 // Our function needs calling
4685 lua_settop(LUA, 0);
4686 lua_getfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
4687
4688 lua_State *thread = lua_tothread(LUA, 1);
4689
4690 // Lua calling C must know that we're busy inside a frame boundary
4691 frameBoundary = true;
4692 frameAdvanceWaiting = false;
4693
4694 numTries = 1000;
4695
4696 int result = lua_resume(thread, 0);
4697
4698 if (result == LUA_YIELD)
4699 {
4700 // Okay, we're fine with that.
4701 }
4702 else if (result != 0)
4703 {
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);
4710
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);
4719 }
4720 else
4721 {
4722 VBALuaOnStop();
4723 printf("Script died of natural causes.\n");
4724 }
4725
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;
4729
4730 if (!frameAdvanceWaiting)
4731 {
4732 VBALuaOnStop();
4733 }
4734 }
4735
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.
4740 *
4741 * Returns true on success, false on failure.
4742 */
4743 int VBALoadLuaCode(const char *filename)
4744 {
4745 static bool sfmtInitialized = false;
4746 if (!sfmtInitialized)
4747 {
4748 init_gen_rand((unsigned)time(NULL));
4749 sfmtInitialized = true;
4750 }
4751
4752 if (filename != luaScriptName)
4753 {
4754 if (luaScriptName)
4755 free(luaScriptName);
4756 luaScriptName = strdup(filename);
4757 }
4758
4759 //stop any lua we might already have had running
4760 VBALuaStop();
4761
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)
4771 {
4772 slash[1] = '\0'; // keep slash itself for some reasons
4773 chdir(dir);
4774 }
4775
4776 if (!LUA)
4777 {
4778 LUA = lua_open();
4779 luaL_openlibs(LUA);
4780
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
4793
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);
4799
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);
4806
4807 luabitop_validate(LUA);
4808
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);
4816
4817 // push arrays for storing hook functions in
4818 for (int i = 0; i < LUAMEMHOOK_COUNT; i++)
4819 {
4820 lua_newtable(LUA);
4821 lua_setfield(LUA, LUA_REGISTRYINDEX, luaMemHookTypeStrings[i]);
4822 }
4823 }
4824
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);
4828
4829 // Load the data
4830 int result = luaL_loadfile(LUA, filename);
4831
4832 if (result)
4833 {
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);
4841
4842 // Wipe the stack. Our thread
4843 lua_settop(LUA, 0);
4844 return 0; // Oh shit.
4845 }
4846
4847 // Get our function into it
4848 lua_xmove(LUA, thread, 1);
4849
4850 // Save the thread to the registry. This is why I make the thread FIRST.
4851 lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
4852
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);
4861
4862 // Set up our protection hook to be executed once every 10,000 bytecode instructions.
4863 lua_sethook(thread, VBALuaHookFunction, LUA_MASKCOUNT, 10000);
4864
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);
4880
4881 // And run it right now. :)
4882 VBALuaFrameBoundary();
4883 systemRenderFrame();
4884
4885 // We're done.
4886 return 1;
4887 }
4888
4889 /**
4890 * Equivalent to repeating the last VBALoadLuaCode() call.
4891 */
4892 int VBAReloadLuaCode(void)
4893 {
4894 if (!luaScriptName)
4895 {
4896 systemScreenMessage("There's no script to reload.");
4897 return 0;
4898 }
4899 else
4900 return VBALoadLuaCode(luaScriptName);
4901 }
4902
4903 /**
4904 * Terminates a running Lua script by killing the whole Lua engine.
4905 *
4906 * Always safe to call, except from within a lua call itself (duh).
4907 *
4908 */
4909 void VBALuaStop(void)
4910 {
4911 //already killed
4912 if (!LUA)
4913 return;
4914
4915 //execute the user's shutdown callbacks
4916 CallExitFunction();
4917
4918 /*info.*/ numMemHooks = 0;
4919 for (int i = 0; i < LUAMEMHOOK_COUNT; i++)
4920 CalculateMemHookRegions((LuaMemHookType)i);
4921
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
4927
4928 if (info_onstop)
4929 info_onstop(info_uid);
4930
4931 //lua_gc(LUA,LUA_GCCOLLECT,0);
4932 lua_close(LUA); // this invokes our garbage collectors for us
4933 LUA = NULL;
4934 VBALuaOnStop();
4935 }
4936
4937 /**
4938 * Returns true if there is a Lua script running.
4939 *
4940 */
4941 int VBALuaRunning(void)
4942 {
4943 // FIXME: return false when no callback functions are registered.
4944 return (int) (LUA != NULL); // should return true if callback functions are active.
4945 }
4946
4947 /**
4948 * Returns true if Lua would like to steal the given joypad control.
4949 *
4950 * Range is 0 through 3
4951 */
4952 int VBALuaUsingJoypad(int which)
4953 {
4954 if (which < 0 || which > 3)
4955 which = systemGetDefaultJoypad();
4956 return lua_joypads_used & (1 << which);
4957 }
4958
4959 /**
4960 * Reads the buttons Lua is feeding for the given joypad, in the same
4961 * format as the OS-specific code.
4962 *
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)
4967 {
4968 if (which < 0 || which > 3)
4969 which = systemGetDefaultJoypad();
4970
4971 //lua_joypads_used &= ~(1 << which);
4972 return lua_joypads[which];
4973 }
4974
4975 /**
4976 * If this function returns true, the movie code should NOT increment
4977 * the rerecord count for a load-state.
4978 *
4979 * This function will not return true if a script is not running.
4980 */
4981 bool8 VBALuaRerecordCountSkip(void)
4982 {
4983 // FIXME: return true if (there are any active callback functions && skipRerecords)
4984 return LUA && luaRunning && skipRerecords;
4985 }
4986
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)
4992 {
4993 if (!LUA /* || !luaRunning*/)
4994 return;
4995
4996 // First, check if we're being called by anybody
4997 lua_getfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
4998
4999 if (lua_isfunction(LUA, -1))
5000 {
5001 // We call it now
5002 numTries = 1000;
5003
5004 int ret = lua_pcall(LUA, 0, 0, 0);
5005 if (ret != 0)
5006 {
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);
5014
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);
5022 }
5023 }
5024
5025 // And wreak the stack
5026 lua_settop(LUA, 0);
5027
5028 if (!gui_used)
5029 return;
5030
5031 gui_used = false;
5032
5033 int x, y;
5034
5035 //int pitch = (((ppl * systemColorDepth + 7)>>3)+3)&~3;
5036 int pitch = ppl * (systemColorDepth / 8) + (systemColorDepth == 24 ? 0 : 4);
5037
5038 if (width > LUA_SCREEN_WIDTH)
5039 width = LUA_SCREEN_WIDTH;
5040 if (height > LUA_SCREEN_HEIGHT)
5041 height = LUA_SCREEN_HEIGHT;
5042
5043 GetColorFunc getColor;
5044 SetColorFunc setColor;
5045 getColorIOFunc(systemColorDepth, &getColor, &setColor);
5046
5047 for (y = 0; y < height; y++)
5048 {
5049 uint8 *scr = &screen[y * pitch];
5050 for (x = 0; x < width; x++, scr += systemColorDepth / 8)
5051 {
5052 const uint8 gui_alpha = gui_data[(y * LUA_SCREEN_WIDTH + x) * 4 + 3];
5053 if (gui_alpha == 0)
5054 {
5055 // do nothing
5056 continue;
5057 }
5058
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;
5063
5064 if (gui_alpha == 255)
5065 {
5066 // direct copy
5067 red = gui_red;
5068 green = gui_green;
5069 blue = gui_blue;
5070 }
5071 else
5072 {
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;
5079 }
5080
5081 setColor(scr, (uint8) red, (uint8) green, (uint8) blue);
5082 }
5083 }
5084
5085 return;
5086 }
5087
5088 void VBALuaClearGui(void)
5089 {
5090 gui_used = false;
5091 }
5092
5093 lua_State *VBAGetLuaState()
5094 {
5095 return LUA;
5096 }
5097
5098 char *VBAGetLuaScriptName()
5099 {
5100 return luaScriptName;
5101 }
5102