You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
3.7 KiB
126 lines
3.7 KiB
#include "hwcursor.hpp" |
|
|
|
#include <cstdint> |
|
#include <tuple> |
|
|
|
#if SDL_VERSION_ATLEAST(2, 0, 0) |
|
#include <SDL_mouse.h> |
|
#include <SDL_render.h> |
|
#include <SDL_surface.h> |
|
#endif |
|
|
|
#include "DiabloUI/diabloui.h" |
|
|
|
#include "appfat.h" |
|
#include "cursor.h" |
|
#include "engine.h" |
|
#include "utils/display.h" |
|
#include "utils/sdl_ptrs.h" |
|
|
|
namespace devilution { |
|
namespace { |
|
CursorInfo CurrentCursorInfo; |
|
|
|
#if SDL_VERSION_ATLEAST(2, 0, 0) |
|
SDLCursorUniquePtr CurrentCursor; |
|
|
|
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"); |
|
} |
|
|
|
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 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 = surface->w * scaleX; // NOLINT(bugprone-narrowing-conversions) |
|
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); |
|
const Point hotpoint = GetHotpointPosition(*scaledSurface, hotpointPosition); |
|
newCursor = SDLCursorUniquePtr { SDL_CreateColorCursor(scaledSurface.get(), hotpoint.x, hotpoint.y) }; |
|
} |
|
if (newCursor == nullptr) |
|
return false; |
|
SDL_SetCursor(newCursor.get()); |
|
CurrentCursor = std::move(newCursor); |
|
return true; |
|
} |
|
|
|
bool SetHardwareCursorFromSprite(int pcurs) |
|
{ |
|
const bool isItem = IsItemSprite(pcurs); |
|
const int outlineWidth = isItem ? 1 : 0; |
|
|
|
auto size = GetInvItemSize(pcurs); |
|
size.width += 2 * outlineWidth; |
|
size.height += 2 * outlineWidth; |
|
|
|
auto out = Surface::Alloc(size.width, size.height); |
|
SDL_SetSurfacePalette(out.surface, Palette); |
|
|
|
// Transparent color must not be used in the sprite itself. |
|
// Colors 1-127 are outside of the UI palette so are safe to use. |
|
constexpr std::uint8_t TransparentColor = 1; |
|
SDL_FillRect(out.surface, nullptr, TransparentColor); |
|
SDL_SetColorKey(out.surface, 1, TransparentColor); |
|
CelDrawCursor(out, { outlineWidth, size.height - outlineWidth }, pcurs); |
|
|
|
const bool result = SetHardwareCursor(out.surface, isItem ? HotpointPosition::Center : HotpointPosition::TopLeft); |
|
out.Free(); |
|
return result; |
|
} |
|
#endif |
|
|
|
} // namespace |
|
|
|
CursorInfo GetCurrentCursorInfo() |
|
{ |
|
return CurrentCursorInfo; |
|
} |
|
|
|
void SetHardwareCursor(CursorInfo cursorInfo) |
|
{ |
|
#if SDL_VERSION_ATLEAST(2, 0, 0) |
|
CurrentCursorInfo = cursorInfo; |
|
switch (cursorInfo.type()) { |
|
case CursorType::Game: |
|
CurrentCursorInfo.SetEnabled(SetHardwareCursorFromSprite(cursorInfo.id())); |
|
break; |
|
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)); |
|
break; |
|
case CursorType::Unknown: |
|
CurrentCursorInfo.SetEnabled(false); |
|
break; |
|
} |
|
#endif |
|
} |
|
|
|
} // namespace devilution
|
|
|