Add support for atlas texture on set_custom_mouse_cursor

This commit is contained in:
Guilherme Felipe 2018-04-22 13:45:47 -03:00
parent 83d5db294d
commit d65e95e5d6
3 changed files with 107 additions and 27 deletions

View File

@ -1197,38 +1197,68 @@ 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) {
if (p_cursor.is_valid()) {
Ref<ImageTexture> texture = p_cursor;
Image image = texture->get_data();
Ref<AtlasTexture> atlas_texture = p_cursor;
Size2 texture_size;
Rect2 atlas_rect;
ERR_FAIL_COND(texture->get_width() > 256 || texture->get_height() > 256);
if (!texture.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.pos.x = atlas_texture->get_region().pos.x;
atlas_rect.pos.y = atlas_texture->get_region().pos.y;
texture_size.width = atlas_texture->get_region().size.x;
texture_size.height = atlas_texture->get_region().size.y;
} else {
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 image = texture->get_data();
NSBitmapImageRep *imgrep = [[[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:image.get_width()
pixelsHigh:image.get_height()
pixelsWide:int(texture_size.width)
pixelsHigh:int(texture_size.height)
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:image.get_width() * 4
bytesPerRow:int(texture_size.width) * 4
bitsPerPixel:32] autorelease];
ERR_FAIL_COND(imgrep == nil);
uint8_t *pixels = [imgrep bitmapData];
int len = image.get_width() * image.get_height();
int len = int(texture_size.width * texture_size.height);
DVector<uint8_t> data = image.get_data();
DVector<uint8_t>::Read r = data.read();
/* Premultiply the alpha channel */
for (int i = 0; i < len; i++) {
uint8_t alpha = r[i * 4 + 3];
pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
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);
int row_index = floor(i / texture_size.width) + atlas_rect.pos.y;
int column_index = (i % int(texture_size.width)) + atlas_rect.pos.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);
}
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;
}
NSImage *nsimage = [[[NSImage alloc] initWithSize:NSMakeSize(image.get_width(), image.get_height())] autorelease];
NSImage *nsimage = [[[NSImage alloc] initWithSize:NSMakeSize(texture_size.width, texture_size.height)] autorelease];
[nsimage addRepresentation:imgrep];
NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)];

View File

@ -1977,28 +1977,53 @@ void OS_Windows::set_cursor_shape(CursorShape p_shape) {
cursor_shape = 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()) {
Ref<ImageTexture> texture = p_cursor;
Ref<AtlasTexture> atlas_texture = p_cursor;
Size2 texture_size;
Rect2 atlas_rect;
if (!texture.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.pos.x = atlas_texture->get_region().pos.x;
atlas_rect.pos.y = atlas_texture->get_region().pos.y;
texture_size.width = atlas_texture->get_region().size.x;
texture_size.height = atlas_texture->get_region().size.y;
} else {
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 image = texture->get_data();
UINT image_size = texture->get_width() * texture->get_height();
UINT image_size = texture_size.width * texture_size.height;
UINT size = sizeof(UINT) * image_size;
ERR_FAIL_COND(texture->get_width() > 256 || texture->get_height() > 256);
// Create the BITMAP with alpha channel
COLORREF *buffer = (COLORREF *)malloc(sizeof(COLORREF) * image_size);
for (UINT index = 0; index < image_size; index++) {
int row_index = floor(index / texture->get_width());
int column_index = index % texture->get_width();
int row_index = floor(index / texture_size.width) + atlas_rect.pos.y;
int column_index = (index % int(texture_size.width)) + atlas_rect.pos.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();
}
// 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;
// Create the AND and XOR masks for the bitmap
@ -2012,7 +2037,7 @@ void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shap
}
// Finally, create the icon
ICONINFO iconinfo = {0};
ICONINFO iconinfo = { 0 };
iconinfo.fIcon = FALSE;
iconinfo.xHotspot = p_hotspot.x;
iconinfo.yHotspot = p_hotspot.y;
@ -2030,7 +2055,7 @@ void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shap
}
if (hXorMask != NULL) {
DeleteObject(hXorMask);
DeleteObject(hXorMask);
}
}
}
@ -2072,7 +2097,7 @@ void OS_Windows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent,
SetBkColor(hXorMaskDC, RGB(0, 0, 0));
SetTextColor(hXorMaskDC, RGB(255, 255, 255));
BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hAndMaskDC, 0, 0, SRCCOPY);
BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0,0, SRCAND);
BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCAND);
// Deselect bitmaps from the helper DC
SelectObject(hMainDC, hOldMainBitmap);

View File

@ -2163,13 +2163,33 @@ void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c
if (p_cursor.is_valid()) {
Ref<ImageTexture> texture = p_cursor;
Ref<AtlasTexture> atlas_texture = p_cursor;
Size2 texture_size;
Rect2 atlas_rect;
if (!texture.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.pos.x = atlas_texture->get_region().pos.x;
atlas_rect.pos.y = atlas_texture->get_region().pos.y;
texture_size.width = atlas_texture->get_region().size.x;
texture_size.height = atlas_texture->get_region().size.y;
} else {
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 image = texture->get_data();
ERR_FAIL_COND(texture->get_width() > 256 || texture->get_height() > 256);
// Create the cursor structure
XcursorImage *cursor_image = XcursorImageCreate(texture->get_width(), texture->get_height());
XcursorUInt image_size = texture->get_width() * texture->get_height();
XcursorImage *cursor_image = XcursorImageCreate(texture_size.width, texture_size.height);
XcursorUInt image_size = texture_size.width * texture_size.height;
XcursorDim size = sizeof(XcursorPixel) * image_size;
cursor_image->version = 1;
@ -2181,8 +2201,13 @@ void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c
cursor_image->pixels = (XcursorPixel *)malloc(size);
for (XcursorPixel index = 0; index < image_size; index++) {
int row_index = floor(index / texture->get_width());
int column_index = index % texture->get_width();
int row_index = floor(index / texture_size.width) + atlas_rect.pos.y;
int column_index = (index % int(texture_size.width)) + atlas_rect.pos.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();
}