mirror of
https://github.com/godotengine/godot.git
synced 2024-12-09 10:09:20 +08:00
[Windows] Simplify cursor handling and add support for fully transparent cursors.
This commit is contained in:
parent
c40855f818
commit
77a4567122
@ -1470,7 +1470,7 @@ void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) {
|
||||
IDC_HELP
|
||||
};
|
||||
|
||||
if (cursors[p_shape] != nullptr) {
|
||||
if (cursors_cache.has(p_shape)) {
|
||||
SetCursor(cursors[p_shape]);
|
||||
} else {
|
||||
SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
|
||||
@ -1483,55 +1483,6 @@ DisplayServer::CursorShape DisplayServerWindows::cursor_get_shape() const {
|
||||
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) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
@ -1584,8 +1535,26 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
|
||||
UINT image_size = texture_size.width * texture_size.height;
|
||||
|
||||
// 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++) {
|
||||
int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
|
||||
int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
|
||||
@ -1594,39 +1563,28 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
|
||||
column_index = MIN(column_index, atlas_rect.size.width - 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();
|
||||
}
|
||||
|
||||
// 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;
|
||||
*(buffer + index) = c.to_argb32();
|
||||
}
|
||||
|
||||
// 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]) {
|
||||
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;
|
||||
params.push_back(p_cursor);
|
||||
@ -1639,17 +1597,15 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
|
||||
}
|
||||
}
|
||||
|
||||
DeleteObject(hAndMask);
|
||||
DeleteObject(hXorMask);
|
||||
|
||||
memfree(buffer);
|
||||
DeleteObject(mask);
|
||||
DeleteObject(bitmap);
|
||||
ReleaseDC(nullptr, dc);
|
||||
} else {
|
||||
// Reset to default system cursor.
|
||||
if (cursors[p_shape]) {
|
||||
DestroyIcon(cursors[p_shape]);
|
||||
cursors[p_shape] = nullptr;
|
||||
}
|
||||
cursors[p_shape] = nullptr;
|
||||
|
||||
CursorShape c = cursor_shape;
|
||||
cursor_shape = CURSOR_MAX;
|
||||
|
@ -295,8 +295,6 @@ class DisplayServerWindows : public DisplayServer {
|
||||
String tablet_driver;
|
||||
Vector<String> tablet_drivers;
|
||||
|
||||
void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);
|
||||
|
||||
enum {
|
||||
KEY_EVENT_BUFFER_SIZE = 512
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user