sgl

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