diff --git a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp index 918bd8e6..7c6d3c9c 100644 --- a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp +++ b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp @@ -29,6 +29,7 @@ IUIScene_AbstractContainerMenu::IUIScene_AbstractContainerMenu() m_pointerPos.y = 0.0f; m_bPointerDrivenByMouse = false; + m_iLastMouseTickTimeNs = -1; } IUIScene_AbstractContainerMenu::~IUIScene_AbstractContainerMenu() @@ -266,6 +267,21 @@ void IUIScene_AbstractContainerMenu::UpdateTooltips() void IUIScene_AbstractContainerMenu::onMouseTick() { + // Frame-rate independent cursor input, normalized to a 60Hz reference frame. + const int64_t kRefFrameNs = 1000000000LL / 60; + const int64_t kMinDeltaNs = 1000000LL; + const int64_t kMaxDeltaNs = 100000000LL; + int64_t iNowNs = System::nanoTime(); + float fFrameScale = 1.0f; + if ( m_iLastMouseTickTimeNs > 0 ) + { + int64_t iDeltaNs = iNowNs - m_iLastMouseTickTimeNs; + if ( iDeltaNs < kMinDeltaNs ) iDeltaNs = kMinDeltaNs; + if ( iDeltaNs > kMaxDeltaNs ) iDeltaNs = kMaxDeltaNs; + fFrameScale = static_cast(iDeltaNs) / static_cast(kRefFrameNs); + } + m_iLastMouseTickTimeNs = iNowNs; + Minecraft *pMinecraft = Minecraft::GetInstance(); if( pMinecraft->localgameModes[getPad()] != nullptr) { @@ -422,10 +438,10 @@ void IUIScene_AbstractContainerMenu::onMouseTick() // The SD/splitscreen scenes are approximately 0.6 times the size of the fullscreen on if(!RenderManager.IsHiDef() || app.GetLocalPlayerCount() > 1) fInputScale *= 0.6f; - fInputX *= fInputScale; - fInputY *= fInputScale; + fInputX *= fInputScale * fFrameScale; + fInputY *= fInputScale * fFrameScale; -#ifdef USE_POINTER_ACCEL +#ifdef USE_POINTER_ACCEL m_fPointerAccelX += fInputX / 50.0f; m_fPointerAccelY += fInputY / 50.0f; @@ -1269,36 +1285,8 @@ void IUIScene_AbstractContainerMenu::onMouseTick() vPointerPos.x -= m_fPointerImageOffsetX; vPointerPos.y -= m_fPointerImageOffsetY; - // Update pointer position. - // 4J-PB - do not allow sub pixel positions or we get broken lines in box edges - - // problem here when sensitivity is low - we'll be moving a sub pixel size, so it'll clamp, and we'll never move. In that case, move 1 pixel - if(fInputDirX!=0.0f) - { - if(fInputDirX==1.0f) - { - vPointerPos.x+=0.999999f; - } - else - { - vPointerPos.x-=0.999999f; - } - } - - if(fInputDirY!=0.0f) - { - if(fInputDirY==1.0f) - { - vPointerPos.y+=0.999999f; - } - else - { - vPointerPos.y-=0.999999f; - } - } - - vPointerPos.x = static_cast(floor(vPointerPos.x + 0.5f)); - vPointerPos.y = static_cast(floor(vPointerPos.y + 0.5f)); + // Keep sub-pixel float state so deltas <1px accumulate across frames; the renderer + // truncates to integer pixels when emitting the Iggy mouse event. m_pointerPos = vPointerPos; adjustPointerForSafeZone(); diff --git a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h index 6710e18f..4a4700f9 100644 --- a/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h +++ b/Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h @@ -145,6 +145,8 @@ protected: int m_iConsectiveInputTicks; + int64_t m_iLastMouseTickTimeNs; + // Used for detecting quick "taps" in a direction, should jump cursor to next slot. enum ETapState {