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
|