sgl

annotate src/wsys_w32.c @ 26:e4c79d2c7f78

finishing win32 module
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 27 Jun 2011 12:19:14 +0300
parents 0eb6abc43ac6
children 25de96fb1526
rev   line source
nuclear@25 1 /* SimplyGL window system module for Win32/WGL */
nuclear@25 2 /* link-with: -lopengl32 */
nuclear@25 3
nuclear@25 4 #include "config.h"
nuclear@25 5
nuclear@25 6 #ifdef USE_WSYS_MODULE_W32
nuclear@25 7
nuclear@25 8 #include <stdlib.h>
nuclear@25 9 #include <assert.h>
nuclear@25 10 #include <windows.h>
nuclear@25 11
nuclear@25 12 struct window {
nuclear@25 13 int id;
nuclear@25 14 HWND win;
nuclear@25 15 HDC dc;
nuclear@25 16 HGLRC ctx;
nuclear@25 17 int width, height;
nuclear@25 18 int redisp_pending;
nuclear@25 19
nuclear@25 20 struct window *next;
nuclear@25 21 };
nuclear@25 22
nuclear@25 23 static int init(void);
nuclear@25 24 static void shutdown(void);
nuclear@25 25
nuclear@25 26 /* video mode switching */
nuclear@25 27 static int set_vidmode(int xsz, int ysz);
nuclear@25 28 static int get_vidmode(int *xsz, int *ysz);
nuclear@25 29
nuclear@25 30 /* create/destroy windows */
nuclear@25 31 static int create_window(int xsz, int ysz, unsigned int flags);
nuclear@25 32 static void close_window(int id);
nuclear@25 33
nuclear@25 34 /* window management */
nuclear@25 35 static int set_active(int id);
nuclear@25 36 static struct window *find_window(int id);
nuclear@26 37 static struct window *find_window_handle(HWND wh);
nuclear@25 38 static int activate_window(struct window *win);
nuclear@25 39 static int set_title(const char *str);
nuclear@25 40 static void redisplay(void);
nuclear@25 41 static void swap_buffers(void);
nuclear@25 42
nuclear@25 43 static int get_modifiers(void);
nuclear@25 44
nuclear@25 45 /* event handling and friends */
nuclear@25 46 static void set_bits(long *mask, long bits);
nuclear@25 47 static void clear_bits(long *mask, long bits);
nuclear@25 48 static void set_event(int idx, int enable);
nuclear@25 49 static int process_events(void);
nuclear@25 50
nuclear@25 51 static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
nuclear@25 52 static int mouse_button(unsigned int msg);
nuclear@26 53 static void calc_win_size(int w, int h, int *width, int *height, int *posx, int *posy);
nuclear@25 54
nuclear@25 55
nuclear@25 56 static struct wsys_module ws = {
nuclear@25 57 "win32", 0,
nuclear@25 58 init,
nuclear@25 59 shutdown,
nuclear@25 60 set_vidmode,
nuclear@25 61 get_vidmode,
nuclear@25 62 create_window,
nuclear@25 63 close_window,
nuclear@25 64 set_active,
nuclear@25 65 set_title,
nuclear@25 66 redisplay,
nuclear@25 67 swap_buffers,
nuclear@25 68 get_modifiers,
nuclear@25 69 set_event,
nuclear@25 70 process_events,
nuclear@25 71 0
nuclear@25 72 };
nuclear@25 73
nuclear@25 74 static struct window *winlist;
nuclear@25 75 static struct window *active_win, *prev_active;
nuclear@25 76 static int next_id = 1;
nuclear@25 77
nuclear@25 78 /* this is the only exported function, everything else should be static */
nuclear@25 79 void sgl_register_w32(void)
nuclear@25 80 {
nuclear@25 81 sgl_register_module(&ws);
nuclear@25 82 }
nuclear@25 83
nuclear@25 84
nuclear@25 85 static int init(void)
nuclear@25 86 {
nuclear@25 87 winlist = 0;
nuclear@25 88 active_win = prev_active = 0;
nuclear@25 89 return 0;
nuclear@25 90 }
nuclear@25 91
nuclear@25 92 static void shutdown(void)
nuclear@25 93 {
nuclear@25 94 /* TODO */
nuclear@25 95 }
nuclear@25 96
nuclear@25 97 static int set_vidmode(int xsz, int ysz)
nuclear@25 98 {
nuclear@25 99 DEVMODE dmode;
nuclear@25 100 memset(&dmode, 0, sizeof dmode);
nuclear@25 101 dmode.dmSize = sizeof dmode;
nuclear@25 102 /*dmode.dmBitsPerPel = 32;*/
nuclear@25 103 dmode.dmPelsWidth = xsz;
nuclear@25 104 dmode.dmPelsHeight = ysz;
nuclear@25 105 dmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
nuclear@25 106
nuclear@25 107 if(ChangeDisplaySettings(&dmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
nuclear@25 108 sgl_log("failed to set video mode: %dx%d\n", xsz, ysz);
nuclear@25 109 return -1;
nuclear@25 110 }
nuclear@25 111 return 0;
nuclear@25 112 }
nuclear@25 113
nuclear@25 114 static int get_vidmode(int *xsz, int *ysz)
nuclear@25 115 {
nuclear@25 116 /* TODO */
nuclear@25 117 return 0;
nuclear@25 118 }
nuclear@25 119
nuclear@25 120 static int create_window(int xsz, int ysz, unsigned int flags)
nuclear@25 121 {
nuclear@25 122 WNDCLASS wclass;
nuclear@25 123 int win_width, win_height, win_x, win_y;
nuclear@25 124 unsigned int style;
nuclear@25 125 HINSTANCE pid;
nuclear@25 126 HWND win;
nuclear@25 127 PIXELFORMATDESCRIPTOR fmt;
nuclear@25 128 int pf_id;
nuclear@25 129 struct window *wnode;
nuclear@25 130 void (*func)();
nuclear@25 131
nuclear@25 132 if(!(wnode = malloc(sizeof *wnode))) {
nuclear@25 133 return -1;
nuclear@25 134 }
nuclear@25 135
nuclear@25 136 pid = GetModuleHandle(0);
nuclear@25 137
nuclear@25 138 memset(&wclass, 0, sizeof wclass);
nuclear@25 139 wclass.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
nuclear@25 140 wclass.lpfnWndProc = handle_events;
nuclear@25 141 wclass.hInstance = pid;
nuclear@25 142 wclass.lpszClassName = "simplygl";
nuclear@25 143
nuclear@25 144 if(!RegisterClass(&wclass)) {
nuclear@25 145 sgl_log("failed to register window class\n");
nuclear@25 146 return -1;
nuclear@25 147 }
nuclear@25 148
nuclear@25 149 calc_win_size(xsz, ysz, &win_width, &win_height, &win_x, &win_y);
nuclear@25 150
nuclear@25 151 style = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_POPUP | WS_SYSMENU | WS_VISIBLE;
nuclear@25 152
nuclear@25 153 if(!(win = CreateWindow("simplygl", "OpenGL/Win32", style, win_x, win_y, win_width, win_height, 0, 0, pid, 0))) {
nuclear@25 154 sgl_log("failed to create window\n");
nuclear@25 155 return -1;
nuclear@25 156 }
nuclear@25 157
nuclear@25 158 ShowWindow(win, SW_SHOW);
nuclear@25 159 SetForegroundWindow(win);
nuclear@25 160 SetActiveWindow(win);
nuclear@25 161
nuclear@25 162 wnode->win = win;
nuclear@25 163 wnode->dc = GetDC(win);
nuclear@25 164
nuclear@25 165 memset(&fmt, 0, sizeof fmt);
nuclear@25 166 fmt.nSize = sizeof fmt;
nuclear@25 167 fmt.nVersion = 1;
nuclear@25 168 fmt.cColorBits = PFD_TYPE_RGBA;
nuclear@25 169 fmt.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
nuclear@25 170
nuclear@25 171 if(flags & SGL_DOUBLE) {
nuclear@25 172 fmt.dwFlags |= PFD_DOUBLEBUFFER;
nuclear@25 173 }
nuclear@25 174 if(flags & SGL_DEPTH) {
nuclear@25 175 fmt.cDepthBits = 24;
nuclear@25 176 }
nuclear@25 177 if(flags & SGL_STENCIL) {
nuclear@25 178 fmt.cStencilBits = 8;
nuclear@25 179 }
nuclear@25 180 /* TODO: more... */
nuclear@25 181
nuclear@25 182 if(!(pf_id = ChoosePixelFormat(wnode->dc, &fmt))) {
nuclear@25 183 sgl_log("can't find requested pixel format\n");
nuclear@25 184 return -1;
nuclear@25 185 }
nuclear@25 186 if(!SetPixelFormat(wnode->dc, pf_id, &fmt)) {
nuclear@25 187 sgl_log("failed to set pixel format\n");
nuclear@25 188 return -1;
nuclear@25 189 }
nuclear@25 190 if(!(wnode->ctx = wglCreateContext(wnode->dc))) {
nuclear@25 191 sgl_log("failed to create OpenGL context\n");
nuclear@25 192 return -1;
nuclear@25 193 }
nuclear@25 194
nuclear@25 195 wnode->id = next_id++;
nuclear@25 196 wnode->width = xsz;
nuclear@25 197 wnode->height = ysz;
nuclear@25 198 wnode->redisp_pending = 1;
nuclear@25 199 wnode->next = winlist;
nuclear@25 200 winlist = wnode;
nuclear@25 201
nuclear@25 202 if(!active_win) {
nuclear@25 203 set_active(wnode->id);
nuclear@25 204 } else {
nuclear@25 205 activate_window(wnode);
nuclear@25 206 }
nuclear@25 207
nuclear@25 208 if((func = sgl_get_callback(SGL_CREATE))) {
nuclear@25 209 func(wnode->id);
nuclear@25 210 }
nuclear@25 211 if((func = sgl_get_callback(SGL_RESHAPE))) {
nuclear@25 212 func(xsz, ysz);
nuclear@25 213 }
nuclear@25 214 activate_window(prev_active);
nuclear@25 215 return wnode->id;
nuclear@25 216 }
nuclear@25 217
nuclear@25 218 static void close_window(int id)
nuclear@25 219 {
nuclear@25 220 struct window dummy, *win, *prev;
nuclear@25 221 sgl_close_callback_t close_func;
nuclear@25 222
nuclear@25 223 dummy.next = winlist;
nuclear@25 224
nuclear@25 225 prev = &dummy;
nuclear@25 226 win = prev->next;
nuclear@25 227
nuclear@25 228 while(win) {
nuclear@25 229 if(win->id == id) {
nuclear@25 230 if((close_func = sgl_get_callback(SGL_CLOSE))) {
nuclear@25 231 close_func(id);
nuclear@25 232 }
nuclear@25 233 wglDeleteContext(win->ctx);
nuclear@25 234 ReleaseDC(win->win, win->dc);
nuclear@25 235 DestroyWindow(win->win);
nuclear@25 236
nuclear@25 237 prev->next = win->next;
nuclear@25 238 free(win);
nuclear@25 239 return;
nuclear@25 240 }
nuclear@25 241 prev = win;
nuclear@25 242 win = win->next;
nuclear@25 243 }
nuclear@25 244 }
nuclear@25 245
nuclear@25 246 static int set_active(int id)
nuclear@25 247 {
nuclear@25 248 struct window *win = find_window(id);
nuclear@25 249 if(!win) {
nuclear@25 250 sgl_log("no such window: %d\n", id);
nuclear@25 251 return -1;
nuclear@25 252 }
nuclear@25 253 /* only the user calls this, so don't revert this selection */
nuclear@25 254 prev_active = win;
nuclear@25 255 return activate_window(win);
nuclear@25 256 }
nuclear@25 257
nuclear@25 258 static struct window *find_window(int id)
nuclear@25 259 {
nuclear@25 260 struct window *win = winlist;
nuclear@25 261
nuclear@25 262 while(win) {
nuclear@26 263 if(win->id == id) {
nuclear@26 264 return win;
nuclear@26 265 }
nuclear@26 266 win = win->next;
nuclear@26 267 }
nuclear@26 268 return 0;
nuclear@26 269 }
nuclear@26 270
nuclear@26 271 static struct window *find_window_handle(HWND wh)
nuclear@26 272 {
nuclear@26 273 struct window *win = winlist;
nuclear@26 274
nuclear@26 275 while(win) {
nuclear@26 276 if(win->win == wh) {
nuclear@25 277 return win;
nuclear@25 278 }
nuclear@25 279 win = win->next;
nuclear@25 280 }
nuclear@25 281 return 0;
nuclear@25 282 }
nuclear@25 283
nuclear@25 284 static int activate_window(struct window *win)
nuclear@25 285 {
nuclear@25 286 if(!wglMakeCurrent(win->dc, win->ctx)) {
nuclear@25 287 sgl_log("failed to activate window %d\n", (int)win->id);
nuclear@25 288 return -1;
nuclear@25 289 }
nuclear@25 290 active_win = win;
nuclear@25 291 return 0;
nuclear@25 292 }
nuclear@25 293
nuclear@25 294 static int set_title(const char *str)
nuclear@25 295 {
nuclear@25 296 SetWindowText(active_win->win, str);
nuclear@25 297 }
nuclear@25 298
nuclear@25 299 static void redisplay(void)
nuclear@25 300 {
nuclear@25 301 InvalidateRect(active_win->win, 0, 0);
nuclear@25 302 }
nuclear@25 303
nuclear@25 304 static void swap_buffers(void)
nuclear@25 305 {
nuclear@25 306 SwapBuffers(active_win->dc);
nuclear@25 307 }
nuclear@25 308
nuclear@25 309 static int get_modifiers(void)
nuclear@25 310 {
nuclear@25 311 return 0; /* TODO */
nuclear@25 312 }
nuclear@25 313
nuclear@25 314 static void set_event(int idx, int enable)
nuclear@25 315 {
nuclear@25 316 /* not needed */
nuclear@25 317 }
nuclear@25 318
nuclear@25 319 static int process_events(void)
nuclear@25 320 {
nuclear@25 321 int ret;
nuclear@25 322 MSG msg;
nuclear@25 323 sgl_idle_callback_t idle;
nuclear@25 324 sgl_display_callback_t disp;
nuclear@25 325
nuclear@25 326 idle = sgl_get_callback(SGL_IDLE);
nuclear@25 327
nuclear@25 328 prev_active = active_win;
nuclear@25 329
nuclear@25 330 if(!idle) {
nuclear@25 331 if(!GetMessage(&msg, 0, 0, 0)) {
nuclear@25 332 ret = -1;
nuclear@25 333 goto end;
nuclear@25 334 }
nuclear@25 335 } else {
nuclear@25 336 if(!PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
nuclear@25 337 ret = 0;
nuclear@25 338 goto end;
nuclear@25 339 }
nuclear@25 340 }
nuclear@25 341
nuclear@25 342 do {
nuclear@25 343 if(msg.message == WM_QUIT) {
nuclear@25 344 ret = -1;
nuclear@25 345 break;
nuclear@25 346 }
nuclear@25 347 TranslateMessage(&msg);
nuclear@25 348 DispatchMessage(&msg);
nuclear@25 349 } while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE));
nuclear@25 350
nuclear@25 351 end:
nuclear@25 352 if(ret != -1 && idle) {
nuclear@25 353 idle();
nuclear@25 354 }
nuclear@25 355 activate_window(prev_active);
nuclear@25 356 return ret;
nuclear@25 357 }
nuclear@25 358
nuclear@25 359 static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
nuclear@25 360 {
nuclear@25 361 static int state;
nuclear@25 362 struct window *win;
nuclear@25 363 void (*func)();
nuclear@25 364
nuclear@25 365 if((win = find_window_handle(hwnd))) {
nuclear@25 366 activate_window(win);
nuclear@25 367 } else {
nuclear@25 368 return DefWindowProc(hwnd, msg, wparam, lparam);
nuclear@25 369 }
nuclear@25 370
nuclear@25 371 switch(msg) {
nuclear@25 372 case WM_PAINT:
nuclear@25 373 if((func = sgl_get_callback(SGL_DISPLAY))) {
nuclear@25 374 func();
nuclear@25 375 }
nuclear@25 376 ValidateRect(hwnd, 0);
nuclear@25 377 break;
nuclear@25 378
nuclear@25 379 case WM_KEYDOWN:
nuclear@25 380 case WM_KEYUP:
nuclear@25 381 if((func = sgl_get_callback(SGL_KEYBOARD))) {
nuclear@25 382 func(MapVirtualKey(wparam, 2), msg == WM_KEYDOWN);
nuclear@25 383 }
nuclear@25 384 break;
nuclear@25 385
nuclear@25 386 case WM_LBUTTONDOWN:
nuclear@25 387 case WM_RBUTTONDOWN:
nuclear@25 388 case WM_MBUTTONDOWN:
nuclear@25 389 if(1) {
nuclear@25 390 state++;
nuclear@25 391 } else {
nuclear@25 392 case WM_LBUTTONUP:
nuclear@25 393 case WM_RBUTTONUP:
nuclear@25 394 case WM_MBUTTONUP:
nuclear@25 395 state--;
nuclear@25 396 }
nuclear@25 397 assert(state >= 0);
nuclear@25 398 if((func = sgl_get_callback(SGL_MOUSE))) {
nuclear@25 399 func(mouse_button(msg), state, LOWORD(lparam), HIWORD(lparam));
nuclear@25 400 }
nuclear@25 401 break;
nuclear@25 402
nuclear@25 403 case WM_MOUSEMOVE:
nuclear@25 404 if(state) {
nuclear@25 405 func = sgl_get_callback(SGL_MOTION);
nuclear@25 406 } else {
nuclear@25 407 func = sgl_get_callback(SGL_PASSIVE);
nuclear@25 408 }
nuclear@25 409 if(func) {
nuclear@25 410 func(LOWORD(lparam), HIWORD(lparam));
nuclear@25 411 }
nuclear@25 412 break;
nuclear@25 413
nuclear@25 414 default:
nuclear@25 415 return DefWindowProc(hwnd, msg, wparam, lparam);
nuclear@25 416 }
nuclear@25 417 return 0;
nuclear@25 418 }
nuclear@25 419
nuclear@25 420 static int mouse_button(unsigned int msg)
nuclear@25 421 {
nuclear@25 422 switch(msg) {
nuclear@25 423 case WM_LBUTTONDOWN:
nuclear@25 424 case WM_LBUTTONUP:
nuclear@25 425 return SGL_LEFT_BUTTON;
nuclear@25 426
nuclear@25 427 case WM_RBUTTONDOWN:
nuclear@25 428 case WM_RBUTTONUP:
nuclear@25 429 return SGL_RIGHT_BUTTON;
nuclear@25 430
nuclear@25 431 case WM_MBUTTONDOWN:
nuclear@25 432 case WM_MBUTTONUP:
nuclear@25 433 return SGL_MIDDLE_BUTTON;
nuclear@25 434
nuclear@25 435 default:
nuclear@25 436 break;
nuclear@25 437 }
nuclear@25 438 return -1;
nuclear@25 439 }
nuclear@25 440
nuclear@26 441 static void calc_win_size(int w, int h, int *width, int *height, int *posx, int *posy)
nuclear@26 442 {
nuclear@26 443 RECT rect;
nuclear@26 444 DEVMODE dmode;
nuclear@26 445 unsigned int style = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_POPUP | WS_SYSMENU | WS_VISIBLE;
nuclear@26 446
nuclear@26 447 rect.left = rect.top = 0;
nuclear@26 448 rect.right = w;
nuclear@26 449 rect.bottom = h;
nuclear@26 450
nuclear@26 451 AdjustWindowRect(&rect, style, 0);
nuclear@26 452
nuclear@26 453 *width = rect.right - rect.left;
nuclear@26 454 *height = rect.bottom - rect.top;
nuclear@26 455
nuclear@26 456 *posx = *posy = 0;
nuclear@26 457
nuclear@26 458 memset(&dmode, 0, sizeof dmode);
nuclear@26 459 dmode.dmSize = sizeof dmode;
nuclear@26 460
nuclear@26 461 if(EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dmode)) {
nuclear@26 462 int x, y;
nuclear@26 463
nuclear@26 464 x = (dmode.dmPelsWidth - *width) / 2;
nuclear@26 465 if(x > 0) {
nuclear@26 466 *posx = x;
nuclear@26 467 }
nuclear@26 468
nuclear@26 469 y = (dmode.dmPelsHeight - *height) / 2;
nuclear@26 470 if(y > 0) {
nuclear@26 471 *posy = y;
nuclear@26 472 }
nuclear@26 473 }
nuclear@26 474 }
nuclear@26 475
nuclear@25 476 #else
nuclear@25 477 int sgl_wsys_w32_silence_the_fucking_empty_file_warnings;
nuclear@25 478 #endif