|
@@ -0,0 +1,824 @@
|
|
|
|
+// 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")
|
|
|
|
+#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);
|
|
|
|
+
|
|
|
|
+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;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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
|