sgl

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