diff --git a/Source/hwcursor.cpp b/Source/hwcursor.cpp index 6aa68eac3..994141b43 100644 --- a/Source/hwcursor.cpp +++ b/Source/hwcursor.cpp @@ -29,6 +29,27 @@ enum class HotpointPosition { Center, }; +Size ScaledSize(Size size) +{ + if (renderer != nullptr) { + float scaleX; + float scaleY; + SDL_RenderGetScale(renderer, &scaleX, &scaleY); + size.width *= scaleX; // NOLINT(bugprone-narrowing-conversions) + size.height *= scaleY; // NOLINT(bugprone-narrowing-conversions) + } + return size; +} + +bool IsCursorSizeAllowed(Size size) +{ + if (sgOptions.Graphics.nHardwareCursorMaxSize <= 0) + return true; + size = ScaledSize(size); + return size.width <= sgOptions.Graphics.nHardwareCursorMaxSize + && size.height <= sgOptions.Graphics.nHardwareCursorMaxSize; +} + Point GetHotpointPosition(const SDL_Surface &surface, HotpointPosition position) { switch (position) { @@ -42,23 +63,18 @@ Point GetHotpointPosition(const SDL_Surface &surface, HotpointPosition position) bool SetHardwareCursor(SDL_Surface *surface, HotpointPosition hotpointPosition) { - float scaleX; - float scaleY; - if (renderer != nullptr) { - SDL_RenderGetScale(renderer, &scaleX, &scaleY); - } - SDLCursorUniquePtr newCursor; - if (renderer == nullptr || (scaleX == 1.0F && scaleY == 1.0F)) { + const Size size { surface->w, surface->h }; + const Size scaledSize = ScaledSize(size); + + if (size == scaledSize) { 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) }; - const int scaledW = static_cast(surface->w * scaleX); - const int scaledH = static_cast(surface->h * scaleY); - SDLSurfaceUniquePtr scaledSurface { SDL_CreateRGBSurfaceWithFormat(0, scaledW, scaledH, 32, SDL_PIXELFORMAT_ARGB8888) }; + SDLSurfaceUniquePtr scaledSurface { SDL_CreateRGBSurfaceWithFormat(0, scaledSize.width, scaledSize.height, 32, SDL_PIXELFORMAT_ARGB8888) }; SDL_BlitScaled(converted.get(), nullptr, scaledSurface.get(), nullptr); const Point hotpoint = GetHotpointPosition(*scaledSurface, hotpointPosition); newCursor = SDLCursorUniquePtr { SDL_CreateColorCursor(scaledSurface.get(), hotpoint.x, hotpoint.y) }; @@ -73,12 +89,18 @@ bool SetHardwareCursor(SDL_Surface *surface, HotpointPosition hotpointPosition) bool SetHardwareCursorFromSprite(int pcurs) { const bool isItem = IsItemSprite(pcurs); + if (isItem && !sgOptions.Graphics.bHardwareCursorForItems) + return false; + const int outlineWidth = isItem ? 1 : 0; auto size = GetInvItemSize(pcurs); size.width += 2 * outlineWidth; size.height += 2 * outlineWidth; + if (!IsCursorSizeAllowed(size)) + return false; + auto out = Surface::Alloc(size.width, size.height); SDL_SetSurfacePalette(out.surface, Palette); @@ -113,13 +135,18 @@ void SetHardwareCursor(CursorInfo cursorInfo) case CursorType::UserInterface: // ArtCursor is null while loading the game on the progress screen, // called via palette fade from ShowProgress. - if (ArtCursor.surface != nullptr) - CurrentCursorInfo.SetEnabled(SetHardwareCursor(ArtCursor.surface.get(), HotpointPosition::TopLeft)); + if (ArtCursor.surface != nullptr) { + CurrentCursorInfo.SetEnabled( + IsCursorSizeAllowed(Size { ArtCursor.surface->w, ArtCursor.surface->h }) + && SetHardwareCursor(ArtCursor.surface.get(), HotpointPosition::TopLeft)); + } break; case CursorType::Unknown: CurrentCursorInfo.SetEnabled(false); break; } + if (!CurrentCursorInfo.Enabled()) + SetHardwareCursorVisible(false); #endif } diff --git a/Source/options.cpp b/Source/options.cpp index 384ff8121..266ec9cf8 100644 --- a/Source/options.cpp +++ b/Source/options.cpp @@ -168,10 +168,10 @@ void LoadOptions() sgOptions.Graphics.bBlendedTransparancy = GetIniBool("Graphics", "Blended Transparency", true); sgOptions.Graphics.nGammaCorrection = GetIniInt("Graphics", "Gamma Correction", 100); sgOptions.Graphics.bColorCycling = GetIniBool("Graphics", "Color Cycling", true); -#ifndef USE_SDL1 - sgOptions.Graphics.bHardwareCursor = GetIniBool("Graphics", "Hardware Cursor", false); -#else - sgOptions.Graphics.bHardwareCursor = false; +#if SDL_VERSION_ATLEAST(2, 0, 0) + sgOptions.Graphics.bHardwareCursor = GetIniBool("Graphics", "Hardware Cursor", true); + sgOptions.Graphics.bHardwareCursorForItems = GetIniBool("Graphics", "Hardware Cursor For Items", false); + sgOptions.Graphics.nHardwareCursorMaxSize = GetIniInt("Graphics", "Hardware Cursor Maximum Size", 128); #endif sgOptions.Graphics.bFPSLimit = GetIniBool("Graphics", "FPS Limiter", true); sgOptions.Graphics.bShowFPS = (GetIniInt("Graphics", "Show FPS", 0) != 0); @@ -252,8 +252,10 @@ void SaveOptions() SetIniValue("Graphics", "Blended Transparency", sgOptions.Graphics.bBlendedTransparancy); SetIniValue("Graphics", "Gamma Correction", sgOptions.Graphics.nGammaCorrection); SetIniValue("Graphics", "Color Cycling", sgOptions.Graphics.bColorCycling); -#ifndef USE_SDL1 +#if SDL_VERSION_ATLEAST(2, 0, 0) SetIniValue("Graphics", "Hardware Cursor", sgOptions.Graphics.bHardwareCursor); + SetIniValue("Graphics", "Hardware Cursor For Items", sgOptions.Graphics.bHardwareCursorForItems); + SetIniValue("Graphics", "Hardware Cursor Maximum Size", sgOptions.Graphics.nHardwareCursorMaxSize); #endif SetIniValue("Graphics", "FPS Limiter", sgOptions.Graphics.bFPSLimit); SetIniValue("Graphics", "Show FPS", sgOptions.Graphics.bShowFPS); diff --git a/Source/options.h b/Source/options.h index 795b8e0b3..aed0d6e44 100644 --- a/Source/options.h +++ b/Source/options.h @@ -2,6 +2,8 @@ #include +#include + #include "pack.h" namespace devilution { @@ -61,8 +63,14 @@ struct GraphicsOptions { int nGammaCorrection; /** @brief Enable color cycling animations. */ bool bColorCycling; +#if SDL_VERSION_ATLEAST(2, 0, 0) /** @brief Use a hardware cursor (SDL2 only). */ bool bHardwareCursor; + /** @brief Use a hardware cursor for items. */ + bool bHardwareCursorForItems; + /** @brief Maximum width / height for the hardware cursor. Larger cursors fall back to software. */ + int nHardwareCursorMaxSize; +#endif /** @brief Enable FPS Limit. */ bool bFPSLimit; /** @brief Show FPS, even without the -f command line flag. */