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