You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
		
		
		
		
		
			
		
			
				
					
					
						
							829 lines
						
					
					
						
							24 KiB
						
					
					
				
			
		
		
	
	
							829 lines
						
					
					
						
							24 KiB
						
					
					
				| // stb_wingraph.h  v0.01 - public domain windows graphics programming | |
| // wraps WinMain, ChoosePixelFormat, ChangeDisplayResolution, etc. for | |
| // doing OpenGL graphics | |
| // | |
| // in ONE source file, put '#define STB_DEFINE' before including this | |
| // OR put '#define STB_WINMAIN' to define a WinMain that calls stbwingraph_main(void) | |
| // | |
| // @TODO: | |
| //    2d rendering interface (that can be done easily in software) | |
| //    STB_WINGRAPH_SOFTWARE -- 2d software rendering only | |
| //    STB_WINGRAPH_OPENGL   -- OpenGL only | |
|  | |
| 
 | |
| #ifndef INCLUDE_STB_WINGRAPH_H | |
| #define INCLUDE_STB_WINGRAPH_H | |
|  | |
| #ifdef STB_WINMAIN | |
|    #ifndef STB_DEFINE | |
|       #define STB_DEFINE | |
|       #define STB_WINGRAPH_DISABLE_DEFINE_AT_END | |
|    #endif | |
| #endif | |
|  | |
| #ifdef STB_DEFINE | |
|    #pragma comment(lib, "opengl32.lib") | |
|    #pragma comment(lib, "glu32.lib") | |
|    #pragma comment(lib, "winmm.lib") | |
|    #pragma comment(lib, "gdi32.lib") | |
|    #pragma comment(lib, "user32.lib") | |
| #endif | |
|  | |
| #ifdef __cplusplus | |
| #define STB_EXTERN extern "C" | |
| #else | |
| #define STB_EXTERN | |
| #endif | |
|  | |
| #ifdef STB_DEFINE | |
| #ifndef _WINDOWS_ | |
|    #ifdef APIENTRY | |
|    #undef APIENTRY | |
|    #endif | |
|    #ifdef WINGDIAPI | |
|    #undef WINGDIAPI | |
|    #endif | |
|    #define _WIN32_WINNT 0x0400  // WM_MOUSEWHEEL | |
|    #include <windows.h> | |
| #endif | |
| #include <stdio.h> | |
| #include <math.h> | |
| #include <time.h> | |
| #include <string.h> | |
| #include <assert.h> | |
| #endif | |
|  | |
| typedef void * stbwingraph_hwnd; | |
| typedef void * stbwingraph_hinstance; | |
| 
 | |
| enum | |
| { | |
|    STBWINGRAPH_unprocessed = -(1 << 24), | |
|    STBWINGRAPH_do_not_show, | |
|    STBWINGRAPH_winproc_exit, | |
|    STBWINGRAPH_winproc_update, | |
|    STBWINGRAPH_update_exit, | |
|    STBWINGRAPH_update_pause, | |
| }; | |
| 
 | |
| typedef enum | |
| { | |
|    STBWGE__none=0, | |
| 
 | |
|    STBWGE_create, | |
|    STBWGE_create_postshow, | |
|    STBWGE_draw, | |
|    STBWGE_destroy, | |
|    STBWGE_char, | |
|    STBWGE_keydown, | |
|    STBWGE_syskeydown, | |
|    STBWGE_keyup, | |
|    STBWGE_syskeyup, | |
|    STBWGE_deactivate, | |
|    STBWGE_activate, | |
|    STBWGE_size, | |
| 
 | |
|    STBWGE_mousemove , | |
|    STBWGE_leftdown  , STBWGE_leftup  , | |
|    STBWGE_middledown, STBWGE_middleup, | |
|    STBWGE_rightdown , STBWGE_rightup , | |
|    STBWGE_mousewheel, | |
| } stbwingraph_event_type; | |
| 
 | |
| typedef struct | |
| { | |
|    stbwingraph_event_type type; | |
| 
 | |
|    // for input events (mouse, keyboard) | |
|    int mx,my; // mouse x & y | |
|    int dx,dy; | |
|    int shift, ctrl, alt; | |
| 
 | |
|    // for keyboard events | |
|    int key; | |
| 
 | |
|    // for STBWGE_size: | |
|    int width, height; | |
| 
 | |
|    // for STBWGE_crate | |
|    int did_share_lists;  // if true, wglShareLists succeeded | |
|  | |
|    void *handle; | |
| 
 | |
| } stbwingraph_event; | |
| 
 | |
| typedef int (*stbwingraph_window_proc)(void *data, stbwingraph_event *event); | |
| 
 | |
| extern stbwingraph_hinstance   stbwingraph_app; | |
| extern stbwingraph_hwnd        stbwingraph_primary_window; | |
| extern int                     stbwingraph_request_fullscreen; | |
| extern int                     stbwingraph_request_windowed; | |
| 
 | |
| STB_EXTERN void stbwingraph_ods(char *str, ...); | |
| STB_EXTERN int stbwingraph_MessageBox(stbwingraph_hwnd win, unsigned int type, | |
|                                               char *caption, char *text, ...); | |
| STB_EXTERN int stbwingraph_ChangeResolution(unsigned int w, unsigned int h, | |
|                                       unsigned int bits, int use_message_box); | |
| STB_EXTERN int stbwingraph_SetPixelFormat(stbwingraph_hwnd win, int color_bits, | |
|             int alpha_bits, int depth_bits, int stencil_bits, int accum_bits); | |
| STB_EXTERN int stbwingraph_DefineClass(void *hinstance, char *iconname); | |
| STB_EXTERN void stbwingraph_SwapBuffers(void *win); | |
| STB_EXTERN void stbwingraph_Priority(int n); | |
| 
 | |
| STB_EXTERN void stbwingraph_MakeFonts(void *window, int font_base); | |
| STB_EXTERN void stbwingraph_ShowWindow(void *window); | |
| 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); | |
| STB_EXTERN void *stbwingraph_CreateWindowSimple(stbwingraph_window_proc func, int width, int height); | |
| STB_EXTERN void *stbwingraph_CreateWindowSimpleFull(stbwingraph_window_proc func, int fullscreen, int ww, int wh, int fw, int fh); | |
| STB_EXTERN void stbwingraph_DestroyWindow(void *window); | |
| STB_EXTERN void stbwingraph_ShowCursor(void *window, int visible); | |
| STB_EXTERN float stbwingraph_GetTimestep(float minimum_time); | |
| STB_EXTERN void stbwingraph_SetGLWindow(void *win); | |
| typedef int (*stbwingraph_update)(float timestep, int real, int in_client); | |
| STB_EXTERN int stbwingraph_MainLoop(stbwingraph_update func, float mintime); | |
| 
 | |
| #ifdef STB_DEFINE | |
| stbwingraph_hinstance   stbwingraph_app; | |
| stbwingraph_hwnd        stbwingraph_primary_window; | |
| int stbwingraph_request_fullscreen; | |
| int stbwingraph_request_windowed; | |
| 
 | |
| void stbwingraph_ods(char *str, ...) | |
| { | |
|    char buffer[1024]; | |
|    va_list v; | |
|    va_start(v,str); | |
|    vsprintf(buffer, str, v); | |
|    va_end(v); | |
|    OutputDebugString(buffer); | |
| } | |
| 
 | |
| int stbwingraph_MessageBox(stbwingraph_hwnd win, unsigned int type, char *caption, char *text, ...) | |
| { | |
|    va_list v; | |
|    char buffer[1024]; | |
|    va_start(v, text); | |
|    vsprintf(buffer, text, v); | |
|    va_end(v); | |
|    return MessageBox(win, buffer, caption, type); | |
| } | |
| 
 | |
| void stbwingraph_Priority(int n) | |
| { | |
|    int p; | |
|    switch (n) { | |
|       case -1: p = THREAD_PRIORITY_BELOW_NORMAL; break; | |
|       case 0: p = THREAD_PRIORITY_NORMAL; break; | |
|       case 1: p = THREAD_PRIORITY_ABOVE_NORMAL; break; | |
|       default: | |
|          if (n < 0) p = THREAD_PRIORITY_LOWEST; | |
|          else p = THREAD_PRIORITY_HIGHEST; | |
|    } | |
|    SetThreadPriority(GetCurrentThread(), p); | |
| } | |
| 
 | |
| static void stbwingraph_ResetResolution(void) | |
| { | |
|    ChangeDisplaySettings(NULL, 0); | |
| } | |
| 
 | |
| static void stbwingraph_RegisterResetResolution(void) | |
| { | |
|    static int done=0; | |
|    if (!done) { | |
|       done = 1; | |
|       atexit(stbwingraph_ResetResolution); | |
|    } | |
| } | |
| 
 | |
| int stbwingraph_ChangeResolution(unsigned int w, unsigned int h, unsigned int bits, int use_message_box) | |
| { | |
|    DEVMODE mode; | |
|    int res; | |
|     | |
|    int i, tries=0; | |
|    for (i=0; ; ++i) { | |
|       int success = EnumDisplaySettings(NULL, i, &mode); | |
|       if (!success) break; | |
|       if (mode.dmBitsPerPel == bits && mode.dmPelsWidth == w && mode.dmPelsHeight == h) { | |
|          ++tries; | |
|          success = ChangeDisplaySettings(&mode, CDS_FULLSCREEN);  | |
|          if (success == DISP_CHANGE_SUCCESSFUL) { | |
|             stbwingraph_RegisterResetResolution(); | |
|             return TRUE; | |
|          } | |
|          break; | |
|       } | |
|    } | |
| 
 | |
|    if (!tries) { | |
|       if (use_message_box) | |
|          stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The resolution %d x %d x %d-bits is not supported.", w, h, bits); | |
|       return FALSE; | |
|    } | |
| 
 | |
|    // we tried but failed, so try explicitly doing it without specifying refresh rate | |
|  | |
|    // Win95 support logic | |
|    mode.dmBitsPerPel = bits;  | |
|    mode.dmPelsWidth = w;  | |
|    mode.dmPelsHeight = h;  | |
|    mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;  | |
| 
 | |
|    res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN); | |
| 
 | |
|    switch (res) { | |
|       case DISP_CHANGE_SUCCESSFUL: | |
|          stbwingraph_RegisterResetResolution(); | |
|          return TRUE; | |
| 
 | |
|       case DISP_CHANGE_RESTART: | |
|          if (use_message_box) | |
|             stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "Please set your desktop to %d-bit color and then try again."); | |
|          return FALSE; | |
| 
 | |
|       case DISP_CHANGE_FAILED: | |
|          if (use_message_box) | |
|             stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The hardware failed to change modes."); | |
|          return FALSE; | |
| 
 | |
|       case DISP_CHANGE_BADMODE: | |
|          if (use_message_box) | |
|             stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The resolution %d x %d x %d-bits is not supported.", w, h, bits); | |
|          return FALSE; | |
| 
 | |
|       default: | |
|          if (use_message_box) | |
|             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); | |
|          return FALSE; | |
|    } | |
| } | |
| 
 | |
| int stbwingraph_SetPixelFormat(stbwingraph_hwnd win, int color_bits, int alpha_bits, int depth_bits, int stencil_bits, int accum_bits) | |
| { | |
|    HDC dc = GetDC(win); | |
|    PIXELFORMATDESCRIPTOR pfd = { sizeof(pfd) }; | |
|    int                   pixel_format; | |
| 
 | |
|    pfd.nVersion = 1; | |
|    pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; | |
|    pfd.dwLayerMask = PFD_MAIN_PLANE; | |
|    pfd.iPixelType = PFD_TYPE_RGBA; | |
|    pfd.cColorBits = color_bits; | |
|    pfd.cAlphaBits = alpha_bits; | |
|    pfd.cDepthBits = depth_bits; | |
|    pfd.cStencilBits = stencil_bits; | |
|    pfd.cAccumBits = accum_bits; | |
| 
 | |
|    pixel_format = ChoosePixelFormat(dc, &pfd); | |
|    if (!pixel_format) return FALSE; | |
| 
 | |
|    if (!DescribePixelFormat(dc, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) | |
|       return FALSE; | |
|    SetPixelFormat(dc, pixel_format, &pfd); | |
| 
 | |
|    return TRUE; | |
| } | |
| 
 | |
| typedef struct | |
| { | |
|    // app data | |
|    stbwingraph_window_proc func; | |
|    void *data; | |
|    // creation parameters | |
|    int   color, alpha, depth, stencil, accum; | |
|    HWND  share_window; | |
|    HWND  window; | |
|    // internal data | |
|    HGLRC rc; | |
|    HDC   dc; | |
|    int   hide_mouse; | |
|    int   in_client; | |
|    int   active; | |
|    int   did_share_lists; | |
|    int   mx,my; // last mouse positions | |
| } stbwingraph__window; | |
| 
 | |
| static void stbwingraph__inclient(stbwingraph__window *win, int state) | |
| { | |
|    if (state != win->in_client) { | |
|       win->in_client = state; | |
|       if (win->hide_mouse) | |
|          ShowCursor(!state); | |
|    } | |
| } | |
| 
 | |
| static void stbwingraph__key(stbwingraph_event *e, int type, int key, stbwingraph__window *z) | |
| { | |
|    e->type  = type; | |
|    e->key   = key; | |
|    e->shift = (GetKeyState(VK_SHIFT)   < 0); | |
|    e->ctrl  = (GetKeyState(VK_CONTROL) < 0); | |
|    e->alt   = (GetKeyState(VK_MENU)    < 0); | |
|    if  (z) { | |
|       e->mx    = z->mx; | |
|       e->my    = z->my; | |
|    } else { | |
|       e->mx = e->my = 0; | |
|    } | |
|    e->dx = e->dy = 0; | |
| } | |
| 
 | |
| static void stbwingraph__mouse(stbwingraph_event *e, int type, WPARAM wparam, LPARAM lparam, int capture, void *wnd, stbwingraph__window *z) | |
| { | |
|    static int captured = 0; | |
|    e->type = type; | |
|    e->mx = (short) LOWORD(lparam); | |
|    e->my = (short) HIWORD(lparam); | |
|    if (!z || z->mx == -(1 << 30)) { | |
|       e->dx = e->dy = 0; | |
|    } else { | |
|       e->dx = e->mx - z->mx; | |
|       e->dy = e->my - z->my; | |
|    } | |
|    e->shift = (wparam & MK_SHIFT) != 0; | |
|    e->ctrl  = (wparam & MK_CONTROL) != 0; | |
|    e->alt   = (wparam & MK_ALT) != 0; | |
|    if (z) { | |
|       z->mx = e->mx; | |
|       z->my = e->my; | |
|    } | |
|    if (capture) { | |
|       if (!captured && capture == 1) | |
|          SetCapture(wnd); | |
|       captured += capture; | |
|       if (!captured && capture == -1) | |
|          ReleaseCapture(); | |
|       if (captured < 0) captured = 0; | |
|    } | |
| } | |
| 
 | |
| static void stbwingraph__mousewheel(stbwingraph_event *e, int type, WPARAM wparam, LPARAM lparam, int capture, void *wnd, stbwingraph__window *z) | |
| { | |
|    // lparam seems bogus! | |
|    static int captured = 0; | |
|    e->type = type; | |
|    if (z) { | |
|       e->mx = z->mx; | |
|       e->my = z->my; | |
|    } | |
|    e->dx = e->dy = 0; | |
|    e->shift = (wparam & MK_SHIFT) != 0; | |
|    e->ctrl  = (wparam & MK_CONTROL) != 0; | |
|    e->alt   = (GetKeyState(VK_MENU)    < 0); | |
|    e->key = ((int) wparam >> 16); | |
| } | |
| 
 | |
| int stbwingraph_force_update; | |
| static int WINAPI stbwingraph_WinProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) | |
| { | |
|    int allow_default = TRUE; | |
|    stbwingraph_event e = { STBWGE__none }; | |
|    // the following line is wrong for 64-bit windows, but VC6 doesn't have GetWindowLongPtr | |
|    stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(wnd, GWL_USERDATA); | |
| 
 | |
|    switch (msg) { | |
| 
 | |
|       case WM_CREATE: | |
|       { | |
|          LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lparam; | |
|          assert(z == NULL); | |
|          z = (stbwingraph__window *) lpcs->lpCreateParams; | |
|          SetWindowLong(wnd, GWL_USERDATA, (LONG) z); | |
|          z->dc = GetDC(wnd); | |
|          if (stbwingraph_SetPixelFormat(wnd, z->color, z->alpha, z->depth, z->stencil, z->accum)) { | |
|             z->rc = wglCreateContext(z->dc); | |
|             if (z->rc) { | |
|                e.type = STBWGE_create; | |
|                z->did_share_lists = FALSE; | |
|                if (z->share_window) { | |
|                   stbwingraph__window *y = (stbwingraph__window *) GetWindowLong(z->share_window, GWL_USERDATA); | |
|                   if (wglShareLists(z->rc, y->rc)) | |
|                      z->did_share_lists = TRUE; | |
|                } | |
|                wglMakeCurrent(z->dc, z->rc); | |
|                return 0; | |
|             } | |
|          } | |
|          return -1; | |
|       } | |
| 
 | |
|       case WM_PAINT: { | |
|          PAINTSTRUCT ps; | |
|          HDC hdc = BeginPaint(wnd, &ps); | |
|          SelectObject(hdc, GetStockObject(NULL_BRUSH)); | |
|          e.type = STBWGE_draw; | |
|          e.handle = wnd; | |
|          z->func(z->data, &e); | |
|          EndPaint(wnd, &ps); | |
|          return 0; | |
|       } | |
| 
 | |
|       case WM_DESTROY: | |
|          e.type = STBWGE_destroy; | |
|          e.handle = wnd; | |
|          if (z && z->func) | |
|             z->func(z->data, &e); | |
|          wglMakeCurrent(NULL, NULL) ;  | |
|          if (z) { | |
|             if (z->rc) wglDeleteContext(z->rc); | |
|             z->dc = 0; | |
|             z->rc = 0; | |
|          } | |
|          if (wnd == stbwingraph_primary_window) | |
|             PostQuitMessage (0); | |
|          return 0; | |
| 
 | |
|       case WM_CHAR:         stbwingraph__key(&e, STBWGE_char   , wparam, z); break; | |
|       case WM_KEYDOWN:      stbwingraph__key(&e, STBWGE_keydown, wparam, z); break; | |
|       case WM_KEYUP:        stbwingraph__key(&e, STBWGE_keyup  , wparam, z); break; | |
| 
 | |
|       case WM_NCMOUSEMOVE:  stbwingraph__inclient(z,0); break; | |
|       case WM_MOUSEMOVE:    stbwingraph__inclient(z,1); stbwingraph__mouse(&e, STBWGE_mousemove,  wparam, lparam,0,wnd, z); break; | |
|       case WM_LBUTTONDOWN:  stbwingraph__mouse(&e, STBWGE_leftdown,   wparam, lparam,1,wnd, z); break; | |
|       case WM_MBUTTONDOWN:  stbwingraph__mouse(&e, STBWGE_middledown, wparam, lparam,1,wnd, z); break; | |
|       case WM_RBUTTONDOWN:  stbwingraph__mouse(&e, STBWGE_rightdown,  wparam, lparam,1,wnd, z); break; | |
|       case WM_LBUTTONUP:    stbwingraph__mouse(&e, STBWGE_leftup,     wparam, lparam,-1,wnd, z); break; | |
|       case WM_MBUTTONUP:    stbwingraph__mouse(&e, STBWGE_middleup,   wparam, lparam,-1,wnd, z); break; | |
|       case WM_RBUTTONUP:    stbwingraph__mouse(&e, STBWGE_rightup,    wparam, lparam,-1,wnd, z); break; | |
|       case WM_MOUSEWHEEL:   stbwingraph__mousewheel(&e, STBWGE_mousewheel, wparam, lparam,0,wnd, z); break; | |
| 
 | |
|       case WM_ACTIVATE: | |
|          allow_default = FALSE; | |
|          if (LOWORD(wparam)==WA_INACTIVE ) { | |
|             wglMakeCurrent(z->dc, NULL); | |
|             e.type = STBWGE_deactivate; | |
|             z->active = FALSE; | |
|          } else { | |
|             wglMakeCurrent(z->dc, z->rc); | |
|             e.type = STBWGE_activate; | |
|             z->active = TRUE; | |
|          } | |
|          e.handle = wnd; | |
|          z->func(z->data, &e); | |
|          return 0; | |
| 
 | |
|       case WM_SIZE: { | |
|          RECT rect; | |
|          allow_default = FALSE; | |
|          GetClientRect(wnd, &rect); | |
|          e.type = STBWGE_size; | |
|          e.width = rect.right; | |
|          e.height = rect.bottom; | |
|          e.handle = wnd; | |
|          z->func(z->data, &e); | |
|          return 0; | |
|       } | |
| 
 | |
|       default: | |
|          return DefWindowProc (wnd, msg, wparam, lparam); | |
|    } | |
| 
 | |
|    if (e.type != STBWGE__none) { | |
|       int n; | |
|       e.handle = wnd; | |
|       n = z->func(z->data, &e); | |
|       if (n == STBWINGRAPH_winproc_exit) { | |
|          PostQuitMessage(0); | |
|          n = 0; | |
|       } | |
|       if (n == STBWINGRAPH_winproc_update) { | |
|          stbwingraph_force_update = TRUE; | |
|          return 1; | |
|       } | |
|       if (n != STBWINGRAPH_unprocessed) | |
|          return n; | |
|    } | |
|    return DefWindowProc (wnd, msg, wparam, lparam); | |
| } | |
| 
 | |
| int stbwingraph_DefineClass(HINSTANCE hInstance, char *iconname) | |
| { | |
|    WNDCLASSEX  wndclass; | |
| 
 | |
|    stbwingraph_app = hInstance; | |
| 
 | |
|    wndclass.cbSize        = sizeof(wndclass); | |
|    wndclass.style         = CS_OWNDC; | |
|    wndclass.lpfnWndProc   = (WNDPROC) stbwingraph_WinProc; | |
|    wndclass.cbClsExtra    = 0; | |
|    wndclass.cbWndExtra    = 0; | |
|    wndclass.hInstance     = hInstance; | |
|    wndclass.hIcon         = LoadIcon(hInstance, iconname); | |
|    wndclass.hCursor       = LoadCursor(NULL,IDC_ARROW); | |
|    wndclass.hbrBackground = GetStockObject(NULL_BRUSH); | |
|    wndclass.lpszMenuName  = "zwingraph"; | |
|    wndclass.lpszClassName = "zwingraph"; | |
|    wndclass.hIconSm       = NULL; | |
| 
 | |
|    if (!RegisterClassEx(&wndclass)) | |
|       return FALSE; | |
|    return TRUE; | |
| } | |
| 
 | |
| void stbwingraph_ShowWindow(void *window) | |
| { | |
|    stbwingraph_event e = { STBWGE_create_postshow }; | |
|    stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(window, GWL_USERDATA); | |
|    ShowWindow(window, SW_SHOWNORMAL); | |
|    InvalidateRect(window, NULL, TRUE); | |
|    UpdateWindow(window); | |
|    e.handle = window; | |
|    z->func(z->data, &e); | |
| } | |
| 
 | |
| 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) | |
| { | |
|    HWND win; | |
|    DWORD dwstyle; | |
|    stbwingraph__window *z = (stbwingraph__window *) malloc(sizeof(*z)); | |
| 
 | |
|    if (z == NULL) return NULL; | |
|    memset(z, 0, sizeof(*z)); | |
|    z->color = 24; | |
|    z->depth = 24; | |
|    z->alpha = dest_alpha; | |
|    z->stencil = stencil; | |
|    z->func = func; | |
|    z->data = data; | |
|    z->mx = -(1 << 30); | |
|    z->my = 0; | |
| 
 | |
|    if (primary) { | |
|       if (stbwingraph_request_windowed) | |
|          fullscreen = FALSE; | |
|       else if (stbwingraph_request_fullscreen) | |
|          fullscreen = TRUE; | |
|    } | |
| 
 | |
|    if (fullscreen) { | |
|       #ifdef STB_SIMPLE | |
|       stbwingraph_ChangeResolution(width, height, 32, 1); | |
|       #else | |
|       if (!stbwingraph_ChangeResolution(width, height, 32, 0)) | |
|          return NULL; | |
|       #endif | |
|       dwstyle = WS_POPUP | WS_CLIPSIBLINGS; | |
|    } else { | |
|       RECT rect; | |
|       dwstyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; | |
|       if (resizeable) | |
|          dwstyle |= WS_SIZEBOX | WS_MAXIMIZEBOX; | |
|       rect.top = 0; | |
|       rect.left = 0; | |
|       rect.right = width; | |
|       rect.bottom = height; | |
|       AdjustWindowRect(&rect, dwstyle, FALSE); | |
|       width = rect.right - rect.left; | |
|       height = rect.bottom - rect.top; | |
|    } | |
| 
 | |
|    win = CreateWindow("zwingraph", text ? text : "sample", dwstyle, | |
|                       CW_USEDEFAULT,0, width, height, | |
|                       NULL, NULL, stbwingraph_app, z); | |
| 
 | |
|    if (win == NULL) return win; | |
| 
 | |
|    if (primary) { | |
|       if (stbwingraph_primary_window) | |
|          stbwingraph_DestroyWindow(stbwingraph_primary_window); | |
|       stbwingraph_primary_window = win; | |
|    } | |
| 
 | |
|    { | |
|       stbwingraph_event e = { STBWGE_create }; | |
|       stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); | |
|       z->window = win; | |
|       e.did_share_lists = z->did_share_lists; | |
|       e.handle = win; | |
|       if (z->func(z->data, &e) != STBWINGRAPH_do_not_show) | |
|          stbwingraph_ShowWindow(win); | |
|    } | |
| 
 | |
|    return win; | |
| } | |
| 
 | |
| void *stbwingraph_CreateWindowSimple(stbwingraph_window_proc func, int width, int height) | |
| { | |
|    int fullscreen = 0; | |
|    #ifndef _DEBUG | |
|    if (width ==  640 && height ==  480) fullscreen = 1; | |
|    if (width ==  800 && height ==  600) fullscreen = 1; | |
|    if (width == 1024 && height ==  768) fullscreen = 1; | |
|    if (width == 1280 && height == 1024) fullscreen = 1; | |
|    if (width == 1600 && height == 1200) fullscreen = 1; | |
|    //@TODO: widescreen widths | |
|    #endif | |
|    return stbwingraph_CreateWindow(1, func, NULL, NULL, width, height, fullscreen, 1, 0, 0); | |
| } | |
| 
 | |
| void *stbwingraph_CreateWindowSimpleFull(stbwingraph_window_proc func, int fullscreen, int ww, int wh, int fw, int fh) | |
| { | |
|    if (fullscreen == -1) { | |
|    #ifdef _DEBUG | |
|       fullscreen = 0; | |
|    #else | |
|       fullscreen = 1; | |
|    #endif | |
|    } | |
| 
 | |
|    if (fullscreen) { | |
|       if (fw) ww = fw; | |
|       if (fh) wh = fh; | |
|    } | |
|    return stbwingraph_CreateWindow(1, func, NULL, NULL, ww, wh, fullscreen, 1, 0, 0); | |
| } | |
| 
 | |
| void stbwingraph_DestroyWindow(void *window) | |
| { | |
|    stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(window, GWL_USERDATA); | |
|    DestroyWindow(window); | |
|    free(z); | |
|    if (stbwingraph_primary_window == window) | |
|       stbwingraph_primary_window = NULL; | |
| } | |
| 
 | |
| void stbwingraph_ShowCursor(void *window, int visible) | |
| { | |
|    int hide; | |
|    stbwingraph__window *win; | |
|    if (!window) | |
|       window = stbwingraph_primary_window; | |
|    win = (stbwingraph__window *) GetWindowLong((HWND) window, GWL_USERDATA); | |
|    hide = !visible; | |
|    if (hide != win->hide_mouse) { | |
|       win->hide_mouse = hide; | |
|       if (!hide) | |
|          ShowCursor(TRUE); | |
|       else if (win->in_client) | |
|          ShowCursor(FALSE); | |
|    } | |
| } | |
| 
 | |
| float stbwingraph_GetTimestep(float minimum_time) | |
| { | |
|    float elapsedTime; | |
|    double thisTime; | |
|    static double lastTime = -1; | |
|     | |
|    if (lastTime == -1) | |
|       lastTime = timeGetTime() / 1000.0 - minimum_time; | |
| 
 | |
|    for(;;) { | |
|       thisTime = timeGetTime() / 1000.0; | |
|       elapsedTime = (float) (thisTime - lastTime); | |
|       if (elapsedTime >= minimum_time) { | |
|          lastTime = thisTime;          | |
|          return elapsedTime; | |
|       } | |
|       #if 1 | |
|       Sleep(2); | |
|       #endif | |
|    } | |
| } | |
| 
 | |
| void stbwingraph_SetGLWindow(void *win) | |
| { | |
|    stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); | |
|    if (z) | |
|       wglMakeCurrent(z->dc, z->rc); | |
| } | |
| 
 | |
| void stbwingraph_MakeFonts(void *window, int font_base) | |
| { | |
|    wglUseFontBitmaps(GetDC(window ? window : stbwingraph_primary_window), 0, 256, font_base); | |
| } | |
| 
 | |
| // returns 1 if WM_QUIT, 0 if 'func' returned 0 | |
| int stbwingraph_MainLoop(stbwingraph_update func, float mintime) | |
| { | |
|    int needs_drawing = FALSE; | |
|    MSG msg; | |
| 
 | |
|    int is_animating = TRUE; | |
|    if (mintime <= 0) mintime = 0.01f; | |
| 
 | |
|    for(;;) { | |
|       int n; | |
| 
 | |
|       is_animating = TRUE; | |
|       // wait for a message if: (a) we're animating and there's already a message | |
|       // or (b) we're not animating | |
|       if (!is_animating || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { | |
|          stbwingraph_force_update = FALSE; | |
|          if (GetMessage(&msg, NULL, 0, 0)) { | |
|             TranslateMessage(&msg); | |
|             DispatchMessage(&msg); | |
|          } else { | |
|             return 1;   // WM_QUIT | |
|          } | |
| 
 | |
|          // only force a draw for certain messages... | |
|          // if I don't do this, we peg at 50% for some reason... must | |
|          // be a bug somewhere, because we peg at 100% when rendering... | |
|          // very weird... looks like NVIDIA is pumping some messages | |
|          // through our pipeline? well, ok, I guess if we can get | |
|          // non-user-generated messages we have to do this | |
|          if (!stbwingraph_force_update) { | |
|             switch (msg.message) { | |
|                case WM_MOUSEMOVE: | |
|                case WM_NCMOUSEMOVE: | |
|                   break; | |
|                case WM_CHAR:          | |
|                case WM_KEYDOWN:       | |
|                case WM_KEYUP:         | |
|                case WM_LBUTTONDOWN:   | |
|                case WM_MBUTTONDOWN:   | |
|                case WM_RBUTTONDOWN:   | |
|                case WM_LBUTTONUP:     | |
|                case WM_MBUTTONUP:     | |
|                case WM_RBUTTONUP:     | |
|                case WM_TIMER: | |
|                case WM_SIZE: | |
|                case WM_ACTIVATE: | |
|                   needs_drawing = TRUE; | |
|                   break; | |
|             } | |
|          } else | |
|             needs_drawing = TRUE; | |
|       } | |
| 
 | |
|       // if another message, process that first | |
|       // @TODO: i don't think this is working, because I can't key ahead | |
|       // in the SVT demo app | |
|       if (PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE)) | |
|          continue; | |
| 
 | |
|       // and now call update | |
|       if (needs_drawing || is_animating) { | |
|          int real=1, in_client=1; | |
|          if (stbwingraph_primary_window) { | |
|             stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(stbwingraph_primary_window, GWL_USERDATA); | |
|             if (z && !z->active) { | |
|                real = 0; | |
|             } | |
|             if (z) | |
|                in_client = z->in_client; | |
|          } | |
| 
 | |
|          if (stbwingraph_primary_window) | |
|             stbwingraph_SetGLWindow(stbwingraph_primary_window); | |
|          n = func(stbwingraph_GetTimestep(mintime), real, in_client); | |
|          if (n == STBWINGRAPH_update_exit) | |
|             return 0; // update_quit | |
|  | |
|          is_animating = (n != STBWINGRAPH_update_pause); | |
| 
 | |
|          needs_drawing = FALSE; | |
|       } | |
|    } | |
| } | |
| 
 | |
| void stbwingraph_SwapBuffers(void *win) | |
| { | |
|    stbwingraph__window *z; | |
|    if (win == NULL) win = stbwingraph_primary_window; | |
|    z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); | |
|    if (z && z->dc) | |
|       SwapBuffers(z->dc); | |
| } | |
| #endif | |
|  | |
| #ifdef STB_WINMAIN     | |
| void stbwingraph_main(void); | |
| 
 | |
| char *stb_wingraph_commandline; | |
| 
 | |
| int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) | |
| { | |
|    { | |
|       char buffer[1024]; | |
|       // add spaces to either side of the string | |
|       buffer[0] = ' '; | |
|       strcpy(buffer+1, lpCmdLine); | |
|       strcat(buffer, " "); | |
|       if (strstr(buffer, " -reset ")) { | |
|          ChangeDisplaySettings(NULL, 0);  | |
|          exit(0); | |
|       } | |
|       if (strstr(buffer, " -window ") || strstr(buffer, " -windowed ")) | |
|          stbwingraph_request_windowed = TRUE; | |
|       else if (strstr(buffer, " -full ") || strstr(buffer, " -fullscreen ")) | |
|          stbwingraph_request_fullscreen = TRUE; | |
|    } | |
|    stb_wingraph_commandline = lpCmdLine; | |
| 
 | |
|    stbwingraph_DefineClass(hInstance, "appicon"); | |
|    stbwingraph_main(); | |
| 
 | |
|    return 0; | |
| } | |
| #endif | |
|  | |
| #undef STB_EXTERN | |
| #ifdef STB_WINGRAPH_DISABLE_DEFINE_AT_END | |
| #undef STB_DEFINE | |
| #endif | |
|  | |
| #endif // INCLUDE_STB_WINGRAPH_H
 | |
| 
 |