aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ode-0.9/drawstuff/src/windows.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ode-0.9/drawstuff/src/windows.cpp')
-rw-r--r--libraries/ode-0.9/drawstuff/src/windows.cpp527
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
35static HINSTANCE ghInstance = 0;
36static int gnCmdShow = 0;
37static HACCEL accelerators = 0;
38static HWND main_window = 0;
39
40//***************************************************************************
41// error and message handling
42
43static 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
51static void dsWarning (char *msg, ...)
52{
53 va_list ap;
54 va_start (ap,msg);
55 errorBox ("Warning",msg,ap);
56}
57
58
59extern "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
68extern "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
79extern "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
91static volatile int renderer_run = 1;
92static volatile int renderer_pause = 0; // 0=run, 1=pause
93static volatile int renderer_ss = 0; // single step command
94static volatile int renderer_width = 1;
95static volatile int renderer_height = 1;
96static dsFunctions *renderer_fn = 0;
97static volatile HDC renderer_dc = 0;
98static volatile int keybuffer[16]; // fifo ring buffer for keypresses
99static volatile int keybuffer_head = 0; // index of next key to put in (modified by GUI)
100static volatile int keybuffer_tail = 0; // index of next key to take out (modified by renderer)
101
102
103static 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
118static 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
167static 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
187static 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
305static 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
317static 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
358void 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
465extern "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
475extern "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
492BOOL 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
516extern "C" int main (int argc, char **argv);
517
518
519int 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