Scale the cursor according to the GUI scale (HiDPI support).

Differential Revision: https://code.wildfiregames.com/D320
Fixes #3875
Patch By: Dariost
Reviewed By: domdomegg
This was SVN commit r19667.
This commit is contained in:
elexis 2017-05-27 09:24:04 +00:00
parent a3913080cc
commit 9ff7ec3465
3 changed files with 30 additions and 18 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2014 Wildfire Games
/* Copyright (c) 2017 Wildfire Games
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -52,7 +52,7 @@ class SDLCursor
SDL_Cursor* cursor;
public:
Status create(const PIVFS& vfs, const VfsPath& pathname, int hotspotx_, int hotspoty_)
Status create(const PIVFS& vfs, const VfsPath& pathname, int hotspotx_, int hotspoty_, double scale)
{
shared_ptr<u8> file; size_t fileSize;
RETURN_STATUS_IF_ERR(vfs->LoadFile(pathname, file, fileSize));
@ -70,6 +70,16 @@ public:
surface = SDL_CreateRGBSurfaceFrom(bgra_img, (int)t.m_Width, (int)t.m_Height, 32, (int)t.m_Width*4, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
if (!surface)
return ERR::FAIL;
if (scale != 1.0)
{
SDL_Surface* scaled_surface = SDL_CreateRGBSurface(0, surface->w * scale, surface->h * scale, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
if (!scaled_surface)
return ERR::FAIL;
if (SDL_BlitScaled(surface, NULL, scaled_surface, NULL))
return ERR::FAIL;
SDL_FreeSurface(surface);
surface = scaled_surface;
}
cursor = SDL_CreateColorCursor(surface, hotspotx_, hotspoty_);
if (!cursor)
return ERR::FAIL;
@ -99,15 +109,15 @@ class GLCursor
int hotspotx, hotspoty;
public:
Status create(const PIVFS& vfs, const VfsPath& pathname, int hotspotx_, int hotspoty_)
Status create(const PIVFS& vfs, const VfsPath& pathname, int hotspotx_, int hotspoty_, double scale)
{
ht = ogl_tex_load(vfs, pathname);
RETURN_STATUS_IF_ERR(ht);
size_t width, height;
(void)ogl_tex_get_size(ht, &width, &height, 0);
w = (GLint)width;
h = (GLint)height;
w = (GLint)(width * scale);
h = (GLint)(height * scale);
hotspotx = hotspotx_; hotspoty = hotspoty_;
@ -169,6 +179,8 @@ enum CursorKind
struct Cursor
{
double scale;
// require kind == CK_OpenGL after reload
bool forceGL;
@ -185,6 +197,7 @@ H_TYPE_DEFINE(Cursor);
static void Cursor_init(Cursor* c, va_list args)
{
c->scale = va_arg(args, double);
c->forceGL = (va_arg(args, int) != 0);
}
@ -227,13 +240,11 @@ static Status Cursor_reload(Cursor* c, const PIVFS& vfs, const VfsPath& name, Ha
const VfsPath pathnameImage = pathname.ChangeExtension(L".png");
// try loading as SDL2 cursor
if (!c->forceGL && c->sdl_cursor.create(vfs, pathnameImage, hotspotx, hotspoty) == INFO::OK)
if (!c->forceGL && c->sdl_cursor.create(vfs, pathnameImage, hotspotx, hotspoty, c->scale) == INFO::OK)
c->kind = CK_SDL;
// fall back to GLCursor (system cursor code is disabled or failed)
else if(c->gl_cursor.create(vfs, pathnameImage, hotspotx, hotspoty) == INFO::OK)
{
else if (c->gl_cursor.create(vfs, pathnameImage, hotspotx, hotspoty, c->scale) == INFO::OK)
c->kind = CK_OpenGL;
}
// everything failed, leave cursor unchanged
else
c->kind = CK_Default;
@ -297,9 +308,9 @@ static Status Cursor_to_string(const Cursor* c, wchar_t* buf)
// in other words, we continually create/free the cursor resource in
// cursor_draw and trust h_mgr's caching to absorb it.
static Handle cursor_load(const PIVFS& vfs, const VfsPath& name, bool forceGL)
static Handle cursor_load(const PIVFS& vfs, const VfsPath& name, double scale, bool forceGL)
{
return h_alloc(H_Cursor, vfs, name, 0, (int)forceGL);
return h_alloc(H_Cursor, vfs, name, 0, scale, (int)forceGL);
}
void cursor_shutdown()
@ -313,7 +324,7 @@ static Status cursor_free(Handle& h)
}
Status cursor_draw(const PIVFS& vfs, const wchar_t* name, int x, int y, bool forceGL)
Status cursor_draw(const PIVFS& vfs, const wchar_t* name, int x, int y, double scale, bool forceGL)
{
// hide the cursor
if(!name)
@ -322,7 +333,7 @@ Status cursor_draw(const PIVFS& vfs, const wchar_t* name, int x, int y, bool for
return INFO::OK;
}
Handle hc = cursor_load(vfs, name, forceGL);
Handle hc = cursor_load(vfs, name, scale, forceGL);
// TODO: if forceGL changes at runtime after a cursor is first created,
// we might reuse a cached version of the cursor with the old forceGL flag

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2010 Wildfire Games
/* Copyright (c) 2017 Wildfire Games
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -39,12 +39,13 @@
* mouse Y coordinate to be subtracted from the client area height.
* Making the caller responsible for this avoids a dependency on
* the g_yres global variable.)
* @param scale Scale factor for drawing size the cursor.
* @param forceGL Require the OpenGL cursor implementation, not hardware cursor
*
* Uses a hardware mouse cursor where available, otherwise a
* portable OpenGL implementation.
**/
extern Status cursor_draw(const PIVFS& vfs, const wchar_t* name, int x, int y, bool forceGL);
extern Status cursor_draw(const PIVFS& vfs, const wchar_t* name, int x, int y, double scale, bool forceGL);
/**
* Forcibly frees all cursor handles.

View File

@ -281,7 +281,7 @@ void Render()
CStrW cursorName = g_CursorName;
if (cursorName.empty())
{
cursor_draw(g_VFS, NULL, g_mouse_x, g_yres-g_mouse_y, false);
cursor_draw(g_VFS, NULL, g_mouse_x, g_yres-g_mouse_y, 1.0 / g_GuiScale, false);
}
else
{
@ -306,7 +306,7 @@ void Render()
#if OS_ANDROID
#warning TODO: cursors for Android
#else
if (cursor_draw(g_VFS, cursorName.c_str(), g_mouse_x, g_yres-g_mouse_y, forceGL) < 0)
if (cursor_draw(g_VFS, cursorName.c_str(), g_mouse_x, g_yres-g_mouse_y, 1.0 / g_GuiScale, forceGL) < 0)
LOGWARNING("Failed to draw cursor '%s'", utf8_from_wstring(cursorName));
#endif
@ -598,7 +598,7 @@ static void ShutdownPs()
UnloadHotkeys();
// disable the special Windows cursor, or free textures for OGL cursors
cursor_draw(g_VFS, 0, g_mouse_x, g_yres-g_mouse_y, false);
cursor_draw(g_VFS, 0, g_mouse_x, g_yres-g_mouse_y, 1.0, false);
}