mirror of
https://github.com/love2d/love.git
synced 2026-08-20 12:40:20 +02:00
Add variant of newCursor which takes an array, for different DPI scales.
Resolves #1708.
This commit is contained in:
@@ -43,7 +43,7 @@ public:
|
|||||||
// Implements Module.
|
// Implements Module.
|
||||||
virtual ModuleType getModuleType() const { return M_MOUSE; }
|
virtual ModuleType getModuleType() const { return M_MOUSE; }
|
||||||
|
|
||||||
virtual Cursor *newCursor(love::image::ImageData *data, int hotx, int hoty) = 0;
|
virtual Cursor *newCursor(const std::vector<image::ImageData *> &data, int hotx, int hoty) = 0;
|
||||||
virtual Cursor *getSystemCursor(Cursor::SystemCursor cursortype) = 0;
|
virtual Cursor *getSystemCursor(Cursor::SystemCursor cursortype) = 0;
|
||||||
|
|
||||||
virtual void setCursor(Cursor *cursor) = 0;
|
virtual void setCursor(Cursor *cursor) = 0;
|
||||||
|
|||||||
@@ -29,23 +29,49 @@ namespace mouse
|
|||||||
namespace sdl
|
namespace sdl
|
||||||
{
|
{
|
||||||
|
|
||||||
Cursor::Cursor(image::ImageData *data, int hotx, int hoty)
|
Cursor::Cursor(const std::vector<image::ImageData *> &imageData, int hotx, int hoty)
|
||||||
: cursor(nullptr)
|
: cursor(nullptr)
|
||||||
, type(CURSORTYPE_IMAGE)
|
, type(CURSORTYPE_IMAGE)
|
||||||
, systemType(CURSOR_MAX_ENUM)
|
, systemType(CURSOR_MAX_ENUM)
|
||||||
{
|
{
|
||||||
int w = data->getWidth();
|
if (imageData.empty())
|
||||||
int h = data->getHeight();
|
throw love::Exception("At least one ImageData must be provided for a custom cursor.");
|
||||||
int pitch = w * 4;
|
|
||||||
|
|
||||||
SDL_Surface *surface = SDL_CreateSurfaceFrom(w, h, SDL_PIXELFORMAT_ABGR8888, data->getData(), pitch);
|
std::vector<SDL_Surface *> surfaces;
|
||||||
if (!surface)
|
|
||||||
throw love::Exception("Cannot create cursor: out of memory.");
|
|
||||||
|
|
||||||
cursor = SDL_CreateColorCursor(surface, hotx, hoty);
|
for (image::ImageData *data : imageData)
|
||||||
SDL_DestroySurface(surface);
|
{
|
||||||
|
int w = data->getWidth();
|
||||||
|
int h = data->getHeight();
|
||||||
|
int pitch = w * 4;
|
||||||
|
|
||||||
if (!cursor)
|
if (getLinearPixelFormat(data->getFormat()) != PIXELFORMAT_RGBA8_UNORM)
|
||||||
|
{
|
||||||
|
for (SDL_Surface *surface : surfaces)
|
||||||
|
SDL_DestroySurface(surface);
|
||||||
|
throw love::Exception("Cannot create cursor: ImageData pixel format must be rgba8.");
|
||||||
|
}
|
||||||
|
|
||||||
|
surfaces.push_back(SDL_CreateSurfaceFrom(w, h, SDL_PIXELFORMAT_ABGR8888, data->getData(), pitch));
|
||||||
|
|
||||||
|
if (surfaces.back() == nullptr)
|
||||||
|
{
|
||||||
|
for (SDL_Surface *surface : surfaces)
|
||||||
|
SDL_DestroySurface(surface);
|
||||||
|
throw love::Exception("Cannot create cursor: out of memory.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add alternate representations for the OS to use in different DPI scales.
|
||||||
|
for (size_t i = 1; i < surfaces.size(); i++)
|
||||||
|
SDL_AddSurfaceAlternateImage(surfaces[0], surfaces[i]);
|
||||||
|
|
||||||
|
cursor = SDL_CreateColorCursor(surfaces[0], hotx, hoty);
|
||||||
|
|
||||||
|
for (SDL_Surface *surface : surfaces)
|
||||||
|
SDL_DestroySurface(surface);
|
||||||
|
|
||||||
|
if (cursor == nullptr)
|
||||||
throw love::Exception("Cannot create cursor: %s", SDL_GetError());
|
throw love::Exception("Cannot create cursor: %s", SDL_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +87,7 @@ Cursor::Cursor(mouse::Cursor::SystemCursor cursortype)
|
|||||||
else
|
else
|
||||||
throw love::Exception("Cannot create system cursor: invalid type.");
|
throw love::Exception("Cannot create system cursor: invalid type.");
|
||||||
|
|
||||||
if (!cursor)
|
if (cursor == nullptr)
|
||||||
throw love::Exception("Cannot create system cursor: %s", SDL_GetError());
|
throw love::Exception("Cannot create system cursor: %s", SDL_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
// SDL
|
// SDL
|
||||||
#include <SDL3/SDL_mouse.h>
|
#include <SDL3/SDL_mouse.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
{
|
{
|
||||||
namespace mouse
|
namespace mouse
|
||||||
@@ -39,7 +41,7 @@ class Cursor : public love::mouse::Cursor
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Cursor(image::ImageData *imageData, int hotx, int hoty);
|
Cursor(const std::vector<image::ImageData *> &imageData, int hotx, int hoty);
|
||||||
Cursor(SystemCursor cursortype);
|
Cursor(SystemCursor cursortype);
|
||||||
~Cursor();
|
~Cursor();
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ Mouse::~Mouse()
|
|||||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
}
|
}
|
||||||
|
|
||||||
love::mouse::Cursor *Mouse::newCursor(love::image::ImageData *data, int hotx, int hoty)
|
love::mouse::Cursor *Mouse::newCursor(const std::vector<image::ImageData *> &data, int hotx, int hoty)
|
||||||
{
|
{
|
||||||
return new Cursor(data, hotx, hoty);
|
return new Cursor(data, hotx, hoty);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public:
|
|||||||
Mouse();
|
Mouse();
|
||||||
virtual ~Mouse();
|
virtual ~Mouse();
|
||||||
|
|
||||||
love::mouse::Cursor *newCursor(love::image::ImageData *data, int hotx, int hoty) override;
|
love::mouse::Cursor *newCursor(const std::vector<image::ImageData *> &data, int hotx, int hoty) override;
|
||||||
love::mouse::Cursor *getSystemCursor(Cursor::SystemCursor cursortype) override;
|
love::mouse::Cursor *getSystemCursor(Cursor::SystemCursor cursortype) override;
|
||||||
|
|
||||||
void setCursor(love::mouse::Cursor *cursor) override;
|
void setCursor(love::mouse::Cursor *cursor) override;
|
||||||
|
|||||||
@@ -36,15 +36,55 @@ namespace mouse
|
|||||||
int w_newCursor(lua_State *L)
|
int w_newCursor(lua_State *L)
|
||||||
{
|
{
|
||||||
Cursor *cursor = nullptr;
|
Cursor *cursor = nullptr;
|
||||||
|
std::vector<love::image::ImageData *> data;
|
||||||
|
|
||||||
if (lua_isstring(L, 1) || luax_istype(L, 1, love::filesystem::File::type) || luax_istype(L, 1, love::filesystem::FileData::type))
|
if (lua_istable(L, 1))
|
||||||
luax_convobj(L, 1, "image", "newImageData");
|
{
|
||||||
|
// Do some type checking first, because memory will leak if we hit an error in the loop after this.
|
||||||
|
for (size_t i = 1; i <= luax_objlen(L, 1); i++)
|
||||||
|
{
|
||||||
|
lua_rawgeti(L, 1, i);
|
||||||
|
|
||||||
|
if (!luax_istype(L, -1, love::image::ImageData::type)
|
||||||
|
&& !(lua_isstring(L, -1) || luax_istype(L, -1, love::filesystem::File::type) || luax_istype(L, -1, love::filesystem::FileData::type)))
|
||||||
|
{
|
||||||
|
luax_checktype<love::image::ImageData>(L, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 1; i <= luax_objlen(L, 1); i++)
|
||||||
|
{
|
||||||
|
lua_rawgeti(L, 1, i);
|
||||||
|
|
||||||
|
if (lua_isstring(L, -1) || luax_istype(L, -1, love::filesystem::File::type) || luax_istype(L, -1, love::filesystem::FileData::type))
|
||||||
|
luax_convobj(L, -1, "image", "newImageData");
|
||||||
|
|
||||||
|
data.push_back(luax_checktype<love::image::ImageData>(L, -1));
|
||||||
|
|
||||||
|
// If a GC step happens within the loop, previous ImageData objects created within the loop may be released.
|
||||||
|
data.back()->retain();
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (lua_isstring(L, 1) || luax_istype(L, 1, love::filesystem::File::type) || luax_istype(L, 1, love::filesystem::FileData::type))
|
||||||
|
luax_convobj(L, 1, "image", "newImageData");
|
||||||
|
|
||||||
|
data.push_back(luax_checktype<love::image::ImageData>(L, 1));
|
||||||
|
data.back()->retain();
|
||||||
|
}
|
||||||
|
|
||||||
love::image::ImageData *data = luax_checktype<love::image::ImageData>(L, 1);
|
|
||||||
int hotx = (int) luaL_optinteger(L, 2, 0);
|
int hotx = (int) luaL_optinteger(L, 2, 0);
|
||||||
int hoty = (int) luaL_optinteger(L, 3, 0);
|
int hoty = (int) luaL_optinteger(L, 3, 0);
|
||||||
|
|
||||||
luax_catchexcept(L, [&](){ cursor = instance()->newCursor(data, hotx, hoty); });
|
luax_catchexcept(L,
|
||||||
|
[&](){ cursor = instance()->newCursor(data, hotx, hoty); },
|
||||||
|
[&](bool /*shoulderror*/) { for (auto d : data) d->release(); }
|
||||||
|
);
|
||||||
|
|
||||||
luax_pushtype(L, cursor);
|
luax_pushtype(L, cursor);
|
||||||
cursor->release();
|
cursor->release();
|
||||||
|
|||||||
Reference in New Issue
Block a user