Forráskód Böngészése

fix cursor flickering

cxgeorge 24 éve
szülő
commit
c4cb56acff

+ 7 - 3
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);
 }

+ 2 - 1
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();
 

+ 90 - 26
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);
 

+ 2 - 2
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;

+ 7 - 2
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);
 }

+ 2 - 1
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;

+ 79 - 25
panda/src/wgldisplay/wglGraphicsWindow.cxx

@@ -21,8 +21,6 @@
 #include "config_wgldisplay.h"
 #include <keyboardButton.h>
 #include <mouseButton.h>
-//#include <throw_event.h>
-//#include <eventQueue.h>
 #include <glGraphicsStateGuardian.h>
 #include <errno.h>
 #include <time.h>
@@ -32,6 +30,8 @@
 #include <tchar.h>
 #include <map>
 #include <throw_event.h>
+//#include <eventQueue.h>
+#include <string.h>
 
 #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??

+ 5 - 7
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