// 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 #endif #include #include #include #include #include #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