diff --git a/panda/src/wdxdisplay/config_wdxdisplay.cxx b/panda/src/wdxdisplay/config_wdxdisplay.cxx index ca09b53c92..e7de162042 100644 --- a/panda/src/wdxdisplay/config_wdxdisplay.cxx +++ b/panda/src/wdxdisplay/config_wdxdisplay.cxx @@ -70,8 +70,12 @@ Filename get_icon_filename() { return ExecutionEnvironment::expand_string(iconname); } -// cant use global var cleanly because global var static init executed after init_libwdxdisplay(), incorrectly reiniting var -Filename get_cursor_filename() { - string cursorname = config_wdxdisplay.GetString("win32-cursor",""); +Filename get_color_cursor_filename() { + string cursorname = config_wdxdisplay.GetString("win32-color-cursor",""); + return ExecutionEnvironment::expand_string(cursorname); +} + +Filename get_mono_cursor_filename() { + string cursorname = config_wdxdisplay.GetString("win32-mono-cursor",""); return ExecutionEnvironment::expand_string(cursorname); } diff --git a/panda/src/wdxdisplay/config_wdxdisplay.h b/panda/src/wdxdisplay/config_wdxdisplay.h index d3ef06c93a..1e6e60e8c9 100644 --- a/panda/src/wdxdisplay/config_wdxdisplay.h +++ b/panda/src/wdxdisplay/config_wdxdisplay.h @@ -28,7 +28,8 @@ NotifyCategoryDecl(wdxdisplay, EXPCL_PANDADX, EXPTP_PANDADX); extern bool bResponsive_minimized_fullscreen_window; extern bool dx_force_16bpp_zbuffer; extern Filename get_icon_filename(); -extern Filename get_cursor_filename(); +extern Filename get_mono_cursor_filename(); +extern Filename get_color_cursor_filename(); extern EXPCL_PANDADX void init_libwdxdisplay(); diff --git a/panda/src/wdxdisplay/wdxGraphicsWindow.cxx b/panda/src/wdxdisplay/wdxGraphicsWindow.cxx index 441b00569c..4cee0b7f02 100644 --- a/panda/src/wdxdisplay/wdxGraphicsWindow.cxx +++ b/panda/src/wdxdisplay/wdxGraphicsWindow.cxx @@ -202,6 +202,9 @@ void wdxGraphicsWindow::DestroyMe(bool bAtExitFnCalled) { } if(_mwindow!=NULL) { + if(_bLoadedCustomCursor && _hMouseCursor!=NULL) + DestroyCursor(_hMouseCursor); + DestroyWindow(_mwindow); hwnd_pandawin_map.erase(_mwindow); _mwindow = NULL; @@ -288,11 +291,18 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { case WM_MOUSEMOVE: if(!DXREADY) break; + + // Win32 doesn't return the same numbers as X does when the mouse + // goes beyond the upper or left side of the window + #define SET_MOUSE_COORD(iVal,VAL) { \ + iVal = VAL; \ + if(iVal & 0x8000) \ + iVal -= 0x10000; \ + } + + SET_MOUSE_COORD(x,LOWORD(lparam)); + SET_MOUSE_COORD(y,HIWORD(lparam)); - x = LOWORD(lparam); - y = HIWORD(lparam); - if(x & 1 << 15) x -= (1 << 16); - if(y & 1 << 15) y -= (1 << 16); if(mouse_motion_enabled() && wparam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) { handle_mouse_motion(x, y); @@ -371,12 +381,8 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if(button < 0) button = 2; SetCapture(hwnd); - // Win32 doesn't return the same numbers as X does when the mouse - // goes beyond the upper or left side of the window - x = LOWORD(lparam); - y = HIWORD(lparam); - if(x & 1 << 15) x -= (1 << 16); - if(y & 1 << 15) y -= (1 << 16); + SET_MOUSE_COORD(x,LOWORD(lparam)); + SET_MOUSE_COORD(y,HIWORD(lparam)); handle_keypress(MouseButton::button(button), x, y); return 0; @@ -393,10 +399,8 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { button = 2; ReleaseCapture(); #if 0 - x = LOWORD(lparam); - y = HIWORD(lparam); - if(x & 1 << 15) x -= (1 << 16); - if(y & 1 << 15) y -= (1 << 16); + SET_MOUSE_COORD(x,LOWORD(lparam)); + SET_MOUSE_COORD(y,HIWORD(lparam)); #endif handle_keyrelease(MouseButton::button(button)); return 0; @@ -876,14 +880,14 @@ void wdxGraphicsWindow::config(void) { wc.hInstance = hinstance; string windows_icon_filename = get_icon_filename().to_os_specific(); - string windows_cursor_filename = get_cursor_filename().to_os_specific(); + string windows_mono_cursor_filename = get_mono_cursor_filename().to_os_specific(); if(!windows_icon_filename.empty()) { // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) // if icon is more than 8bpp // loads a .ico fmt file - wc.hIcon = (HICON) LoadImage(NULL, windows_icon_filename.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE); + wc.hIcon = (HICON) LoadImage(NULL, windows_icon_filename.c_str(), IMAGE_ICON, 0, 0, LR_LOADFROMFILE ); if(wc.hIcon==NULL) { wdxdisplay_cat.warning() << "windows icon filename '" << windows_icon_filename << "' not found!!\n"; @@ -892,16 +896,20 @@ void wdxGraphicsWindow::config(void) { wc.hIcon = NULL; // use default app icon } - if(!windows_cursor_filename.empty()) { + _bLoadedCustomCursor=false; + + if(!windows_mono_cursor_filename.empty()) { // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) // if icon is more than 8bpp // loads a .cur fmt file - _hMouseCursor = (HCURSOR) LoadImage(NULL, windows_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); + _hMouseCursor = (HCURSOR) LoadImage(NULL, windows_mono_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); if(_hMouseCursor==NULL) { - wdxdisplay_cat.warning() << "windows cursor filename '" << windows_cursor_filename << "' not found!!\n"; + wdxdisplay_cat.warning() << "windows cursor filename '" << windows_mono_cursor_filename << "' not found!!\n"; + _hMouseCursor = LoadCursor(NULL, IDC_ARROW); } + _bLoadedCustomCursor=true; } else { _hMouseCursor = LoadCursor(NULL, IDC_ARROW); } @@ -967,12 +975,12 @@ void wdxGraphicsWindow::config(void) { _mouse_motion_enabled = false; _mouse_passive_motion_enabled = false; _mouse_entry_enabled = false; - _entry_state = -1; // Enable detection of mouse input enable_mouse_input(true); enable_mouse_motion(true); enable_mouse_passive_motion(true); + // enable_mouse_entry(true); re-enable this?? // Now indicate that we have our keyboard/mouse device ready. GraphicsWindowInputDevice device = GraphicsWindowInputDevice::pointer_and_keyboard("keyboard/mouse"); @@ -1184,6 +1192,63 @@ verify_window_sizes(unsigned int numsizes,unsigned int *dimen) { return num_valid_modes; } +// imperfect method to ID NVid? could also scan desc str, but that isnt fullproof either +#define IS_NVIDIA(DDDEVICEID) ((DDDEVICEID.dwVendorId==0x10DE) || (DDDEVICEID.dwVendorId==0x12D2)) +#define IS_ATI(DDDEVICEID) (DDDEVICEID.dwVendorId==0x1002) +#define IS_MATROX(DDDEVICEID) (DDDEVICEID.dwVendorId==0x102B) + +void wdxGraphicsWindow:: +check_for_color_cursor_support(void) { + // card support for non-black/white GDI cursors varies greatly. if the cursor is not supported, + // it is rendered in software by GDI, which causes a flickering effect (because it's not synced + // with flip?). GDI transparently masks what's happening so there is no easy way for app to detect + // if HW cursor support exists. alternatives are to tie cursor motion to frame rate using DDraw blts + // or overlays, or to have separate thread draw cursor (sync issues?). instead we do mono cursor + // unless card is known to support 256 color cursors + + string windows_color_cursor_filename = get_color_cursor_filename().to_os_specific(); + if(windows_color_cursor_filename.empty()) + return; + + bool bSupportsColorCursor=false; + + if(IS_NVIDIA(_DXDeviceID)) { + // all nvidia seem to support 256 color + bSupportsColorCursor=true; + } else if(IS_ATI(_DXDeviceID)) { + // radeons seem to be in the 5100 range and support color, assume anything in 6000 or above + // is newer than radeon and supports 256 color + if(((_DXDeviceID.dwDeviceId>=0x5100) && (_DXDeviceID.dwDeviceId<=0x5200)) || + (_DXDeviceID.dwDeviceId>=0x6000)) + bSupportsColorCursor=true; + } else if IS_MATROX(_DXDeviceID) { + if(_DXDeviceID.dwDeviceId==0x0525) // G400 seems to support color cursors, havent tested other matrox + bSupportsColorCursor=true; + } + + // TODO: add more cards as more testing is done + + if(bSupportsColorCursor) { + // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) + // if icon is more than 8bpp + + // loads a .cur fmt file + HCURSOR hNewMouseCursor = (HCURSOR) LoadImage(NULL, windows_color_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); + + if(hNewMouseCursor==NULL) { + wdxdisplay_cat.warning() << "windows color cursor filename '" << windows_color_cursor_filename << "' not found!!\n"; + return; + } + + SetClassLongPtr(_mwindow, GCLP_HCURSOR, (LONG_PTR) hNewMouseCursor); + SetCursor(hNewMouseCursor); + + if(_bLoadedCustomCursor) + DestroyCursor(_hMouseCursor); + _hMouseCursor = hNewMouseCursor; + } +} + //////////////////////////////////////////////////////////////////// // Function: dx_setup // Description: Set up the DirectX environment. The size of the @@ -1193,8 +1258,8 @@ verify_window_sizes(unsigned int numsizes,unsigned int *dimen) { //////////////////////////////////////////////////////////////////// void wdxGraphicsWindow:: dx_setup() { - LPDIRECT3D7 pD3DI; - LPDIRECTDRAW7 pDD; + LPDIRECT3D7 pD3DI; + LPDIRECTDRAW7 pDD; HRESULT hr; DX_DECLARE_CLEAN( DDSURFACEDESC2, SurfaceDesc ); @@ -1242,9 +1307,8 @@ dx_setup() { #ifdef _DEBUG wdxdisplay_cat.debug() << " GfxCard: " << _DXDeviceID.szDescription << "; DriverFile: '" << _DXDeviceID.szDriver << "'; VendorID: " <<_DXDeviceID.dwVendorId <<"; DriverVer: " << HIWORD(_DXDeviceID.liDriverVersion.HighPart) << "." << LOWORD(_DXDeviceID.liDriverVersion.HighPart) << "." << HIWORD(_DXDeviceID.liDriverVersion.LowPart) << "." << LOWORD(_DXDeviceID.liDriverVersion.LowPart) << endl; #endif - - // imperfect method to ID NVid, could also scan desc str, but that isnt fullproof either - #define ISNVIDIA(DDDEVICEID) ((DDDEVICEID.dwVendorId==0x10DE) || (DDDEVICEID.dwVendorId==0x12D2)) + + check_for_color_cursor_support(); // Query DirectDraw for access to Direct3D @@ -1730,7 +1794,7 @@ CreateScreenBuffersAndDevice(DWORD dwRenderWidth, DWORD dwRenderHeight,LPDIRECTD exit(1); } - if(ISNVIDIA(_DXDeviceID)) { + if(IS_NVIDIA(_DXDeviceID)) { DX_DECLARE_CLEAN(DDSURFACEDESC2,ddsd_pri) pPrimaryDDSurf->GetSurfaceDesc(&ddsd_pri); diff --git a/panda/src/wdxdisplay/wdxGraphicsWindow.h b/panda/src/wdxdisplay/wdxGraphicsWindow.h index e621e5d92b..ec1e454fbc 100644 --- a/panda/src/wdxdisplay/wdxGraphicsWindow.h +++ b/panda/src/wdxdisplay/wdxGraphicsWindow.h @@ -94,6 +94,7 @@ protected: void enable_mouse_motion(bool val); void enable_mouse_passive_motion(bool val); void enable_mouse_entry(bool val); + void check_for_color_cursor_support(void); DDDEVICEIDENTIFIER2 _DXDeviceID; public: @@ -107,14 +108,13 @@ private: typedef enum { NotAdjusting,MovingOrResizing,Resizing } WindowAdjustType; WindowAdjustType _WindowAdjustingType; bool _bIsLowVidMemCard; + bool _bLoadedCustomCursor; HCURSOR _hMouseCursor; bool _bSizeIsMaximized; bool _mouse_input_enabled; bool _mouse_motion_enabled; bool _mouse_passive_motion_enabled; bool _mouse_entry_enabled; - int _entry_state; - bool _ignore_key_repeat; bool _exiting_window; bool _window_inactive; bool _active_minimized_fullscreen; diff --git a/panda/src/wgldisplay/config_wgldisplay.cxx b/panda/src/wgldisplay/config_wgldisplay.cxx index 2d83284779..087aaf5d3a 100644 --- a/panda/src/wgldisplay/config_wgldisplay.cxx +++ b/panda/src/wgldisplay/config_wgldisplay.cxx @@ -78,7 +78,12 @@ Filename get_icon_filename_2() { return ExecutionEnvironment::expand_string(iconname); } -Filename get_cursor_filename_2() { - string cursorname = config_wgldisplay.GetString("win32-cursor",""); +Filename get_color_cursor_filename_2() { + string cursorname = config_wgldisplay.GetString("win32-color-cursor",""); + return ExecutionEnvironment::expand_string(cursorname); +} + +Filename get_mono_cursor_filename_2() { + string cursorname = config_wgldisplay.GetString("win32-mono-cursor",""); return ExecutionEnvironment::expand_string(cursorname); } diff --git a/panda/src/wgldisplay/config_wgldisplay.h b/panda/src/wgldisplay/config_wgldisplay.h index c54fee43b1..f354560594 100644 --- a/panda/src/wgldisplay/config_wgldisplay.h +++ b/panda/src/wgldisplay/config_wgldisplay.h @@ -28,7 +28,8 @@ NotifyCategoryDecl(wgldisplay, EXPCL_PANDAGL, EXPTP_PANDAGL); // for some reason there is a conflict with the pandadx versions of get_icon_filename during linking, // so appended '_2' to name extern Filename get_icon_filename_2(); -extern Filename get_cursor_filename_2(); +extern Filename get_color_cursor_filename_2(); +extern Filename get_mono_cursor_filename_2(); extern bool gl_show_fps_meter; extern float gl_fps_meter_update_interval; diff --git a/panda/src/wgldisplay/wglGraphicsWindow.cxx b/panda/src/wgldisplay/wglGraphicsWindow.cxx index 62a52ca170..4da4023e4b 100644 --- a/panda/src/wgldisplay/wglGraphicsWindow.cxx +++ b/panda/src/wgldisplay/wglGraphicsWindow.cxx @@ -21,8 +21,6 @@ #include "config_wgldisplay.h" #include #include -//#include -//#include #include #include #include @@ -32,6 +30,8 @@ #include #include #include +//#include +#include #define WGL_WGLEXT_PROTOTYPES #include "wglext.h" @@ -145,6 +145,9 @@ void wglGraphicsWindow::DestroyMe(bool bAtExitFnCalled) { } if(_mwindow!=NULL) { + if(_bLoadedCustomCursor && _hMouseCursor!=NULL) + DestroyCursor(_hMouseCursor); + DestroyWindow(_mwindow); hwnd_pandawin_map.erase(_mwindow); _mwindow = NULL; @@ -327,7 +330,6 @@ void wglGraphicsWindow::config(void) { _mouse_motion_enabled = false; _mouse_passive_motion_enabled = false; _mouse_entry_enabled = false; - _entry_state = -1; _context = NULL; _hdc = NULL; _window_inactive = false; @@ -345,7 +347,7 @@ void wglGraphicsWindow::config(void) { wc.hInstance = hinstance; string windows_icon_filename = get_icon_filename_2().to_os_specific(); - string windows_cursor_filename = get_cursor_filename_2().to_os_specific(); + string windows_mono_cursor_filename = get_mono_cursor_filename_2().to_os_specific(); if(!windows_icon_filename.empty()) { // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) @@ -361,16 +363,18 @@ void wglGraphicsWindow::config(void) { wc.hIcon = NULL; // use default app icon } - if(!windows_cursor_filename.empty()) { + _bLoadedCustomCursor = false; + if(!windows_mono_cursor_filename.empty()) { // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) // if icon is more than 8bpp // loads a .cur fmt file - _hMouseCursor = (HCURSOR) LoadImage(NULL, windows_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); + _hMouseCursor = (HCURSOR) LoadImage(NULL, windows_mono_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); if(_hMouseCursor==NULL) { - wgldisplay_cat.warning() << "windows cursor filename '" << windows_cursor_filename << "' not found!!\n"; + wgldisplay_cat.warning() << "windows cursor filename '" << windows_mono_cursor_filename << "' not found!!\n"; } + _bLoadedCustomCursor = true; } else { _hMouseCursor = LoadCursor(NULL, IDC_ARROW); } @@ -546,6 +550,8 @@ void wglGraphicsWindow::config(void) { make_current(); make_gsg(); + check_for_color_cursor_support(); + // _glgsg = DCAST(GLGraphicsStateGuardian, _gsg); dont need this now string tmpstr((char*)glGetString(GL_EXTENSIONS)); @@ -613,6 +619,57 @@ void wglGraphicsWindow::config(void) { } } +void wglGraphicsWindow:: +check_for_color_cursor_support(void) { + // card support for non-black/white GDI cursors varies greatly. if the cursor is not supported, + // it is rendered in software by GDI, which causes a flickering effect (because it's not synced + // with flip?). GDI transparently masks what's happening so there is no easy way for app to detect + // if HW cursor support exists. alternatives are to tie cursor motion to frame rate using DDraw blts + // or overlays, or to have separate thread draw cursor (sync issues?). instead we do mono cursor + // unless card is known to support 256 color cursors + + string windows_color_cursor_filename = get_color_cursor_filename_2().to_os_specific(); + if(windows_color_cursor_filename.empty()) + return; + + bool bSupportsColorCursor=false; + const GLubyte *vendorname=glGetString(GL_VENDOR); + if(vendorname==NULL) { + return; + } + char vendorstr[500]; + strncpy(vendorstr,(const char *)vendorname,sizeof(vendorstr)); + _strlwr(vendorstr); + if(strstr(vendorstr,"nvidia")!=NULL) + bSupportsColorCursor=true; + + // for now, just assume only nvidia supports color. need to add more checks for other cards + // like in DX l8r. + + if(bSupportsColorCursor) { + // Note: LoadImage seems to cause win2k internal heap corruption (outputdbgstr warnings) + // if icon is more than 8bpp + + // loads a .cur fmt file + HCURSOR hNewMouseCursor = (HCURSOR) LoadImage(NULL, windows_color_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE); + + if(hNewMouseCursor==NULL) { + wgldisplay_cat.warning() << "windows color cursor filename '" << windows_color_cursor_filename << "' not found!!\n"; + return; + } + + SetClassLongPtr(_mwindow, GCLP_HCURSOR, (LONG_PTR) hNewMouseCursor); + SetCursor(hNewMouseCursor); + + if(_bLoadedCustomCursor) + DestroyCursor(_hMouseCursor); + _hMouseCursor = hNewMouseCursor; + + if(wgldisplay_cat.is_spam()) + wgldisplay_cat.spam() << "loaded color cursor\n"; + } +} + //////////////////////////////////////////////////////////////////// // Function: Constructor // Access: @@ -1590,18 +1647,22 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { case WM_MBUTTONDOWN: if (button < 0) button = 1; + case WM_RBUTTONDOWN: if (button < 0) button = 2; SetCapture(hwnd); // Win32 doesn't return the same numbers as X does when the mouse // goes beyond the upper or left side of the window - x = LOWORD(lparam); - y = HIWORD(lparam); - if (x & 1 << 15) - x -= (1 << 16); - if (y & 1 << 15) - y -= (1 << 16); + #define SET_MOUSE_COORD(iVal,VAL) { \ + iVal = VAL; \ + if(iVal & 0x8000) \ + iVal -= 0x10000; \ + } + + SET_MOUSE_COORD(x,LOWORD(lparam)); + SET_MOUSE_COORD(y,HIWORD(lparam)); + // make_current(); what does OGL have to do with mouse input?? handle_keypress(MouseButton::button(button), x, y); break; @@ -1615,24 +1676,17 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { button = 2; ReleaseCapture(); #if 0 - x = LOWORD(lparam); - y = HIWORD(lparam); - if (x & 1 << 15) - x -= (1 << 16); - if (y & 1 << 15) - y -= (1 << 16); + SET_MOUSE_COORD(x,LOWORD(lparam)); + SET_MOUSE_COORD(y,HIWORD(lparam)); // make_current(); what does OGL have to do with mouse input?? #endif handle_keyrelease(MouseButton::button(button)); break; case WM_MOUSEMOVE: - x = LOWORD(lparam); - y = HIWORD(lparam); - if (x & 1 << 15) - x -= (1 << 16); - if (y & 1 << 15) - y -= (1 << 16); + SET_MOUSE_COORD(x,LOWORD(lparam)); + SET_MOUSE_COORD(y,HIWORD(lparam)); + if (mouse_motion_enabled() && (wparam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON))) { // make_current(); what does OGL have to do with mouse input?? diff --git a/panda/src/wgldisplay/wglGraphicsWindow.h b/panda/src/wgldisplay/wglGraphicsWindow.h index 378bd6a99b..7fd7e5659f 100644 --- a/panda/src/wgldisplay/wglGraphicsWindow.h +++ b/panda/src/wgldisplay/wglGraphicsWindow.h @@ -118,6 +118,7 @@ private: DEVMODE *_pCurrent_display_settings; bool _bIsLowVidMemCard; + bool _bLoadedCustomCursor; bool _window_inactive; bool _active_minimized_fullscreen; @@ -128,10 +129,6 @@ private: bool _mouse_motion_enabled; bool _mouse_passive_motion_enabled; bool _mouse_entry_enabled; - int _entry_state; - bool _ignore_key_repeat; - int _full_height, _full_width; - // vars for frames/sec meter DWORD _start_time; @@ -157,13 +154,14 @@ public: virtual unsigned int verify_window_sizes(unsigned int numsizes,unsigned int *dimen); protected: - virtual void do_close_window(); + virtual void do_close_window(void); + void check_for_color_cursor_support(void); private: static TypeHandle _type_handle; }; -extern void set_global_parameters(); -extern void restore_global_parameters(); +extern void set_global_parameters(void); +extern void restore_global_parameters(void); #endif