sgl

annotate src/wsys_w32.c @ 27:25de96fb1526

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