1 // Windows interface layer
2 // for the Build Engine
3 // by Jonathon Fowler (jf@jonof.id.au)
4 //
5 // This is all very ugly.
6 
7 #ifndef _WIN32
8 #error winlayer.c is for Windows only.
9 #endif
10 
11 #define WINVER 0x0600
12 #define _WIN32_WINNT 0x0600
13 
14 #define WIN32_LEAN_AND_MEAN
15 #include <windows.h>
16 #include <xinput.h>
17 #include <math.h>
18 
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <signal.h>
22 #include <stdarg.h>
23 #include <commdlg.h>
24 
25 #include "build.h"
26 
27 #if USE_OPENGL
28 #include "glbuild.h"
29 #include "wglext.h"
30 #endif
31 
32 #include "winlayer.h"
33 #include "pragmas.h"
34 #include "a.h"
35 #include "osd.h"
36 
37 
38 // undefine to restrict windowed resolutions to conventional sizes
39 #define ANY_WINDOWED_SIZE
40 
41 int   _buildargc = 0;
42 const char **_buildargv = NULL;
43 static char *argvbuf = NULL;
44 
45 // Windows crud
46 static HINSTANCE hInstance = 0;
47 static HWND hWindow = 0;
48 static HDC hDCWindow = NULL;
49 #define WINDOW_CLASS "buildapp"
50 static BOOL window_class_registered = FALSE;
51 static HANDLE instanceflag = NULL;
52 
53 int    backgroundidle = 1;
54 static char apptitle[256] = "Build Engine";
55 static char wintitle[256] = "";
56 
57 static WORD sysgamma[3][256];
58 extern int gammabrightness;
59 extern float curgamma;
60 
61 #if USE_OPENGL
62 // OpenGL stuff
63 static HGLRC hGLRC = 0;
64 static HANDLE hGLDLL;
65 static glbuild8bit gl8bit;
66 static unsigned char nogl=0;
67 static unsigned char *frame = NULL;
68 
69 static HWND hGLWindow = NULL;
70 static HWND dummyhGLwindow = NULL;
71 static HDC hDCGLWindow = NULL;
72 
73 static struct winlayer_glfuncs {
74 	HGLRC (WINAPI * wglCreateContext)(HDC);
75 	BOOL (WINAPI * wglDeleteContext)(HGLRC);
76 	PROC (WINAPI * wglGetProcAddress)(LPCSTR);
77 	BOOL (WINAPI * wglMakeCurrent)(HDC,HGLRC);
78 	BOOL (WINAPI * wglSwapBuffers)(HDC);
79 
80 	const char * (WINAPI * wglGetExtensionsStringARB)(HDC hdc);
81 	BOOL (WINAPI * wglChoosePixelFormatARB)(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
82 	HGLRC (WINAPI * wglCreateContextAttribsARB)(HDC hDC, HGLRC hShareContext, const int *attribList);
83 	BOOL (WINAPI * wglSwapIntervalEXT)(int interval);
84 	int (WINAPI * wglGetSwapIntervalEXT)(void);
85 
86 	int have_ARB_create_context_profile;
87 } wglfunc;
88 #endif
89 
90 static LPTSTR GetWindowsErrorMsg(DWORD code);
91 static const char * getwindowserrorstr(DWORD code);
92 static void ShowErrorBox(const char *m);
93 static BOOL CheckWinVersion(void);
94 static LRESULT CALLBACK WndProcCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
95 static void fetchkeynames(void);
96 static void updatemouse(void);
97 static void updatejoystick(void);
98 static void UninitDIB(void);
99 static int SetupDIB(int width, int height);
100 static void UninitOpenGL(void);
101 static int SetupOpenGL(int width, int height, int bitspp, int cover);
102 static BOOL RegisterWindowClass(void);
103 static BOOL CreateAppWindow(int width, int height, int bitspp, int fs, int refresh);
104 static void DestroyAppWindow(void);
105 static void UpdateAppWindowTitle(void);
106 
107 static void shutdownvideo(void);
108 
109 // video
110 static int desktopxdim=0,desktopydim=0,desktopbpp=0, desktopmodeset=0;
111 int xres=-1, yres=-1, fullscreen=0, bpp=0, bytesperline=0, imageSize=0;
112 intptr_t frameplace=0;
113 static int windowposx, windowposy;
114 static unsigned modeschecked=0;
115 unsigned maxrefreshfreq=60;
116 char modechange=1;
117 char offscreenrendering=0;
118 int glswapinterval = 1;
119 int glcolourdepth=32;
120 char videomodereset = 0;
121 
122 // input and events
123 int inputdevices=0;
124 char quitevent=0, appactive=1;
125 int mousex=0, mousey=0, mouseb=0;
126 static unsigned int mousewheel[2] = { 0,0 };
127 #define MouseWheelFakePressTime (100)	// getticks() is a 1000Hz timer, and the button press is faked for 100ms
128 int joyaxis[8], joyb=0;
129 char joynumaxes=0, joynumbuttons=0;
130 
131 static char taskswitching=1;
132 
133 char keystatus[256];
134 int keyfifo[KEYFIFOSIZ];
135 unsigned char keyasciififo[KEYFIFOSIZ];
136 int keyfifoplc, keyfifoend;
137 int keyasciififoplc, keyasciififoend;
138 static char keynames[256][24];
139 static const int wscantable[256], wxscantable[256];
140 
141 void (*keypresscallback)(int,int) = 0;
142 void (*mousepresscallback)(int,int) = 0;
143 void (*joypresscallback)(int,int) = 0;
144 
145 
146 
147 
148 //-------------------------------------------------------------------------------------------------
149 //  MAIN CRAP
150 //=================================================================================================
151 
152 
153 //
154 // win_gethwnd() -- gets the window handle
155 //
win_gethwnd(void)156 intptr_t win_gethwnd(void)
157 {
158 	return (intptr_t)hWindow;
159 }
160 
161 
162 //
163 // win_gethinstance() -- gets the application instance
164 //
win_gethinstance(void)165 intptr_t win_gethinstance(void)
166 {
167 	return (intptr_t)hInstance;
168 }
169 
170 
171 //
172 // win_allowtaskswitching() -- captures/releases alt+tab hotkeys
173 //
win_allowtaskswitching(int onf)174 void win_allowtaskswitching(int onf)
175 {
176 	if (onf == taskswitching) return;
177 
178 	if (onf) {
179 		UnregisterHotKey(0,0);
180 		UnregisterHotKey(0,1);
181 	} else {
182 		RegisterHotKey(0,0,MOD_ALT,VK_TAB);
183 		RegisterHotKey(0,1,MOD_ALT|MOD_SHIFT,VK_TAB);
184 	}
185 
186 	taskswitching = onf;
187 }
188 
189 
190 //
191 // win_checkinstance() -- looks for another instance of a Build app
192 //
win_checkinstance(void)193 int win_checkinstance(void)
194 {
195 	if (!instanceflag) return 0;
196 	return (WaitForSingleObject(instanceflag,0) == WAIT_TIMEOUT);
197 }
198 
199 
200 //
201 // wm_msgbox/wm_ynbox() -- window-manager-provided message boxes
202 //
wm_msgbox(const char * name,const char * fmt,...)203 int wm_msgbox(const char *name, const char *fmt, ...)
204 {
205 	char buf[1000];
206 	va_list va;
207 
208 	va_start(va,fmt);
209 	vsprintf(buf,fmt,va);
210 	va_end(va);
211 
212 	MessageBox(hWindow,buf,name,MB_OK|MB_TASKMODAL);
213 	return 0;
214 }
wm_ynbox(const char * name,const char * fmt,...)215 int wm_ynbox(const char *name, const char *fmt, ...)
216 {
217 	char buf[1000];
218 	va_list va;
219 	int r;
220 
221 	va_start(va,fmt);
222 	vsprintf(buf,fmt,va);
223 	va_end(va);
224 
225 	r = MessageBox((HWND)win_gethwnd(),buf,name,MB_YESNO|MB_TASKMODAL);
226 	if (r==IDYES) return 1;
227 	return 0;
228 }
229 
230 //
231 // wm_filechooser() -- display a file selector dialogue box
232 //
wm_filechooser(const char * initialdir,const char * initialfile,const char * type,int foropen,char ** choice)233 int wm_filechooser(const char *initialdir, const char *initialfile, const char *type, int foropen, char **choice)
234 {
235 	OPENFILENAME ofn;
236 	char filter[100], *filterp = filter;
237 	char filename[BMAX_PATH+1] = "";
238 
239 	*choice = NULL;
240 
241 	if (!foropen && initialfile) {
242 		strcpy(filename, initialfile);
243 	}
244 
245 	// ext Files\0*.ext\0\0
246 	memset(filter, 0, sizeof(filter));
247 	sprintf(filterp, "%s Files", type);
248 	filterp += strlen(filterp) + 1;
249 	sprintf(filterp, "*.%s", type);
250 
251 	ZeroMemory(&ofn, sizeof(ofn));
252 	ofn.lStructSize = sizeof(OPENFILENAME);
253 	ofn.hwndOwner = hWindow;
254 	ofn.lpstrFilter = filter;
255 	ofn.nFilterIndex = 1;
256 	ofn.lpstrFile = filename;
257 	ofn.nMaxFile = sizeof(filename);
258 	ofn.lpstrInitialDir = initialdir;
259 	ofn.Flags = OFN_DONTADDTORECENT | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
260 	ofn.lpstrDefExt = type;
261 
262 	if (foropen ? GetOpenFileName(&ofn) : GetSaveFileName(&ofn)) {
263 		*choice = strdup(filename);
264 		return 1;
265 	} else {
266 		return 0;
267 	}
268 }
269 
270 //
271 // wm_setapptitle() -- changes the application title
272 //
wm_setapptitle(const char * name)273 void wm_setapptitle(const char *name)
274 {
275 	if (name) {
276 		Bstrncpy(apptitle, name, sizeof(apptitle)-1);
277 		apptitle[ sizeof(apptitle)-1 ] = 0;
278 	}
279 
280 	UpdateAppWindowTitle();
281 	startwin_settitle(apptitle);
282 }
283 
284 //
285 // wm_setwindowtitle() -- changes the rendering window title
286 //
wm_setwindowtitle(const char * name)287 void wm_setwindowtitle(const char *name)
288 {
289 	if (name) {
290 		Bstrncpy(wintitle, name, sizeof(wintitle)-1);
291 		wintitle[ sizeof(wintitle)-1 ] = 0;
292 	}
293 
294 	UpdateAppWindowTitle();
295 }
296 
297 //
298 // SignalHandler() -- called when we've sprung a leak
299 //
SignalHandler(int signum)300 static void SignalHandler(int signum)
301 {
302 	switch (signum) {
303 		case SIGSEGV:
304 			buildputs("Fatal Signal caught: SIGSEGV. Bailing out.\n");
305 			uninitsystem();
306 			if (stdout) fclose(stdout);
307 			break;
308 		default:
309 			break;
310 	}
311 }
312 
313 
314 //
315 // WinMain() -- main Windows entry point
316 //
WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nCmdShow)317 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
318 {
319 	int r;
320 	char *argp;
321 	FILE *fp;
322 	HDC hdc;
323 
324 	hInstance = hInst;
325 
326 	if (CheckWinVersion() || hPrevInst) {
327 		MessageBox(0, "This application must be run under Windows Vista or newer.",
328 			apptitle, MB_OK|MB_ICONSTOP);
329 		return -1;
330 	}
331 
332 	hdc = GetDC(NULL);
333 	r = GetDeviceCaps(hdc, BITSPIXEL);
334 	ReleaseDC(NULL, hdc);
335 	if (r <= 8) {
336 		MessageBox(0, "This application requires a desktop colour depth of 65536-colours or more.",
337 			apptitle, MB_OK|MB_ICONSTOP);
338 		return -1;
339 	}
340 
341 	// carve up the commandline into more recognizable pieces
342 	argvbuf = strdup(GetCommandLine());
343 	_buildargc = 0;
344 	if (argvbuf) {
345 		char quoted = 0, instring = 0, swallownext = 0;
346 		char *p,*wp; int i;
347 		for (p=wp=argvbuf; *p; p++) {
348 			if (*p == ' ') {
349 				if (instring && !quoted) {
350 					// end of a string
351 					*(wp++) = 0;
352 					instring = 0;
353 				} else if (instring) {
354 					*(wp++) = *p;
355 				}
356 			} else if (*p == '"' && !swallownext) {
357 				if (instring && quoted) {
358 					// end of a string
359 					if (p[1] == ' ') {
360 						*(wp++) = 0;
361 						instring = 0;
362 						quoted = 0;
363 					} else {
364 						quoted = 0;
365 					}
366 				} else if (instring && !quoted) {
367 					quoted = 1;
368 				} else if (!instring) {
369 					instring = 1;
370 					quoted = 1;
371 					_buildargc++;
372 				}
373 			} else if (*p == '\\' && p[1] == '"' && !swallownext) {
374 				swallownext = 1;
375 			} else {
376 				if (!instring) _buildargc++;
377 				instring = 1;
378 				*(wp++) = *p;
379 				swallownext = 0;
380 			}
381 		}
382 		*wp = 0;
383 
384 		_buildargv = malloc(sizeof(char*)*_buildargc);
385 		wp = argvbuf;
386 		for (i=0; i<_buildargc; i++,wp++) {
387 			_buildargv[i] = wp;
388 			while (*wp) wp++;
389 		}
390 	}
391 
392 	// pipe standard outputs to files
393 	if ((argp = Bgetenv("BUILD_LOGSTDOUT")) != NULL)
394 		if (!Bstrcasecmp(argp, "TRUE")) {
395 			fp = freopen("stdout.txt", "w", stdout);
396 			if (!fp) {
397 				fp = fopen("stdout.txt", "w");
398 			}
399 			if (fp) setvbuf(fp, 0, _IONBF, 0);
400 			*stdout = *fp;
401 			*stderr = *fp;
402 		}
403 
404 	// install signal handlers
405 	signal(SIGSEGV, SignalHandler);
406 
407 	if (RegisterWindowClass()) return -1;
408 
409 	atexit(uninitsystem);
410 
411 	instanceflag = CreateSemaphore(NULL, 1,1, WINDOW_CLASS);
412 
413 	startwin_open();
414 	baselayer_init();
415 	r = app_main(_buildargc, _buildargv);
416 
417 	fclose(stdout);
418 
419 	startwin_close();
420 	if (instanceflag) CloseHandle(instanceflag);
421 
422 	if (argvbuf) free(argvbuf);
423 
424 	return r;
425 }
426 
427 
set_maxrefreshfreq(const osdfuncparm_t * parm)428 static int set_maxrefreshfreq(const osdfuncparm_t *parm)
429 {
430 	int freq;
431 	if (parm->numparms == 0) {
432 		if (maxrefreshfreq == 0)
433 			buildputs("maxrefreshfreq = No maximum\n");
434 		else
435 			buildprintf("maxrefreshfreq = %d Hz\n",maxrefreshfreq);
436 		return OSDCMD_OK;
437 	}
438 	if (parm->numparms != 1) return OSDCMD_SHOWHELP;
439 
440 	freq = Batol(parm->parms[0]);
441 	if (freq < 0) return OSDCMD_SHOWHELP;
442 
443 	maxrefreshfreq = (unsigned)freq;
444 	modeschecked = 0;
445 
446 	return OSDCMD_OK;
447 }
448 
449 #if USE_OPENGL
set_glswapinterval(const osdfuncparm_t * parm)450 static int set_glswapinterval(const osdfuncparm_t *parm)
451 {
452 	int interval;
453 
454 	if (!wglfunc.wglSwapIntervalEXT || nogl) {
455 		buildputs("glswapinterval is not adjustable\n");
456 		return OSDCMD_OK;
457 	}
458 	if (parm->numparms == 0) {
459 		buildprintf("glswapinterval = %d\n", glswapinterval);
460 		return OSDCMD_OK;
461 	}
462 	if (parm->numparms != 1) return OSDCMD_SHOWHELP;
463 
464 	interval = Batol(parm->parms[0]);
465 	if (interval < 0 || interval > 2) return OSDCMD_SHOWHELP;
466 
467 	glswapinterval = interval;
468 	wglfunc.wglSwapIntervalEXT(interval);
469 
470 	return OSDCMD_OK;
471 }
472 #endif
473 
474 //
475 // initsystem() -- init systems
476 //
initsystem(void)477 int initsystem(void)
478 {
479 	DEVMODE desktopmode;
480 
481 	buildputs("Initialising Windows system interface\n");
482 
483 	// get the desktop dimensions before anything changes them
484 	ZeroMemory(&desktopmode, sizeof(DEVMODE));
485 	desktopmode.dmSize = sizeof(DEVMODE);
486 	EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&desktopmode);
487 
488 	desktopxdim = desktopmode.dmPelsWidth;
489 	desktopydim = desktopmode.dmPelsHeight;
490 	desktopbpp  = desktopmode.dmBitsPerPel;
491 
492 	memset(curpalette, 0, sizeof(palette_t) * 256);
493 
494 	atexit(uninitsystem);
495 
496 	frameplace=0;
497 
498 #if USE_OPENGL
499 	memset(&wglfunc, 0, sizeof(wglfunc));
500 	nogl = loadgldriver(getenv("BUILD_GLDRV"));
501 	if (!nogl) {
502 		// Load the core WGL functions.
503 		wglfunc.wglGetProcAddress = getglprocaddress("wglGetProcAddress", 0);
504 		wglfunc.wglCreateContext  = getglprocaddress("wglCreateContext", 0);
505 		wglfunc.wglDeleteContext  = getglprocaddress("wglDeleteContext", 0);
506 		wglfunc.wglMakeCurrent    = getglprocaddress("wglMakeCurrent", 0);
507 		wglfunc.wglSwapBuffers    = getglprocaddress("wglSwapBuffers", 0);
508 		nogl = !wglfunc.wglGetProcAddress ||
509 		 	   !wglfunc.wglCreateContext ||
510 		 	   !wglfunc.wglDeleteContext ||
511 		 	   !wglfunc.wglMakeCurrent ||
512 		 	   !wglfunc.wglSwapBuffers;
513 	}
514 	if (nogl) {
515 		buildputs("Failed loading OpenGL driver. GL modes will be unavailable.\n");
516 		memset(&wglfunc, 0, sizeof(wglfunc));
517 	} else {
518 		OSD_RegisterFunction("glswapinterval", "glswapinterval: frame swap interval for OpenGL modes (0 = no vsync, max 2)", set_glswapinterval);
519 	}
520 #endif
521 
522 	OSD_RegisterFunction("maxrefreshfreq", "maxrefreshfreq: maximum display frequency to set for OpenGL Polymost modes (0=no maximum)", set_maxrefreshfreq);
523 	return 0;
524 }
525 
526 
527 //
528 // uninitsystem() -- uninit systems
529 //
uninitsystem(void)530 void uninitsystem(void)
531 {
532 	DestroyAppWindow();
533 
534 	startwin_close();
535 
536 	uninitinput();
537 	uninittimer();
538 
539 	win_allowtaskswitching(1);
540 
541 	shutdownvideo();
542 #if USE_OPENGL
543 	glbuild_unloadfunctions();
544 	memset(&wglfunc, 0, sizeof(wglfunc));
545 	unloadgldriver();
546 #endif
547 }
548 
549 
550 //
551 // initputs() -- prints a string to the intitialization window
552 //
initputs(const char * buf)553 void initputs(const char *buf)
554 {
555 	startwin_puts(buf);
556 }
557 
558 
559 //
560 // debugprintf() -- sends a debug string to the debugger
561 //
debugprintf(const char * f,...)562 void debugprintf(const char *f, ...)
563 {
564 #ifdef DEBUGGINGAIDS
565 	va_list va;
566 	char buf[1024];
567 
568 	va_start(va,f);
569 	Bvsnprintf(buf, 1024, f, va);
570 	va_end(va);
571 
572 	if (IsDebuggerPresent()) {
573 		OutputDebugString(buf);
574 	} else {
575 		fputs(buf, stdout);
576 	}
577 #endif
578 }
579 
580 
581 //
582 // handleevents() -- process the Windows message queue
583 //   returns !0 if there was an important event worth checking (like quitting)
584 //
585 static int eatosdinput = 0;
handleevents(void)586 int handleevents(void)
587 {
588 	int rv=0;
589 	MSG msg;
590 
591 	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
592 		if (msg.message == WM_QUIT)
593 			quitevent = 1;
594 
595 		if (startwin_idle((void*)&msg) > 0) continue;
596 
597 		TranslateMessage(&msg);
598 		DispatchMessage(&msg);
599 	}
600 
601 	eatosdinput = 0;
602 	updatemouse();
603 	updatejoystick();
604 
605 	if (!appactive || quitevent) rv = -1;
606 
607 	sampletimer();
608 
609 	return rv;
610 }
611 
612 
613 
614 
615 //-------------------------------------------------------------------------------------------------
616 //  INPUT (MOUSE/KEYBOARD)
617 //=================================================================================================
618 
619 static char moustat = 0, mousegrab = 0;
620 static int joyblast=0;
621 
622 static int xinputusernum = -1;
623 
624 // I don't see any pressing need to store the key-up events yet
625 #define SetKey(key,state) { \
626 	keystatus[key] = state; \
627 		if (state) { \
628 	keyfifo[keyfifoend] = key; \
629 	keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = state; \
630 	keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1)); \
631 		} \
632 }
633 
634 
635 //
636 // initinput() -- init input system
637 //
initinput(void)638 int initinput(void)
639 {
640 	moustat=0;
641 	memset(keystatus, 0, sizeof(keystatus));
642 	keyfifoplc = keyfifoend = 0;
643 	keyasciififoplc = keyasciififoend = 0;
644 
645 	inputdevices = 1;
646 	joynumaxes=0;
647 	joynumbuttons=0;
648 
649 	fetchkeynames();
650 
651 	{
652 		DWORD usernum, result;
653 		XINPUT_CAPABILITIES caps;
654 
655 		buildputs("Initialising game controllers\n");
656 
657 		for (usernum = 0; usernum < XUSER_MAX_COUNT; usernum++) {
658 			result = XInputGetCapabilities(usernum, XINPUT_FLAG_GAMEPAD, &caps);
659 			if (result == ERROR_SUCCESS && xinputusernum < 0) {
660 				xinputusernum = (int)usernum;
661 				inputdevices |= 4;
662 
663 				joynumbuttons = 15;
664 				joynumaxes = 6;
665 			}
666 		}
667 		if (xinputusernum >= 0) {
668 			buildprintf("  - Using controller in port %d\n", xinputusernum);
669 		} else {
670 			buildputs("  - No usable controller found\n");
671 		}
672 	}
673 
674 	return 0;
675 }
676 
677 
678 //
679 // uninitinput() -- uninit input system
680 //
uninitinput(void)681 void uninitinput(void)
682 {
683 	uninitmouse();
684 
685 	xinputusernum = -1;
686 	inputdevices &= ~4;
687 }
688 
689 
690 //
691 // bgetchar, bkbhit, bflushchars -- character-based input functions
692 //
bgetchar(void)693 unsigned char bgetchar(void)
694 {
695 	unsigned char c;
696 	if (keyasciififoplc == keyasciififoend) return 0;
697 	c = keyasciififo[keyasciififoplc];
698 	keyasciififoplc = ((keyasciififoplc+1)&(KEYFIFOSIZ-1));
699 	return c;
700 }
701 
bkbhit(void)702 int bkbhit(void)
703 {
704 	return (keyasciififoplc != keyasciififoend);
705 }
706 
bflushchars(void)707 void bflushchars(void)
708 {
709 	keyasciififoplc = keyasciififoend = 0;
710 }
711 
712 
713 //
714 // set{key|mouse|joy}presscallback() -- sets a callback which gets notified when keys are pressed
715 //
setkeypresscallback(void (* callback)(int,int))716 void setkeypresscallback(void (*callback)(int, int)) { keypresscallback = callback; }
setmousepresscallback(void (* callback)(int,int))717 void setmousepresscallback(void (*callback)(int, int)) { mousepresscallback = callback; }
setjoypresscallback(void (* callback)(int,int))718 void setjoypresscallback(void (*callback)(int, int)) { joypresscallback = callback; }
719 
720 
721 //
722 // initmouse() -- init mouse input
723 //
initmouse(void)724 int initmouse(void)
725 {
726 	RAWINPUTDEVICE rid;
727 
728 	if (moustat) return 0;
729 
730 	buildputs("Initialising mouse\n");
731 
732 	// Register for mouse raw input.
733 	rid.usUsagePage = 0x01;
734 	rid.usUsage = 0x02;
735 	rid.dwFlags = 0;	// We want legacy events when the mouse is not grabbed, so no RIDEV_NOLEGACY.
736 	rid.hwndTarget = NULL;
737 	if (RegisterRawInputDevices(&rid, 1, sizeof(rid)) == FALSE) {
738 		buildprintf("initinput: could not register for raw mouse input (%s)\n",
739 			getwindowserrorstr(GetLastError()));
740 		return -1;
741 	}
742 
743 	// grab input
744 	moustat=1;
745 	inputdevices |= 2;
746 	grabmouse(1);
747 
748 	return 0;
749 }
750 
751 
752 //
753 // uninitmouse() -- uninit mouse input
754 //
uninitmouse(void)755 void uninitmouse(void)
756 {
757 	RAWINPUTDEVICE rid;
758 
759 	if (!moustat) return;
760 
761 	grabmouse(0);
762 	moustat=mousegrab=0;
763 
764 	// Unregister for mouse raw input.
765 	rid.usUsagePage = 0x01;
766 	rid.usUsage = 0x02;
767 	rid.dwFlags = RIDEV_REMOVE;
768 	rid.hwndTarget = NULL;
769 	if (RegisterRawInputDevices(&rid, 1, sizeof(rid)) == FALSE) {
770 		buildprintf("initinput: could not unregister for raw mouse input (%s)\n",
771 			getwindowserrorstr(GetLastError()));
772 	}
773 }
774 
775 
constrainmouse(int a)776 static void constrainmouse(int a)
777 {
778 	RECT rect;
779 	LONG x, y;
780 
781 	if (!hWindow) return;
782 	if (a) {
783 		GetWindowRect(hWindow, &rect);
784 
785 		x = rect.left + (rect.right - rect.left) / 2;
786 		y = rect.top + (rect.bottom - rect.top) / 2;
787 		rect.left = x - 1;
788 		rect.right = x + 1;
789 		rect.top = y - 1;
790 		rect.bottom = y + 1;
791 
792 		ClipCursor(&rect);
793 		ShowCursor(FALSE);
794 	} else {
795 		ClipCursor(NULL);
796 		ShowCursor(TRUE);
797 	}
798 }
799 
updatemouse(void)800 static void updatemouse(void)
801 {
802 	unsigned t = getticks();
803 
804 	if (!mousegrab) return;
805 
806 	// we only want the wheel to signal once, but hold the state for a moment
807 	if (mousewheel[0] > 0 && t - mousewheel[0] > MouseWheelFakePressTime) {
808 		if (mousepresscallback) mousepresscallback(5,0);
809 		mousewheel[0] = 0; mouseb &= ~16;
810 	}
811 	if (mousewheel[1] > 0 && t - mousewheel[1] > MouseWheelFakePressTime) {
812 		if (mousepresscallback) mousepresscallback(6,0);
813 		mousewheel[1] = 0; mouseb &= ~32;
814 	}
815 }
816 
817 //
818 // grabmouse() -- show/hide mouse cursor
819 //
grabmouse(int a)820 void grabmouse(int a)
821 {
822 	if (!moustat) return;
823 
824 	mousegrab = a;
825 
826 	constrainmouse(a);
827 	mousex = 0;
828 	mousey = 0;
829 	mouseb = 0;
830 }
831 
832 
833 //
834 // readmousexy() -- return mouse motion information
835 //
readmousexy(int * x,int * y)836 void readmousexy(int *x, int *y)
837 {
838 	if (!moustat || !mousegrab) { *x = *y = 0; return; }
839 	*x = mousex;
840 	*y = mousey;
841 	mousex = 0;
842 	mousey = 0;
843 }
844 
845 
846 //
847 // readmousebstatus() -- return mouse button information
848 //
readmousebstatus(int * b)849 void readmousebstatus(int *b)
850 {
851 	if (!moustat || !mousegrab) *b = 0;
852 	else *b = mouseb;
853 }
854 
855 
updatejoystick(void)856 static void updatejoystick(void)
857 {
858 	XINPUT_STATE state;
859 
860 	if (xinputusernum < 0) return;
861 
862 	ZeroMemory(&state, sizeof(state));
863 	if (XInputGetState(xinputusernum, &state) != ERROR_SUCCESS) {
864 		buildputs("Joystick error, disabling.\n");
865 		joyb = 0;
866 		memset(joyaxis, 0, sizeof(joyaxis));
867 		xinputusernum = -1;
868 		return;
869 	}
870 
871 	// We use SDL's game controller button order for BUILD:
872 	//   A, B, X, Y, Back, (Guide), Start, LThumb, RThumb,
873 	//   LShoulder, RShoulder, DPUp, DPDown, DPLeft, DPRight
874 	// So we must shuffle XInput around.
875 	joyb = ((state.Gamepad.wButtons & 0xF000) >> 12) |		// A,B,X,Y
876 	       ((state.Gamepad.wButtons & 0x0020) >> 1) |		// Back
877 	       ((state.Gamepad.wButtons & 0x0010) << 2) |       // Start
878 	       ((state.Gamepad.wButtons & 0x03C0) << 1) |       // LThumb,RThumb,LShoulder,RShoulder
879 	       ((state.Gamepad.wButtons & 0x000F) << 8);		// DPadUp,Down,Left,Right
880 
881 	joyaxis[0] = state.Gamepad.sThumbLX;
882 	joyaxis[1] = -state.Gamepad.sThumbLY;
883 	joyaxis[2] = state.Gamepad.sThumbRX;
884 	joyaxis[3] = -state.Gamepad.sThumbRY;
885 	joyaxis[4] = (state.Gamepad.bLeftTrigger >> 1) | ((int)state.Gamepad.bLeftTrigger << 7);	// Extend to 0-32767
886 	joyaxis[5] = (state.Gamepad.bRightTrigger >> 1) | ((int)state.Gamepad.bRightTrigger << 7);
887 }
888 
889 
releaseallbuttons(void)890 void releaseallbuttons(void)
891 {
892 	int i;
893 
894 	if (mousepresscallback) {
895 		if (mouseb & 1) mousepresscallback(1, 0);
896 		if (mouseb & 2) mousepresscallback(2, 0);
897 		if (mouseb & 4) mousepresscallback(3, 0);
898 		if (mouseb & 8) mousepresscallback(4, 0);
899 		if (mousewheel[0]>0) mousepresscallback(5,0);
900 		if (mousewheel[1]>0) mousepresscallback(6,0);
901 	}
902 	mousewheel[0]=mousewheel[1]=0;
903 	mouseb = 0;
904 
905 	if (joypresscallback) {
906 		for (i=0;i<32;i++)
907 			if (joyb & (1<<i)) joypresscallback(i+1, 0);
908 	}
909 	joyb = joyblast = 0;
910 
911 	for (i=0;i<256;i++) {
912 		//if (!keystatus[i]) continue;
913 		//if (OSD_HandleKey(i, 0) != 0) {
914 			OSD_HandleKey(i, 0);
915 			SetKey(i, 0);
916 			if (keypresscallback) keypresscallback(i, 0);
917 		//}
918 	}
919 }
920 
921 
922 //
923 // fetchkeynames() -- retrieves the names for all the keys on the keyboard
924 //
putkeyname(int vsc,int ex,int scan)925 static void putkeyname(int vsc, int ex, int scan) {
926 	TCHAR tbuf[24];
927 
928 	vsc <<= 16;
929 	vsc |= ex << 24;
930 	if (GetKeyNameText(vsc, tbuf, 24) == 0) return;
931 	CharToOemBuff(tbuf, keynames[scan], 24-1);
932 
933 	//buildprintf("VSC %8x scan %-2x = %s\n", vsc, scan, keynames[scan]);
934 }
935 
fetchkeynames(void)936 static void fetchkeynames(void)
937 {
938 	int scan, ex;
939 	unsigned i;
940 
941 	memset(keynames,0,sizeof(keynames));
942 	for (i=0; i < 256; i++) {
943 		scan = wscantable[i];
944 		if (scan != 0) {
945 			putkeyname(i, 0, scan);
946 		}
947 		scan = wxscantable[i];
948 		if (scan != 0) {
949 			putkeyname(i, 1, scan);
950 		}
951 	}
952 }
953 
getkeyname(int num)954 const char *getkeyname(int num)
955 {
956 	if ((unsigned)num >= 256) return NULL;
957 	return keynames[num];
958 }
959 
getjoyname(int what,int num)960 const char *getjoyname(int what, int num)
961 {
962 	static const char * axisnames[6] = {
963 		"Left Stick X",
964 		"Left Stick Y",
965 		"Right Stick X",
966 		"Right Stick Y",
967 		"Left Trigger",
968 		"Right Trigger",
969 	};
970 	static const char * buttonnames[15] = {
971 		"A",
972 		"B",
973 		"X",
974 		"Y",
975 		"Start",
976 		"Guide",
977 		"Back",
978 		"Left Thumb",
979 		"Right Thumb",
980 		"Left Shoulder",
981 		"Right Shoulder",
982 		"DPad Up",
983 		"DPad Down",
984 		"DPad Left",
985 		"DPad Right",
986 	};
987 	switch (what) {
988 		case 0:	// axis
989 			if ((unsigned)num > (unsigned)6) return NULL;
990 			return axisnames[num];
991 
992 		case 1: // button
993 			if ((unsigned)num > (unsigned)15) return NULL;
994 			return buttonnames[num];
995 
996 		default:
997 			return NULL;
998 	}
999 }
1000 
1001 
1002 
1003 
1004 
1005 //-------------------------------------------------------------------------------------------------
1006 //  TIMER
1007 //=================================================================================================
1008 
1009 static int64_t timerfreq=0;
1010 static int timerlastsample=0;
1011 static int timerticspersec=0;
1012 static void (*usertimercallback)(void) = NULL;
1013 
1014 //  This timer stuff is all Ken's idea.
1015 
1016 //
1017 // installusertimercallback() -- set up a callback function to be called when the timer is fired
1018 //
installusertimercallback(void (* callback)(void))1019 void (*installusertimercallback(void (*callback)(void)))(void)
1020 {
1021 	void (*oldtimercallback)(void);
1022 
1023 	oldtimercallback = usertimercallback;
1024 	usertimercallback = callback;
1025 
1026 	return oldtimercallback;
1027 }
1028 
1029 
1030 //
1031 // inittimer() -- initialise timer
1032 //
inittimer(int tickspersecond)1033 int inittimer(int tickspersecond)
1034 {
1035 	int64_t t;
1036 
1037 	if (timerfreq) return 0;	// already installed
1038 
1039 	buildputs("Initialising timer\n");
1040 
1041 	// OpenWatcom seems to want us to query the value into a local variable
1042 	// instead of the global 'timerfreq' or else it gets pissed with an
1043 	// access violation
1044 	if (!QueryPerformanceFrequency((LARGE_INTEGER*)&t)) {
1045 		ShowErrorBox("Failed fetching timer frequency");
1046 		return -1;
1047 	}
1048 	timerfreq = t;
1049 	timerticspersec = tickspersecond;
1050 	QueryPerformanceCounter((LARGE_INTEGER*)&t);
1051 	timerlastsample = (int)(t*timerticspersec / timerfreq);
1052 
1053 	usertimercallback = NULL;
1054 
1055 	return 0;
1056 }
1057 
1058 //
1059 // uninittimer() -- shut down timer
1060 //
uninittimer(void)1061 void uninittimer(void)
1062 {
1063 	if (!timerfreq) return;
1064 
1065 	timerfreq=0;
1066 	timerticspersec = 0;
1067 }
1068 
1069 //
1070 // sampletimer() -- update totalclock
1071 //
sampletimer(void)1072 void sampletimer(void)
1073 {
1074 	int64_t i;
1075 	int n;
1076 
1077 	if (!timerfreq) return;
1078 
1079 	QueryPerformanceCounter((LARGE_INTEGER*)&i);
1080 	n = (int)(i*timerticspersec / timerfreq) - timerlastsample;
1081 	if (n>0) {
1082 		totalclock += n;
1083 		timerlastsample += n;
1084 	}
1085 
1086 	if (usertimercallback) for (; n>0; n--) usertimercallback();
1087 }
1088 
1089 
1090 //
1091 // getticks() -- returns the millisecond ticks count
1092 //
getticks(void)1093 unsigned int getticks(void)
1094 {
1095 	int64_t i;
1096 	if (timerfreq == 0) return 0;
1097 	QueryPerformanceCounter((LARGE_INTEGER*)&i);
1098 	return (unsigned int)(i*INT64_C(1000)/timerfreq);
1099 }
1100 
1101 
1102 //
1103 // getusecticks() -- returns the microsecond ticks count
1104 //
getusecticks(void)1105 unsigned int getusecticks(void)
1106 {
1107 	int64_t i;
1108 	if (timerfreq == 0) return 0;
1109 	QueryPerformanceCounter((LARGE_INTEGER*)&i);
1110 	return (unsigned int)(i*INT64_C(1000000)/timerfreq);
1111 }
1112 
1113 
1114 //
1115 // gettimerfreq() -- returns the number of ticks per second the timer is configured to generate
1116 //
gettimerfreq(void)1117 int gettimerfreq(void)
1118 {
1119 	return timerticspersec;
1120 }
1121 
1122 
1123 
1124 
1125 //-------------------------------------------------------------------------------------------------
1126 //  VIDEO
1127 //=================================================================================================
1128 
1129 // DIB stuff
1130 static HDC      hDCSection  = NULL;
1131 static HBITMAP  hDIBSection = NULL;
1132 static HPALETTE hPalette    = NULL;
1133 static VOID    *lpPixels    = NULL;
1134 
1135 static int setgammaramp(WORD gt[3][256]);
1136 static int getgammaramp(WORD gt[3][256]);
1137 
1138 //
1139 // checkvideomode() -- makes sure the video mode passed is legal
1140 //
checkvideomode(int * x,int * y,int c,int fs,int forced)1141 int checkvideomode(int *x, int *y, int c, int fs, int forced)
1142 {
1143 	int i, nearest=-1, dx, dy, odx=9999, ody=9999;
1144 
1145 	getvalidmodes();
1146 
1147 #if USE_OPENGL
1148 	if (c > 8 && nogl) return -1;
1149 #else
1150 	if (c > 8) return -1;
1151 #endif
1152 
1153 	// fix up the passed resolution values to be multiples of 8
1154 	// and at least 320x200 or at most MAXXDIMxMAXYDIM
1155 	if (*x < 320) *x = 320;
1156 	if (*y < 200) *y = 200;
1157 	if (*x > MAXXDIM) *x = MAXXDIM;
1158 	if (*y > MAXYDIM) *y = MAXYDIM;
1159 	*x &= 0xfffffff8l;
1160 
1161 	for (i=0; i<validmodecnt; i++) {
1162 		if (validmode[i].bpp != c) continue;
1163 		if (validmode[i].fs != fs) continue;
1164 		dx = klabs(validmode[i].xdim - *x);
1165 		dy = klabs(validmode[i].ydim - *y);
1166 		if (!(dx | dy)) { 	// perfect match
1167 			nearest = i;
1168 			break;
1169 		}
1170 		if ((dx <= odx) && (dy <= ody)) {
1171 			nearest = i;
1172 			odx = dx; ody = dy;
1173 		}
1174 	}
1175 
1176 #ifdef ANY_WINDOWED_SIZE
1177 	if (!forced && (fs&1) == 0 && (nearest < 0 || validmode[nearest].xdim!=*x || validmode[nearest].ydim!=*y)) {
1178 		// check the colour depth is recognised at the very least
1179 		for (i=0;i<validmodecnt;i++)
1180 			if (validmode[i].bpp == c)
1181 				return 0x7fffffffl;
1182 		return -1;	// strange colour depth
1183 	}
1184 #endif
1185 
1186 	if (nearest < 0) {
1187 		// no mode that will match (eg. if no fullscreen modes)
1188 		return -1;
1189 	}
1190 
1191 	*x = validmode[nearest].xdim;
1192 	*y = validmode[nearest].ydim;
1193 
1194 	return nearest;		// JBF 20031206: Returns the mode number
1195 }
1196 
shutdownvideo(void)1197 static void shutdownvideo(void)
1198 {
1199 #if USE_OPENGL
1200 	if (frame) {
1201 		free(frame);
1202 		frame = NULL;
1203 	}
1204 	glbuild_delete_8bit_shader(&gl8bit);
1205 	UninitOpenGL();
1206 #endif
1207 	UninitDIB();
1208 
1209 	if (desktopmodeset) {
1210 		ChangeDisplaySettings(NULL, 0);
1211 		desktopmodeset = 0;
1212 	}
1213 }
1214 
1215 //
1216 // setvideomode() -- set the video mode
1217 //
setvideomode(int x,int y,int c,int fs)1218 int setvideomode(int x, int y, int c, int fs)
1219 {
1220 	int i, modenum, refresh=-1;
1221 
1222 	if ((fs == fullscreen) && (x == xres) && (y == yres) && (c == bpp) && !videomodereset) {
1223 		OSD_ResizeDisplay(xres,yres);
1224 		return 0;
1225 	}
1226 
1227 	modenum = checkvideomode(&x,&y,c,fs,0);
1228 	if (modenum < 0) return -1;
1229 	if (modenum != 0x7fffffff) {
1230 		refresh = validmode[modenum].extra;
1231 	}
1232 
1233 	if (hWindow && gammabrightness) {
1234 		setgammaramp(sysgamma);
1235 		gammabrightness = 0;
1236 	}
1237 
1238 	shutdownvideo();
1239 
1240 	buildprintf("Setting video mode %dx%d (%d-bit %s)\n",
1241 			x,y,c, ((fs&1) ? "fullscreen" : "windowed"));
1242 
1243 	if (CreateAppWindow(x, y, c, fs, refresh)) return -1;
1244 
1245 	if (!gammabrightness) {
1246 		if (getgammaramp(sysgamma) >= 0) gammabrightness = 1;
1247 		if (gammabrightness && setgamma(curgamma) < 0) gammabrightness = 0;
1248 	}
1249 
1250 	modechange=1;
1251 	videomodereset = 0;
1252 	//baselayer_onvideomodechange(c>8);
1253 
1254 	return 0;
1255 }
1256 
1257 
1258 //
1259 // getvalidmodes() -- figure out what video modes are available
1260 //
1261 #define ADDMODE(x,y,c,f,n) if (validmodecnt<MAXVALIDMODES) { \
1262 	validmode[validmodecnt].xdim=x; \
1263 	validmode[validmodecnt].ydim=y; \
1264 	validmode[validmodecnt].bpp=c; \
1265 	validmode[validmodecnt].fs=f; \
1266 	validmode[validmodecnt].extra=n; \
1267 	validmodecnt++; \
1268 	buildprintf("  - %dx%d %d-bit %s\n", x, y, c, (f&1)?"fullscreen":"windowed"); \
1269 	}
1270 
1271 #define CHECKL(w,h) if ((w < maxx) && (h < maxy))
1272 #define CHECKLE(w,h) if ((w <= maxx) && (h <= maxy))
1273 
1274 #if USE_OPENGL
cdsenummodes(void)1275 static void cdsenummodes(void)
1276 {
1277 	DEVMODE dm;
1278 	int i = 0, j = 0;
1279 
1280 	struct { unsigned x,y,bpp,freq; } modes[MAXVALIDMODES];
1281 	int nmodes=0;
1282 	unsigned maxx = MAXXDIM, maxy = MAXYDIM;
1283 
1284 	// Enumerate display modes.
1285 	ZeroMemory(&dm,sizeof(DEVMODE));
1286 	dm.dmSize = sizeof(DEVMODE);
1287 	while (nmodes < MAXVALIDMODES && EnumDisplaySettings(NULL, j, &dm)) {
1288 		// Identify the same resolution and bit depth in the existing set.
1289 		for (i=0;i<nmodes;i++) {
1290 			if (modes[i].x == dm.dmPelsWidth
1291 			 && modes[i].y == dm.dmPelsHeight
1292 			 && modes[i].bpp == dm.dmBitsPerPel)
1293 				break;
1294 		}
1295 		// A new mode, or a same format mode with a better refresh rate match.
1296 		if ((i==nmodes) ||
1297 		    (dm.dmDisplayFrequency <= maxrefreshfreq && dm.dmDisplayFrequency > modes[i].freq && maxrefreshfreq > 0) ||
1298 		    (dm.dmDisplayFrequency > modes[i].freq && maxrefreshfreq == 0)) {
1299 			if (i==nmodes) nmodes++;
1300 
1301 			modes[i].x = dm.dmPelsWidth;
1302 			modes[i].y = dm.dmPelsHeight;
1303 			modes[i].bpp = dm.dmBitsPerPel;
1304 			modes[i].freq = dm.dmDisplayFrequency;
1305 		}
1306 
1307 		j++;
1308 		ZeroMemory(&dm,sizeof(DEVMODE));
1309 		dm.dmSize = sizeof(DEVMODE);
1310 	}
1311 
1312 	// Add what was found to the list.
1313 	for (i=0;i<nmodes;i++) {
1314 		CHECKLE(modes[i].x, modes[i].y) {
1315 			ADDMODE(modes[i].x, modes[i].y, modes[i].bpp, 1, modes[i].freq);
1316 		}
1317 	}
1318 }
1319 #endif
1320 
sortmodes(const struct validmode_t * a,const struct validmode_t * b)1321 static int sortmodes(const struct validmode_t *a, const struct validmode_t *b)
1322 {
1323 	int x;
1324 
1325 	if ((x = a->fs   - b->fs)   != 0) return x;
1326 	if ((x = a->bpp  - b->bpp)  != 0) return x;
1327 	if ((x = a->xdim - b->xdim) != 0) return x;
1328 	if ((x = a->ydim - b->ydim) != 0) return x;
1329 
1330 	return 0;
1331 }
getvalidmodes(void)1332 void getvalidmodes(void)
1333 {
1334 	static int defaultres[][2] = {
1335 		{1920,1200},{1920,1080},{1600,1200},{1680,1050},{1600,900},{1400,1050},{1440,900},{1366,768},
1336 		{1280,1024},{1280,960},{1280,800},{1280,720},{1152,864},{1024,768},{800,600},{640,480},
1337 		{640,400},{512,384},{480,360},{400,300},{320,240},{320,200},{0,0}
1338 	};
1339 	int i, j, maxx=0, maxy=0;
1340 
1341 	if (modeschecked) return;
1342 
1343 	validmodecnt=0;
1344 	buildputs("Detecting video modes:\n");
1345 
1346 	// Fullscreen 8-bit modes: upsamples to the desktop mode.
1347 	maxx = desktopxdim;
1348 	maxy = desktopydim;
1349 	for (i=0; defaultres[i][0]; i++) {
1350 		CHECKLE(defaultres[i][0],defaultres[i][1]) {
1351 			ADDMODE(defaultres[i][0], defaultres[i][1], 8, 1, -1);
1352 		}
1353 	}
1354 
1355 #if USE_POLYMOST && USE_OPENGL
1356 	// Fullscreen >8-bit modes.
1357 	if (!nogl) cdsenummodes();
1358 #endif
1359 
1360 	// Windowed modes can't be bigger than the current desktop resolution.
1361 	maxx = desktopxdim-1;
1362 	maxy = desktopydim-1;
1363 
1364 	// Windows 8-bit modes
1365 	for (i=0; defaultres[i][0]; i++) {
1366 		CHECKL(defaultres[i][0],defaultres[i][1]) {
1367 			ADDMODE(defaultres[i][0], defaultres[i][1], 8, 0, -1);
1368 		}
1369 	}
1370 
1371 #if USE_POLYMOST && USE_OPENGL
1372 	// Windowed >8-bit modes
1373 	if (!nogl) {
1374 		for (i=0; defaultres[i][0]; i++) {
1375 			CHECKL(defaultres[i][0],defaultres[i][1]) {
1376 				ADDMODE(defaultres[i][0], defaultres[i][1], desktopbpp, 0, -1);
1377 			}
1378 		}
1379 	}
1380 #endif
1381 
1382 	qsort((void*)validmode, validmodecnt, sizeof(struct validmode_t), (int(*)(const void*,const void*))sortmodes);
1383 
1384 	modeschecked=1;
1385 }
1386 
1387 #undef CHECK
1388 #undef ADDMODE
1389 
1390 
1391 //
1392 // resetvideomode() -- resets the video system
1393 //
resetvideomode(void)1394 void resetvideomode(void)
1395 {
1396 	videomodereset = 1;
1397 	modeschecked = 0;
1398 }
1399 
1400 
1401 //
1402 // begindrawing() -- locks the framebuffer for drawing
1403 //
begindrawing(void)1404 void begindrawing(void)
1405 {
1406 }
1407 
1408 
1409 //
1410 // enddrawing() -- unlocks the framebuffer
1411 //
enddrawing(void)1412 void enddrawing(void)
1413 {
1414 }
1415 
1416 
1417 //
1418 // showframe() -- update the display
1419 //
showframe(void)1420 void showframe(void)
1421 {
1422 	HRESULT result;
1423 	char *p,*q;
1424 	int i,j;
1425 
1426 #if USE_OPENGL
1427 	if (!nogl) {
1428 		if (bpp == 8) {
1429 			glbuild_update_8bit_frame(&gl8bit, frame, xres, yres, bytesperline);
1430 			glbuild_draw_8bit_frame(&gl8bit);
1431 		}
1432 
1433 		wglfunc.wglSwapBuffers(hDCGLWindow);
1434 		return;
1435 	}
1436 #endif
1437 
1438 	{
1439 		if ((xres == desktopxdim && yres == desktopydim) || !fullscreen) {
1440 			BitBlt(hDCWindow, 0, 0, xres, yres, hDCSection, 0, 0, SRCCOPY);
1441 		} else {
1442 			int xpos, ypos, xscl, yscl;
1443 			int desktopaspect = divscale16(desktopxdim, desktopydim);
1444 			int frameaspect = divscale16(xres, yres);
1445 
1446 			if (desktopaspect >= frameaspect) {
1447 				// Desktop is at least as wide as the frame. We maximise frame height and centre on width.
1448 				ypos = 0;
1449 				yscl = desktopydim;
1450 				xscl = mulscale16(desktopydim, frameaspect);
1451 				xpos = (desktopxdim - xscl) >> 1;
1452 			} else {
1453 				// Desktop is narrower than the frame. We maximise frame width and centre on height.
1454 				xpos = 0;
1455 				xscl = desktopxdim;
1456 				yscl = divscale16(desktopxdim, frameaspect);
1457 				ypos = (desktopydim - yscl) >> 1;
1458 			}
1459 
1460 			StretchBlt(hDCWindow, xpos, ypos, xscl, yscl, hDCSection, 0, 0, xres, yres, SRCCOPY);
1461 		}
1462 	}
1463 }
1464 
1465 
1466 //
1467 // setpalette() -- set palette values
1468 //
setpalette(int UNUSED (start),int UNUSED (num),unsigned char * UNUSED (dapal))1469 int setpalette(int UNUSED(start), int UNUSED(num), unsigned char * UNUSED(dapal))
1470 {
1471 #if USE_OPENGL
1472 	if (!nogl && bpp == 8) {
1473 		glbuild_update_8bit_palette(&gl8bit, curpalettefaded);
1474 		return 0;
1475 	}
1476 #endif
1477 	if (hDCSection) {
1478 		RGBQUAD rgb[256];
1479 		int i;
1480 
1481 		for (i = 0; i < 256; i++) {
1482 			rgb[i].rgbBlue = curpalettefaded[i].b;
1483 			rgb[i].rgbGreen = curpalettefaded[i].g;
1484 			rgb[i].rgbRed = curpalettefaded[i].r;
1485 			rgb[i].rgbReserved = 0;
1486 		}
1487 
1488 		SetDIBColorTable(hDCSection, 0, 256, rgb);
1489 	}
1490 
1491 	return 0;
1492 }
1493 
1494 
1495 //
1496 // setgamma
1497 //
setgammaramp(WORD gt[3][256])1498 static int setgammaramp(WORD gt[3][256])
1499 {
1500 	int i;
1501 	i = SetDeviceGammaRamp(hDCWindow, gt) ? 0 : -1;
1502 	return i;
1503 }
1504 
setgamma(float gamma)1505 int setgamma(float gamma)
1506 {
1507 	int i;
1508 	WORD gt[3][256];
1509 
1510 	if (!hWindow) return -1;
1511 
1512 	gamma = 1.0 / gamma;
1513 	for (i=0;i<256;i++) {
1514 		gt[0][i] =
1515 		gt[1][i] =
1516 		gt[2][i] = (WORD)min(65535, max(0, (int)(pow((double)i / 256.0, gamma) * 65535.0 + 0.5)));
1517 	}
1518 
1519 	return setgammaramp(gt);
1520 }
1521 
getgammaramp(WORD gt[3][256])1522 static int getgammaramp(WORD gt[3][256])
1523 {
1524 	int i;
1525 
1526 	if (!hWindow) return -1;
1527 
1528 	i = GetDeviceGammaRamp(hDCWindow, gt) ? 0 : -1;
1529 
1530 	return i;
1531 }
1532 
1533 
1534 //
1535 // UninitDIB() -- clean up the DIB renderer
1536 //
UninitDIB(void)1537 static void UninitDIB(void)
1538 {
1539 	if (hPalette) {
1540 		DeleteObject(hPalette);
1541 		hPalette = NULL;
1542 	}
1543 
1544 	if (hDCSection) {
1545 		DeleteDC(hDCSection);
1546 		hDCSection = NULL;
1547 	}
1548 
1549 	if (hDIBSection) {
1550 		DeleteObject(hDIBSection);
1551 		hDIBSection = NULL;
1552 	}
1553 }
1554 
1555 
1556 //
1557 // SetupDIB() -- sets up DIB rendering
1558 //
SetupDIB(int width,int height)1559 static int SetupDIB(int width, int height)
1560 {
1561 	struct binfo {
1562 		BITMAPINFOHEADER header;
1563 		RGBQUAD colours[256];
1564 	} dibsect;
1565 	int i, bpl;
1566 
1567 	// create the new DIB section
1568 	memset(&dibsect, 0, sizeof(dibsect));
1569 	numpages = 1;	// KJS 20031225
1570 	dibsect.header.biSize = sizeof(dibsect.header);
1571 	dibsect.header.biWidth = width|1;	// Ken did this
1572 	dibsect.header.biHeight = -height;
1573 	dibsect.header.biPlanes = 1;
1574 	dibsect.header.biBitCount = 8;
1575 	dibsect.header.biCompression = BI_RGB;
1576 	dibsect.header.biClrUsed = 256;
1577 	dibsect.header.biClrImportant = 256;
1578 	for (i=0; i<256; i++) {
1579 		dibsect.colours[i].rgbBlue = curpalettefaded[i].b;
1580 		dibsect.colours[i].rgbGreen = curpalettefaded[i].g;
1581 		dibsect.colours[i].rgbRed = curpalettefaded[i].r;
1582 	}
1583 
1584 	hDIBSection = CreateDIBSection(hDCWindow, (BITMAPINFO *)&dibsect, DIB_RGB_COLORS, &lpPixels, NULL, 0);
1585 	if (!hDIBSection || lpPixels == NULL) {
1586 		UninitDIB();
1587 		ShowErrorBox("Error creating DIB section");
1588 		return TRUE;
1589 	}
1590 
1591 	memset(lpPixels, 0, (((width|1) + 4) & ~3)*height);
1592 
1593 	// create a compatible memory DC
1594 	hDCSection = CreateCompatibleDC(hDCWindow);
1595 	if (!hDCSection) {
1596 		UninitDIB();
1597 		ShowErrorBox("Error creating compatible DC");
1598 		return TRUE;
1599 	}
1600 
1601 	// select the DIB section into the memory DC
1602 	if (!SelectObject(hDCSection, hDIBSection)) {
1603 		UninitDIB();
1604 		ShowErrorBox("Error creating compatible DC");
1605 		return TRUE;
1606 	}
1607 
1608 	return FALSE;
1609 }
1610 
1611 #if USE_OPENGL
1612 
1613 //
1614 // loadgldriver -- loads an OpenGL DLL
1615 //
loadgldriver(const char * dll)1616 int loadgldriver(const char *dll)
1617 {
1618 	if (hGLDLL) return 0;	// Already loaded
1619 
1620 	if (!dll) {
1621 		dll = "OPENGL32.DLL";
1622 	}
1623 
1624 	buildprintf("Loading %s\n", dll);
1625 
1626 	hGLDLL = LoadLibrary(dll);
1627 	if (!hGLDLL) return -1;
1628 
1629 	return 0;
1630 }
1631 
unloadgldriver(void)1632 int unloadgldriver(void)
1633 {
1634 	if (!hGLDLL) return 0;
1635 	FreeLibrary(hGLDLL);
1636 	hGLDLL = NULL;
1637 	return 0;
1638 }
1639 
1640 //
1641 // getglprocaddress
1642 //
getglprocaddress(const char * name,int ext)1643 void *getglprocaddress(const char *name, int ext)
1644 {
1645 	void *func = NULL;
1646 	if (!hGLDLL) return NULL;
1647 	if (ext && wglfunc.wglGetProcAddress) {
1648 		func = wglfunc.wglGetProcAddress(name);
1649 	}
1650 	if (!func) {
1651 		func = GetProcAddress(hGLDLL, name);
1652 	}
1653 	return func;
1654 }
1655 
1656 
1657 //
1658 // UninitOpenGL() -- cleans up OpenGL rendering
1659 //
1660 
UninitOpenGL(void)1661 static void UninitOpenGL(void)
1662 {
1663 	if (hGLRC) {
1664 #if USE_POLYMOST
1665 		polymost_glreset();
1666 #endif
1667 		if (!wglfunc.wglMakeCurrent(0,0)) { }
1668 		if (!wglfunc.wglDeleteContext(hGLRC)) { }
1669 		hGLRC = NULL;
1670 	}
1671 	if (hGLWindow) {
1672 		if (hDCGLWindow) {
1673 			ReleaseDC(hGLWindow, hDCGLWindow);
1674 			hDCGLWindow = NULL;
1675 		}
1676 
1677 		DestroyWindow(hGLWindow);
1678 		hGLWindow = NULL;
1679 	}
1680 }
1681 
1682 // Enumerate the WGL interface extensions.
EnumWGLExts(HDC hdc)1683 static void EnumWGLExts(HDC hdc)
1684 {
1685 	const GLchar *extstr;
1686 	char *workstr, *workptr, *nextptr = NULL, *ext = NULL;
1687 	int ack;
1688 
1689 	wglfunc.wglGetExtensionsStringARB = getglprocaddress("wglGetExtensionsStringARB", 1);
1690 	if (!wglfunc.wglGetExtensionsStringARB) {
1691 		debugprintf("Note: OpenGL does not provide WGL_ARB_extensions_string extension.\n");
1692 		return;
1693 	}
1694 
1695 	extstr = wglfunc.wglGetExtensionsStringARB(hdc);
1696 
1697 	debugprintf("WGL extensions supported:\n");
1698 	workstr = workptr = strdup(extstr);
1699 	while ((ext = Bstrtoken(workptr, " ", &nextptr, 1)) != NULL) {
1700 		if (!strcmp(ext, "WGL_ARB_pixel_format")) {
1701 			wglfunc.wglChoosePixelFormatARB = getglprocaddress("wglChoosePixelFormatARB", 1);
1702 			ack = !wglfunc.wglChoosePixelFormatARB ? '!' : '+';
1703 		} else if (!strcmp(ext, "WGL_ARB_create_context")) {
1704 			wglfunc.wglCreateContextAttribsARB = getglprocaddress("wglCreateContextAttribsARB", 1);
1705 			ack = !wglfunc.wglCreateContextAttribsARB ? '!' : '+';
1706 		} else if (!strcmp(ext, "WGL_ARB_create_context_profile")) {
1707 			wglfunc.have_ARB_create_context_profile = 1;
1708 			ack = '+';
1709 		} else if (!strcmp(ext, "WGL_EXT_swap_control")) {
1710 			wglfunc.wglSwapIntervalEXT = getglprocaddress("wglSwapIntervalEXT", 1);
1711 			wglfunc.wglGetSwapIntervalEXT = getglprocaddress("wglGetSwapIntervalEXT", 1);
1712 			ack = (!wglfunc.wglSwapIntervalEXT || !wglfunc.wglGetSwapIntervalEXT) ? '!' : '+';
1713 		} else {
1714 			ack = ' ';
1715 		}
1716 		debugprintf("  %s %c\n", ext, ack);
1717 		workptr = NULL;
1718 	}
1719 	free(workstr);
1720 }
1721 
1722 //
1723 // SetupOpenGL() -- sets up opengl rendering
1724 //
SetupOpenGL(int width,int height,int bitspp,int cover)1725 static int SetupOpenGL(int width, int height, int bitspp, int cover)
1726 {
1727 	int err, pixelformat;
1728 
1729 	// Step 1. Create a fake context with a safe pixel format descriptor.
1730 	GLuint dummyPixelFormat;
1731 	PIXELFORMATDESCRIPTOR dummyPfd = {
1732 		sizeof(PIXELFORMATDESCRIPTOR),
1733 		1,                             //Version Number
1734 		PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER, //Must Support these
1735 		PFD_TYPE_RGBA,                 //Request An RGBA Format
1736 		32,                            //Color Depth
1737 		0,0,0,0,0,0,                   //Color Bits Ignored
1738 		0,                             //No Alpha Buffer
1739 		0,                             //Shift Bit Ignored
1740 		0,                             //No Accumulation Buffer
1741 		0,0,0,0,                       //Accumulation Bits Ignored
1742 		24,                            //16/24/32 Z-Buffer depth
1743 		8,                             //Stencil Buffer
1744 		0,                             //No Auxiliary Buffer
1745 		PFD_MAIN_PLANE,                //Main Drawing Layer
1746 		0,                             //Reserved
1747 		0,0,0                          //Layer Masks Ignored
1748 	};
1749 	HDC dummyhDC = 0;
1750 	HGLRC dummyhGLRC = 0;
1751 	const char *errmsg = NULL;
1752 
1753 	dummyhGLwindow = CreateWindow(
1754 			WINDOW_CLASS,
1755 			"OpenGL Window",
1756 			WS_CHILD,
1757 			0,0,
1758 			1,1,
1759 			hWindow,
1760 			(HMENU)0,
1761 			hInstance,
1762 			NULL);
1763 	if (!dummyhGLwindow) {
1764 		errmsg = "Error creating dummy OpenGL child window.";
1765 		goto fail;
1766 	}
1767 
1768 	dummyhDC = GetDC(dummyhGLwindow);
1769 	if (!dummyhDC) {
1770 		errmsg = "Error getting dummy device context";
1771 		goto fail;
1772 	}
1773 
1774 	dummyPixelFormat = ChoosePixelFormat(dummyhDC, &dummyPfd);
1775 	if (!dummyPixelFormat) {
1776 		errmsg = "Can't choose dummy pixel format";
1777 		goto fail;
1778 	}
1779 
1780 	err = SetPixelFormat(dummyhDC, dummyPixelFormat, &dummyPfd);
1781 	if (!err) {
1782 		errmsg = "Can't set dummy pixel format";
1783 		goto fail;
1784 	}
1785 
1786 	dummyhGLRC = wglfunc.wglCreateContext(dummyhDC);
1787 	if (!dummyhGLRC) {
1788 		errmsg = "Can't create dummy GL context";
1789 		goto fail;
1790 	}
1791 
1792 	if (!wglfunc.wglMakeCurrent(dummyhDC, dummyhGLRC)) {
1793 		errmsg = "Can't activate dummy GL context";
1794 		goto fail;
1795 	}
1796 
1797 	// Step 2. Check the WGL extensions.
1798 	EnumWGLExts(dummyhDC);
1799 
1800 	// Step 3. Create the actual window we will use going forward.
1801 	{
1802 		int xpos, ypos, xscl, yscl;
1803 
1804 		if (cover) {
1805 			// The desktop resolution is set to the target. Fill the screen.
1806 			xpos = ypos = 0;
1807 			xscl = width;
1808 			yscl = height;
1809 		} else {
1810 			// The desktop resolution remains the same and we stretch to fit.
1811 			int desktopaspect = divscale16(desktopxdim, desktopydim);
1812 			int frameaspect = divscale16(width, height);
1813 			if (desktopaspect >= frameaspect) {
1814 				// Desktop is at least as wide as the frame. We maximise frame height and centre on width.
1815 				ypos = 0;
1816 				yscl = desktopydim;
1817 				xscl = mulscale16(desktopydim, frameaspect);
1818 				xpos = (desktopxdim - xscl) >> 1;
1819 			} else {
1820 				// Desktop is narrower than the frame. We maximise frame width and centre on height.
1821 				xpos = 0;
1822 				xscl = desktopxdim;
1823 				yscl = divscale16(desktopxdim, frameaspect);
1824 				ypos = (desktopydim - yscl) >> 1;
1825 			}
1826 		}
1827 
1828 		hGLWindow = CreateWindow(
1829 				WINDOW_CLASS,
1830 				"OpenGL Window",
1831 				WS_CHILD|WS_VISIBLE,
1832 				xpos, ypos,
1833 				xscl, yscl,
1834 				hWindow,
1835 				(HMENU)0,
1836 				hInstance,
1837 				NULL);
1838 		if (!hGLWindow) {
1839 			errmsg = "Error creating OpenGL child window.";
1840 			goto fail;
1841 		}
1842 	}
1843 
1844 	hDCGLWindow = GetDC(hGLWindow);
1845 	if (!hDCGLWindow) {
1846 		errmsg = "Error getting device context.";
1847 		goto fail;
1848 	}
1849 
1850 	// Step 3. Find and set a suitable pixel format.
1851 	if (wglfunc.wglChoosePixelFormatARB) {
1852 		UINT numformats;
1853 		int pformatattribs[] = {
1854 			WGL_DRAW_TO_WINDOW_ARB,	GL_TRUE,
1855 			WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
1856 			WGL_DOUBLE_BUFFER_ARB,  GL_TRUE,
1857 			WGL_PIXEL_TYPE_ARB,     WGL_TYPE_RGBA_ARB,
1858 			WGL_COLOR_BITS_ARB,     bitspp,
1859 			WGL_DEPTH_BITS_ARB,     24,
1860 			WGL_STENCIL_BITS_ARB,   0,
1861 			WGL_ACCELERATION_ARB,   WGL_FULL_ACCELERATION_ARB,
1862 			0,
1863 		};
1864 		if (!wglfunc.wglChoosePixelFormatARB(hDCGLWindow, pformatattribs, NULL, 1, &pixelformat, &numformats)) {
1865 			errmsg = "Can't choose pixel format.";
1866 			goto fail;
1867 		} else if (numformats < 1) {
1868 			errmsg = "No suitable pixel format available.";
1869 			goto fail;
1870 		}
1871 	} else {
1872 		PIXELFORMATDESCRIPTOR pfd = {
1873 			sizeof(PIXELFORMATDESCRIPTOR),
1874 			1,                             //Version Number
1875 			PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER, //Must Support these
1876 			PFD_TYPE_RGBA,                 //Request An RGBA Format
1877 			bitspp,                        //Color Depth
1878 			0,0,0,0,0,0,                   //Color Bits Ignored
1879 			0,                             //No Alpha Buffer
1880 			0,                             //Shift Bit Ignored
1881 			0,                             //No Accumulation Buffer
1882 			0,0,0,0,                       //Accumulation Bits Ignored
1883 			24,                            //16/24/32 Z-Buffer depth
1884 			0,                             //Stencil Buffer
1885 			0,                             //No Auxiliary Buffer
1886 			PFD_MAIN_PLANE,                //Main Drawing Layer
1887 			0,                             //Reserved
1888 			0,0,0                          //Layer Masks Ignored
1889 		};
1890 		pixelformat = ChoosePixelFormat(hDCGLWindow, &pfd);
1891 		if (!pixelformat) {
1892 			errmsg = "Can't choose pixel format";
1893 			goto fail;
1894 		}
1895 	}
1896 
1897 	DescribePixelFormat(hDCGLWindow, pixelformat, sizeof(PIXELFORMATDESCRIPTOR), &dummyPfd);
1898 	err = SetPixelFormat(hDCGLWindow, pixelformat, &dummyPfd);
1899 	if (!err) {
1900 		errmsg = "Can't set pixel format.";
1901 		goto fail;
1902 	}
1903 
1904 	// Step 4. Create a context with the needed profile.
1905 	if (wglfunc.wglCreateContextAttribsARB) {
1906 		int contextattribs[] = {
1907 #if (USE_OPENGL == USE_GL3)
1908 			WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
1909 			WGL_CONTEXT_MINOR_VERSION_ARB, 2,
1910 			WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
1911 #else
1912 			WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
1913 			WGL_CONTEXT_MINOR_VERSION_ARB, 1,
1914 			WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
1915 #endif
1916 			0,
1917 		};
1918 		if (!wglfunc.have_ARB_create_context_profile) {
1919 			contextattribs[4] = 0;	//WGL_CONTEXT_PROFILE_MASK_ARB
1920 		}
1921 		hGLRC = wglfunc.wglCreateContextAttribsARB(hDCGLWindow, 0, contextattribs);
1922 		if (!hGLRC) {
1923 			errmsg = "Can't create GL context.";
1924 			goto fail;
1925 		}
1926 	} else {
1927 		hGLRC = wglfunc.wglCreateContext(hDCGLWindow);
1928 		if (!hGLRC) {
1929 			errmsg = "Can't create GL context.";
1930 			goto fail;
1931 		}
1932 	}
1933 
1934 	// Scrap the dummy stuff.
1935 	if (!wglfunc.wglMakeCurrent(NULL, NULL)) { }
1936 	if (!wglfunc.wglDeleteContext(dummyhGLRC)) { }
1937 	ReleaseDC(dummyhGLwindow, dummyhDC);
1938 	DestroyWindow(dummyhGLwindow);
1939 	dummyhGLwindow = NULL;
1940 	dummyhGLRC = NULL;
1941 	dummyhDC = NULL;
1942 
1943 	if (!wglfunc.wglMakeCurrent(hDCGLWindow, hGLRC)) {
1944 		errmsg = "Can't activate GL context";
1945 		goto fail;
1946 	}
1947 
1948 	// Step 5. Done.
1949 	switch (baselayer_setupopengl()) {
1950 		case 0:
1951 			break;
1952 		case -1:
1953 			errmsg = "Can't load required OpenGL function pointers.";
1954 			goto fail;
1955 		case -2:
1956 			errmsg = "Minimum OpenGL requirements are not met.";
1957 			goto fail;
1958 		default:
1959 			errmsg = "Other OpenGL initialisation error.";
1960 			goto fail;
1961 	}
1962 
1963 	if (wglfunc.wglSwapIntervalEXT) {
1964 		wglfunc.wglSwapIntervalEXT(glswapinterval);
1965 	}
1966 	numpages = 127;
1967 
1968 	return FALSE;
1969 
1970 fail:
1971 	if (bpp > 8) {
1972 		ShowErrorBox(errmsg);
1973 	}
1974 	shutdownvideo();
1975 
1976 	if (!wglfunc.wglMakeCurrent(NULL, NULL)) { }
1977 
1978 	if (hGLRC) {
1979 		if (!wglfunc.wglDeleteContext(hGLRC)) { }
1980 	}
1981 	if (hGLWindow) {
1982 		if (hDCGLWindow) {
1983 			ReleaseDC(hGLWindow, hDCGLWindow);
1984 		}
1985 	}
1986 	hDCGLWindow = NULL;
1987 	hGLRC = NULL;
1988 	hGLWindow = NULL;
1989 
1990 	if (dummyhGLRC) {
1991 		if (!wglfunc.wglDeleteContext(dummyhGLRC)) { }
1992 	}
1993 	if (dummyhGLwindow) {
1994 		if (dummyhDC) {
1995 			ReleaseDC(dummyhGLwindow, dummyhDC);
1996 		}
1997 		DestroyWindow(dummyhGLwindow);
1998 	}
1999 
2000 	return TRUE;
2001 }
2002 
2003 #endif	//USE_OPENGL
2004 
2005 //
2006 // CreateAppWindow() -- create the application window
2007 //
CreateAppWindow(int width,int height,int bitspp,int fs,int refresh)2008 static BOOL CreateAppWindow(int width, int height, int bitspp, int fs, int refresh)
2009 {
2010 	RECT rect;
2011 	int w, h, x, y, stylebits = 0, stylebitsex = 0;
2012 	HRESULT result;
2013 
2014 	if (width == xres && height == yres && fs == fullscreen && bitspp == bpp && !videomodereset) return FALSE;
2015 
2016 	if (hWindow) {
2017 		ShowWindow(hWindow, SW_HIDE);	// so Windows redraws what's behind if the window shrinks
2018 	}
2019 
2020 	if (fs) {
2021 		stylebitsex = WS_EX_TOPMOST;
2022 		stylebits = WS_POPUP;
2023 	} else {
2024 		stylebitsex = 0;
2025 		stylebits = (WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX);
2026 	}
2027 
2028 	if (!hWindow) {
2029 		hWindow = CreateWindowEx(
2030 			stylebitsex,
2031 			"buildapp",
2032 			apptitle,
2033 			stylebits,
2034 			CW_USEDEFAULT,
2035 			CW_USEDEFAULT,
2036 			320,
2037 			200,
2038 			NULL,
2039 			NULL,
2040 			hInstance,
2041 			0);
2042 		if (!hWindow) {
2043 			ShowErrorBox("Unable to create window");
2044 			return TRUE;
2045 		}
2046 
2047 		hDCWindow = GetDC(hWindow);
2048 		if (!hDCWindow) {
2049 			ShowErrorBox("Error getting device context");
2050 			return TRUE;
2051 		}
2052 
2053 		startwin_close();
2054 	} else {
2055 		SetWindowLong(hWindow,GWL_EXSTYLE,stylebitsex);
2056 		SetWindowLong(hWindow,GWL_STYLE,stylebits);
2057 	}
2058 
2059 	// resize the window
2060 	if (!fs) {
2061 		rect.left = 0;
2062 		rect.top = 0;
2063 		rect.right = width-1;
2064 		rect.bottom = height-1;
2065 		AdjustWindowRect(&rect, stylebits, FALSE);
2066 
2067 		w = (rect.right - rect.left);
2068 		h = (rect.bottom - rect.top);
2069 		x = (desktopxdim - w) / 2;
2070 		y = (desktopydim - h) / 2;
2071 	} else {
2072 		x=y=0;
2073 		w=desktopxdim;
2074 		h=desktopydim;
2075 	}
2076 	SetWindowPos(hWindow, HWND_TOP, x, y, w, h, 0);
2077 
2078 	UpdateAppWindowTitle();
2079 	ShowWindow(hWindow, SW_SHOWNORMAL);
2080 	SetForegroundWindow(hWindow);
2081 	SetFocus(hWindow);
2082 
2083 	if (bitspp == 8) {
2084 		int i, j;
2085 
2086 #if USE_OPENGL
2087 		if (nogl) {
2088 #endif
2089 			// 8-bit software with no GL shader uses classic Windows DIB blitting.
2090 			if (SetupDIB(width, height)) {
2091 				return TRUE;
2092 			}
2093 
2094 			frameplace = (intptr_t)lpPixels;
2095 			bytesperline = (((width|1) + 4) & ~3);
2096 #if USE_OPENGL
2097 		} else {
2098 			// Prepare the GLSL shader for 8-bit blitting.
2099 			if (SetupOpenGL(width, height, bitspp, !fs)) {
2100 				// No luck. Write off OpenGL and try DIB.
2101 				buildputs("OpenGL initialisation failed. Falling back to DIB mode.\n");
2102 				nogl = 1;
2103 				return CreateAppWindow(width, height, bitspp, fs, refresh);
2104 			}
2105 
2106 			bytesperline = (((width|1) + 4) & ~3);
2107 
2108 			if (glbuild_prepare_8bit_shader(&gl8bit, width, height, bytesperline) < 0) {
2109 				shutdownvideo();
2110 				return -1;
2111 			}
2112 
2113 			frame = (unsigned char *) malloc(bytesperline * height);
2114 			if (!frame) {
2115 				shutdownvideo();
2116 				buildputs("Unable to allocate framebuffer\n");
2117 				return FALSE;
2118 			}
2119 
2120 			frameplace = (intptr_t)frame;
2121 		}
2122 #endif
2123 
2124 		imageSize = bytesperline*height;
2125 		setvlinebpl(bytesperline);
2126 
2127 		for(i=j=0; i<=height; i++) ylookup[i] = j, j += bytesperline;
2128 		modechange=0;
2129 
2130 		numpages = 1;
2131 	} else {
2132 #if USE_OPENGL
2133 		if (fs) {
2134 			DEVMODE dmScreenSettings;
2135 
2136 			ZeroMemory(&dmScreenSettings, sizeof(DEVMODE));
2137 			dmScreenSettings.dmSize = sizeof(DEVMODE);
2138 			dmScreenSettings.dmPelsWidth = width;
2139 			dmScreenSettings.dmPelsHeight = height;
2140 			dmScreenSettings.dmBitsPerPel = bitspp;
2141 			dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
2142 			if (refresh > 0) {
2143 				dmScreenSettings.dmDisplayFrequency = refresh;
2144 				dmScreenSettings.dmFields |= DM_DISPLAYFREQUENCY;
2145 			}
2146 
2147 			if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
2148 				ShowErrorBox("Video mode not supported");
2149 				return TRUE;
2150 			}
2151 			desktopmodeset = 1;
2152 		}
2153 
2154 		ShowWindow(hWindow, SW_SHOWNORMAL);
2155 		SetForegroundWindow(hWindow);
2156 		SetFocus(hWindow);
2157 
2158 		if (SetupOpenGL(width, height, bitspp, !desktopmodeset)) {
2159 			return TRUE;
2160 		}
2161 
2162 		frameplace = 0;
2163 		bytesperline = 0;
2164 		imageSize = 0;
2165 #else
2166 		return FALSE;
2167 #endif
2168 	}
2169 
2170 	xres = width;
2171 	yres = height;
2172 	bpp = bitspp;
2173 	fullscreen = fs;
2174 
2175 	modechange = 1;
2176 	OSD_ResizeDisplay(xres,yres);
2177 
2178 	UpdateWindow(hWindow);
2179 
2180 	return FALSE;
2181 }
2182 
2183 
2184 //
2185 // DestroyAppWindow() -- destroys the application window
2186 //
DestroyAppWindow(void)2187 static void DestroyAppWindow(void)
2188 {
2189 	if (hWindow && gammabrightness) {
2190 		setgammaramp(sysgamma);
2191 		gammabrightness = 0;
2192 	}
2193 
2194 	shutdownvideo();
2195 
2196 	if (hDCWindow) {
2197 		ReleaseDC(hWindow, hDCWindow);
2198 		hDCWindow = NULL;
2199 	}
2200 
2201 	if (hWindow) {
2202 		DestroyWindow(hWindow);
2203 		hWindow = NULL;
2204 	}
2205 }
2206 
2207 //
2208 // UpdateAppWindowTitle() -- sets the title of the application window
2209 //
UpdateAppWindowTitle(void)2210 static void UpdateAppWindowTitle(void)
2211 {
2212 	char tmp[256+3+256+1];		//sizeof(wintitle) + " - " + sizeof(apptitle) + '\0'
2213 
2214 	if (!hWindow) return;
2215 
2216 	if (wintitle[0]) {
2217 		snprintf(tmp, sizeof(tmp), "%s - %s", wintitle, apptitle);
2218 		tmp[sizeof(tmp)-1] = 0;
2219 		SetWindowText(hWindow, tmp);
2220 	} else {
2221 		SetWindowText(hWindow, apptitle);
2222 	}
2223 }
2224 
2225 
2226 
2227 
2228 
2229 
2230 //-------------------------------------------------------------------------------------------------
2231 //  MOSTLY STATIC INTERNAL WINDOWS THINGS
2232 //=================================================================================================
2233 
2234 //
2235 // ShowErrorBox() -- shows an error message box
2236 //
ShowErrorBox(const char * m)2237 static void ShowErrorBox(const char *m)
2238 {
2239 	TCHAR msg[1024];
2240 
2241 	wsprintf(msg, "%s: %s", m, GetWindowsErrorMsg(GetLastError()));
2242 	MessageBox(0, msg, apptitle, MB_OK|MB_ICONSTOP);
2243 }
2244 
2245 
2246 //
2247 // CheckWinVersion() -- check to see what version of Windows we happen to be running under
2248 //
CheckWinVersion(void)2249 static BOOL CheckWinVersion(void)
2250 {
2251 	OSVERSIONINFO osv;
2252 
2253 	ZeroMemory(&osv, sizeof(osv));
2254 	osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
2255 	if (!GetVersionEx(&osv)) return TRUE;
2256 
2257 	// At least Windows Vista
2258 	if (osv.dwPlatformId != VER_PLATFORM_WIN32_NT) return TRUE;
2259 	if (osv.dwMajorVersion < 6) return TRUE;
2260 
2261 	return FALSE;
2262 }
2263 
2264 
2265 static const int wscantable[256] = {
2266 /*         x0    x1    x2    x3    x4    x5    x6    x7    x8    x9    xA    xB    xC    xD    xE    xF */
2267 /* 0y */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
2268 /* 1y */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
2269 /* 2y */ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
2270 /* 3y */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
2271 /* 4y */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x59, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
2272 /* 5y */ 0x50, 0x51, 0x52, 0x53, 0,    0,    0,    0x57, 0x58, 0,    0,    0,    0,    0,    0,    0,
2273 /* 6y */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2274 /* 7y */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2275 /* 8y */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2276 /* 9y */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2277 /* Ay */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2278 /* By */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2279 /* Cy */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2280 /* Dy */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2281 /* Ey */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2282 /* Fy */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2283 };
2284 
2285 static const int wxscantable[256] = {
2286 /*         x0    x1    x2    x3    x4    x5    x6    x7    x8    x9    xA    xB    xC    xD    xE    xF */
2287 /* 0y */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2288 /* 1y */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0x9c, 0x9d, 0,    0,
2289 /* 2y */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2290 /* 3y */ 0,    0,    0,    0,    0,    0xb5, 0,    0,    0xb8, 0,    0,    0,    0,    0xb8, 0,    0,
2291 /* 4y */ 0,    0,    0,    0,    0,    0x45, 0,    0xc7, 0xc8, 0xc9, 0,    0xcb, 0,    0xcd, 0,    0xcf,
2292 /* 5y */ 0xd0, 0xd1, 0xd2, 0xd3, 0,    0,    0,    0,    0,    0,    0,    0x5b, 0x5c, 0x5d, 0,    0,
2293 /* 6y */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2294 /* 7y */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2295 /* 8y */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2296 /* 9y */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0x9d, 0,    0,
2297 /* Ay */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2298 /* By */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2299 /* Cy */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2300 /* Dy */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2301 /* Ey */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2302 /* Fy */ 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
2303 };
2304 
2305 
2306 //
2307 // WndProcCallback() -- the Windows window callback
2308 //
WndProcCallback(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2309 static LRESULT CALLBACK WndProcCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2310 {
2311 	RECT rect;
2312 	POINT pt;
2313 	HRESULT result;
2314 
2315 #if USE_OPENGL
2316 	if (hGLWindow && hWnd == hGLWindow) return DefWindowProc(hWnd,uMsg,wParam,lParam);
2317 	if (dummyhGLwindow && hWnd == dummyhGLwindow) return DefWindowProc(hWnd,uMsg,wParam,lParam);
2318 #endif
2319 
2320 	switch (uMsg) {
2321 		case WM_SYSCOMMAND:
2322 			// don't let the monitor fall asleep or let the screensaver activate
2323 			if (wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER) return 0;
2324 
2325 			// Since DirectInput won't let me set an exclusive-foreground
2326 			// keyboard for some unknown reason I just have to tell Windows to
2327 			// rack off with its keyboard accelerators.
2328 			if (wParam == SC_KEYMENU || wParam == SC_HOTKEY) return 0;
2329 			break;
2330 
2331 		case WM_ACTIVATEAPP:
2332 			appactive = wParam;
2333 			if (backgroundidle)
2334 				SetPriorityClass( GetCurrentProcess(),
2335 					appactive ? NORMAL_PRIORITY_CLASS : IDLE_PRIORITY_CLASS );
2336 			break;
2337 
2338 		case WM_ACTIVATE:
2339 //			AcquireInputDevices(appactive);
2340 			constrainmouse(LOWORD(wParam) != WA_INACTIVE && HIWORD(wParam) == 0);
2341 			break;
2342 
2343 		case WM_SIZE:
2344 			if (wParam == SIZE_MAXHIDE || wParam == SIZE_MINIMIZED) appactive = 0;
2345 			else appactive = 1;
2346 //			AcquireInputDevices(appactive);
2347 			break;
2348 
2349 		case WM_DISPLAYCHANGE:
2350 			// desktop settings changed so adjust our world-view accordingly
2351 			desktopxdim = LOWORD(lParam);
2352 			desktopydim = HIWORD(lParam);
2353 			desktopbpp  = wParam;
2354 			getvalidmodes();
2355 			break;
2356 
2357 		case WM_PAINT:
2358 			break;
2359 
2360 			// don't draw the frame if fullscreen
2361 		//case WM_NCPAINT:
2362 			//if (!fullscreen) break;
2363 			//return 0;
2364 
2365 		case WM_ERASEBKGND:
2366 			break;//return TRUE;
2367 
2368 		case WM_MOVE:
2369 			windowposx = LOWORD(lParam);
2370 			windowposy = HIWORD(lParam);
2371 			return 0;
2372 
2373 		case WM_CLOSE:
2374 			quitevent = 1;
2375 			return 0;
2376 
2377 		case WM_SYSKEYDOWN:
2378 		case WM_SYSKEYUP:
2379 		case WM_KEYDOWN:
2380 		case WM_KEYUP:
2381 			{
2382 				int press = (lParam & 0x80000000l) == 0;
2383 				int wscan = (lParam >> 16) & 0xff;
2384 				int scan = 0;
2385 
2386 				if (lParam & (1<<24)) {
2387 					scan = wxscantable[wscan];
2388 				} else {
2389 					scan = wscantable[wscan];
2390 				}
2391 
2392 				//buildprintf("VK %-2x VSC %8x scan %-2x = %s\n", wParam, (UINT)lParam, scan, keynames[scan]);
2393 
2394 				if (scan == 0) {
2395 					// Not a key we want, so give it to the OS to handle.
2396 					break;
2397 				} else if (scan == OSD_CaptureKey(-1)) {
2398 					if (press) {
2399 						OSD_ShowDisplay(-1);
2400 						eatosdinput = 1;
2401 					}
2402 				} else if (OSD_HandleKey(scan, press) != 0) {
2403 					if (!keystatus[scan] || !press) {
2404 						SetKey(scan, press);
2405 						if (keypresscallback) keypresscallback(scan, press);
2406 					}
2407 				}
2408 			}
2409 			return 0;
2410 
2411 		case WM_CHAR:
2412 			if (eatosdinput) {
2413 				eatosdinput = 0;
2414 			} else if (OSD_HandleChar((unsigned char)wParam)) {
2415 				if (((keyasciififoend+1)&(KEYFIFOSIZ-1)) != keyasciififoplc) {
2416 					keyasciififo[keyasciififoend] = (unsigned char)wParam;
2417 					keyasciififoend = ((keyasciififoend+1)&(KEYFIFOSIZ-1));
2418 					//buildprintf("Char %d, %d-%d\n",wParam,keyasciififoplc,keyasciififoend);
2419 				}
2420 			}
2421 			return 0;
2422 
2423 		case WM_HOTKEY:
2424 			return 0;
2425 
2426 		case WM_INPUT:
2427 			{
2428 				RAWINPUT raw;
2429 				UINT dwSize = sizeof(RAWINPUT);
2430 
2431 				GetRawInputData((HRAWINPUT)lParam, RID_INPUT, (LPVOID)&raw, &dwSize, sizeof(RAWINPUTHEADER));
2432 
2433 				if (raw.header.dwType == RIM_TYPEMOUSE) {
2434 					int but;
2435 
2436 					if (!mousegrab) {
2437 						return 0;
2438 					}
2439 
2440 					for (but = 0; but < 4; but++) {  // Sorry XBUTTON2, I didn't plan for you.
2441 						switch ((raw.data.mouse.usButtonFlags >> (but << 1)) & 3) {
2442 							case 1:		// press
2443 								mouseb |= (1 << but);
2444 								if (mousepresscallback) {
2445 									mousepresscallback(but, 1);
2446 								}
2447 								break;
2448 							case 2:		// release
2449 								mouseb &= ~(1 << but);
2450 								if (mousepresscallback) {
2451 									mousepresscallback(but, 0);
2452 								}
2453 								break;
2454 							default: break;	// no change
2455 						}
2456 					}
2457 
2458 					if (raw.data.mouse.usButtonFlags & RI_MOUSE_WHEEL) {
2459 						int direction = (short)raw.data.mouse.usButtonData < 0;	// 1 = down (-ve values), 0 = up
2460 
2461 						// Repeated events before the fake button release timer
2462 						// expires need to trigger a release and a new press.
2463 						if (mousewheel[direction] > 0 && mousepresscallback) {
2464 							mousepresscallback(5 + direction, 0);
2465 						}
2466 
2467 						mousewheel[direction] = getticks();
2468 						mouseb |= (16 << direction);
2469 						if (mousepresscallback) {
2470 							mousepresscallback(5 + direction, 1);
2471 						}
2472 					}
2473 
2474 					if (raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
2475 						static LONG absx = 0, absy = 0;
2476 						static char first = 1;
2477 
2478 						if (!first) {
2479 							mousex += raw.data.mouse.lLastX - absx;
2480 							mousey += raw.data.mouse.lLastY - absy;
2481 						} else {
2482 							first = 0;
2483 						}
2484 						absx = raw.data.mouse.lLastX;
2485 						absy = raw.data.mouse.lLastY;
2486 					} else {
2487 						mousex += raw.data.mouse.lLastX;
2488 						mousey += raw.data.mouse.lLastY;
2489 					}
2490 				}
2491 			}
2492 			return 0;
2493 
2494 		case WM_ENTERMENULOOP:
2495 		case WM_ENTERSIZEMOVE:
2496 //			AcquireInputDevices(0);
2497 			return 0;
2498 		case WM_EXITMENULOOP:
2499 		case WM_EXITSIZEMOVE:
2500 //			AcquireInputDevices(1);
2501 			return 0;
2502 
2503 		case WM_DESTROY:
2504 			hWindow = 0;
2505 			//PostQuitMessage(0);	// JBF 20040115: not anymore
2506 			return 0;
2507 
2508 		default:
2509 			break;
2510 	}
2511 
2512 	return DefWindowProc(hWnd, uMsg, wParam, lParam);
2513 }
2514 
2515 
2516 //
2517 // RegisterWindowClass() -- register the window class
2518 //
RegisterWindowClass(void)2519 static BOOL RegisterWindowClass(void)
2520 {
2521 	WNDCLASSEX wcx;
2522 
2523 	if (window_class_registered) return FALSE;
2524 
2525 	//buildputs("Registering window class\n");
2526 
2527 	wcx.cbSize	= sizeof(wcx);
2528 	wcx.style	= CS_OWNDC;
2529 	wcx.lpfnWndProc	= WndProcCallback;
2530 	wcx.cbClsExtra	= 0;
2531 	wcx.cbWndExtra	= 0;
2532 	wcx.hInstance	= hInstance;
2533 	wcx.hIcon	= LoadImage(hInstance, MAKEINTRESOURCE(100), IMAGE_ICON,
2534 				GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
2535 	wcx.hCursor	= LoadCursor(NULL, IDC_ARROW);
2536 	wcx.hbrBackground = CreateSolidBrush(RGB(0,0,0));
2537 	wcx.lpszMenuName = NULL;
2538 	wcx.lpszClassName = WINDOW_CLASS;
2539 	wcx.hIconSm	= LoadImage(hInstance, MAKEINTRESOURCE(100), IMAGE_ICON,
2540 				GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
2541 	if (!RegisterClassEx(&wcx)) {
2542 		ShowErrorBox("Failed to register window class");
2543 		return TRUE;
2544 	}
2545 
2546 	window_class_registered = TRUE;
2547 
2548 	return FALSE;
2549 }
2550 
2551 
2552 //
2553 // GetWindowsErrorMsg() -- gives a pointer to a static buffer containing the Windows error message
2554 //
GetWindowsErrorMsg(DWORD code)2555 static LPTSTR GetWindowsErrorMsg(DWORD code)
2556 {
2557 	static TCHAR lpMsgBuf[1024];
2558 
2559 	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
2560 		NULL, code,
2561 		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2562 		(LPTSTR)lpMsgBuf, 1024, NULL);
2563 
2564 	return lpMsgBuf;
2565 }
2566 
getwindowserrorstr(DWORD code)2567 static const char *getwindowserrorstr(DWORD code)
2568 {
2569 	static char msg[1024];
2570 	memset(msg, 0, sizeof(msg));
2571 	OemToCharBuff(GetWindowsErrorMsg(code), msg, sizeof(msg)-1);
2572 	return msg;
2573 }
2574