Add support for atlas texture on set_custom_mouse_cursor
This commit is contained in:
parent
e668757aa9
commit
8ead09342d
3 changed files with 123 additions and 24 deletions
|
@ -1513,39 +1513,78 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) {
|
||||||
void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||||
if (p_cursor.is_valid()) {
|
if (p_cursor.is_valid()) {
|
||||||
Ref<Texture> texture = p_cursor;
|
Ref<Texture> texture = p_cursor;
|
||||||
Ref<Image> image = texture->get_data();
|
Ref<AtlasTexture> atlas_texture = p_cursor;
|
||||||
|
Ref<Image> image;
|
||||||
|
Size2 texture_size;
|
||||||
|
Rect2 atlas_rect;
|
||||||
|
|
||||||
ERR_FAIL_COND(texture->get_width() > 256 || texture->get_height() > 256);
|
if (texture.is_valid()) {
|
||||||
|
image = texture->get_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!image.is_valid() && atlas_texture.is_valid()) {
|
||||||
|
texture = atlas_texture->get_atlas();
|
||||||
|
|
||||||
|
atlas_rect.size.width = texture->get_width();
|
||||||
|
atlas_rect.size.height = texture->get_height();
|
||||||
|
atlas_rect.position.x = atlas_texture->get_region().position.x;
|
||||||
|
atlas_rect.position.y = atlas_texture->get_region().position.y;
|
||||||
|
|
||||||
|
texture_size.width = atlas_texture->get_region().size.x;
|
||||||
|
texture_size.height = atlas_texture->get_region().size.y;
|
||||||
|
} else if (image.is_valid()) {
|
||||||
|
texture_size.width = texture->get_width();
|
||||||
|
texture_size.height = texture->get_height();
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_FAIL_COND(!texture.is_valid());
|
||||||
|
ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
|
||||||
|
|
||||||
|
image = texture->get_data();
|
||||||
|
|
||||||
NSBitmapImageRep *imgrep = [[[NSBitmapImageRep alloc]
|
NSBitmapImageRep *imgrep = [[[NSBitmapImageRep alloc]
|
||||||
initWithBitmapDataPlanes:NULL
|
initWithBitmapDataPlanes:NULL
|
||||||
pixelsWide:image->get_width()
|
pixelsWide:int(texture_size.width)
|
||||||
pixelsHigh:image->get_height()
|
pixelsHigh:int(texture_size.height)
|
||||||
bitsPerSample:8
|
bitsPerSample:8
|
||||||
samplesPerPixel:4
|
samplesPerPixel:4
|
||||||
hasAlpha:YES
|
hasAlpha:YES
|
||||||
isPlanar:NO
|
isPlanar:NO
|
||||||
colorSpaceName:NSDeviceRGBColorSpace
|
colorSpaceName:NSDeviceRGBColorSpace
|
||||||
bytesPerRow:image->get_width() * 4
|
bytesPerRow:int(texture_size.width) * 4
|
||||||
bitsPerPixel:32] autorelease];
|
bitsPerPixel:32] autorelease];
|
||||||
|
|
||||||
ERR_FAIL_COND(imgrep == nil);
|
ERR_FAIL_COND(imgrep == nil);
|
||||||
uint8_t *pixels = [imgrep bitmapData];
|
uint8_t *pixels = [imgrep bitmapData];
|
||||||
|
|
||||||
int len = image->get_width() * image->get_height();
|
int len = int(texture_size.width * texture_size.height);
|
||||||
PoolVector<uint8_t> data = image->get_data();
|
PoolVector<uint8_t> data = image->get_data();
|
||||||
PoolVector<uint8_t>::Read r = data.read();
|
PoolVector<uint8_t>::Read r = data.read();
|
||||||
|
|
||||||
|
image->lock();
|
||||||
|
|
||||||
/* Premultiply the alpha channel */
|
/* Premultiply the alpha channel */
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
uint8_t alpha = r[i * 4 + 3];
|
int row_index = floor(i / texture_size.width) + atlas_rect.position.y;
|
||||||
pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
|
int column_index = (i % int(texture_size.width)) + atlas_rect.position.x;
|
||||||
pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
|
|
||||||
pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
|
if (atlas_texture.is_valid()) {
|
||||||
|
column_index = MIN(column_index, atlas_rect.size.width - 1);
|
||||||
|
row_index = MIN(row_index, atlas_rect.size.height - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t color = image->get_pixel(column_index, row_index).to_argb32();
|
||||||
|
|
||||||
|
uint8_t alpha = (color >> 24) & 0xFF;
|
||||||
|
pixels[i * 4 + 0] = ((color >> 16) & 0xFF) * alpha / 255;
|
||||||
|
pixels[i * 4 + 1] = ((color >> 8) & 0xFF) * alpha / 255;
|
||||||
|
pixels[i * 4 + 2] = ((color)&0xFF) * alpha / 255;
|
||||||
pixels[i * 4 + 3] = alpha;
|
pixels[i * 4 + 3] = alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSImage *nsimage = [[[NSImage alloc] initWithSize:NSMakeSize(image->get_width(), image->get_height())] autorelease];
|
image->unlock();
|
||||||
|
|
||||||
|
NSImage *nsimage = [[[NSImage alloc] initWithSize:NSMakeSize(texture_size.width, texture_size.height)] autorelease];
|
||||||
[nsimage addRepresentation:imgrep];
|
[nsimage addRepresentation:imgrep];
|
||||||
|
|
||||||
NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)];
|
NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)];
|
||||||
|
|
|
@ -2033,27 +2033,57 @@ void OS_Windows::set_cursor_shape(CursorShape p_shape) {
|
||||||
void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||||
if (p_cursor.is_valid()) {
|
if (p_cursor.is_valid()) {
|
||||||
Ref<Texture> texture = p_cursor;
|
Ref<Texture> texture = p_cursor;
|
||||||
Ref<Image> image = texture->get_data();
|
Ref<AtlasTexture> atlas_texture = p_cursor;
|
||||||
|
Ref<Image> image;
|
||||||
|
Size2 texture_size;
|
||||||
|
Rect2 atlas_rect;
|
||||||
|
|
||||||
UINT image_size = texture->get_width() * texture->get_height();
|
if (texture.is_valid()) {
|
||||||
|
image = texture->get_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!image.is_valid() && atlas_texture.is_valid()) {
|
||||||
|
texture = atlas_texture->get_atlas();
|
||||||
|
|
||||||
|
atlas_rect.size.width = texture->get_width();
|
||||||
|
atlas_rect.size.height = texture->get_height();
|
||||||
|
atlas_rect.position.x = atlas_texture->get_region().position.x;
|
||||||
|
atlas_rect.position.y = atlas_texture->get_region().position.y;
|
||||||
|
|
||||||
|
texture_size.width = atlas_texture->get_region().size.x;
|
||||||
|
texture_size.height = atlas_texture->get_region().size.y;
|
||||||
|
} else if (image.is_valid()) {
|
||||||
|
texture_size.width = texture->get_width();
|
||||||
|
texture_size.height = texture->get_height();
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_FAIL_COND(!texture.is_valid());
|
||||||
|
ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
|
||||||
|
|
||||||
|
image = texture->get_data();
|
||||||
|
|
||||||
|
UINT image_size = texture_size.width * texture_size.height;
|
||||||
UINT size = sizeof(UINT) * image_size;
|
UINT size = sizeof(UINT) * image_size;
|
||||||
|
|
||||||
ERR_FAIL_COND(texture->get_width() > 256 || texture->get_height() > 256);
|
|
||||||
|
|
||||||
// Create the BITMAP with alpha channel
|
// Create the BITMAP with alpha channel
|
||||||
COLORREF *buffer = (COLORREF *)malloc(sizeof(COLORREF) * image_size);
|
COLORREF *buffer = (COLORREF *)malloc(sizeof(COLORREF) * image_size);
|
||||||
|
|
||||||
image->lock();
|
image->lock();
|
||||||
for (UINT index = 0; index < image_size; index++) {
|
for (UINT index = 0; index < image_size; index++) {
|
||||||
int row_index = floor(index / texture->get_width());
|
int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
|
||||||
int column_index = index % texture->get_width();
|
int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
|
||||||
|
|
||||||
|
if (atlas_texture.is_valid()) {
|
||||||
|
column_index = MIN(column_index, atlas_rect.size.width - 1);
|
||||||
|
row_index = MIN(row_index, atlas_rect.size.height - 1);
|
||||||
|
}
|
||||||
|
|
||||||
*(buffer + index) = image->get_pixel(column_index, row_index).to_argb32();
|
*(buffer + index) = image->get_pixel(column_index, row_index).to_argb32();
|
||||||
}
|
}
|
||||||
image->unlock();
|
image->unlock();
|
||||||
|
|
||||||
// Using 4 channels, so 4 * 8 bits
|
// Using 4 channels, so 4 * 8 bits
|
||||||
HBITMAP bitmap = CreateBitmap(texture->get_width(), texture->get_height(), 1, 4 * 8, buffer);
|
HBITMAP bitmap = CreateBitmap(texture_size.width, texture_size.height, 1, 4 * 8, buffer);
|
||||||
COLORREF clrTransparent = -1;
|
COLORREF clrTransparent = -1;
|
||||||
|
|
||||||
// Create the AND and XOR masks for the bitmap
|
// Create the AND and XOR masks for the bitmap
|
||||||
|
|
|
@ -2420,13 +2420,38 @@ void OS_X11::set_cursor_shape(CursorShape p_shape) {
|
||||||
void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||||
if (p_cursor.is_valid()) {
|
if (p_cursor.is_valid()) {
|
||||||
Ref<Texture> texture = p_cursor;
|
Ref<Texture> texture = p_cursor;
|
||||||
Ref<Image> image = texture->get_data();
|
Ref<AtlasTexture> atlas_texture = p_cursor;
|
||||||
|
Ref<Image> image;
|
||||||
|
Size2 texture_size;
|
||||||
|
Rect2 atlas_rect;
|
||||||
|
|
||||||
ERR_FAIL_COND(texture->get_width() > 256 || texture->get_height() > 256);
|
if (texture.is_valid()) {
|
||||||
|
image = texture->get_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!image.is_valid() && atlas_texture.is_valid()) {
|
||||||
|
texture = atlas_texture->get_atlas();
|
||||||
|
|
||||||
|
atlas_rect.size.width = texture->get_width();
|
||||||
|
atlas_rect.size.height = texture->get_height();
|
||||||
|
atlas_rect.position.x = atlas_texture->get_region().position.x;
|
||||||
|
atlas_rect.position.y = atlas_texture->get_region().position.y;
|
||||||
|
|
||||||
|
texture_size.width = atlas_texture->get_region().size.x;
|
||||||
|
texture_size.height = atlas_texture->get_region().size.y;
|
||||||
|
} else if (image.is_valid()) {
|
||||||
|
texture_size.width = texture->get_width();
|
||||||
|
texture_size.height = texture->get_height();
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR_FAIL_COND(!texture.is_valid());
|
||||||
|
ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
|
||||||
|
|
||||||
|
image = texture->get_data();
|
||||||
|
|
||||||
// Create the cursor structure
|
// Create the cursor structure
|
||||||
XcursorImage *cursor_image = XcursorImageCreate(texture->get_width(), texture->get_height());
|
XcursorImage *cursor_image = XcursorImageCreate(texture_size.width, texture_size.height);
|
||||||
XcursorUInt image_size = texture->get_width() * texture->get_height();
|
XcursorUInt image_size = texture_size.width * texture_size.height;
|
||||||
XcursorDim size = sizeof(XcursorPixel) * image_size;
|
XcursorDim size = sizeof(XcursorPixel) * image_size;
|
||||||
|
|
||||||
cursor_image->version = 1;
|
cursor_image->version = 1;
|
||||||
|
@ -2440,8 +2465,13 @@ void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c
|
||||||
image->lock();
|
image->lock();
|
||||||
|
|
||||||
for (XcursorPixel index = 0; index < image_size; index++) {
|
for (XcursorPixel index = 0; index < image_size; index++) {
|
||||||
int row_index = floor(index / texture->get_width());
|
int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
|
||||||
int column_index = index % texture->get_width();
|
int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
|
||||||
|
|
||||||
|
if (atlas_texture.is_valid()) {
|
||||||
|
column_index = MIN(column_index, atlas_rect.size.width - 1);
|
||||||
|
row_index = MIN(row_index, atlas_rect.size.height - 1);
|
||||||
|
}
|
||||||
|
|
||||||
*(cursor_image->pixels + index) = image->get_pixel(column_index, row_index).to_argb32();
|
*(cursor_image->pixels + index) = image->get_pixel(column_index, row_index).to_argb32();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue