added stb, more binaryout changes"
[henge/apc.git] / stb / tests / oversample / stb_wingraph.h
1 // stb_wingraph.h v0.01 - public domain windows graphics programming
2 // wraps WinMain, ChoosePixelFormat, ChangeDisplayResolution, etc. for
3 // doing OpenGL graphics
4 //
5 // in ONE source file, put '#define STB_DEFINE' before including this
6 // OR put '#define STB_WINMAIN' to define a WinMain that calls stbwingraph_main(void)
7 //
8 // @TODO:
9 // 2d rendering interface (that can be done easily in software)
10 // STB_WINGRAPH_SOFTWARE -- 2d software rendering only
11 // STB_WINGRAPH_OPENGL -- OpenGL only
12
13
14 #ifndef INCLUDE_STB_WINGRAPH_H
15 #define INCLUDE_STB_WINGRAPH_H
16
17 #ifdef STB_WINMAIN
18 #ifndef STB_DEFINE
19 #define STB_DEFINE
20 #define STB_WINGRAPH_DISABLE_DEFINE_AT_END
21 #endif
22 #endif
23
24 #ifdef STB_DEFINE
25 #pragma comment(lib, "opengl32.lib")
26 #pragma comment(lib, "glu32.lib")
27 #pragma comment(lib, "winmm.lib")
28 #pragma comment(lib, "gdi32.lib")
29 #pragma comment(lib, "user32.lib")
30 #endif
31
32 #ifdef __cplusplus
33 #define STB_EXTERN extern "C"
34 #else
35 #define STB_EXTERN
36 #endif
37
38 #ifdef STB_DEFINE
39 #ifndef _WINDOWS_
40 #ifdef APIENTRY
41 #undef APIENTRY
42 #endif
43 #ifdef WINGDIAPI
44 #undef WINGDIAPI
45 #endif
46 #define _WIN32_WINNT 0x0400 // WM_MOUSEWHEEL
47 #include <windows.h>
48 #endif
49 #include <stdio.h>
50 #include <math.h>
51 #include <time.h>
52 #include <string.h>
53 #include <assert.h>
54 #endif
55
56 typedef void * stbwingraph_hwnd;
57 typedef void * stbwingraph_hinstance;
58
59 enum
60 {
61 STBWINGRAPH_unprocessed = -(1 << 24),
62 STBWINGRAPH_do_not_show,
63 STBWINGRAPH_winproc_exit,
64 STBWINGRAPH_winproc_update,
65 STBWINGRAPH_update_exit,
66 STBWINGRAPH_update_pause,
67 };
68
69 typedef enum
70 {
71 STBWGE__none=0,
72
73 STBWGE_create,
74 STBWGE_create_postshow,
75 STBWGE_draw,
76 STBWGE_destroy,
77 STBWGE_char,
78 STBWGE_keydown,
79 STBWGE_syskeydown,
80 STBWGE_keyup,
81 STBWGE_syskeyup,
82 STBWGE_deactivate,
83 STBWGE_activate,
84 STBWGE_size,
85
86 STBWGE_mousemove ,
87 STBWGE_leftdown , STBWGE_leftup ,
88 STBWGE_middledown, STBWGE_middleup,
89 STBWGE_rightdown , STBWGE_rightup ,
90 STBWGE_mousewheel,
91 } stbwingraph_event_type;
92
93 typedef struct
94 {
95 stbwingraph_event_type type;
96
97 // for input events (mouse, keyboard)
98 int mx,my; // mouse x & y
99 int dx,dy;
100 int shift, ctrl, alt;
101
102 // for keyboard events
103 int key;
104
105 // for STBWGE_size:
106 int width, height;
107
108 // for STBWGE_crate
109 int did_share_lists; // if true, wglShareLists succeeded
110
111 void *handle;
112
113 } stbwingraph_event;
114
115 typedef int (*stbwingraph_window_proc)(void *data, stbwingraph_event *event);
116
117 extern stbwingraph_hinstance stbwingraph_app;
118 extern stbwingraph_hwnd stbwingraph_primary_window;
119 extern int stbwingraph_request_fullscreen;
120 extern int stbwingraph_request_windowed;
121
122 STB_EXTERN void stbwingraph_ods(char *str, ...);
123 STB_EXTERN int stbwingraph_MessageBox(stbwingraph_hwnd win, unsigned int type,
124 char *caption, char *text, ...);
125 STB_EXTERN int stbwingraph_ChangeResolution(unsigned int w, unsigned int h,
126 unsigned int bits, int use_message_box);
127 STB_EXTERN int stbwingraph_SetPixelFormat(stbwingraph_hwnd win, int color_bits,
128 int alpha_bits, int depth_bits, int stencil_bits, int accum_bits);
129 STB_EXTERN int stbwingraph_DefineClass(void *hinstance, char *iconname);
130 STB_EXTERN void stbwingraph_SwapBuffers(void *win);
131 STB_EXTERN void stbwingraph_Priority(int n);
132
133 STB_EXTERN void stbwingraph_MakeFonts(void *window, int font_base);
134 STB_EXTERN void stbwingraph_ShowWindow(void *window);
135 STB_EXTERN void *stbwingraph_CreateWindow(int primary, stbwingraph_window_proc func, void *data, char *text, int width, int height, int fullscreen, int resizeable, int dest_alpha, int stencil);
136 STB_EXTERN void *stbwingraph_CreateWindowSimple(stbwingraph_window_proc func, int width, int height);
137 STB_EXTERN void *stbwingraph_CreateWindowSimpleFull(stbwingraph_window_proc func, int fullscreen, int ww, int wh, int fw, int fh);
138 STB_EXTERN void stbwingraph_DestroyWindow(void *window);
139 STB_EXTERN void stbwingraph_ShowCursor(void *window, int visible);
140 STB_EXTERN float stbwingraph_GetTimestep(float minimum_time);
141 STB_EXTERN void stbwingraph_SetGLWindow(void *win);
142 typedef int (*stbwingraph_update)(float timestep, int real, int in_client);
143 STB_EXTERN int stbwingraph_MainLoop(stbwingraph_update func, float mintime);
144
145 #ifdef STB_DEFINE
146 stbwingraph_hinstance stbwingraph_app;
147 stbwingraph_hwnd stbwingraph_primary_window;
148 int stbwingraph_request_fullscreen;
149 int stbwingraph_request_windowed;
150
151 void stbwingraph_ods(char *str, ...)
152 {
153 char buffer[1024];
154 va_list v;
155 va_start(v,str);
156 vsprintf(buffer, str, v);
157 va_end(v);
158 OutputDebugString(buffer);
159 }
160
161 int stbwingraph_MessageBox(stbwingraph_hwnd win, unsigned int type, char *caption, char *text, ...)
162 {
163 va_list v;
164 char buffer[1024];
165 va_start(v, text);
166 vsprintf(buffer, text, v);
167 va_end(v);
168 return MessageBox(win, buffer, caption, type);
169 }
170
171 void stbwingraph_Priority(int n)
172 {
173 int p;
174 switch (n) {
175 case -1: p = THREAD_PRIORITY_BELOW_NORMAL; break;
176 case 0: p = THREAD_PRIORITY_NORMAL; break;
177 case 1: p = THREAD_PRIORITY_ABOVE_NORMAL; break;
178 default:
179 if (n < 0) p = THREAD_PRIORITY_LOWEST;
180 else p = THREAD_PRIORITY_HIGHEST;
181 }
182 SetThreadPriority(GetCurrentThread(), p);
183 }
184
185 static void stbwingraph_ResetResolution(void)
186 {
187 ChangeDisplaySettings(NULL, 0);
188 }
189
190 static void stbwingraph_RegisterResetResolution(void)
191 {
192 static int done=0;
193 if (!done) {
194 done = 1;
195 atexit(stbwingraph_ResetResolution);
196 }
197 }
198
199 int stbwingraph_ChangeResolution(unsigned int w, unsigned int h, unsigned int bits, int use_message_box)
200 {
201 DEVMODE mode;
202 int res;
203
204 int i, tries=0;
205 for (i=0; ; ++i) {
206 int success = EnumDisplaySettings(NULL, i, &mode);
207 if (!success) break;
208 if (mode.dmBitsPerPel == bits && mode.dmPelsWidth == w && mode.dmPelsHeight == h) {
209 ++tries;
210 success = ChangeDisplaySettings(&mode, CDS_FULLSCREEN);
211 if (success == DISP_CHANGE_SUCCESSFUL) {
212 stbwingraph_RegisterResetResolution();
213 return TRUE;
214 }
215 break;
216 }
217 }
218
219 if (!tries) {
220 if (use_message_box)
221 stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The resolution %d x %d x %d-bits is not supported.", w, h, bits);
222 return FALSE;
223 }
224
225 // we tried but failed, so try explicitly doing it without specifying refresh rate
226
227 // Win95 support logic
228 mode.dmBitsPerPel = bits;
229 mode.dmPelsWidth = w;
230 mode.dmPelsHeight = h;
231 mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
232
233 res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN);
234
235 switch (res) {
236 case DISP_CHANGE_SUCCESSFUL:
237 stbwingraph_RegisterResetResolution();
238 return TRUE;
239
240 case DISP_CHANGE_RESTART:
241 if (use_message_box)
242 stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "Please set your desktop to %d-bit color and then try again.");
243 return FALSE;
244
245 case DISP_CHANGE_FAILED:
246 if (use_message_box)
247 stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The hardware failed to change modes.");
248 return FALSE;
249
250 case DISP_CHANGE_BADMODE:
251 if (use_message_box)
252 stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The resolution %d x %d x %d-bits is not supported.", w, h, bits);
253 return FALSE;
254
255 default:
256 if (use_message_box)
257 stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "An unknown error prevented a change to a %d x %d x %d-bit display.", w, h, bits);
258 return FALSE;
259 }
260 }
261
262 int stbwingraph_SetPixelFormat(stbwingraph_hwnd win, int color_bits, int alpha_bits, int depth_bits, int stencil_bits, int accum_bits)
263 {
264 HDC dc = GetDC(win);
265 PIXELFORMATDESCRIPTOR pfd = { sizeof(pfd) };
266 int pixel_format;
267
268 pfd.nVersion = 1;
269 pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
270 pfd.dwLayerMask = PFD_MAIN_PLANE;
271 pfd.iPixelType = PFD_TYPE_RGBA;
272 pfd.cColorBits = color_bits;
273 pfd.cAlphaBits = alpha_bits;
274 pfd.cDepthBits = depth_bits;
275 pfd.cStencilBits = stencil_bits;
276 pfd.cAccumBits = accum_bits;
277
278 pixel_format = ChoosePixelFormat(dc, &pfd);
279 if (!pixel_format) return FALSE;
280
281 if (!DescribePixelFormat(dc, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), &pfd))
282 return FALSE;
283 SetPixelFormat(dc, pixel_format, &pfd);
284
285 return TRUE;
286 }
287
288 typedef struct
289 {
290 // app data
291 stbwingraph_window_proc func;
292 void *data;
293 // creation parameters
294 int color, alpha, depth, stencil, accum;
295 HWND share_window;
296 HWND window;
297 // internal data
298 HGLRC rc;
299 HDC dc;
300 int hide_mouse;
301 int in_client;
302 int active;
303 int did_share_lists;
304 int mx,my; // last mouse positions
305 } stbwingraph__window;
306
307 static void stbwingraph__inclient(stbwingraph__window *win, int state)
308 {
309 if (state != win->in_client) {
310 win->in_client = state;
311 if (win->hide_mouse)
312 ShowCursor(!state);
313 }
314 }
315
316 static void stbwingraph__key(stbwingraph_event *e, int type, int key, stbwingraph__window *z)
317 {
318 e->type = type;
319 e->key = key;
320 e->shift = (GetKeyState(VK_SHIFT) < 0);
321 e->ctrl = (GetKeyState(VK_CONTROL) < 0);
322 e->alt = (GetKeyState(VK_MENU) < 0);
323 if (z) {
324 e->mx = z->mx;
325 e->my = z->my;
326 } else {
327 e->mx = e->my = 0;
328 }
329 e->dx = e->dy = 0;
330 }
331
332 static void stbwingraph__mouse(stbwingraph_event *e, int type, WPARAM wparam, LPARAM lparam, int capture, void *wnd, stbwingraph__window *z)
333 {
334 static int captured = 0;
335 e->type = type;
336 e->mx = (short) LOWORD(lparam);
337 e->my = (short) HIWORD(lparam);
338 if (!z || z->mx == -(1 << 30)) {
339 e->dx = e->dy = 0;
340 } else {
341 e->dx = e->mx - z->mx;
342 e->dy = e->my - z->my;
343 }
344 e->shift = (wparam & MK_SHIFT) != 0;
345 e->ctrl = (wparam & MK_CONTROL) != 0;
346 e->alt = (wparam & MK_ALT) != 0;
347 if (z) {
348 z->mx = e->mx;
349 z->my = e->my;
350 }
351 if (capture) {
352 if (!captured && capture == 1)
353 SetCapture(wnd);
354 captured += capture;
355 if (!captured && capture == -1)
356 ReleaseCapture();
357 if (captured < 0) captured = 0;
358 }
359 }
360
361 static void stbwingraph__mousewheel(stbwingraph_event *e, int type, WPARAM wparam, LPARAM lparam, int capture, void *wnd, stbwingraph__window *z)
362 {
363 // lparam seems bogus!
364 static int captured = 0;
365 e->type = type;
366 if (z) {
367 e->mx = z->mx;
368 e->my = z->my;
369 }
370 e->dx = e->dy = 0;
371 e->shift = (wparam & MK_SHIFT) != 0;
372 e->ctrl = (wparam & MK_CONTROL) != 0;
373 e->alt = (GetKeyState(VK_MENU) < 0);
374 e->key = ((int) wparam >> 16);
375 }
376
377 int stbwingraph_force_update;
378 static int WINAPI stbwingraph_WinProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
379 {
380 int allow_default = TRUE;
381 stbwingraph_event e = { STBWGE__none };
382 // the following line is wrong for 64-bit windows, but VC6 doesn't have GetWindowLongPtr
383 stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(wnd, GWL_USERDATA);
384
385 switch (msg) {
386
387 case WM_CREATE:
388 {
389 LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lparam;
390 assert(z == NULL);
391 z = (stbwingraph__window *) lpcs->lpCreateParams;
392 SetWindowLong(wnd, GWL_USERDATA, (LONG) z);
393 z->dc = GetDC(wnd);
394 if (stbwingraph_SetPixelFormat(wnd, z->color, z->alpha, z->depth, z->stencil, z->accum)) {
395 z->rc = wglCreateContext(z->dc);
396 if (z->rc) {
397 e.type = STBWGE_create;
398 z->did_share_lists = FALSE;
399 if (z->share_window) {
400 stbwingraph__window *y = (stbwingraph__window *) GetWindowLong(z->share_window, GWL_USERDATA);
401 if (wglShareLists(z->rc, y->rc))
402 z->did_share_lists = TRUE;
403 }
404 wglMakeCurrent(z->dc, z->rc);
405 return 0;
406 }
407 }
408 return -1;
409 }
410
411 case WM_PAINT: {
412 PAINTSTRUCT ps;
413 HDC hdc = BeginPaint(wnd, &ps);
414 SelectObject(hdc, GetStockObject(NULL_BRUSH));
415 e.type = STBWGE_draw;
416 e.handle = wnd;
417 z->func(z->data, &e);
418 EndPaint(wnd, &ps);
419 return 0;
420 }
421
422 case WM_DESTROY:
423 e.type = STBWGE_destroy;
424 e.handle = wnd;
425 if (z && z->func)
426 z->func(z->data, &e);
427 wglMakeCurrent(NULL, NULL) ;
428 if (z) {
429 if (z->rc) wglDeleteContext(z->rc);
430 z->dc = 0;
431 z->rc = 0;
432 }
433 if (wnd == stbwingraph_primary_window)
434 PostQuitMessage (0);
435 return 0;
436
437 case WM_CHAR: stbwingraph__key(&e, STBWGE_char , wparam, z); break;
438 case WM_KEYDOWN: stbwingraph__key(&e, STBWGE_keydown, wparam, z); break;
439 case WM_KEYUP: stbwingraph__key(&e, STBWGE_keyup , wparam, z); break;
440
441 case WM_NCMOUSEMOVE: stbwingraph__inclient(z,0); break;
442 case WM_MOUSEMOVE: stbwingraph__inclient(z,1); stbwingraph__mouse(&e, STBWGE_mousemove, wparam, lparam,0,wnd, z); break;
443 case WM_LBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_leftdown, wparam, lparam,1,wnd, z); break;
444 case WM_MBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_middledown, wparam, lparam,1,wnd, z); break;
445 case WM_RBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_rightdown, wparam, lparam,1,wnd, z); break;
446 case WM_LBUTTONUP: stbwingraph__mouse(&e, STBWGE_leftup, wparam, lparam,-1,wnd, z); break;
447 case WM_MBUTTONUP: stbwingraph__mouse(&e, STBWGE_middleup, wparam, lparam,-1,wnd, z); break;
448 case WM_RBUTTONUP: stbwingraph__mouse(&e, STBWGE_rightup, wparam, lparam,-1,wnd, z); break;
449 case WM_MOUSEWHEEL: stbwingraph__mousewheel(&e, STBWGE_mousewheel, wparam, lparam,0,wnd, z); break;
450
451 case WM_ACTIVATE:
452 allow_default = FALSE;
453 if (LOWORD(wparam)==WA_INACTIVE ) {
454 wglMakeCurrent(z->dc, NULL);
455 e.type = STBWGE_deactivate;
456 z->active = FALSE;
457 } else {
458 wglMakeCurrent(z->dc, z->rc);
459 e.type = STBWGE_activate;
460 z->active = TRUE;
461 }
462 e.handle = wnd;
463 z->func(z->data, &e);
464 return 0;
465
466 case WM_SIZE: {
467 RECT rect;
468 allow_default = FALSE;
469 GetClientRect(wnd, &rect);
470 e.type = STBWGE_size;
471 e.width = rect.right;
472 e.height = rect.bottom;
473 e.handle = wnd;
474 z->func(z->data, &e);
475 return 0;
476 }
477
478 default:
479 return DefWindowProc (wnd, msg, wparam, lparam);
480 }
481
482 if (e.type != STBWGE__none) {
483 int n;
484 e.handle = wnd;
485 n = z->func(z->data, &e);
486 if (n == STBWINGRAPH_winproc_exit) {
487 PostQuitMessage(0);
488 n = 0;
489 }
490 if (n == STBWINGRAPH_winproc_update) {
491 stbwingraph_force_update = TRUE;
492 return 1;
493 }
494 if (n != STBWINGRAPH_unprocessed)
495 return n;
496 }
497 return DefWindowProc (wnd, msg, wparam, lparam);
498 }
499
500 int stbwingraph_DefineClass(HINSTANCE hInstance, char *iconname)
501 {
502 WNDCLASSEX wndclass;
503
504 stbwingraph_app = hInstance;
505
506 wndclass.cbSize = sizeof(wndclass);
507 wndclass.style = CS_OWNDC;
508 wndclass.lpfnWndProc = (WNDPROC) stbwingraph_WinProc;
509 wndclass.cbClsExtra = 0;
510 wndclass.cbWndExtra = 0;
511 wndclass.hInstance = hInstance;
512 wndclass.hIcon = LoadIcon(hInstance, iconname);
513 wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
514 wndclass.hbrBackground = GetStockObject(NULL_BRUSH);
515 wndclass.lpszMenuName = "zwingraph";
516 wndclass.lpszClassName = "zwingraph";
517 wndclass.hIconSm = NULL;
518
519 if (!RegisterClassEx(&wndclass))
520 return FALSE;
521 return TRUE;
522 }
523
524 void stbwingraph_ShowWindow(void *window)
525 {
526 stbwingraph_event e = { STBWGE_create_postshow };
527 stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(window, GWL_USERDATA);
528 ShowWindow(window, SW_SHOWNORMAL);
529 InvalidateRect(window, NULL, TRUE);
530 UpdateWindow(window);
531 e.handle = window;
532 z->func(z->data, &e);
533 }
534
535 void *stbwingraph_CreateWindow(int primary, stbwingraph_window_proc func, void *data, char *text,
536 int width, int height, int fullscreen, int resizeable, int dest_alpha, int stencil)
537 {
538 HWND win;
539 DWORD dwstyle;
540 stbwingraph__window *z = (stbwingraph__window *) malloc(sizeof(*z));
541
542 if (z == NULL) return NULL;
543 memset(z, 0, sizeof(*z));
544 z->color = 24;
545 z->depth = 24;
546 z->alpha = dest_alpha;
547 z->stencil = stencil;
548 z->func = func;
549 z->data = data;
550 z->mx = -(1 << 30);
551 z->my = 0;
552
553 if (primary) {
554 if (stbwingraph_request_windowed)
555 fullscreen = FALSE;
556 else if (stbwingraph_request_fullscreen)
557 fullscreen = TRUE;
558 }
559
560 if (fullscreen) {
561 #ifdef STB_SIMPLE
562 stbwingraph_ChangeResolution(width, height, 32, 1);
563 #else
564 if (!stbwingraph_ChangeResolution(width, height, 32, 0))
565 return NULL;
566 #endif
567 dwstyle = WS_POPUP | WS_CLIPSIBLINGS;
568 } else {
569 RECT rect;
570 dwstyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
571 if (resizeable)
572 dwstyle |= WS_SIZEBOX | WS_MAXIMIZEBOX;
573 rect.top = 0;
574 rect.left = 0;
575 rect.right = width;
576 rect.bottom = height;
577 AdjustWindowRect(&rect, dwstyle, FALSE);
578 width = rect.right - rect.left;
579 height = rect.bottom - rect.top;
580 }
581
582 win = CreateWindow("zwingraph", text ? text : "sample", dwstyle,
583 CW_USEDEFAULT,0, width, height,
584 NULL, NULL, stbwingraph_app, z);
585
586 if (win == NULL) return win;
587
588 if (primary) {
589 if (stbwingraph_primary_window)
590 stbwingraph_DestroyWindow(stbwingraph_primary_window);
591 stbwingraph_primary_window = win;
592 }
593
594 {
595 stbwingraph_event e = { STBWGE_create };
596 stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA);
597 z->window = win;
598 e.did_share_lists = z->did_share_lists;
599 e.handle = win;
600 if (z->func(z->data, &e) != STBWINGRAPH_do_not_show)
601 stbwingraph_ShowWindow(win);
602 }
603
604 return win;
605 }
606
607 void *stbwingraph_CreateWindowSimple(stbwingraph_window_proc func, int width, int height)
608 {
609 int fullscreen = 0;
610 #ifndef _DEBUG
611 if (width == 640 && height == 480) fullscreen = 1;
612 if (width == 800 && height == 600) fullscreen = 1;
613 if (width == 1024 && height == 768) fullscreen = 1;
614 if (width == 1280 && height == 1024) fullscreen = 1;
615 if (width == 1600 && height == 1200) fullscreen = 1;
616 //@TODO: widescreen widths
617 #endif
618 return stbwingraph_CreateWindow(1, func, NULL, NULL, width, height, fullscreen, 1, 0, 0);
619 }
620
621 void *stbwingraph_CreateWindowSimpleFull(stbwingraph_window_proc func, int fullscreen, int ww, int wh, int fw, int fh)
622 {
623 if (fullscreen == -1) {
624 #ifdef _DEBUG
625 fullscreen = 0;
626 #else
627 fullscreen = 1;
628 #endif
629 }
630
631 if (fullscreen) {
632 if (fw) ww = fw;
633 if (fh) wh = fh;
634 }
635 return stbwingraph_CreateWindow(1, func, NULL, NULL, ww, wh, fullscreen, 1, 0, 0);
636 }
637
638 void stbwingraph_DestroyWindow(void *window)
639 {
640 stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(window, GWL_USERDATA);
641 DestroyWindow(window);
642 free(z);
643 if (stbwingraph_primary_window == window)
644 stbwingraph_primary_window = NULL;
645 }
646
647 void stbwingraph_ShowCursor(void *window, int visible)
648 {
649 int hide;
650 stbwingraph__window *win;
651 if (!window)
652 window = stbwingraph_primary_window;
653 win = (stbwingraph__window *) GetWindowLong((HWND) window, GWL_USERDATA);
654 hide = !visible;
655 if (hide != win->hide_mouse) {
656 win->hide_mouse = hide;
657 if (!hide)
658 ShowCursor(TRUE);
659 else if (win->in_client)
660 ShowCursor(FALSE);
661 }
662 }
663
664 float stbwingraph_GetTimestep(float minimum_time)
665 {
666 float elapsedTime;
667 double thisTime;
668 static double lastTime = -1;
669
670 if (lastTime == -1)
671 lastTime = timeGetTime() / 1000.0 - minimum_time;
672
673 for(;;) {
674 thisTime = timeGetTime() / 1000.0;
675 elapsedTime = (float) (thisTime - lastTime);
676 if (elapsedTime >= minimum_time) {
677 lastTime = thisTime;
678 return elapsedTime;
679 }
680 #if 1
681 Sleep(2);
682 #endif
683 }
684 }
685
686 void stbwingraph_SetGLWindow(void *win)
687 {
688 stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA);
689 if (z)
690 wglMakeCurrent(z->dc, z->rc);
691 }
692
693 void stbwingraph_MakeFonts(void *window, int font_base)
694 {
695 wglUseFontBitmaps(GetDC(window ? window : stbwingraph_primary_window), 0, 256, font_base);
696 }
697
698 // returns 1 if WM_QUIT, 0 if 'func' returned 0
699 int stbwingraph_MainLoop(stbwingraph_update func, float mintime)
700 {
701 int needs_drawing = FALSE;
702 MSG msg;
703
704 int is_animating = TRUE;
705 if (mintime <= 0) mintime = 0.01f;
706
707 for(;;) {
708 int n;
709
710 is_animating = TRUE;
711 // wait for a message if: (a) we're animating and there's already a message
712 // or (b) we're not animating
713 if (!is_animating || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
714 stbwingraph_force_update = FALSE;
715 if (GetMessage(&msg, NULL, 0, 0)) {
716 TranslateMessage(&msg);
717 DispatchMessage(&msg);
718 } else {
719 return 1; // WM_QUIT
720 }
721
722 // only force a draw for certain messages...
723 // if I don't do this, we peg at 50% for some reason... must
724 // be a bug somewhere, because we peg at 100% when rendering...
725 // very weird... looks like NVIDIA is pumping some messages
726 // through our pipeline? well, ok, I guess if we can get
727 // non-user-generated messages we have to do this
728 if (!stbwingraph_force_update) {
729 switch (msg.message) {
730 case WM_MOUSEMOVE:
731 case WM_NCMOUSEMOVE:
732 break;
733 case WM_CHAR:
734 case WM_KEYDOWN:
735 case WM_KEYUP:
736 case WM_LBUTTONDOWN:
737 case WM_MBUTTONDOWN:
738 case WM_RBUTTONDOWN:
739 case WM_LBUTTONUP:
740 case WM_MBUTTONUP:
741 case WM_RBUTTONUP:
742 case WM_TIMER:
743 case WM_SIZE:
744 case WM_ACTIVATE:
745 needs_drawing = TRUE;
746 break;
747 }
748 } else
749 needs_drawing = TRUE;
750 }
751
752 // if another message, process that first
753 // @TODO: i don't think this is working, because I can't key ahead
754 // in the SVT demo app
755 if (PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE))
756 continue;
757
758 // and now call update
759 if (needs_drawing || is_animating) {
760 int real=1, in_client=1;
761 if (stbwingraph_primary_window) {
762 stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(stbwingraph_primary_window, GWL_USERDATA);
763 if (z && !z->active) {
764 real = 0;
765 }
766 if (z)
767 in_client = z->in_client;
768 }
769
770 if (stbwingraph_primary_window)
771 stbwingraph_SetGLWindow(stbwingraph_primary_window);
772 n = func(stbwingraph_GetTimestep(mintime), real, in_client);
773 if (n == STBWINGRAPH_update_exit)
774 return 0; // update_quit
775
776 is_animating = (n != STBWINGRAPH_update_pause);
777
778 needs_drawing = FALSE;
779 }
780 }
781 }
782
783 void stbwingraph_SwapBuffers(void *win)
784 {
785 stbwingraph__window *z;
786 if (win == NULL) win = stbwingraph_primary_window;
787 z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA);
788 if (z && z->dc)
789 SwapBuffers(z->dc);
790 }
791 #endif
792
793 #ifdef STB_WINMAIN
794 void stbwingraph_main(void);
795
796 char *stb_wingraph_commandline;
797
798 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
799 {
800 {
801 char buffer[1024];
802 // add spaces to either side of the string
803 buffer[0] = ' ';
804 strcpy(buffer+1, lpCmdLine);
805 strcat(buffer, " ");
806 if (strstr(buffer, " -reset ")) {
807 ChangeDisplaySettings(NULL, 0);
808 exit(0);
809 }
810 if (strstr(buffer, " -window ") || strstr(buffer, " -windowed "))
811 stbwingraph_request_windowed = TRUE;
812 else if (strstr(buffer, " -full ") || strstr(buffer, " -fullscreen "))
813 stbwingraph_request_fullscreen = TRUE;
814 }
815 stb_wingraph_commandline = lpCmdLine;
816
817 stbwingraph_DefineClass(hInstance, "appicon");
818 stbwingraph_main();
819
820 return 0;
821 }
822 #endif
823
824 #undef STB_EXTERN
825 #ifdef STB_WINGRAPH_DISABLE_DEFINE_AT_END
826 #undef STB_DEFINE
827 #endif
828
829 #endif // INCLUDE_STB_WINGRAPH_H