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