sgl
diff src/wsys_w32.c @ 25:0eb6abc43ac6
added wsys_w32.c
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 27 Jun 2011 12:05:51 +0300 |
parents | |
children | e4c79d2c7f78 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/wsys_w32.c Mon Jun 27 12:05:51 2011 +0300 1.3 @@ -0,0 +1,428 @@ 1.4 +/* SimplyGL window system module for Win32/WGL */ 1.5 +/* link-with: -lopengl32 */ 1.6 + 1.7 +#include "config.h" 1.8 + 1.9 +#ifdef USE_WSYS_MODULE_W32 1.10 + 1.11 +#include <stdlib.h> 1.12 +#include <assert.h> 1.13 +#include <windows.h> 1.14 + 1.15 +struct window { 1.16 + int id; 1.17 + HWND win; 1.18 + HDC dc; 1.19 + HGLRC ctx; 1.20 + int width, height; 1.21 + int redisp_pending; 1.22 + 1.23 + struct window *next; 1.24 +}; 1.25 + 1.26 +static int init(void); 1.27 +static void shutdown(void); 1.28 + 1.29 +/* video mode switching */ 1.30 +static int set_vidmode(int xsz, int ysz); 1.31 +static int get_vidmode(int *xsz, int *ysz); 1.32 + 1.33 +/* create/destroy windows */ 1.34 +static int create_window(int xsz, int ysz, unsigned int flags); 1.35 +static void close_window(int id); 1.36 + 1.37 +/* window management */ 1.38 +static int set_active(int id); 1.39 +static struct window *find_window(int id); 1.40 +static int activate_window(struct window *win); 1.41 +static int set_title(const char *str); 1.42 +static void redisplay(void); 1.43 +static void swap_buffers(void); 1.44 + 1.45 +static int get_modifiers(void); 1.46 + 1.47 +/* event handling and friends */ 1.48 +static void set_bits(long *mask, long bits); 1.49 +static void clear_bits(long *mask, long bits); 1.50 +static void set_event(int idx, int enable); 1.51 +static int process_events(void); 1.52 + 1.53 +static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); 1.54 +static int mouse_button(unsigned int msg); 1.55 + 1.56 + 1.57 +static struct wsys_module ws = { 1.58 + "win32", 0, 1.59 + init, 1.60 + shutdown, 1.61 + set_vidmode, 1.62 + get_vidmode, 1.63 + create_window, 1.64 + close_window, 1.65 + set_active, 1.66 + set_title, 1.67 + redisplay, 1.68 + swap_buffers, 1.69 + get_modifiers, 1.70 + set_event, 1.71 + process_events, 1.72 + 0 1.73 +}; 1.74 + 1.75 +static struct window *winlist; 1.76 +static struct window *active_win, *prev_active; 1.77 +static int next_id = 1; 1.78 + 1.79 +/* this is the only exported function, everything else should be static */ 1.80 +void sgl_register_w32(void) 1.81 +{ 1.82 + sgl_register_module(&ws); 1.83 +} 1.84 + 1.85 + 1.86 +static int init(void) 1.87 +{ 1.88 + winlist = 0; 1.89 + active_win = prev_active = 0; 1.90 + return 0; 1.91 +} 1.92 + 1.93 +static void shutdown(void) 1.94 +{ 1.95 + /* TODO */ 1.96 +} 1.97 + 1.98 +static int set_vidmode(int xsz, int ysz) 1.99 +{ 1.100 + DEVMODE dmode; 1.101 + memset(&dmode, 0, sizeof dmode); 1.102 + dmode.dmSize = sizeof dmode; 1.103 + /*dmode.dmBitsPerPel = 32;*/ 1.104 + dmode.dmPelsWidth = xsz; 1.105 + dmode.dmPelsHeight = ysz; 1.106 + dmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; 1.107 + 1.108 + if(ChangeDisplaySettings(&dmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { 1.109 + sgl_log("failed to set video mode: %dx%d\n", xsz, ysz); 1.110 + return -1; 1.111 + } 1.112 + return 0; 1.113 +} 1.114 + 1.115 +static int get_vidmode(int *xsz, int *ysz) 1.116 +{ 1.117 + /* TODO */ 1.118 + return 0; 1.119 +} 1.120 + 1.121 +static int create_window(int xsz, int ysz, unsigned int flags) 1.122 +{ 1.123 + WNDCLASS wclass; 1.124 + int win_width, win_height, win_x, win_y; 1.125 + unsigned int style; 1.126 + HINSTANCE pid; 1.127 + HWND win; 1.128 + PIXELFORMATDESCRIPTOR fmt; 1.129 + int pf_id; 1.130 + struct window *wnode; 1.131 + void (*func)(); 1.132 + 1.133 + if(!(wnode = malloc(sizeof *wnode))) { 1.134 + return -1; 1.135 + } 1.136 + 1.137 + pid = GetModuleHandle(0); 1.138 + 1.139 + memset(&wclass, 0, sizeof wclass); 1.140 + wclass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC; 1.141 + wclass.lpfnWndProc = handle_events; 1.142 + wclass.hInstance = pid; 1.143 + wclass.lpszClassName = "simplygl"; 1.144 + 1.145 + if(!RegisterClass(&wclass)) { 1.146 + sgl_log("failed to register window class\n"); 1.147 + return -1; 1.148 + } 1.149 + 1.150 + calc_win_size(xsz, ysz, &win_width, &win_height, &win_x, &win_y); 1.151 + 1.152 + style = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_POPUP | WS_SYSMENU | WS_VISIBLE; 1.153 + 1.154 + if(!(win = CreateWindow("simplygl", "OpenGL/Win32", style, win_x, win_y, win_width, win_height, 0, 0, pid, 0))) { 1.155 + sgl_log("failed to create window\n"); 1.156 + return -1; 1.157 + } 1.158 + 1.159 + ShowWindow(win, SW_SHOW); 1.160 + SetForegroundWindow(win); 1.161 + SetActiveWindow(win); 1.162 + 1.163 + wnode->win = win; 1.164 + wnode->dc = GetDC(win); 1.165 + 1.166 + memset(&fmt, 0, sizeof fmt); 1.167 + fmt.nSize = sizeof fmt; 1.168 + fmt.nVersion = 1; 1.169 + fmt.cColorBits = PFD_TYPE_RGBA; 1.170 + fmt.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; 1.171 + 1.172 + if(flags & SGL_DOUBLE) { 1.173 + fmt.dwFlags |= PFD_DOUBLEBUFFER; 1.174 + } 1.175 + if(flags & SGL_DEPTH) { 1.176 + fmt.cDepthBits = 24; 1.177 + } 1.178 + if(flags & SGL_STENCIL) { 1.179 + fmt.cStencilBits = 8; 1.180 + } 1.181 + /* TODO: more... */ 1.182 + 1.183 + if(!(pf_id = ChoosePixelFormat(wnode->dc, &fmt))) { 1.184 + sgl_log("can't find requested pixel format\n"); 1.185 + return -1; 1.186 + } 1.187 + if(!SetPixelFormat(wnode->dc, pf_id, &fmt)) { 1.188 + sgl_log("failed to set pixel format\n"); 1.189 + return -1; 1.190 + } 1.191 + if(!(wnode->ctx = wglCreateContext(wnode->dc))) { 1.192 + sgl_log("failed to create OpenGL context\n"); 1.193 + return -1; 1.194 + } 1.195 + 1.196 + wnode->id = next_id++; 1.197 + wnode->width = xsz; 1.198 + wnode->height = ysz; 1.199 + wnode->redisp_pending = 1; 1.200 + wnode->next = winlist; 1.201 + winlist = wnode; 1.202 + 1.203 + if(!active_win) { 1.204 + set_active(wnode->id); 1.205 + } else { 1.206 + activate_window(wnode); 1.207 + } 1.208 + 1.209 + if((func = sgl_get_callback(SGL_CREATE))) { 1.210 + func(wnode->id); 1.211 + } 1.212 + if((func = sgl_get_callback(SGL_RESHAPE))) { 1.213 + func(xsz, ysz); 1.214 + } 1.215 + activate_window(prev_active); 1.216 + return wnode->id; 1.217 +} 1.218 + 1.219 +static void close_window(int id) 1.220 +{ 1.221 + struct window dummy, *win, *prev; 1.222 + sgl_close_callback_t close_func; 1.223 + 1.224 + dummy.next = winlist; 1.225 + 1.226 + prev = &dummy; 1.227 + win = prev->next; 1.228 + 1.229 + while(win) { 1.230 + if(win->id == id) { 1.231 + if((close_func = sgl_get_callback(SGL_CLOSE))) { 1.232 + close_func(id); 1.233 + } 1.234 + wglDeleteContext(win->ctx); 1.235 + ReleaseDC(win->win, win->dc); 1.236 + DestroyWindow(win->win); 1.237 + 1.238 + prev->next = win->next; 1.239 + free(win); 1.240 + return; 1.241 + } 1.242 + prev = win; 1.243 + win = win->next; 1.244 + } 1.245 +} 1.246 + 1.247 +static int set_active(int id) 1.248 +{ 1.249 + struct window *win = find_window(id); 1.250 + if(!win) { 1.251 + sgl_log("no such window: %d\n", id); 1.252 + return -1; 1.253 + } 1.254 + /* only the user calls this, so don't revert this selection */ 1.255 + prev_active = win; 1.256 + return activate_window(win); 1.257 +} 1.258 + 1.259 +static struct window *find_window(int id) 1.260 +{ 1.261 + struct window *win = winlist; 1.262 + 1.263 + while(win) { 1.264 + if(win->win == id) { 1.265 + return win; 1.266 + } 1.267 + win = win->next; 1.268 + } 1.269 + return 0; 1.270 +} 1.271 + 1.272 +static int activate_window(struct window *win) 1.273 +{ 1.274 + if(!wglMakeCurrent(win->dc, win->ctx)) { 1.275 + sgl_log("failed to activate window %d\n", (int)win->id); 1.276 + return -1; 1.277 + } 1.278 + active_win = win; 1.279 + return 0; 1.280 +} 1.281 + 1.282 +static int set_title(const char *str) 1.283 +{ 1.284 + SetWindowText(active_win->win, str); 1.285 +} 1.286 + 1.287 +static void redisplay(void) 1.288 +{ 1.289 + InvalidateRect(active_win->win, 0, 0); 1.290 +} 1.291 + 1.292 +static void swap_buffers(void) 1.293 +{ 1.294 + SwapBuffers(active_win->dc); 1.295 +} 1.296 + 1.297 +static int get_modifiers(void) 1.298 +{ 1.299 + return 0; /* TODO */ 1.300 +} 1.301 + 1.302 +static void set_event(int idx, int enable) 1.303 +{ 1.304 + /* not needed */ 1.305 +} 1.306 + 1.307 +static int process_events(void) 1.308 +{ 1.309 + int ret; 1.310 + MSG msg; 1.311 + sgl_idle_callback_t idle; 1.312 + sgl_display_callback_t disp; 1.313 + 1.314 + idle = sgl_get_callback(SGL_IDLE); 1.315 + 1.316 + prev_active = active_win; 1.317 + 1.318 + if(!idle) { 1.319 + if(!GetMessage(&msg, 0, 0, 0)) { 1.320 + ret = -1; 1.321 + goto end; 1.322 + } 1.323 + } else { 1.324 + if(!PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { 1.325 + ret = 0; 1.326 + goto end; 1.327 + } 1.328 + } 1.329 + 1.330 + do { 1.331 + if(msg.message == WM_QUIT) { 1.332 + ret = -1; 1.333 + break; 1.334 + } 1.335 + TranslateMessage(&msg); 1.336 + DispatchMessage(&msg); 1.337 + } while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)); 1.338 + 1.339 +end: 1.340 + if(ret != -1 && idle) { 1.341 + idle(); 1.342 + } 1.343 + activate_window(prev_active); 1.344 + return ret; 1.345 +} 1.346 + 1.347 +static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 1.348 +{ 1.349 + static int state; 1.350 + struct window *win; 1.351 + void (*func)(); 1.352 + 1.353 + if((win = find_window_handle(hwnd))) { 1.354 + activate_window(win); 1.355 + } else { 1.356 + return DefWindowProc(hwnd, msg, wparam, lparam); 1.357 + } 1.358 + 1.359 + switch(msg) { 1.360 + case WM_PAINT: 1.361 + if((func = sgl_get_callback(SGL_DISPLAY))) { 1.362 + func(); 1.363 + } 1.364 + ValidateRect(hwnd, 0); 1.365 + break; 1.366 + 1.367 + case WM_KEYDOWN: 1.368 + case WM_KEYUP: 1.369 + if((func = sgl_get_callback(SGL_KEYBOARD))) { 1.370 + func(MapVirtualKey(wparam, 2), msg == WM_KEYDOWN); 1.371 + } 1.372 + break; 1.373 + 1.374 + case WM_LBUTTONDOWN: 1.375 + case WM_RBUTTONDOWN: 1.376 + case WM_MBUTTONDOWN: 1.377 + if(1) { 1.378 + state++; 1.379 + } else { 1.380 + case WM_LBUTTONUP: 1.381 + case WM_RBUTTONUP: 1.382 + case WM_MBUTTONUP: 1.383 + state--; 1.384 + } 1.385 + assert(state >= 0); 1.386 + if((func = sgl_get_callback(SGL_MOUSE))) { 1.387 + func(mouse_button(msg), state, LOWORD(lparam), HIWORD(lparam)); 1.388 + } 1.389 + break; 1.390 + 1.391 + case WM_MOUSEMOVE: 1.392 + if(state) { 1.393 + func = sgl_get_callback(SGL_MOTION); 1.394 + } else { 1.395 + func = sgl_get_callback(SGL_PASSIVE); 1.396 + } 1.397 + if(func) { 1.398 + func(LOWORD(lparam), HIWORD(lparam)); 1.399 + } 1.400 + break; 1.401 + 1.402 + default: 1.403 + return DefWindowProc(hwnd, msg, wparam, lparam); 1.404 + } 1.405 + return 0; 1.406 +} 1.407 + 1.408 +static int mouse_button(unsigned int msg) 1.409 +{ 1.410 + switch(msg) { 1.411 + case WM_LBUTTONDOWN: 1.412 + case WM_LBUTTONUP: 1.413 + return SGL_LEFT_BUTTON; 1.414 + 1.415 + case WM_RBUTTONDOWN: 1.416 + case WM_RBUTTONUP: 1.417 + return SGL_RIGHT_BUTTON; 1.418 + 1.419 + case WM_MBUTTONDOWN: 1.420 + case WM_MBUTTONUP: 1.421 + return SGL_MIDDLE_BUTTON; 1.422 + 1.423 + default: 1.424 + break; 1.425 + } 1.426 + return -1; 1.427 +} 1.428 + 1.429 +#else 1.430 +int sgl_wsys_w32_silence_the_fucking_empty_file_warnings; 1.431 +#endif