diff options
Diffstat (limited to 'libraries/ode-0.9/drawstuff/src/windows.cpp')
-rw-r--r-- | libraries/ode-0.9/drawstuff/src/windows.cpp | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/libraries/ode-0.9/drawstuff/src/windows.cpp b/libraries/ode-0.9/drawstuff/src/windows.cpp new file mode 100644 index 0000000..e2b442a --- /dev/null +++ b/libraries/ode-0.9/drawstuff/src/windows.cpp | |||
@@ -0,0 +1,527 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #if defined(WIN32) || defined(__CYGWIN__)// this prevents warnings when dependencies built | ||
24 | #include <windows.h> | ||
25 | #endif | ||
26 | #include <ode/config.h> | ||
27 | #include <GL/gl.h> | ||
28 | |||
29 | #include "resource.h" | ||
30 | #include "internal.h" | ||
31 | |||
32 | //*************************************************************************** | ||
33 | // application globals | ||
34 | |||
35 | static HINSTANCE ghInstance = 0; | ||
36 | static int gnCmdShow = 0; | ||
37 | static HACCEL accelerators = 0; | ||
38 | static HWND main_window = 0; | ||
39 | |||
40 | //*************************************************************************** | ||
41 | // error and message handling | ||
42 | |||
43 | static void errorBox (char *title, char *msg, va_list ap) | ||
44 | { | ||
45 | char s[1000]; | ||
46 | vsprintf (s,msg,ap); | ||
47 | MessageBox (0,s,title,MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION); | ||
48 | } | ||
49 | |||
50 | |||
51 | static void dsWarning (char *msg, ...) | ||
52 | { | ||
53 | va_list ap; | ||
54 | va_start (ap,msg); | ||
55 | errorBox ("Warning",msg,ap); | ||
56 | } | ||
57 | |||
58 | |||
59 | extern "C" void dsError (char *msg, ...) | ||
60 | { | ||
61 | va_list ap; | ||
62 | va_start (ap,msg); | ||
63 | errorBox ("Error",msg,ap); | ||
64 | exit (1); | ||
65 | } | ||
66 | |||
67 | |||
68 | extern "C" void dsDebug (char *msg, ...) | ||
69 | { | ||
70 | va_list ap; | ||
71 | va_start (ap,msg); | ||
72 | errorBox ("INTERNAL ERROR",msg,ap); | ||
73 | // *((char *)0) = 0; ... commit SEGVicide ? | ||
74 | abort(); | ||
75 | exit (1); // should never get here, but just in case... | ||
76 | } | ||
77 | |||
78 | |||
79 | extern "C" void dsPrint (char *msg, ...) | ||
80 | { | ||
81 | va_list ap; | ||
82 | va_start (ap,msg); | ||
83 | vprintf (msg,ap); | ||
84 | } | ||
85 | |||
86 | //*************************************************************************** | ||
87 | // rendering thread | ||
88 | |||
89 | // globals used to communicate with rendering thread | ||
90 | |||
91 | static volatile int renderer_run = 1; | ||
92 | static volatile int renderer_pause = 0; // 0=run, 1=pause | ||
93 | static volatile int renderer_ss = 0; // single step command | ||
94 | static volatile int renderer_width = 1; | ||
95 | static volatile int renderer_height = 1; | ||
96 | static dsFunctions *renderer_fn = 0; | ||
97 | static volatile HDC renderer_dc = 0; | ||
98 | static volatile int keybuffer[16]; // fifo ring buffer for keypresses | ||
99 | static volatile int keybuffer_head = 0; // index of next key to put in (modified by GUI) | ||
100 | static volatile int keybuffer_tail = 0; // index of next key to take out (modified by renderer) | ||
101 | |||
102 | |||
103 | static void setupRendererGlobals() | ||
104 | { | ||
105 | renderer_run = 1; | ||
106 | renderer_pause = 0; | ||
107 | renderer_ss = 0; | ||
108 | renderer_width = 1; | ||
109 | renderer_height = 1; | ||
110 | renderer_fn = 0; | ||
111 | renderer_dc = 0; | ||
112 | keybuffer[16]; | ||
113 | keybuffer_head = 0; | ||
114 | keybuffer_tail = 0; | ||
115 | } | ||
116 | |||
117 | |||
118 | static DWORD WINAPI renderingThread (LPVOID lpParam) | ||
119 | { | ||
120 | // create openGL context and make it current | ||
121 | HGLRC glc = wglCreateContext (renderer_dc); | ||
122 | if (glc==NULL) dsError ("could not create OpenGL context"); | ||
123 | if (wglMakeCurrent (renderer_dc,glc) != TRUE) | ||
124 | dsError ("could not make OpenGL context current"); | ||
125 | |||
126 | // test openGL capabilities | ||
127 | int maxtsize=0; | ||
128 | glGetIntegerv (GL_MAX_TEXTURE_SIZE,&maxtsize); | ||
129 | if (maxtsize < 128) dsWarning ("max texture size too small (%dx%d)", | ||
130 | maxtsize,maxtsize); | ||
131 | |||
132 | dsStartGraphics (renderer_width,renderer_height,renderer_fn); | ||
133 | if (renderer_fn->start) renderer_fn->start(); | ||
134 | |||
135 | while (renderer_run) { | ||
136 | // need to make local copy of renderer_ss to help prevent races | ||
137 | int ss = renderer_ss; | ||
138 | dsDrawFrame (renderer_width,renderer_height,renderer_fn, | ||
139 | renderer_pause && !ss); | ||
140 | if (ss) renderer_ss = 0; | ||
141 | |||
142 | // read keys out of ring buffer and feed them to the command function | ||
143 | while (keybuffer_head != keybuffer_tail) { | ||
144 | if (renderer_fn->command) renderer_fn->command (keybuffer[keybuffer_tail]); | ||
145 | keybuffer_tail = (keybuffer_tail+1) & 15; | ||
146 | } | ||
147 | |||
148 | // swap buffers | ||
149 | SwapBuffers (renderer_dc); | ||
150 | } | ||
151 | |||
152 | if (renderer_fn->stop) renderer_fn->stop(); | ||
153 | dsStopGraphics(); | ||
154 | |||
155 | // delete openGL context | ||
156 | wglMakeCurrent (NULL,NULL); | ||
157 | wglDeleteContext (glc); | ||
158 | |||
159 | return 123; // magic value used to test for thread termination | ||
160 | } | ||
161 | |||
162 | //*************************************************************************** | ||
163 | // window handling | ||
164 | |||
165 | // callback function for "about" dialog box | ||
166 | |||
167 | static LRESULT CALLBACK AboutDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, | ||
168 | LPARAM lParam) | ||
169 | { | ||
170 | switch (uMsg) { | ||
171 | case WM_INITDIALOG: | ||
172 | return TRUE; | ||
173 | case WM_COMMAND: | ||
174 | switch (wParam) { | ||
175 | case IDOK: | ||
176 | EndDialog (hDlg, TRUE); | ||
177 | return TRUE; | ||
178 | } | ||
179 | break; | ||
180 | } | ||
181 | return FALSE; | ||
182 | } | ||
183 | |||
184 | |||
185 | // callback function for the main window | ||
186 | |||
187 | static LRESULT CALLBACK mainWndProc (HWND hWnd, UINT msg, WPARAM wParam, | ||
188 | LPARAM lParam) | ||
189 | { | ||
190 | static int button=0,lastx=0,lasty=0; | ||
191 | int ctrl = int(wParam & MK_CONTROL); | ||
192 | |||
193 | switch (msg) { | ||
194 | case WM_LBUTTONDOWN: | ||
195 | case WM_MBUTTONDOWN: | ||
196 | case WM_RBUTTONDOWN: | ||
197 | if (msg==WM_LBUTTONDOWN) button |= 1; | ||
198 | else if (msg==WM_MBUTTONDOWN) button |= 2; | ||
199 | else button |= 4; | ||
200 | lastx = SHORT(LOWORD(lParam)); | ||
201 | lasty = SHORT(HIWORD(lParam)); | ||
202 | SetCapture (hWnd); | ||
203 | break; | ||
204 | |||
205 | case WM_LBUTTONUP: | ||
206 | case WM_MBUTTONUP: | ||
207 | case WM_RBUTTONUP: | ||
208 | if (msg==WM_LBUTTONUP) button &= ~1; | ||
209 | else if (msg==WM_MBUTTONUP) button &= ~2; | ||
210 | else button &= ~4; | ||
211 | if (button==0) ReleaseCapture(); | ||
212 | break; | ||
213 | |||
214 | case WM_MOUSEMOVE: { | ||
215 | int x = SHORT(LOWORD(lParam)); | ||
216 | int y = SHORT(HIWORD(lParam)); | ||
217 | if (button) dsMotion (button,x-lastx,y-lasty); | ||
218 | lastx = x; | ||
219 | lasty = y; | ||
220 | break; | ||
221 | } | ||
222 | |||
223 | case WM_CHAR: { | ||
224 | if (wParam >= ' ' && wParam <= 126) { | ||
225 | int nexth = (keybuffer_head+1) & 15; | ||
226 | if (nexth != keybuffer_tail) { | ||
227 | keybuffer[keybuffer_head] = int(wParam); | ||
228 | keybuffer_head = nexth; | ||
229 | } | ||
230 | } | ||
231 | break; | ||
232 | } | ||
233 | |||
234 | case WM_SIZE: | ||
235 | // lParam will contain the size of the *client* area! | ||
236 | renderer_width = LOWORD(lParam); | ||
237 | renderer_height = HIWORD(lParam); | ||
238 | break; | ||
239 | |||
240 | case WM_COMMAND: | ||
241 | switch (wParam & 0xffff) { | ||
242 | case IDM_ABOUT: | ||
243 | DialogBox (ghInstance,MAKEINTRESOURCE(IDD_ABOUT),hWnd, | ||
244 | (DLGPROC) AboutDlgProc); | ||
245 | break; | ||
246 | case IDM_PAUSE: { | ||
247 | renderer_pause ^= 1; | ||
248 | CheckMenuItem (GetMenu(hWnd),IDM_PAUSE, | ||
249 | renderer_pause ? MF_CHECKED : MF_UNCHECKED); | ||
250 | if (renderer_pause) renderer_ss = 0; | ||
251 | break; | ||
252 | } | ||
253 | case IDM_SINGLE_STEP: { | ||
254 | if (renderer_pause) | ||
255 | renderer_ss = 1; | ||
256 | else | ||
257 | SendMessage( hWnd, WM_COMMAND, IDM_PAUSE, 0 ); | ||
258 | break; | ||
259 | } | ||
260 | case IDM_PERF_MONITOR: { | ||
261 | dsWarning ("Performance monitor not yet implemented."); | ||
262 | break; | ||
263 | } | ||
264 | case IDM_TEXTURES: { | ||
265 | static int tex = 1; | ||
266 | tex ^= 1; | ||
267 | CheckMenuItem (GetMenu(hWnd),IDM_TEXTURES, | ||
268 | tex ? MF_CHECKED : MF_UNCHECKED); | ||
269 | dsSetTextures (tex); | ||
270 | break; | ||
271 | } | ||
272 | case IDM_SHADOWS: { | ||
273 | static int shadows = 1; | ||
274 | shadows ^= 1; | ||
275 | CheckMenuItem (GetMenu(hWnd),IDM_SHADOWS, | ||
276 | shadows ? MF_CHECKED : MF_UNCHECKED); | ||
277 | dsSetShadows (shadows); | ||
278 | break; | ||
279 | } | ||
280 | case IDM_SAVE_SETTINGS: { | ||
281 | dsWarning ("\"Save Settings\" not yet implemented."); | ||
282 | break; | ||
283 | } | ||
284 | case IDM_EXIT: | ||
285 | PostQuitMessage (0); | ||
286 | break; | ||
287 | } | ||
288 | break; | ||
289 | |||
290 | case WM_CLOSE: | ||
291 | PostQuitMessage (0); | ||
292 | break; | ||
293 | |||
294 | default: | ||
295 | return (DefWindowProc (hWnd, msg, wParam, lParam)); | ||
296 | } | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | |||
302 | // this comes from an MSDN example. believe it or not, this is the recommended | ||
303 | // way to get the console window handle. | ||
304 | |||
305 | static HWND GetConsoleHwnd() | ||
306 | { | ||
307 | // the console window title to a "unique" value, then find the window | ||
308 | // that has this title. | ||
309 | char title[1024]; | ||
310 | wsprintf (title,"DrawStuff:%d/%d",GetTickCount(),GetCurrentProcessId()); | ||
311 | SetConsoleTitle (title); | ||
312 | Sleep(40); // ensure window title has been updated | ||
313 | return FindWindow (NULL,title); | ||
314 | } | ||
315 | |||
316 | |||
317 | static void drawStuffStartup() | ||
318 | { | ||
319 | static int startup_called = 0; | ||
320 | if (startup_called) return; | ||
321 | startup_called = 1; | ||
322 | if (!ghInstance) | ||
323 | ghInstance = GetModuleHandleA (NULL); | ||
324 | gnCmdShow = SW_SHOWNORMAL; // @@@ fix this later | ||
325 | |||
326 | // redirect standard I/O to a new console (except on cygwin) | ||
327 | #ifndef __CYGWIN__ | ||
328 | FreeConsole(); | ||
329 | if (AllocConsole()==0) dsError ("AllocConsole() failed"); | ||
330 | if (freopen ("CONIN$","rt",stdin)==0) dsError ("could not open stdin"); | ||
331 | if (freopen ("CONOUT$","wt",stdout)==0) dsError ("could not open stdout"); | ||
332 | if (freopen ("CONOUT$","wt",stderr)==0) dsError ("could not open stderr"); | ||
333 | BringWindowToTop (GetConsoleHwnd()); | ||
334 | SetConsoleTitle ("DrawStuff Messages"); | ||
335 | #endif | ||
336 | |||
337 | // register the window class | ||
338 | WNDCLASS wc; | ||
339 | wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; | ||
340 | wc.lpfnWndProc = mainWndProc; | ||
341 | wc.cbClsExtra = 0; | ||
342 | wc.cbWndExtra = 0; | ||
343 | wc.hInstance = ghInstance; | ||
344 | wc.hIcon = LoadIcon (NULL,IDI_APPLICATION); | ||
345 | wc.hCursor = LoadCursor (NULL,IDC_ARROW); | ||
346 | wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1); | ||
347 | wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); | ||
348 | wc.lpszClassName = "SimAppClass"; | ||
349 | if (RegisterClass (&wc)==0) dsError ("could not register window class"); | ||
350 | |||
351 | // load accelerators | ||
352 | accelerators = LoadAccelerators (ghInstance, | ||
353 | MAKEINTRESOURCE(IDR_ACCELERATOR1)); | ||
354 | if (accelerators==NULL) dsError ("could not load accelerators"); | ||
355 | } | ||
356 | |||
357 | |||
358 | void dsPlatformSimLoop (int window_width, int window_height, | ||
359 | dsFunctions *fn, int initial_pause) | ||
360 | { | ||
361 | drawStuffStartup(); | ||
362 | setupRendererGlobals(); | ||
363 | renderer_pause = initial_pause; | ||
364 | |||
365 | // create window - but first get window size for desired size of client area. | ||
366 | // if this adjustment isn't made then the openGL area will be shifted into | ||
367 | // the nonclient area and determining the frame buffer coordinate from the | ||
368 | // client area coordinate will be hard. | ||
369 | RECT winrect; | ||
370 | winrect.left = 50; | ||
371 | winrect.top = 80; | ||
372 | winrect.right = winrect.left + window_width; | ||
373 | winrect.bottom = winrect.top + window_height; | ||
374 | DWORD style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; | ||
375 | AdjustWindowRect (&winrect,style,1); | ||
376 | char title[100]; | ||
377 | sprintf (title,"Simulation test environment v%d.%02d", | ||
378 | DS_VERSION >> 8,DS_VERSION & 0xff); | ||
379 | main_window = CreateWindow ("SimAppClass",title,style, | ||
380 | winrect.left,winrect.top,winrect.right-winrect.left,winrect.bottom-winrect.top, | ||
381 | NULL,NULL,ghInstance,NULL); | ||
382 | if (main_window==NULL) dsError ("could not create main window"); | ||
383 | ShowWindow (main_window, gnCmdShow); | ||
384 | |||
385 | HDC dc = GetDC (main_window); // get DC for this window | ||
386 | if (dc==NULL) dsError ("could not get window DC"); | ||
387 | |||
388 | // set pixel format for DC | ||
389 | |||
390 | PIXELFORMATDESCRIPTOR pfd = { | ||
391 | sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd | ||
392 | 1, // version number | ||
393 | PFD_DRAW_TO_WINDOW | // support window | ||
394 | PFD_SUPPORT_OPENGL | // support OpenGL | ||
395 | PFD_DOUBLEBUFFER, // double buffered | ||
396 | PFD_TYPE_RGBA, // RGBA type | ||
397 | 24, // 24-bit color depth | ||
398 | 0, 0, 0, 0, 0, 0, // color bits ignored | ||
399 | 0, // no alpha buffer | ||
400 | 0, // shift bit ignored | ||
401 | 0, // no accumulation buffer | ||
402 | 0, 0, 0, 0, // accum bits ignored | ||
403 | 32, // 32-bit z-buffer | ||
404 | 0, // no stencil buffer | ||
405 | 0, // no auxiliary buffer | ||
406 | PFD_MAIN_PLANE, // main layer | ||
407 | 0, // reserved | ||
408 | 0, 0, 0 // layer masks ignored | ||
409 | }; | ||
410 | // get the best available match of pixel format for the device context | ||
411 | int iPixelFormat = ChoosePixelFormat (dc,&pfd); | ||
412 | if (iPixelFormat==0) | ||
413 | dsError ("could not find a good OpenGL pixel format"); | ||
414 | // set the pixel format of the device context | ||
415 | if (SetPixelFormat (dc,iPixelFormat,&pfd)==FALSE) | ||
416 | dsError ("could not set DC pixel format for OpenGL"); | ||
417 | |||
418 | // ********** | ||
419 | // start the rendering thread | ||
420 | |||
421 | // set renderer globals | ||
422 | renderer_dc = dc; | ||
423 | renderer_width = window_width; | ||
424 | renderer_height = window_height; | ||
425 | renderer_fn = fn; | ||
426 | |||
427 | DWORD threadId, thirdParam = 0; | ||
428 | HANDLE hThread; | ||
429 | |||
430 | hThread = CreateThread( | ||
431 | NULL, // no security attributes | ||
432 | 0, // use default stack size | ||
433 | renderingThread, // thread function | ||
434 | &thirdParam, // argument to thread function | ||
435 | 0, // use default creation flags | ||
436 | &threadId); // returns the thread identifier | ||
437 | |||
438 | if (hThread==NULL) dsError ("Could not create rendering thread"); | ||
439 | |||
440 | // ********** | ||
441 | // start GUI message processing | ||
442 | |||
443 | MSG msg; | ||
444 | while (GetMessage (&msg,main_window,0,0)) { | ||
445 | if (!TranslateAccelerator (main_window,accelerators,&msg)) { | ||
446 | TranslateMessage (&msg); | ||
447 | DispatchMessage (&msg); | ||
448 | } | ||
449 | } | ||
450 | |||
451 | // terminate rendering thread | ||
452 | renderer_run = 0; | ||
453 | DWORD ret = WaitForSingleObject (hThread,2000); | ||
454 | if (ret==WAIT_TIMEOUT) dsWarning ("Could not kill rendering thread (1)"); | ||
455 | DWORD exitcode=0; | ||
456 | if (!(GetExitCodeThread (hThread,&exitcode) && exitcode == 123)) | ||
457 | dsWarning ("Could not kill rendering thread (2)"); | ||
458 | CloseHandle (hThread); // dont need thread handle anymore | ||
459 | |||
460 | // destroy window | ||
461 | DestroyWindow (main_window); | ||
462 | } | ||
463 | |||
464 | |||
465 | extern "C" void dsStop() | ||
466 | { | ||
467 | // just calling PostQuitMessage() here wont work, as this function is | ||
468 | // typically called from the rendering thread, not the GUI thread. | ||
469 | // instead we must post the message to the GUI window explicitly. | ||
470 | |||
471 | if (main_window) PostMessage (main_window,WM_QUIT,0,0); | ||
472 | } | ||
473 | |||
474 | |||
475 | extern "C" double dsElapsedTime() | ||
476 | { | ||
477 | static double prev=0.0; | ||
478 | double curr = timeGetTime()/1000.0; | ||
479 | if (!prev) | ||
480 | prev=curr; | ||
481 | double retval = curr-prev; | ||
482 | prev=curr; | ||
483 | if (retval>1.0) retval=1.0; | ||
484 | if (retval<dEpsilon) retval=dEpsilon; | ||
485 | return retval; | ||
486 | } | ||
487 | |||
488 | |||
489 | // JPerkins: if running as a DLL, grab my module handle at load time so | ||
490 | // I can find the accelerators table later | ||
491 | |||
492 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) | ||
493 | { | ||
494 | switch (fdwReason) | ||
495 | { | ||
496 | case DLL_PROCESS_ATTACH: | ||
497 | ghInstance = hinstDLL; | ||
498 | break; | ||
499 | } | ||
500 | return TRUE; | ||
501 | } | ||
502 | |||
503 | |||
504 | // JPerkins: the new build system can set the entry point of the tests to | ||
505 | // main(); this code is no longer necessary | ||
506 | /* | ||
507 | |||
508 | //*************************************************************************** | ||
509 | // windows entry point | ||
510 | // | ||
511 | // NOTE: WinMain is not guaranteed to be called with MinGW, because MinGW | ||
512 | // always calls main if it is defined and most users of this library will | ||
513 | // define their own main. So the startup functionality is kept in | ||
514 | // zDriverStartup(), which is also called when dsSimulationLoop() is called. | ||
515 | |||
516 | extern "C" int main (int argc, char **argv); | ||
517 | |||
518 | |||
519 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, | ||
520 | LPSTR lpCmdLine, int nCmdShow) | ||
521 | { | ||
522 | drawStuffStartup(); | ||
523 | return main (0,0); // @@@ should really pass cmd line arguments | ||
524 | } | ||
525 | |||
526 | */ | ||
527 | |||