sgl

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