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