sgl

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