1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <malloc.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <algorithm>
7 #include <vector>
8 #include <assert.h>
9 #include <map>
10 #include <string>
11 
12 using std::min;
13 using std::max;
14 
15 #ifdef __linux
16 #include <unistd.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #endif
20 
21 extern "C" {
22 	#include "lua.h"
23 	#include "lauxlib.h"
24 	#include "lualib.h"
25 	#include "lstate.h"
26 }
27 
28 #include "burner.h"
29 #ifdef WIN32
30 #include <direct.h>
31 #include "win32/resource.h"
32 #endif
33 #include "luaengine.h"
34 #include "luasav.h"
35 #include "../cpu/m68000_intf.h"
36 #include "../cpu/z80/z80.h"
37 extern Z80_Regs Z80;
38 
39 #ifndef TRUE
40 #define TRUE 1
41 #define FALSE 0
42 #endif
43 
44 #ifndef inline
45 #define inline __inline
46 #endif
47 
48 static void(*info_print)(INT64 uid, const char* str);
49 static void(*info_onstart)(INT64 uid);
50 static void(*info_onstop)(INT64 uid);
51 static INT64 info_uid;
52 #ifdef WIN32
53 extern INT_PTR CALLBACK DlgLuaScriptDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
54 extern void PrintToWindowConsole(INT64 hDlgAsInt, const char* str);
55 extern void WinLuaOnStart(INT64 hDlgAsInt);
56 extern void WinLuaOnStop(INT64 hDlgAsInt);
57 #endif
58 
59 void EmulatorAppDoFast(bool dofast);
60 
61 static lua_State *LUA;
62 
63 // Screen
64 static UINT8 *XBuf;
65 static int iScreenWidth  = 320;
66 static int iScreenHeight = 240;
67 static int iScreenBpp    = 4;
68 static int iScreenPitch  = 1024;
69 static int LUA_SCREEN_WIDTH  = 320;
70 static int LUA_SCREEN_HEIGHT = 240;
71 
72 // Current working directory of the script
73 static char luaCWD [_MAX_PATH] = {0};
74 static char fbnCWD [_MAX_PATH] = {0};
75 
76 // Are we running any code right now?
77 static char *luaScriptName = NULL;
78 
79 // Are we running any code right now?
80 static int luaRunning = FALSE;
81 
82 // True at the frame boundary, false otherwise.
83 static int frameBoundary = FALSE;
84 
85 // The execution speed we're running at.
86 static enum {SPEED_NORMAL, SPEED_NOTHROTTLE, SPEED_TURBO, SPEED_MAXIMUM} speedmode = SPEED_NORMAL;
87 
88 // Rerecord count skip mode
89 static int skipRerecords = FALSE;
90 
91 // Used by the registry to find our functions
92 static const char *frameAdvanceThread = "FBA.FrameAdvance";
93 static const char *guiCallbackTable = "FBA.GUI";
94 
95 // True if there's a thread waiting to run after a run of frame-advance.
96 static int frameAdvanceWaiting = FALSE;
97 
98 // Transparency strength. 255=opaque, 0=so transparent it's invisible
99 static int transparencyModifier = 255;
100 
101 // Our joypads.
102 static short lua_joypads[0x0100];
103 static UINT8 lua_joypads_used;
104 
105 static UINT8 gui_enabled = TRUE;
106 static enum { GUI_USED_SINCE_LAST_DISPLAY, GUI_USED_SINCE_LAST_FRAME, GUI_CLEAR } gui_used = GUI_CLEAR;
107 static UINT8 *gui_data = NULL;
108 
109 static int MAX_TRIES = 1500;
110 
111 // Protects Lua calls from going nuts.
112 // We set this to a big number like MAX_TRIES and decrement it
113 // over time. The script gets knifed once this reaches zero.
114 static int numTries;
115 
116 // number of registered memory functions (1 per hooked byte)
117 static unsigned int numMemHooks;
118 
119 #ifdef _MSC_VER
120 	#define snprintf _snprintf
121 	#define vscprintf _vscprintf
122 #else
123 	#define stricmp strcasecmp
124 	#define strnicmp strncasecmp
125 	#define __forceinline __attribute__((always_inline))
126 #endif
127 
128 static const char* luaCallIDStrings [] =
129 {
130 	"CALL_BEFOREEMULATION",
131 	"CALL_AFTEREMULATION",
132 	"CALL_BEFOREEXIT",
133 	"CALL_ONSTART",
134 
135 	"CALL_HOTKEY_1",
136 	"CALL_HOTKEY_2",
137 	"CALL_HOTKEY_3",
138 	"CALL_HOTKEY_4",
139 	"CALL_HOTKEY_5",
140 	"CALL_HOTKEY_6",
141 	"CALL_HOTKEY_7",
142 	"CALL_HOTKEY_8",
143 	"CALL_HOTKEY_9",
144 };
145 
146 static char* rawToCString(lua_State* L, int idx=0);
147 static const char* toCString(lua_State* L, int idx=0);
148 
149 static const char* luaMemHookTypeStrings [] =
150 {
151 	"MEMHOOK_WRITE",
152 	"MEMHOOK_READ",
153 	"MEMHOOK_EXEC",
154 
155 	"MEMHOOK_WRITE_SUB",
156 	"MEMHOOK_READ_SUB",
157 	"MEMHOOK_EXEC_SUB",
158 };
159 //static const int _makeSureWeHaveTheRightNumberOfStrings2 [sizeof(luaMemHookTypeStrings)/sizeof(*luaMemHookTypeStrings) == LUAMEMHOOK_COUNT ? 1 : 0];
160 
161 /**
162  * Resets emulator speed / pause states after script exit.
163  * (Actually, FBA doesn't do any of these. They were very annoying.)
164  */
FBA_LuaOnStop()165 static void FBA_LuaOnStop() {
166 	luaRunning = FALSE;
167 	lua_joypads_used = 0;
168 	gui_used = GUI_CLEAR;
169 }
170 
171 
172 /**
173  * Asks Lua if it wants control of the emulator's speed.
174  * Returns 0 if no, 1 if yes. If yes, caller should also
175  * consult FBA_LuaFrameSkip().
176  */
FBA_LuaSpeed()177 int FBA_LuaSpeed() {
178 	if (!LUA || !luaRunning)
179 		return 0;
180 
181 	switch (speedmode) {
182 	case SPEED_NOTHROTTLE:
183 	case SPEED_TURBO:
184 	case SPEED_MAXIMUM:
185 		return 1;
186 	case SPEED_NORMAL:
187 	default:
188 		return 0;
189 	}
190 }
191 
192 
193 /**
194  * Asks Lua if it wants control whether this frame is skipped.
195  * Returns 0 if no, 1 if frame should be skipped, -1 if it should not be.
196  */
FBA_LuaFrameSkip()197 int FBA_LuaFrameSkip() {
198 	if (!LUA || !luaRunning)
199 		return 0;
200 
201 	switch (speedmode) {
202 	case SPEED_NORMAL:
203 		return 0;
204 	case SPEED_NOTHROTTLE:
205 		return -1;
206 	case SPEED_TURBO:
207 		return 0;
208 	case SPEED_MAXIMUM:
209 		return 1;
210 	}
211 
212 	return 0;
213 }
214 
215 
216 ///////////////////////////
217 
218 // fba.hardreset()
fba_hardreset(lua_State * L)219 static int fba_hardreset(lua_State *L) {
220 	StartFromReset(NULL);
221 	return 1;
222 }
223 
224 // string fba.romname()
225 //
226 //   Returns the name of the running game.
fba_romname(lua_State * L)227 static int fba_romname(lua_State *L) {
228 	lua_pushstring(L, BurnDrvGetTextA(DRV_NAME));
229 	return 1;
230 }
231 
232 // string fba.gamename()
233 //
234 //   Returns the name of the source file for the running game.
fba_gamename(lua_State * L)235 static int fba_gamename(lua_State *L) {
236 	lua_pushstring(L, BurnDrvGetTextA(DRV_FULLNAME));
237 	return 1;
238 }
239 
240 // string fba.parentname()
241 //
242 //   Returns the name of the source file for the running game.
fba_parentname(lua_State * L)243 static int fba_parentname(lua_State *L) {
244 	if (BurnDrvGetTextA(DRV_PARENT))
245 		lua_pushstring(L, BurnDrvGetTextA(DRV_PARENT));
246 	else
247 		lua_pushstring(L, "0");
248 	return 1;
249 }
250 
251 // string fba.sourcename()
252 //
253 //   Returns the name of the source file for the running game.
fba_sourcename(lua_State * L)254 static int fba_sourcename(lua_State *L) {
255 	if (BurnDrvGetTextA(DRV_BOARDROM))
256 		lua_pushstring(L, BurnDrvGetTextA(DRV_BOARDROM));
257 	else
258 		lua_pushstring(L, BurnDrvGetTextA(DRV_SYSTEM));
259 	return 1;
260 }
261 
262 // fba.speedmode(string mode)
263 //
264 //   Takes control of the emulation speed
265 //   of the system. Normal is normal speed (60fps, 50 for PAL),
266 //   nothrottle disables speed control but renders every frame,
267 //   turbo renders only a few frames in order to speed up emulation,
268 //   maximum renders no frames
fba_speedmode(lua_State * L)269 static int fba_speedmode(lua_State *L) {
270 	const char *mode = luaL_checkstring(L,1);
271 
272 	if (strcmp(mode, "normal")==0) {
273 		speedmode = SPEED_NORMAL;
274 		EmulatorAppDoFast(0);
275 	} else if (strcmp(mode, "turbo")==0) {
276 		speedmode = SPEED_TURBO;
277 		EmulatorAppDoFast(1);
278 	} else
279 		luaL_error(L, "Invalid mode %s to fba.speedmode",mode);
280 
281 	return 0;
282 }
283 
284 
285 // fba.frameadvance()
286 //
287 //  Executes a frame advance. Occurs by yielding the coroutine, then re-running
288 //  when we break out.
fba_frameadvance(lua_State * L)289 static int fba_frameadvance(lua_State *L) {
290 	// We're going to sleep for a frame-advance. Take notes.
291 
292 	if (frameAdvanceWaiting)
293 		return luaL_error(L, "can't call fba.frameadvance() from here");
294 
295 	frameAdvanceWaiting = TRUE;
296 
297 	// Now we can yield to the main
298 	return lua_yield(L, 0);
299 }
300 
301 
302 // fba.pause()
303 //
304 //  Pauses the emulator, function "waits" until the user unpauses.
305 //  This function MAY be called from a non-frame boundary, but the frame
306 //  finishes executing anyways. In this case, the function returns immediately.
fba_pause(lua_State * L)307 static int fba_pause(lua_State *L) {
308 	SetPauseMode(1);
309 	speedmode = SPEED_NORMAL;
310 
311 	// If it's on a frame boundary, we also yield.
312 	frameAdvanceWaiting = TRUE;
313 	return lua_yield(L, 0);
314 }
315 
316 
317 // fba.unpause()
fba_unpause(lua_State * L)318 static int fba_unpause(lua_State *L) {
319 	SetPauseMode(0);
320 
321 	return lua_yield(L, 0);
322 }
323 
324 // int fba.screenwidth()
325 //
326 //   Gets the screen width
fba_screenwidth(lua_State * L)327 int fba_screenwidth(lua_State *L) {
328 	lua_pushinteger(L, iScreenWidth);
329 	return 1;
330 }
331 // int fba.screenheight()
332 //
333 //   Gets the screen height
fba_screenheight(lua_State * L)334 int fba_screenheight(lua_State *L) {
335 	lua_pushinteger(L, iScreenHeight);
336 	return 1;
337 }
338 
isalphaorunderscore(char c)339 static inline bool isalphaorunderscore(char c)
340 {
341 	return isalpha(c) || c == '_';
342 }
343 
344 static std::vector<const void*> s_tableAddressStack; // prevents infinite recursion of a table within a table (when cycle is found, print something like table:parent)
345 static std::vector<const void*> s_metacallStack; // prevents infinite recursion if something's __tostring returns another table that contains that something (when cycle is found, print the inner result without using __tostring)
346 
347 #define APPENDPRINT { int _n = snprintf(ptr, remaining,
348 #define END ); if(_n >= 0) { ptr += _n; remaining -= _n; } else { remaining = 0; } }
toCStringConverter(lua_State * L,int i,char * & ptr,int & remaining)349 static void toCStringConverter(lua_State* L, int i, char*& ptr, int& remaining)
350 {
351 	if(remaining <= 0)
352 		return;
353 
354 //	const char* str = ptr; // for debugging
355 
356 	// if there is a __tostring metamethod then call it
357 	int usedMeta = luaL_callmeta(L, i, "__tostring");
358 	if(usedMeta)
359 	{
360 		std::vector<const void*>::const_iterator foundCycleIter = std::find(s_metacallStack.begin(), s_metacallStack.end(), lua_topointer(L,i));
361 		if(foundCycleIter != s_metacallStack.end())
362 		{
363 			lua_pop(L, 1);
364 			usedMeta = false;
365 		}
366 		else
367 		{
368 			s_metacallStack.push_back(lua_topointer(L,i));
369 			i = lua_gettop(L);
370 		}
371 	}
372 
373 	switch(lua_type(L, i))
374 	{
375 		case LUA_TNONE: break;
376 		case LUA_TNIL: APPENDPRINT "nil" END break;
377 		case LUA_TBOOLEAN: APPENDPRINT lua_toboolean(L,i) ? "true" : "false" END break;
378 		case LUA_TSTRING: APPENDPRINT "%s",lua_tostring(L,i) END break;
379 		case LUA_TNUMBER: APPENDPRINT "%.12g",lua_tonumber(L,i) END break;
380 		case LUA_TFUNCTION:
381 			if((L->base + i-1)->value.gc->cl.c.isC)
382 			{
383 				//lua_CFunction func = lua_tocfunction(L, i);
384 				//std::map<lua_CFunction, const char*>::iterator iter = s_cFuncInfoMap.find(func);
385 				//if(iter == s_cFuncInfoMap.end())
386 					goto defcase;
387 				//APPENDPRINT "function(%s)", iter->second END
388 			}
389 			else
390 			{
391 				APPENDPRINT "function(" END
392 				Proto* p = (L->base + i-1)->value.gc->cl.l.p;
393 				int numParams = p->numparams + (p->is_vararg?1:0);
394 				for (int n=0; n<p->numparams; n++)
395 				{
396 					APPENDPRINT "%s", getstr(p->locvars[n].varname) END
397 					if(n != numParams-1)
398 						APPENDPRINT "," END
399 				}
400 				if(p->is_vararg)
401 					APPENDPRINT "..." END
402 				APPENDPRINT ")" END
403 			}
404 			break;
405 defcase:default: APPENDPRINT "%s:%p",luaL_typename(L,i),lua_topointer(L,i) END break;
406 		case LUA_TTABLE:
407 		{
408 			// first make sure there's enough stack space
409 			if(!lua_checkstack(L, 4))
410 			{
411 				// note that even if lua_checkstack never returns false,
412 				// that doesn't mean we didn't need to call it,
413 				// because calling it retrieves stack space past LUA_MINSTACK
414 				goto defcase;
415 			}
416 
417 			std::vector<const void*>::const_iterator foundCycleIter = std::find(s_tableAddressStack.begin(), s_tableAddressStack.end(), lua_topointer(L,i));
418 			if(foundCycleIter != s_tableAddressStack.end())
419 			{
420 				int parentNum = s_tableAddressStack.end() - foundCycleIter;
421 				if(parentNum > 1)
422 					APPENDPRINT "%s:parent^%d",luaL_typename(L,i),parentNum END
423 				else
424 					APPENDPRINT "%s:parent",luaL_typename(L,i) END
425 			}
426 			else
427 			{
428 				s_tableAddressStack.push_back(lua_topointer(L,i));
429 //				struct Scope { ~Scope(){ s_tableAddressStack.pop_back(); } } scope;
430 
431 				APPENDPRINT "{" END
432 
433 				lua_pushnil(L); // first key
434 				int keyIndex = lua_gettop(L);
435 				int valueIndex = keyIndex + 1;
436 				bool first = true;
437 				bool skipKey = true; // true if we're still in the "array part" of the table
438 				lua_Number arrayIndex = (lua_Number)0;
439 				while(lua_next(L, i))
440 				{
441 					if(first)
442 						first = false;
443 					else
444 						APPENDPRINT ", " END
445 					if(skipKey)
446 					{
447 						arrayIndex += (lua_Number)1;
448 						bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER);
449 						skipKey = keyIsNumber && (lua_tonumber(L, keyIndex) == arrayIndex);
450 					}
451 					if(!skipKey)
452 					{
453 						bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING);
454 						bool invalidLuaIdentifier = (!keyIsString || !isalphaorunderscore(*lua_tostring(L, keyIndex)));
455 						if(invalidLuaIdentifier) {
456 							if(keyIsString)
457 								APPENDPRINT "['" END
458 							else
459 								APPENDPRINT "[" END
460 						}
461 
462 						toCStringConverter(L, keyIndex, ptr, remaining); // key
463 
464 						if(invalidLuaIdentifier)
465 							if(keyIsString)
466 								APPENDPRINT "']=" END
467 							else
468 								APPENDPRINT "]=" END
469 						else
470 							APPENDPRINT "=" END
471 					}
472 
473 					bool valueIsString = (lua_type(L, valueIndex) == LUA_TSTRING);
474 					if(valueIsString)
475 						APPENDPRINT "'" END
476 
477 					toCStringConverter(L, valueIndex, ptr, remaining); // value
478 
479 					if(valueIsString)
480 						APPENDPRINT "'" END
481 
482 					lua_pop(L, 1);
483 
484 					if(remaining <= 0)
485 					{
486 						lua_settop(L, keyIndex-1); // stack might not be clean yet if we're breaking early
487 						break;
488 					}
489 				}
490 				APPENDPRINT "}" END
491 			}
492 		}	break;
493 	}
494 
495 	if(usedMeta)
496 	{
497 		s_metacallStack.pop_back();
498 		lua_pop(L, 1);
499 	}
500 }
501 
502 static const int s_tempStrMaxLen = 64 * 1024;
503 static char s_tempStr [s_tempStrMaxLen];
504 
rawToCString(lua_State * L,int idx)505 static char* rawToCString(lua_State* L, int idx)
506 {
507 	int a = idx>0 ? idx : 1;
508 	int n = idx>0 ? idx : lua_gettop(L);
509 
510 	char* ptr = s_tempStr;
511 	*ptr = 0;
512 
513 	int remaining = s_tempStrMaxLen;
514 	for(int i = a; i <= n; i++)
515 	{
516 		toCStringConverter(L, i, ptr, remaining);
517 		if(i != n)
518 			APPENDPRINT " " END
519 	}
520 
521 	if(remaining < 3)
522 	{
523 		while(remaining < 6)
524 			remaining++, ptr--;
525 		APPENDPRINT "..." END
526 	}
527 	APPENDPRINT "\r\n" END
528 	// the trailing newline is so print() can avoid having to do wasteful things to print its newline
529 	// (string copying would be wasteful and calling info.print() twice can be extremely slow)
530 	// at the cost of functions that don't want the newline needing to trim off the last two characters
531 	// (which is a very fast operation and thus acceptable in this case)
532 
533 	return s_tempStr;
534 }
535 #undef APPENDPRINT
536 #undef END
537 
538 
539 // replacement for luaB_tostring() that is able to show the contents of tables (and formats numbers better, and show function prototypes)
540 // can be called directly from lua via tostring(), assuming tostring hasn't been reassigned
tostring(lua_State * L)541 static int tostring(lua_State *L)
542 {
543 	char* str = rawToCString(L);
544 	str[strlen(str)-2] = 0; // hack: trim off the \r\n (which is there to simplify the print function's task)
545 	lua_pushstring(L, str);
546 	return 1;
547 }
548 
549 // like rawToCString, but will check if the global Lua function tostring()
550 // has been replaced with a custom function, and call that instead if so
toCString(lua_State * L,int idx)551 static const char* toCString(lua_State* L, int idx)
552 {
553 	int a = idx>0 ? idx : 1;
554 	int n = idx>0 ? idx : lua_gettop(L);
555 	lua_getglobal(L, "tostring");
556 	lua_CFunction cf = lua_tocfunction(L,-1);
557 	if(cf == tostring) // optimization: if using our own C tostring function, we can bypass the call through Lua and all the string object allocation that would entail
558 	{
559 		lua_pop(L,1);
560 		return rawToCString(L, idx);
561 	}
562 	else // if the user overrided the tostring function, we have to actually call it and store the temporarily allocated string it returns
563 	{
564 		lua_pushstring(L, "");
565 		for (int i=a; i<=n; i++) {
566 			lua_pushvalue(L, -2);  // function to be called
567 			lua_pushvalue(L, i);   // value to print
568 			lua_call(L, 1, 1);
569 			if(lua_tostring(L, -1) == NULL)
570 				luaL_error(L, LUA_QL("tostring") " must return a string to " LUA_QL("print"));
571 			lua_pushstring(L, (i<n) ? " " : "\r\n");
572 			lua_concat(L, 3);
573 		}
574 		const char* str = lua_tostring(L, -1);
575 		strncpy(s_tempStr, str, s_tempStrMaxLen);
576 		s_tempStr[s_tempStrMaxLen-1] = 0;
577 		lua_pop(L, 2);
578 		return s_tempStr;
579 	}
580 }
581 
582 // replacement for luaB_print() that goes to the appropriate textbox instead of stdout
print(lua_State * L)583 static int print(lua_State *L)
584 {
585 	const char* str = toCString(L);
586 
587 	int uid = info_uid;//luaStateToUIDMap[L->l_G->mainthread];
588 	//LuaContextInfo& info = GetCurrentInfo();
589 
590 	if(info_print)
591 		info_print(uid, str);
592 	else
593 		puts(str);
594 
595 	//worry(L, 100);
596 	return 0;
597 }
598 
599 char fba_message_buffer[1024];
600 // fba.message(string msg)
601 //
602 //  Displays the given message on the screen.
fba_message(lua_State * L)603 static int fba_message(lua_State *L) {
604 	const char *msg = luaL_checkstring(L,1);
605 	sprintf(fba_message_buffer, "%s", msg);
606 	VidSNewTinyMsg(_AtoT(fba_message_buffer));
607 
608 	return 0;
609 }
610 
611 // provides an easy way to copy a table from Lua
612 // (simple assignment only makes an alias, but sometimes an independent table is desired)
613 // currently this function only performs a shallow copy,
614 // but I think it should be changed to do a deep copy (possibly of configurable depth?)
615 // that maintains the internal table reference structure
copytable(lua_State * L)616 static int copytable(lua_State *L)
617 {
618 	int origIndex = 1; // we only care about the first argument
619 	int origType = lua_type(L, origIndex);
620 	if(origType == LUA_TNIL)
621 	{
622 		lua_pushnil(L);
623 		return 1;
624 	}
625 	if(origType != LUA_TTABLE)
626 	{
627 		luaL_typerror(L, 1, lua_typename(L, LUA_TTABLE));
628 		lua_pushnil(L);
629 		return 1;
630 	}
631 
632 	lua_createtable(L, lua_objlen(L,1), 0);
633 	int copyIndex = lua_gettop(L);
634 
635 	lua_pushnil(L); // first key
636 	int keyIndex = lua_gettop(L);
637 	int valueIndex = keyIndex + 1;
638 
639 	while(lua_next(L, origIndex))
640 	{
641 		lua_pushvalue(L, keyIndex);
642 		lua_pushvalue(L, valueIndex);
643 		lua_rawset(L, copyIndex); // copytable[key] = value
644 		lua_pop(L, 1);
645 	}
646 
647 	// copy the reference to the metatable as well, if any
648 	if(lua_getmetatable(L, origIndex))
649 		lua_setmetatable(L, copyIndex);
650 
651 	return 1; // return the new table
652 }
653 
654 // because print traditionally shows the address of tables,
655 // and the print function I provide instead shows the contents of tables,
656 // I also provide this function
657 // (otherwise there would be no way to see a table's address, AFAICT)
addressof(lua_State * L)658 static int addressof(lua_State *L)
659 {
660 	const void* ptr = lua_topointer(L,-1);
661 	lua_pushinteger(L, (lua_Integer)ptr);
662 	return 1;
663 }
664 
fba_registerbefore(lua_State * L)665 static int fba_registerbefore(lua_State *L) {
666 	if (!lua_isnil(L,1))
667 		luaL_checktype(L, 1, LUA_TFUNCTION);
668 	lua_settop(L,1);
669 	lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]);
670 	lua_insert(L,1);
671 	lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEMULATION]);
672 	return 1;
673 }
674 
675 
fba_registerafter(lua_State * L)676 static int fba_registerafter(lua_State *L) {
677 	if (!lua_isnil(L,1))
678 		luaL_checktype(L, 1, LUA_TFUNCTION);
679 	lua_settop(L,1);
680 	lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]);
681 	lua_insert(L,1);
682 	lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_AFTEREMULATION]);
683 	return 1;
684 }
685 
686 
fba_registerexit(lua_State * L)687 static int fba_registerexit(lua_State *L) {
688 	if (!lua_isnil(L,1))
689 		luaL_checktype(L, 1, LUA_TFUNCTION);
690 	lua_settop(L,1);
691 	lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
692 	lua_insert(L,1);
693 	lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
694 	return 1;
695 }
696 
fba_registerstart(lua_State * L)697 static int fba_registerstart(lua_State *L) {
698 	if (!lua_isnil(L,1))
699 		luaL_checktype(L, 1, LUA_TFUNCTION);
700 	lua_settop(L,1);
701 	lua_getfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_ONSTART]);
702 	lua_insert(L,1);
703 	lua_pushvalue(L,-1); // copy the function so we can also call it
704 	lua_setfield(L, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_ONSTART]);
705 	if (!lua_isnil(L,-1))
706 		lua_call(L,0,0); // call the function now since the game has already started and this start function hasn't been called yet
707 	return 1;
708 }
709 
710 
711 
HandleCallbackError(lua_State * L)712 void HandleCallbackError(lua_State* L)
713 {
714 	//if(L->errfunc || L->errorJmp)
715 	//      luaL_error(L, "%s", lua_tostring(L,-1));
716 	//else
717 	{
718 		lua_pushnil(L);
719 		lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable);
720 
721 		// Error?
722 #ifdef WIN32
723 		MessageBoxA(hScrnWnd, lua_tostring(L,-1), "Lua run error", MB_OK | MB_ICONSTOP);
724 #else
725 		fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(L,-1));
726 #endif
727 
728 		FBA_LuaStop();
729 	}
730 }
731 
732 
733 // the purpose of this structure is to provide a way of
734 // QUICKLY determining whether a memory address range has a hook associated with it,
735 // with a bias toward fast rejection because the majority of addresses will not be hooked.
736 // (it must not use any part of Lua or perform any per-script operations,
737 //  otherwise it would definitely be too slow.)
738 // calculating the regions when a hook is added/removed may be slow,
739 // but this is an intentional tradeoff to obtain a high speed of checking during later execution
740 struct TieredRegion
741 {
742 	template<unsigned int maxGap>
743 	struct Region
744 	{
745 		struct Island
746 		{
747 			unsigned int start;
748 			unsigned int end;
ContainsTieredRegion::Region::Island749 			__forceinline bool Contains(unsigned int address, int size) const { return address < end && address+size > start; }
750 		};
751 		std::vector<Island> islands;
752 
CalculateTieredRegion::Region753 		void Calculate(const std::vector<unsigned int>& bytes)
754 		{
755 			islands.clear();
756 
757 			unsigned int lastEnd = ~0;
758 
759 			std::vector<unsigned int>::const_iterator iter = bytes.begin();
760 			std::vector<unsigned int>::const_iterator end = bytes.end();
761 			for(; iter != end; ++iter)
762 			{
763 				unsigned int addr = *iter;
764 				if(addr < lastEnd || addr > lastEnd + (long long)maxGap)
765 				{
766 					islands.push_back(Island());
767 					islands.back().start = addr;
768 				}
769 				islands.back().end = addr+1;
770 				lastEnd = addr+1;
771 			}
772 		}
773 
ContainsTieredRegion::Region774 		bool Contains(unsigned int address, int size) const
775 		{
776 			typename std::vector<Island>::const_iterator iter = islands.begin();
777 			typename std::vector<Island>::const_iterator end = islands.end();
778 			for(; iter != end; ++iter)
779 				if(iter->Contains(address, size))
780 					return true;
781 			return false;
782 		}
783 	};
784 
785 	Region<0xFFFFFFFF> broad;
786 	Region<0x1000> mid;
787 	Region<0> narrow;
788 
CalculateTieredRegion789 	void Calculate(std::vector<unsigned int>& bytes)
790 	{
791 		std::sort(bytes.begin(), bytes.end());
792 
793 		broad.Calculate(bytes);
794 		mid.Calculate(bytes);
795 		narrow.Calculate(bytes);
796 	}
797 
TieredRegionTieredRegion798 	TieredRegion()
799 	{
800 //		Calculate(std::vector<unsigned int>()); // TODO: this doesn't compile... So I wrote the next two lines (I should learn C++)
801 		std::vector<unsigned int> bytes;
802 		Calculate(bytes);
803 	}
804 
NotEmptyTieredRegion805 	__forceinline int NotEmpty()
806 	{
807 		return broad.islands.size();
808 	}
809 
810 	// note: it is illegal to call this if NotEmpty() returns 0
ContainsTieredRegion811 	__forceinline bool Contains(unsigned int address, int size)
812 	{
813 		return broad.islands[0].Contains(address,size) &&
814 		       mid.Contains(address,size) &&
815 			   narrow.Contains(address,size);
816 	}
817 };
818 TieredRegion hookedRegions [LUAMEMHOOK_COUNT];
819 
820 
CalculateMemHookRegions(LuaMemHookType hookType)821 static void CalculateMemHookRegions(LuaMemHookType hookType)
822 {
823 	std::vector<unsigned int> hookedBytes;
824 //      std::map<int, LuaContextInfo*>::iterator iter = luaContextInfo.begin();
825 //      std::map<int, LuaContextInfo*>::iterator end = luaContextInfo.end();
826 //      while(iter != end)
827 //      {
828 //              LuaContextInfo& info = *iter->second;
829 		if(/*info.*/ numMemHooks)
830 		{
831 //                      lua_State* L = info.L;
832 			if(LUA)
833 			{
834 				lua_settop(LUA, 0);
835 				lua_getfield(LUA, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
836 				lua_pushnil(LUA);
837 				while(lua_next(LUA, -2))
838 				{
839 					if(lua_isfunction(LUA, -1))
840 					{
841 						unsigned int addr = lua_tointeger(LUA, -2);
842 						hookedBytes.push_back(addr);
843 					}
844 					lua_pop(LUA, 1);
845 				}
846 				lua_settop(LUA, 0);
847 			}
848 		}
849 //              ++iter;
850 //      }
851 	hookedRegions[hookType].Calculate(hookedBytes);
852 }
853 
CallRegisteredLuaMemHook_LuaMatch(unsigned int address,int size,unsigned int value,LuaMemHookType hookType)854 static void CallRegisteredLuaMemHook_LuaMatch(unsigned int address, int size, unsigned int value, LuaMemHookType hookType)
855 {
856 //      std::map<int, LuaContextInfo*>::iterator iter = luaContextInfo.begin();
857 //      std::map<int, LuaContextInfo*>::iterator end = luaContextInfo.end();
858 //      while(iter != end)
859 //      {
860 //              LuaContextInfo& info = *iter->second;
861 		if(/*info.*/ numMemHooks)
862 		{
863 //                      lua_State* L = info.L;
864 			if(LUA/* && !info.panic*/)
865 			{
866 #ifdef USE_INFO_STACK
867 				infoStack.insert(infoStack.begin(), &info);
868 				struct Scope { ~Scope(){ infoStack.erase(infoStack.begin()); } } scope;
869 #endif
870 				lua_settop(LUA, 0);
871 				lua_getfield(LUA, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
872 				for(int i = address; i != address+size; i++)
873 				{
874 					lua_rawgeti(LUA, -1, i);
875 					if (lua_isfunction(LUA, -1))
876 					{
877 						bool wasRunning = (luaRunning!=0) /*info.running*/;
878 						luaRunning /*info.running*/ = true;
879 						//RefreshScriptSpeedStatus();
880 						lua_pushinteger(LUA, address);
881 						lua_pushinteger(LUA, size);
882 						int errorcode = lua_pcall(LUA, 2, 0, 0);
883 						luaRunning /*info.running*/ = wasRunning;
884 						//RefreshScriptSpeedStatus();
885 						if (errorcode)
886 						{
887 							HandleCallbackError(LUA);
888 							//int uid = iter->first;
889 							//HandleCallbackError(LUA,info,uid,true);
890 						}
891 						break;
892 					}
893 					else
894 					{
895 						lua_pop(LUA,1);
896 					}
897 				}
898 				lua_settop(LUA, 0);
899 			}
900 		}
901 //		++iter;
902 //	}
903 }
CallRegisteredLuaMemHook(unsigned int address,int size,unsigned int value,LuaMemHookType hookType)904 void CallRegisteredLuaMemHook(unsigned int address, int size, unsigned int value, LuaMemHookType hookType)
905 {
906 	// performance critical! (called VERY frequently)
907 	// I suggest timing a large number of calls to this function in Release if you change anything in here,
908 	// before and after, because even the most innocent change can make it become 30% to 400% slower.
909 	// a good amount to test is: 100000000 calls with no hook set, and another 100000000 with a hook set.
910 	// (on my system that consistently took 200 ms total in the former case and 350 ms total in the latter case)
911 	if(hookedRegions[hookType].NotEmpty())
912 	{
913 		//if((hookType <= LUAMEMHOOK_EXEC) && (address >= 0xE00000))
914 		//      address |= 0xFF0000; // account for mirroring of RAM
915 		if(hookedRegions[hookType].Contains(address, size))
916 			CallRegisteredLuaMemHook_LuaMatch(address, size, value, hookType); // something has hooked this specific address
917 	}
918 }
919 
CallRegisteredLuaFunctions(LuaCallID calltype)920 void CallRegisteredLuaFunctions(LuaCallID calltype)
921 {
922 	assert((unsigned int)calltype < (unsigned int)LUACALL_COUNT);
923 	const char* idstring = luaCallIDStrings[calltype];
924 
925 	if (!LUA)
926 		return;
927 
928 	lua_settop(LUA, 0);
929 	lua_getfield(LUA, LUA_REGISTRYINDEX, idstring);
930 
931 	int errorcode = 0;
932 	if (lua_isfunction(LUA, -1))
933 	{
934 		chdir(luaCWD);
935 		errorcode = lua_pcall(LUA, 0, 0, 0);
936 		chdir(fbnCWD);
937 		if (errorcode)
938 			HandleCallbackError(LUA);
939 	}
940 	else
941 	{
942 		lua_pop(LUA, 1);
943 	}
944 }
945 
946 
947 
948 
is_little_endian(lua_State * L,int argn)949 static int is_little_endian(lua_State *L,int argn)
950 {
951 	int littleEndian;
952 	if(lua_gettop(L) >= argn)
953 		littleEndian = lua_toboolean(L,argn);
954 	else
955 		littleEndian = 0;
956 	return littleEndian;
957 }
958 
memory_readbyte(lua_State * L)959 static int memory_readbyte(lua_State *L)
960 {
961 	lua_pushinteger(L, ReadValueAtHardwareAddress(luaL_checkinteger(L,1),1,0));
962 	return 1;
963 }
964 
memory_readbytesigned(lua_State * L)965 static int memory_readbytesigned(lua_State *L) {
966 	signed char c = (signed char)ReadValueAtHardwareAddress(luaL_checkinteger(L,1),1,0);
967 	lua_pushinteger(L, c);
968 	return 1;
969 }
970 
memory_readword(lua_State * L)971 static int memory_readword(lua_State *L)
972 {
973 	lua_pushinteger(L, ReadValueAtHardwareAddress(luaL_checkinteger(L,1),2,is_little_endian(L,2)));
974 	return 1;
975 }
976 
memory_readwordsigned(lua_State * L)977 static int memory_readwordsigned(lua_State *L) {
978 	signed short c = (signed short)ReadValueAtHardwareAddress(luaL_checkinteger(L,1),2,is_little_endian(L,2));
979 	lua_pushinteger(L, c);
980 	return 1;
981 }
982 
memory_readdword(lua_State * L)983 static int memory_readdword(lua_State *L)
984 {
985 	UINT32 addr = luaL_checkinteger(L,1);
986 	UINT32 val = ReadValueAtHardwareAddress(addr,4,is_little_endian(L,2));
987 
988 	// lua_pushinteger doesn't work properly for 32bit system, does it?
989 	if (val >= 0x80000000 && sizeof(int) <= 4)
990 		lua_pushnumber(L, val);
991 	else
992 		lua_pushinteger(L, val);
993 	return 1;
994 }
995 
memory_readdwordsigned(lua_State * L)996 static int memory_readdwordsigned(lua_State *L) {
997 	UINT32 addr = luaL_checkinteger(L,1);
998 	INT32 val = (INT32)ReadValueAtHardwareAddress(addr,4,is_little_endian(L,2));
999 
1000 	lua_pushinteger(L, val);
1001 	return 1;
1002 }
1003 
memory_readbyterange(lua_State * L)1004 static int memory_readbyterange(lua_State *L) {
1005 	int a,n;
1006 	UINT32 address = luaL_checkinteger(L,1);
1007 	int length = luaL_checkinteger(L,2);
1008 
1009 	if(length < 0)
1010 	{
1011 		address += length;
1012 		length = -length;
1013 	}
1014 
1015 	// push the array
1016 	lua_createtable(L, abs(length), 0);
1017 
1018 	// put all the values into the (1-based) array
1019 	for(a = address, n = 1; n <= length; a++, n++)
1020 	{
1021 		unsigned char value = ReadValueAtHardwareAddress(a,1,0);
1022 		lua_pushinteger(L, value);
1023 		lua_rawseti(L, -2, n);
1024 	}
1025 
1026 	return 1;
1027 }
1028 
memory_writebyte(lua_State * L)1029 static int memory_writebyte(lua_State *L)
1030 {
1031 	WriteValueAtHardwareAddress(luaL_checkinteger(L,1), luaL_checkinteger(L,2),1,0);
1032 	return 0;
1033 }
1034 
memory_writeword(lua_State * L)1035 static int memory_writeword(lua_State *L)
1036 {
1037 	WriteValueAtHardwareAddress(luaL_checkinteger(L,1), luaL_checkinteger(L,2),2,is_little_endian(L,3));
1038 	return 0;
1039 }
1040 
memory_writedword(lua_State * L)1041 static int memory_writedword(lua_State *L)
1042 {
1043 	WriteValueAtHardwareAddress(luaL_checkinteger(L,1), luaL_checkinteger(L,2),4,is_little_endian(L,3));
1044 	return 0;
1045 }
1046 
1047 
memory_registerHook(lua_State * L,LuaMemHookType hookType,int defaultSize)1048 static int memory_registerHook(lua_State* L, LuaMemHookType hookType, int defaultSize)
1049 {
1050 	// get first argument: address
1051 	unsigned int addr = luaL_checkinteger(L,1);
1052 	if((addr & ~0xFFFFFFFF) == ~0xFFFFFFFF)
1053 		addr &= 0xFFFFFFFF;
1054 
1055 	// get optional second argument: size
1056 	int size = defaultSize;
1057 	int funcIdx = 2;
1058 	if(lua_isnumber(L,2))
1059 	{
1060 		size = luaL_checkinteger(L,2);
1061 		if(size < 0)
1062 		{
1063 			size = -size;
1064 			addr -= size;
1065 		}
1066 		funcIdx++;
1067 	}
1068 
1069 	// check last argument: callback function
1070 	bool clearing = lua_isnil(L,funcIdx);
1071 	if(!clearing)
1072 		luaL_checktype(L, funcIdx, LUA_TFUNCTION);
1073 	lua_settop(L,funcIdx);
1074 
1075 	// get the address-to-callback table for this hook type of the current script
1076 	lua_getfield(L, LUA_REGISTRYINDEX, luaMemHookTypeStrings[hookType]);
1077 
1078 	// count how many callback functions we'll be displacing
1079 	int numFuncsAfter = clearing ? 0 : size;
1080 	int numFuncsBefore = 0;
1081 	for(unsigned int i = addr; i != addr+size; i++)
1082 	{
1083 		lua_rawgeti(L, -1, i);
1084 		if(lua_isfunction(L, -1))
1085 			numFuncsBefore++;
1086 		lua_pop(L,1);
1087 	}
1088 
1089 	// put the callback function in the address slots
1090 	for(unsigned int i = addr; i != addr+size; i++)
1091 	{
1092 		lua_pushvalue(L, -2);
1093 		lua_rawseti(L, -2, i);
1094 	}
1095 
1096 	// adjust the count of active hooks
1097 	//LuaContextInfo& info = GetCurrentInfo();
1098 	/*info.*/ numMemHooks += numFuncsAfter - numFuncsBefore;
1099 
1100 	// re-cache regions of hooked memory across all scripts
1101 	CalculateMemHookRegions(hookType);
1102 
1103 	//StopScriptIfFinished(luaStateToUIDMap[L]);
1104 	return 0;
1105 }
1106 
MatchHookTypeToCPU(lua_State * L,LuaMemHookType hookType)1107 LuaMemHookType MatchHookTypeToCPU(lua_State* L, LuaMemHookType hookType)
1108 {
1109 	int cpuID = 0;
1110 
1111 	int cpunameIndex = 0;
1112 	if(lua_type(L,2) == LUA_TSTRING)
1113 		cpunameIndex = 2;
1114 	else if(lua_type(L,3) == LUA_TSTRING)
1115 		cpunameIndex = 3;
1116 
1117 	if(cpunameIndex)
1118 	{
1119 		const char* cpuName = lua_tostring(L, cpunameIndex);
1120 		if(!_stricmp(cpuName, "sub"))
1121 			cpuID = 1;
1122 		lua_remove(L, cpunameIndex);
1123 	}
1124 
1125 	switch(cpuID)
1126 	{
1127 	case 0:
1128 		return hookType;
1129 
1130 	case 1:
1131 		switch(hookType)
1132 		{
1133 		case LUAMEMHOOK_WRITE: return LUAMEMHOOK_WRITE_SUB;
1134 		case LUAMEMHOOK_READ: return LUAMEMHOOK_READ_SUB;
1135 		case LUAMEMHOOK_EXEC: return LUAMEMHOOK_EXEC_SUB;
1136 		}
1137 	}
1138 	return hookType;
1139 }
1140 
memory_registerwrite(lua_State * L)1141 static int memory_registerwrite(lua_State *L)
1142 {
1143 	return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_WRITE), 1);
1144 }
memory_registerread(lua_State * L)1145 static int memory_registerread(lua_State *L)
1146 {
1147 	return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_READ), 1);
1148 }
memory_registerexec(lua_State * L)1149 static int memory_registerexec(lua_State *L)
1150 {
1151 	return memory_registerHook(L, MatchHookTypeToCPU(L,LUAMEMHOOK_EXEC), 1);
1152 }
1153 
1154 
1155 struct registerPointerMap
1156 {
1157 	const char* registerName;
1158 	unsigned int* pointer;
1159 	int dataSize;
1160 };
1161 
1162 #define RPM_ENTRY(name,var) {name, (unsigned int*)&var, sizeof(var)},
1163 
1164 registerPointerMap m68000RegPointerMap [] = {
1165 	/*
1166 	RPM_ENTRY("pc", M68000_regs.pc)
1167 	RPM_ENTRY("d0", M68000_regs.d[0])
1168 	RPM_ENTRY("d1", M68000_regs.d[1])
1169 	RPM_ENTRY("d2", M68000_regs.d[2])
1170 	RPM_ENTRY("d3", M68000_regs.d[3])
1171 	RPM_ENTRY("d4", M68000_regs.d[4])
1172 	RPM_ENTRY("d5", M68000_regs.d[5])
1173 	RPM_ENTRY("d6", M68000_regs.d[6])
1174 	RPM_ENTRY("d7", M68000_regs.d[7])
1175 	RPM_ENTRY("a0", M68000_regs.a[0])
1176 	RPM_ENTRY("a1", M68000_regs.a[1])
1177 	RPM_ENTRY("a2", M68000_regs.a[2])
1178 	RPM_ENTRY("a3", M68000_regs.a[3])
1179 	RPM_ENTRY("a4", M68000_regs.a[4])
1180 	RPM_ENTRY("a5", M68000_regs.a[5])
1181 	RPM_ENTRY("a6", M68000_regs.a[6])
1182 	RPM_ENTRY("a7", M68000_regs.a[7])
1183 	*/
1184 	{}
1185 };
1186 
1187 registerPointerMap z80RegPointerMap [] = {
1188 	/*	RPM_ENTRY("prvpc", Z80.prvpc.w.l)
1189 	RPM_ENTRY("pc", Z80.pc.w.l)
1190 	RPM_ENTRY("sp", Z80.sp.w.l)
1191 	RPM_ENTRY("af", Z80.af.w.l)
1192 	RPM_ENTRY("bc", Z80.bc.w.l)
1193 	RPM_ENTRY("de", Z80.de.w.l)
1194 	RPM_ENTRY("hl", Z80.hl.w.l)
1195 	RPM_ENTRY("ix", Z80.ix.w.l)
1196 	RPM_ENTRY("iy", Z80.iy.w.l)
1197 	*/
1198 	{}
1199 };
1200 
1201 struct cpuToRegisterMap
1202 {
1203 	const char* cpuName;
1204 	registerPointerMap* rpmap;
1205 }
1206 cpuToRegisterMaps [] =
1207 {
1208 	{"m68000.", m68000RegPointerMap},
1209 	{"z80.", z80RegPointerMap},
1210 };
1211 
1212 
1213 //DEFINE_LUA_FUNCTION(memory_getregister, "cpu_dot_registername_string")
memory_getregister(lua_State * L)1214 static int memory_getregister(lua_State *L)
1215 {
1216 	const char* qualifiedRegisterName = luaL_checkstring(L,1);
1217 	lua_settop(L,0);
1218 	for(int cpu = 0; cpu < sizeof(cpuToRegisterMaps)/sizeof(*cpuToRegisterMaps); cpu++)
1219 	{
1220 		cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
1221 		int cpuNameLen = strlen(ctrm.cpuName);
1222 		if(!strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen))
1223 		{
1224 			qualifiedRegisterName += cpuNameLen;
1225 			for(int reg = 0; ctrm.rpmap[reg].dataSize; reg++)
1226 			{
1227 				registerPointerMap rpm = ctrm.rpmap[reg];
1228 				if(!stricmp(qualifiedRegisterName, rpm.registerName))
1229 				{
1230 					switch(rpm.dataSize)
1231 					{ default:
1232 					case 1: lua_pushinteger(L, *(unsigned char*)rpm.pointer); break;
1233 					case 2: lua_pushinteger(L, *(unsigned short*)rpm.pointer); break;
1234 					case 4: lua_pushinteger(L, *(unsigned long*)rpm.pointer); break;
1235 					}
1236 					return 1;
1237 				}
1238 			}
1239 			lua_pushnil(L);
1240 			return 1;
1241 		}
1242 	}
1243 	lua_pushnil(L);
1244 	return 1;
1245 }
1246 //DEFINE_LUA_FUNCTION(memory_setregister, "cpu_dot_registername_string,value")
memory_setregister(lua_State * L)1247 static int memory_setregister(lua_State *L)
1248 {
1249 	const char* qualifiedRegisterName = luaL_checkstring(L,1);
1250 	unsigned long value = (unsigned long)(luaL_checkinteger(L,2));
1251 	lua_settop(L,0);
1252 	for(int cpu = 0; cpu < sizeof(cpuToRegisterMaps)/sizeof(*cpuToRegisterMaps); cpu++)
1253 	{
1254 		cpuToRegisterMap ctrm = cpuToRegisterMaps[cpu];
1255 		int cpuNameLen = strlen(ctrm.cpuName);
1256 		if(!_strnicmp(qualifiedRegisterName, ctrm.cpuName, cpuNameLen))
1257 		{
1258 			qualifiedRegisterName += cpuNameLen;
1259 			for(int reg = 0; ctrm.rpmap[reg].dataSize; reg++)
1260 			{
1261 				registerPointerMap rpm = ctrm.rpmap[reg];
1262 				if(!stricmp(qualifiedRegisterName, rpm.registerName))
1263 				{
1264 					switch(rpm.dataSize)
1265 					{ default:
1266 					case 1: *(unsigned char*)rpm.pointer = (unsigned char)(value & 0xFF); break;
1267 					case 2: *(unsigned short*)rpm.pointer = (unsigned short)(value & 0xFFFF); break;
1268 					case 4: *(unsigned long*)rpm.pointer = value; break;
1269 					}
1270 					return 0;
1271 				}
1272 			}
1273 			return 0;
1274 		}
1275 	}
1276 	return 0;
1277 }
1278 
1279 // table joypad.read()
1280 //
1281 //  Reads the joypads as inputted by the user.
joy_get_internal(lua_State * L,bool reportUp,bool reportDown)1282 static int joy_get_internal(lua_State *L, bool reportUp, bool reportDown) {
1283 	unsigned int i = 0;
1284 	struct GameInp* pgi = NULL;
1285 	unsigned short nThisVal;
1286 
1287 	lua_newtable(L);
1288 
1289 	// Update the values of all the inputs
1290 	for (i = 0, pgi = GameInp; i < nGameInpCount; i++, pgi++) {
1291 		if (pgi->nType == 0) {
1292 			continue;
1293 		}
1294 		struct BurnInputInfo bii;
1295 
1296 		// Get the name of the input
1297 		bii.szName = NULL;
1298 		BurnDrvGetInputInfo(&bii, i);
1299 
1300 		// skip unused inputs
1301 		if (bii.pVal == NULL) {
1302 			continue;
1303 		}
1304 		if (bii.szName == NULL)	{
1305 			bii.szName = "";
1306 		}
1307 
1308 		nThisVal = *pgi->Input.pVal;
1309 		bool pressed = nThisVal != 0;
1310 		if ((pressed && reportDown) || (!pressed && reportUp)) {
1311 			if (bii.nType & BIT_DIGITAL && !(bii.nType & BIT_GROUP_CONSTANT))
1312 				lua_pushboolean(L,pressed);
1313 			else
1314 				lua_pushinteger(L,nThisVal);
1315 			lua_setfield(L, -2, bii.szName);
1316 		}
1317 	}
1318 	return 1;
1319 }
1320 // joypad.get(which)
1321 // returns a table of every game button,
1322 // true meaning currently-held and false meaning not-currently-held
1323 // (as of last frame boundary)
1324 // this WILL read input from a currently-playing movie
joypad_get(lua_State * L)1325 static int joypad_get(lua_State *L)
1326 {
1327 	return joy_get_internal(L, true, true);
1328 }
1329 // joypad.getdown(which)
1330 // returns a table of every game button that is currently held
joypad_getdown(lua_State * L)1331 static int joypad_getdown(lua_State *L)
1332 {
1333 	return joy_get_internal(L, false, true);
1334 }
1335 // joypad.getup(which)
1336 // returns a table of every game button that is not currently held
joypad_getup(lua_State * L)1337 static int joypad_getup(lua_State *L)
1338 {
1339 	return joy_get_internal(L, true, false);
1340 }
1341 
1342 // joypad.set(table buttons)
1343 //
1344 //   Sets the given buttons to be pressed during the next
1345 //   frame advance. The table should have the right
1346 //   keys (no pun intended) set.
joypad_set(lua_State * L)1347 static int joypad_set(lua_State *L) {
1348 	struct GameInp* pgi = NULL;
1349 	unsigned int i;
1350 
1351 	// table of buttons.
1352 	luaL_checktype(L,1,LUA_TTABLE);
1353 
1354 	// Set up for taking control of the indicated controller
1355 	lua_joypads_used = 1;
1356 	memset(lua_joypads,0,sizeof(lua_joypads));
1357 
1358 	// Update the values of all the inputs
1359 	for (i = 0, pgi = GameInp; i < nGameInpCount; i++, pgi++) {
1360 		if (pgi->nType == 0) {
1361 			continue;
1362 		}
1363 		struct BurnInputInfo bii;
1364 
1365 		// Get the name of the input
1366 		bii.szName = NULL;
1367 		BurnDrvGetInputInfo(&bii, i);
1368 
1369 		// skip unused inputs
1370 		if (bii.pVal == NULL) {
1371 			continue;
1372 		}
1373 		if (bii.szName == NULL)	{
1374 			bii.szName = "";
1375 		}
1376 
1377 		lua_getfield(L, 1, bii.szName);
1378 		if (!lua_isnil(L,-1)) {
1379 			if (bii.nType & BIT_DIGITAL && !(bii.nType & BIT_GROUP_CONSTANT)) {
1380 				if (lua_toboolean(L,-1))
1381 					lua_joypads[i] = 1; // pressed
1382 				else
1383 					lua_joypads[i] = 2; // unpressed
1384 			}
1385 			else {
1386 				lua_joypads[i] = lua_tonumber(L, -1);
1387 			}
1388 //			dprintf(_T("*JOYPAD*: '%s' : %d\n"),_AtoT(bii.szName),lua_joypads[i]);
1389 		}
1390 		lua_pop(L,1);
1391 	}
1392 
1393 	return 0;
1394 }
1395 
1396 
1397 #ifdef WIN32
1398 char szSavestateFilename[MAX_PATH];
1399 
GetSavestateFilename(int nSlot)1400 char *GetSavestateFilename(int nSlot) {
1401 	sprintf(szSavestateFilename, "./savestates/%s slot %02x.fs", BurnDrvGetTextA(DRV_NAME), nSlot);
1402 	return szSavestateFilename;
1403 }
1404 #endif
1405 
1406 
luasav_save(const char * filename)1407 void luasav_save(const char *filename) {
1408 	LuaSaveData saveData;
1409 	char luaSaveFilename[512];
1410 	char slotnum[512];
1411 	char* filenameEnd;
1412 
1413 	const char *posa = strrchr(filename, '/') ;
1414 	const char *posb = strrchr(filename, '\\');
1415 	const char *pos = posa > posb ? posa : posb;
1416 	if (pos) {
1417 		sprintf(luaSaveFilename, "%s.luasav", filename);
1418 		strncpy(slotnum, pos+1, strlen(pos));
1419 		filenameEnd = strrchr(slotnum, '.');
1420 		filenameEnd[0] = '\0';
1421 		strcpy(slotnum, filenameEnd-1);
1422 
1423 		// call savestate.save callback if any and store the results in a luasav file if any
1424 		CallRegisteredLuaSaveFunctions(slotnum, saveData);
1425 		if (saveData.recordList) {
1426 			FILE* luaSaveFile = fopen(luaSaveFilename, "wb");
1427 			if(luaSaveFile) {
1428 				saveData.ExportRecords(luaSaveFile);
1429 				fclose(luaSaveFile);
1430 			}
1431 		}
1432 		else {
1433 			unlink(luaSaveFilename);
1434 		}
1435 	}
1436 }
1437 
luasav_load(const char * filename)1438 void luasav_load(const char *filename) {
1439 	LuaSaveData saveData;
1440 	char luaSaveFilename[512];
1441 	char slotnum[512];
1442 	char* filenameEnd;
1443 
1444 	const char *posa = strrchr(filename, '/') ;
1445 	const char *posb = strrchr(filename, '\\');
1446 	const char *pos = posa > posb ? posa : posb;
1447 	if (pos) {
1448 		sprintf(luaSaveFilename, "%s.luasav", filename);
1449 		strncpy(slotnum, pos+1, strlen(pos));
1450 		filenameEnd = strrchr(slotnum, '.');
1451 		filenameEnd[0] = '\0';
1452 		strcpy(slotnum, filenameEnd-1);
1453 
1454 		// call savestate.registerload callback if any
1455 		// and pass it the result from the previous savestate.registerload callback to the same state if any
1456 		FILE* luaSaveFile = fopen(luaSaveFilename, "rb");
1457 		if (luaSaveFile) {
1458 			saveData.ImportRecords(luaSaveFile);
1459 			fclose(luaSaveFile);
1460 		}
1461 		CallRegisteredLuaLoadFunctions(slotnum, saveData);
1462 	}
1463 }
1464 
1465 
1466 // Helper function to convert a savestate object to the filename it represents.
savestateobj2filename(lua_State * L,int offset)1467 static char *savestateobj2filename(lua_State *L, int offset) {
1468 	// First we get the metatable of the indicated object
1469 	int result = lua_getmetatable(L, offset);
1470 
1471 	if (!result)
1472 		luaL_error(L, "object not a savestate object");
1473 
1474 	// Also check that the type entry is set
1475 	lua_getfield(L, -1, "__metatable");
1476 	if (strcmp(lua_tostring(L,-1), "FBA Savestate") != 0)
1477 		luaL_error(L, "object not a savestate object");
1478 	lua_pop(L,1);
1479 
1480 	// Now, get the field we want
1481 	lua_getfield(L, -1, "filename");
1482 
1483 	// Return it
1484 	return (char *) lua_tostring(L, -1);
1485 }
1486 
1487 
1488 // Helper function for garbage collection.
savestate_gc(lua_State * L)1489 static int savestate_gc(lua_State *L) {
1490 	const char *filename;
1491 
1492 	// The object we're collecting is on top of the stack
1493 	lua_getmetatable(L,1);
1494 
1495 	// Get the filename
1496 	lua_getfield(L, -1, "filename");
1497 	filename = lua_tostring(L,-1);
1498 
1499 	// Delete the file
1500 	remove(filename);
1501 
1502 	// We exit, and the garbage collector takes care of the rest.
1503 	return 0;
1504 }
1505 
1506 // object savestate.create(int which = nil)
1507 //
1508 //  Creates an object used for savestates.
1509 //  The object can be associated with a player-accessible savestate
1510 //  ("which" between 1 and 10) or not (which == nil).
savestate_create(lua_State * L)1511 static int savestate_create(lua_State *L) {
1512 	const char *filename;
1513 	bool anonymous = false;
1514 
1515 	if (lua_gettop(L) >= 1)
1516 		if (lua_isstring(L,1))
1517 			filename = luaL_checkstring(L,1);
1518 		else
1519 			filename = GetSavestateFilename(luaL_checkinteger(L,1));
1520 	else {
1521 		filename = tempnam(NULL, "snlua");
1522 		anonymous = true;
1523 	}
1524 
1525 	// Our "object". We don't care about the type, we just need the memory and GC services.
1526 	lua_newuserdata(L,1);
1527 
1528 	// The metatable we use, protected from Lua and contains garbage collection info and stuff.
1529 	lua_newtable(L);
1530 
1531 	// First, we must protect it
1532 	lua_pushstring(L, "FBA Savestate");
1533 	lua_setfield(L, -2, "__metatable");
1534 
1535 	// Now we need to save the file itself.
1536 	lua_pushstring(L, filename);
1537 	lua_setfield(L, -2, "filename");
1538 
1539 	// If it's an anonymous savestate, we must delete the file from disk should it be gargage collected
1540 	if (anonymous) {
1541 		lua_pushcfunction(L, savestate_gc);
1542 		lua_setfield(L, -2, "__gc");
1543 	}
1544 
1545 	// Set the metatable
1546 	lua_setmetatable(L, -2);
1547 
1548 	// Awesome. Return the object
1549 	return 1;
1550 }
1551 
1552 
1553 // savestate.save(object state)
1554 //
1555 //   Saves a state to the given object.
savestate_save(lua_State * L)1556 static int savestate_save(lua_State *L) {
1557 	const char *filename;
1558 
1559 	if (lua_type(L,1) == LUA_TUSERDATA)
1560 		filename = savestateobj2filename(L,1);
1561 	else if (lua_isstring(L,1))
1562 		filename = luaL_checkstring(L,1);
1563 	else
1564 		filename = GetSavestateFilename(luaL_checkinteger(L,1));
1565 
1566 	// Save states are very expensive. They take time.
1567 	numTries--;
1568 
1569 	BurnStateSave(_AtoT(filename), 1);
1570 	return 0;
1571 }
1572 
1573 // savestate.load(object state)
1574 //
1575 //   Loads the given state
savestate_load(lua_State * L)1576 static int savestate_load(lua_State *L) {
1577 	const char *filename;
1578 
1579 	if (lua_type(L,1) == LUA_TUSERDATA)
1580 		filename = savestateobj2filename(L,1);
1581 	else if (lua_isstring(L,1))
1582 		filename = luaL_checkstring(L,1);
1583 	else
1584 		filename = GetSavestateFilename(luaL_checkinteger(L,1));
1585 
1586 	numTries--;
1587 
1588 	BurnStateLoad(_AtoT(filename), 1, &DrvInitCallback);
1589 	return 0;
1590 }
1591 
savestate_registersave(lua_State * L)1592 static int savestate_registersave(lua_State *L) {
1593 	lua_settop(L,1);
1594 	if (!lua_isnil(L,1))
1595 		luaL_checktype(L, 1, LUA_TFUNCTION);
1596 	lua_getfield(L, LUA_REGISTRYINDEX, LUA_SAVE_CALLBACK_STRING);
1597 	lua_pushvalue(L,1);
1598 	lua_setfield(L, LUA_REGISTRYINDEX, LUA_SAVE_CALLBACK_STRING);
1599 	return 1;
1600 }
1601 
savestate_registerload(lua_State * L)1602 static int savestate_registerload(lua_State *L) {
1603 	lua_settop(L,1);
1604 	if (!lua_isnil(L,1))
1605 		luaL_checktype(L, 1, LUA_TFUNCTION);
1606 	lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOAD_CALLBACK_STRING);
1607 	lua_pushvalue(L,1);
1608 	lua_setfield(L, LUA_REGISTRYINDEX, LUA_LOAD_CALLBACK_STRING);
1609 	return 1;
1610 }
1611 
savestate_loadscriptdata(lua_State * L)1612 static int savestate_loadscriptdata(lua_State *L) {
1613 	const char *filename;
1614 	LuaSaveData saveData;
1615 	char luaSaveFilename[512];
1616 	FILE* luaSaveFile;
1617 
1618 	if (lua_type(L,1) == LUA_TUSERDATA)
1619 		filename = savestateobj2filename(L,1);
1620 	else
1621 		filename = GetSavestateFilename(luaL_checkinteger(L,1));
1622 
1623 	sprintf(luaSaveFilename, "%s.luasav", filename);
1624 	luaSaveFile = fopen(luaSaveFilename, "rb");
1625 	if(luaSaveFile)
1626 	{
1627 		saveData.ImportRecords(luaSaveFile);
1628 		fclose(luaSaveFile);
1629 
1630 		lua_settop(L, 0);
1631 		saveData.LoadRecord(L, LUA_DATARECORDKEY, (unsigned int)-1);
1632 		return lua_gettop(L);
1633 	}
1634 	return 0;
1635 }
1636 
savestate_savescriptdata(lua_State * L)1637 static int savestate_savescriptdata(lua_State *L) {
1638 	const char *filename;
1639 
1640 	if (lua_type(L,1) == LUA_TUSERDATA)
1641 		filename = savestateobj2filename(L,1);
1642 	else
1643 		filename = GetSavestateFilename(luaL_checkinteger(L,1));
1644 
1645 	luasav_save(filename);
1646 	return 0;
1647 }
1648 
1649 extern unsigned int nStartFrame;
1650 // int movie.framecount()
1651 //
1652 //   Gets the frame counter for the movie
movie_framecount(lua_State * L)1653 int movie_framecount(lua_State *L) {
1654 	lua_pushinteger(L, GetCurrentFrame() - nStartFrame);
1655 	return 1;
1656 }
1657 
1658 
1659 // string movie.mode()
1660 //
1661 //   "record", "playback" or nil
movie_mode(lua_State * L)1662 int movie_mode(lua_State *L) {
1663 	if (nReplayStatus == 1)
1664 		lua_pushstring(L, "record");
1665 	else if (nReplayStatus == 2)
1666 		lua_pushstring(L, "playback");
1667 	else
1668 		lua_pushnil(L);
1669 	return 1;
1670 }
1671 
1672 
1673 // movie.setreadonly()
1674 //
1675 // sets the read-only flag
movie_setreadonly(lua_State * L)1676 static int movie_setreadonly(lua_State *L) {
1677 	bReplayReadOnly = (lua_toboolean( L, 1 ) == 1);
1678 
1679 	if (bReplayReadOnly)
1680 		VidSNewShortMsg(_T("read-only"));
1681 	else
1682 		VidSNewShortMsg(_T("read+write"));
1683 
1684 	return 0;
1685 }
1686 
1687 
1688 // movie.getreadonly()
1689 //
1690 // returns the state of the read-only flag
movie_getreadonly(lua_State * L)1691 static int movie_getreadonly(lua_State *L) {
1692 	lua_pushboolean(L, bReplayReadOnly);
1693 
1694 	return 1;
1695 }
1696 
1697 
movie_rerecordcounting(lua_State * L)1698 static int movie_rerecordcounting(lua_State *L) {
1699 	if (lua_gettop(L) == 0)
1700 		luaL_error(L, "no parameters specified");
1701 
1702 	skipRerecords = lua_toboolean(L,1);
1703 	return 0;
1704 }
1705 
1706 
1707 // movie.length()
1708 //
1709 //	Returns the total number of frames of a movie
movie_length(lua_State * L)1710 static int movie_length(lua_State *L) {
1711 #ifdef WIN32 //adelikat: GetTotalMovieFrames is a win32 only file, so this can only be implemented in win32
1712 	//lua_pushinteger(L, GetTotalMovieFrames());
1713 #endif
1714 	return 1;
1715 }
1716 
1717 
1718 // movie.stop()
1719 //
1720 //   Stops movie playback/recording. Bombs out if movie is not running.
movie_stop(lua_State * L)1721 static int movie_stop(lua_State *L) {
1722 	if (nReplayStatus == 0)
1723 		luaL_error(L, "no movie");
1724 
1725 	StopReplay();
1726 	return 0;
1727 }
1728 
1729 
1730 // movie.playbeginning()
1731 //
1732 // Restarts the movie from beginning
movie_playbeginning(lua_State * L)1733 static int movie_playbeginning(lua_State *L) {
1734 	//HK_playFromBeginning(0);
1735 	return 0;
1736 }
1737 
1738 
1739 // Common code by the gui library: make sure the screen array is ready
gui_prepare()1740 static void gui_prepare() {
1741 	int x,y;
1742 	if (!gui_data)
1743 		gui_data = (UINT8 *) malloc(LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4);
1744 	if (gui_used != GUI_USED_SINCE_LAST_DISPLAY) {
1745 		for (y = 0; y < LUA_SCREEN_HEIGHT; y++) {
1746 			for (x=0; x < LUA_SCREEN_WIDTH; x++) {
1747 				if (gui_data[(y*LUA_SCREEN_WIDTH+x)*4+3] != 0)
1748 					gui_data[(y*LUA_SCREEN_WIDTH+x)*4+3] = 0;
1749 			}
1750 		}
1751 	}
1752 //		if (gui_used != GUI_USED_SINCE_LAST_DISPLAY) /* mz: 10% slower on my system */
1753 //			memset(gui_data,0,LUA_SCREEN_WIDTH * LUA_SCREEN_HEIGHT * 4);
1754 	gui_used = GUI_USED_SINCE_LAST_DISPLAY;
1755 }
1756 
1757 
1758 // pixform for lua graphics
1759 #define BUILD_PIXEL_ARGB8888(A,R,G,B) (((int) (A) << 24) | ((int) (R) << 16) | ((int) (G) << 8) | (int) (B))
1760 #define DECOMPOSE_PIXEL_ARGB8888(PIX,A,R,G,B) { (A) = ((PIX) >> 24) & 0xff; (R) = ((PIX) >> 16) & 0xff; (G) = ((PIX) >> 8) & 0xff; (B) = (PIX) & 0xff; }
1761 #define LUA_BUILD_PIXEL BUILD_PIXEL_ARGB8888
1762 #define LUA_DECOMPOSE_PIXEL DECOMPOSE_PIXEL_ARGB8888
1763 #define LUA_PIXEL_A(PIX) (((PIX) >> 24) & 0xff)
1764 #define LUA_PIXEL_R(PIX) (((PIX) >> 16) & 0xff)
1765 #define LUA_PIXEL_G(PIX) (((PIX) >> 8) & 0xff)
1766 #define LUA_PIXEL_B(PIX) ((PIX) & 0xff)
1767 
1768 // I'm going to use this a lot in here
1769 #define swap(T, one, two) { \
1770 	T temp = one; \
1771 	one = two;    \
1772 	two = temp;   \
1773 }
1774 
1775 // write a pixel to buffer
blend32(UINT32 * dstPixel,UINT32 colour)1776 static inline void blend32(UINT32 *dstPixel, UINT32 colour)
1777 {
1778 	UINT8 *dst = (UINT8*) dstPixel;
1779 	int a, r, g, b;
1780 	LUA_DECOMPOSE_PIXEL(colour, a, r, g, b);
1781 
1782 	if (a == 255 || dst[3] == 0) {
1783 		// direct copy
1784 		*(UINT32*)(dst) = colour;
1785 	}
1786 	else if (a == 0) {
1787 		// do not copy
1788 	}
1789 	else {
1790 		// alpha-blending
1791 		int a_dst = ((255 - a) * dst[3] + 128) / 255;
1792 		int a_new = a + a_dst;
1793 
1794 		dst[0] = (UINT8) ((( dst[0] * a_dst + b * a) + (a_new / 2)) / a_new);
1795 		dst[1] = (UINT8) ((( dst[1] * a_dst + g * a) + (a_new / 2)) / a_new);
1796 		dst[2] = (UINT8) ((( dst[2] * a_dst + r * a) + (a_new / 2)) / a_new);
1797 		dst[3] = (UINT8) a_new;
1798 	}
1799 }
1800 
1801 // check if a pixel is in the lua canvas
gui_check_boundary(int x,int y)1802 static inline UINT8 gui_check_boundary(int x, int y) {
1803 	return !(x < 0 || x >= LUA_SCREEN_WIDTH || y < 0 || y >= LUA_SCREEN_HEIGHT);
1804 }
1805 
1806 // write a pixel to gui_data (do not check boundaries for speedup)
gui_drawpixel_fast(int x,int y,UINT32 colour)1807 static inline void gui_drawpixel_fast(int x, int y, UINT32 colour) {
1808 	//gui_prepare();
1809 	blend32((UINT32*) &gui_data[(y*LUA_SCREEN_WIDTH+x)*4], colour);
1810 }
1811 
1812 // write a pixel to gui_data (check boundaries)
gui_drawpixel_internal(int x,int y,UINT32 colour)1813 static inline void gui_drawpixel_internal(int x, int y, UINT32 colour) {
1814 	//gui_prepare();
1815 	if (gui_check_boundary(x, y))
1816 		gui_drawpixel_fast(x, y, colour);
1817 }
1818 
1819 // draw a line on gui_data (checks boundaries)
gui_drawline_internal(int x1,int y1,int x2,int y2,UINT8 lastPixel,UINT32 colour)1820 static void gui_drawline_internal(int x1, int y1, int x2, int y2, UINT8 lastPixel, UINT32 colour) {
1821 
1822 	//gui_prepare();
1823 
1824 	// Note: New version of Bresenham's Line Algorithm
1825 	// http://groups.google.co.jp/group/rec.games.roguelike.development/browse_thread/thread/345f4c42c3b25858/29e07a3af3a450e6?show_docid=29e07a3af3a450e6
1826 
1827 	int swappedx = 0;
1828 	int swappedy = 0;
1829 
1830 	int xtemp = x1-x2;
1831 	int ytemp = y1-y2;
1832 
1833 	int delta_x;
1834 	int delta_y;
1835 
1836 	signed char ix;
1837 	signed char iy;
1838 
1839 	if (xtemp == 0 && ytemp == 0) {
1840 		gui_drawpixel_internal(x1, y1, colour);
1841 		return;
1842 	}
1843 	if (xtemp < 0) {
1844 		xtemp = -xtemp;
1845 		swappedx = 1;
1846 	}
1847 	if (ytemp < 0) {
1848 		ytemp = -ytemp;
1849 		swappedy = 1;
1850 	}
1851 
1852 	delta_x = xtemp << 1;
1853 	delta_y = ytemp << 1;
1854 
1855 	ix = x1 > x2?1:-1;
1856 	iy = y1 > y2?1:-1;
1857 
1858 	if (lastPixel)
1859 		gui_drawpixel_internal(x2, y2, colour);
1860 
1861 	if (delta_x >= delta_y) {
1862 		int error = delta_y - (delta_x >> 1);
1863 
1864 		while (x2 != x1) {
1865 			if (error == 0 && !swappedx)
1866 				gui_drawpixel_internal(x2+ix, y2, colour);
1867 			if (error >= 0) {
1868 				if (error || (ix > 0)) {
1869 					y2 += iy;
1870 					error -= delta_x;
1871 				}
1872 			}
1873 			x2 += ix;
1874 			gui_drawpixel_internal(x2, y2, colour);
1875 			if (error == 0 && swappedx)
1876 				gui_drawpixel_internal(x2, y2+iy, colour);
1877 			error += delta_y;
1878 		}
1879 	}
1880 	else {
1881 		int error = delta_x - (delta_y >> 1);
1882 
1883 		while (y2 != y1) {
1884 			if (error == 0 && !swappedy)
1885 				gui_drawpixel_internal(x2, y2+iy, colour);
1886 			if (error >= 0) {
1887 				if (error || (iy > 0)) {
1888 					x2 += ix;
1889 					error -= delta_y;
1890 				}
1891 			}
1892 			y2 += iy;
1893 			gui_drawpixel_internal(x2, y2, colour);
1894 			if (error == 0 && swappedy)
1895 				gui_drawpixel_internal(x2+ix, y2, colour);
1896 			error += delta_x;
1897 		}
1898 	}
1899 }
1900 
1901 // draw a rect on gui_data
gui_drawbox_internal(int x1,int y1,int x2,int y2,UINT32 colour)1902 static void gui_drawbox_internal(int x1, int y1, int x2, int y2, UINT32 colour) {
1903 
1904 	if (x1 > x2)
1905 		swap(int, x1, x2);
1906 	if (y1 > y2)
1907 		swap(int, y1, y2);
1908 	if (x1 < 0)
1909 		x1 = -1;
1910 	if (y1 < 0)
1911 		y1 = -1;
1912 	if (x2 >= LUA_SCREEN_WIDTH)
1913 		x2 = LUA_SCREEN_WIDTH;
1914 	if (y2 >= LUA_SCREEN_HEIGHT)
1915 		y2 = LUA_SCREEN_HEIGHT;
1916 
1917 	//gui_prepare();
1918 
1919 	gui_drawline_internal(x1, y1, x2, y1, TRUE, colour);
1920 	gui_drawline_internal(x1, y2, x2, y2, TRUE, colour);
1921 	gui_drawline_internal(x1, y1, x1, y2, TRUE, colour);
1922 	gui_drawline_internal(x2, y1, x2, y2, TRUE, colour);
1923 }
1924 
1925 /*
1926 // draw a circle on gui_data
1927 static void gui_drawcircle_internal(int x0, int y0, int radius, UINT32 colour) {
1928 
1929 	int f;
1930 	int ddF_x;
1931 	int ddF_y;
1932 	int x;
1933 	int y;
1934 
1935 	//gui_prepare();
1936 
1937 	if (radius < 0)
1938 		radius = -radius;
1939 	if (radius == 0)
1940 		return;
1941 	if (radius == 1) {
1942 		gui_drawpixel_internal(x0, y0, colour);
1943 		return;
1944 	}
1945 
1946 	// http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
1947 
1948 	f = 1 - radius;
1949 	ddF_x = 1;
1950 	ddF_y = -2 * radius;
1951 	x = 0;
1952 	y = radius;
1953 
1954 	gui_drawpixel_internal(x0, y0 + radius, colour);
1955 	gui_drawpixel_internal(x0, y0 - radius, colour);
1956 	gui_drawpixel_internal(x0 + radius, y0, colour);
1957 	gui_drawpixel_internal(x0 - radius, y0, colour);
1958 
1959 	// same pixel shouldn't be drawed twice,
1960 	// because each pixel has opacity.
1961 	// so now the routine gets ugly.
1962 	while(TRUE)
1963 	{
1964 		assert(ddF_x == 2 * x + 1);
1965 		assert(ddF_y == -2 * y);
1966 		assert(f == x*x + y*y - radius*radius + 2*x - y + 1);
1967 		if(f >= 0)
1968 		{
1969 			y--;
1970 			ddF_y += 2;
1971 			f += ddF_y;
1972 		}
1973 		x++;
1974 		ddF_x += 2;
1975 		f += ddF_x;
1976 		if (x < y) {
1977 			gui_drawpixel_internal(x0 + x, y0 + y, colour);
1978 			gui_drawpixel_internal(x0 - x, y0 + y, colour);
1979 			gui_drawpixel_internal(x0 + x, y0 - y, colour);
1980 			gui_drawpixel_internal(x0 - x, y0 - y, colour);
1981 			gui_drawpixel_internal(x0 + y, y0 + x, colour);
1982 			gui_drawpixel_internal(x0 - y, y0 + x, colour);
1983 			gui_drawpixel_internal(x0 + y, y0 - x, colour);
1984 			gui_drawpixel_internal(x0 - y, y0 - x, colour);
1985 		}
1986 		else if (x == y) {
1987 			gui_drawpixel_internal(x0 + x, y0 + y, colour);
1988 			gui_drawpixel_internal(x0 - x, y0 + y, colour);
1989 			gui_drawpixel_internal(x0 + x, y0 - y, colour);
1990 			gui_drawpixel_internal(x0 - x, y0 - y, colour);
1991 			break;
1992 		}
1993 		else
1994 			break;
1995 	}
1996 }
1997 */
1998 
1999 // draw fill rect on gui_data
gui_fillbox_internal(int x1,int y1,int x2,int y2,UINT32 colour)2000 static void gui_fillbox_internal(int x1, int y1, int x2, int y2, UINT32 colour) {
2001 
2002 	int ix, iy;
2003 
2004 	if (x1 > x2)
2005 		swap(int, x1, x2);
2006 	if (y1 > y2)
2007 		swap(int, y1, y2);
2008 	if (x1 < 0)
2009 		x1 = 0;
2010 	if (y1 < 0)
2011 		y1 = 0;
2012 	if (x2 >= LUA_SCREEN_WIDTH)
2013 		x2 = LUA_SCREEN_WIDTH - 1;
2014 	if (y2 >= LUA_SCREEN_HEIGHT)
2015 		y2 = LUA_SCREEN_HEIGHT - 1;
2016 
2017 	//gui_prepare();
2018 
2019 	for (iy = y1; iy <= y2; iy++) {
2020 		for (ix = x1; ix <= x2; ix++) {
2021 			gui_drawpixel_fast(ix, iy, colour);
2022 		}
2023 	}
2024 }
2025 
2026 /*
2027 // fill a circle on gui_data
2028 static void gui_fillcircle_internal(int x0, int y0, int radius, UINT32 colour) {
2029 
2030 	int f;
2031 	int ddF_x;
2032 	int ddF_y;
2033 	int x;
2034 	int y;
2035 
2036 	//gui_prepare();
2037 
2038 	if (radius < 0)
2039 		radius = -radius;
2040 	if (radius == 0)
2041 		return;
2042 	if (radius == 1) {
2043 		gui_drawpixel_internal(x0, y0, colour);
2044 		return;
2045 	}
2046 
2047 	// http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
2048 
2049 	f = 1 - radius;
2050 	ddF_x = 1;
2051 	ddF_y = -2 * radius;
2052 	x = 0;
2053 	y = radius;
2054 
2055 	gui_drawline_internal(x0, y0 - radius, x0, y0 + radius, TRUE, colour);
2056 
2057 	while(TRUE)
2058 	{
2059 		assert(ddF_x == 2 * x + 1);
2060 		assert(ddF_y == -2 * y);
2061 		assert(f == x*x + y*y - radius*radius + 2*x - y + 1);
2062 		if(f >= 0)
2063 		{
2064 			y--;
2065 			ddF_y += 2;
2066 			f += ddF_y;
2067 		}
2068 		x++;
2069 		ddF_x += 2;
2070 		f += ddF_x;
2071 
2072 		if (x < y) {
2073 			gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, TRUE, colour);
2074 			gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, TRUE, colour);
2075 			if (f >= 0) {
2076 				gui_drawline_internal(x0 + y, y0 - x, x0 + y, y0 + x, TRUE, colour);
2077 				gui_drawline_internal(x0 - y, y0 - x, x0 - y, y0 + x, TRUE, colour);
2078 			}
2079 		}
2080 		else if (x == y) {
2081 			gui_drawline_internal(x0 + x, y0 - y, x0 + x, y0 + y, TRUE, colour);
2082 			gui_drawline_internal(x0 - x, y0 - y, x0 - x, y0 + y, TRUE, colour);
2083 			break;
2084 		}
2085 		else
2086 			break;
2087 	}
2088 }
2089 */
2090 
2091 static const struct ColorMapping
2092 {
2093 	const char* name;
2094 	int value;
2095 }
2096 s_colorMapping [] =
2097 {
2098 	{"white",     0xFFFFFFFF},
2099 	{"black",     0x000000FF},
2100 	{"clear",     0x00000000},
2101 	{"gray",      0x7F7F7FFF},
2102 	{"grey",      0x7F7F7FFF},
2103 	{"red",       0xFF0000FF},
2104 	{"orange",    0xFF7F00FF},
2105 	{"yellow",    0xFFFF00FF},
2106 	{"chartreuse",0x7FFF00FF},
2107 	{"green",     0x00FF00FF},
2108 	{"teal",      0x00FF7FFF},
2109 	{"cyan" ,     0x00FFFFFF},
2110 	{"blue",      0x0000FFFF},
2111 	{"purple",    0x7F00FFFF},
2112 	{"magenta",   0xFF00FFFF},
2113 };
2114 
2115 /**
2116  * Converts an integer or a string on the stack at the given
2117  * offset to a RGB32 colour. Several encodings are supported.
2118  * The user may construct their own RGB value, given a simple colour name,
2119  * or an HTML-style "#09abcd" colour. 16 bit reduction doesn't occur at this time.
2120  */
str2colour(UINT32 * colour,const char * str)2121 static inline UINT8 str2colour(UINT32 *colour, const char *str) {
2122 	if (str[0] == '#') {
2123 		unsigned int color;
2124 		int len;
2125 		int missing;
2126 		sscanf(str+1, "%X", &color);
2127 		len = strlen(str+1);
2128 		missing = max(0, 8-len);
2129 		color <<= missing << 2;
2130 		if(missing >= 2) color |= 0xFF;
2131 		*colour = color;
2132 		return TRUE;
2133 	}
2134 	else {
2135 		unsigned int i;
2136 		if(!strnicmp(str, "rand", 4)) {
2137 			*colour = ((rand()*255/RAND_MAX) << 8) | ((rand()*255/RAND_MAX) << 16) | ((rand()*255/RAND_MAX) << 24) | 0xFF;
2138 			return TRUE;
2139 		}
2140 		for(i = 0; i < sizeof(s_colorMapping)/sizeof(*s_colorMapping); i++) {
2141 			if(!stricmp(str,s_colorMapping[i].name)) {
2142 				*colour = s_colorMapping[i].value;
2143 				return TRUE;
2144 			}
2145 		}
2146 	}
2147 	return FALSE;
2148 }
gui_getcolour_wrapped(lua_State * L,int offset,UINT8 hasDefaultValue,UINT32 defaultColour)2149 static inline UINT32 gui_getcolour_wrapped(lua_State *L, int offset, UINT8 hasDefaultValue, UINT32 defaultColour) {
2150 	switch (lua_type(L,offset)) {
2151 	case LUA_TSTRING:
2152 		{
2153 			const char *str = lua_tostring(L,offset);
2154 			UINT32 colour;
2155 
2156 			if (str2colour(&colour, str))
2157 				return colour;
2158 			else {
2159 				if (hasDefaultValue)
2160 					return defaultColour;
2161 				else
2162 					return luaL_error(L, "unknown colour %s", str);
2163 			}
2164 		}
2165 	case LUA_TNUMBER:
2166 		{
2167 			UINT32 colour = (UINT32) lua_tointeger(L,offset);
2168 			return colour;
2169 		}
2170 	case LUA_TTABLE:
2171 		{
2172 			int color = 0xFF;
2173 			lua_pushnil(L); // first key
2174 			int keyIndex = lua_gettop(L);
2175 			int valueIndex = keyIndex + 1;
2176 			while(lua_next(L, offset))
2177 			{
2178 				bool keyIsString = (lua_type(L, keyIndex) == LUA_TSTRING);
2179 				bool keyIsNumber = (lua_type(L, keyIndex) == LUA_TNUMBER);
2180 				int key = keyIsString ? tolower(*lua_tostring(L, keyIndex)) : (keyIsNumber ? lua_tointeger(L, keyIndex) : 0);
2181 				int value = lua_tointeger(L, valueIndex);
2182 				if(value < 0) value = 0;
2183 				if(value > 255) value = 255;
2184 				switch(key)
2185 				{
2186 				case 1: case 'r': color |= value << 24; break;
2187 				case 2: case 'g': color |= value << 16; break;
2188 				case 3: case 'b': color |= value << 8; break;
2189 				case 4: case 'a': color = (color & ~0xFF) | value; break;
2190 				}
2191 				lua_pop(L, 1);
2192 			}
2193 			return color;
2194 		}	break;
2195 	case LUA_TFUNCTION:
2196 		luaL_error(L, "invalid colour"); // NYI
2197 		return 0;
2198 	default:
2199 		if (hasDefaultValue)
2200 			return defaultColour;
2201 		else
2202 			return luaL_error(L, "invalid colour");
2203 	}
2204 }
gui_getcolour(lua_State * L,int offset)2205 static UINT32 gui_getcolour(lua_State *L, int offset) {
2206 	UINT32 colour;
2207 	UINT32 a, r, g, b;
2208 
2209 	colour = gui_getcolour_wrapped(L, offset, FALSE, 0);
2210 	a = ((colour & 0xff) * transparencyModifier) / 255;
2211 	if (a > 255) a = 255;
2212 	b = (colour >> 8) & 0xff;
2213 	g = (colour >> 16) & 0xff;
2214 	r = (colour >> 24) & 0xff;
2215 	return LUA_BUILD_PIXEL(a, r, g, b);
2216 }
gui_optcolour(lua_State * L,int offset,UINT32 defaultColour)2217 static UINT32 gui_optcolour(lua_State *L, int offset, UINT32 defaultColour) {
2218 	UINT32 colour;
2219 	UINT32 a, r, g, b;
2220 	UINT8 defA, defB, defG, defR;
2221 
2222 	LUA_DECOMPOSE_PIXEL(defaultColour, defA, defR, defG, defB);
2223 	defaultColour = (defR << 24) | (defG << 16) | (defB << 8) | defA;
2224 
2225 	colour = gui_getcolour_wrapped(L, offset, TRUE, defaultColour);
2226 	a = ((colour & 0xff) * transparencyModifier) / 255;
2227 	if (a > 255) a = 255;
2228 	b = (colour >> 8) & 0xff;
2229 	g = (colour >> 16) & 0xff;
2230 	r = (colour >> 24) & 0xff;
2231 	return LUA_BUILD_PIXEL(a, r, g, b);
2232 }
2233 
2234 // gui.drawpixel(x,y,colour)
gui_drawpixel(lua_State * L)2235 static int gui_drawpixel(lua_State *L) {
2236 
2237 	int x = luaL_checkinteger(L, 1);
2238 	int y = luaL_checkinteger(L,2);
2239 
2240 	UINT32 colour = gui_getcolour(L,3);
2241 
2242 //	if (!gui_check_boundary(x, y))
2243 //		luaL_error(L,"bad coordinates");
2244 
2245 	gui_prepare();
2246 
2247 	gui_drawpixel_internal(x, y, colour);
2248 
2249 	return 0;
2250 }
2251 
2252 // gui.drawline(x1,y1,x2,y2,color,skipFirst)
gui_drawline(lua_State * L)2253 static int gui_drawline(lua_State *L) {
2254 
2255 	int x1,y1,x2,y2;
2256 	UINT32 color;
2257 	x1 = luaL_checkinteger(L,1);
2258 	y1 = luaL_checkinteger(L,2);
2259 	x2 = luaL_checkinteger(L,3);
2260 	y2 = luaL_checkinteger(L,4);
2261 	color = gui_optcolour(L,5,LUA_BUILD_PIXEL(255, 255, 255, 255));
2262 	int skipFirst = lua_toboolean(L,6);
2263 
2264 	gui_prepare();
2265 
2266 	gui_drawline_internal(x2, y2, x1, y1, !skipFirst, color);
2267 
2268 	return 0;
2269 }
2270 
2271 // gui.drawbox(x1, y1, x2, y2, fillcolor, outlinecolor)
gui_drawbox(lua_State * L)2272 static int gui_drawbox(lua_State *L) {
2273 
2274 	int x1,y1,x2,y2;
2275 	UINT32 fillcolor;
2276 	UINT32 outlinecolor;
2277 
2278 	x1 = luaL_checkinteger(L,1);
2279 	y1 = luaL_checkinteger(L,2);
2280 	x2 = luaL_checkinteger(L,3);
2281 	y2 = luaL_checkinteger(L,4);
2282 	fillcolor = gui_optcolour(L,5,LUA_BUILD_PIXEL(63, 255, 255, 255));
2283 	outlinecolor = gui_optcolour(L,6,LUA_BUILD_PIXEL(255, LUA_PIXEL_R(fillcolor), LUA_PIXEL_G(fillcolor), LUA_PIXEL_B(fillcolor)));
2284 
2285 	if (x1 > x2)
2286 		swap(int,x1, x2);
2287 	if (y1 > y2)
2288 		swap(int, y1, y2);
2289 
2290 	gui_prepare();
2291 
2292 	gui_drawbox_internal(x1, y1, x2, y2, outlinecolor);
2293 	if ((x2 - x1) >= 2 && (y2 - y1) >= 2)
2294 		gui_fillbox_internal(x1+1, y1+1, x2-1, y2-1, fillcolor);
2295 
2296 	return 0;
2297 }
2298 
2299 /*
2300 // gui.drawcircle(x0, y0, radius, colour)
2301 static int gui_drawcircle(lua_State *L) {
2302 
2303 	int x, y, r;
2304 	UINT32 colour;
2305 
2306 	x = luaL_checkinteger(L,1);
2307 	y = luaL_checkinteger(L,2);
2308 	r = luaL_checkinteger(L,3);
2309 	colour = gui_getcolour(L,4);
2310 
2311 	gui_prepare();
2312 
2313 	gui_drawcircle_internal(x, y, r, colour);
2314 
2315 	return 0;
2316 }
2317 
2318 // gui.fillbox(x1, y1, x2, y2, colour)
2319 static int gui_fillbox(lua_State *L) {
2320 
2321 	int x1,y1,x2,y2;
2322 	UINT32 colour;
2323 
2324 	x1 = luaL_checkinteger(L,1);
2325 	y1 = luaL_checkinteger(L,2);
2326 	x2 = luaL_checkinteger(L,3);
2327 	y2 = luaL_checkinteger(L,4);
2328 	colour = gui_getcolour(L,5);
2329 
2330 //	if (!gui_check_boundary(x1, y1))
2331 //		luaL_error(L,"bad coordinates");
2332 //
2333 //	if (!gui_check_boundary(x2, y2))
2334 //		luaL_error(L,"bad coordinates");
2335 
2336 	gui_prepare();
2337 
2338 	gui_fillbox_internal(x1, y1, x2, y2, colour);
2339 
2340 	return 0;
2341 }
2342 
2343 // gui.fillcircle(x0, y0, radius, colour)
2344 static int gui_fillcircle(lua_State *L) {
2345 
2346 	int x, y, r;
2347 	UINT32 colour;
2348 
2349 	x = luaL_checkinteger(L,1);
2350 	y = luaL_checkinteger(L,2);
2351 	r = luaL_checkinteger(L,3);
2352 	colour = gui_getcolour(L,4);
2353 
2354 	gui_prepare();
2355 
2356 	gui_fillcircle_internal(x, y, r, colour);
2357 
2358 	return 0;
2359 }
2360 */
2361 
gui_getpixel(lua_State * L)2362 static int gui_getpixel(lua_State *L) {
2363 	int x = luaL_checkinteger(L, 1);
2364 	int y = luaL_checkinteger(L, 2);
2365 
2366 	if(!gui_check_boundary(x,y))
2367 	{
2368 		lua_pushinteger(L, 0);
2369 		lua_pushinteger(L, 0);
2370 		lua_pushinteger(L, 0);
2371 	}
2372 	else
2373 	{
2374 		switch(iScreenBpp)
2375 		{
2376 		case 2:
2377 			{
2378 				UINT16 *screen = (UINT16*) XBuf;
2379 				UINT16 pix = screen[y*(iScreenPitch/2) + x];
2380 				lua_pushinteger(L, (pix >> 8) & 0xF8); // red
2381 				lua_pushinteger(L, (pix >> 3) & 0xFC); // green
2382 				lua_pushinteger(L, (pix << 3) & 0xF8); // blue
2383 			}
2384 			break;
2385 		case 3:
2386 			{
2387 				UINT8 *screen = XBuf;
2388 				lua_pushinteger(L, screen[y*iScreenPitch + x*3 + 2]); // red
2389 				lua_pushinteger(L, screen[y*iScreenPitch + x*3 + 1]); // green
2390 				lua_pushinteger(L, screen[y*iScreenPitch + x*3 + 0]); // blue
2391 			}
2392 			break;
2393 		case 4:
2394 			{
2395 				UINT8 *screen = XBuf;
2396 				lua_pushinteger(L, screen[y*iScreenPitch + x*4 + 2]); // red
2397 				lua_pushinteger(L, screen[y*iScreenPitch + x*4 + 1]); // green
2398 				lua_pushinteger(L, screen[y*iScreenPitch + x*4 + 0]); // blue
2399 			}
2400 			break;
2401 		default:
2402 			lua_pushinteger(L, 0);
2403 			lua_pushinteger(L, 0);
2404 			lua_pushinteger(L, 0);
2405 			break;
2406 		}
2407 	}
2408 
2409 	return 3;
2410 }
2411 
gui_parsecolor(lua_State * L)2412 static int gui_parsecolor(lua_State *L)
2413 {
2414 	int r, g, b, a;
2415 	UINT32 color = gui_getcolour(L,1);
2416 	LUA_DECOMPOSE_PIXEL(color, a, r, g, b);
2417 	lua_pushinteger(L, r);
2418 	lua_pushinteger(L, g);
2419 	lua_pushinteger(L, b);
2420 	lua_pushinteger(L, a);
2421 	return 4;
2422 }
2423 
2424 
2425 // gui.savescreenshot()
2426 //
2427 // Causes FBA to write a screenshot to a file as if the user pressed the associated hotkey.
2428 //
2429 // Unconditionally retrns 1; any failure in taking a screenshot would be reported on-screen
2430 // from the function HK_screenShot().
gui_savescreenshot(lua_State * L)2431 static int gui_savescreenshot(lua_State *L) {
2432 	//HK_screenShot(0);
2433 	return 1;
2434 }
2435 
2436 // gui.gdscreenshot()
2437 //
2438 //  Returns a screen shot as a string in gd's v1 file format.
2439 //  This allows us to make screen shots available without gd installed locally.
2440 //  Users can also just grab pixels via substring selection.
2441 //
2442 //  I think...  Does lua support grabbing byte values from a string? // yes, string.byte(str,offset)
2443 //  Well, either way, just install gd and do what you like with it.
2444 //  It really is easier that way.
2445 // example: gd.createFromGdStr(gui.gdscreenshot()):png("outputimage.png")
gui_gdscreenshot(lua_State * L)2446 static int gui_gdscreenshot(lua_State *L) {
2447 	int x,y;
2448 
2449 	int width = iScreenWidth;
2450 	int height = iScreenHeight;
2451 
2452 	int size = 11 + width * height * 4;
2453 	char* str = (char*)malloc(size+1);
2454 	unsigned char* ptr;
2455 
2456 	str[size] = 0;
2457 	ptr = (unsigned char*)str;
2458 
2459 	// GD format header for truecolor image (11 bytes)
2460 	*ptr++ = (65534 >> 8) & 0xFF;
2461 	*ptr++ = (65534     ) & 0xFF;
2462 	*ptr++ = (width >> 8) & 0xFF;
2463 	*ptr++ = (width     ) & 0xFF;
2464 	*ptr++ = (height >> 8) & 0xFF;
2465 	*ptr++ = (height     ) & 0xFF;
2466 	*ptr++ = 1;
2467 	*ptr++ = 255;
2468 	*ptr++ = 255;
2469 	*ptr++ = 255;
2470 	*ptr++ = 255;
2471 
2472 	for(y=0; y<height; y++){
2473 		for(x=0; x<width; x++){
2474 			UINT32 r, g, b;
2475 			switch(iScreenBpp)
2476 			{
2477 			case 2:
2478 				{
2479 					UINT16 *screen = (UINT16*) XBuf;
2480 					r = ((screen[y*(iScreenPitch/2) + x] >> 11) & 31) << 3;
2481 					g = ((screen[y*(iScreenPitch/2) + x] >> 5)  & 63) << 2;
2482 					b = ( screen[y*(iScreenPitch/2) + x]        & 31) << 3;
2483 				}
2484 				break;
2485 			case 3:
2486 				{
2487 					UINT8 *screen = XBuf;
2488 					r = screen[y*iScreenPitch + x*3+2];
2489 					g = screen[y*iScreenPitch + x*3+1];
2490 					b = screen[y*iScreenPitch + x*3];
2491 				}
2492 				break;
2493 			case 4:
2494 			default:
2495 				{
2496 					UINT8 *screen = XBuf;
2497 					r = screen[y*iScreenPitch + x*4+2];
2498 					g = screen[y*iScreenPitch + x*4+1];
2499 					b = screen[y*iScreenPitch + x*4];
2500 				}
2501 				break;
2502 			}
2503 
2504 			// overlay uncommited Lua drawings if needed
2505 			if (gui_used != GUI_CLEAR && gui_enabled) {
2506 				const UINT8 gui_alpha = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+3];
2507 				const UINT8 gui_red   = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+2];
2508 				const UINT8 gui_green = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+1];
2509 				const UINT8 gui_blue  = gui_data[(y*LUA_SCREEN_WIDTH+x)*4];
2510 
2511 				if (gui_alpha == 255) {
2512 					// direct copy
2513 					r = gui_red;
2514 					g = gui_green;
2515 					b = gui_blue;
2516 				}
2517 				else if (gui_alpha != 0) {
2518 					// alpha-blending
2519 					r = (((int) gui_red   - r) * gui_alpha / 255 + r) & 255;
2520 					g = (((int) gui_green - g) * gui_alpha / 255 + g) & 255;
2521 					b = (((int) gui_blue  - b) * gui_alpha / 255 + b) & 255;
2522 				}
2523 			}
2524 
2525 			*ptr++ = 0;
2526 			*ptr++ = r;
2527 			*ptr++ = g;
2528 			*ptr++ = b;
2529 		}
2530 	}
2531 
2532 	lua_pushlstring(L, str, size);
2533 	free(str);
2534 	return 1;
2535 }
2536 
2537 
2538 // gui.opacity(number alphaValue)
2539 // sets the transparency of subsequent draw calls
2540 // 0.0 is completely transparent, 1.0 is completely opaque
2541 // non-integer values are supported and meaningful, as are values greater than 1.0
2542 // it is not necessary to use this function to get transparency (or the less-recommended gui.transparency() either),
2543 // because you can provide an alpha value in the color argument of each draw call.
2544 // however, it can be convenient to be able to globally modify the drawing transparency
gui_setopacity(lua_State * L)2545 static int gui_setopacity(lua_State *L) {
2546 	double opacF = luaL_checknumber(L,1);
2547 	transparencyModifier = (int) (opacF * 255);
2548 	if (transparencyModifier < 0)
2549 		transparencyModifier = 0;
2550 	return 0;
2551 }
2552 
2553 // gui.transparency(int strength)
2554 //
2555 //  0 = solid,
gui_transparency(lua_State * L)2556 static int gui_transparency(lua_State *L) {
2557 	double trans = luaL_checknumber(L,1);
2558 	transparencyModifier = (int) ((4.0 - trans) / 4.0 * 255);
2559 	if (transparencyModifier < 0)
2560 		transparencyModifier = 0;
2561 	return 0;
2562 }
2563 
2564 // gui.clearuncommitted()
2565 //
2566 //  undoes uncommitted drawing commands
gui_clearuncommitted(lua_State * L)2567 static int gui_clearuncommitted(lua_State *L) {
2568 	FBA_LuaClearGui();
2569 	return 0;
2570 }
2571 
2572 
2573 static const UINT32 Small_Font_Data[] =
2574 {
2575 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,			// 32
2576 	0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000000, 0x00000700, 0x00000000,			// 33	!
2577 	0x00000000, 0x00040002, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000,			// 34	"
2578 	0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070605, 0x00080006, 0x00000000,			// 35	#
2579 	0x00000000, 0x00040300, 0x00000403, 0x00000500, 0x00070600, 0x00000706, 0x00000000,			// 36	$
2580 	0x00000000, 0x00000002, 0x00050000, 0x00000500, 0x00000005, 0x00080000, 0x00000000,			// 37	%
2581 	0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00080700, 0x00000000,			// 38	&
2582 	0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000,			// 39	'
2583 	0x00000000, 0x00000300, 0x00000003, 0x00000004, 0x00000005, 0x00000700, 0x00000000,			// 40	(
2584 	0x00000000, 0x00000300, 0x00050000, 0x00060000, 0x00070000, 0x00000700, 0x00000000,			// 41	)
2585 	0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00080006, 0x00000000,			// 42	*
2586 	0x00000000, 0x00000000, 0x00000400, 0x00060504, 0x00000600, 0x00000000, 0x00000000,			// 43	+
2587 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000600, 0x00000700, 0x00000007,			// 44	,
2588 	0x00000000, 0x00000000, 0x00000000, 0x00060504, 0x00000000, 0x00000000, 0x00000000,			// 45	-
2589 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000700, 0x00000000,			// 46	.
2590 	0x00030000, 0x00040000, 0x00000400, 0x00000500, 0x00000005, 0x00000006, 0x00000000,			// 47	/
2591 	0x00000000, 0x00000300, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000,			// 48	0
2592 	0x00000000, 0x00000300, 0x00000403, 0x00000500, 0x00000600, 0x00000700, 0x00000000,			// 49	1
2593 	0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000,			// 50	2
2594 	0x00000000, 0x00000302, 0x00050000, 0x00000504, 0x00070000, 0x00000706, 0x00000000,			// 51	3
2595 	0x00000000, 0x00000300, 0x00000003, 0x00060004, 0x00070605, 0x00080000, 0x00000000,			// 52	4
2596 	0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00070000, 0x00000706, 0x00000000,			// 53	5
2597 	0x00000000, 0x00000300, 0x00000003, 0x00000504, 0x00070005, 0x00000700, 0x00000000,			// 54	6
2598 	0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000600, 0x00000700, 0x00000000,			// 55	7
2599 	0x00000000, 0x00000300, 0x00050003, 0x00000500, 0x00070005, 0x00000700, 0x00000000,			// 56	8
2600 	0x00000000, 0x00000300, 0x00050003, 0x00060500, 0x00070000, 0x00000700, 0x00000000,			// 57	9
2601 	0x00000000, 0x00000000, 0x00000400, 0x00000000, 0x00000000, 0x00000700, 0x00000000,			// 58	:
2602 	0x00000000, 0x00000000, 0x00000000, 0x00000500, 0x00000000, 0x00000700, 0x00000007,			// 59	;
2603 	0x00000000, 0x00040000, 0x00000400, 0x00000004, 0x00000600, 0x00080000, 0x00000000,			// 60	<
2604 	0x00000000, 0x00000000, 0x00050403, 0x00000000, 0x00070605, 0x00000000, 0x00000000,			// 61	=
2605 	0x00000000, 0x00000002, 0x00000400, 0x00060000, 0x00000600, 0x00000006, 0x00000000,			// 62	>
2606 	0x00000000, 0x00000302, 0x00050000, 0x00000500, 0x00000000, 0x00000700, 0x00000000,			// 63	?
2607 	0x00000000, 0x00000300, 0x00050400, 0x00060004, 0x00070600, 0x00000000, 0x00000000,			// 64	@
2608 	0x00000000, 0x00000300, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000,			// 65	A
2609 	0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00000706, 0x00000000,			// 66	B
2610 	0x00000000, 0x00040300, 0x00000003, 0x00000004, 0x00000005, 0x00080700, 0x00000000,			// 67	C
2611 	0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00000706, 0x00000000,			// 68	D
2612 	0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00080706, 0x00000000,			// 69	E
2613 	0x00000000, 0x00040302, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000,			// 70	F
2614 	0x00000000, 0x00040300, 0x00000003, 0x00060004, 0x00070005, 0x00080700, 0x00000000,			// 71	G
2615 	0x00000000, 0x00040002, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000,			// 72	H
2616 	0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000,			// 73	I
2617 	0x00000000, 0x00040000, 0x00050000, 0x00060000, 0x00070005, 0x00000700, 0x00000000,			// 74	J
2618 	0x00000000, 0x00040002, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000,			// 75	K
2619 	0x00000000, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00080706, 0x00000000,			// 76	l
2620 	0x00000000, 0x00040002, 0x00050403, 0x00060004, 0x00070005, 0x00080006, 0x00000000,			// 77	M
2621 	0x00000000, 0x00000302, 0x00050003, 0x00060004, 0x00070005, 0x00080006, 0x00000000,			// 78	N
2622 	0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000,			// 79	O
2623 	0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000,			// 80	P
2624 	0x00000000, 0x00040302, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00090000,			// 81	Q
2625 	0x00000000, 0x00000302, 0x00050003, 0x00000504, 0x00070005, 0x00080006, 0x00000000,			// 82	R
2626 	0x00000000, 0x00040300, 0x00000003, 0x00000500, 0x00070000, 0x00000706, 0x00000000,			// 83	S
2627 	0x00000000, 0x00040302, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000000,			// 84	T
2628 	0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070005, 0x00080706, 0x00000000,			// 85	U
2629 	0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000000,			// 86	V
2630 	0x00000000, 0x00040002, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000,			// 87	W
2631 	0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000,			// 88	X
2632 	0x00000000, 0x00040002, 0x00050003, 0x00000500, 0x00000600, 0x00000700, 0x00000000,			// 89	Y
2633 	0x00000000, 0x00040302, 0x00050000, 0x00000500, 0x00000005, 0x00080706, 0x00000000,			// 90	Z
2634 	0x00000000, 0x00040300, 0x00000400, 0x00000500, 0x00000600, 0x00080700, 0x00000000,			// 91	[
2635 	0x00000000, 0x00000002, 0x00000400, 0x00000500, 0x00070000, 0x00080000, 0x00000000,			// 92	'\'
2636 	0x00000000, 0x00000302, 0x00000400, 0x00000500, 0x00000600, 0x00000706, 0x00000000,			// 93	]
2637 	0x00000000, 0x00000300, 0x00050003, 0x00000000, 0x00000000, 0x00000000, 0x00000000,			// 94	^
2638 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00080706, 0x00000000,			// 95	_
2639 	0x00000000, 0x00000002, 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000,			// 96	`
2640 	0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070005, 0x00080700, 0x00000000,			// 97	a
2641 	0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00000706, 0x00000000,			// 98	b
2642 	0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00000005, 0x00080700, 0x00000000,			// 99	c
2643 	0x00000000, 0x00040000, 0x00050000, 0x00060500, 0x00070005, 0x00080700, 0x00000000,			// 100	d
2644 	0x00000000, 0x00000000, 0x00050400, 0x00060504, 0x00000005, 0x00080700, 0x00000000,			// 101	e
2645 	0x00000000, 0x00040300, 0x00000003, 0x00000504, 0x00000005, 0x00000006, 0x00000000,			// 102	f
2646 	0x00000000, 0x00000000, 0x00050400, 0x00060004, 0x00070600, 0x00080000, 0x00000807,			// 103	g
2647 	0x00000000, 0x00000002, 0x00000003, 0x00000504, 0x00070005, 0x00080006, 0x00000000,			// 104	h
2648 	0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000000,			// 105	i
2649 	0x00000000, 0x00000300, 0x00000000, 0x00000500, 0x00000600, 0x00000700, 0x00000007,			// 106	j
2650 	0x00000000, 0x00000002, 0x00000003, 0x00060004, 0x00000605, 0x00080006, 0x00000000,			// 107	k
2651 	0x00000000, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00080000, 0x00000000,			// 108	l
2652 	0x00000000, 0x00000000, 0x00050003, 0x00060504, 0x00070005, 0x00080006, 0x00000000,			// 109	m
2653 	0x00000000, 0x00000000, 0x00000403, 0x00060004, 0x00070005, 0x00080006, 0x00000000,			// 110	n
2654 	0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070005, 0x00000700, 0x00000000,			// 111	o
2655 	0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00000605, 0x00000006, 0x00000007,			// 112	p
2656 	0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070600, 0x00080000, 0x00090000,			// 113	q
2657 	0x00000000, 0x00000000, 0x00050003, 0x00000504, 0x00000005, 0x00000006, 0x00000000,			// 114	r
2658 	0x00000000, 0x00000000, 0x00050400, 0x00000004, 0x00070600, 0x00000706, 0x00000000,			// 115	s
2659 	0x00000000, 0x00000300, 0x00050403, 0x00000500, 0x00000600, 0x00080000, 0x00000000,			// 116	t
2660 	0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00080700, 0x00000000,			// 117	u
2661 	0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070005, 0x00000700, 0x00000000,			// 118	v
2662 	0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00070605, 0x00080006, 0x00000000,			// 119	w
2663 	0x00000000, 0x00000000, 0x00050003, 0x00000500, 0x00070005, 0x00080006, 0x00000000,			// 120	x
2664 	0x00000000, 0x00000000, 0x00050003, 0x00060004, 0x00000600, 0x00000700, 0x00000007,			// 121	y
2665 	0x00000000, 0x00000000, 0x00050403, 0x00000500, 0x00000005, 0x00080706, 0x00000000,			// 122	z
2666 	0x00000000, 0x00040300, 0x00000400, 0x00000504, 0x00000600, 0x00080700, 0x00000000,			// 123	{
2667 	0x00000000, 0x00000300, 0x00000400, 0x00000000, 0x00000600, 0x00000700, 0x00000000,			// 124	|
2668 	0x00000000, 0x00000302, 0x00000400, 0x00060500, 0x00000600, 0x00000706, 0x00000000,			// 125	}
2669 	0x00000000, 0x00000302, 0x00050000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,			// 126	~
2670 	0x00000000, 0x00000000, 0x00000400, 0x00060004, 0x00070605, 0x00000000, 0x00000000,			// 127	
2671 	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
2672 };
2673 
2674 
PutTextInternal(const char * str,int len,short x,short y,int color,int backcolor)2675 static void PutTextInternal (const char *str, int len, short x, short y, int color, int backcolor)
2676 {
2677 	int Opac = (color >> 24) & 0xFF;
2678 	int backOpac = (backcolor >> 24) & 0xFF;
2679 	int origX = x;
2680 
2681 	if(!Opac && !backOpac)
2682 		return;
2683 
2684 	while(*str && len && y < LUA_SCREEN_HEIGHT)
2685 	{
2686 		int c = *str++;
2687 		const unsigned char* Cur_Glyph;
2688 		int y2,x2,y3,x3;
2689 
2690 		while (x > LUA_SCREEN_WIDTH && c != '\n') {
2691 			c = *str;
2692 			if (c == '\0')
2693 				break;
2694 			str++;
2695 		}
2696 		if(c == '\n')
2697 		{
2698 			x = origX;
2699 			y += 8;
2700 			continue;
2701 		}
2702 		else if(c == '\t') // just in case
2703 		{
2704 			const int tabSpace = 8;
2705 			x += (tabSpace-(((x-origX)/4)%tabSpace))*4;
2706 			continue;
2707 		}
2708 		if((unsigned int)(c-32) >= 96)
2709 			continue;
2710 		Cur_Glyph = (const unsigned char*)&Small_Font_Data + (c-32)*7*4;
2711 
2712 		for(y2 = 0; y2 < 8; y2++)
2713 		{
2714 			unsigned int glyphLine = *((unsigned int*)Cur_Glyph + y2);
2715 			for(x2 = -1; x2 < 4; x2++)
2716 			{
2717 				int shift = x2 << 3;
2718 				int mask = 0xFF << shift;
2719 				int intensity = (glyphLine & mask) >> shift;
2720 
2721 				if(intensity && x2 >= 0 && y2 < 7)
2722 				{
2723 					//int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2));
2724 					//int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2));
2725 					//gui_drawpixel_fast(xdraw, ydraw, color);
2726 					gui_drawpixel_internal(x+x2, y+y2, color);
2727 				}
2728 				else if(backOpac)
2729 				{
2730 					for(y3 = max(0,y2-1); y3 <= min(6,y2+1); y3++)
2731 					{
2732 						unsigned int glyphLineTmp = *((unsigned int*)Cur_Glyph + y3);
2733 						for(x3 = max(0,x2-1); x3 <= min(3,x2+1); x3++)
2734 						{
2735 							int shiftTmp = x3 << 3;
2736 							int maskTmp = 0xFF << shiftTmp;
2737 							intensity |= (glyphLineTmp & maskTmp) >> shiftTmp;
2738 							if (intensity)
2739 								goto draw_outline; // speedup?
2740 						}
2741 					}
2742 draw_outline:
2743 					if(intensity)
2744 					{
2745 						//int xdraw = max(0,min(LUA_SCREEN_WIDTH - 1,x+x2));
2746 						//int ydraw = max(0,min(LUA_SCREEN_HEIGHT - 1,y+y2));
2747 						//gui_drawpixel_fast(xdraw, ydraw, backcolor);
2748 						gui_drawpixel_internal(x+x2, y+y2, backcolor);
2749 					}
2750 				}
2751 			}
2752 		}
2753 
2754 		x += 4;
2755 		len--;
2756 	}
2757 }
2758 
2759 
LuaDisplayString(const char * string,int y,int x,UINT32 color,UINT32 outlineColor)2760 static void LuaDisplayString (const char *string, int y, int x, UINT32 color, UINT32 outlineColor)
2761 {
2762 	if(!string)
2763 		return;
2764 
2765 	gui_prepare();
2766 
2767 	PutTextInternal(string, strlen(string), x, y, color, outlineColor);
2768 }
2769 
2770 
2771 // gui.text(int x, int y, string msg[, color="white"[, outline="black"]])
2772 //
2773 //  Displays the given text on the screen, using the same font and techniques as the
2774 //  main HUD.
gui_text(lua_State * L)2775 static int gui_text(lua_State *L) {
2776 	const char *msg;
2777 	int x, y;
2778 	UINT32 colour, borderColour;
2779 	int argCount = lua_gettop(L);
2780 
2781 	x = luaL_checkinteger(L,1);
2782 	y = luaL_checkinteger(L,2);
2783 	msg = luaL_checkstring(L,3);
2784 
2785 	if(argCount>=4)
2786 		colour = gui_getcolour(L,4);
2787 	else
2788 		colour = gui_optcolour(L,4,LUA_BUILD_PIXEL(255, 255, 255, 255));
2789 
2790 	if(argCount>=5)
2791 		borderColour = gui_getcolour(L,5);
2792 	else
2793 		borderColour = gui_optcolour(L,5,LUA_BUILD_PIXEL(255, 0, 0, 0));
2794 
2795 	gui_prepare();
2796 
2797 	LuaDisplayString(msg, y, x, colour, borderColour);
2798 
2799 	return 0;
2800 }
2801 
2802 
2803 // gui.gdoverlay([int dx=0, int dy=0,] string str [, sx=0, sy=0, sw, sh] [, float alphamul=1.0])
2804 //
2805 //  Overlays the given image on the screen.
2806 // example: gui.gdoverlay(gd.createFromPng("myimage.png"):gdStr())
gui_gdoverlay(lua_State * L)2807 static int gui_gdoverlay(lua_State *L) {
2808 
2809 	int i,y,x;
2810 	int argCount = lua_gettop(L);
2811 
2812 	int xStartDst = 0;
2813 	int yStartDst = 0;
2814 	int xStartSrc = 0;
2815 	int yStartSrc = 0;
2816 
2817 	const unsigned char* ptr;
2818 
2819 	int trueColor;
2820 	int imgwidth;
2821 	int width;
2822 	int imgheight;
2823 	int height;
2824 	int pitch;
2825 	int alphaMul;
2826 	int opacMap[256];
2827 	int colorsTotal = 0;
2828 	int transparent;
2829 	struct { UINT8 r, g, b, a; } pal[256];
2830 	const UINT8* pix;
2831 	int bytesToNextLine;
2832 
2833 	int index = 1;
2834 	if(lua_type(L,index) == LUA_TNUMBER)
2835 	{
2836 		xStartDst = lua_tointeger(L,index++);
2837 		if(lua_type(L,index) == LUA_TNUMBER)
2838 			yStartDst = lua_tointeger(L,index++);
2839 	}
2840 
2841 	luaL_checktype(L,index,LUA_TSTRING);
2842 	ptr = (const unsigned char*)lua_tostring(L,index++);
2843 
2844 	if (ptr[0] != 255 || (ptr[1] != 254 && ptr[1] != 255))
2845 		luaL_error(L, "bad image data");
2846 	trueColor = (ptr[1] == 254);
2847 	ptr += 2;
2848 	imgwidth = *ptr++ << 8;
2849 	imgwidth |= *ptr++;
2850 	width = imgwidth;
2851 	imgheight = *ptr++ << 8;
2852 	imgheight |= *ptr++;
2853 	height = imgheight;
2854 	if ((!trueColor && *ptr) || (trueColor && !*ptr))
2855 		luaL_error(L, "bad image data");
2856 	ptr++;
2857 	pitch = imgwidth * (trueColor?4:1);
2858 
2859 	if ((argCount - index + 1) >= 4) {
2860 		xStartSrc = luaL_checkinteger(L,index++);
2861 		yStartSrc = luaL_checkinteger(L,index++);
2862 		width = luaL_checkinteger(L,index++);
2863 		height = luaL_checkinteger(L,index++);
2864 	}
2865 
2866 	alphaMul = transparencyModifier;
2867 	if(lua_isnumber(L, index))
2868 		alphaMul = (int)(alphaMul * lua_tonumber(L, index++));
2869 	if(alphaMul <= 0)
2870 		return 0;
2871 
2872 	// since there aren't that many possible opacity levels,
2873 	// do the opacity modification calculations beforehand instead of per pixel
2874 	for(i = 0; i < 128; i++)
2875 	{
2876 		int opac = 255 - ((i << 1) | (i & 1)); // gdAlphaMax = 127, not 255
2877 		opac = (opac * alphaMul) / 255;
2878 		if(opac < 0) opac = 0;
2879 		if(opac > 255) opac = 255;
2880 		opacMap[i] = opac;
2881 	}
2882 	for(i = 128; i < 256; i++)
2883 		opacMap[i] = 0; // what should we do for them, actually?
2884 
2885 	if (!trueColor) {
2886 		colorsTotal = *ptr++ << 8;
2887 		colorsTotal |= *ptr++;
2888 	}
2889 	transparent = *ptr++ << 24;
2890 	transparent |= *ptr++ << 16;
2891 	transparent |= *ptr++ << 8;
2892 	transparent |= *ptr++;
2893 	if (!trueColor) for (i = 0; i < 256; i++) {
2894 		pal[i].r = *ptr++;
2895 		pal[i].g = *ptr++;
2896 		pal[i].b = *ptr++;
2897 		pal[i].a = opacMap[*ptr++];
2898 	}
2899 
2900 	// some of clippings
2901 	if (xStartSrc < 0) {
2902 		width += xStartSrc;
2903 		xStartDst -= xStartSrc;
2904 		xStartSrc = 0;
2905 	}
2906 	if (yStartSrc < 0) {
2907 		height += yStartSrc;
2908 		yStartDst -= yStartSrc;
2909 		yStartSrc = 0;
2910 	}
2911 	if (xStartSrc+width >= imgwidth)
2912 		width = imgwidth - xStartSrc;
2913 	if (yStartSrc+height >= imgheight)
2914 		height = imgheight - yStartSrc;
2915 	if (xStartDst < 0) {
2916 		width += xStartDst;
2917 		if (width <= 0)
2918 			return 0;
2919 		xStartSrc = -xStartDst;
2920 		xStartDst = 0;
2921 	}
2922 	if (yStartDst < 0) {
2923 		height += yStartDst;
2924 		if (height <= 0)
2925 			return 0;
2926 		yStartSrc = -yStartDst;
2927 		yStartDst = 0;
2928 	}
2929 	if (xStartDst+width >= LUA_SCREEN_WIDTH)
2930 		width = LUA_SCREEN_WIDTH - xStartDst;
2931 	if (yStartDst+height >= LUA_SCREEN_HEIGHT)
2932 		height = LUA_SCREEN_HEIGHT - yStartDst;
2933 	if (width <= 0 || height <= 0)
2934 		return 0; // out of screen or invalid size
2935 
2936 	gui_prepare();
2937 
2938 	pix = (const UINT8*)(&ptr[yStartSrc*pitch + (xStartSrc*(trueColor?4:1))]);
2939 	bytesToNextLine = pitch - (width * (trueColor?4:1));
2940 	if (trueColor)
2941 		for (y = yStartDst; y < height+yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine) {
2942 			for (x = xStartDst; x < width+xStartDst && x < LUA_SCREEN_WIDTH; x++, pix += 4) {
2943 				gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(opacMap[pix[0]], pix[1], pix[2], pix[3]));
2944 			}
2945 		}
2946 	else
2947 		for (y = yStartDst; y < height+yStartDst && y < LUA_SCREEN_HEIGHT; y++, pix += bytesToNextLine) {
2948 			for (x = xStartDst; x < width+xStartDst && x < LUA_SCREEN_WIDTH; x++, pix++) {
2949 				gui_drawpixel_fast(x, y, LUA_BUILD_PIXEL(pal[*pix].a, pal[*pix].r, pal[*pix].g, pal[*pix].b));
2950 			}
2951 		}
2952 
2953 	return 0;
2954 }
2955 
2956 
2957 // function gui.register(function f)
2958 //
2959 //  This function will be called just before a graphical update.
2960 //  More complicated, but doesn't suffer any frame delays.
2961 //  Nil will be accepted in place of a function to erase
2962 //  a previously registered function, and the previous function
2963 //  (if any) is returned, or nil if none.
gui_register(lua_State * L)2964 static int gui_register(lua_State *L) {
2965 	// We'll do this straight up.
2966 
2967 	// First set up the stack.
2968 	lua_settop(L,1);
2969 
2970 	// Verify the validity of the entry
2971 	if (!lua_isnil(L,1))
2972 		luaL_checktype(L, 1, LUA_TFUNCTION);
2973 
2974 	// Get the old value
2975 	lua_getfield(L, LUA_REGISTRYINDEX, guiCallbackTable);
2976 
2977 	// Save the new value
2978 	lua_pushvalue(L,1);
2979 	lua_setfield(L, LUA_REGISTRYINDEX, guiCallbackTable);
2980 
2981 	// The old value is on top of the stack. Return it.
2982 	return 1;
2983 }
2984 
2985 
doPopup(lua_State * L,const char * deftype,const char * deficon)2986 static int doPopup(lua_State *L, const char* deftype, const char* deficon) {
2987 	const char *str = luaL_checkstring(L, 1);
2988 	const char* type = lua_type(L,2) == LUA_TSTRING ? lua_tostring(L,2) : deftype;
2989 	const char* icon = lua_type(L,3) == LUA_TSTRING ? lua_tostring(L,3) : deficon;
2990 
2991 	int itype = -1, iters = 0;
2992 	int iicon = -1;
2993 	static const char * const titles [] = {"Notice", "Question", "Warning", "Error"};
2994 	const char* answer = "ok";
2995 
2996 	while(itype == -1 && iters++ < 2)
2997 	{
2998 		if(!stricmp(type, "ok")) itype = 0;
2999 		else if(!stricmp(type, "yesno")) itype = 1;
3000 		else if(!stricmp(type, "yesnocancel")) itype = 2;
3001 		else if(!stricmp(type, "okcancel")) itype = 3;
3002 		else if(!stricmp(type, "abortretryignore")) itype = 4;
3003 		else type = deftype;
3004 	}
3005 	assert(itype >= 0 && itype <= 4);
3006 	if(!(itype >= 0 && itype <= 4)) itype = 0;
3007 
3008 	iters = 0;
3009 	while(iicon == -1 && iters++ < 2)
3010 	{
3011 		if(!stricmp(icon, "message") || !stricmp(icon, "notice")) iicon = 0;
3012 		else if(!stricmp(icon, "question")) iicon = 1;
3013 		else if(!stricmp(icon, "warning")) iicon = 2;
3014 		else if(!stricmp(icon, "error")) iicon = 3;
3015 		else icon = deficon;
3016 	}
3017 	assert(iicon >= 0 && iicon <= 3);
3018 	if(!(iicon >= 0 && iicon <= 3)) iicon = 0;
3019 
3020 #ifdef WIN32
3021 	{
3022 		static const int etypes [] = {MB_OK, MB_YESNO, MB_YESNOCANCEL, MB_OKCANCEL, MB_ABORTRETRYIGNORE};
3023 		static const int eicons [] = {MB_ICONINFORMATION, MB_ICONQUESTION, MB_ICONWARNING, MB_ICONERROR};
3024 		int ianswer = MessageBoxA(hScrnWnd, str, titles[iicon], etypes[itype] | eicons[iicon]);
3025 		switch(ianswer)
3026 		{
3027 			case IDOK: answer = "ok"; break;
3028 			case IDCANCEL: answer = "cancel"; break;
3029 			case IDABORT: answer = "abort"; break;
3030 			case IDRETRY: answer = "retry"; break;
3031 			case IDIGNORE: answer = "ignore"; break;
3032 			case IDYES: answer = "yes"; break;
3033 			case IDNO: answer = "no"; break;
3034 		}
3035 
3036 		lua_pushstring(L, answer);
3037 		return 1;
3038 	}
3039 #else
3040 
3041 	char *t;
3042 #ifdef __linux
3043 	int pid; // appease compiler
3044 
3045 	// Before doing any work, verify the correctness of the parameters.
3046 	if (strcmp(type, "ok") == 0)
3047 		t = "OK:100";
3048 	else if (strcmp(type, "yesno") == 0)
3049 		t = "Yes:100,No:101";
3050 	else if (strcmp(type, "yesnocancel") == 0)
3051 		t = "Yes:100,No:101,Cancel:102";
3052 	else
3053 		return luaL_error(L, "invalid popup type \"%s\"", type);
3054 
3055 	// Can we find a copy of xmessage? Search the path.
3056 
3057 	char *path = strdup(getenv("PATH"));
3058 
3059 	char *current = path;
3060 
3061 	char *colon;
3062 
3063 	int found = 0;
3064 
3065 	while (current) {
3066 		colon = strchr(current, ':');
3067 
3068 		// Clip off the colon.
3069 		*colon++ = 0;
3070 
3071 		int len = strlen(current);
3072 		char *filename = (char*)malloc(len + 12); // always give excess
3073 		snprintf(filename, len+12, "%s/xmessage", current);
3074 
3075 		if (access(filename, X_OK) == 0) {
3076 			free(filename);
3077 			found = 1;
3078 			break;
3079 		}
3080 
3081 		// Failed, move on.
3082 		current = colon;
3083 		free(filename);
3084 
3085 	}
3086 
3087 	free(path);
3088 
3089 	// We've found it?
3090 	if (!found)
3091 		goto use_console;
3092 
3093 	pid = fork();
3094 	if (pid == 0) {// I'm the virgin sacrifice
3095 
3096 		// I'm gonna be dead in a matter of microseconds anyways, so wasted memory doesn't matter to me.
3097 		// Go ahead and abuse strdup.
3098 		char * parameters[] = {"xmessage", "-buttons", t, strdup(str), NULL};
3099 
3100 		execvp("xmessage", parameters);
3101 
3102 		// Aw shitty
3103 		perror("exec xmessage");
3104 		exit(1);
3105 	}
3106 	else if (pid < 0) // something went wrong!!! Oh hell... use the console
3107 		goto use_console;
3108 	else {
3109 		// We're the parent. Watch for the child.
3110 		int r;
3111 		int res = waitpid(pid, &r, 0);
3112 		if (res < 0) // wtf?
3113 			goto use_console;
3114 
3115 		// The return value gets copmlicated...
3116 		if (!WIFEXITED(r)) {
3117 			luaL_error(L, "don't screw with my xmessage process!");
3118 		}
3119 		r = WEXITSTATUS(r);
3120 
3121 		// We assume it's worked.
3122 		if (r == 0)
3123 		{
3124 			return 0; // no parameters for an OK
3125 		}
3126 		if (r == 100) {
3127 			lua_pushstring(L, "yes");
3128 			return 1;
3129 		}
3130 		if (r == 101) {
3131 			lua_pushstring(L, "no");
3132 			return 1;
3133 		}
3134 		if (r == 102) {
3135 			lua_pushstring(L, "cancel");
3136 			return 1;
3137 		}
3138 
3139 		// Wtf?
3140 		return luaL_error(L, "popup failed due to unknown results involving xmessage (%d)", r);
3141 	}
3142 
3143 use_console:
3144 #endif
3145 
3146 	// All else has failed
3147 
3148 	if (strcmp(type, "ok") == 0)
3149 		t = "";
3150 	else if (strcmp(type, "yesno") == 0)
3151 		t = "yn";
3152 	else if (strcmp(type, "yesnocancel") == 0)
3153 		t = "ync";
3154 	else
3155 		return luaL_error(L, "invalid popup type \"%s\"", type);
3156 
3157 	fprintf(stderr, "Lua Message: %s\n", str);
3158 
3159 	while (true) {
3160 		char buffer[64];
3161 
3162 		// We don't want parameters
3163 		if (!t[0]) {
3164 			fprintf(stderr, "[Press Enter]");
3165 			fgets(buffer, sizeof(buffer), stdin);
3166 			// We're done
3167 			return 0;
3168 
3169 		}
3170 		fprintf(stderr, "(%s): ", t);
3171 		fgets(buffer, sizeof(buffer), stdin);
3172 
3173 		// Check if the option is in the list
3174 		if (strchr(t, tolower(buffer[0]))) {
3175 			switch (tolower(buffer[0])) {
3176 			case 'y':
3177 				lua_pushstring(L, "yes");
3178 				return 1;
3179 			case 'n':
3180 				lua_pushstring(L, "no");
3181 				return 1;
3182 			case 'c':
3183 				lua_pushstring(L, "cancel");
3184 				return 1;
3185 			default:
3186 				luaL_error(L, "internal logic error in console based prompts for gui.popup");
3187 
3188 			}
3189 		}
3190 
3191 		// We fell through, so we assume the user answered wrong and prompt again.
3192 
3193 	}
3194 
3195 	// Nothing here, since the only way out is in the loop.
3196 #endif
3197 
3198 }
3199 
input_registerhotkey(lua_State * L)3200 static int input_registerhotkey(lua_State *L)
3201 {
3202 	int hotkeyNumber = luaL_checkinteger(L,1);
3203 	if (hotkeyNumber < 1 || hotkeyNumber > 9)
3204 	{
3205 		luaL_error(L, "input.registerhotkey(n,func) requires 1 <= n <= 9, but got n = %d.", hotkeyNumber);
3206 		return 0;
3207 	}
3208 	else
3209 	{
3210 		const char* key = luaCallIDStrings[LUACALL_HOTKEY_1 + hotkeyNumber-1];
3211 		lua_getfield(L, LUA_REGISTRYINDEX, key);
3212 		lua_replace(L,1);
3213 		if (!lua_isnil(L,2))
3214 			luaL_checktype(L, 2, LUA_TFUNCTION);
3215 		lua_settop(L,2);
3216 		lua_setfield(L, LUA_REGISTRYINDEX, key);
3217 		return 1;
3218 	}
3219 }
3220 
3221 // string gui.popup(string message, string type = "ok", string icon = "message")
3222 // string input.popup(string message, string type = "yesno", string icon = "question")
gui_popup(lua_State * L)3223 static int gui_popup(lua_State *L)
3224 {
3225 	return doPopup(L, "ok", "message");
3226 }
input_popup(lua_State * L)3227 static int input_popup(lua_State *L)
3228 {
3229 	return doPopup(L, "yesno", "question");
3230 }
3231 
3232 #ifdef WIN32
3233 
3234 const char* s_keyToName[256] =
3235 {
3236 	NULL,
3237 	"leftclick",
3238 	"rightclick",
3239 	NULL,
3240 	"middleclick",
3241 	NULL,
3242 	NULL,
3243 	NULL,
3244 	"backspace",
3245 	"tab",
3246 	NULL,
3247 	NULL,
3248 	NULL,
3249 	"enter",
3250 	NULL,
3251 	NULL,
3252 	"shift", // 0x10
3253 	"control",
3254 	"alt",
3255 	"pause",
3256 	"capslock",
3257 	NULL,
3258 	NULL,
3259 	NULL,
3260 	NULL,
3261 	NULL,
3262 	NULL,
3263 	"escape",
3264 	NULL,
3265 	NULL,
3266 	NULL,
3267 	NULL,
3268 	"space", // 0x20
3269 	"pageup",
3270 	"pagedown",
3271 	"end",
3272 	"home",
3273 	"left",
3274 	"up",
3275 	"right",
3276 	"down",
3277 	NULL,
3278 	NULL,
3279 	NULL,
3280 	NULL,
3281 	"insert",
3282 	"delete",
3283 	NULL,
3284 	"0","1","2","3","4","5","6","7","8","9",
3285 	NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3286 	"A","B","C","D","E","F","G","H","I","J",
3287 	"K","L","M","N","O","P","Q","R","S","T",
3288 	"U","V","W","X","Y","Z",
3289 	NULL,
3290 	NULL,
3291 	NULL,
3292 	NULL,
3293 	NULL,
3294 	"numpad0","numpad1","numpad2","numpad3","numpad4","numpad5","numpad6","numpad7","numpad8","numpad9",
3295 	"numpad*","numpad+",
3296 	NULL,
3297 	"numpad-","numpad.","numpad/",
3298 	"F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12",
3299 	"F13","F14","F15","F16","F17","F18","F19","F20","F21","F22","F23","F24",
3300 	NULL,
3301 	NULL,
3302 	NULL,
3303 	NULL,
3304 	NULL,
3305 	NULL,
3306 	NULL,
3307 	NULL,
3308 	"numlock",
3309 	"scrolllock",
3310 	NULL, // 0x92
3311 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3312 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3313 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3314 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3315 	NULL, // 0xB9
3316 	"semicolon",
3317 	"plus",
3318 	"comma",
3319 	"minus",
3320 	"period",
3321 	"slash",
3322 	"tilde",
3323 	NULL, // 0xC1
3324 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3325 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3326 	NULL, NULL, NULL, NULL, NULL, NULL, NULL,
3327 	NULL, // 0xDA
3328 	"leftbracket",
3329 	"backslash",
3330 	"rightbracket",
3331 	"quote",
3332 };
3333 
GetMouseData(UINT32 * md)3334 void GetMouseData(UINT32 *md)
3335 {
3336 	extern UINT32 mousex,mousey;
3337 	RECT t;
3338 	GetClientRect(hScrnWnd, &t);
3339 	//md[0] = (UINT32)(mousex / ((float)t.right / iScreenWidth));
3340 	//md[1] = (UINT32)(mousey / ((float)t.bottom / iScreenHeight));
3341 }
3342 
3343 #endif
3344 
3345 // input.get()
3346 // takes no input, returns a lua table of entries representing the current input state,
3347 // independent of the joypad buttons the emulated game thinks are pressed
3348 // for example:
3349 //   if the user is holding the W key and the left mouse button
3350 //   and has the mouse at the bottom-right corner of the game screen,
3351 //   then this would return {W=true, leftclick=true, xmouse=255, ymouse=223}
input_getcurrentinputstatus(lua_State * L)3352 static int input_getcurrentinputstatus(lua_State *L) {
3353 	lua_newtable(L);
3354 
3355 #ifdef WIN32
3356 	// keyboard and mouse button status
3357 	{
3358 		int i;
3359 		for(i = 1; i < 255; i++) {
3360 			const char* name = s_keyToName[i];
3361 			if(name) {
3362 				int active;
3363 				if(i == VK_CAPITAL || i == VK_NUMLOCK || i == VK_SCROLL)
3364 					active = GetKeyState(i) & 0x01;
3365 				else
3366 					active = GetAsyncKeyState(i) & 0x8000;
3367 				if(active) {
3368 					lua_pushboolean(L, TRUE);
3369 					lua_setfield(L, -2, name);
3370 				}
3371 			}
3372 		}
3373 	}
3374 	// mouse position in game screen pixel coordinates
3375 	{
3376 		UINT32 MouseData[2];
3377 		int x, y;
3378 		GetMouseData(MouseData);
3379 		x = MouseData[0];
3380 		y = MouseData[1];
3381 
3382 		lua_pushinteger(L, x);
3383 		lua_setfield(L, -2, "xmouse");
3384 		lua_pushinteger(L, y);
3385 		lua_setfield(L, -2, "ymouse");
3386 	}
3387 #else
3388 	// NYI (well, return an empty table)
3389 #endif
3390 
3391 	return 1;
3392 }
3393 
3394 
3395 // the following bit operations are ported from LuaBitOp 1.0.1,
3396 // because it can handle the sign bit (bit 31) correctly.
3397 
3398 /*
3399 ** Lua BitOp -- a bit operations library for Lua 5.1.
3400 ** http://bitop.luajit.org/
3401 **
3402 ** Copyright (C) 2008-2009 Mike Pall. All rights reserved.
3403 **
3404 ** Permission is hereby granted, free of charge, to any person obtaining
3405 ** a copy of this software and associated documentation files (the
3406 ** "Software"), to deal in the Software without restriction, including
3407 ** without limitation the rights to use, copy, modify, merge, publish,
3408 ** distribute, sublicense, and/or sell copies of the Software, and to
3409 ** permit persons to whom the Software is furnished to do so, subject to
3410 ** the following conditions:
3411 **
3412 ** The above copyright notice and this permission notice shall be
3413 ** included in all copies or substantial portions of the Software.
3414 **
3415 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
3416 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
3417 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
3418 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
3419 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
3420 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
3421 ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3422 **
3423 ** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
3424 */
3425 
3426 #ifdef _MSC_VER
3427 /* MSVC is stuck in the last century and doesn't have C99's stdint.h. */
3428 typedef __int32 int32_t;
3429 typedef unsigned __int32 uint32_t;
3430 typedef unsigned __int64 uint64_t;
3431 #else
3432 #include <stdint.h>
3433 #endif
3434 
3435 typedef int32_t SBits;
3436 typedef uint32_t UBits;
3437 
3438 typedef union {
3439   lua_Number n;
3440 #ifdef LUA_NUMBER_DOUBLE
3441   uint64_t b;
3442 #else
3443   UBits b;
3444 #endif
3445 } BitNum;
3446 
3447 /* Convert argument to bit type. */
barg(lua_State * L,int idx)3448 static UBits barg(lua_State *L, int idx)
3449 {
3450   BitNum bn;
3451   UBits b;
3452   bn.n = lua_tonumber(L, idx);
3453 #if defined(LUA_NUMBER_DOUBLE)
3454   bn.n += 6755399441055744.0;  /* 2^52+2^51 */
3455 #ifdef SWAPPED_DOUBLE
3456   b = (UBits)(bn.b >> 32);
3457 #else
3458   b = (UBits)bn.b;
3459 #endif
3460 #elif defined(LUA_NUMBER_INT) || defined(LUA_NUMBER_LONG) || \
3461       defined(LUA_NUMBER_LONGLONG) || defined(LUA_NUMBER_LONG_LONG) || \
3462       defined(LUA_NUMBER_LLONG)
3463   if (sizeof(UBits) == sizeof(lua_Number))
3464     b = bn.b;
3465   else
3466     b = (UBits)(SBits)bn.n;
3467 #elif defined(LUA_NUMBER_FLOAT)
3468 #error "A 'float' lua_Number type is incompatible with this library"
3469 #else
3470 #error "Unknown number type, check LUA_NUMBER_* in luaconf.h"
3471 #endif
3472   if (b == 0 && !lua_isnumber(L, idx))
3473     luaL_typerror(L, idx, "number");
3474   return b;
3475 }
3476 
3477 /* Return bit type. */
3478 #define BRET(b)  lua_pushnumber(L, (lua_Number)(SBits)(b)); return 1;
3479 
bit_tobit(lua_State * L)3480 static int bit_tobit(lua_State *L) { BRET(barg(L, 1)) }
bit_bnot(lua_State * L)3481 static int bit_bnot(lua_State *L) { BRET(~barg(L, 1)) }
3482 
3483 #define BIT_OP(func, opr) \
3484   static int func(lua_State *L) { int i; UBits b = barg(L, 1); \
3485     for (i = lua_gettop(L); i > 1; i--) b opr barg(L, i); BRET(b) }
3486 BIT_OP(bit_band, &=)
3487 BIT_OP(bit_bor, |=)
3488 BIT_OP(bit_bxor, ^=)
3489 
3490 #define bshl(b, n)  (b << n)
3491 #define bshr(b, n)  (b >> n)
3492 #define bsar(b, n)  ((SBits)b >> n)
3493 #define brol(b, n)  ((b << n) | (b >> (32-n)))
3494 #define bror(b, n)  ((b << (32-n)) | (b >> n))
3495 #define BIT_SH(func, fn) \
3496   static int func(lua_State *L) { \
3497     UBits b = barg(L, 1); UBits n = barg(L, 2) & 31; BRET(fn(b, n)) }
BIT_SH(bit_lshift,bshl)3498 BIT_SH(bit_lshift, bshl)
3499 BIT_SH(bit_rshift, bshr)
3500 BIT_SH(bit_arshift, bsar)
3501 BIT_SH(bit_rol, brol)
3502 BIT_SH(bit_ror, bror)
3503 
3504 static int bit_bswap(lua_State *L)
3505 {
3506   UBits b = barg(L, 1);
3507   b = (b >> 24) | ((b >> 8) & 0xff00) | ((b & 0xff00) << 8) | (b << 24);
3508   BRET(b)
3509 }
3510 
bit_tohex(lua_State * L)3511 static int bit_tohex(lua_State *L)
3512 {
3513   UBits b = barg(L, 1);
3514   SBits n = lua_isnone(L, 2) ? 8 : (SBits)barg(L, 2);
3515   const char *hexdigits = "0123456789abcdef";
3516   char buf[8];
3517   int i;
3518   if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
3519   if (n > 8) n = 8;
3520   for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
3521   lua_pushlstring(L, buf, (size_t)n);
3522   return 1;
3523 }
3524 
3525 static const struct luaL_Reg bit_funcs[] = {
3526   { "tobit",	bit_tobit },
3527   { "bnot",	bit_bnot },
3528   { "band",	bit_band },
3529   { "bor",	bit_bor },
3530   { "bxor",	bit_bxor },
3531   { "lshift",	bit_lshift },
3532   { "rshift",	bit_rshift },
3533   { "arshift",	bit_arshift },
3534   { "rol",	bit_rol },
3535   { "ror",	bit_ror },
3536   { "bswap",	bit_bswap },
3537   { "tohex",	bit_tohex },
3538   { NULL, NULL }
3539 };
3540 
3541 /* Signed right-shifts are implementation-defined per C89/C99.
3542 ** But the de facto standard are arithmetic right-shifts on two's
3543 ** complement CPUs. This behaviour is required here, so test for it.
3544 */
3545 #define BAD_SAR		(bsar(-8, 2) != (SBits)-2)
3546 
luabitop_validate(lua_State * L)3547 BOOL luabitop_validate(lua_State *L) // originally named as luaopen_bit
3548 {
3549   UBits b;
3550   lua_pushnumber(L, (lua_Number)1437217655L);
3551   b = barg(L, -1);
3552   if (b != (UBits)1437217655L || BAD_SAR) {  /* Perform a simple self-test. */
3553     const char *msg = "compiled with incompatible luaconf.h";
3554 #ifdef LUA_NUMBER_DOUBLE
3555 #ifdef WIN32
3556     if (b == (UBits)1610612736L)
3557       msg = "use D3DCREATE_FPU_PRESERVE with DirectX";
3558 #endif
3559     if (b == (UBits)1127743488L)
3560       msg = "not compiled with SWAPPED_DOUBLE";
3561 #endif
3562     if (BAD_SAR)
3563       msg = "arithmetic right-shift broken";
3564     luaL_error(L, "bit library self-test failed (%s)", msg);
3565     return FALSE;
3566   }
3567   return TRUE;
3568 }
3569 
3570 // LuaBitOp ends here
3571 
bit_bshift_emulua(lua_State * L)3572 static int bit_bshift_emulua(lua_State *L)
3573 {
3574 	int shift = luaL_checkinteger(L,2);
3575 	if (shift < 0) {
3576 		lua_pushinteger(L, -shift);
3577 		lua_replace(L, 2);
3578 		return bit_lshift(L);
3579 	}
3580 	else
3581 		return bit_rshift(L);
3582 }
3583 
bitbit(lua_State * L)3584 static int bitbit(lua_State *L)
3585 {
3586 	int rv = 0;
3587 	int numArgs = lua_gettop(L);
3588 	int i;
3589 	for(i = 1; i <= numArgs; i++) {
3590 		int where = luaL_checkinteger(L,i);
3591 		if (where >= 0 && where < 32)
3592 			rv |= (1 << where);
3593 	}
3594 	lua_settop(L,0);
3595 	BRET(rv);
3596 }
3597 
3598 
3599 // The function called periodically to ensure Lua doesn't run amok.
FBA_LuaHookFunction(lua_State * L,lua_Debug * dbg)3600 static void FBA_LuaHookFunction(lua_State *L, lua_Debug *dbg) {
3601 	if (numTries-- == 0) {
3602 
3603 		int kill = 0;
3604 
3605 #ifdef WIN32
3606 		// Uh oh
3607 		int ret = MessageBoxA(hScrnWnd, "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)", "Lua Script Gone Nuts?", MB_YESNO);
3608 
3609 		if (ret == IDYES) {
3610 			kill = 1;
3611 		}
3612 
3613 #else
3614 		fprintf(stderr, "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");
3615 		char buffer[64];
3616 		while (TRUE) {
3617 			fprintf(stderr, "(y/n): ");
3618 			fgets(buffer, sizeof(buffer), stdin);
3619 			if (buffer[0] == 'y' || buffer[0] == 'Y') {
3620 				kill = 1;
3621 				break;
3622 			}
3623 
3624 			if (buffer[0] == 'n' || buffer[0] == 'N')
3625 				break;
3626 		}
3627 #endif
3628 
3629 		if (kill) {
3630 			luaL_error(L, "Killed by user request.");
3631 			FBA_LuaOnStop();
3632 		}
3633 
3634 		// else, kill the debug hook.
3635 		lua_sethook(L, NULL, 0, 0);
3636 	}
3637 }
3638 
3639 
CallExitFunction()3640 void CallExitFunction() {
3641 	int errorcode = 0;
3642 
3643 	if (!LUA)
3644 		return;
3645 
3646 	lua_settop(LUA, 0);
3647 	lua_getfield(LUA, LUA_REGISTRYINDEX, luaCallIDStrings[LUACALL_BEFOREEXIT]);
3648 
3649 	if (lua_isfunction(LUA, -1))
3650 	{
3651 		chdir(luaCWD);
3652 		errorcode = lua_pcall(LUA, 0, 0, 0);
3653 		chdir(fbnCWD);
3654 	}
3655 
3656 	if (errorcode)
3657 		HandleCallbackError(LUA);
3658 }
3659 
3660 
3661 static const struct luaL_reg fbalib [] = {
3662 	{"hardreset", fba_hardreset},
3663 	{"romname", fba_romname},
3664 	{"gamename", fba_gamename},
3665 	{"parentname", fba_parentname},
3666 	{"sourcename", fba_sourcename},
3667 	{"speedmode", fba_speedmode},
3668 	{"frameadvance", fba_frameadvance},
3669 	{"pause", fba_pause},
3670 	{"unpause", fba_unpause},
3671 	{"framecount", movie_framecount},
3672 	{"registerbefore", fba_registerbefore},
3673 	{"registerafter", fba_registerafter},
3674 	{"registerexit", fba_registerexit},
3675 	{"registerstart", fba_registerstart},
3676 	{"message", fba_message},
3677 	{"print", print}, // sure, why not
3678 	{"screenwidth", fba_screenwidth},
3679 	{"screenheight", fba_screenheight},
3680 	{"getreadonly", movie_getreadonly},
3681 	{"setreadonly", movie_setreadonly},
3682 	{NULL,NULL}
3683 };
3684 
3685 static const struct luaL_reg memorylib [] = {
3686 	{"readbyte", memory_readbyte},
3687 	{"readbytesigned", memory_readbytesigned},
3688 	{"readword", memory_readword},
3689 	{"readwordsigned", memory_readwordsigned},
3690 	{"readdword", memory_readdword},
3691 	{"readdwordsigned", memory_readdwordsigned},
3692 	{"readbyterange", memory_readbyterange},
3693 	{"writebyte", memory_writebyte},
3694 	{"writeword", memory_writeword},
3695 	{"writedword", memory_writedword},
3696 	// alternate naming scheme for word and double-word and unsigned
3697 	{"readbyteunsigned", memory_readbyte},
3698 	{"readwordunsigned", memory_readword},
3699 	{"readdwordunsigned", memory_readdword},
3700 	{"readshort", memory_readword},
3701 	{"readshortunsigned", memory_readword},
3702 	{"readshortsigned", memory_readwordsigned},
3703 	{"readlong", memory_readdword},
3704 	{"readlongunsigned", memory_readdword},
3705 	{"readlongsigned", memory_readdwordsigned},
3706 	{"writeshort", memory_writeword},
3707 	{"writelong", memory_writedword},
3708 
3709 	// memory hooks
3710 	{"registerwrite", memory_registerwrite},
3711 	{"registerread", memory_registerread},
3712 	{"registerexec", memory_registerexec},
3713 
3714 	// registers
3715 	{"getregister", memory_getregister},
3716 	{"setregister", memory_setregister},
3717 
3718 	{NULL,NULL}
3719 };
3720 
3721 static const struct luaL_reg joypadlib[] = {
3722 	{"get", joypad_get},
3723 	{"getdown", joypad_getdown},
3724 	{"getup", joypad_getup},
3725 	{"set", joypad_set},
3726 	// alternative names
3727 	{"read", joypad_get},
3728 	{"readdown", joypad_getdown},
3729 	{"readup", joypad_getup},
3730 	{"write", joypad_set},
3731 	{NULL,NULL}
3732 };
3733 
3734 static const struct luaL_reg savestatelib[] = {
3735 	{"create", savestate_create},
3736 	{"save", savestate_save},
3737 	{"load", savestate_load},
3738 
3739 	{"registersave", savestate_registersave},
3740 	{"registerload", savestate_registerload},
3741 	{"savescriptdata", savestate_savescriptdata},
3742 	{"loadscriptdata", savestate_loadscriptdata},
3743 
3744 	{NULL,NULL}
3745 };
3746 
3747 static const struct luaL_reg movielib[] = {
3748 	{"framecount", movie_framecount},
3749 	{"mode", movie_mode},
3750 	{"rerecordcounting", movie_rerecordcounting},
3751 	{"setreadonly", movie_setreadonly},
3752 	{"getreadonly", movie_getreadonly},
3753 	{"stop", movie_stop},
3754 	{"close", movie_stop}, // (alternative name)
3755 	{"playbeginning", movie_playbeginning},
3756 	{"length", movie_length},
3757 	{NULL,NULL}
3758 };
3759 
3760 static const struct luaL_reg guilib[] = {
3761 	{"register", gui_register},
3762 	{"text", gui_text},
3763 	{"box", gui_drawbox},
3764 	{"line", gui_drawline},
3765 	{"pixel", gui_drawpixel},
3766 	{"opacity", gui_setopacity},
3767 	{"transparency", gui_transparency},
3768 	{"popup", gui_popup},
3769 	{"parsecolor", gui_parsecolor},
3770 	{"savescreenshot", gui_savescreenshot},
3771 	{"gdscreenshot", gui_gdscreenshot},
3772 	{"gdoverlay", gui_gdoverlay},
3773 	{"getpixel", gui_getpixel},
3774 	{"clearuncommitted", gui_clearuncommitted},
3775 	// alternative names
3776 	{"drawtext", gui_text},
3777 	{"drawbox", gui_drawbox},
3778 	{"drawline", gui_drawline},
3779 	{"drawpixel", gui_drawpixel},
3780 	{"setpixel", gui_drawpixel},
3781 	{"writepixel", gui_drawpixel},
3782 	{"rect", gui_drawbox},
3783 	{"drawrect", gui_drawbox},
3784 	{"drawimage", gui_gdoverlay},
3785 	{"image", gui_gdoverlay},
3786 	{"readpixel", gui_getpixel},
3787 	{NULL,NULL}
3788 };
3789 
3790 static const struct luaL_reg inputlib[] = {
3791 	{"get", input_getcurrentinputstatus},
3792 	{"registerhotkey", input_registerhotkey},
3793 	{"popup", input_popup},
3794 	// alternative names
3795 	{"read", input_getcurrentinputstatus},
3796 	{NULL, NULL}
3797 };
3798 
3799 
FBA_LuaFrameBoundary()3800 void FBA_LuaFrameBoundary() {
3801 	lua_State *thread;
3802 	int result;
3803 
3804 	// HA!
3805 	if (!LUA || !luaRunning || !bDrvOkay)
3806 		return;
3807 
3808 	// Our function needs calling
3809 	lua_settop(LUA,0);
3810 	lua_getfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
3811 	thread = lua_tothread(LUA,1);
3812 
3813 	// Lua calling C must know that we're busy inside a frame boundary
3814 	frameBoundary = TRUE;
3815 	frameAdvanceWaiting = FALSE;
3816 
3817 	numTries = MAX_TRIES;
3818 	chdir(luaCWD);
3819 	result = lua_resume(thread, 0);
3820 	chdir(fbnCWD);
3821 
3822 	if (result == LUA_YIELD) {
3823 		// Okay, we're fine with that.
3824 	} else if (result != 0) {
3825 		// Done execution by bad causes
3826 		FBA_LuaOnStop();
3827 		lua_pushnil(LUA);
3828 		lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
3829 
3830 		// Error?
3831 #ifdef WIN32
3832 		MessageBoxA( hScrnWnd, lua_tostring(thread,-1), "Lua run error", MB_OK | MB_ICONSTOP);
3833 #else
3834 		fprintf(stderr, "Lua thread bombed out: %s\n", lua_tostring(thread,-1));
3835 #endif
3836 
3837 	} else {
3838 		FBA_LuaOnStop();
3839 		//VidSNewTinyMsg(_T("Script died of natural causes.\n"));
3840 	}
3841 
3842 	// Past here, the nes actually runs, so any Lua code is called mid-frame. We must
3843 	// not do anything too stupid, so let ourselves know.
3844 	frameBoundary = FALSE;
3845 
3846 	if (!frameAdvanceWaiting) {
3847 		FBA_LuaOnStop();
3848 	}
3849 }
3850 
3851 
3852 /**
3853  * Loads and runs the given Lua script.
3854  * The emulator MUST be paused for this function to be
3855  * called. Otherwise, all frame boundary assumptions go out the window.
3856  *
3857  * Returns true on success, false on failure.
3858  */
FBA_LoadLuaCode(const char * filename)3859 int FBA_LoadLuaCode(const char *filename) {
3860 	lua_State *thread;
3861 	int result;
3862 	char dir[_MAX_PATH];
3863 	char *slash, *backslash;
3864 	const char *luafile = filename;
3865 
3866 	if (luafile != luaScriptName)
3867 	{
3868 		if (luaScriptName) free(luaScriptName);
3869 		luaScriptName = strdup(luafile);
3870 	}
3871 
3872 	// Set current directory from luafile (for dofile)
3873 	_getcwd(fbnCWD, _MAX_PATH);
3874 	strcpy(dir, luafile);
3875 	slash = strrchr(dir, '/');
3876 	backslash = strrchr(dir, '\\');
3877 	if (!slash || (backslash && backslash < slash))
3878 		slash = backslash;
3879 	if (slash) {
3880 		slash[1] = '\0';    // keep slash itself for some reasons
3881 		if (!LuaConsoleHWnd) {
3882 			luafile+= strlen (dir);
3883 		}
3884 		_chdir(dir);
3885 	}
3886 	_getcwd(luaCWD, _MAX_PATH);
3887 
3888 	FBA_LuaStop();
3889 	if (!LUA) {
3890 		LUA = lua_open();
3891 		luaL_openlibs(LUA);
3892 
3893 		luaL_register(LUA, "emu", fbalib);
3894 		luaL_register(LUA, "fba", fbalib);
3895 		luaL_register(LUA, "memory", memorylib);
3896 		luaL_register(LUA, "joypad", joypadlib);
3897 		luaL_register(LUA, "savestate", savestatelib);
3898 		luaL_register(LUA, "movie", movielib);
3899 		luaL_register(LUA, "gui", guilib);
3900 		luaL_register(LUA, "input", inputlib);
3901 		luaL_register(LUA, "bit", bit_funcs); // LuaBitOp library
3902 		lua_settop(LUA, 0); // clean the stack, because each call to luaL_register leaves a table on top
3903 
3904 		// register a few utility functions outside of libraries (in the global namespace)
3905 		lua_register(LUA, "print", print);
3906 		lua_register(LUA, "tostring", tostring);
3907 		lua_register(LUA, "addressof", addressof);
3908 		lua_register(LUA, "copytable", copytable);
3909 
3910 		// old bit operation functions
3911 		lua_register(LUA, "AND", bit_band);
3912 		lua_register(LUA, "OR", bit_bor);
3913 		lua_register(LUA, "XOR", bit_bxor);
3914 		lua_register(LUA, "SHIFT", bit_bshift_emulua);
3915 		lua_register(LUA, "BIT", bitbit);
3916 
3917 		luabitop_validate(LUA);
3918 
3919 		// push arrays for storing hook functions in
3920 		for(int i = 0; i < LUAMEMHOOK_COUNT; i++)
3921 		{
3922 			lua_newtable(LUA);
3923 			lua_setfield(LUA, LUA_REGISTRYINDEX, luaMemHookTypeStrings[i]);
3924 		}
3925 	}
3926 
3927 	// We make our thread NOW because we want it at the bottom of the stack.
3928 	// If all goes wrong, we let the garbage collector remove it.
3929 	thread = lua_newthread(LUA);
3930 
3931 	// Load the data
3932 	result = luaL_loadfile(LUA, luafile);
3933 
3934 	if (result) {
3935 #ifdef WIN32
3936 		// Doing this here caused nasty problems; reverting to MessageBox-from-dialog behavior.
3937 		MessageBoxA(NULL, lua_tostring(LUA,-1), "Lua load error", MB_OK | MB_ICONSTOP);
3938 #else
3939 		fprintf(stderr, "Failed to compile file: %s\n", lua_tostring(LUA,-1));
3940 #endif
3941 
3942 		// Wipe the stack. Our thread
3943 		lua_settop(LUA,0);
3944 		_chdir(fbnCWD);
3945 		return 0; // Oh shit.
3946 	}
3947 
3948 
3949 	// Get our function into it
3950 	lua_xmove(LUA, thread, 1);
3951 
3952 	// Save the thread to the registry. This is why I make the thread FIRST.
3953 	lua_setfield(LUA, LUA_REGISTRYINDEX, frameAdvanceThread);
3954 
3955 
3956 	// Initialize settings
3957 	luaRunning = TRUE;
3958 	skipRerecords = FALSE;
3959 	numMemHooks = 0;
3960 	transparencyModifier = 255; // opaque
3961 	lua_joypads_used = 0; // not used
3962 
3963 #ifdef WIN32
3964 	info_print = PrintToWindowConsole;
3965 	info_onstart = WinLuaOnStart;
3966 	info_onstop = WinLuaOnStop;
3967 	//if(!LuaConsoleHWnd)
3968 	//	LuaConsoleHWnd = CreateDialog(hAppInst, MAKEINTRESOURCE(IDD_LUA), NULL, (DLGPROC) DlgLuaScriptDialog);
3969 	info_uid = (INT64)LuaConsoleHWnd;
3970 #else
3971 	info_print = NULL;
3972 	info_onstart = NULL;
3973 	info_onstop = NULL;
3974 #endif
3975 	if (info_onstart)
3976 		info_onstart(info_uid);
3977 
3978 	// And run it right now. :)
3979 	FBA_LuaFrameBoundary();
3980 
3981 	// Set up our protection hook to be executed once every 10,000 bytecode instructions.
3982 	lua_sethook(thread, FBA_LuaHookFunction, LUA_MASKCOUNT, 10000);
3983 
3984 	_chdir(fbnCWD);
3985 
3986 	// We're done.
3987 	return 1;
3988 }
3989 
3990 
3991 /**
3992  * Equivalent to repeating the last FBA_LoadLuaCode() call.
3993  */
FBA_ReloadLuaCode()3994 void FBA_ReloadLuaCode()
3995 {
3996 	if (!luaScriptName)
3997 		VidSNewTinyMsg(_T("There's no script to reload."));
3998 	else
3999 		FBA_LoadLuaCode(luaScriptName);
4000 }
4001 
4002 
4003 /**
4004  * Terminates a running Lua script by killing the whole Lua engine.
4005  *
4006  * Always safe to call, except from within a lua call itself (duh).
4007  *
4008  */
FBA_LuaStop()4009 void FBA_LuaStop() {
4010 	//already killed
4011 	if (!LUA) return;
4012 
4013 	//execute the user's shutdown callbacks
4014 	CallExitFunction();
4015 
4016 	/*info.*/numMemHooks = 0;
4017 	for(int i = 0; i < LUAMEMHOOK_COUNT; i++)
4018 		CalculateMemHookRegions((LuaMemHookType)i);
4019 
4020 	if (info_onstop)
4021 		info_onstop(info_uid);
4022 
4023 	lua_close(LUA); // this invokes our garbage collectors for us
4024 	LUA = NULL;
4025 	FBA_LuaOnStop();
4026 }
4027 
4028 
4029 /**
4030  * Returns true if there is a Lua script running.
4031  *
4032  */
FBA_LuaRunning()4033 int FBA_LuaRunning() {
4034 	// FIXME: return false when no callback functions are registered.
4035 	return (int) (LUA != NULL); // should return true if callback functions are active.
4036 }
4037 
4038 
4039 /**
4040  * Returns true if Lua would like to steal the given joypad control.
4041  */
FBA_LuaUsingJoypad()4042 int FBA_LuaUsingJoypad() {
4043 	if (!FBA_LuaRunning())
4044 		return 0;
4045 	return lua_joypads_used;
4046 }
4047 
4048 
4049 /**
4050  * Reads the buttons Lua is feeding for the given joypad, in the same
4051  * format as the OS-specific code.
4052  *
4053  * This function must not be called more than once per frame. Ideally exactly once
4054  * per frame (if FBA_LuaUsingJoypad says it's safe to do so)
4055  */
FBA_LuaReadJoypad()4056 UINT32 FBA_LuaReadJoypad() {
4057 	if (!FBA_LuaRunning())
4058 		return 1;
4059 
4060 	if (lua_joypads_used) {
4061 		// Update the values of all the inputs
4062 		struct GameInp* pgi = NULL;
4063 		unsigned int i;
4064 		for (i = 0, pgi = GameInp; i < nGameInpCount; i++, pgi++) {
4065 			if (pgi->nType == 0) {
4066 				continue;
4067 			}
4068 			struct BurnInputInfo bii;
4069 
4070 			// Get the name of the input
4071 			BurnDrvGetInputInfo(&bii, i);
4072 
4073 			// skip unused inputs
4074 			if (bii.pVal == NULL) {
4075 				continue;
4076 			}
4077 			if (bii.nType & BIT_GROUP_ANALOG) {
4078 				*bii.pShortVal = lua_joypads[i];
4079 			}
4080 			else {
4081 				if (bii.nType & BIT_DIGITAL && !(bii.nType & BIT_GROUP_CONSTANT)) {
4082 					if(lua_joypads[i] == 1)
4083 						*bii.pVal = 1;
4084 					if(lua_joypads[i] == 2)
4085 						*bii.pVal = 0;
4086 				}
4087 				else {
4088 					*bii.pVal = lua_joypads[i];
4089 				}
4090 			}
4091 //			dprintf(_T("*READ_JOY*: '%s' %d: "),_AtoT(bii.szName),lua_joypads[i]);
4092 		}
4093 
4094 		lua_joypads_used = 0;
4095 		memset(lua_joypads,0,sizeof(lua_joypads));
4096 		return 0;
4097 	}
4098 	else
4099 		return 1; // disconnected
4100 }
4101 
4102 
4103 /**
4104  * If this function returns true, the movie code should NOT increment
4105  * the rerecord count for a load-state.
4106  *
4107  * This function will not return true if a script is not running.
4108  */
FBA_LuaRerecordCountSkip()4109 int FBA_LuaRerecordCountSkip() {
4110 	// FIXME: return true if (there are any active callback functions && skipRerecords)
4111 	return LUA && luaRunning && skipRerecords;
4112 }
4113 
4114 
4115 /**
4116  * Given an 8-bit screen with the indicated resolution,
4117  * draw the current GUI onto it.
4118  *
4119  * Currently we only support 256x* resolutions.
4120  */
FBA_LuaGui(unsigned char * s,int width,int height,int bpp,int pitch)4121 void FBA_LuaGui(unsigned char *s, int width, int height, int bpp, int pitch) {
4122 	XBuf = (UINT8 *)s;
4123 
4124 	iScreenWidth  = width;
4125 	iScreenHeight = height;
4126 	iScreenBpp    = bpp;
4127 	iScreenPitch  = pitch;
4128 
4129 	LUA_SCREEN_WIDTH  = width;
4130 	LUA_SCREEN_HEIGHT = height;
4131 
4132 	if (!LUA || !bDrvOkay/* || !luaRunning*/)
4133 		return;
4134 
4135 //	dprintf(_T("*LUA GUI START*: x:%d y:%d d:%d p:%d\n"),width,height,bpp,pitch);
4136 
4137 	// First, check if we're being called by anybody
4138 	lua_getfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
4139 
4140 	if (lua_isfunction(LUA, -1)) {
4141 		int ret;
4142 
4143 		// We call it now
4144 		numTries = MAX_TRIES;
4145 		chdir(luaCWD);
4146 		ret = lua_pcall(LUA, 0, 0, 0);
4147 		chdir(fbnCWD);
4148 		if (ret != 0) {
4149 #ifdef WIN32
4150 			MessageBoxA(hScrnWnd, lua_tostring(LUA, -1), "Lua Error in GUI function", MB_OK);
4151 #else
4152 			fprintf(stderr, "Lua error in gui.register function: %s\n", lua_tostring(LUA, -1));
4153 #endif
4154 			// This is grounds for trashing the function
4155 			lua_pushnil(LUA);
4156 			lua_setfield(LUA, LUA_REGISTRYINDEX, guiCallbackTable);
4157 		}
4158 	}
4159 
4160 	// And wreak the stack
4161 	lua_settop(LUA, 0);
4162 
4163 	if (gui_used == GUI_CLEAR || !gui_enabled)
4164 		return;
4165 
4166 	gui_used = GUI_USED_SINCE_LAST_FRAME;
4167 
4168 	int x, y;
4169 
4170 	switch(bpp)
4171 	{
4172 	case 2:
4173 	 {
4174 		UINT16 *screen = (UINT16*) s;
4175 		int ppl = pitch/2;
4176 		for (y=0; y < height && y < LUA_SCREEN_HEIGHT; y++) {
4177 			for (x=0; x < LUA_SCREEN_WIDTH; x++) {
4178 				const UINT8 gui_alpha = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+3];
4179 				if (gui_alpha == 0) {
4180 					// do nothing
4181 					continue;
4182 				}
4183 
4184 				const UINT8 gui_red   = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+2];
4185 				const UINT8 gui_green = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+1];
4186 				const UINT8 gui_blue  = gui_data[(y*LUA_SCREEN_WIDTH+x)*4];
4187 				int red, green, blue;
4188 
4189 				if (gui_alpha == 255) {
4190 					// direct copy
4191 					red = gui_red;
4192 					green = gui_green;
4193 					blue = gui_blue;
4194 				}
4195 				else {
4196 					// alpha-blending
4197 					const UINT8 scr_red   = ((screen[y*ppl + x] >> 11) & 31) << 3;
4198 					const UINT8 scr_green = ((screen[y*ppl + x] >> 5)  & 63) << 2;
4199 					const UINT8 scr_blue  = ( screen[y*ppl + x]        & 31) << 3;
4200 					red   = (((int) gui_red   - scr_red)   * gui_alpha / 255 + scr_red)   & 255;
4201 					green = (((int) gui_green - scr_green) * gui_alpha / 255 + scr_green) & 255;
4202 					blue  = (((int) gui_blue  - scr_blue)  * gui_alpha / 255 + scr_blue)  & 255;
4203 				}
4204 				screen[y*ppl + x] =  ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
4205 			}
4206 		}
4207 		break;
4208 	 }
4209 	case 3:
4210 	 {
4211 		#define bytesPerPixel   3
4212 		UINT8 *screen = (UINT8*) s;
4213 		for (y=0; y < height && y < LUA_SCREEN_HEIGHT; y++) {
4214 			for (x=0; x < LUA_SCREEN_WIDTH; x++) {
4215 				const UINT8 gui_alpha = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+3];
4216 				if (gui_alpha == 0) {
4217 					// do nothing
4218 					continue;
4219 				}
4220 
4221 				const UINT8 gui_red   = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+2];
4222 				const UINT8 gui_green = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+1];
4223 				const UINT8 gui_blue  = gui_data[(y*LUA_SCREEN_WIDTH+x)*4];
4224 				int red, green, blue;
4225 
4226 				if (gui_alpha == 255) {
4227 					// direct copy
4228 					red = gui_red;
4229 					green = gui_green;
4230 					blue = gui_blue;
4231 				}
4232 				else {
4233 					// alpha-blending
4234 					const UINT8 scr_red   = screen[y*pitch + x*bytesPerPixel + 2];
4235 					const UINT8 scr_green = screen[y*pitch + x*bytesPerPixel + 1];
4236 					const UINT8 scr_blue  = screen[y*pitch + x*bytesPerPixel];
4237 					red   = (((int) gui_red   - scr_red)   * gui_alpha / 255 + scr_red)   & 255;
4238 					green = (((int) gui_green - scr_green) * gui_alpha / 255 + scr_green) & 255;
4239 					blue  = (((int) gui_blue  - scr_blue)  * gui_alpha / 255 + scr_blue)  & 255;
4240 				}
4241 				screen[y*pitch + x*bytesPerPixel] = blue;
4242 				screen[y*pitch + x*bytesPerPixel + 1] = green;
4243 				screen[y*pitch + x*bytesPerPixel + 2] = red;
4244 			}
4245 		}
4246 		#undef bytesPerPixel
4247 		break;
4248 	 }
4249 	case 4:
4250 	 {
4251 		#define bytesPerPixel   4
4252 		UINT8 *screen = (UINT8*) s;
4253 		for (y=0; y < height && y < LUA_SCREEN_HEIGHT; y++) {
4254 			for (x=0; x < LUA_SCREEN_WIDTH; x++) {
4255 				const UINT8 gui_alpha = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+3];
4256 				if (gui_alpha == 0) {
4257 					// do nothing
4258 					continue;
4259 				}
4260 
4261 				const UINT8 gui_red   = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+2];
4262 				const UINT8 gui_green = gui_data[(y*LUA_SCREEN_WIDTH+x)*4+1];
4263 				const UINT8 gui_blue  = gui_data[(y*LUA_SCREEN_WIDTH+x)*4];
4264 				int red, green, blue;
4265 
4266 				if (gui_alpha == 255) {
4267 					// direct copy
4268 					red = gui_red;
4269 					green = gui_green;
4270 					blue = gui_blue;
4271 				}
4272 				else {
4273 					// alpha-blending
4274 					const UINT8 scr_red   = screen[y*pitch + x*bytesPerPixel + 2];
4275 					const UINT8 scr_green = screen[y*pitch + x*bytesPerPixel + 1];
4276 					const UINT8 scr_blue  = screen[y*pitch + x*bytesPerPixel];
4277 					red   = (((int) gui_red   - scr_red)   * gui_alpha / 255 + scr_red)   & 255;
4278 					green = (((int) gui_green - scr_green) * gui_alpha / 255 + scr_green) & 255;
4279 					blue  = (((int) gui_blue  - scr_blue)  * gui_alpha / 255 + scr_blue)  & 255;
4280 				}
4281 				screen[y*pitch + x*bytesPerPixel] = blue;
4282 				screen[y*pitch + x*bytesPerPixel + 1] = green;
4283 				screen[y*pitch + x*bytesPerPixel + 2] = red;
4284 			}
4285 		}
4286 		#undef bytesPerPixel
4287 		break;
4288 	 }
4289 	default:
4290 		assert(false /* unsupported color-depth */);
4291 	}
4292 	return;
4293 }
4294 
4295 
FBA_LuaClearGui()4296 void FBA_LuaClearGui() {
4297 	gui_used = GUI_CLEAR;
4298 	if (gui_data) {
4299 		free(gui_data);
4300 		gui_data = NULL;
4301 	}
4302 }
4303 
FBA_LuaEnableGui(UINT8 enabled)4304 void FBA_LuaEnableGui(UINT8 enabled) {
4305 	gui_enabled = enabled;
4306 }
4307 
4308 
FBA_GetLuaState()4309 lua_State* FBA_GetLuaState() {
4310 	return LUA;
4311 }
FBA_GetLuaScriptName()4312 char* FBA_GetLuaScriptName() {
4313 	return luaScriptName;
4314 }
4315