From 9ff7ec34653a2c81dd49d55828dc77ade99bd106 Mon Sep 17 00:00:00 2001 From: elexis Date: Sat, 27 May 2017 09:24:04 +0000 Subject: [PATCH] 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. --- source/lib/res/graphics/cursor.cpp | 37 +++++++++++++++++++----------- source/lib/res/graphics/cursor.h | 5 ++-- source/ps/GameSetup/GameSetup.cpp | 6 ++--- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/source/lib/res/graphics/cursor.cpp b/source/lib/res/graphics/cursor.cpp index c02ca42e0a..876682ca64 100644 --- a/source/lib/res/graphics/cursor.cpp +++ b/source/lib/res/graphics/cursor.cpp @@ -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 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 diff --git a/source/lib/res/graphics/cursor.h b/source/lib/res/graphics/cursor.h index 074e9770b5..d9fbff3cdc 100644 --- a/source/lib/res/graphics/cursor.h +++ b/source/lib/res/graphics/cursor.h @@ -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. diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index fd3e8fc30d..a6d291257d 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -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); }