From 523d838bd4e33369d76ede8bfef22fc564cd54ca Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Sat, 19 Jun 2021 11:52:40 +0100 Subject: [PATCH] Hardware Cursor: Use item hotpoint For a hardware item cursor, set the hotpoint to the center instead of manually setting the cursor position. --- Source/hwcursor.cpp | 32 ++++++++++++++++++++++++++------ Source/inv.cpp | 12 ++++++++---- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/Source/hwcursor.cpp b/Source/hwcursor.cpp index 69641b244..f3a1578f9 100644 --- a/Source/hwcursor.cpp +++ b/Source/hwcursor.cpp @@ -11,6 +11,7 @@ #include "DiabloUI/diabloui.h" +#include "appfat.h" #include "cursor.h" #include "engine.h" #include "utils/display.h" @@ -23,7 +24,23 @@ CursorInfo CurrentCursorInfo; #if SDL_VERSION_ATLEAST(2, 0, 0) SDLCursorUniquePtr CurrentCursor; -void SetHardwareCursor(SDL_Surface *surface) +enum class HotpointPosition { + TopLeft, + Center, +}; + +Point GetHotpointPosition(const SDL_Surface &surface, HotpointPosition position) +{ + switch (position) { + case HotpointPosition::TopLeft: + return { 0, 0 }; + case HotpointPosition::Center: + return { surface.w / 2, surface.h / 2 }; + } + app_fatal("Unhandled enum value"); +} + +void SetHardwareCursor(SDL_Surface *surface, HotpointPosition hotpointPosition) { float scaleX; float scaleY; @@ -33,7 +50,8 @@ void SetHardwareCursor(SDL_Surface *surface) SDLCursorUniquePtr newCursor; if (renderer == nullptr || (scaleX == 1.0F && scaleY == 1.0F)) { - newCursor = SDLCursorUniquePtr { SDL_CreateColorCursor(surface, 0, 0) }; + const Point hotpoint = GetHotpointPosition(*surface, hotpointPosition); + newCursor = SDLCursorUniquePtr { SDL_CreateColorCursor(surface, hotpoint.x, hotpoint.y) }; } else { // SDL does not support BlitScaled from 8-bit to RGBA. SDLSurfaceUniquePtr converted { SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0) }; @@ -42,7 +60,8 @@ void SetHardwareCursor(SDL_Surface *surface) const int scaledH = surface->h * scaleY; // NOLINT(bugprone-narrowing-conversions) SDLSurfaceUniquePtr scaledSurface { SDL_CreateRGBSurfaceWithFormat(0, scaledW, scaledH, 32, SDL_PIXELFORMAT_ARGB8888) }; SDL_BlitScaled(converted.get(), nullptr, scaledSurface.get(), nullptr); - newCursor = SDLCursorUniquePtr { SDL_CreateColorCursor(scaledSurface.get(), 0, 0) }; + const Point hotpoint = GetHotpointPosition(*scaledSurface, hotpointPosition); + newCursor = SDLCursorUniquePtr { SDL_CreateColorCursor(scaledSurface.get(), hotpoint.x, hotpoint.y) }; } SDL_SetCursor(newCursor.get()); CurrentCursor = std::move(newCursor); @@ -50,7 +69,8 @@ void SetHardwareCursor(SDL_Surface *surface) void SetHardwareCursorFromSprite(int pcurs) { - const int outlineWidth = IsItemSprite(pcurs) ? 1 : 0; + const bool isItem = IsItemSprite(pcurs); + const int outlineWidth = isItem ? 1 : 0; int width; int height; @@ -68,7 +88,7 @@ void SetHardwareCursorFromSprite(int pcurs) SDL_SetColorKey(out.surface, 1, TransparentColor); CelDrawCursor(out, { outlineWidth, height - outlineWidth }, pcurs); - SetHardwareCursor(out.surface); + SetHardwareCursor(out.surface, isItem ? HotpointPosition::Center : HotpointPosition::TopLeft); out.Free(); } #endif @@ -92,7 +112,7 @@ void SetHardwareCursor(CursorInfo cursorInfo) // ArtCursor is null while loading the game on the progress screen, // called via palette fade from ShowProgress. if (ArtCursor.surface != nullptr) - SetHardwareCursor(ArtCursor.surface.get()); + SetHardwareCursor(ArtCursor.surface.get(), HotpointPosition::TopLeft); break; case CursorType::Unknown: break; diff --git a/Source/inv.cpp b/Source/inv.cpp index b8049af60..6f50867fb 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -11,6 +11,7 @@ #include "cursor.h" #include "engine/render/cel_render.hpp" #include "engine/render/text_render.hpp" +#include "hwcursor.hpp" #include "minitext.h" #include "options.h" #include "plrmsg.h" @@ -808,8 +809,8 @@ void CheckInvPaste(int pnum, Point cursorPosition) auto &player = plr[pnum]; SetICursor(player.HoldItem._iCurs + CURSOR_FIRSTITEM); - int i = cursorPosition.x + (icursW / 2); - int j = cursorPosition.y + (icursH / 2); + int i = cursorPosition.x + (IsHardwareCursorEnabled() ? 0 : (icursW / 2)); + int j = cursorPosition.y + (IsHardwareCursorEnabled() ? 0 : (icursH / 2)); int sx = icursW28; int sy = icursH28; bool done = false; @@ -1177,7 +1178,7 @@ void CheckInvPaste(int pnum, Point cursorPosition) } CalcPlrInv(pnum, true); if (pnum == myplr) { - if (cn == CURSOR_HAND) + if (cn == CURSOR_HAND && !IsHardwareCursorEnabled()) SetCursorPos(MouseX + (cursW / 2), MouseY + (cursH / 2)); NewCursor(cn); } @@ -1416,7 +1417,10 @@ void CheckInvCut(int pnum, Point cursorPosition, bool automaticMove) holdItem._itype = ITYPE_NONE; } else { NewCursor(holdItem._iCurs + CURSOR_FIRSTITEM); - SetCursorPos(cursorPosition.x - (cursW / 2), MouseY - (cursH / 2)); + if (!IsHardwareCursorEnabled()) { + // For a hardware cursor, we set the "hot point" to the center of the item instead. + SetCursorPos(cursorPosition.x - (cursW / 2), cursorPosition.y - (cursH / 2)); + } } } }