Merge pull request #13437 from xsellier/bugfix/mouse-cursor-lag

Implement hardware cursor acceleration for Godot Engine 2.1
This commit is contained in:
Rémi Verschelde 2018-01-03 08:36:44 +01:00 committed by GitHub
commit 3102dc17ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 335 additions and 264 deletions

View File

@ -81,13 +81,32 @@ void Input::_bind_methods() {
ObjectTypeDB::bind_method(_MD("warp_mouse_pos", "to"), &Input::warp_mouse_pos);
ObjectTypeDB::bind_method(_MD("action_press", "action"), &Input::action_press);
ObjectTypeDB::bind_method(_MD("action_release", "action"), &Input::action_release);
ObjectTypeDB::bind_method(_MD("set_custom_mouse_cursor", "image:Texture", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(Vector2()));
ObjectTypeDB::bind_method(_MD("set_custom_mouse_cursor", "image:Texture", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
ObjectTypeDB::bind_method(_MD("parse_input_event", "event"), &Input::parse_input_event);
BIND_CONSTANT(MOUSE_MODE_VISIBLE);
BIND_CONSTANT(MOUSE_MODE_HIDDEN);
BIND_CONSTANT(MOUSE_MODE_CAPTURED);
// Those constants are used to change the mouse texture for given cursor shapes
BIND_CONSTANT(CURSOR_ARROW);
BIND_CONSTANT(CURSOR_IBEAM);
BIND_CONSTANT(CURSOR_POINTING_HAND);
BIND_CONSTANT(CURSOR_CROSS);
BIND_CONSTANT(CURSOR_WAIT);
BIND_CONSTANT(CURSOR_BUSY);
BIND_CONSTANT(CURSOR_DRAG);
BIND_CONSTANT(CURSOR_CAN_DROP);
BIND_CONSTANT(CURSOR_FORBIDDEN);
BIND_CONSTANT(CURSOR_VSIZE);
BIND_CONSTANT(CURSOR_HSIZE);
BIND_CONSTANT(CURSOR_BDIAGSIZE);
BIND_CONSTANT(CURSOR_FDIAGSIZE);
BIND_CONSTANT(CURSOR_MOVE);
BIND_CONSTANT(CURSOR_VSPLIT);
BIND_CONSTANT(CURSOR_HSPLIT);
BIND_CONSTANT(CURSOR_HELP);
ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "connected")));
}

View File

@ -50,6 +50,28 @@ public:
MOUSE_MODE_CAPTURED
};
#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;
@ -93,8 +115,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_mouse_in_window(bool p_in_window) = 0;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0;
virtual String get_joy_button_string(int p_button) = 0;
virtual String get_joy_axis_string(int p_axis) = 0;
@ -107,5 +128,6 @@ public:
};
VARIANT_ENUM_CAST(Input::MouseMode);
VARIANT_ENUM_CAST(Input::CursorShape);
#endif // INPUT_H

View File

@ -314,7 +314,8 @@ public:
virtual void hide_virtual_keyboard();
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);
virtual void dump_resources_to_file(const char *p_file);

View File

@ -16607,9 +16607,12 @@
<method name="set_custom_mouse_cursor">
<argument index="0" name="image" type="Texture">
</argument>
<argument index="1" name="hotspot" type="Vector2" default="Vector2(0, 0)">
<argument index="1" name="hotspot" type="int" default="CURSOR_ARROW">
</argument>
<argument index="2" name="hotspot" type="Vector2" default="Vector2(0, 0)">
</argument>
<description>
See enum CURSOR_* for the list of shapes.
Set a custom mouse cursor image, which is only visible inside the game window. The hotspot can also be specified.
</description>
</method>
@ -46819,42 +46822,6 @@
<description>
</description>
</method>
<method name="cursor_set_pos">
<argument index="0" name="arg0" type="Vector2">
</argument>
<argument index="1" name="arg1" type="int">
</argument>
<description>
</description>
</method>
<method name="cursor_set_rotation">
<argument index="0" name="arg0" type="float">
</argument>
<argument index="1" name="arg1" type="int">
</argument>
<description>
</description>
</method>
<method name="cursor_set_texture">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Vector2">
</argument>
<argument index="2" name="arg2" type="int">
</argument>
<argument index="3" name="arg3" type="Rect2">
</argument>
<description>
</description>
</method>
<method name="cursor_set_visible">
<argument index="0" name="arg0" type="bool">
</argument>
<argument index="1" name="arg1" type="int">
</argument>
<description>
</description>
</method>
<method name="draw">
<description>
</description>

View File

@ -80,8 +80,6 @@ static const char *globals_renames[][2] = {
{ "display/custom_theme", "gui/theme/custom" },
{ "display/custom_theme_font", "gui/theme/custom_font" },
{ "display/swap_ok_cancel", "gui/common/swap_ok_cancel" },
{ "display/custom_mouse_cursor", "display/mouse_cursor/custom_image" },
{ "display/custom_mouse_cursor_hotspot", "display/mouse_cursor/custom_hotspot" },
{ "display/tooltip_delay", "gui/timers/tooltip_delay_sec" },
{ "display/text_edit_idle_detect_sec", "gui/timers/text_edit_idle_detect_sec" },
{ "display/stretch_mode", "display/stretch/mode" },

View File

@ -930,17 +930,6 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func
boot_splash = splash;
}
}
StringName custom_cursor;
{
String splash = Globals::get_singleton()->get("display/custom_mouse_cursor"); //avoid splash from being converted
splash = splash.strip_edges();
if (splash != String()) {
if (!splash.begins_with("res://"))
splash = "res://" + splash;
splash = splash.simplify_path();
custom_cursor = splash;
}
}
for (int i = 0; i < files.size(); i++) {
@ -949,7 +938,7 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func
String src = files[i];
Vector<uint8_t> buf;
if (src == boot_splash || src == custom_cursor)
if (src == boot_splash)
buf = get_exported_file_default(src); //bootsplash must be kept if used
else
buf = get_exported_file(src);

View File

@ -415,9 +415,6 @@ void InputDefault::set_mouse_pos(const Point2 &p_posf) {
mouse_speed_track.update(p_posf - mouse_pos);
mouse_pos = p_posf;
if (custom_cursor.is_valid()) {
VisualServer::get_singleton()->cursor_set_pos(get_mouse_pos());
}
}
Point2 InputDefault::get_mouse_pos() const {
@ -497,37 +494,13 @@ bool InputDefault::is_emulating_touchscreen() const {
return emulate_touch;
}
void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, const Vector2 &p_hotspot) {
if (custom_cursor == p_cursor)
void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (custom_cursors[p_shape] == p_cursor)
return;
custom_cursor = p_cursor;
custom_cursors[p_shape] = p_cursor;
if (p_cursor.is_null()) {
set_mouse_mode(MOUSE_MODE_VISIBLE);
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_pos());
}
}
void InputDefault::set_mouse_in_window(bool p_in_window) {
if (custom_cursor.is_valid()) {
if (p_in_window) {
set_mouse_mode(MOUSE_MODE_HIDDEN);
VisualServer::get_singleton()->cursor_set_visible(true);
} else {
set_mouse_mode(MOUSE_MODE_VISIBLE);
VisualServer::get_singleton()->cursor_set_visible(false);
}
}
OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape) p_shape, p_hotspot);
}
// from github.com/gabomdq/SDL_GameControllerDB

View File

@ -105,7 +105,7 @@ class InputDefault : public Input {
SpeedTrack mouse_speed_track;
Map<int, Joystick> joy_names;
int fallback_mapping;
RES custom_cursor;
RES custom_cursors[CURSOR_MAX] = { NULL };
public:
enum HatMask {
@ -214,8 +214,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_mouse_in_window(bool p_in_window);
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
void parse_mapping(String p_mapping);
uint32_t joy_button(uint32_t p_last_id, int p_device, int p_button, bool p_pressed);

View File

@ -953,20 +953,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
register_scene_types();
register_server_types();
GLOBAL_DEF("display/custom_mouse_cursor", String());
GLOBAL_DEF("display/custom_mouse_cursor_hotspot", Vector2());
Globals::get_singleton()->set_custom_property_info("display/custom_mouse_cursor", PropertyInfo(Variant::STRING, "display/custom_mouse_cursor", PROPERTY_HINT_FILE, "*.png,*.webp"));
if (String(Globals::get_singleton()->get("display/custom_mouse_cursor")) != String()) {
//print_line("use custom cursor");
Ref<Texture> cursor = ResourceLoader::load(Globals::get_singleton()->get("display/custom_mouse_cursor"));
if (cursor.is_valid()) {
// print_line("loaded ok");
Vector2 hotspot = Globals::get_singleton()->get("display/custom_mouse_cursor_hotspot");
Input::get_singleton()->set_custom_mouse_cursor(cursor, hotspot);
}
}
#ifdef TOOLS_ENABLED
EditorNode::register_editor_types();
#endif

View File

@ -30,7 +30,6 @@
#include "dvector.h"
#include "math_funcs.h"
#include "print_string.h"
#include "servers/visual/default_mouse_cursor.xpm"
#include "set.h"
#include "image.h"
@ -51,23 +50,6 @@ MainLoop *test() {
}
*/
{
// static const int size = 16;
Image img;
img.create(default_mouse_cursor_xpm);
{
for (int i = 0; i < 8; i++) {
Image mipmap;
//img.make_mipmap(mipmap);
img = mipmap;
if (img.get_width() <= 4) break;
};
};
};
#if 0
Set<int> set;

View File

@ -142,7 +142,6 @@ void OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int
visual_server = memnew(VisualServerWrapMT(visual_server, false));
};
visual_server->init();
visual_server->cursor_set_visible(false, 0);
AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
@ -325,6 +324,11 @@ 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) {
// Since android has no mouse, we do not need to change its texture (how amazing !)
}
void OS_Android::main_loop_begin() {
if (main_loop)

View File

@ -203,6 +203,7 @@ public:
virtual bool can_draw() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual void set_cursor_shape(CursorShape p_shape);
void main_loop_begin();

View File

@ -136,7 +136,6 @@ void OSBB10::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
visual_server = memnew(VisualServerRaster(rasterizer));
visual_server->init();
visual_server->cursor_set_visible(false, 0);
audio_driver = memnew(AudioDriverBB10);
audio_driver->set_singleton();
@ -285,6 +284,11 @@ void OSBB10::set_cursor_shape(CursorShape p_shape) {
//android really really really has no mouse.. how amazing..
}
void OSBB10::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
// Since BlackBerry 10 has no mouse, we do not need to change its texture (how amazing !)
}
void OSBB10::handle_screen_event(bps_event_t *event) {
screen_event_t screen_event = screen_event_get_event(event);

View File

@ -142,6 +142,7 @@ public:
virtual bool can_draw() const;
virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
virtual void set_cursor_shape(CursorShape p_shape);
virtual bool has_touchscreen_ui_hint() const;

View File

@ -235,6 +235,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: implement set_custom_mouse_cursor()
}
int OS_Haiku::get_screen_count() const {
// TODO: implement get_screen_count()
return 1;

View File

@ -98,7 +98,8 @@ public:
virtual Point2 get_mouse_pos() 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;
virtual void set_current_screen(int p_screen);

View File

@ -120,7 +120,6 @@ void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_
visual_server->init();
visual_server->init();
visual_server->cursor_set_visible(false, 0);
audio_driver = memnew(AudioDriverIphone);
audio_driver->set_singleton();
@ -479,6 +478,10 @@ void OSIPhone::set_cursor_shape(CursorShape p_shape){
};
void OSIPhone::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
};
String OSIPhone::get_data_dir() const {
return data_dir;

View File

@ -183,6 +183,7 @@ public:
virtual void hide_virtual_keyboard();
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;

View File

@ -439,7 +439,6 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i
visual_server = memnew(VisualServerRaster(rasterizer));
visual_server->init();
visual_server->cursor_set_visible(false, 0);
/*AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
@ -686,6 +685,10 @@ void OS_JavaScript::set_cursor_shape(CursorShape p_shape) {
//javascript really really really has no mouse.. how amazing..
}
void OS_JavaScript::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
}
void OS_JavaScript::main_loop_begin() {
if (main_loop)

View File

@ -138,6 +138,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();

View File

@ -49,6 +49,7 @@
#include "servers/visual/visual_server_wrap_mt.h"
#include "servers/visual_server.h"
#include <ApplicationServices/ApplicationServices.h>
#include <AppKit/NSCursor.h>
//bitch
#undef CursorShape
@ -102,6 +103,7 @@ public:
id context;
CursorShape cursor_shape;
NSCursor *cursors[CURSOR_MAX] = { NULL };
MouseMode mouse_mode;
String title;
@ -149,6 +151,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);

View File

@ -38,6 +38,7 @@
#include "servers/physics/physics_server_sw.h"
#include "servers/visual/visual_server_raster.h"
#include "servers/visual/visual_server_wrap_mt.h"
#include "scene/resources/texture.h"
#include <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h>
@ -490,9 +491,6 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
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_EXIT);
if (OS_OSX::singleton->input)
OS_OSX::singleton->input->set_mouse_in_window(false);
//_glfwInputCursorEnter(window, GL_FALSE);
}
@ -505,7 +503,8 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
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)viewDidChangeBackingProperties {
@ -1026,7 +1025,6 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
}
visual_server->init();
visual_server->cursor_set_visible(false, 0);
AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
@ -1167,30 +1165,83 @@ 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<ImageTexture> texture = p_cursor;
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();
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);
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) {
}

View File

@ -198,6 +198,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) {
}
void OS_Server::run() {
force_quit = false;

View File

@ -89,6 +89,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);

View File

@ -42,6 +42,7 @@
#include "servers/audio/audio_server_sw.h"
#include "servers/visual/visual_server_raster.h"
#include "servers/visual/visual_server_wrap_mt.h"
#include "scene/resources/texture.h"
#include "globals.h"
#include "io/marshalls.h"
@ -359,8 +360,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
outside = true;
if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
if (input)
input->set_mouse_in_window(false);
} break;
case WM_MOUSEMOVE: {
@ -370,8 +369,6 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
if (input)
input->set_mouse_in_window(true);
CursorShape c = cursor_shape;
cursor_shape = CURSOR_MAX;
@ -1937,10 +1934,124 @@ 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<ImageTexture> texture = p_cursor;
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);
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();
}
// 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) {

View File

@ -126,6 +126,7 @@ class OS_Windows : public OS {
bool force_quit;
uint32_t last_button_state;
HCURSOR cursors[CURSOR_MAX] = { NULL };
CursorShape cursor_shape;
InputDefault *input;
@ -255,6 +256,8 @@ public:
virtual String get_clipboard() const;
void set_cursor_shape(CursorShape p_shape);
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 Image &p_icon);
virtual String get_executable_path() const;

View File

@ -771,6 +771,13 @@ void OSWinrt::set_cursor_shape(CursorShape p_shape) {
cursor_shape = p_shape;
}
void OSWinrt::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
// FIXME:
// Not implemented, some work needs to be done for this one
// Might be a good source: https://stackoverflow.com/questions/43793745/set-custom-mouse-cursor-on-windows-10-universal-app-uwp
}
Error OSWinrt::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;

View File

@ -236,6 +236,7 @@ public:
virtual String get_clipboard() const;
void set_cursor_shape(CursorShape p_shape);
void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
void set_icon(const Image &p_icon);
virtual String get_executable_path() const;

View File

@ -42,6 +42,7 @@
#include "X11/Xatom.h"
#include "X11/extensions/Xinerama.h"
#include "scene/resources/texture.h"
// ICCCM
#define WM_NormalState 1L // window normal state
#define WM_IconicState 3L // window minimized
@ -1452,16 +1453,12 @@ void OS_X11::process_xevents() {
if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
if (input)
input->set_mouse_in_window(false);
} break;
case EnterNotify: {
if (main_loop && mouse_mode != MOUSE_MODE_CAPTURED)
main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
if (input)
input->set_mouse_in_window(true);
} break;
case FocusIn:
minimized = false;
@ -2038,6 +2035,45 @@ 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<ImageTexture> texture = p_cursor;
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);
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();
}
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();

View File

@ -218,6 +218,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;

View File

@ -1,23 +0,0 @@
/* XPM */
static const char * default_mouse_cursor_xpm[] = {
"16 16 4 1",
" c None",
". c #000000",
"+ c #FF00FF",
"@ c #FFFFFF",
"...+++++++++++++",
".@...+++++++++++",
".@@@...+++++++++",
".@@@@@....++++++",
".@@@@@@@@...++++",
".@@@@@@@@@@...++",
".@@@@@@@@@@@@..+",
".@@@@@@@@@@@@@..",
".@@@@@@@@@@@@..+",
".@@@@@@@@@@@..++",
".@@@@@@@@@...+++",
".@@@.....@@..+++",
".....+++.@@@..++",
"++++++++..@@@..+",
"+++++++++..@@@.+",
"++++++++++.....+"};

View File

@ -28,7 +28,6 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "visual_server_raster.h"
#include "default_mouse_cursor.xpm"
#include "globals.h"
#include "io/marshalls.h"
#include "os/os.h"
@ -4068,38 +4067,6 @@ void VisualServerRaster::canvas_item_material_set_shading_mode(RID p_material, C
/******** CANVAS *********/
void VisualServerRaster::cursor_set_rotation(float p_rotation, int p_cursor) {
VS_CHANGED;
ERR_FAIL_INDEX(p_cursor, MAX_CURSORS);
cursors[p_cursor].rot = p_rotation;
};
void VisualServerRaster::cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor, const Rect2 &p_region) {
VS_CHANGED;
ERR_FAIL_INDEX(p_cursor, MAX_CURSORS);
cursors[p_cursor].texture = p_texture;
cursors[p_cursor].center = p_center_offset;
cursors[p_cursor].region = p_region;
};
void VisualServerRaster::cursor_set_visible(bool p_visible, int p_cursor) {
VS_CHANGED;
ERR_FAIL_INDEX(p_cursor, MAX_CURSORS);
cursors[p_cursor].visible = p_visible;
};
void VisualServerRaster::cursor_set_pos(const Point2 &p_pos, int p_cursor) {
ERR_FAIL_INDEX(p_cursor, MAX_CURSORS);
if (cursors[p_cursor].pos == p_pos)
return;
VS_CHANGED;
cursors[p_cursor].pos = p_pos;
};
void VisualServerRaster::black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) {
black_margin[MARGIN_LEFT] = p_left;
@ -6925,24 +6892,6 @@ void VisualServerRaster::_draw_cursors_and_margins() {
rasterizer->canvas_begin();
rasterizer->canvas_begin_rect(Matrix32());
for (int i = 0; i < MAX_CURSORS; i++) {
if (!cursors[i].visible) {
continue;
};
RID tex = cursors[i].texture ? cursors[i].texture : default_cursor_texture;
ERR_CONTINUE(!tex);
if (cursors[i].region.has_no_area()) {
Point2 size(texture_get_width(tex), texture_get_height(tex));
rasterizer->canvas_draw_rect(Rect2(cursors[i].pos - cursors[i].center, size), 0, Rect2(), tex, Color(1, 1, 1, 1));
} else {
Point2 size = cursors[i].region.size;
rasterizer->canvas_draw_rect(Rect2(cursors[i].pos - cursors[i].center, size), Rasterizer::CANVAS_RECT_REGION, cursors[i].region, tex, Color(1, 1, 1, 1));
}
};
if (black_image[MARGIN_LEFT].is_valid()) {
Size2 sz(rasterizer->texture_get_width(black_image[MARGIN_LEFT]), rasterizer->texture_get_height(black_image[MARGIN_LEFT]));
rasterizer->canvas_draw_rect(Rect2(0, 0, black_margin[MARGIN_LEFT], window_h), 0, Rect2(0, 0, sz.x, sz.y), black_image[MARGIN_LEFT], Color(1, 1, 1));
@ -7085,11 +7034,6 @@ void VisualServerRaster::init() {
for (int i = 0; i < 4; i++)
black_margin[i] = 0;
Image img;
img.create(default_mouse_cursor_xpm);
//img.convert(Image::FORMAT_RGB);
default_cursor_texture = texture_create_from_image(img, 0);
aabb_random_points.resize(GLOBAL_DEF("render/aabb_random_points", 16));
for (int i = 0; i < aabb_random_points.size(); i++)
aabb_random_points[i] = Vector3(Math::random(0, 1), Math::random(0, 1), Math::random(0, 1));
@ -7116,7 +7060,6 @@ void VisualServerRaster::_clean_up_owner(RID_OwnerBase *p_owner, String p_type)
void VisualServerRaster::finish() {
free(default_cursor_texture);
if (test_cube.is_valid())
free(test_cube);

View File

@ -556,8 +556,6 @@ class VisualServerRaster : public VisualServer {
Rect2 canvas_clip;
Color clear_color;
Cursor cursors[MAX_CURSORS];
RID default_cursor_texture;
static void *instance_pair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int);
static void instance_unpair(void *p_self, OctreeElementID, Instance *p_A, int, OctreeElementID, Instance *p_B, int, void *);
@ -1213,12 +1211,6 @@ public:
virtual Variant canvas_item_material_get_shader_param(RID p_material, const StringName &p_param) const;
virtual void canvas_item_material_set_shading_mode(RID p_material, CanvasItemShadingMode p_mode);
/* CURSOR */
virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0); // radians
virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset, int p_cursor = 0, const Rect2 &p_region = Rect2());
virtual void cursor_set_visible(bool p_visible, int p_cursor = 0);
virtual void cursor_set_pos(const Point2 &p_pos, int p_cursor = 0);
/* BLACK BARS */
virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom);

View File

@ -648,12 +648,6 @@ public:
FUNC2RC(Variant, canvas_item_material_get_shader_param, RID, const StringName &);
FUNC2(canvas_item_material_set_shading_mode, RID, CanvasItemShadingMode);
/* CURSOR */
FUNC2(cursor_set_rotation, float, int); // radians
FUNC4(cursor_set_texture, RID, const Point2 &, int, const Rect2 &);
FUNC2(cursor_set_visible, bool, int);
FUNC2(cursor_set_pos, const Point2 &, int);
/* BLACK BARS */
FUNC4(black_bars_set_margins, int, int, int, int);

View File

@ -522,11 +522,6 @@ void VisualServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("canvas_item_clear"), &VisualServer::canvas_item_clear);
ObjectTypeDB::bind_method(_MD("canvas_item_raise"), &VisualServer::canvas_item_raise);
ObjectTypeDB::bind_method(_MD("cursor_set_rotation"), &VisualServer::cursor_set_rotation);
ObjectTypeDB::bind_method(_MD("cursor_set_texture"), &VisualServer::cursor_set_texture);
ObjectTypeDB::bind_method(_MD("cursor_set_visible"), &VisualServer::cursor_set_visible);
ObjectTypeDB::bind_method(_MD("cursor_set_pos"), &VisualServer::cursor_set_pos);
ObjectTypeDB::bind_method(_MD("black_bars_set_margins", "left", "top", "right", "bottom"), &VisualServer::black_bars_set_margins);
ObjectTypeDB::bind_method(_MD("black_bars_set_images", "left", "top", "right", "bottom"), &VisualServer::black_bars_set_images);

View File

@ -1068,12 +1068,6 @@ public:
virtual void canvas_item_material_set_shading_mode(RID p_material, CanvasItemShadingMode p_mode) = 0;
/* CURSOR */
virtual void cursor_set_rotation(float p_rotation, int p_cursor = 0) = 0; // radians
virtual void cursor_set_texture(RID p_texture, const Point2 &p_center_offset = Point2(0, 0), int p_cursor = 0, const Rect2 &p_region = Rect2()) = 0;
virtual void cursor_set_visible(bool p_visible, int p_cursor = 0) = 0;
virtual void cursor_set_pos(const Point2 &p_pos, int p_cursor = 0) = 0;
/* BLACK BARS */
virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) = 0;