1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-20 19:54:19 +01:00

[d3d9] Make proper use of X/YHotSpot for software cursors

This commit is contained in:
WinterSnowfall 2024-10-11 11:51:27 +03:00 committed by Philip Rebohle
parent 44b682051b
commit 48c57c11e9
5 changed files with 24 additions and 53 deletions

View File

@ -41,8 +41,8 @@ namespace dxvk {
POINT currentPos = { };
::GetCursorPos(&currentPos);
m_sCursor.X = static_cast<UINT>(currentPos.x);
m_sCursor.Y = static_cast<UINT>(currentPos.y);
m_sCursor.X = static_cast<int32_t>(currentPos.x) - m_sCursor.XHotSpot;
m_sCursor.Y = static_cast<int32_t>(currentPos.y) - m_sCursor.YHotSpot;
}
@ -97,8 +97,8 @@ namespace dxvk {
m_sCursor.Width = Width;
m_sCursor.Height = Height;
m_sCursor.X = XHotSpot;
m_sCursor.Y = YHotSpot;
m_sCursor.XHotSpot = XHotSpot;
m_sCursor.YHotSpot = YHotSpot;
m_sCursor.ResetCursor = false;
ShowCursor(m_visible);

View File

@ -10,8 +10,10 @@ namespace dxvk {
struct D3D9_SOFTWARE_CURSOR {
UINT Width = 0;
UINT Height = 0;
UINT X = 0;
UINT Y = 0;
UINT XHotSpot = 0;
UINT YHotSpot = 0;
int32_t X = 0;
int32_t Y = 0;
bool DrawCursor = false;
bool ResetCursor = false;
};

View File

@ -350,6 +350,11 @@ namespace dxvk {
|| (inputHeight && (inputHeight & (inputHeight - 1))))
return D3DERR_INVALIDCALL;
// It makes no sense to have a hotspot outside of the bitmap.
if (XHotSpot > std::max(inputWidth - 1, 0u)
|| YHotSpot > std::max(inputHeight - 1, 0u))
return D3DERR_INVALIDCALL;
D3DPRESENT_PARAMETERS params;
m_implicitSwapchain->GetPresentParameters(&params);
@ -387,55 +392,17 @@ namespace dxvk {
// Set this as our cursor.
return m_cursor.SetHardwareCursor(XHotSpot, YHotSpot, bitmap);
} else {
// The cursor bitmap passed by the application has the potential
// to not be clipped to the correct dimensions, so we need to
// discard any transparent edges and keep only a tight rectangle
// bounded by the cursor's visible edge pixels
uint32_t leftEdge = inputWidth * HardwareCursorFormatSize;
uint32_t topEdge = inputHeight;
uint32_t rightEdge = 0;
uint32_t bottomEdge = 0;
size_t copyPitch = inputWidth * HardwareCursorFormatSize;
std::vector<uint8_t> bitmap(inputHeight * copyPitch, 0);
uint32_t rowPitch = inputWidth * HardwareCursorFormatSize;
for (uint32_t h = 0; h < inputHeight; h++) {
uint32_t rowOffset = h * rowPitch;
for (uint32_t w = 0; w < rowPitch; w += HardwareCursorFormatSize) {
// Examine only pixels with non-zero alpha
if (data[rowOffset + w + 3] != 0) {
if (leftEdge > w) leftEdge = w;
if (topEdge > h) topEdge = h;
if (rightEdge < w) rightEdge = w;
if (bottomEdge < h) bottomEdge = h;
}
}
}
leftEdge /= HardwareCursorFormatSize;
rightEdge /= HardwareCursorFormatSize;
if (leftEdge > rightEdge || topEdge > bottomEdge) {
UnlockImage(cursorTex, 0, 0);
return D3DERR_INVALIDCALL;
}
// Calculate clipped bitmap dimensions
uint32_t clippedInputWidth = rightEdge + 1 - leftEdge + 1;
uint32_t clippedInputHeight = bottomEdge + 1 - topEdge + 1;
// Windows works with a stride of 128, lets respect that.
uint32_t clippedCopyPitch = clippedInputWidth * HardwareCursorFormatSize;
std::vector<uint8_t> clippedBitmap(clippedInputHeight * clippedCopyPitch, 0);
for (uint32_t h = 0; h < clippedInputHeight; h++)
std::memcpy(&clippedBitmap[h * clippedCopyPitch],
&data[(h + topEdge) * lockedBox.RowPitch + leftEdge * HardwareCursorFormatSize], clippedCopyPitch);
for (uint32_t h = 0; h < inputHeight; h++)
std::memcpy(&bitmap[h * copyPitch], &data[h * lockedBox.RowPitch], copyPitch);
UnlockImage(cursorTex, 0, 0);
m_implicitSwapchain->SetCursorTexture(clippedInputWidth, clippedInputHeight, &clippedBitmap[0]);
m_implicitSwapchain->SetCursorTexture(inputWidth, inputHeight, &bitmap[0]);
return m_cursor.SetSoftwareCursor(clippedInputWidth, clippedInputHeight, XHotSpot, YHotSpot);
return m_cursor.SetSoftwareCursor(inputWidth, inputHeight, XHotSpot, YHotSpot);
}
return D3D_OK;
@ -3929,6 +3896,8 @@ namespace dxvk {
if (unlikely(pSoftwareCursor->ResetCursor)) {
pSoftwareCursor->Width = 0;
pSoftwareCursor->Height = 0;
pSoftwareCursor->XHotSpot = 0;
pSoftwareCursor->YHotSpot = 0;
pSoftwareCursor->X = 0;
pSoftwareCursor->Y = 0;
pSoftwareCursor->ResetCursor = false;

View File

@ -758,8 +758,8 @@ namespace dxvk {
}
void D3D9SwapChainEx::SetCursorPosition(UINT X, UINT Y, UINT Width, UINT Height) {
VkOffset2D cursorPosition = { int32_t(X), int32_t(Y) };
void D3D9SwapChainEx::SetCursorPosition(int32_t X, int32_t Y, UINT Width, UINT Height) {
VkOffset2D cursorPosition = { X, Y };
VkExtent2D cursorSize = { uint32_t(Width), uint32_t(Height) };
VkRect2D cursorRect = { cursorPosition, cursorSize };

View File

@ -120,7 +120,7 @@ namespace dxvk {
void SetCursorTexture(UINT Width, UINT Height, uint8_t* pCursorBitmap);
void SetCursorPosition(UINT X, UINT Y, UINT Width, UINT Height);
void SetCursorPosition(int32_t X, int32_t Y, UINT Width, UINT Height);
HRESULT SetDialogBoxMode(bool bEnableDialogs);