Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ode/ode-0.9/drawstuff/src/windows.cpp @ 216

Last change on this file since 216 was 216, checked in by mathiask, 16 years ago

[Physik] add ode-0.9

File size: 15.2 KB
Line 
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
Note: See TracBrowser for help on using the repository browser.