From d48ea5bb797037069d641da41da0f195f0124491 Mon Sep 17 00:00:00 2001 From: dan miller Date: Fri, 19 Oct 2007 05:20:48 +0000 Subject: one more for the gipper --- libraries/ode-0.9/drawstuff/src/windows.cpp | 527 ++++++++++++++++++++++++++++ 1 file changed, 527 insertions(+) create mode 100644 libraries/ode-0.9/drawstuff/src/windows.cpp (limited to 'libraries/ode-0.9/drawstuff/src/windows.cpp') 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 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#if defined(WIN32) || defined(__CYGWIN__)// this prevents warnings when dependencies built +#include +#endif +#include +#include + +#include "resource.h" +#include "internal.h" + +//*************************************************************************** +// application globals + +static HINSTANCE ghInstance = 0; +static int gnCmdShow = 0; +static HACCEL accelerators = 0; +static HWND main_window = 0; + +//*************************************************************************** +// error and message handling + +static void errorBox (char *title, char *msg, va_list ap) +{ + char s[1000]; + vsprintf (s,msg,ap); + MessageBox (0,s,title,MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION); +} + + +static void dsWarning (char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + errorBox ("Warning",msg,ap); +} + + +extern "C" void dsError (char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + errorBox ("Error",msg,ap); + exit (1); +} + + +extern "C" void dsDebug (char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + errorBox ("INTERNAL ERROR",msg,ap); + // *((char *)0) = 0; ... commit SEGVicide ? + abort(); + exit (1); // should never get here, but just in case... +} + + +extern "C" void dsPrint (char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + vprintf (msg,ap); +} + +//*************************************************************************** +// rendering thread + +// globals used to communicate with rendering thread + +static volatile int renderer_run = 1; +static volatile int renderer_pause = 0; // 0=run, 1=pause +static volatile int renderer_ss = 0; // single step command +static volatile int renderer_width = 1; +static volatile int renderer_height = 1; +static dsFunctions *renderer_fn = 0; +static volatile HDC renderer_dc = 0; +static volatile int keybuffer[16]; // fifo ring buffer for keypresses +static volatile int keybuffer_head = 0; // index of next key to put in (modified by GUI) +static volatile int keybuffer_tail = 0; // index of next key to take out (modified by renderer) + + +static void setupRendererGlobals() +{ + renderer_run = 1; + renderer_pause = 0; + renderer_ss = 0; + renderer_width = 1; + renderer_height = 1; + renderer_fn = 0; + renderer_dc = 0; + keybuffer[16]; + keybuffer_head = 0; + keybuffer_tail = 0; +} + + +static DWORD WINAPI renderingThread (LPVOID lpParam) +{ + // create openGL context and make it current + HGLRC glc = wglCreateContext (renderer_dc); + if (glc==NULL) dsError ("could not create OpenGL context"); + if (wglMakeCurrent (renderer_dc,glc) != TRUE) + dsError ("could not make OpenGL context current"); + + // test openGL capabilities + int maxtsize=0; + glGetIntegerv (GL_MAX_TEXTURE_SIZE,&maxtsize); + if (maxtsize < 128) dsWarning ("max texture size too small (%dx%d)", + maxtsize,maxtsize); + + dsStartGraphics (renderer_width,renderer_height,renderer_fn); + if (renderer_fn->start) renderer_fn->start(); + + while (renderer_run) { + // need to make local copy of renderer_ss to help prevent races + int ss = renderer_ss; + dsDrawFrame (renderer_width,renderer_height,renderer_fn, + renderer_pause && !ss); + if (ss) renderer_ss = 0; + + // read keys out of ring buffer and feed them to the command function + while (keybuffer_head != keybuffer_tail) { + if (renderer_fn->command) renderer_fn->command (keybuffer[keybuffer_tail]); + keybuffer_tail = (keybuffer_tail+1) & 15; + } + + // swap buffers + SwapBuffers (renderer_dc); + } + + if (renderer_fn->stop) renderer_fn->stop(); + dsStopGraphics(); + + // delete openGL context + wglMakeCurrent (NULL,NULL); + wglDeleteContext (glc); + + return 123; // magic value used to test for thread termination +} + +//*************************************************************************** +// window handling + +// callback function for "about" dialog box + +static LRESULT CALLBACK AboutDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) { + case WM_INITDIALOG: + return TRUE; + case WM_COMMAND: + switch (wParam) { + case IDOK: + EndDialog (hDlg, TRUE); + return TRUE; + } + break; + } + return FALSE; +} + + +// callback function for the main window + +static LRESULT CALLBACK mainWndProc (HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam) +{ + static int button=0,lastx=0,lasty=0; + int ctrl = int(wParam & MK_CONTROL); + + switch (msg) { + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + if (msg==WM_LBUTTONDOWN) button |= 1; + else if (msg==WM_MBUTTONDOWN) button |= 2; + else button |= 4; + lastx = SHORT(LOWORD(lParam)); + lasty = SHORT(HIWORD(lParam)); + SetCapture (hWnd); + break; + + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + if (msg==WM_LBUTTONUP) button &= ~1; + else if (msg==WM_MBUTTONUP) button &= ~2; + else button &= ~4; + if (button==0) ReleaseCapture(); + break; + + case WM_MOUSEMOVE: { + int x = SHORT(LOWORD(lParam)); + int y = SHORT(HIWORD(lParam)); + if (button) dsMotion (button,x-lastx,y-lasty); + lastx = x; + lasty = y; + break; + } + + case WM_CHAR: { + if (wParam >= ' ' && wParam <= 126) { + int nexth = (keybuffer_head+1) & 15; + if (nexth != keybuffer_tail) { + keybuffer[keybuffer_head] = int(wParam); + keybuffer_head = nexth; + } + } + break; + } + + case WM_SIZE: + // lParam will contain the size of the *client* area! + renderer_width = LOWORD(lParam); + renderer_height = HIWORD(lParam); + break; + + case WM_COMMAND: + switch (wParam & 0xffff) { + case IDM_ABOUT: + DialogBox (ghInstance,MAKEINTRESOURCE(IDD_ABOUT),hWnd, + (DLGPROC) AboutDlgProc); + break; + case IDM_PAUSE: { + renderer_pause ^= 1; + CheckMenuItem (GetMenu(hWnd),IDM_PAUSE, + renderer_pause ? MF_CHECKED : MF_UNCHECKED); + if (renderer_pause) renderer_ss = 0; + break; + } + case IDM_SINGLE_STEP: { + if (renderer_pause) + renderer_ss = 1; + else + SendMessage( hWnd, WM_COMMAND, IDM_PAUSE, 0 ); + break; + } + case IDM_PERF_MONITOR: { + dsWarning ("Performance monitor not yet implemented."); + break; + } + case IDM_TEXTURES: { + static int tex = 1; + tex ^= 1; + CheckMenuItem (GetMenu(hWnd),IDM_TEXTURES, + tex ? MF_CHECKED : MF_UNCHECKED); + dsSetTextures (tex); + break; + } + case IDM_SHADOWS: { + static int shadows = 1; + shadows ^= 1; + CheckMenuItem (GetMenu(hWnd),IDM_SHADOWS, + shadows ? MF_CHECKED : MF_UNCHECKED); + dsSetShadows (shadows); + break; + } + case IDM_SAVE_SETTINGS: { + dsWarning ("\"Save Settings\" not yet implemented."); + break; + } + case IDM_EXIT: + PostQuitMessage (0); + break; + } + break; + + case WM_CLOSE: + PostQuitMessage (0); + break; + + default: + return (DefWindowProc (hWnd, msg, wParam, lParam)); + } + + return 0; +} + + +// this comes from an MSDN example. believe it or not, this is the recommended +// way to get the console window handle. + +static HWND GetConsoleHwnd() +{ + // the console window title to a "unique" value, then find the window + // that has this title. + char title[1024]; + wsprintf (title,"DrawStuff:%d/%d",GetTickCount(),GetCurrentProcessId()); + SetConsoleTitle (title); + Sleep(40); // ensure window title has been updated + return FindWindow (NULL,title); +} + + +static void drawStuffStartup() +{ + static int startup_called = 0; + if (startup_called) return; + startup_called = 1; + if (!ghInstance) + ghInstance = GetModuleHandleA (NULL); + gnCmdShow = SW_SHOWNORMAL; // @@@ fix this later + + // redirect standard I/O to a new console (except on cygwin) +#ifndef __CYGWIN__ + FreeConsole(); + if (AllocConsole()==0) dsError ("AllocConsole() failed"); + if (freopen ("CONIN$","rt",stdin)==0) dsError ("could not open stdin"); + if (freopen ("CONOUT$","wt",stdout)==0) dsError ("could not open stdout"); + if (freopen ("CONOUT$","wt",stderr)==0) dsError ("could not open stderr"); + BringWindowToTop (GetConsoleHwnd()); + SetConsoleTitle ("DrawStuff Messages"); +#endif + + // register the window class + WNDCLASS wc; + wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; + wc.lpfnWndProc = mainWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = ghInstance; + wc.hIcon = LoadIcon (NULL,IDI_APPLICATION); + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1); + wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); + wc.lpszClassName = "SimAppClass"; + if (RegisterClass (&wc)==0) dsError ("could not register window class"); + + // load accelerators + accelerators = LoadAccelerators (ghInstance, + MAKEINTRESOURCE(IDR_ACCELERATOR1)); + if (accelerators==NULL) dsError ("could not load accelerators"); +} + + +void dsPlatformSimLoop (int window_width, int window_height, + dsFunctions *fn, int initial_pause) +{ + drawStuffStartup(); + setupRendererGlobals(); + renderer_pause = initial_pause; + + // create window - but first get window size for desired size of client area. + // if this adjustment isn't made then the openGL area will be shifted into + // the nonclient area and determining the frame buffer coordinate from the + // client area coordinate will be hard. + RECT winrect; + winrect.left = 50; + winrect.top = 80; + winrect.right = winrect.left + window_width; + winrect.bottom = winrect.top + window_height; + DWORD style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + AdjustWindowRect (&winrect,style,1); + char title[100]; + sprintf (title,"Simulation test environment v%d.%02d", + DS_VERSION >> 8,DS_VERSION & 0xff); + main_window = CreateWindow ("SimAppClass",title,style, + winrect.left,winrect.top,winrect.right-winrect.left,winrect.bottom-winrect.top, + NULL,NULL,ghInstance,NULL); + if (main_window==NULL) dsError ("could not create main window"); + ShowWindow (main_window, gnCmdShow); + + HDC dc = GetDC (main_window); // get DC for this window + if (dc==NULL) dsError ("could not get window DC"); + + // set pixel format for DC + + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd + 1, // version number + PFD_DRAW_TO_WINDOW | // support window + PFD_SUPPORT_OPENGL | // support OpenGL + PFD_DOUBLEBUFFER, // double buffered + PFD_TYPE_RGBA, // RGBA type + 24, // 24-bit color depth + 0, 0, 0, 0, 0, 0, // color bits ignored + 0, // no alpha buffer + 0, // shift bit ignored + 0, // no accumulation buffer + 0, 0, 0, 0, // accum bits ignored + 32, // 32-bit z-buffer + 0, // no stencil buffer + 0, // no auxiliary buffer + PFD_MAIN_PLANE, // main layer + 0, // reserved + 0, 0, 0 // layer masks ignored + }; + // get the best available match of pixel format for the device context + int iPixelFormat = ChoosePixelFormat (dc,&pfd); + if (iPixelFormat==0) + dsError ("could not find a good OpenGL pixel format"); + // set the pixel format of the device context + if (SetPixelFormat (dc,iPixelFormat,&pfd)==FALSE) + dsError ("could not set DC pixel format for OpenGL"); + + // ********** + // start the rendering thread + + // set renderer globals + renderer_dc = dc; + renderer_width = window_width; + renderer_height = window_height; + renderer_fn = fn; + + DWORD threadId, thirdParam = 0; + HANDLE hThread; + + hThread = CreateThread( + NULL, // no security attributes + 0, // use default stack size + renderingThread, // thread function + &thirdParam, // argument to thread function + 0, // use default creation flags + &threadId); // returns the thread identifier + + if (hThread==NULL) dsError ("Could not create rendering thread"); + + // ********** + // start GUI message processing + + MSG msg; + while (GetMessage (&msg,main_window,0,0)) { + if (!TranslateAccelerator (main_window,accelerators,&msg)) { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + } + + // terminate rendering thread + renderer_run = 0; + DWORD ret = WaitForSingleObject (hThread,2000); + if (ret==WAIT_TIMEOUT) dsWarning ("Could not kill rendering thread (1)"); + DWORD exitcode=0; + if (!(GetExitCodeThread (hThread,&exitcode) && exitcode == 123)) + dsWarning ("Could not kill rendering thread (2)"); + CloseHandle (hThread); // dont need thread handle anymore + + // destroy window + DestroyWindow (main_window); +} + + +extern "C" void dsStop() +{ + // just calling PostQuitMessage() here wont work, as this function is + // typically called from the rendering thread, not the GUI thread. + // instead we must post the message to the GUI window explicitly. + + if (main_window) PostMessage (main_window,WM_QUIT,0,0); +} + + +extern "C" double dsElapsedTime() +{ + static double prev=0.0; + double curr = timeGetTime()/1000.0; + if (!prev) + prev=curr; + double retval = curr-prev; + prev=curr; + if (retval>1.0) retval=1.0; + if (retval