Merge pull request #12814 from guilhermefelipecgs/add_hardware_custom_cursor
Custom hardware-accelerated mouse cursor
This commit is contained in:
commit
6322b0bbb7
23 changed files with 318 additions and 41 deletions
|
@ -84,7 +84,7 @@ void Input::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position);
|
||||
ClassDB::bind_method(D_METHOD("action_press", "action"), &Input::action_press);
|
||||
ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
|
||||
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(Vector2()));
|
||||
ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
|
||||
ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
|
||||
|
||||
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
|
||||
|
@ -92,6 +92,24 @@ void Input::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
|
||||
BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
|
||||
|
||||
BIND_ENUM_CONSTANT(CURSOR_ARROW);
|
||||
BIND_ENUM_CONSTANT(CURSOR_IBEAM);
|
||||
BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
|
||||
BIND_ENUM_CONSTANT(CURSOR_CROSS);
|
||||
BIND_ENUM_CONSTANT(CURSOR_WAIT);
|
||||
BIND_ENUM_CONSTANT(CURSOR_BUSY);
|
||||
BIND_ENUM_CONSTANT(CURSOR_DRAG);
|
||||
BIND_ENUM_CONSTANT(CURSOR_CAN_DROP);
|
||||
BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN);
|
||||
BIND_ENUM_CONSTANT(CURSOR_VSIZE);
|
||||
BIND_ENUM_CONSTANT(CURSOR_HSIZE);
|
||||
BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE);
|
||||
BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE);
|
||||
BIND_ENUM_CONSTANT(CURSOR_MOVE);
|
||||
BIND_ENUM_CONSTANT(CURSOR_VSPLIT);
|
||||
BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
|
||||
BIND_ENUM_CONSTANT(CURSOR_HELP);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "connected")));
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,28 @@ public:
|
|||
MOUSE_MODE_CONFINED
|
||||
};
|
||||
|
||||
#undef CursorShape
|
||||
enum CursorShape {
|
||||
CURSOR_ARROW,
|
||||
CURSOR_IBEAM,
|
||||
CURSOR_POINTING_HAND,
|
||||
CURSOR_CROSS,
|
||||
CURSOR_WAIT,
|
||||
CURSOR_BUSY,
|
||||
CURSOR_DRAG,
|
||||
CURSOR_CAN_DROP,
|
||||
CURSOR_FORBIDDEN,
|
||||
CURSOR_VSIZE,
|
||||
CURSOR_HSIZE,
|
||||
CURSOR_BDIAGSIZE,
|
||||
CURSOR_FDIAGSIZE,
|
||||
CURSOR_MOVE,
|
||||
CURSOR_VSPLIT,
|
||||
CURSOR_HSPLIT,
|
||||
CURSOR_HELP,
|
||||
CURSOR_MAX
|
||||
};
|
||||
|
||||
void set_mouse_mode(MouseMode p_mode);
|
||||
MouseMode get_mouse_mode() const;
|
||||
|
||||
|
@ -96,7 +118,7 @@ public:
|
|||
|
||||
virtual bool is_emulating_touchscreen() const = 0;
|
||||
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot = Vector2()) = 0;
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0;
|
||||
virtual void set_mouse_in_window(bool p_in_window) = 0;
|
||||
|
||||
virtual String get_joy_button_string(int p_button) = 0;
|
||||
|
@ -110,5 +132,6 @@ public:
|
|||
};
|
||||
|
||||
VARIANT_ENUM_CAST(Input::MouseMode);
|
||||
VARIANT_ENUM_CAST(Input::CursorShape);
|
||||
|
||||
#endif // INPUT_H
|
||||
|
|
|
@ -325,6 +325,7 @@ public:
|
|||
virtual int get_virtual_keyboard_height() const;
|
||||
|
||||
virtual void set_cursor_shape(CursorShape p_shape) = 0;
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) = 0;
|
||||
|
||||
virtual bool get_swap_ok_cancel() { return false; }
|
||||
virtual void dump_memory_to_file(const char *p_file);
|
||||
|
|
|
@ -275,9 +275,12 @@
|
|||
</return>
|
||||
<argument index="0" name="image" type="Resource">
|
||||
</argument>
|
||||
<argument index="1" name="hotspot" type="Vector2" default="Vector2( 0, 0 )">
|
||||
<argument index="1" name="cursor_shape" type="int" default="CURSOR_ARROW">
|
||||
</argument>
|
||||
<argument index="2" name="hotspot" type="Vector2" default="Vector2( 0, 0 )">
|
||||
</argument>
|
||||
<description>
|
||||
Set a custom mouse cursor image, which is only visible inside the game window. The hotspot can also be specified. See enum [code]CURSOR_*[/code] for the list of shapes.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_mouse_mode">
|
||||
|
|
|
@ -497,26 +497,16 @@ bool InputDefault::is_emulating_touchscreen() const {
|
|||
return emulate_touch;
|
||||
}
|
||||
|
||||
void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot) {
|
||||
/* no longer supported, leaving this for reference to anyone who might want to implement hardware cursors
|
||||
void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||
if (Engine::get_singleton()->is_editor_hint())
|
||||
return;
|
||||
|
||||
if (custom_cursor == p_cursor)
|
||||
return;
|
||||
|
||||
custom_cursor = p_cursor;
|
||||
|
||||
if (p_cursor.is_null()) {
|
||||
set_mouse_mode(MOUSE_MODE_VISIBLE);
|
||||
//removed, please insist us to implement hardare cursors
|
||||
//VisualServer::get_singleton()->cursor_set_visible(false);
|
||||
} else {
|
||||
Ref<AtlasTexture> atex = custom_cursor;
|
||||
Rect2 region = atex.is_valid() ? atex->get_region() : Rect2();
|
||||
set_mouse_mode(MOUSE_MODE_HIDDEN);
|
||||
VisualServer::get_singleton()->cursor_set_visible(true);
|
||||
VisualServer::get_singleton()->cursor_set_texture(custom_cursor->get_rid(), p_hotspot, 0, region);
|
||||
VisualServer::get_singleton()->cursor_set_pos(get_mouse_position());
|
||||
}
|
||||
*/
|
||||
OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot);
|
||||
}
|
||||
|
||||
void InputDefault::set_mouse_in_window(bool p_in_window) {
|
||||
|
|
|
@ -225,7 +225,7 @@ public:
|
|||
void set_emulate_touch(bool p_emulate);
|
||||
virtual bool is_emulating_touchscreen() const;
|
||||
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot = Vector2());
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
|
||||
virtual void set_mouse_in_window(bool p_in_window);
|
||||
|
||||
void parse_mapping(String p_mapping);
|
||||
|
|
|
@ -1107,7 +1107,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
|||
if (cursor.is_valid()) {
|
||||
//print_line("loaded ok");
|
||||
Vector2 hotspot = ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image_hotspot");
|
||||
Input::get_singleton()->set_custom_mouse_cursor(cursor, hotspot);
|
||||
Input::get_singleton()->set_custom_mouse_cursor(cursor, Input::CURSOR_ARROW, hotspot);
|
||||
}
|
||||
}
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
|
|
@ -248,6 +248,9 @@ void OS_Android::set_cursor_shape(CursorShape p_shape) {
|
|||
//android really really really has no mouse.. how amazing..
|
||||
}
|
||||
|
||||
void OS_Android::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||
}
|
||||
|
||||
void OS_Android::main_loop_begin() {
|
||||
|
||||
if (main_loop)
|
||||
|
|
|
@ -182,6 +182,7 @@ public:
|
|||
virtual bool can_draw() const;
|
||||
|
||||
virtual void set_cursor_shape(CursorShape p_shape);
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
|
||||
|
||||
void main_loop_begin();
|
||||
bool main_loop_iterate();
|
||||
|
|
|
@ -200,6 +200,10 @@ void OS_Haiku::set_cursor_shape(CursorShape p_shape) {
|
|||
//ERR_PRINT("set_cursor_shape() NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
void OS_Haiku::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
int OS_Haiku::get_screen_count() const {
|
||||
// TODO: implement get_screen_count()
|
||||
return 1;
|
||||
|
|
|
@ -87,6 +87,7 @@ public:
|
|||
virtual Point2 get_mouse_position() const;
|
||||
virtual int get_mouse_button_state() const;
|
||||
virtual void set_cursor_shape(CursorShape p_shape);
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
|
||||
|
||||
virtual int get_screen_count() const;
|
||||
virtual int get_current_screen() const;
|
||||
|
|
|
@ -490,6 +490,8 @@ String OSIPhone::get_user_data_dir() const {
|
|||
return data_dir;
|
||||
};
|
||||
|
||||
void OSIPhone::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot){};
|
||||
|
||||
String OSIPhone::get_name() {
|
||||
|
||||
return "iOS";
|
||||
|
|
|
@ -173,6 +173,7 @@ public:
|
|||
virtual int get_virtual_keyboard_height() const;
|
||||
|
||||
virtual void set_cursor_shape(CursorShape p_shape);
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
|
||||
|
||||
virtual Size2 get_window_size() const;
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "servers/visual/rasterizer.h"
|
||||
#include "servers/visual/visual_server_wrap_mt.h"
|
||||
#include "servers/visual_server.h"
|
||||
#include <AppKit/NSCursor.h>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
#undef CursorShape
|
||||
|
@ -86,6 +87,7 @@ public:
|
|||
id context;
|
||||
|
||||
CursorShape cursor_shape;
|
||||
NSCursor *cursors[CURSOR_MAX] = { NULL };
|
||||
MouseMode mouse_mode;
|
||||
|
||||
String title;
|
||||
|
@ -137,6 +139,7 @@ public:
|
|||
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
|
||||
|
||||
virtual void set_cursor_shape(CursorShape p_shape);
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
|
||||
|
||||
virtual void set_mouse_show(bool p_show);
|
||||
virtual void set_mouse_grab(bool p_grab);
|
||||
|
|
|
@ -577,8 +577,11 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
|
|||
return;
|
||||
if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode != OS::MOUSE_MODE_CAPTURED)
|
||||
OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
|
||||
if (OS_OSX::singleton->input)
|
||||
if (OS_OSX::singleton->input) {
|
||||
OS_OSX::singleton->input->set_mouse_in_window(true);
|
||||
OS_OSX::singleton->cursor_shape = OS::CURSOR_MAX;
|
||||
OS_OSX::singleton->set_cursor_shape(OS::CURSOR_ARROW);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)magnifyWithEvent:(NSEvent *)event {
|
||||
|
@ -1240,30 +1243,84 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) {
|
|||
if (cursor_shape == p_shape)
|
||||
return;
|
||||
|
||||
switch (p_shape) {
|
||||
case CURSOR_ARROW: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_IBEAM: [[NSCursor IBeamCursor] set]; break;
|
||||
case CURSOR_POINTING_HAND: [[NSCursor pointingHandCursor] set]; break;
|
||||
case CURSOR_CROSS: [[NSCursor crosshairCursor] set]; break;
|
||||
case CURSOR_WAIT: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break;
|
||||
case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break;
|
||||
case CURSOR_FORBIDDEN: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_VSIZE: [[NSCursor resizeUpDownCursor] set]; break;
|
||||
case CURSOR_HSIZE: [[NSCursor resizeLeftRightCursor] set]; break;
|
||||
case CURSOR_BDIAGSIZE: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_FDIAGSIZE: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break;
|
||||
case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break;
|
||||
case CURSOR_HELP: [[NSCursor arrowCursor] set]; break;
|
||||
default: {};
|
||||
if (cursors[p_shape] != NULL) {
|
||||
[cursors[p_shape] set];
|
||||
} else {
|
||||
switch (p_shape) {
|
||||
case CURSOR_ARROW: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_IBEAM: [[NSCursor IBeamCursor] set]; break;
|
||||
case CURSOR_POINTING_HAND: [[NSCursor pointingHandCursor] set]; break;
|
||||
case CURSOR_CROSS: [[NSCursor crosshairCursor] set]; break;
|
||||
case CURSOR_WAIT: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_BUSY: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_DRAG: [[NSCursor closedHandCursor] set]; break;
|
||||
case CURSOR_CAN_DROP: [[NSCursor openHandCursor] set]; break;
|
||||
case CURSOR_FORBIDDEN: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_VSIZE: [[NSCursor resizeUpDownCursor] set]; break;
|
||||
case CURSOR_HSIZE: [[NSCursor resizeLeftRightCursor] set]; break;
|
||||
case CURSOR_BDIAGSIZE: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_FDIAGSIZE: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_MOVE: [[NSCursor arrowCursor] set]; break;
|
||||
case CURSOR_VSPLIT: [[NSCursor resizeUpDownCursor] set]; break;
|
||||
case CURSOR_HSPLIT: [[NSCursor resizeLeftRightCursor] set]; break;
|
||||
case CURSOR_HELP: [[NSCursor arrowCursor] set]; break;
|
||||
default: {};
|
||||
}
|
||||
}
|
||||
|
||||
cursor_shape = 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<Texture> texture = p_cursor;
|
||||
Ref<Image> image = texture->get_data();
|
||||
|
||||
int image_size = 32 * 32;
|
||||
|
||||
ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32);
|
||||
|
||||
NSBitmapImageRep *imgrep = [[[NSBitmapImageRep alloc]
|
||||
initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:image->get_width()
|
||||
pixelsHigh:image->get_height()
|
||||
bitsPerSample:8
|
||||
samplesPerPixel:4
|
||||
hasAlpha:YES
|
||||
isPlanar:NO
|
||||
colorSpaceName:NSDeviceRGBColorSpace
|
||||
bytesPerRow:image->get_width() * 4
|
||||
bitsPerPixel:32] autorelease];
|
||||
|
||||
ERR_FAIL_COND(imgrep == nil);
|
||||
uint8_t *pixels = [imgrep bitmapData];
|
||||
|
||||
int len = image->get_width() * image->get_height();
|
||||
PoolVector<uint8_t> data = image->get_data();
|
||||
PoolVector<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);
|
||||
pixels[i * 4 + 3] = alpha;
|
||||
}
|
||||
|
||||
NSImage *nsimage = [[[NSImage alloc] initWithSize:NSMakeSize(image->get_width(), image->get_height())] autorelease];
|
||||
[nsimage addRepresentation:imgrep];
|
||||
|
||||
NSCursor *cursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSMakePoint(p_hotspot.x, p_hotspot.y)];
|
||||
|
||||
cursors[p_shape] = cursor;
|
||||
|
||||
if (p_shape == CURSOR_ARROW) {
|
||||
[cursor set];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OS_OSX::set_mouse_show(bool p_show) {
|
||||
}
|
||||
|
||||
|
|
|
@ -179,6 +179,9 @@ void OS_Server::move_window_to_foreground() {
|
|||
void OS_Server::set_cursor_shape(CursorShape p_shape) {
|
||||
}
|
||||
|
||||
void OS_Server::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||
}
|
||||
|
||||
OS::PowerState OS_Server::get_power_state() {
|
||||
return power_manager->get_power_state();
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ public:
|
|||
virtual String get_name();
|
||||
|
||||
virtual void set_cursor_shape(CursorShape p_shape);
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
|
||||
|
||||
virtual void set_mouse_show(bool p_show);
|
||||
virtual void set_mouse_grab(bool p_grab);
|
||||
|
|
|
@ -651,6 +651,10 @@ void OSUWP::set_cursor_shape(CursorShape p_shape) {
|
|||
cursor_shape = p_shape;
|
||||
}
|
||||
|
||||
void OSUWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
Error OSUWP::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
|
||||
|
||||
return FAILED;
|
||||
|
|
|
@ -218,6 +218,7 @@ public:
|
|||
virtual String get_clipboard() const;
|
||||
|
||||
void set_cursor_shape(CursorShape p_shape);
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
|
||||
void set_icon(const Ref<Image> &p_icon);
|
||||
|
||||
virtual String get_executable_path() const;
|
||||
|
|
|
@ -1844,10 +1844,125 @@ void OS_Windows::set_cursor_shape(CursorShape p_shape) {
|
|||
IDC_HELP
|
||||
};
|
||||
|
||||
SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
|
||||
if (cursors[p_shape] != NULL) {
|
||||
SetCursor(cursors[p_shape]);
|
||||
} else {
|
||||
SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
|
||||
}
|
||||
cursor_shape = p_shape;
|
||||
}
|
||||
|
||||
void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||
if (p_cursor.is_valid()) {
|
||||
Ref<Texture> texture = p_cursor;
|
||||
Ref<Image> image = texture->get_data();
|
||||
|
||||
UINT image_size = 32 * 32;
|
||||
UINT size = sizeof(UINT) * image_size;
|
||||
|
||||
ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32);
|
||||
|
||||
// Create the BITMAP with alpha channel
|
||||
COLORREF *buffer = (COLORREF *)malloc(sizeof(COLORREF) * image_size);
|
||||
|
||||
image->lock();
|
||||
for (UINT index = 0; index < image_size; index++) {
|
||||
int column_index = floor(index / 32);
|
||||
int row_index = index % 32;
|
||||
|
||||
Color pcColor = image->get_pixel(row_index, column_index);
|
||||
*(buffer + index) = image->get_pixel(row_index, column_index).to_argb32();
|
||||
}
|
||||
image->unlock();
|
||||
|
||||
// Using 4 channels, so 4 * 8 bits
|
||||
HBITMAP bitmap = CreateBitmap(32, 32, 1, 4 * 8, buffer);
|
||||
COLORREF clrTransparent = -1;
|
||||
|
||||
// Create the AND and XOR masks for the bitmap
|
||||
HBITMAP hAndMask = NULL;
|
||||
HBITMAP hXorMask = NULL;
|
||||
|
||||
GetMaskBitmaps(bitmap, clrTransparent, hAndMask, hXorMask);
|
||||
|
||||
if (NULL == hAndMask || NULL == hXorMask) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Finally, create the icon
|
||||
ICONINFO iconinfo = { 0 };
|
||||
iconinfo.fIcon = FALSE;
|
||||
iconinfo.xHotspot = p_hotspot.x;
|
||||
iconinfo.yHotspot = p_hotspot.y;
|
||||
iconinfo.hbmMask = hAndMask;
|
||||
iconinfo.hbmColor = hXorMask;
|
||||
|
||||
cursors[p_shape] = CreateIconIndirect(&iconinfo);
|
||||
|
||||
if (p_shape == CURSOR_ARROW) {
|
||||
SetCursor(cursors[p_shape]);
|
||||
}
|
||||
|
||||
if (hAndMask != NULL) {
|
||||
DeleteObject(hAndMask);
|
||||
}
|
||||
|
||||
if (hXorMask != NULL) {
|
||||
DeleteObject(hXorMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OS_Windows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) {
|
||||
|
||||
// Get the system display DC
|
||||
HDC hDC = GetDC(NULL);
|
||||
|
||||
// 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(NULL, 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 a 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 a 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);
|
||||
}
|
||||
|
||||
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) {
|
||||
|
||||
if (p_blocking && r_pipe) {
|
||||
|
|
|
@ -113,6 +113,7 @@ class OS_Windows : public OS {
|
|||
bool window_has_focus;
|
||||
uint32_t last_button_state;
|
||||
|
||||
HCURSOR cursors[CURSOR_MAX] = { NULL };
|
||||
CursorShape cursor_shape;
|
||||
|
||||
InputDefault *input;
|
||||
|
@ -244,6 +245,8 @@ public:
|
|||
virtual String get_clipboard() const;
|
||||
|
||||
void set_cursor_shape(CursorShape p_shape);
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
|
||||
void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);
|
||||
void set_icon(const Ref<Image> &p_icon);
|
||||
|
||||
virtual String get_executable_path() const;
|
||||
|
|
|
@ -2205,6 +2205,48 @@ void OS_X11::set_cursor_shape(CursorShape p_shape) {
|
|||
current_cursor = p_shape;
|
||||
}
|
||||
|
||||
void OS_X11::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||
if (p_cursor.is_valid()) {
|
||||
Ref<Texture> texture = p_cursor;
|
||||
Ref<Image> image = texture->get_data();
|
||||
|
||||
ERR_FAIL_COND(texture->get_width() != 32 || texture->get_height() != 32);
|
||||
|
||||
// Create the cursor structure
|
||||
XcursorImage *cursor_image = XcursorImageCreate(texture->get_width(), texture->get_height());
|
||||
XcursorUInt image_size = 32 * 32;
|
||||
XcursorDim size = sizeof(XcursorPixel) * image_size;
|
||||
|
||||
cursor_image->version = 1;
|
||||
cursor_image->size = size;
|
||||
cursor_image->xhot = p_hotspot.x;
|
||||
cursor_image->yhot = p_hotspot.y;
|
||||
|
||||
// allocate memory to contain the whole file
|
||||
cursor_image->pixels = (XcursorPixel *)malloc(size);
|
||||
|
||||
image->lock();
|
||||
|
||||
for (XcursorPixel index = 0; index < image_size; index++) {
|
||||
int column_index = floor(index / 32);
|
||||
int row_index = index % 32;
|
||||
|
||||
*(cursor_image->pixels + index) = image->get_pixel(row_index, column_index).to_argb32();
|
||||
}
|
||||
|
||||
image->unlock();
|
||||
|
||||
ERR_FAIL_COND(cursor_image->pixels == NULL);
|
||||
|
||||
// Save it for a further usage
|
||||
cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_image);
|
||||
|
||||
if (p_shape == CURSOR_ARROW) {
|
||||
XDefineCursor(x11_display, x11_window, cursors[p_shape]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OS_X11::release_rendering_thread() {
|
||||
|
||||
context_gl->release_current();
|
||||
|
|
|
@ -204,6 +204,7 @@ public:
|
|||
virtual String get_name();
|
||||
|
||||
virtual void set_cursor_shape(CursorShape p_shape);
|
||||
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
|
||||
|
||||
void set_mouse_mode(MouseMode p_mode);
|
||||
MouseMode get_mouse_mode() const;
|
||||
|
|
Loading…
Reference in a new issue