mirror of https://github.com/godotengine/godot
Merge pull request #65133 from bruvzg/win_cursor
[Windows] Simplify cursor handling and add support for fully transparent cursors.
This commit is contained in:
commit
5ff8e4ee67
|
|
@ -1496,7 +1496,7 @@ void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) {
|
||||||
IDC_HELP
|
IDC_HELP
|
||||||
};
|
};
|
||||||
|
|
||||||
if (cursors[p_shape] != nullptr) {
|
if (cursors_cache.has(p_shape)) {
|
||||||
SetCursor(cursors[p_shape]);
|
SetCursor(cursors[p_shape]);
|
||||||
} else {
|
} else {
|
||||||
SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
|
SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
|
||||||
|
|
@ -1509,55 +1509,6 @@ DisplayServer::CursorShape DisplayServerWindows::cursor_get_shape() const {
|
||||||
return cursor_shape;
|
return cursor_shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) {
|
|
||||||
// Get the system display DC.
|
|
||||||
HDC hDC = GetDC(nullptr);
|
|
||||||
|
|
||||||
// Create helper DC.
|
|
||||||
HDC hMainDC = CreateCompatibleDC(hDC);
|
|
||||||
HDC hAndMaskDC = CreateCompatibleDC(hDC);
|
|
||||||
HDC hXorMaskDC = CreateCompatibleDC(hDC);
|
|
||||||
|
|
||||||
// Get the dimensions of the source bitmap.
|
|
||||||
BITMAP bm;
|
|
||||||
GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
|
|
||||||
|
|
||||||
// Create the mask bitmaps.
|
|
||||||
hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color.
|
|
||||||
hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color.
|
|
||||||
|
|
||||||
// Release the system display DC.
|
|
||||||
ReleaseDC(nullptr, hDC);
|
|
||||||
|
|
||||||
// Select the bitmaps to helper DC.
|
|
||||||
HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap);
|
|
||||||
HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap);
|
|
||||||
HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap);
|
|
||||||
|
|
||||||
// Assign the monochrome AND mask bitmap pixels so that the pixels of the source bitmap
|
|
||||||
// with 'clrTransparent' will be white pixels of the monochrome bitmap.
|
|
||||||
SetBkColor(hMainDC, clrTransparent);
|
|
||||||
BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY);
|
|
||||||
|
|
||||||
// Assign the color XOR mask bitmap pixels so that the pixels of the source bitmap
|
|
||||||
// with 'clrTransparent' will be black and rest the pixels same as corresponding
|
|
||||||
// pixels of the source bitmap.
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Deselect bitmaps from the helper DC.
|
|
||||||
SelectObject(hMainDC, hOldMainBitmap);
|
|
||||||
SelectObject(hAndMaskDC, hOldAndMaskBitmap);
|
|
||||||
SelectObject(hXorMaskDC, hOldXorMaskBitmap);
|
|
||||||
|
|
||||||
// Delete the helper DC.
|
|
||||||
DeleteDC(hXorMaskDC);
|
|
||||||
DeleteDC(hAndMaskDC);
|
|
||||||
DeleteDC(hMainDC);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||||
_THREAD_SAFE_METHOD_
|
_THREAD_SAFE_METHOD_
|
||||||
|
|
||||||
|
|
@ -1610,8 +1561,26 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
|
||||||
UINT image_size = texture_size.width * texture_size.height;
|
UINT image_size = texture_size.width * texture_size.height;
|
||||||
|
|
||||||
// Create the BITMAP with alpha channel.
|
// Create the BITMAP with alpha channel.
|
||||||
COLORREF *buffer = (COLORREF *)memalloc(sizeof(COLORREF) * image_size);
|
COLORREF *buffer = nullptr;
|
||||||
|
|
||||||
|
BITMAPV5HEADER bi;
|
||||||
|
ZeroMemory(&bi, sizeof(bi));
|
||||||
|
bi.bV5Size = sizeof(bi);
|
||||||
|
bi.bV5Width = texture_size.width;
|
||||||
|
bi.bV5Height = -texture_size.height;
|
||||||
|
bi.bV5Planes = 1;
|
||||||
|
bi.bV5BitCount = 32;
|
||||||
|
bi.bV5Compression = BI_BITFIELDS;
|
||||||
|
bi.bV5RedMask = 0x00ff0000;
|
||||||
|
bi.bV5GreenMask = 0x0000ff00;
|
||||||
|
bi.bV5BlueMask = 0x000000ff;
|
||||||
|
bi.bV5AlphaMask = 0xff000000;
|
||||||
|
|
||||||
|
HDC dc = GetDC(nullptr);
|
||||||
|
HBITMAP bitmap = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO *>(&bi), DIB_RGB_COLORS, reinterpret_cast<void **>(&buffer), nullptr, 0);
|
||||||
|
HBITMAP mask = CreateBitmap(texture_size.width, texture_size.height, 1, 1, nullptr);
|
||||||
|
|
||||||
|
bool fully_transparent = true;
|
||||||
for (UINT index = 0; index < image_size; index++) {
|
for (UINT index = 0; index < image_size; index++) {
|
||||||
int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
|
int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
|
||||||
int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
|
int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
|
||||||
|
|
@ -1620,39 +1589,28 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
|
||||||
column_index = MIN(column_index, atlas_rect.size.width - 1);
|
column_index = MIN(column_index, atlas_rect.size.width - 1);
|
||||||
row_index = MIN(row_index, atlas_rect.size.height - 1);
|
row_index = MIN(row_index, atlas_rect.size.height - 1);
|
||||||
}
|
}
|
||||||
|
const Color &c = image->get_pixel(column_index, row_index);
|
||||||
|
fully_transparent = fully_transparent && (c.a == 0.f);
|
||||||
|
|
||||||
*(buffer + index) = image->get_pixel(column_index, row_index).to_argb32();
|
*(buffer + index) = c.to_argb32();
|
||||||
}
|
|
||||||
|
|
||||||
// Using 4 channels, so 4 * 8 bits.
|
|
||||||
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.
|
|
||||||
HBITMAP hAndMask = nullptr;
|
|
||||||
HBITMAP hXorMask = nullptr;
|
|
||||||
|
|
||||||
GetMaskBitmaps(bitmap, clrTransparent, hAndMask, hXorMask);
|
|
||||||
|
|
||||||
if (nullptr == hAndMask || nullptr == hXorMask) {
|
|
||||||
memfree(buffer);
|
|
||||||
DeleteObject(bitmap);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, create the icon.
|
// Finally, create the icon.
|
||||||
ICONINFO iconinfo;
|
|
||||||
iconinfo.fIcon = FALSE;
|
|
||||||
iconinfo.xHotspot = p_hotspot.x;
|
|
||||||
iconinfo.yHotspot = p_hotspot.y;
|
|
||||||
iconinfo.hbmMask = hAndMask;
|
|
||||||
iconinfo.hbmColor = hXorMask;
|
|
||||||
|
|
||||||
if (cursors[p_shape]) {
|
if (cursors[p_shape]) {
|
||||||
DestroyIcon(cursors[p_shape]);
|
DestroyIcon(cursors[p_shape]);
|
||||||
}
|
}
|
||||||
|
|
||||||
cursors[p_shape] = CreateIconIndirect(&iconinfo);
|
if (fully_transparent) {
|
||||||
|
cursors[p_shape] = nullptr;
|
||||||
|
} else {
|
||||||
|
ICONINFO iconinfo;
|
||||||
|
iconinfo.fIcon = FALSE;
|
||||||
|
iconinfo.xHotspot = p_hotspot.x;
|
||||||
|
iconinfo.yHotspot = p_hotspot.y;
|
||||||
|
iconinfo.hbmMask = mask;
|
||||||
|
iconinfo.hbmColor = bitmap;
|
||||||
|
cursors[p_shape] = CreateIconIndirect(&iconinfo);
|
||||||
|
}
|
||||||
|
|
||||||
Vector<Variant> params;
|
Vector<Variant> params;
|
||||||
params.push_back(p_cursor);
|
params.push_back(p_cursor);
|
||||||
|
|
@ -1665,17 +1623,15 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteObject(hAndMask);
|
DeleteObject(mask);
|
||||||
DeleteObject(hXorMask);
|
|
||||||
|
|
||||||
memfree(buffer);
|
|
||||||
DeleteObject(bitmap);
|
DeleteObject(bitmap);
|
||||||
|
ReleaseDC(nullptr, dc);
|
||||||
} else {
|
} else {
|
||||||
// Reset to default system cursor.
|
// Reset to default system cursor.
|
||||||
if (cursors[p_shape]) {
|
if (cursors[p_shape]) {
|
||||||
DestroyIcon(cursors[p_shape]);
|
DestroyIcon(cursors[p_shape]);
|
||||||
cursors[p_shape] = nullptr;
|
|
||||||
}
|
}
|
||||||
|
cursors[p_shape] = nullptr;
|
||||||
|
|
||||||
CursorShape c = cursor_shape;
|
CursorShape c = cursor_shape;
|
||||||
cursor_shape = CURSOR_MAX;
|
cursor_shape = CURSOR_MAX;
|
||||||
|
|
|
||||||
|
|
@ -311,8 +311,6 @@ class DisplayServerWindows : public DisplayServer {
|
||||||
String tablet_driver;
|
String tablet_driver;
|
||||||
Vector<String> tablet_drivers;
|
Vector<String> tablet_drivers;
|
||||||
|
|
||||||
void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
KEY_EVENT_BUFFER_SIZE = 512
|
KEY_EVENT_BUFFER_SIZE = 512
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue