Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/wcrdisplay/wcrGraphicsWindow.cxx

Go to the documentation of this file.
00001 // Filename: wcrGraphicsWindow.cxx
00002 // Created by:  skyler, based on wgl* file.
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "wcrGraphicsWindow.h"
00020 #include "wcrGraphicsPipe.h"
00021 #include "config_wcrdisplay.h"
00022 #include <keyboardButton.h>
00023 #include <mouseButton.h>
00024 #include "crGraphicsStateGuardian.h"
00025 #include <errno.h>
00026 #include <time.h>
00027 #include <mmsystem.h>
00028 #include <tchar.h>
00029 #include <map>
00030 #include <throw_event.h>
00031 //#include <eventQueue.h>
00032 #include <string.h>
00033 #include "../wgldisplay/Win32Defs.h"
00034 
00035 //#include "ChromiumOpenGL.h"
00036 
00037 #ifdef DO_PSTATS
00038 #include <pStatTimer.h>
00039 #endif
00040 
00041 #define WCR_WCREXT_PROTOTYPES
00042 #include "wcrext.h"
00043 
00044 ////////////////////////////////////////////////////////////////////
00045 // Static variables
00046 ////////////////////////////////////////////////////////////////////
00047 TypeHandle wcrGraphicsWindow::_type_handle;
00048 
00049 static bool wc_registered = false;
00050 
00051 #define MOUSE_ENTERED 0
00052 #define MOUSE_EXITED 1
00053 
00054 #define FONT_BITMAP_OGLDISPLAYLISTNUM 1000    // an arbitrary ID #
00055 
00056 #define LAST_ERROR 0
00057 #define ERRORBOX_TITLE "Panda3D Error"
00058 #define WCR_WINDOWCLASSNAME "wcrDisplay"
00059 
00060 #define PAUSED_TIMER_ID  7   // completely arbitrary choice
00061 
00062 typedef map<HWND,wcrGraphicsWindow *> HWND_PANDAWIN_MAP;
00063 
00064 HWND_PANDAWIN_MAP hwnd_pandawin_map;
00065 wcrGraphicsWindow *global_wcrwinptr=NULL;  // need this for temporary windproc
00066 
00067 typedef enum {Software, MCD, ICD} OGLDriverType;
00068 static char *OGLDrvStrings[3] = {"Software","MCD","ICD"};
00069 
00070 LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam,LPARAM lparam);
00071 
00072 // because we dont have access to ModifierButtons, as a hack just synchronize state of these
00073 // keys on get/lose keybd focus
00074 #define NUM_MODIFIER_KEYS 16
00075 unsigned int hardcoded_modifier_buttons[NUM_MODIFIER_KEYS]={VK_SHIFT,VK_MENU,VK_CONTROL,VK_SPACE,VK_TAB,
00076                                          VK_UP,VK_DOWN,VK_LEFT,VK_RIGHT,VK_PRIOR,VK_NEXT,VK_HOME,VK_END,
00077                                          VK_INSERT,VK_DELETE,VK_ESCAPE};
00078 
00079 // dont pick any video modes < MIN_REFRESH_RATE Hz
00080 #define MIN_REFRESH_RATE 60
00081 // EnumDisplaySettings may indicate 0 or 1 for refresh rate, which means use driver default rate (assume its >min_refresh_rate)
00082 #define ACCEPTABLE_REFRESH_RATE(RATE) ((RATE >= MIN_REFRESH_RATE) || (RATE==0) || (RATE==1))
00083 
00084 void PrintErrorMessage(DWORD msgID) {
00085    LPTSTR pMessageBuffer;
00086 
00087    if (msgID==LAST_ERROR)
00088      msgID=GetLastError();
00089 
00090    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
00091                  NULL,msgID,
00092                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //The user default language
00093                  (LPTSTR) &pMessageBuffer,  // the weird ptrptr->ptr cast is intentional, see FORMAT_MESSAGE_ALLOCATE_BUFFER
00094                  1024, NULL);
00095    MessageBox(GetDesktopWindow(),pMessageBuffer,_T(ERRORBOX_TITLE),MB_OK);
00096    wcrdisplay_cat.fatal() << "System error msg: " << pMessageBuffer << endl;
00097    LocalFree(pMessageBuffer);
00098 }
00099 
00100 // fn exists so AtExitFn can call it without refcntr blowing up since its !=0
00101 void wcrGraphicsWindow::DestroyMe(bool bAtExitFnCalled) {
00102 
00103   _exiting_window = true;  // needed before DestroyWindow call
00104 
00105   // several GL drivers (voodoo,ATI, not nvidia) crash if we call these wcr deletion routines from
00106   // an atexit() fn.  Possible that GL has already unloaded itself.  So we just wont call them for now
00107   // for that case, we're exiting the app anyway.
00108   if (!bAtExitFnCalled) {
00109       // to do gl releases, we need to have the context be current
00110       #if 0 //[ TODO:skyler
00111       if ((_hdc!=NULL)&&(_context!=NULL)) {
00112           // need to bypass make_current() since it checks _window_inactive 
00113           // which we need to ignore
00114           HGLRC current_context = GetCurrentContext();
00115           //TODO: HDC current_dc = chromium.GetCurrentDC();
00116           HDC current_dc = NULL;
00117 
00118           if ((current_context != _context) || (current_dc != _hdc)) {
00119               if (!chromium.MakeCurrent(_hdc, 0, _context)) {
00120                   PrintErrorMessage(LAST_ERROR);
00121               }
00122           }
00123           report_errors();
00124       }
00125       #endif //]
00126 
00127       if (gl_show_fps_meter)
00128         chromium.DeleteLists(FONT_BITMAP_OGLDISPLAYLISTNUM, 128);
00129 
00130       report_errors();
00131 
00132       // implicitly calls gsg destructors which release GL objects (textures, display lists, etc)
00133       release_gsg();
00134 
00135       report_errors();
00136       // cant report errors after we set cur context to NULL
00137 
00138       #if 0 //[ TODO:skyler
00139       HGLRC curcxt=GetCurrentContext();
00140       if (curcxt!=NULL)
00141         unmake_current();
00142 
00143       if (_context!=NULL) {
00144           chromium.DeleteContext(_context);
00145           _context = NULL;
00146       }
00147       #endif //]
00148   }
00149 
00150   if (_hdc!=NULL) {
00151     ReleaseDC(_mwindow,_hdc);
00152     _hdc = NULL;
00153   }
00154 
00155   if ((_hOldForegroundWindow!=NULL) && (_mwindow==GetForegroundWindow())) {
00156       SetForegroundWindow(_hOldForegroundWindow);
00157   }
00158 
00159   if (_mwindow!=NULL) {
00160     if (_bLoadedCustomCursor && _hMouseCursor!=NULL)
00161       DestroyCursor(_hMouseCursor);
00162 
00163     DestroyWindow(_mwindow);
00164     hwnd_pandawin_map.erase(_mwindow);
00165     _mwindow = NULL;
00166   }
00167 
00168   if (_pCurrent_display_settings!=NULL) {
00169       delete _pCurrent_display_settings;
00170       _pCurrent_display_settings = NULL;
00171   }
00172 
00173   if (_props._fullscreen) {
00174       // revert to default display mode
00175       ChangeDisplaySettings(NULL,0x0);
00176   }
00177 }
00178 
00179 void wcrGraphicsWindow::do_close_window() {
00180   GraphicsWindow::do_close_window();
00181    DestroyMe(false);
00182 }
00183 
00184 ////////////////////////////////////////////////////////////////////
00185 //     Function: Destructor
00186 //       Access:
00187 //  Description:
00188 ////////////////////////////////////////////////////////////////////
00189 wcrGraphicsWindow::~wcrGraphicsWindow() {
00190    close_window();
00191 }
00192 
00193 void DestroyAllWindows(bool bAtExitFnCalled) {
00194    // need to go through all windows in map var and delete them
00195    while(!hwnd_pandawin_map.empty()) {
00196      // cant use a for loop cause DestroyMe erases things out from under us, so iterator is invalid
00197      HWND_PANDAWIN_MAP::iterator pwin = hwnd_pandawin_map.begin();
00198      if ((*pwin).second != NULL)
00199          (*pwin).second->DestroyMe(bAtExitFnCalled);
00200    }
00201 }
00202 
00203 void AtExitFn() {
00204   #ifdef _DEBUG
00205     wcrdisplay_cat.spam() << "AtExitFn called\n";
00206   #endif
00207   DestroyAllWindows(true);
00208 }
00209 
00210 bool find_acceptable_display_mode(DWORD dwWidth,DWORD dwHeight,DWORD bpp,DEVMODE &dm) {
00211     int modenum=0;
00212 
00213     // look for acceptable mode
00214     while(1) {
00215         ZeroMemory(&dm, sizeof(dm));
00216         dm.dmSize = sizeof(dm);
00217 
00218         if (!EnumDisplaySettings(NULL,modenum,&dm))
00219           break;
00220 
00221         if ((dm.dmPelsWidth==dwWidth) && (dm.dmPelsHeight==dwHeight) &&
00222            (dm.dmBitsPerPel==bpp) && ACCEPTABLE_REFRESH_RATE(dm.dmDisplayFrequency)) {
00223            return true;
00224         }
00225         modenum++;
00226     }
00227 
00228     return false;
00229 }
00230 
00231 ////////////////////////////////////////////////////////////////////
00232 //     Function: config
00233 //       Access:
00234 //  Description:
00235 ////////////////////////////////////////////////////////////////////
00236 void wcrGraphicsWindow::config() {
00237 #if 1 //[
00238   int spu_ids[] = { 0, 1 };
00239   char *spu_names[] = { "readback", "pack" };
00240   //char *spu_names[] = { "print", "pack" };
00241   SPU *spu;
00242   spu = crSPULoadChain(sizeof(spu_names)/sizeof(spu_names[0]), spu_ids, 
00243       spu_names, NULL, NULL);
00244   if (!spu) {
00245     cerr << "!spu" << endl;
00246     exit(0);
00247   }
00248   chromium=spu->dispatch_table;
00249   /***/ cerr << "CRGraphicsStateGuardian chromium:" << (void*)&chromium << 
00250       " spu:" << (void*)spu << " dispatch:" << (void*)&(spu->dispatch_table) << "\n\n\n\n\n\n" << endl;
00251   ///***/ __asm int 3
00252 #endif //]
00253 
00254     GraphicsWindow::config();
00255 
00256     HINSTANCE hinstance = GetModuleHandle(NULL);
00257     HWND hDesktopWindow = GetDesktopWindow();
00258 
00259     global_wcrwinptr = this;  // need this until we get an HWND from CreateWindow
00260 
00261     _exiting_window = false;
00262     _return_control_to_app = false;
00263     _bIsLowVidMemCard = false;
00264     _active_minimized_fullscreen = false;
00265     _PandaPausedTimer = NULL;
00266     _mouse_input_enabled = false;
00267     _mouse_motion_enabled = false;
00268     _mouse_passive_motion_enabled = false;
00269     _mouse_entry_enabled = false;
00270     _context = NULL;
00271     _hdc = NULL;
00272     _window_inactive = false;
00273     _pCurrent_display_settings = NULL;
00274     _mwindow = NULL;
00275     _gsg = NULL;
00276     ZeroMemory(&_pixelformat,sizeof(_pixelformat));
00277     _hOldForegroundWindow=GetForegroundWindow();
00278 
00279     WNDCLASS wc;
00280 
00281     // Clear before filling in window structure!
00282     ZeroMemory(&wc, sizeof(WNDCLASS));
00283     wc.style      = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
00284     wc.lpfnWndProc = (WNDPROC) static_window_proc;
00285     wc.hInstance   = hinstance;
00286 
00287     string windows_icon_filename = get_icon_filename_2().to_os_specific();
00288     string windows_mono_cursor_filename = get_mono_cursor_filename_2().to_os_specific();
00289 
00290     if (!windows_icon_filename.empty()) {
00291         // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings)
00292         // if icon is more than 8bpp
00293 
00294         // loads a .ico fmt file
00295         wc.hIcon = (HICON) LoadImage(NULL, windows_icon_filename.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
00296 
00297         if (wc.hIcon==NULL) {
00298             wcrdisplay_cat.warning() << "windows icon filename '" << windows_icon_filename << "' not found!!\n";
00299         }
00300     } else {
00301         wc.hIcon = NULL; // use default app icon
00302     }
00303 
00304     _bLoadedCustomCursor = false;
00305     if (!windows_mono_cursor_filename.empty()) {
00306         // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings)
00307         // if icon is more than 8bpp (because it was 'mapping' 16bpp colors to the device?)
00308 
00309         DWORD load_flags = LR_LOADFROMFILE;
00310 
00311         if (_props._fullscreen) {
00312           // I think cursors should use LR_CREATEDIBSECTION since they should not be mapped to the device palette (in the case of 256-color cursors)
00313           // since they are not going to be used on the desktop
00314           load_flags |= LR_CREATEDIBSECTION;
00315         }
00316 
00317         // loads a .cur fmt file
00318         _hMouseCursor = (HCURSOR) LoadImage(NULL, windows_mono_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, load_flags);
00319 
00320         if (_hMouseCursor==NULL) {
00321             wcrdisplay_cat.warning() << "windows cursor filename '" << windows_mono_cursor_filename << "' not found!!\n";
00322         }
00323         _bLoadedCustomCursor = true;
00324     } else {
00325         _hMouseCursor = LoadCursor(NULL, IDC_ARROW);
00326     }
00327 
00328     if (!wc_registered) {
00329       // We only need to register the window class once per session.
00330       wc.hCursor = _hMouseCursor;
00331       wc.hbrBackground  = (HBRUSH)GetStockObject(BLACK_BRUSH);
00332       wc.lpszMenuName   = NULL;
00333       wc.lpszClassName  = WCR_WINDOWCLASSNAME;
00334 
00335       if (!RegisterClass(&wc)) {
00336         wcrdisplay_cat.error() << "could not register window class!" << endl;
00337       }
00338       wc_registered = true;
00339     }
00340 
00341 //  from MSDN:
00342 //  An OpenGL window has its own pixel format. Because of this, only device contexts retrieved
00343 //  for the client area of an OpenGL window are allowed to draw into the window. As a result, an
00344 //  OpenGL window should be created with the WS_CLIPCHILDREN and WS_CLIPSIBLINGS styles. Additionally,
00345 //  the window class attribute should not include the CS_PARENTDC style.
00346 
00347     DWORD window_style = WS_POPUP | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;  // for CreateWindow
00348 
00349     // rect now contains the coords for the entire window, not the client
00350     if (_props._fullscreen) {
00351       DWORD dwWidth =  _props._xsize;
00352       DWORD dwHeight = _props._ysize;
00353 
00354       HDC scrnDC=GetDC(hDesktopWindow);
00355       DWORD drvr_ver=GetDeviceCaps(scrnDC,DRIVERVERSION);
00356       DWORD cur_bitdepth=GetDeviceCaps(scrnDC,BITSPIXEL);
00357       DWORD cur_scrnwidth=GetDeviceCaps(scrnDC,HORZRES);
00358       DWORD cur_scrnheight=GetDeviceCaps(scrnDC,VERTRES);
00359       ReleaseDC(hDesktopWindow,scrnDC);
00360 
00361       DWORD dwFullScreenBitDepth=cur_bitdepth;
00362 
00363       DEVMODE dm;
00364       if (!find_acceptable_display_mode(dwWidth,dwHeight,dwFullScreenBitDepth,dm)) {
00365           wcrdisplay_cat.fatal() << "Videocard has no supported display resolutions at specified res (" << dwWidth << " X " << dwHeight << " X " << dwFullScreenBitDepth <<")\n";
00366           exit(1);
00367       }
00368 
00369       // I'd prefer to CreateWindow after DisplayChange in case it messes up GL somehow,
00370       // but I need the window's black background to cover up the desktop during the mode change
00371       _mwindow = CreateWindow(WCR_WINDOWCLASSNAME, _props._title.c_str(),
00372                 window_style,0,0,dwWidth,dwHeight,hDesktopWindow, NULL, hinstance, 0);
00373 
00374       // move window to top of zorder,
00375       SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
00376 
00377       ShowWindow(_mwindow, SW_SHOWNORMAL);
00378       ShowWindow(_mwindow, SW_SHOWNORMAL);
00379 
00380       int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
00381 
00382       if (chg_result!=DISP_CHANGE_SUCCESSFUL) {
00383             wcrdisplay_cat.fatal() << "ChangeDisplaySettings failed (error code: " << chg_result <<") for specified res (" << dwWidth << " X " << dwHeight << " X " << dwFullScreenBitDepth <<"), " << dm.dmDisplayFrequency  << "Hz\n";
00384             exit(1);
00385       }
00386 
00387       _pCurrent_display_settings = new(DEVMODE);
00388       memcpy(_pCurrent_display_settings,&dm,sizeof(DEVMODE));
00389 
00390       _props._xorg = 0;
00391       _props._yorg = 0;
00392       _props._xsize = dwWidth;
00393       _props._ysize = dwHeight;
00394 
00395        if (wcrdisplay_cat.is_debug())
00396            wcrdisplay_cat.debug() << "set fullscreen mode at res (" << dwWidth << " X " << dwHeight << " X " << dwFullScreenBitDepth <<"), " << dm.dmDisplayFrequency  << "Hz\n";
00397   } else {
00398 
00399         RECT win_rect;
00400         SetRect(&win_rect, _props._xorg,  _props._yorg, _props._xorg + _props._xsize,
00401                 _props._yorg + _props._ysize);
00402 
00403         if (_props._border) {
00404             window_style |= WS_OVERLAPPEDWINDOW;
00405         }
00406 
00407         BOOL bRes = AdjustWindowRect(&win_rect, window_style, FALSE);  //compute window size based on desired client area size
00408 
00409         if (!bRes) {
00410             wcrdisplay_cat.fatal() << "AdjustWindowRect failed!" << endl;
00411             exit(1);
00412         }
00413 
00414         // make sure origin is on screen, slide far bounds over if necessary
00415         if (win_rect.left < 0) {
00416             win_rect.right += abs(win_rect.left); win_rect.left = 0;
00417         }
00418         if (win_rect.top < 0) {
00419             win_rect.bottom += abs(win_rect.top); win_rect.top = 0;
00420         }
00421 
00422         _mwindow = CreateWindow(WCR_WINDOWCLASSNAME, _props._title.c_str(),
00423                                 window_style, win_rect.left, win_rect.top, win_rect.right-win_rect.left,
00424                                 win_rect.bottom-win_rect.top,
00425                                 NULL, NULL, hinstance, 0);
00426   }
00427 
00428   if (!_mwindow) {
00429         wcrdisplay_cat.fatal() << "CreateWindow() failed!" << endl;
00430         PrintErrorMessage(LAST_ERROR);
00431         exit(1);
00432   }
00433 
00434   // Determine the initial open status of the IME.
00435   _ime_open = false;
00436   HIMC hIMC = ImmGetContext(_mwindow);
00437   if (hIMC != 0) {
00438     _ime_open = (ImmGetOpenStatus(hIMC) != 0);
00439     ImmReleaseContext(_mwindow, hIMC);
00440   }
00441 
00442   hwnd_pandawin_map[_mwindow] = this;
00443   global_wcrwinptr = NULL;  // get rid of any reference to this obj
00444 
00445   // move window to top of zorder
00446   SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER);
00447 
00448   _hdc = GetDC(_mwindow);
00449 
00450   // Configure the framebuffer according to parameters specified in _props
00451   // Initializes _pixelformat
00452   int pfnum=choose_visual();
00453 
00454   if (gl_forced_pixfmt!=0) {
00455     if (wcrdisplay_cat.is_debug())
00456       wcrdisplay_cat.debug() << "overriding pixfmt choice algorithm (" << pfnum << ") with gl-force-pixfmt("<<gl_forced_pixfmt<< ")\n";
00457     pfnum=gl_forced_pixfmt;
00458   }
00459 
00460   //  int pfnum=ChoosePixelFormat(_hdc, _pixelformat);
00461   if (wcrdisplay_cat.is_debug())
00462      wcrdisplay_cat.debug() << "config() - picking pixfmt #"<< pfnum <<endl;
00463 
00464   if (!SetPixelFormat(_hdc, pfnum, &_pixelformat)) {
00465     wcrdisplay_cat.fatal()
00466       << "config() - SetPixelFormat("<< pfnum << ") failed after window create" << endl;
00467     exit(1);
00468   }
00469 
00470   // Initializes _colormap
00471   setup_colormap();
00472 
00473   _context = chromium.CreateContext(_hdc, CR_RGB_BIT | CR_DOUBLE_BIT);
00474   if (!_context) {
00475     wcrdisplay_cat.fatal()
00476       << "config() - failed to create Win32 rendering context" << endl;
00477     exit(1);
00478   }
00479 
00480   // need to do twice to override any minimized flags in StartProcessInfo
00481   ShowWindow(_mwindow, SW_SHOWNORMAL);
00482   ShowWindow(_mwindow, SW_SHOWNORMAL);
00483 
00484   // Enable detection of mouse input
00485   enable_mouse_input(true);
00486   enable_mouse_motion(true);
00487   enable_mouse_passive_motion(true);
00488 
00489   // Now indicate that we have our keyboard/mouse device ready.
00490   GraphicsWindowInputDevice device =
00491     GraphicsWindowInputDevice::pointer_and_keyboard("keyboard/mouse");
00492   _input_devices.push_back(device);
00493 
00494   // Create a GSG to manage the graphics
00495   // First make the new context and window the current one so GL knows how
00496   // to configure itself in the gsg
00497   make_current();
00498   make_gsg();
00499 
00500   check_for_color_cursor_support();
00501 
00502   //PT(crGraphicsStateGuardian) crgsg = DCAST(CRGraphicsStateGuardian, _gsg);
00503 
00504   string tmpstr((char*)chromium.GetString(GL_EXTENSIONS));
00505 
00506   _extensions_str = tmpstr;
00507 
00508   PFNWCRGETEXTENSIONSSTRINGEXTPROC wcrGetExtensionsStringEXT = NULL;
00509   PFNWCRGETEXTENSIONSSTRINGARBPROC wcrGetExtensionsStringARB = NULL;
00510 
00511   #if 0 //[
00512   if (!support_wiregl) {
00513     wcrGetExtensionsStringARB = (PFNWCRGETEXTENSIONSSTRINGARBPROC)chromium.GetProcAddress("wcrGetExtensionsStringARB");
00514     wcrGetExtensionsStringEXT = (PFNWCRGETEXTENSIONSSTRINGEXTPROC)chromium.GetProcAddress("wcrGetExtensionsStringEXT");
00515   }
00516   #endif //]
00517 
00518   if (wcrGetExtensionsStringARB!=NULL) {
00519        _extensions_str += " ";
00520        //TODO: const char *ARBextensions = wcrGetExtensionsStringARB(chromium.GetCurrentDC());
00521        const char *ARBextensions = wcrGetExtensionsStringARB(NULL);
00522        _extensions_str.append(ARBextensions);
00523   }
00524 
00525   if (wcrGetExtensionsStringEXT!=NULL) {
00526       // usually this will be the same as ARB extensions, but whatever
00527       _extensions_str += " ";
00528       const char *EXTextensions = wcrGetExtensionsStringEXT();
00529       _extensions_str.append(EXTextensions);
00530   }
00531 
00532   if (wcrdisplay_cat.is_spam())
00533      wcrdisplay_cat.spam() << "GL extensions: " << _extensions_str << endl;
00534 
00535   #if 0 //[
00536   if (gl_sync_video) {
00537       // set swapbuffers to swap no more than once per monitor refresh
00538       // note sometimes the ICD advertises this ext, but it still doesn't seem to work
00539       if (_extensions_str.find("WCR_EXT_swap_control")!=_extensions_str.npos) {
00540            PFNWCRSWAPINTERVALEXTPROC wcrSwapIntervalEXT;
00541            wcrSwapIntervalEXT = (PFNWCRSWAPINTERVALEXTPROC) chromium.GetProcAddress("wcrSwapIntervalEXT");
00542            if (wcrSwapIntervalEXT!=NULL)
00543                wcrSwapIntervalEXT(1);
00544 
00545            if (wcrdisplay_cat.is_spam())
00546                wcrdisplay_cat.spam() << "setting swapbuffer interval to 1/refresh\n";
00547       }
00548   }
00549   #endif //]
00550 
00551   if (gl_show_fps_meter) {
00552 
00553       _start_time = timeGetTime();
00554       _current_fps = 0.0;
00555       _start_frame_count = _cur_frame_count = 0;
00556 
00557      // 128 enough to handle all the ascii chars
00558      // this creates a display list for each char.  displist numbering starts
00559      // at FONT_BITMAP_OGLDISPLAYLISTNUM.  Might want to optimize just to save
00560      // mem by just allocing bitmaps for chars we need (0-9 fps,SPC)
00561      
00562      //TODO: chromium.UseFontBitmaps(_hdc, 0, 128, FONT_BITMAP_OGLDISPLAYLISTNUM);
00563   }
00564 
00565   if (wcrdisplay_cat.is_info()) {
00566      const char *vendStr=(const char *) chromium.GetString(GL_VENDOR);
00567      const char *rendStr=(const char *) chromium.GetString(GL_RENDERER);
00568      const char *versStr=(const char *) chromium.GetString(GL_VERSION);
00569 
00570      // Note:  glGetString will never return a valid value until you do chromium.MakeCurrent
00571 
00572      if (vendStr!=NULL) {
00573          wcrdisplay_cat.info()
00574               << "GL_VENDOR: " <<  vendStr
00575               << "  GL_RENDERER: " << ((rendStr==NULL) ? "" : rendStr)
00576               << "  GL_VERSION: " <<  ((versStr==NULL) ? "" : versStr) << endl;
00577       } else {
00578          wcrdisplay_cat.info() << "chromium.GetString(GL_VENDOR) returns NULL!\n";
00579       }
00580   }
00581 }
00582 
00583 void wcrGraphicsWindow::
00584 check_for_color_cursor_support() {
00585     // card support for non-black/white GDI cursors varies greatly.  if the cursor is not supported,
00586     // it is rendered in software by GDI, which causes a flickering effect (because it's not synced
00587     // with flip?).  GDI transparently masks what's happening so there is no easy way for app to detect
00588     // if HW cursor support exists.  alternatives are to tie cursor motion to frame rate using DDraw blts
00589     // or overlays, or to have separate thread draw cursor (sync issues?).  instead we do mono cursor
00590     // unless card is known to support 256 color cursors
00591 
00592     string windows_color_cursor_filename = get_color_cursor_filename_2().to_os_specific();
00593     if (windows_color_cursor_filename.empty())
00594        return;
00595 
00596     bool bSupportsColorCursor=false;
00597     const GLubyte *vendorname=chromium.GetString(GL_VENDOR);
00598     if (vendorname==NULL) {
00599         return;
00600     }
00601     char vendorstr[500];
00602     strncpy(vendorstr,(const char *)vendorname,sizeof(vendorstr));
00603     _strlwr(vendorstr);
00604     if (strstr(vendorstr,"nvidia")!=NULL)
00605         bSupportsColorCursor=true;
00606 
00607     // for now, just assume only nvidia supports color. need to add more checks for other cards
00608     // like in DX l8r.
00609 
00610     if (bSupportsColorCursor) {
00611         // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings)
00612         // if icon is more than 8bpp (because it was 'mapping' 16bpp colors to the device?)
00613 
00614         DWORD load_flags = LR_LOADFROMFILE;
00615 
00616         if (_props._fullscreen) {
00617           // I think cursors should use LR_CREATEDIBSECTION since they should not be mapped to the device palette (in the case of 256-color cursors)
00618           // since they are not going to be used on the desktop
00619           load_flags |= LR_CREATEDIBSECTION;
00620 
00621           // note: this is still doing weird stuff when it loads 8bpp colors, even with LR_CREATEDIBSECTION
00622           // there is still a bug here  BUGBUG
00623         }
00624 
00625         // loads a .cur fmt file
00626         HCURSOR hNewMouseCursor = (HCURSOR) LoadImage(NULL, windows_color_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, load_flags);
00627 
00628         if (hNewMouseCursor==NULL) {
00629             wcrdisplay_cat.warning() << "windows color cursor filename '" << windows_color_cursor_filename << "' not found!!\n";
00630             return;
00631         }
00632 
00633         SetClassLongPtr(_mwindow, GCLP_HCURSOR, (LONG_PTR) hNewMouseCursor);
00634         SetCursor(hNewMouseCursor);
00635 
00636         if (_bLoadedCustomCursor)
00637            DestroyCursor(_hMouseCursor);
00638         _hMouseCursor = hNewMouseCursor;
00639 
00640         if (wcrdisplay_cat.is_spam())
00641             wcrdisplay_cat.spam() << "loaded color cursor\n";
00642     }
00643 }
00644 
00645 ////////////////////////////////////////////////////////////////////
00646 //     Function: Constructor
00647 //       Access:
00648 //  Description:
00649 ////////////////////////////////////////////////////////////////////
00650 wcrGraphicsWindow::
00651 wcrGraphicsWindow(GraphicsPipe* pipe) : GraphicsWindow(pipe) {
00652   config();
00653 }
00654 
00655 ////////////////////////////////////////////////////////////////////
00656 //     Function: Constructor
00657 //       Access:
00658 //  Description:
00659 ////////////////////////////////////////////////////////////////////
00660 wcrGraphicsWindow::
00661 wcrGraphicsWindow(GraphicsPipe* pipe, const
00662     GraphicsWindow::Properties& props) : GraphicsWindow(pipe, props) {
00663   config();
00664 }
00665 
00666 #ifdef _DEBUG
00667 void PrintPFD(PIXELFORMATDESCRIPTOR *pfd,char *msg) {
00668 
00669   OGLDriverType drvtype;
00670   if ((pfd->dwFlags & PFD_GENERIC_ACCELERATED) && (pfd->dwFlags & PFD_GENERIC_FORMAT))
00671       drvtype=MCD;
00672    else if (!(pfd->dwFlags & PFD_GENERIC_ACCELERATED) && !(pfd->dwFlags & PFD_GENERIC_FORMAT))
00673       drvtype=ICD;
00674    else {
00675      drvtype=Software;
00676    }
00677 
00678 #define PrintFlag(FLG) ((pfd->dwFlags &  PFD_##FLG) ? (" PFD_" #FLG "|") : "")
00679   wcrdisplay_cat.spam() << "================================\n";
00680 
00681   wcrdisplay_cat.spam() << msg << ", " << OGLDrvStrings[drvtype] << " driver\n"
00682                          << "PFD flags: 0x" << (void*)pfd->dwFlags << " (" <<
00683                         PrintFlag(GENERIC_ACCELERATED) <<
00684                         PrintFlag(GENERIC_FORMAT) <<
00685                         PrintFlag(DOUBLEBUFFER) <<
00686                         PrintFlag(SUPPORT_OPENGL) <<
00687                         PrintFlag(SUPPORT_GDI) <<
00688                         PrintFlag(STEREO) <<
00689                         PrintFlag(DRAW_TO_WINDOW) <<
00690                         PrintFlag(DRAW_TO_BITMAP) <<
00691                         PrintFlag(SWAP_EXCHANGE) <<
00692                         PrintFlag(SWAP_COPY) <<
00693                         PrintFlag(SWAP_LAYER_BUFFERS) <<
00694                         PrintFlag(NEED_PALETTE) <<
00695                         PrintFlag(NEED_SYSTEM_PALETTE) <<
00696                         PrintFlag(SUPPORT_DIRECTDRAW) << ")\n"
00697                          << "PFD iPixelType: " << ((pfd->iPixelType==PFD_TYPE_RGBA) ? "PFD_TYPE_RGBA":"PFD_TYPE_COLORINDEX") << endl
00698                          << "PFD cColorBits: " << (DWORD)pfd->cColorBits << "  R: " << (DWORD)pfd->cRedBits <<" G: " << (DWORD)pfd->cGreenBits <<" B: " << (DWORD)pfd->cBlueBits << endl
00699                          << "PFD cAlphaBits: " << (DWORD)pfd->cAlphaBits << "  DepthBits: " << (DWORD)pfd->cDepthBits <<" StencilBits: " << (DWORD)pfd->cStencilBits <<" AccumBits: " << (DWORD)pfd->cAccumBits << endl;
00700 }
00701 #endif
00702 
00703 ////////////////////////////////////////////////////////////////////
00704 //     Function: choose visual
00705 //       Access:
00706 //  Description:
00707 ////////////////////////////////////////////////////////////////////
00708 int wcrGraphicsWindow::choose_visual() {
00709 
00710   int mask = _props._mask;
00711   int want_depth_bits = _props._want_depth_bits;
00712   int want_color_bits = _props._want_color_bits;
00713   OGLDriverType drvtype;
00714 
00715   if (mask & W_MULTISAMPLE) {
00716     wcrdisplay_cat.info()
00717       << "config() - multisample not supported"<< endl;
00718     mask &= ~W_MULTISAMPLE;
00719   }
00720     wcrdisplay_cat.info()
00721       << "mask =0x" << (void*) mask
00722     << endl;
00723 
00724   PIXELFORMATDESCRIPTOR pfd;
00725   ZeroMemory(&pfd,sizeof(PIXELFORMATDESCRIPTOR));
00726   pfd.nSize=sizeof(PIXELFORMATDESCRIPTOR);
00727   pfd.nVersion=1;
00728 
00729 //  if (_props._fullscreen) {
00730 //  do anything different for fullscrn?
00731 
00732   // just use the pixfmt of the current desktop
00733 
00734   int MaxPixFmtNum=DescribePixelFormat(_hdc, 1, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
00735   int cur_bpp=GetDeviceCaps(_hdc,BITSPIXEL);
00736   int pfnum;
00737 
00738 #ifdef _DEBUG
00739   if (wcrdisplay_cat.is_debug()) {
00740     for(pfnum=1;pfnum<=MaxPixFmtNum;pfnum++) {
00741       DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
00742 
00743       if ((pfd.dwFlags & PFD_GENERIC_ACCELERATED) && (pfd.dwFlags & PFD_GENERIC_FORMAT))
00744           drvtype=MCD;
00745        else if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && !(pfd.dwFlags & PFD_GENERIC_FORMAT))
00746           drvtype=ICD;
00747        else {
00748          drvtype=Software;
00749          continue;  // skipping all SW fmts
00750        }
00751 
00752        // use wcrinfo.exe instead
00753        char msg[200];
00754        sprintf(msg,"GL PixelFormat[%d]",pfnum);
00755        PrintPFD(&pfd,msg);
00756     }
00757   }
00758 #endif
00759 
00760   for(pfnum=1;pfnum<=MaxPixFmtNum;pfnum++) {
00761       DescribePixelFormat(_hdc, pfnum, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
00762 
00763     // official, nvidia sanctioned way.  should be equiv to my algorithm
00764     if ((pfd.dwFlags & PFD_GENERIC_FORMAT) != 0) {
00765         drvtype = Software;
00766         continue;
00767     }
00768     else if (pfd.dwFlags & PFD_GENERIC_ACCELERATED)
00769         drvtype = MCD;
00770     else
00771         drvtype = ICD;
00772 
00773 #if MY_OLD_ALGORITHM
00774       if ((pfd.dwFlags & PFD_GENERIC_ACCELERATED) && (pfd.dwFlags & PFD_GENERIC_FORMAT))
00775           drvtype=MCD;
00776        else if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && !(pfd.dwFlags & PFD_GENERIC_FORMAT))
00777           drvtype=ICD;
00778        else {
00779          drvtype=Software;
00780          continue;  // skipping all SW fmts
00781        }
00782 #endif
00783 
00784       if (wcrdisplay_cat.is_debug())
00785           wcrdisplay_cat->debug() << "----------------" << endl;
00786 
00787       if ((pfd.iPixelType == PFD_TYPE_COLORINDEX) && !(mask & W_INDEX))
00788           continue;
00789 
00790        DWORD dwReqFlags=(PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW);
00791 
00792        if (wcrdisplay_cat.is_debug()) {
00793          if (mask & W_ALPHA)
00794            wcrdisplay_cat->debug() << "want alpha, pfd says '"
00795                        << (int)(pfd.cAlphaBits) << "'" << endl;
00796          if (mask & W_DEPTH)
00797            wcrdisplay_cat->debug() << "want depth, pfd says '"
00798                        << (int)(pfd.cDepthBits) << "'" << endl;
00799          if (mask & W_STENCIL)
00800            wcrdisplay_cat->debug() << "want stencil, pfd says '"
00801                        << (int)(pfd.cStencilBits) << "'" << endl;
00802          wcrdisplay_cat->debug() << "final flag check "
00803                      << (int)(pfd.dwFlags & dwReqFlags) << " =? "
00804                      << (int)dwReqFlags << endl;
00805          wcrdisplay_cat->debug() << "pfd bits = " << (int)(pfd.cColorBits)
00806                      << endl;
00807          wcrdisplay_cat->debug() << "cur_bpp = " << cur_bpp << endl;
00808        }
00809 
00810        if (mask & W_DOUBLE)
00811            dwReqFlags|= PFD_DOUBLEBUFFER;
00812        if ((mask & W_ALPHA) && (pfd.cAlphaBits==0))
00813            continue;
00814        if ((mask & W_DEPTH) && (pfd.cDepthBits==0))
00815            continue;
00816        if ((mask & W_STENCIL) && (pfd.cStencilBits==0))
00817            continue;
00818 
00819        if ((pfd.dwFlags & dwReqFlags)!=dwReqFlags)
00820            continue;
00821 
00822        // now we ignore the specified want_color_bits for windowed mode
00823        // instead we use the current screen depth
00824 
00825        if ((pfd.cColorBits!=cur_bpp) && (!((cur_bpp==16) && (pfd.cColorBits==15)))
00826                                     && (!((cur_bpp==32) && (pfd.cColorBits==24))))
00827            continue;
00828        // we've passed all the tests, go ahead and pick this fmt
00829        // note: could go continue looping looking for more alpha bits or more depth bits
00830        // so this would pick 16bpp depth buffer, probably not 24bpp
00831 
00832        break;
00833   }
00834 
00835   if (pfnum>MaxPixFmtNum) {
00836       wcrdisplay_cat.error() << "ERROR: couldn't find HW-accelerated OpenGL pixfmt appropriate for this desktop!!\n";
00837       wcrdisplay_cat.error() << "make sure OpenGL driver is installed, and try reducing the screen size\n";
00838       if (cur_bpp>16)
00839         wcrdisplay_cat.error() << "or reducing the desktop screen pixeldepth\n";
00840       exit(1);
00841   }
00842 
00843   #ifdef _DEBUG
00844     char msg[200];
00845     sprintf(msg,"Selected GL PixelFormat is #%d",pfnum);
00846     PrintPFD(&pfd,msg);
00847   #endif
00848 
00849   memcpy(&_pixelformat,&pfd,sizeof(PIXELFORMATDESCRIPTOR));
00850 
00851   return pfnum;
00852 }
00853 
00854 ////////////////////////////////////////////////////////////////////
00855 //     Function: setup_colormap
00856 //       Access:
00857 //  Description:
00858 ////////////////////////////////////////////////////////////////////
00859 void wcrGraphicsWindow::setup_colormap() {
00860 
00861   PIXELFORMATDESCRIPTOR pfd;
00862   LOGPALETTE *logical;
00863   int n;
00864 
00865   /* grab the pixel format */
00866   memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
00867   DescribePixelFormat(_hdc, GetPixelFormat(_hdc),
00868                       sizeof(PIXELFORMATDESCRIPTOR), &pfd);
00869 
00870   if (!(pfd.dwFlags & PFD_NEED_PALETTE ||
00871       pfd.iPixelType == PFD_TYPE_COLORINDEX))
00872     return;
00873 
00874   n = 1 << pfd.cColorBits;
00875 
00876   /* allocate a bunch of memory for the logical palette (assume 256
00877      colors in a Win32 palette */
00878   logical = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
00879                                 sizeof(PALETTEENTRY) * n);
00880   memset(logical, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
00881 
00882   /* set the entries in the logical palette */
00883   logical->palVersion = 0x300;
00884   logical->palNumEntries = n;
00885 
00886   /* start with a copy of the current system palette */
00887   GetSystemPaletteEntries(_hdc, 0, 256, &logical->palPalEntry[0]);
00888 
00889   if (pfd.iPixelType == PFD_TYPE_RGBA) {
00890     int redMask = (1 << pfd.cRedBits) - 1;
00891     int greenMask = (1 << pfd.cGreenBits) - 1;
00892     int blueMask = (1 << pfd.cBlueBits) - 1;
00893     int i;
00894 
00895     /* fill in an RGBA color palette */
00896     for (i = 0; i < n; ++i) {
00897       logical->palPalEntry[i].peRed =
00898         (((i >> pfd.cRedShift)   & redMask)   * 255) / redMask;
00899       logical->palPalEntry[i].peGreen =
00900         (((i >> pfd.cGreenShift) & greenMask) * 255) / greenMask;
00901         logical->palPalEntry[i].peBlue =
00902         (((i >> pfd.cBlueShift)  & blueMask)  * 255) / blueMask;
00903       logical->palPalEntry[i].peFlags = 0;
00904     }
00905   }
00906 
00907   _colormap = CreatePalette(logical);
00908   free(logical);
00909 
00910   SelectPalette(_hdc, _colormap, FALSE);
00911   RealizePalette(_hdc);
00912 }
00913 
00914 ////////////////////////////////////////////////////////////////////
00915 //     Function: end_frame
00916 //       Access:
00917 //  Description: Swaps the front and back buffers.
00918 ////////////////////////////////////////////////////////////////////
00919 void wcrGraphicsWindow::end_frame() {
00920   if (gl_show_fps_meter) {
00921     DO_PSTATS_STUFF(PStatTimer timer(_show_fps_pcollector);)
00922     DWORD now = timeGetTime();  // this is win32 fn
00923 
00924     float time_delta = (now - _start_time) * 0.001f;
00925 
00926     if (time_delta > gl_fps_meter_update_interval) {
00927       // didnt use global clock object, it wasnt working properly when
00928       // I tried, its probably slower due to cache faults, and I can
00929       // easily track all the info I need in dxgsg
00930       DWORD num_frames = _cur_frame_count - _start_frame_count;
00931 
00932       _current_fps = num_frames / time_delta;
00933       _start_time = now;
00934       _start_frame_count = _cur_frame_count;
00935     }
00936 
00937     char fps_msg[15];
00938     sprintf(fps_msg, "%.02f fps", _current_fps);
00939 
00940     // Note: we cant use simple GDI TextOut calls to draw FPS meter
00941     // chars (like DX fps meter) because WCR doesnt support GDI in
00942     // double-buffered mode.  Instead we have to use glBitMap display
00943     // lists created by chromium.UseFontBitmaps
00944 
00945     chromium.Color3f(0.0f,1.0f,1.0f);
00946 
00947     GLboolean tex_was_on = chromium.IsEnabled(GL_TEXTURE_2D);
00948 
00949     if (tex_was_on)
00950       chromium.Disable(GL_TEXTURE_2D);
00951 
00952     chromium.MatrixMode(GL_MODELVIEW);
00953     chromium.PushMatrix();
00954     chromium.LoadIdentity();
00955     chromium.MatrixMode(GL_PROJECTION);
00956     chromium.PushMatrix();
00957     chromium.LoadIdentity();
00958 
00959     chromium.Ortho(0.0f,_props._xsize,
00960             0.0f,_props._ysize,
00961             -1.0f,1.0f);
00962 
00963     chromium.RasterPos2f(_props._xsize-70,_props._ysize-20);  // these seem to be good for default font
00964 
00965     // set up for a string-drawing display list call
00966     chromium.ListBase(FONT_BITMAP_OGLDISPLAYLISTNUM);
00967 
00968     // draw a string using font display lists.  chars index their
00969     // corresponding displist name
00970     chromium.CallLists(strlen(fps_msg), GL_UNSIGNED_BYTE, fps_msg);
00971 
00972     chromium.PopMatrix();
00973     chromium.MatrixMode(GL_MODELVIEW);
00974     chromium.PopMatrix();
00975 
00976     if (tex_was_on)
00977       chromium.Enable(GL_TEXTURE_2D);
00978 
00979     _cur_frame_count++;  // only used by fps meter right now
00980   }
00981 
00982   {
00983     DO_PSTATS_STUFF(PStatTimer timer(_swap_pcollector);)
00984     if (_is_synced)
00985       chromium.Finish();
00986     else {
00987       chromium.SwapBuffers();
00988     }
00989   }
00990   GraphicsWindow::end_frame();
00991 }
00992 
00993 ////////////////////////////////////////////////////////////////////
00994 //     Function: swap
00995 //       Access:
00996 //  Description: Swaps the front and back buffers explicitly.
00997 ////////////////////////////////////////////////////////////////////
00998 void wcrGraphicsWindow::swap() {
00999   if (_is_synced)
01000     chromium.SwapBuffers();
01001 }
01002 
01003 bool wcrGraphicsWindow::resize(unsigned int xsize,unsigned int ysize) {
01004     if (!_props._fullscreen) {
01005         // resizing windowed mode is easy
01006         SetWindowPos(_mwindow, NULL, 0,0, xsize,ysize, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSENDCHANGING);
01007     } else {
01008       DWORD dwWidth =  xsize;
01009       DWORD dwHeight = ysize;
01010 
01011       HWND hDesktopWindow = GetDesktopWindow();
01012       HDC scrnDC=GetDC(hDesktopWindow);
01013       DWORD dwFullScreenBitDepth=GetDeviceCaps(scrnDC,BITSPIXEL);
01014       ReleaseDC(hDesktopWindow,scrnDC);
01015 
01016       // resize will always leave screen bitdepth unchanged
01017 
01018       // allowing resizing of lowvidmem cards to > 640x480.  why?  I'll assume
01019       // check was already done by caller, so he knows what he wants
01020 
01021       DEVMODE dm;
01022       if (!find_acceptable_display_mode(dwWidth,dwHeight,dwFullScreenBitDepth,dm)) {
01023           wcrdisplay_cat.fatal() << "window resize(" << xsize << "," << ysize << ") failed, no compatible fullscreen display mode found!\n";
01024           return false;
01025       }
01026 
01027       // this causes WM_SIZE msg to be produced
01028       SetWindowPos(_mwindow, NULL, 0,0, xsize, ysize, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSENDCHANGING);
01029 
01030       int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
01031 
01032       if (chg_result!=DISP_CHANGE_SUCCESSFUL) {
01033             wcrdisplay_cat.fatal() << "resize ChangeDisplaySettings failed (error code: " << chg_result <<") for specified res (" << dwWidth << " X " << dwHeight << " X " << dwFullScreenBitDepth <<"), " << dm.dmDisplayFrequency  << "Hz\n";
01034             exit(1);
01035       }
01036 
01037       // this assertion could be violated if we eventually allow dynamic fullscrn/windowed mode switching
01038       assert(_pCurrent_display_settings!=NULL);
01039       memcpy(_pCurrent_display_settings,&dm,sizeof(DEVMODE));
01040     }
01041     return true;
01042 }
01043 
01044 unsigned int wcrGraphicsWindow::
01045 verify_window_sizes(unsigned int numsizes,unsigned int *dimen) {
01046   // see if window sizes are supported (i.e. in fullscrn mode)
01047   // dimen is an array containing contiguous x,y pairs specifying
01048   // possible display sizes, it is numsizes*2 long.  fn will zero
01049   // out any invalid x,y size pairs.  return value is number of valid
01050   // sizes that were found.
01051   //
01052   // note: it might be better to implement some sort of query
01053   //       interface that returns an array of supported sizes,
01054   //       but this way is somewhat simpler and will do the job
01055   //       on most cards, assuming they handle the std sizes the app
01056   //       knows about.
01057 
01058   if (!_props._fullscreen || (numsizes==0)) {
01059       return numsizes;
01060   }
01061 
01062   assert(dimen!=NULL);
01063 
01064   HWND hDesktopWindow = GetDesktopWindow();
01065   HDC scrnDC=GetDC(hDesktopWindow);
01066   DWORD dwFullScreenBitDepth=GetDeviceCaps(scrnDC,BITSPIXEL);
01067   ReleaseDC(hDesktopWindow,scrnDC);
01068 
01069   // gonna do an n^2 loop alg for simplicity.  if speed is necessary,
01070   // could do linear time with some kind of STL hash container I guess
01071 
01072   DEVMODE dm;
01073   uint modenum=0;
01074   uint goodmodes=0;
01075   unsigned int *cur_dim_pair=dimen;
01076   for(;modenum<numsizes;modenum++,cur_dim_pair+=2) {
01077       bool bIsGoodmode;
01078       DWORD dwWidth=cur_dim_pair[0];
01079       DWORD dwHeight=cur_dim_pair[1];
01080 
01081       if ((dwWidth==0)||(dwHeight==0)) {
01082           bIsGoodmode=false;
01083       } else {
01084           if (_bIsLowVidMemCard) {
01085               bIsGoodmode=((float)(dwWidth*(float)dwHeight)<=(float)(640*480));
01086           } else {
01087               bIsGoodmode = find_acceptable_display_mode(dwWidth,dwHeight,dwFullScreenBitDepth,dm);
01088           }
01089       }
01090 
01091       if (bIsGoodmode) {
01092          goodmodes++;
01093       } else {
01094          // zero out the bad mode
01095          cur_dim_pair[0]=0;
01096          cur_dim_pair[1]=0;
01097       }
01098   }
01099 
01100   return goodmodes;
01101 }
01102 
01103 ////////////////////////////////////////////////////////////////////
01104 //     Function: handle_reshape
01105 //       Access:
01106 //  Description:
01107 ////////////////////////////////////////////////////////////////////
01108 void wcrGraphicsWindow::handle_reshape() {
01109       RECT view_rect;
01110       GetClientRect(_mwindow, &view_rect);
01111       ClientToScreen(_mwindow, (POINT*)&view_rect.left);   // translates top,left pnt
01112       ClientToScreen(_mwindow, (POINT*)&view_rect.right);  // translates right,bottom pnt
01113 
01114       // change _props xsize,ysize
01115       resized((view_rect.right - view_rect.left),(view_rect.bottom - view_rect.top));
01116 
01117       _props._xorg = view_rect.left;  // _props origin should reflect upper left of view rectangle
01118       _props._yorg = view_rect.top;
01119 
01120       if (wcrdisplay_cat.is_spam()) {
01121           wcrdisplay_cat.spam() << "reshape to origin: (" << _props._xorg << "," << _props._yorg << "), size: (" << _props._xsize << "," << _props._ysize << ")\n";
01122       }
01123 }
01124 
01125 ////////////////////////////////////////////////////////////////////
01126 //     Function: handle_mouse_motion
01127 //       Access:
01128 //  Description:
01129 ////////////////////////////////////////////////////////////////////
01130 void wcrGraphicsWindow::handle_mouse_motion(int x, int y) {
01131   _input_devices[0].set_pointer_in_window(x, y);
01132 }
01133 
01134 ////////////////////////////////////////////////////////////////////
01135 //     Function: handle_mouse_entry
01136 //       Access:
01137 //  Description:
01138 ////////////////////////////////////////////////////////////////////
01139 void wcrGraphicsWindow::handle_mouse_entry(int state) {
01140   if (state == MOUSE_EXITED) {
01141     _input_devices[0].set_pointer_out_of_window();
01142   }
01143 }
01144 
01145 ////////////////////////////////////////////////////////////////////
01146 //     Function: handle_keypress
01147 //       Access:
01148 //  Description:
01149 ////////////////////////////////////////////////////////////////////
01150 void wcrGraphicsWindow::
01151 handle_keypress(ButtonHandle key, int x, int y) {
01152   _input_devices[0].set_pointer_in_window(x, y);
01153   if (key != ButtonHandle::none()) {
01154     _input_devices[0].button_down(key);
01155   }
01156 }
01157 
01158 ////////////////////////////////////////////////////////////////////
01159 //     Function: handle_keyrelease
01160 //       Access:
01161 //  Description:
01162 ////////////////////////////////////////////////////////////////////
01163 void wcrGraphicsWindow::
01164 handle_keyrelease(ButtonHandle key) {
01165   if (key != ButtonHandle::none()) {
01166     _input_devices[0].button_up(key);
01167   }
01168 }
01169 
01170 void INLINE process_1_event() {
01171   MSG msg;
01172 
01173   if (!GetMessage(&msg, NULL, 0, 0)) {
01174       // WM_QUIT received
01175       DestroyAllWindows(false);
01176       exit(msg.wParam);  // this will invoke AtExitFn
01177   }
01178 
01179   // Translate virtual key messages
01180   TranslateMessage(&msg);
01181   // Call window_proc
01182   DispatchMessage(&msg);
01183 }
01184 
01185 void INLINE wcrGraphicsWindow::process_events() {
01186   if (_window_inactive) {
01187       // Get 1 msg at a time until no more are left and we block and sleep,
01188       // or message changes _return_control_to_app or _window_inactive status
01189 
01190       while(_window_inactive && (!_return_control_to_app)) {
01191           process_1_event();
01192       }
01193       _return_control_to_app = false;
01194 
01195   } else {
01196       MSG msg;
01197 
01198       // handle all msgs on queue in a row
01199       while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
01200           process_1_event();
01201       }
01202   }
01203 }
01204 
01205 ////////////////////////////////////////////////////////////////////
01206 //     Function: wcrGraphicsWindow::supports_update
01207 //       Access: Public, Virtual
01208 //  Description: Returns true if this particular kind of
01209 //               GraphicsWindow supports use of the update() function
01210 //               to update the graphics one frame at a time, so that
01211 //               the window does not need to be the program's main
01212 //               loop.  Returns false if the only way to update the
01213 //               window is to call main_loop().
01214 ////////////////////////////////////////////////////////////////////
01215 bool wcrGraphicsWindow::
01216 supports_update() const {
01217   return true;
01218 }
01219 
01220 ////////////////////////////////////////////////////////////////////
01221 //     Function: update
01222 //       Access:
01223 //  Description:
01224 ////////////////////////////////////////////////////////////////////
01225 void wcrGraphicsWindow::update() {
01226 #ifdef DO_PSTATS
01227   _show_code_pcollector.stop();
01228 
01229   if (!_window_inactive) {
01230       PStatClient::main_tick();
01231   }
01232 #endif
01233 
01234   process_events();
01235 
01236   if (_window_inactive) {
01237       // note _window_inactive must be checked after process_events is called, to avoid draw_callback being called
01238       if (_idle_callback)
01239           call_idle_callback();
01240       return;
01241   }
01242 
01243   call_draw_callback(true);
01244 
01245   if (_idle_callback)
01246     call_idle_callback();
01247 
01248 #ifdef DO_PSTATS
01249   _show_code_pcollector.start();
01250 #endif
01251 }
01252 
01253 ////////////////////////////////////////////////////////////////////
01254 //     Function: enable_mouse_input
01255 //       Access:
01256 //  Description:
01257 ////////////////////////////////////////////////////////////////////
01258 void wcrGraphicsWindow::enable_mouse_input(bool val) {
01259   _mouse_input_enabled = val;
01260 }
01261 
01262 ////////////////////////////////////////////////////////////////////
01263 //     Function: enable_mouse_motion
01264 //       Access:
01265 //  Description:
01266 ////////////////////////////////////////////////////////////////////
01267 void wcrGraphicsWindow::enable_mouse_motion(bool val) {
01268   _mouse_motion_enabled = val;
01269 }
01270 
01271 ////////////////////////////////////////////////////////////////////
01272 //     Function: enable_mouse_passive_motion
01273 //       Access:
01274 //  Description:
01275 ////////////////////////////////////////////////////////////////////
01276 void wcrGraphicsWindow::enable_mouse_passive_motion(bool val) {
01277   _mouse_passive_motion_enabled = val;
01278 }
01279 
01280 ////////////////////////////////////////////////////////////////////
01281 //     Function: make_current
01282 //       Access: Public
01283 //  Description:
01284 ////////////////////////////////////////////////////////////////////
01285 void wcrGraphicsWindow::make_current() {
01286   //chromium.MakeCurrent(_hdc, 0, _context);
01287   chromium.MakeCurrent(0, 0, _context);
01288   #if 0 //[
01289   if ((_hdc==NULL)||(_context==NULL)||(_window_inactive)) {
01290       return;  // we're only allow unmake_current() to set this to NULL
01291   }
01292 
01293   DO_PSTATS_STUFF(PStatTimer timer(_make_current_pcollector);)
01294   //HGLRC current_context = GetCurrentContext();
01295   ////GLint current_context = (int)GetCurrentContext();
01296   GLint current_context = 0;
01297   //TODO: HDC current_dc = chromium.GetCurrentDC();
01298   HDC current_dc = NULL;
01299 
01300   if ((current_context != (int)_context) || (current_dc != _hdc)) {
01301     #if 1 //[
01302     chromium.MakeCurrent(_hdc, 0, _context);
01303     #else //][
01304     if (!chromium.MakeCurrent(_hdc, 0, _context)) {
01305         PrintErrorMessage(LAST_ERROR);
01306     }
01307     #endif //]
01308   }
01309   #endif //]
01310 
01311   report_errors();
01312 }
01313 
01314 ////////////////////////////////////////////////////////////////////
01315 //     Function: unmake_current
01316 //       Access: Public
01317 //  Description:
01318 ////////////////////////////////////////////////////////////////////
01319 void wcrGraphicsWindow::unmake_current() {
01320   report_errors();
01321 
01322   #if 1 //[
01323   chromium.MakeCurrent(0, 0, 0);
01324   #else //][
01325   if (!chromium.MakeCurrent(NULL, NULL, 0)) {
01326       PrintErrorMessage(LAST_ERROR);
01327   }
01328   #endif //]
01329 }
01330 
01331 int wcrGraphicsWindow::get_depth_bitwidth() {
01332     return _pixelformat.cDepthBits;
01333 }
01334 
01335 ////////////////////////////////////////////////////////////////////
01336 //     Function: wcrGraphicsWindow::get_gsg_type
01337 //       Access: Public, Virtual
01338 //  Description: Returns the TypeHandle of the kind of GSG preferred
01339 //               by this kind of window.
01340 ////////////////////////////////////////////////////////////////////
01341 TypeHandle wcrGraphicsWindow::
01342 get_gsg_type() const {
01343   return CRGraphicsStateGuardian::get_class_type();
01344 }
01345 
01346 GraphicsWindow *wcrGraphicsWindow::
01347 make_wcrGraphicsWindow(const FactoryParams &params) {
01348   GraphicsWindow::WindowPipe *pipe_param;
01349   if (!get_param_into(pipe_param, params)) {
01350     wcrdisplay_cat.error()
01351       << "No pipe specified for window creation!" << endl;
01352     return NULL;
01353   }
01354 
01355   GraphicsPipe *pipe = pipe_param->get_pipe();
01356 
01357   GraphicsWindow::WindowProps *props_param;
01358   if (!get_param_into(props_param, params)) {
01359     return new wcrGraphicsWindow(pipe);
01360   } else {
01361     return new wcrGraphicsWindow(pipe, props_param->get_properties());
01362   }
01363 }
01364 
01365 TypeHandle wcrGraphicsWindow::get_class_type() {
01366   return _type_handle;
01367 }
01368 
01369 void wcrGraphicsWindow::init_type() {
01370   GraphicsWindow::init_type();
01371   register_type(_type_handle, "wcrGraphicsWindow",
01372         GraphicsWindow::get_class_type());
01373 }
01374 
01375 TypeHandle wcrGraphicsWindow::get_type() const {
01376   return get_class_type();
01377 }
01378 
01379 ////////////////////////////////////////////////////////////////////
01380 //     Function: static_window_proc
01381 //       Access:
01382 //  Description:
01383 ////////////////////////////////////////////////////////////////////
01384 LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
01385    HWND_PANDAWIN_MAP::iterator pwin;
01386    pwin=hwnd_pandawin_map.find(hwnd);
01387 
01388    if (pwin!=hwnd_pandawin_map.end()) {
01389       wcrGraphicsWindow *wcrwinptr=(*pwin).second;
01390       return wcrwinptr->window_proc(hwnd, msg, wparam, lparam);
01391    } else if (global_wcrwinptr!=NULL){
01392        // this stuff should only be used during CreateWindow()
01393        return global_wcrwinptr->window_proc(hwnd, msg, wparam, lparam);
01394    } else {
01395        // should never need this??  (maybe at shutdwn?)
01396        return DefWindowProc(hwnd, msg, wparam, lparam);
01397    }
01398 }
01399 
01400 void wcrGraphicsWindow::deactivate_window() {
01401     // current policy is to suspend minimized or deactivated fullscreen windows, but leave
01402     // regular windows running normally
01403 
01404    if ((!_props._fullscreen) || _exiting_window || _window_inactive || _active_minimized_fullscreen) {
01405        #ifdef _DEBUG
01406           if (wcrdisplay_cat.is_spam())
01407             wcrdisplay_cat.spam()  << "deactivate_window called, but ignored in current mode"  << endl;
01408        #endif
01409      return;
01410    }
01411 
01412    throw_event("PandaPaused"); // right now this is used to signal python event handler to disable audio
01413 
01414    if (!bResponsive_minimized_fullscreen_window) {
01415        if (wcrdisplay_cat.is_spam())
01416            wcrdisplay_cat.spam() << "WCR window deactivated, releasing gl context and waiting...\n";
01417 
01418       _window_inactive = true;
01419       unmake_current();
01420    } else {
01421        _active_minimized_fullscreen = true;
01422        assert(_props._fullscreen);
01423 
01424        if (wcrdisplay_cat.is_spam())
01425            wcrdisplay_cat.spam() << "WCR window minimized from fullscreen mode, remaining active...\n";
01426    }
01427 
01428    // make sure window is minimized
01429 
01430    WINDOWPLACEMENT wndpl;
01431    wndpl.length=sizeof(WINDOWPLACEMENT);
01432 
01433    if (!GetWindowPlacement(_mwindow,&wndpl)) {
01434        wcrdisplay_cat.error() << "GetWindowPlacement failed!\n";
01435        return;
01436    }
01437 
01438    if ((wndpl.showCmd!=SW_MINIMIZE)&&(wndpl.showCmd!=SW_SHOWMINIMIZED)) {
01439        ShowWindow(_mwindow, SW_MINIMIZE);
01440    }
01441 
01442    // revert to default display mode
01443    ChangeDisplaySettings(NULL,0x0);
01444 
01445    if (!bResponsive_minimized_fullscreen_window) {
01446        _PandaPausedTimer = SetTimer(_mwindow,PAUSED_TIMER_ID,1500,NULL);
01447        if (_PandaPausedTimer!=PAUSED_TIMER_ID) {
01448            wcrdisplay_cat.error() << "Error in SetTimer!\n";
01449        }
01450    }
01451 
01452    if (_props._fullscreen) {
01453       throw_event("PandaRestarted");  // right now this is used to signal python event handler to re-enable audio
01454    }
01455 }
01456 
01457 void wcrGraphicsWindow::reactivate_window() {
01458     if (_window_inactive) {
01459         if (wcrdisplay_cat.is_spam())
01460             wcrdisplay_cat.spam() << "WCR window re-activated...\n";
01461 
01462         _window_inactive = false;
01463 
01464         if (_PandaPausedTimer!=NULL) {
01465             KillTimer(_mwindow,_PandaPausedTimer);
01466             _PandaPausedTimer = NULL;
01467         }
01468 
01469         // move window to top of zorder,
01470         SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER);
01471 
01472         ChangeDisplaySettings(_pCurrent_display_settings,CDS_FULLSCREEN);
01473 
01474         GdiFlush();
01475         make_current();
01476     } else if (_active_minimized_fullscreen) {
01477         if (wcrdisplay_cat.is_spam())
01478             wcrdisplay_cat.spam() << "redisplaying minimized fullscrn active WCR window...\n";
01479 
01480         // move window to top of zorder,
01481         SetWindowPos(_mwindow, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER);
01482 
01483         ChangeDisplaySettings(_pCurrent_display_settings,CDS_FULLSCREEN);
01484 
01485         GdiFlush();
01486         make_current();
01487         _active_minimized_fullscreen = false;
01488     }
01489 }
01490 
01491 ////////////////////////////////////////////////////////////////////
01492 //     Function: window_proc
01493 //       Access:
01494 //  Description:
01495 ////////////////////////////////////////////////////////////////////
01496 LONG WINAPI wcrGraphicsWindow::
01497 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
01498   int button = -1;
01499   int x, y;
01500 
01501   switch (msg) {
01502     case WM_CREATE:
01503       break;
01504 
01505     case WM_CLOSE:
01506           close_window();
01507 
01508           // BUGBUG:  right now there is no way to tell the panda app the graphics window is invalid or
01509           //          has been closed by the user, to prevent further methods from being called on the window.
01510           //          this needs to be added to panda for multiple windows to work.  in the meantime, just
01511           //          trigger an exit here if numwindows==0, since that is the expected behavior when all
01512           //          windows are closed (should be done by the app though, and it assumes you only make this
01513           //          type of panda gfx window)
01514 
01515           if (hwnd_pandawin_map.size()==0) {
01516               exit(0);
01517           }
01518           break;
01519 
01520     case WM_MOVE:
01521           // handle all this stuff in EXITSIZEMOVE.  will rendering work during moving?  do we care?
01522           //_props._xorg = LOWORD(lparam);
01523           //_props._yorg = HIWORD(lparam);
01524           break;
01525 
01526 
01527     case WM_ACTIVATEAPP: {
01528             #ifdef _DEBUG
01529               wcrdisplay_cat.spam()  << "WM_ACTIVATEAPP(" << (bool)(wparam!=0) <<") received\n";
01530             #endif
01531 
01532            if (!wparam) {
01533                deactivate_window();
01534                return 0;
01535            }         // dont want to reactivate until window is actually un-minimized (see WM_SIZE)
01536            break;
01537         }
01538 
01539     case WM_EXITSIZEMOVE:
01540             #ifdef _DEBUG
01541               wcrdisplay_cat.spam()  << "WM_EXITSIZEMOVE received"  << endl;
01542             #endif
01543 
01544             reactivate_window();
01545             handle_reshape();
01546             break;
01547 
01548     case WM_ENTERSIZEMOVE:
01549             break;
01550 
01551     case WM_SIZE: {
01552                 DWORD width,height;
01553 
01554                 width = LOWORD(lparam);  height = HIWORD(lparam);
01555             #ifdef _DEBUG
01556                 {
01557                     wcrdisplay_cat.spam() << "WM_SIZE received with width:" << width << "  height: " << height << " flags: " <<
01558                     ((wparam == SIZE_MAXHIDE)? "SIZE_MAXHIDE " : "") << ((wparam == SIZE_MAXSHOW)? "SIZE_MAXSHOW " : "") <<
01559                     ((wparam == SIZE_MINIMIZED)? "SIZE_MINIMIZED " : "") << ((wparam == SIZE_RESTORED)? "SIZE_RESTORED " : "") <<
01560                     ((wparam == SIZE_MAXIMIZED)? "SIZE_MAXIMIZED " : "") << endl;
01561                 }
01562             #endif
01563                 if (_mwindow==NULL)
01564                     break;
01565 
01566                 if ((wparam==SIZE_MAXIMIZED) || (wparam==SIZE_RESTORED)) { // old comment -- added SIZE_RESTORED to handle 3dfx case  (what does this mean?)
01567                      reactivate_window();
01568 
01569 //                  if ((_props._xsize != width) || (_props._ysize != height))
01570                      handle_reshape();
01571                 }
01572                 break;
01573     }
01574 
01575     case WM_PAINT: {
01576           PAINTSTRUCT ps;
01577           BeginPaint(hwnd, &ps);
01578             // glReadBuffer(GL_BACK);  need to copy current rendering to front buffer, a la wdxdisplay?
01579           EndPaint(hwnd, &ps);
01580           return 0;
01581     }
01582 
01583     case WM_IME_NOTIFY:
01584       if (wparam == IMN_SETOPENSTATUS) {
01585         HIMC hIMC = ImmGetContext(hwnd);
01586         nassertr(hIMC != 0, 0);
01587         _ime_open = (ImmGetOpenStatus(hIMC) != 0);
01588         ImmReleaseContext(hwnd, hIMC);
01589       }
01590       break;
01591 
01592     case WM_IME_COMPOSITION:
01593       if (lparam & GCS_RESULTSTR) {
01594         HIMC hIMC = ImmGetContext(hwnd);
01595         nassertr(hIMC != 0, 0);
01596 
01597         static const int max_ime_result = 128;
01598         static char ime_result[max_ime_result];
01599 
01600         DWORD result_size =
01601           ImmGetCompositionStringW(hIMC, GCS_RESULTSTR,
01602                                    ime_result, max_ime_result);
01603         ImmReleaseContext(hwnd, hIMC);
01604 
01605         // Add this string into the text buffer of the application.
01606         wchar_t *ime_wchar_result = (wchar_t *)ime_result;
01607         for (DWORD i = 0; i < result_size / 2; i++) {
01608           _input_devices[0].keystroke(ime_wchar_result[i]);
01609         }
01610       }
01611       break;
01612 
01613     case WM_CHAR:
01614       // Ignore WM_CHAR messages if we have the IME open, since
01615       // everything will come in through WM_IME_COMPOSITION.  (It's
01616       // supposed to come in through WM_CHAR, too, but there seems to
01617       // be a bug in Win2000 in that it only sends question mark
01618       // characters through here.)
01619       if (!_ime_open && !_input_devices.empty()) {
01620         _input_devices[0].keystroke(wparam);
01621       }
01622       break;
01623 
01624     case WM_SYSKEYDOWN:
01625       // want to use defwindproc on Alt syskey so Alt-F4 works, etc
01626       // but do want to bypass defwindproc F10 behavior (it activates
01627       // the main menu, but we have none)
01628       if (wparam == VK_F10) {
01629         return 0;
01630       }
01631       break;
01632 
01633     case WM_KEYDOWN: {
01634             POINT point;
01635 
01636             GetCursorPos(&point);
01637             ScreenToClient(hwnd, &point);
01638 
01639           #ifdef NDEBUG
01640                handle_keypress(lookup_key(wparam), point.x, point.y);
01641           #else
01642             // handle Cntrl-V paste from clipboard
01643             if (!((wparam=='V') && (GetKeyState(VK_CONTROL) < 0))) {
01644                handle_keypress(lookup_key(wparam), point.x, point.y);
01645             } else {
01646                 HGLOBAL   hglb;
01647                 char    *lptstr;
01648 
01649                 if (!IsClipboardFormatAvailable(CF_TEXT))
01650                    return 0;
01651 
01652                 if (!OpenClipboard(NULL))
01653                    return 0;
01654 
01655                 hglb = GetClipboardData(CF_TEXT);
01656                 if (hglb!=NULL) {
01657                     lptstr = (char *) GlobalLock(hglb);
01658                     if (lptstr != NULL)  {
01659                         char *pChar;
01660                         for(pChar=lptstr;*pChar!=NULL;pChar++) {
01661                            handle_keypress(KeyboardButton::ascii_key((uchar)*pChar), point.x, point.y);
01662                         }
01663                         GlobalUnlock(hglb);
01664                     }
01665                 }
01666                 CloseClipboard();
01667             }
01668           #endif
01669               break;
01670     }
01671 
01672     case WM_SYSKEYUP:
01673     case WM_KEYUP:
01674       handle_keyrelease(lookup_key(wparam));
01675       break;
01676 
01677     case WM_LBUTTONDOWN:
01678       button = 0;
01679     case WM_MBUTTONDOWN:
01680       if (button < 0)
01681         button = 1;
01682 
01683     case WM_RBUTTONDOWN:
01684       if (button < 0)
01685         button = 2;
01686       SetCapture(hwnd);
01687       // Win32 doesn't return the same numbers as X does when the mouse
01688       // goes beyond the upper or left side of the window
01689       #define SET_MOUSE_COORD(iVal,VAL) { \
01690             iVal = VAL;                   \
01691             if (iVal & 0x8000)             \
01692               iVal -= 0x10000;            \
01693       }
01694 
01695       SET_MOUSE_COORD(x,LOWORD(lparam));
01696       SET_MOUSE_COORD(y,HIWORD(lparam));
01697 
01698       // make_current();  what does OGL have to do with mouse input??
01699       handle_keypress(MouseButton::button(button), x, y);
01700       break;
01701     case WM_LBUTTONUP:
01702       button = 0;
01703     case WM_MBUTTONUP:
01704       if (button < 0)
01705           button = 1;
01706     case WM_RBUTTONUP:
01707       if (button < 0)
01708           button = 2;
01709       ReleaseCapture();
01710       #if 0
01711           SET_MOUSE_COORD(x,LOWORD(lparam));
01712           SET_MOUSE_COORD(y,HIWORD(lparam));
01713           // make_current();  what does OGL have to do with mouse input??
01714       #endif
01715       handle_keyrelease(MouseButton::button(button));
01716       break;
01717 
01718     case WM_MOUSEMOVE:
01719         SET_MOUSE_COORD(x,LOWORD(lparam));
01720         SET_MOUSE_COORD(y,HIWORD(lparam));
01721 
01722         if (mouse_motion_enabled() &&
01723             (wparam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON))) {
01724             // make_current();  what does OGL have to do with mouse input??
01725             handle_mouse_motion(x, y);
01726         } else if (mouse_passive_motion_enabled() &&
01727                    ((wparam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) == 0)) {
01728                     // make_current();  what does OGL have to do with mouse input??
01729                     handle_mouse_motion(x, y);
01730         }
01731         break;
01732 
01733     case WM_SETFOCUS: {
01734             // wcrdisplay_cat.info() << "got WM_SETFOCUS\n";
01735 
01736             if (_mouse_entry_enabled) {
01737                 make_current();
01738                 handle_mouse_entry(MOUSE_ENTERED);
01739             }
01740 
01741             POINT point;
01742             GetCursorPos(&point);
01743             ScreenToClient(hwnd, &point);
01744 
01745             // this is a hack to make sure common modifier keys have proper state
01746             // since at focus loss, app may never receive key-up event corresponding to
01747             // a key-down. it would be better to know the exact set of ModifierButtons the
01748             // user is using, since we may miss some here
01749 
01750             int i;
01751             for(i=0;i<NUM_MODIFIER_KEYS;i++) {
01752               if (GetKeyState(hardcoded_modifier_buttons[i]) < 0)
01753                 handle_keypress(lookup_key(hardcoded_modifier_buttons[i]),point.x,point.y);
01754             }
01755             return 0;
01756         }
01757 
01758     case WM_KILLFOCUS: {
01759             if (_mouse_entry_enabled)
01760               handle_mouse_entry(MOUSE_EXITED);
01761 
01762             int i;
01763             for(i=0;i<NUM_MODIFIER_KEYS;i++) {
01764               if (GetKeyState(hardcoded_modifier_buttons[i]) < 0)
01765                 handle_keyrelease(lookup_key(hardcoded_modifier_buttons[i]));
01766             }
01767 
01768             return 0;
01769     }
01770     break;
01771 
01772     case WM_TIMER:
01773       if ((wparam==_PandaPausedTimer) && _window_inactive) {
01774          //wcrdisplay_cat.spam() << "returning control to app\n";
01775           _return_control_to_app = true;
01776          // throw_event("PandaPaused");
01777          // do we still need to do this since I return control to app periodically using timer msgs?
01778          // does app need to know to avoid major computation?
01779       }
01780 
01781       break;
01782   }
01783 
01784   return DefWindowProc(hwnd, msg, wparam, lparam);
01785 }
01786 
01787 ////////////////////////////////////////////////////////////////////
01788 //     Function: lookup_key
01789 //       Access:
01790 //  Description:
01791 ////////////////////////////////////////////////////////////////////
01792 ButtonHandle wcrGraphicsWindow::
01793 lookup_key(WPARAM wparam) const {
01794     switch(wparam) {
01795         case VK_BACK: return KeyboardButton::backspace();
01796         case VK_TAB: return KeyboardButton::tab();
01797         case VK_ESCAPE: return KeyboardButton::escape();
01798         case VK_SPACE: return KeyboardButton::space();
01799         case VK_UP: return KeyboardButton::up();
01800         case VK_DOWN: return KeyboardButton::down();
01801         case VK_LEFT: return KeyboardButton::left();
01802         case VK_RIGHT: return KeyboardButton::right();
01803         case VK_PRIOR: return KeyboardButton::page_up();
01804         case VK_NEXT: return KeyboardButton::page_down();
01805         case VK_HOME: return KeyboardButton::home();
01806         case VK_END: return KeyboardButton::end();
01807         case VK_F1: return KeyboardButton::f1();
01808         case VK_F2: return KeyboardButton::f2();
01809         case VK_F3: return KeyboardButton::f3();
01810         case VK_F4: return KeyboardButton::f4();
01811         case VK_F5: return KeyboardButton::f5();
01812         case VK_F6: return KeyboardButton::f6();
01813         case VK_F7: return KeyboardButton::f7();
01814         case VK_F8: return KeyboardButton::f8();
01815         case VK_F9: return KeyboardButton::f9();
01816         case VK_F10: return KeyboardButton::f10();
01817         case VK_F11: return KeyboardButton::f11();
01818         case VK_F12: return KeyboardButton::f12();
01819         case VK_INSERT: return KeyboardButton::insert();
01820         case VK_DELETE: return KeyboardButton::del();
01821         case VK_CAPITAL: return KeyboardButton::caps_lock();
01822         case VK_NUMLOCK: return KeyboardButton::num_lock();
01823         case VK_SCROLL: return KeyboardButton::scroll_lock();
01824         case VK_SNAPSHOT: return KeyboardButton::print_screen();
01825 
01826         case VK_SHIFT:
01827         case VK_LSHIFT:
01828         case VK_RSHIFT:
01829             return KeyboardButton::shift();
01830 
01831         case VK_CONTROL:
01832         case VK_LCONTROL:
01833         case VK_RCONTROL:
01834             return KeyboardButton::control();
01835 
01836         case VK_MENU:
01837         case VK_LMENU:
01838         case VK_RMENU:
01839             return KeyboardButton::alt();
01840 
01841         default:
01842             int key = MapVirtualKey(wparam, 2);
01843             if (isascii(key) && key != 0) {
01844                 bool bCapsLockDown=((GetKeyState(VK_CAPITAL) & 0x1)!=0);
01845                 bool bShiftUp = (GetKeyState(VK_SHIFT) >= 0);
01846                 if (bShiftUp) {
01847                     if (bCapsLockDown)
01848                         key = toupper(key);
01849                     else key = tolower(key);
01850                 } else {
01851                     switch(key) {
01852                         // these keys are unaffected by capslock
01853                         case '1': key = '!'; break;
01854                         case '2': key = '@'; break;
01855                         case '3': key = '#'; break;
01856                         case '4': key = '$'; break;
01857                         case '5': key = '%'; break;
01858                         case '6': key = '^'; break;
01859                         case '7': key = '&'; break;
01860                         case '8': key = '*'; break;
01861                         case '9': key = '('; break;
01862                         case '0': key = ')'; break;
01863                         case '-': key = '_'; break;
01864                         case '=': key = '+'; break;
01865                         case ',': key = '<'; break;
01866                         case '.': key = '>'; break;
01867                         case '/': key = '?'; break;
01868                         case ';': key = ':'; break;
01869                         case '\'': key = '"'; break;
01870                         case '[': key = '{'; break;
01871                         case ']': key = '}'; break;
01872                         case '\\': key = '|'; break;
01873                         case '`': key = '~'; break;
01874                         default:
01875                             if (bCapsLockDown)
01876                                 key = tolower(key);
01877                             else key = toupper(key);
01878                     }
01879                 }
01880                 return KeyboardButton::ascii_key((uchar)key);
01881             }
01882             break;
01883     }
01884     return ButtonHandle::none();
01885 }
01886 
01887 

Generated on Fri May 2 00:44:41 2003 for Panda by doxygen1.3