# HG changeset patch # User John Tsiombikas # Date 1309165551 -10800 # Node ID 0eb6abc43ac616475fef78f5b847a5e240dfed66 # Parent 23a01d912cf85e61a19ec07ad54f4d1016def641 added wsys_w32.c diff -r 23a01d912cf8 -r 0eb6abc43ac6 src/wsys_w32.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wsys_w32.c Mon Jun 27 12:05:51 2011 +0300 @@ -0,0 +1,428 @@ +/* SimplyGL window system module for Win32/WGL */ +/* link-with: -lopengl32 */ + +#include "config.h" + +#ifdef USE_WSYS_MODULE_W32 + +#include +#include +#include + +struct window { + int id; + HWND win; + HDC dc; + HGLRC ctx; + int width, height; + int redisp_pending; + + struct window *next; +}; + +static int init(void); +static void shutdown(void); + +/* video mode switching */ +static int set_vidmode(int xsz, int ysz); +static int get_vidmode(int *xsz, int *ysz); + +/* create/destroy windows */ +static int create_window(int xsz, int ysz, unsigned int flags); +static void close_window(int id); + +/* window management */ +static int set_active(int id); +static struct window *find_window(int id); +static int activate_window(struct window *win); +static int set_title(const char *str); +static void redisplay(void); +static void swap_buffers(void); + +static int get_modifiers(void); + +/* event handling and friends */ +static void set_bits(long *mask, long bits); +static void clear_bits(long *mask, long bits); +static void set_event(int idx, int enable); +static int process_events(void); + +static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); +static int mouse_button(unsigned int msg); + + +static struct wsys_module ws = { + "win32", 0, + init, + shutdown, + set_vidmode, + get_vidmode, + create_window, + close_window, + set_active, + set_title, + redisplay, + swap_buffers, + get_modifiers, + set_event, + process_events, + 0 +}; + +static struct window *winlist; +static struct window *active_win, *prev_active; +static int next_id = 1; + +/* this is the only exported function, everything else should be static */ +void sgl_register_w32(void) +{ + sgl_register_module(&ws); +} + + +static int init(void) +{ + winlist = 0; + active_win = prev_active = 0; + return 0; +} + +static void shutdown(void) +{ + /* TODO */ +} + +static int set_vidmode(int xsz, int ysz) +{ + DEVMODE dmode; + memset(&dmode, 0, sizeof dmode); + dmode.dmSize = sizeof dmode; + /*dmode.dmBitsPerPel = 32;*/ + dmode.dmPelsWidth = xsz; + dmode.dmPelsHeight = ysz; + dmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; + + if(ChangeDisplaySettings(&dmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { + sgl_log("failed to set video mode: %dx%d\n", xsz, ysz); + return -1; + } + return 0; +} + +static int get_vidmode(int *xsz, int *ysz) +{ + /* TODO */ + return 0; +} + +static int create_window(int xsz, int ysz, unsigned int flags) +{ + WNDCLASS wclass; + int win_width, win_height, win_x, win_y; + unsigned int style; + HINSTANCE pid; + HWND win; + PIXELFORMATDESCRIPTOR fmt; + int pf_id; + struct window *wnode; + void (*func)(); + + if(!(wnode = malloc(sizeof *wnode))) { + return -1; + } + + pid = GetModuleHandle(0); + + memset(&wclass, 0, sizeof wclass); + wclass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC; + wclass.lpfnWndProc = handle_events; + wclass.hInstance = pid; + wclass.lpszClassName = "simplygl"; + + if(!RegisterClass(&wclass)) { + sgl_log("failed to register window class\n"); + return -1; + } + + calc_win_size(xsz, ysz, &win_width, &win_height, &win_x, &win_y); + + style = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_POPUP | WS_SYSMENU | WS_VISIBLE; + + if(!(win = CreateWindow("simplygl", "OpenGL/Win32", style, win_x, win_y, win_width, win_height, 0, 0, pid, 0))) { + sgl_log("failed to create window\n"); + return -1; + } + + ShowWindow(win, SW_SHOW); + SetForegroundWindow(win); + SetActiveWindow(win); + + wnode->win = win; + wnode->dc = GetDC(win); + + memset(&fmt, 0, sizeof fmt); + fmt.nSize = sizeof fmt; + fmt.nVersion = 1; + fmt.cColorBits = PFD_TYPE_RGBA; + fmt.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; + + if(flags & SGL_DOUBLE) { + fmt.dwFlags |= PFD_DOUBLEBUFFER; + } + if(flags & SGL_DEPTH) { + fmt.cDepthBits = 24; + } + if(flags & SGL_STENCIL) { + fmt.cStencilBits = 8; + } + /* TODO: more... */ + + if(!(pf_id = ChoosePixelFormat(wnode->dc, &fmt))) { + sgl_log("can't find requested pixel format\n"); + return -1; + } + if(!SetPixelFormat(wnode->dc, pf_id, &fmt)) { + sgl_log("failed to set pixel format\n"); + return -1; + } + if(!(wnode->ctx = wglCreateContext(wnode->dc))) { + sgl_log("failed to create OpenGL context\n"); + return -1; + } + + wnode->id = next_id++; + wnode->width = xsz; + wnode->height = ysz; + wnode->redisp_pending = 1; + wnode->next = winlist; + winlist = wnode; + + if(!active_win) { + set_active(wnode->id); + } else { + activate_window(wnode); + } + + if((func = sgl_get_callback(SGL_CREATE))) { + func(wnode->id); + } + if((func = sgl_get_callback(SGL_RESHAPE))) { + func(xsz, ysz); + } + activate_window(prev_active); + return wnode->id; +} + +static void close_window(int id) +{ + struct window dummy, *win, *prev; + sgl_close_callback_t close_func; + + dummy.next = winlist; + + prev = &dummy; + win = prev->next; + + while(win) { + if(win->id == id) { + if((close_func = sgl_get_callback(SGL_CLOSE))) { + close_func(id); + } + wglDeleteContext(win->ctx); + ReleaseDC(win->win, win->dc); + DestroyWindow(win->win); + + prev->next = win->next; + free(win); + return; + } + prev = win; + win = win->next; + } +} + +static int set_active(int id) +{ + struct window *win = find_window(id); + if(!win) { + sgl_log("no such window: %d\n", id); + return -1; + } + /* only the user calls this, so don't revert this selection */ + prev_active = win; + return activate_window(win); +} + +static struct window *find_window(int id) +{ + struct window *win = winlist; + + while(win) { + if(win->win == id) { + return win; + } + win = win->next; + } + return 0; +} + +static int activate_window(struct window *win) +{ + if(!wglMakeCurrent(win->dc, win->ctx)) { + sgl_log("failed to activate window %d\n", (int)win->id); + return -1; + } + active_win = win; + return 0; +} + +static int set_title(const char *str) +{ + SetWindowText(active_win->win, str); +} + +static void redisplay(void) +{ + InvalidateRect(active_win->win, 0, 0); +} + +static void swap_buffers(void) +{ + SwapBuffers(active_win->dc); +} + +static int get_modifiers(void) +{ + return 0; /* TODO */ +} + +static void set_event(int idx, int enable) +{ + /* not needed */ +} + +static int process_events(void) +{ + int ret; + MSG msg; + sgl_idle_callback_t idle; + sgl_display_callback_t disp; + + idle = sgl_get_callback(SGL_IDLE); + + prev_active = active_win; + + if(!idle) { + if(!GetMessage(&msg, 0, 0, 0)) { + ret = -1; + goto end; + } + } else { + if(!PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { + ret = 0; + goto end; + } + } + + do { + if(msg.message == WM_QUIT) { + ret = -1; + break; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)); + +end: + if(ret != -1 && idle) { + idle(); + } + activate_window(prev_active); + return ret; +} + +static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + static int state; + struct window *win; + void (*func)(); + + if((win = find_window_handle(hwnd))) { + activate_window(win); + } else { + return DefWindowProc(hwnd, msg, wparam, lparam); + } + + switch(msg) { + case WM_PAINT: + if((func = sgl_get_callback(SGL_DISPLAY))) { + func(); + } + ValidateRect(hwnd, 0); + break; + + case WM_KEYDOWN: + case WM_KEYUP: + if((func = sgl_get_callback(SGL_KEYBOARD))) { + func(MapVirtualKey(wparam, 2), msg == WM_KEYDOWN); + } + break; + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + if(1) { + state++; + } else { + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + state--; + } + assert(state >= 0); + if((func = sgl_get_callback(SGL_MOUSE))) { + func(mouse_button(msg), state, LOWORD(lparam), HIWORD(lparam)); + } + break; + + case WM_MOUSEMOVE: + if(state) { + func = sgl_get_callback(SGL_MOTION); + } else { + func = sgl_get_callback(SGL_PASSIVE); + } + if(func) { + func(LOWORD(lparam), HIWORD(lparam)); + } + break; + + default: + return DefWindowProc(hwnd, msg, wparam, lparam); + } + return 0; +} + +static int mouse_button(unsigned int msg) +{ + switch(msg) { + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + return SGL_LEFT_BUTTON; + + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + return SGL_RIGHT_BUTTON; + + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + return SGL_MIDDLE_BUTTON; + + default: + break; + } + return -1; +} + +#else +int sgl_wsys_w32_silence_the_fucking_empty_file_warnings; +#endif