Browse Source

When Input detects screen mode change (initial or otherwise), calculate scaling ratio from SDL window size and Graphics backbuffer size. Scale mouse positions and deltas with the input scale. Inspired by work of Elissa Ross in PR #1725. Related to issue #1252, might resolve it, but not tested on actual Retina hardware.

Lasse Öörni 9 years ago
parent
commit
d229db148c

+ 1 - 1
Source/Urho3D/AngelScript/InputAPI.cpp

@@ -591,7 +591,7 @@ static void RegisterInput(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Input", "int get_qualifiers() const", asMETHOD(Input, GetQualifiers), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_qualifiers() const", asMETHOD(Input, GetQualifiers), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "void set_mousePosition(const IntVector2&in)", asMETHOD(Input, SetMousePosition), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "void set_mousePosition(const IntVector2&in)", asMETHOD(Input, SetMousePosition), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "IntVector2 get_mousePosition() const", asMETHOD(Input, GetMousePosition), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "IntVector2 get_mousePosition() const", asMETHOD(Input, GetMousePosition), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Input", "const IntVector2& get_mouseMove() const", asMETHOD(Input, GetMouseMove), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Input", "IntVector2 get_mouseMove() const", asMETHOD(Input, GetMouseMove), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_mouseMoveX() const", asMETHOD(Input, GetMouseMoveX), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_mouseMoveX() const", asMETHOD(Input, GetMouseMoveX), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_mouseMoveY() const", asMETHOD(Input, GetMouseMoveY), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_mouseMoveY() const", asMETHOD(Input, GetMouseMoveY), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_mouseMoveWheel() const", asMETHOD(Input, GetMouseMoveWheel), asCALL_THISCALL);
     engine->RegisterObjectMethod("Input", "int get_mouseMoveWheel() const", asMETHOD(Input, GetMouseMoveWheel), asCALL_THISCALL);

+ 41 - 11
Source/Urho3D/Input/Input.cpp

@@ -345,6 +345,7 @@ Input::Input(Context* context) :
     minimized_(false),
     minimized_(false),
     focusedThisFrame_(false),
     focusedThisFrame_(false),
     suppressNextMouseMove_(false),
     suppressNextMouseMove_(false),
+    mouseMoveScaled_(false),
     initialized_(false)
     initialized_(false)
 {
 {
     for (int i = 0; i < TOUCHID_MAX; i++)
     for (int i = 0; i < TOUCHID_MAX; i++)
@@ -423,6 +424,10 @@ void Input::Update()
         const int width = graphics_->GetWidth() - buffer * 2;
         const int width = graphics_->GetWidth() - buffer * 2;
         const int height = graphics_->GetHeight() - buffer * 2;
         const int height = graphics_->GetHeight() - buffer * 2;
 
 
+        // SetMousePosition utilizes backbuffer coordinate system, scale now from window coordinates
+        mpos.x_ = (int)(mpos.x_ * inputScale_.x_);
+        mpos.y_ = (int)(mpos.y_ * inputScale_.y_);
+
         bool warp = false;
         bool warp = false;
         if (mpos.x_ < buffer)
         if (mpos.x_ < buffer)
         {
         {
@@ -467,6 +472,7 @@ void Input::Update()
     {
     {
         const IntVector2 mousePosition = GetMousePosition();
         const IntVector2 mousePosition = GetMousePosition();
         mouseMove_ = mousePosition - lastMousePosition_;
         mouseMove_ = mousePosition - lastMousePosition_;
+        mouseMoveScaled_ = true; // Already in backbuffer scale, since GetMousePosition() operates in that
 
 
 #ifndef __EMSCRIPTEN__
 #ifndef __EMSCRIPTEN__
         if (graphics_->GetExternalWindow())
         if (graphics_->GetExternalWindow())
@@ -1364,14 +1370,16 @@ IntVector2 Input::GetMousePosition() const
         return ret;
         return ret;
 
 
     SDL_GetMouseState(&ret.x_, &ret.y_);
     SDL_GetMouseState(&ret.x_, &ret.y_);
+    ret.x_ = (int)(ret.x_ * inputScale_.x_);
+    ret.y_ = (int)(ret.y_ * inputScale_.y_);
 
 
     return ret;
     return ret;
 }
 }
 
 
-const IntVector2& Input::GetMouseMove() const
+IntVector2 Input::GetMouseMove() const
 {
 {
     if (!suppressNextMouseMove_)
     if (!suppressNextMouseMove_)
-        return mouseMove_;
+        return mouseMoveScaled_ ? mouseMove_ : IntVector2((int)(mouseMove_.x_ * inputScale_.x_), (int)(mouseMove_.y_ * inputScale_.y_));
     else
     else
         return IntVector2::ZERO;
         return IntVector2::ZERO;
 }
 }
@@ -1379,7 +1387,7 @@ const IntVector2& Input::GetMouseMove() const
 int Input::GetMouseMoveX() const
 int Input::GetMouseMoveX() const
 {
 {
     if (!suppressNextMouseMove_)
     if (!suppressNextMouseMove_)
-        return mouseMove_.x_;
+        return mouseMoveScaled_ ? mouseMove_.x_ : (int)(mouseMove_.x_ * inputScale_.x_);
     else
     else
         return 0;
         return 0;
 }
 }
@@ -1387,7 +1395,7 @@ int Input::GetMouseMoveX() const
 int Input::GetMouseMoveY() const
 int Input::GetMouseMoveY() const
 {
 {
     if (!suppressNextMouseMove_)
     if (!suppressNextMouseMove_)
-        return mouseMove_.y_;
+        return mouseMoveScaled_ ? mouseMove_.y_ : mouseMove_.y_ * inputScale_.y_;
     else
     else
         return 0;
         return 0;
 }
 }
@@ -1779,7 +1787,7 @@ void Input::SetMousePosition(const IntVector2& position)
     if (!graphics_)
     if (!graphics_)
         return;
         return;
 
 
-    SDL_WarpMouseInWindow(graphics_->GetWindow(), position.x_, position.y_);
+    SDL_WarpMouseInWindow(graphics_->GetWindow(), (int)(position.x_ / inputScale_.x_), (int)(position.y_ / inputScale_.y_));
 }
 }
 
 
 void Input::CenterMousePosition()
 void Input::CenterMousePosition()
@@ -1884,6 +1892,8 @@ void Input::HandleSDLEvent(void* sdlEvent)
         {
         {
             int x, y;
             int x, y;
             SDL_GetMouseState(&x, &y);
             SDL_GetMouseState(&x, &y);
+            x = (int)(x * inputScale_.x_);
+            y = (int)(y * inputScale_.y_);
 
 
             SDL_Event event;
             SDL_Event event;
             event.type = SDL_FINGERDOWN;
             event.type = SDL_FINGERDOWN;
@@ -1905,6 +1915,8 @@ void Input::HandleSDLEvent(void* sdlEvent)
         {
         {
             int x, y;
             int x, y;
             SDL_GetMouseState(&x, &y);
             SDL_GetMouseState(&x, &y);
+            x = (int)(x * inputScale_.x_);
+            y = (int)(y * inputScale_.y_);
 
 
             SDL_Event event;
             SDL_Event event;
             event.type = SDL_FINGERUP;
             event.type = SDL_FINGERUP;
@@ -1934,18 +1946,21 @@ void Input::HandleSDLEvent(void* sdlEvent)
             }
             }
 #endif
 #endif
 
 
+            // Accumulate without scaling for accuracy, needs to be scaled to backbuffer coordinates when asked
             mouseMove_.x_ += evt.motion.xrel;
             mouseMove_.x_ += evt.motion.xrel;
             mouseMove_.y_ += evt.motion.yrel;
             mouseMove_.y_ += evt.motion.yrel;
+            mouseMoveScaled_ = false;
 
 
             if (!suppressNextMouseMove_)
             if (!suppressNextMouseMove_)
             {
             {
                 using namespace MouseMove;
                 using namespace MouseMove;
 
 
                 VariantMap& eventData = GetEventDataMap();
                 VariantMap& eventData = GetEventDataMap();
-                eventData[P_X] = evt.motion.x;
-                eventData[P_Y] = evt.motion.y;
-                eventData[P_DX] = evt.motion.xrel;
-                eventData[P_DY] = evt.motion.yrel;
+                eventData[P_X] = (int)(evt.motion.x * inputScale_.x_);
+                eventData[P_Y] = (int)(evt.motion.y * inputScale_.y_);
+                // The "on-the-fly" motion data needs to be scaled now, though this may reduce accuracy
+                eventData[P_DX] = (int)(evt.motion.xrel * inputScale_.x_);
+                eventData[P_DY] = (int)(evt.motion.yrel * inputScale_.y_);
                 eventData[P_BUTTONS] = mouseButtonDown_;
                 eventData[P_BUTTONS] = mouseButtonDown_;
                 eventData[P_QUALIFIERS] = GetQualifiers();
                 eventData[P_QUALIFIERS] = GetQualifiers();
                 SendEvent(E_MOUSEMOVE, eventData);
                 SendEvent(E_MOUSEMOVE, eventData);
@@ -1956,6 +1971,8 @@ void Input::HandleSDLEvent(void* sdlEvent)
         {
         {
             int x, y;
             int x, y;
             SDL_GetMouseState(&x, &y);
             SDL_GetMouseState(&x, &y);
+            x = (int)(x * inputScale_.x_);
+            y = (int)(y * inputScale_.y_);
 
 
             SDL_Event event;
             SDL_Event event;
             event.type = SDL_FINGERMOTION;
             event.type = SDL_FINGERMOTION;
@@ -1964,8 +1981,8 @@ void Input::HandleSDLEvent(void* sdlEvent)
             event.tfinger.pressure = 1.0f;
             event.tfinger.pressure = 1.0f;
             event.tfinger.x = (float)x / (float)graphics_->GetWidth();
             event.tfinger.x = (float)x / (float)graphics_->GetWidth();
             event.tfinger.y = (float)y / (float)graphics_->GetHeight();
             event.tfinger.y = (float)y / (float)graphics_->GetHeight();
-            event.tfinger.dx = (float)evt.motion.xrel / (float)graphics_->GetWidth();
-            event.tfinger.dy = (float)evt.motion.yrel / (float)graphics_->GetHeight();
+            event.tfinger.dx = (float)evt.motion.xrel * inputScale_.x_ / (float)graphics_->GetWidth();
+            event.tfinger.dy = (float)evt.motion.yrel * inputScale_.y_ / (float)graphics_->GetHeight();
             SDL_PushEvent(&event);
             SDL_PushEvent(&event);
         }
         }
         break;
         break;
@@ -2348,6 +2365,19 @@ void Input::HandleScreenMode(StringHash eventType, VariantMap& eventData)
 
 
     // After setting a new screen mode we should not be minimized
     // After setting a new screen mode we should not be minimized
     minimized_ = (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) != 0;
     minimized_ = (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) != 0;
+
+    // Calculate input coordinate scaling from SDL window to backbuffer ratio
+    int winWidth, winHeight;
+    int gfxWidth = graphics_->GetWidth();
+    int gfxHeight = graphics_->GetHeight();
+    SDL_GetWindowSize(window, &winWidth, &winHeight);
+    if (winWidth > 0 && winHeight > 0 && gfxWidth > 0 && gfxHeight > 0)
+    {
+        inputScale_.x_ = (float)gfxWidth / (float)winWidth;
+        inputScale_.y_ = (float)gfxHeight / (float)winHeight;
+    }
+    else
+        inputScale_ = Vector2::ONE;
 }
 }
 
 
 void Input::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
 void Input::HandleBeginFrame(StringHash eventType, VariantMap& eventData)

+ 7 - 3
Source/Urho3D/Input/Input.h

@@ -212,7 +212,7 @@ public:
     bool RemoveGesture(unsigned gestureID);
     bool RemoveGesture(unsigned gestureID);
     /// Remove all in-memory gestures.
     /// Remove all in-memory gestures.
     void RemoveAllGestures();
     void RemoveAllGestures();
-    /// Set the mouse cursor position.
+    /// Set the mouse cursor position. Uses the backbuffer (Graphics width/height) coordinates.
     void SetMousePosition(const IntVector2& position);
     void SetMousePosition(const IntVector2& position);
     /// Center the mouse position.
     /// Center the mouse position.
     void CenterMousePosition();
     void CenterMousePosition();
@@ -247,10 +247,10 @@ public:
     bool GetQualifierPress(int qualifier) const;
     bool GetQualifierPress(int qualifier) const;
     /// Return the currently held down qualifiers.
     /// Return the currently held down qualifiers.
     int GetQualifiers() const;
     int GetQualifiers() const;
-    /// Return mouse position within window. Should only be used with a visible mouse cursor.
+    /// Return mouse position within window. Should only be used with a visible mouse cursor. Uses the backbuffer (Graphics width/height) coordinates.
     IntVector2 GetMousePosition() const;
     IntVector2 GetMousePosition() const;
     /// Return mouse movement since last frame.
     /// Return mouse movement since last frame.
-    const IntVector2& GetMouseMove() const;
+    IntVector2 GetMouseMove() const;
     /// Return horizontal mouse movement since last frame.
     /// Return horizontal mouse movement since last frame.
     int GetMouseMoveX() const;
     int GetMouseMoveX() const;
     /// Return vertical mouse movement since last frame.
     /// Return vertical mouse movement since last frame.
@@ -393,6 +393,8 @@ private:
     IntVector2 mouseMove_;
     IntVector2 mouseMove_;
     /// Mouse wheel movement since last frame.
     /// Mouse wheel movement since last frame.
     int mouseMoveWheel_;
     int mouseMoveWheel_;
+    /// Input coordinate scaling. Non-unity when window and backbuffer have different sizes (e.g. Retina display.)
+    Vector2 inputScale_;
     /// SDL window ID.
     /// SDL window ID.
     unsigned windowID_;
     unsigned windowID_;
     /// Fullscreen toggle flag.
     /// Fullscreen toggle flag.
@@ -423,6 +425,8 @@ private:
     bool focusedThisFrame_;
     bool focusedThisFrame_;
     /// Next mouse move suppress flag.
     /// Next mouse move suppress flag.
     bool suppressNextMouseMove_;
     bool suppressNextMouseMove_;
+    /// Whether mouse move is accumulated in backbuffer scale or not (when using events directly).
+    bool mouseMoveScaled_;
     /// Initialized flag.
     /// Initialized flag.
     bool initialized_;
     bool initialized_;
 
 

+ 2 - 2
Source/Urho3D/LuaScript/pkgs/Input/Input.pkg

@@ -83,7 +83,7 @@ class Input : public Object
     bool GetQualifierPress(int qualifier) const;
     bool GetQualifierPress(int qualifier) const;
     int GetQualifiers() const;
     int GetQualifiers() const;
     IntVector2 GetMousePosition() const;
     IntVector2 GetMousePosition() const;
-    const IntVector2& GetMouseMove() const;
+    IntVector2 GetMouseMove() const;
     int GetMouseMoveX() const;
     int GetMouseMoveX() const;
     int GetMouseMoveY() const;
     int GetMouseMoveY() const;
     int GetMouseMoveWheel() const;
     int GetMouseMoveWheel() const;
@@ -106,7 +106,7 @@ class Input : public Object
 
 
     tolua_readonly tolua_property__get_set int qualifiers;
     tolua_readonly tolua_property__get_set int qualifiers;
     tolua_property__get_set IntVector2 mousePosition;
     tolua_property__get_set IntVector2 mousePosition;
-    tolua_readonly tolua_property__get_set IntVector2& mouseMove;
+    tolua_readonly tolua_property__get_set IntVector2 mouseMove;
     tolua_readonly tolua_property__get_set int mouseMoveX;
     tolua_readonly tolua_property__get_set int mouseMoveX;
     tolua_readonly tolua_property__get_set int mouseMoveY;
     tolua_readonly tolua_property__get_set int mouseMoveY;
     tolua_readonly tolua_property__get_set int mouseMoveWheel;
     tolua_readonly tolua_property__get_set int mouseMoveWheel;