summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/ProjectSettings.xml6
-rw-r--r--editor/editor_node.cpp2
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp13
-rw-r--r--editor/progress_dialog.cpp2
-rw-r--r--modules/gridmap/grid_map.cpp4
-rw-r--r--platform/android/android_input_handler.cpp217
-rw-r--r--platform/android/android_input_handler.h22
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt16
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java23
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java35
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java23
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java87
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt289
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java279
-rw-r--r--platform/android/java_godot_lib_jni.cpp44
-rw-r--r--platform/android/java_godot_lib_jni.h10
-rw-r--r--scene/2d/tile_map.cpp17
-rw-r--r--scene/3d/navigation_region_3d.cpp1
-rw-r--r--scene/main/scene_tree.cpp52
-rw-r--r--scene/main/scene_tree.h8
-rw-r--r--scene/resources/navigation_mesh.cpp98
-rw-r--r--scene/resources/navigation_mesh.h8
24 files changed, 736 insertions, 526 deletions
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 1145798240..ce627bb762 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -477,9 +477,6 @@
<member name="debug/shapes/collision/shape_color" type="Color" setter="" getter="" default="Color(0, 0.6, 0.7, 0.42)">
Color of the collision shapes, visible when "Visible Collision Shapes" is enabled in the Debug menu.
</member>
- <member name="debug/shapes/navigation/disabled_geometry_color" type="Color" setter="" getter="" default="Color(1, 0.7, 0.1, 0.4)">
- Color of the disabled navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu.
- </member>
<member name="debug/shapes/navigation/edge_connection_color" type="Color" setter="" getter="" default="Color(1, 0, 1, 1)">
Color to display edge connections between navigation regions, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
@@ -504,9 +501,6 @@
<member name="debug/shapes/navigation/enable_link_connections_xray" type="bool" setter="" getter="" default="true">
If enabled, displays navigation link connections through geometry when "Visible Navigation" is enabled in the Debug menu.
</member>
- <member name="debug/shapes/navigation/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)">
- Color of the navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu.
- </member>
<member name="debug/shapes/navigation/geometry_edge_color" type="Color" setter="" getter="" default="Color(0.5, 1, 1, 1)">
Color to display enabled navigation mesh polygon edges, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index a2231f4601..13eccfec3e 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -566,8 +566,6 @@ void EditorNode::_update_from_settings() {
SceneTree *tree = get_tree();
tree->set_debug_collisions_color(GLOBAL_GET("debug/shapes/collision/shape_color"));
tree->set_debug_collision_contact_color(GLOBAL_GET("debug/shapes/collision/contact_color"));
- tree->set_debug_navigation_color(GLOBAL_GET("debug/shapes/navigation/geometry_color"));
- tree->set_debug_navigation_disabled_color(GLOBAL_GET("debug/shapes/navigation/disabled_geometry_color"));
#ifdef DEBUG_ENABLED
NavigationServer3D::get_singleton_mut()->set_debug_navigation_edge_connection_color(GLOBAL_GET("debug/shapes/navigation/edge_connection_color"));
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index 1dce41e4c7..4d54001b94 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -40,6 +40,10 @@
#include "editor/editor_scale.h"
#include "editor/editor_undo_redo_manager.h"
+#ifdef DEBUG_ENABLED
+#include "servers/navigation_server_3d.h"
+#endif // DEBUG_ENABLED
+
void TileDataEditor::_tile_set_changed_plan_update() {
_tile_set_changed_update_needed = true;
call_deferred(SNAME("_tile_set_changed_deferred_update"));
@@ -2674,7 +2678,9 @@ void TileDataNavigationEditor::_tile_set_changed() {
void TileDataNavigationEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- polygon_editor->set_polygons_color(get_tree()->get_debug_navigation_color());
+#ifdef DEBUG_ENABLED
+ polygon_editor->set_polygons_color(NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color());
+#endif // DEBUG_ENABLED
} break;
}
}
@@ -2701,7 +2707,10 @@ void TileDataNavigationEditor::draw_over_tile(CanvasItem *p_canvas_item, Transfo
return;
}
- Color color = p_canvas_item->get_tree()->get_debug_navigation_color();
+ Color color = Color(0.5, 1.0, 1.0, 1.0);
+#ifdef DEBUG_ENABLED
+ color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
+#endif // DEBUG_ENABLED
if (p_selected) {
Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
diff --git a/editor/progress_dialog.cpp b/editor/progress_dialog.cpp
index 1c9afa8be8..cfdf743bb0 100644
--- a/editor/progress_dialog.cpp
+++ b/editor/progress_dialog.cpp
@@ -207,7 +207,9 @@ bool ProgressDialog::task_step(const String &p_task, const String &p_state, int
DisplayServer::get_singleton()->process_events();
}
+#ifndef ANDROID_ENABLED
Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor
+#endif
return cancelled;
}
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 961281cd13..466a2efd21 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -668,6 +668,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
}
nm.region = region;
+#ifdef DEBUG_ENABLED
// add navigation debugmesh visual instances if debug is enabled
SceneTree *st = SceneTree::get_singleton();
if (st && st->is_debugging_navigation_hint()) {
@@ -675,15 +676,14 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
RID navmesh_debug_rid = navmesh->get_debug_mesh()->get_rid();
nm.navmesh_debug_instance = RS::get_singleton()->instance_create();
RS::get_singleton()->instance_set_base(nm.navmesh_debug_instance, navmesh_debug_rid);
- RS::get_singleton()->mesh_surface_set_material(navmesh_debug_rid, 0, st->get_debug_navigation_material()->get_rid());
}
if (is_inside_tree()) {
RS::get_singleton()->instance_set_scenario(nm.navmesh_debug_instance, get_world_3d()->get_scenario());
RS::get_singleton()->instance_set_transform(nm.navmesh_debug_instance, get_global_transform() * nm.xform);
}
}
+#endif // DEBUG_ENABLED
}
-
g.navmesh_ids[E] = nm;
}
}
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index 6427346365..454bcd2eda 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -118,20 +118,31 @@ void AndroidInputHandler::process_key_event(int p_keycode, int p_physical_keycod
Input::get_singleton()->parse_input_event(ev);
}
-void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector<AndroidInputHandler::TouchPos> &p_points) {
+void AndroidInputHandler::_parse_all_touch(bool p_pressed) {
+ if (touch.size()) {
+ //end all if exist
+ for (int i = 0; i < touch.size(); i++) {
+ Ref<InputEventScreenTouch> ev;
+ ev.instantiate();
+ ev->set_index(touch[i].id);
+ ev->set_pressed(p_pressed);
+ ev->set_position(touch[i].pos);
+ Input::get_singleton()->parse_input_event(ev);
+ }
+ }
+}
+
+void AndroidInputHandler::_release_all_touch() {
+ _parse_all_touch(false);
+ touch.clear();
+}
+
+void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points) {
switch (p_event) {
case AMOTION_EVENT_ACTION_DOWN: { //gesture begin
- if (touch.size()) {
- //end all if exist
- for (int i = 0; i < touch.size(); i++) {
- Ref<InputEventScreenTouch> ev;
- ev.instantiate();
- ev->set_index(touch[i].id);
- ev->set_pressed(false);
- ev->set_position(touch[i].pos);
- Input::get_singleton()->parse_input_event(ev);
- }
- }
+ // Release any remaining touches or mouse event
+ _release_mouse_event_info();
+ _release_all_touch();
touch.resize(p_points.size());
for (int i = 0; i < p_points.size(); i++) {
@@ -140,18 +151,13 @@ void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector
}
//send touch
- for (int i = 0; i < touch.size(); i++) {
- Ref<InputEventScreenTouch> ev;
- ev.instantiate();
- ev->set_index(touch[i].id);
- ev->set_pressed(true);
- ev->set_position(touch[i].pos);
- Input::get_singleton()->parse_input_event(ev);
- }
+ _parse_all_touch(true);
} break;
case AMOTION_EVENT_ACTION_MOVE: { //motion
- ERR_FAIL_COND(touch.size() != p_points.size());
+ if (touch.size() != p_points.size()) {
+ return;
+ }
for (int i = 0; i < touch.size(); i++) {
int idx = -1;
@@ -180,18 +186,7 @@ void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector
} break;
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_UP: { //release
- if (touch.size()) {
- //end all if exist
- for (int i = 0; i < touch.size(); i++) {
- Ref<InputEventScreenTouch> ev;
- ev.instantiate();
- ev->set_index(touch[i].id);
- ev->set_pressed(false);
- ev->set_position(touch[i].pos);
- Input::get_singleton()->parse_input_event(ev);
- }
- touch.clear();
- }
+ _release_all_touch();
} break;
case AMOTION_EVENT_ACTION_POINTER_DOWN: { // add touch
for (int i = 0; i < p_points.size(); i++) {
@@ -229,88 +224,118 @@ void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector
}
}
-void AndroidInputHandler::process_hover(int p_type, Point2 p_pos) {
- // https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER
- switch (p_type) {
+void AndroidInputHandler::_parse_mouse_event_info(MouseButton event_buttons_mask, bool p_pressed, bool p_double_click, bool p_source_mouse_relative) {
+ if (!mouse_event_info.valid) {
+ return;
+ }
+
+ Ref<InputEventMouseButton> ev;
+ ev.instantiate();
+ _set_key_modifier_state(ev);
+ if (p_source_mouse_relative) {
+ ev->set_position(hover_prev_pos);
+ ev->set_global_position(hover_prev_pos);
+ } else {
+ ev->set_position(mouse_event_info.pos);
+ ev->set_global_position(mouse_event_info.pos);
+ hover_prev_pos = mouse_event_info.pos;
+ }
+ ev->set_pressed(p_pressed);
+ MouseButton changed_button_mask = MouseButton(buttons_state ^ event_buttons_mask);
+
+ buttons_state = event_buttons_mask;
+
+ ev->set_button_index(_button_index_from_mask(changed_button_mask));
+ ev->set_button_mask(event_buttons_mask);
+ ev->set_double_click(p_double_click);
+ Input::get_singleton()->parse_input_event(ev);
+}
+
+void AndroidInputHandler::_release_mouse_event_info(bool p_source_mouse_relative) {
+ _parse_mouse_event_info(MouseButton::NONE, false, false, p_source_mouse_relative);
+ mouse_event_info.valid = false;
+}
+
+void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative) {
+ MouseButton event_buttons_mask = _android_button_mask_to_godot_button_mask(p_event_android_buttons_mask);
+ switch (p_event_action) {
case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move
case AMOTION_EVENT_ACTION_HOVER_ENTER: // hover enter
case AMOTION_EVENT_ACTION_HOVER_EXIT: { // hover exit
+ // https://developer.android.com/reference/android/view/MotionEvent.html#ACTION_HOVER_ENTER
Ref<InputEventMouseMotion> ev;
ev.instantiate();
_set_key_modifier_state(ev);
- ev->set_position(p_pos);
- ev->set_global_position(p_pos);
- ev->set_relative(p_pos - hover_prev_pos);
+ ev->set_position(p_event_pos);
+ ev->set_global_position(p_event_pos);
+ ev->set_relative(p_event_pos - hover_prev_pos);
Input::get_singleton()->parse_input_event(ev);
- hover_prev_pos = p_pos;
+ hover_prev_pos = p_event_pos;
} break;
- }
-}
-void AndroidInputHandler::process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor) {
- MouseButton event_buttons_mask = _android_button_mask_to_godot_button_mask(event_android_buttons_mask);
- switch (event_action) {
- case AMOTION_EVENT_ACTION_BUTTON_PRESS:
- case AMOTION_EVENT_ACTION_BUTTON_RELEASE: {
- Ref<InputEventMouseButton> ev;
- ev.instantiate();
- _set_key_modifier_state(ev);
- if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
- ev->set_position(event_pos);
- ev->set_global_position(event_pos);
- } else {
- ev->set_position(hover_prev_pos);
- ev->set_global_position(hover_prev_pos);
- }
- ev->set_pressed(event_action == AMOTION_EVENT_ACTION_BUTTON_PRESS);
- MouseButton changed_button_mask = MouseButton(buttons_state ^ event_buttons_mask);
+ case AMOTION_EVENT_ACTION_DOWN:
+ case AMOTION_EVENT_ACTION_BUTTON_PRESS: {
+ // Release any remaining touches or mouse event
+ _release_mouse_event_info();
+ _release_all_touch();
- buttons_state = event_buttons_mask;
+ mouse_event_info.valid = true;
+ mouse_event_info.pos = p_event_pos;
+ _parse_mouse_event_info(event_buttons_mask, true, p_double_click, p_source_mouse_relative);
+ } break;
- ev->set_button_index(_button_index_from_mask(changed_button_mask));
- ev->set_button_mask(event_buttons_mask);
- Input::get_singleton()->parse_input_event(ev);
+ case AMOTION_EVENT_ACTION_UP:
+ case AMOTION_EVENT_ACTION_CANCEL:
+ case AMOTION_EVENT_ACTION_BUTTON_RELEASE: {
+ _release_mouse_event_info(p_source_mouse_relative);
} break;
case AMOTION_EVENT_ACTION_MOVE: {
+ if (!mouse_event_info.valid) {
+ return;
+ }
+
Ref<InputEventMouseMotion> ev;
ev.instantiate();
_set_key_modifier_state(ev);
- if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
- ev->set_position(event_pos);
- ev->set_global_position(event_pos);
- ev->set_relative(event_pos - hover_prev_pos);
- hover_prev_pos = event_pos;
- } else {
+ if (p_source_mouse_relative) {
ev->set_position(hover_prev_pos);
ev->set_global_position(hover_prev_pos);
- ev->set_relative(event_pos);
+ ev->set_relative(p_event_pos);
+ } else {
+ ev->set_position(p_event_pos);
+ ev->set_global_position(p_event_pos);
+ ev->set_relative(p_event_pos - hover_prev_pos);
+ mouse_event_info.pos = p_event_pos;
+ hover_prev_pos = p_event_pos;
}
ev->set_button_mask(event_buttons_mask);
Input::get_singleton()->parse_input_event(ev);
} break;
+
case AMOTION_EVENT_ACTION_SCROLL: {
Ref<InputEventMouseButton> ev;
ev.instantiate();
- if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) {
- ev->set_position(event_pos);
- ev->set_global_position(event_pos);
- } else {
+ _set_key_modifier_state(ev);
+ if (p_source_mouse_relative) {
ev->set_position(hover_prev_pos);
ev->set_global_position(hover_prev_pos);
+ } else {
+ ev->set_position(p_event_pos);
+ ev->set_global_position(p_event_pos);
}
ev->set_pressed(true);
buttons_state = event_buttons_mask;
- if (event_vertical_factor > 0) {
- _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_UP, event_vertical_factor);
- } else if (event_vertical_factor < 0) {
- _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_DOWN, -event_vertical_factor);
+ if (p_delta.y > 0) {
+ _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_UP, p_delta.y);
+ } else if (p_delta.y < 0) {
+ _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_DOWN, -p_delta.y);
}
- if (event_horizontal_factor > 0) {
- _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_RIGHT, event_horizontal_factor);
- } else if (event_horizontal_factor < 0) {
- _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_LEFT, -event_horizontal_factor);
+ if (p_delta.x > 0) {
+ _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_RIGHT, p_delta.x);
+ } else if (p_delta.x < 0) {
+ _wheel_button_click(event_buttons_mask, ev, MouseButton::WHEEL_LEFT, -p_delta.x);
}
} break;
}
@@ -329,18 +354,22 @@ void AndroidInputHandler::_wheel_button_click(MouseButton event_buttons_mask, co
Input::get_singleton()->parse_input_event(evdd);
}
-void AndroidInputHandler::process_double_tap(int event_android_button_mask, Point2 p_pos) {
- MouseButton event_button_mask = _android_button_mask_to_godot_button_mask(event_android_button_mask);
- Ref<InputEventMouseButton> ev;
- ev.instantiate();
- _set_key_modifier_state(ev);
- ev->set_position(p_pos);
- ev->set_global_position(p_pos);
- ev->set_pressed(event_button_mask != MouseButton::NONE);
- ev->set_button_index(_button_index_from_mask(event_button_mask));
- ev->set_button_mask(event_button_mask);
- ev->set_double_click(true);
- Input::get_singleton()->parse_input_event(ev);
+void AndroidInputHandler::process_magnify(Point2 p_pos, float p_factor) {
+ Ref<InputEventMagnifyGesture> magnify_event;
+ magnify_event.instantiate();
+ _set_key_modifier_state(magnify_event);
+ magnify_event->set_position(p_pos);
+ magnify_event->set_factor(p_factor);
+ Input::get_singleton()->parse_input_event(magnify_event);
+}
+
+void AndroidInputHandler::process_pan(Point2 p_pos, Vector2 p_delta) {
+ Ref<InputEventPanGesture> pan_event;
+ pan_event.instantiate();
+ _set_key_modifier_state(pan_event);
+ pan_event->set_position(p_pos);
+ pan_event->set_delta(p_delta);
+ Input::get_singleton()->parse_input_event(pan_event);
}
MouseButton AndroidInputHandler::_button_index_from_mask(MouseButton button_mask) {
diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h
index 6dfab7def8..88490f0407 100644
--- a/platform/android/android_input_handler.h
+++ b/platform/android/android_input_handler.h
@@ -44,6 +44,11 @@ public:
Point2 pos;
};
+ struct MouseEventInfo {
+ bool valid = false;
+ Point2 pos;
+ };
+
enum {
JOY_EVENT_BUTTON = 0,
JOY_EVENT_AXIS = 1,
@@ -68,6 +73,7 @@ private:
MouseButton buttons_state = MouseButton::NONE;
Vector<TouchPos> touch;
+ MouseEventInfo mouse_event_info;
Point2 hover_prev_pos; // needed to calculate the relative position on hover events
void _set_key_modifier_state(Ref<InputEventWithModifiers> ev);
@@ -77,11 +83,19 @@ private:
void _wheel_button_click(MouseButton event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor);
+ void _parse_mouse_event_info(MouseButton event_buttons_mask, bool p_pressed, bool p_double_click, bool p_source_mouse_relative);
+
+ void _release_mouse_event_info(bool p_source_mouse_relative = false);
+
+ void _parse_all_touch(bool p_pressed);
+
+ void _release_all_touch();
+
public:
- void process_touch(int p_event, int p_pointer, const Vector<TouchPos> &p_points);
- void process_hover(int p_type, Point2 p_pos);
- void process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor = 0, float event_horizontal_factor = 0);
- void process_double_tap(int event_android_button_mask, Point2 p_pos);
+ void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative);
+ void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points);
+ void process_magnify(Point2 p_pos, float p_factor);
+ void process_pan(Point2 p_pos, Vector2 p_delta);
void process_joy_event(JoypadEvent p_event);
void process_key_event(int p_keycode, int p_physical_keycode, int p_unicode, bool p_pressed);
};
diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
index 740f3f48d3..489a81fc1a 100644
--- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
+++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
@@ -77,6 +77,12 @@ open class GodotEditor : FullScreenGodotApp() {
}
super.onCreate(savedInstanceState)
+
+ // Enable long press, panning and scaling gestures
+ godotFragment?.renderView?.inputHandler?.apply {
+ enableLongPress(enableLongPressGestures())
+ enablePanningAndScalingGestures(enablePanAndScaleGestures())
+ }
}
private fun updateCommandLineParams(args: Array<String>?) {
@@ -148,6 +154,16 @@ open class GodotEditor : FullScreenGodotApp() {
*/
protected open fun overrideOrientationRequest() = true
+ /**
+ * Enable long press gestures for the Godot Android editor.
+ */
+ protected open fun enableLongPressGestures() = true
+
+ /**
+ * Enable pan and scale gestures for the Godot Android editor.
+ */
+ protected open fun enablePanAndScaleGestures() = true
+
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// Check if we got the MANAGE_EXTERNAL_STORAGE permission
diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt
index 783095f93a..b9536a7066 100644
--- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt
+++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt
@@ -35,4 +35,8 @@ package org.godotengine.editor
*/
class GodotGame : GodotEditor() {
override fun overrideOrientationRequest() = false
+
+ override fun enableLongPressGestures() = false
+
+ override fun enablePanAndScaleGestures() = false
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 28e689e63a..6ebe7e4ee9 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -1023,7 +1023,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
}
@Keep
- private GodotRenderView getRenderView() { // used by native side to get renderView
+ public GodotRenderView getRenderView() { // used by native side to get renderView
return mRenderView;
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
index 08da1b1832..513021f1d1 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
@@ -31,7 +31,6 @@
package org.godotengine.godot;
import org.godotengine.godot.gl.GLSurfaceView;
import org.godotengine.godot.gl.GodotRenderer;
-import org.godotengine.godot.input.GodotGestureHandler;
import org.godotengine.godot.input.GodotInputHandler;
import org.godotengine.godot.utils.GLUtils;
import org.godotengine.godot.xr.XRMode;
@@ -46,7 +45,6 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Build;
-import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.PointerIcon;
@@ -75,7 +73,6 @@ import androidx.annotation.Keep;
public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
private final Godot godot;
private final GodotInputHandler inputHandler;
- private final GestureDetector detector;
private final GodotRenderer godotRenderer;
private PointerIcon pointerIcon;
@@ -85,7 +82,6 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
this.godot = godot;
this.inputHandler = new GodotInputHandler(this);
- this.detector = new GestureDetector(context, new GodotGestureHandler(this));
this.godotRenderer = new GodotRenderer();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
@@ -132,7 +128,6 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
- this.detector.onTouchEvent(event);
return inputHandler.onTouchEvent(event);
}
@@ -156,6 +151,24 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
return inputHandler.onGenericMotionEvent(event);
}
+ @Override
+ public void onPointerCaptureChange(boolean hasCapture) {
+ super.onPointerCaptureChange(hasCapture);
+ inputHandler.onPointerCaptureChange(hasCapture);
+ }
+
+ @Override
+ public void requestPointerCapture() {
+ super.requestPointerCapture();
+ inputHandler.onPointerCaptureChange(true);
+ }
+
+ @Override
+ public void releasePointerCapture() {
+ super.releasePointerCapture();
+ inputHandler.onPointerCaptureChange(false);
+ }
+
/**
* called from JNI to change pointer icon
*/
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index f855fc6cf6..d4fa12ed15 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -92,7 +92,7 @@ public class GodotLib {
public static native void newcontext(Surface p_surface);
/**
- * Forward {@link Activity#onBackPressed()} event from the main thread to the GL thread.
+ * Forward {@link Activity#onBackPressed()} event.
*/
public static native void back();
@@ -108,63 +108,60 @@ public class GodotLib {
public static native void ttsCallback(int event, int id, int pos);
/**
- * Forward touch events from the main thread to the GL thread.
+ * Forward touch events.
*/
- public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions);
- public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions, int buttonsMask);
- public static native void touch(int inputDevice, int event, int pointer, int pointerCount, float[] positions, int buttonsMask, float verticalFactor, float horizontalFactor);
+ public static native void dispatchTouchEvent(int event, int pointer, int pointerCount, float[] positions);
/**
- * Forward hover events from the main thread to the GL thread.
+ * Dispatch mouse events
*/
- public static native void hover(int type, float x, float y);
+ public static native void dispatchMouseEvent(int event, int buttonMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative);
- /**
- * Forward double_tap events from the main thread to the GL thread.
- */
- public static native void doubleTap(int buttonMask, int x, int y);
+ public static native void magnify(float x, float y, float factor);
+
+ public static native void pan(float x, float y, float deltaX, float deltaY);
/**
- * Forward accelerometer sensor events from the main thread to the GL thread.
+ * Forward accelerometer sensor events.
* @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
*/
public static native void accelerometer(float x, float y, float z);
/**
- * Forward gravity sensor events from the main thread to the GL thread.
+ * Forward gravity sensor events.
* @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
*/
public static native void gravity(float x, float y, float z);
/**
- * Forward magnetometer sensor events from the main thread to the GL thread.
+ * Forward magnetometer sensor events.
* @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
*/
public static native void magnetometer(float x, float y, float z);
/**
- * Forward gyroscope sensor events from the main thread to the GL thread.
+ * Forward gyroscope sensor events.
* @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent)
*/
public static native void gyroscope(float x, float y, float z);
/**
- * Forward regular key events from the main thread to the GL thread.
+ * Forward regular key events.
*/
public static native void key(int p_keycode, int p_physical_keycode, int p_unicode, boolean p_pressed);
/**
- * Forward game device's key events from the main thread to the GL thread.
+ * Forward game device's key events.
*/
public static native void joybutton(int p_device, int p_but, boolean p_pressed);
/**
- * Forward joystick devices axis motion events from the main thread to the GL thread.
+ * Forward joystick devices axis motion events.
*/
public static native void joyaxis(int p_device, int p_axis, float p_value);
/**
- * Forward joystick devices hat motion events from the main thread to the GL thread.
+ * Forward joystick devices hat motion events.
*/
public static native void joyhat(int p_device, int p_hat_x, int p_hat_y);
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
index c386a2d2eb..fa6c3280b9 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
@@ -30,7 +30,6 @@
package org.godotengine.godot;
-import org.godotengine.godot.input.GodotGestureHandler;
import org.godotengine.godot.input.GodotInputHandler;
import org.godotengine.godot.vulkan.VkRenderer;
import org.godotengine.godot.vulkan.VkSurfaceView;
@@ -38,7 +37,6 @@ import org.godotengine.godot.vulkan.VkSurfaceView;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
-import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.PointerIcon;
@@ -49,7 +47,6 @@ import androidx.annotation.Keep;
public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
private final Godot godot;
private final GodotInputHandler mInputHandler;
- private final GestureDetector mGestureDetector;
private final VkRenderer mRenderer;
private PointerIcon pointerIcon;
@@ -58,7 +55,6 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
this.godot = godot;
mInputHandler = new GodotInputHandler(this);
- mGestureDetector = new GestureDetector(context, new GodotGestureHandler(this));
mRenderer = new VkRenderer();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
@@ -106,7 +102,6 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
- mGestureDetector.onTouchEvent(event);
return mInputHandler.onTouchEvent(event);
}
@@ -130,6 +125,24 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
return mInputHandler.onGenericMotionEvent(event);
}
+ @Override
+ public void requestPointerCapture() {
+ super.requestPointerCapture();
+ mInputHandler.onPointerCaptureChange(true);
+ }
+
+ @Override
+ public void releasePointerCapture() {
+ super.releasePointerCapture();
+ mInputHandler.onPointerCaptureChange(false);
+ }
+
+ @Override
+ public void onPointerCaptureChange(boolean hasCapture) {
+ super.onPointerCaptureChange(hasCapture);
+ mInputHandler.onPointerCaptureChange(hasCapture);
+ }
+
/**
* called from JNI to change pointer icon
*/
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java
deleted file mode 100644
index 778efa914a..0000000000
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*************************************************************************/
-/* GodotGestureHandler.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-package org.godotengine.godot.input;
-
-import org.godotengine.godot.GodotLib;
-import org.godotengine.godot.GodotRenderView;
-
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-
-/**
- * Handles gesture input related events for the {@link GodotRenderView} view.
- * https://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener
- */
-public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener {
- private final GodotRenderView mRenderView;
-
- public GodotGestureHandler(GodotRenderView godotView) {
- mRenderView = godotView;
- }
-
- private void queueEvent(Runnable task) {
- mRenderView.queueOnRenderThread(task);
- }
-
- @Override
- public boolean onDown(MotionEvent event) {
- super.onDown(event);
- //Log.i("GodotGesture", "onDown");
- return true;
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent event) {
- super.onSingleTapConfirmed(event);
- return true;
- }
-
- @Override
- public void onLongPress(MotionEvent event) {
- //Log.i("GodotGesture", "onLongPress");
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent event) {
- //Log.i("GodotGesture", "onDoubleTap");
- final int x = Math.round(event.getX());
- final int y = Math.round(event.getY());
- final int buttonMask = event.getButtonState();
- GodotLib.doubleTap(buttonMask, x, y);
- return true;
- }
-
- @Override
- public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
- //Log.i("GodotGesture", "onFling");
- return true;
- }
-}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
new file mode 100644
index 0000000000..9715c31fc1
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
@@ -0,0 +1,289 @@
+/*************************************************************************/
+/* GodotGestureHandler.kt */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+package org.godotengine.godot.input
+
+import android.os.Build
+import android.view.GestureDetector.SimpleOnGestureListener
+import android.view.InputDevice
+import android.view.MotionEvent
+import android.view.ScaleGestureDetector
+import android.view.ScaleGestureDetector.OnScaleGestureListener
+import org.godotengine.godot.GodotLib
+
+/**
+ * Handles regular and scale gesture input related events for the [GodotView] view.
+ *
+ * @See https://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener
+ * @See https://developer.android.com/reference/android/view/ScaleGestureDetector.OnScaleGestureListener
+ */
+internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureListener {
+
+ companion object {
+ private val TAG = GodotGestureHandler::class.java.simpleName
+ }
+
+ /**
+ * Enable pan and scale gestures
+ */
+ var panningAndScalingEnabled = false
+
+ private var doubleTapInProgress = false
+ private var dragInProgress = false
+ private var scaleInProgress = false
+ private var contextClickInProgress = false
+ private var pointerCaptureInProgress = false
+
+ override fun onDown(event: MotionEvent): Boolean {
+ // Don't send / register a down event while we're in the middle of a double-tap
+ if (!doubleTapInProgress) {
+ // Send the down event
+ GodotInputHandler.handleMotionEvent(event)
+ }
+ return true
+ }
+
+ override fun onSingleTapUp(event: MotionEvent): Boolean {
+ GodotInputHandler.handleMotionEvent(event)
+ return true
+ }
+
+ override fun onLongPress(event: MotionEvent) {
+ contextClickRouter(event)
+ }
+
+ private fun contextClickRouter(event: MotionEvent) {
+ if (scaleInProgress) {
+ return
+ }
+
+ // Cancel the previous down event
+ GodotInputHandler.handleMotionEvent(
+ event.source,
+ MotionEvent.ACTION_CANCEL,
+ event.buttonState,
+ event.x,
+ event.y
+ )
+
+ // Turn a context click into a single tap right mouse button click.
+ GodotInputHandler.handleMouseEvent(
+ MotionEvent.ACTION_DOWN,
+ MotionEvent.BUTTON_SECONDARY,
+ event.x,
+ event.y
+ )
+ contextClickInProgress = true
+ }
+
+ fun onPointerCaptureChange(hasCapture: Boolean) {
+ if (pointerCaptureInProgress == hasCapture) {
+ return
+ }
+
+ if (!hasCapture) {
+ // Dispatch a mouse relative ACTION_UP event to signal the end of the capture
+ GodotInputHandler.handleMouseEvent(
+ MotionEvent.ACTION_UP,
+ 0,
+ 0f,
+ 0f,
+ 0f,
+ 0f,
+ false,
+ true
+ )
+ }
+ pointerCaptureInProgress = hasCapture
+ }
+
+ fun onMotionEvent(event: MotionEvent): Boolean {
+ return when (event.actionMasked) {
+ MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_BUTTON_RELEASE -> {
+ onActionUp(event)
+ }
+ MotionEvent.ACTION_MOVE -> {
+ onActionMove(event)
+ }
+ else -> false
+ }
+ }
+
+ private fun onActionUp(event: MotionEvent): Boolean {
+ val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)
+ } else {
+ false
+ }
+ when {
+ pointerCaptureInProgress -> {
+ return if (event.actionMasked == MotionEvent.ACTION_CANCEL) {
+ // Don't dispatch the ACTION_CANCEL while a capture is in progress
+ true
+ } else {
+ GodotInputHandler.handleMouseEvent(
+ MotionEvent.ACTION_UP,
+ event.buttonState,
+ event.x,
+ event.y,
+ 0f,
+ 0f,
+ false,
+ sourceMouseRelative
+ )
+ pointerCaptureInProgress = false
+ true
+ }
+ }
+ dragInProgress -> {
+ GodotInputHandler.handleMotionEvent(event)
+ dragInProgress = false
+ return true
+ }
+ contextClickInProgress -> {
+ GodotInputHandler.handleMouseEvent(
+ event.actionMasked,
+ 0,
+ event.x,
+ event.y,
+ 0f,
+ 0f,
+ false,
+ sourceMouseRelative
+ )
+ contextClickInProgress = false
+ return true
+ }
+ else -> return false
+ }
+ }
+
+ private fun onActionMove(event: MotionEvent): Boolean {
+ if (contextClickInProgress) {
+ val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)
+ } else {
+ false
+ }
+ GodotInputHandler.handleMouseEvent(
+ event.actionMasked,
+ MotionEvent.BUTTON_SECONDARY,
+ event.x,
+ event.y,
+ 0f,
+ 0f,
+ false,
+ sourceMouseRelative
+ )
+ return true
+ }
+ return false
+ }
+
+ override fun onDoubleTapEvent(event: MotionEvent): Boolean {
+ if (event.actionMasked == MotionEvent.ACTION_UP) {
+ doubleTapInProgress = false
+ }
+ return true
+ }
+
+ override fun onDoubleTap(event: MotionEvent): Boolean {
+ doubleTapInProgress = true
+ val x = event.x
+ val y = event.y
+ val buttonMask =
+ if (GodotInputHandler.isMouseEvent(event)) {
+ event.buttonState
+ } else {
+ MotionEvent.BUTTON_PRIMARY
+ }
+ GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_DOWN, buttonMask, x, y, true)
+ GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_UP, 0, x, y, false)
+
+ return true
+ }
+
+ override fun onScroll(
+ originEvent: MotionEvent,
+ terminusEvent: MotionEvent,
+ distanceX: Float,
+ distanceY: Float
+ ): Boolean {
+ if (scaleInProgress) {
+ if (dragInProgress) {
+ // Cancel the drag
+ GodotInputHandler.handleMotionEvent(
+ originEvent.source,
+ MotionEvent.ACTION_CANCEL,
+ originEvent.buttonState,
+ originEvent.x,
+ originEvent.y
+ )
+ dragInProgress = false
+ }
+ return true
+ }
+
+ dragInProgress = true
+
+ val x = terminusEvent.x
+ val y = terminusEvent.y
+ if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled) {
+ GodotLib.pan(x, y, distanceX / 5f, distanceY / 5f)
+ } else {
+ GodotInputHandler.handleMotionEvent(terminusEvent)
+ }
+ return true
+ }
+
+ override fun onScale(detector: ScaleGestureDetector?): Boolean {
+ if (detector == null || !panningAndScalingEnabled) {
+ return false
+ }
+ GodotLib.magnify(
+ detector.focusX,
+ detector.focusY,
+ detector.scaleFactor
+ )
+ return true
+ }
+
+ override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean {
+ if (detector == null || !panningAndScalingEnabled) {
+ return false
+ }
+ scaleInProgress = true
+ return true
+ }
+
+ override fun onScaleEnd(detector: ScaleGestureDetector?) {
+ scaleInProgress = false
+ }
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index da15b2490c..03cb8034fa 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -41,13 +41,13 @@ import android.os.Build;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.view.GestureDetector;
import android.view.InputDevice;
-import android.view.InputDevice.MotionRange;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
@@ -55,21 +55,49 @@ import java.util.Set;
* Handles input related events for the {@link GodotRenderView} view.
*/
public class GodotInputHandler implements InputManager.InputDeviceListener {
- private final GodotRenderView mRenderView;
- private final InputManager mInputManager;
-
- private final String tag = this.getClass().getSimpleName();
+ private static final String TAG = GodotInputHandler.class.getSimpleName();
private final SparseIntArray mJoystickIds = new SparseIntArray(4);
private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4);
+ private final GodotRenderView mRenderView;
+ private final InputManager mInputManager;
+ private final GestureDetector gestureDetector;
+ private final ScaleGestureDetector scaleGestureDetector;
+ private final GodotGestureHandler godotGestureHandler;
+
public GodotInputHandler(GodotRenderView godotView) {
+ final Context context = godotView.getView().getContext();
mRenderView = godotView;
- mInputManager = (InputManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_SERVICE);
+ mInputManager = (InputManager)context.getSystemService(Context.INPUT_SERVICE);
mInputManager.registerInputDeviceListener(this, null);
+
+ this.godotGestureHandler = new GodotGestureHandler();
+ this.gestureDetector = new GestureDetector(context, godotGestureHandler);
+ this.gestureDetector.setIsLongpressEnabled(false);
+ this.scaleGestureDetector = new ScaleGestureDetector(context, godotGestureHandler);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ this.scaleGestureDetector.setStylusScaleEnabled(true);
+ }
}
- private boolean isKeyEvent_GameDevice(int source) {
+ /**
+ * Enable long press events. This is false by default.
+ */
+ public void enableLongPress(boolean enable) {
+ this.gestureDetector.setIsLongpressEnabled(enable);
+ }
+
+ /**
+ * Enable multi-fingers pan & scale gestures. This is false by default.
+ *
+ * Note: This may interfere with multi-touch handling / support.
+ */
+ public void enablePanningAndScalingGestures(boolean enable) {
+ this.godotGestureHandler.setPanningAndScalingEnabled(enable);
+ }
+
+ private boolean isKeyEventGameDevice(int source) {
// Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD)
if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD))
return false;
@@ -77,6 +105,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
return (source & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK || (source & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD || (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD;
}
+ public void onPointerCaptureChange(boolean hasCapture) {
+ godotGestureHandler.onPointerCaptureChange(hasCapture);
+ }
+
public boolean onKeyUp(final int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
return true;
@@ -87,7 +119,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
int source = event.getSource();
- if (isKeyEvent_GameDevice(source)) {
+ if (isKeyEventGameDevice(source)) {
// Check if the device exists
final int deviceId = event.getDeviceId();
if (mJoystickIds.indexOfKey(deviceId) >= 0) {
@@ -121,11 +153,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
int source = event.getSource();
- //Log.e(TAG, String.format("Key down! source %d, device %d, joystick %d, %d, %d", event.getDeviceId(), source, (source & InputDevice.SOURCE_JOYSTICK), (source & InputDevice.SOURCE_DPAD), (source & InputDevice.SOURCE_GAMEPAD)));
final int deviceId = event.getDeviceId();
// Check if source is a game device and that the device is a registered gamepad
- if (isKeyEvent_GameDevice(source)) {
+ if (isKeyEventGameDevice(source)) {
if (event.getRepeatCount() > 0) // ignore key echo
return true;
@@ -145,47 +176,41 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
public boolean onTouchEvent(final MotionEvent event) {
- // Mouse drag (mouse pressed and move) doesn't fire onGenericMotionEvent so this is needed
- if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
- if (event.getAction() != MotionEvent.ACTION_MOVE) {
- // we return true because every time a mouse event is fired, the event is already handled
- // in onGenericMotionEvent, so by touch event we can say that the event is also handled
- return true;
- }
- return handleMouseEvent(event);
+ this.scaleGestureDetector.onTouchEvent(event);
+ if (this.gestureDetector.onTouchEvent(event)) {
+ // The gesture detector has handled the event.
+ return true;
}
- final int evcount = event.getPointerCount();
- if (evcount == 0)
+ if (godotGestureHandler.onMotionEvent(event)) {
+ // The gesture handler has handled the event.
return true;
+ }
- if (mRenderView != null) {
- final float[] arr = new float[event.getPointerCount() * 3]; // pointerId1, x1, y1, pointerId2, etc...
+ // Drag events are handled by the [GodotGestureHandler]
+ if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
+ return true;
+ }
- for (int i = 0; i < event.getPointerCount(); i++) {
- arr[i * 3 + 0] = event.getPointerId(i);
- arr[i * 3 + 1] = event.getX(i);
- arr[i * 3 + 2] = event.getY(i);
- }
- final int action = event.getActionMasked();
- final int pointer_idx = event.getPointerId(event.getActionIndex());
-
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_MOVE:
- case MotionEvent.ACTION_POINTER_UP:
- case MotionEvent.ACTION_POINTER_DOWN: {
- GodotLib.touch(event.getSource(), action, pointer_idx, evcount, arr);
- } break;
- }
+ if (isMouseEvent(event)) {
+ return handleMouseEvent(event);
}
- return true;
+
+ return handleTouchEvent(event);
}
public boolean onGenericMotionEvent(MotionEvent event) {
- if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getAction() == MotionEvent.ACTION_MOVE) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && gestureDetector.onGenericMotionEvent(event)) {
+ // The gesture detector has handled the event.
+ return true;
+ }
+
+ if (godotGestureHandler.onMotionEvent(event)) {
+ // The gesture handler has handled the event.
+ return true;
+ }
+
+ if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getActionMasked() == MotionEvent.ACTION_MOVE) {
// Check if the device exists
final int deviceId = event.getDeviceId();
if (mJoystickIds.indexOfKey(deviceId) >= 0) {
@@ -198,15 +223,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
for (int i = 0; i < joystick.axes.size(); i++) {
final int axis = joystick.axes.get(i);
final float value = event.getAxisValue(axis);
- /**
- * As all axes are polled for each event, only fire an axis event if the value has actually changed.
- * Prevents flooding Godot with repeated events.
+ /*
+ As all axes are polled for each event, only fire an axis event if the value has actually changed.
+ Prevents flooding Godot with repeated events.
*/
if (joystick.axesValues.indexOfKey(axis) < 0 || (float)joystick.axesValues.get(axis) != value) {
// save value to prevent repeats
joystick.axesValues.put(axis, value);
- final int godotAxisIdx = i;
- GodotLib.joyaxis(godotJoyId, godotAxisIdx, value);
+ GodotLib.joyaxis(godotJoyId, i, value);
}
}
@@ -221,17 +245,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
return true;
}
- } else if (event.isFromSource(InputDevice.SOURCE_STYLUS)) {
- final float x = event.getX();
- final float y = event.getY();
- final int type = event.getAction();
- GodotLib.hover(type, x, y);
- return true;
-
- } else if (event.isFromSource(InputDevice.SOURCE_MOUSE) || event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- return handleMouseEvent(event);
- }
+ } else if (isMouseEvent(event)) {
+ return handleMouseEvent(event);
}
return false;
@@ -243,7 +258,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
for (int deviceId : deviceIds) {
InputDevice device = mInputManager.getInputDevice(deviceId);
if (DEBUG) {
- Log.v("GodotInputHandler", String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName()));
+ Log.v(TAG, String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName()));
}
onInputDeviceAdded(deviceId);
}
@@ -288,13 +303,12 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
joystick.name = device.getName();
//Helps with creating new joypad mappings.
- Log.i(tag, "=== New Input Device: " + joystick.name);
+ Log.i(TAG, "=== New Input Device: " + joystick.name);
Set<Integer> already = new HashSet<>();
for (InputDevice.MotionRange range : device.getMotionRanges()) {
boolean isJoystick = range.isFromSource(InputDevice.SOURCE_JOYSTICK);
boolean isGamepad = range.isFromSource(InputDevice.SOURCE_GAMEPAD);
- //Log.i(tag, "axis: "+range.getAxis()+ ", isJoystick: "+isJoystick+", isGamepad: "+isGamepad);
if (!isJoystick && !isGamepad) {
continue;
}
@@ -306,14 +320,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
already.add(axis);
joystick.axes.add(axis);
} else {
- Log.w(tag, " - DUPLICATE AXIS VALUE IN LIST: " + axis);
+ Log.w(TAG, " - DUPLICATE AXIS VALUE IN LIST: " + axis);
}
}
}
Collections.sort(joystick.axes);
for (int idx = 0; idx < joystick.axes.size(); idx++) {
//Helps with creating new joypad mappings.
- Log.i(tag, " - Mapping Android axis " + joystick.axes.get(idx) + " to Godot axis " + idx);
+ Log.i(TAG, " - Mapping Android axis " + joystick.axes.get(idx) + " to Godot axis " + idx);
}
mJoysticksDevices.put(deviceId, joystick);
@@ -338,13 +352,6 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
onInputDeviceAdded(deviceId);
}
- private static class RangeComparator implements Comparator<MotionRange> {
- @Override
- public int compare(MotionRange arg0, MotionRange arg1) {
- return arg0.getAxis() - arg1.getAxis();
- }
- }
-
public static int getGodotButton(int keyCode) {
int button;
switch (keyCode) {
@@ -410,39 +417,113 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
return button;
}
- private boolean handleMouseEvent(final MotionEvent event) {
- switch (event.getActionMasked()) {
+ static boolean isMouseEvent(MotionEvent event) {
+ return isMouseEvent(event.getSource());
+ }
+
+ private static boolean isMouseEvent(int eventSource) {
+ boolean mouseSource = ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ mouseSource = mouseSource || ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE);
+ }
+ return mouseSource;
+ }
+
+ static boolean handleMotionEvent(final MotionEvent event) {
+ if (isMouseEvent(event)) {
+ return handleMouseEvent(event);
+ }
+
+ return handleTouchEvent(event);
+ }
+
+ static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y) {
+ return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0);
+ }
+
+ static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY) {
+ if (isMouseEvent(eventSource)) {
+ return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, false, false);
+ }
+
+ return handleTouchEvent(eventAction, x, y);
+ }
+
+ static boolean handleMouseEvent(final MotionEvent event) {
+ final int eventAction = event.getActionMasked();
+ final float x = event.getX();
+ final float y = event.getY();
+ final int buttonsMask = event.getButtonState();
+
+ final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
+ final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
+ boolean sourceMouseRelative = false;
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
+ sourceMouseRelative = event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE);
+ }
+ return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false, sourceMouseRelative);
+ }
+
+ static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y) {
+ return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false, false);
+ }
+
+ static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, boolean doubleClick) {
+ return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, doubleClick, false);
+ }
+
+ static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) {
+ switch (eventAction) {
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ // Zero-up the button state
+ buttonsMask = 0;
+ // FALL THROUGH
+ case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_HOVER_ENTER:
+ case MotionEvent.ACTION_HOVER_EXIT:
case MotionEvent.ACTION_HOVER_MOVE:
- case MotionEvent.ACTION_HOVER_EXIT: {
- final float x = event.getX();
- final float y = event.getY();
- final int type = event.getAction();
- GodotLib.hover(type, x, y);
- return true;
- }
- case MotionEvent.ACTION_BUTTON_PRESS:
- case MotionEvent.ACTION_BUTTON_RELEASE:
- case MotionEvent.ACTION_MOVE: {
- final float x = event.getX();
- final float y = event.getY();
- final int buttonsMask = event.getButtonState();
- final int action = event.getAction();
- GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask);
- return true;
- }
+ case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_SCROLL: {
- final float x = event.getX();
- final float y = event.getY();
- final int buttonsMask = event.getButtonState();
- final int action = event.getAction();
- final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
- final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
- GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask, verticalFactor, horizontalFactor);
+ GodotLib.dispatchMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative);
+ return true;
}
+ }
+ return false;
+ }
+
+ static boolean handleTouchEvent(final MotionEvent event) {
+ final int pointerCount = event.getPointerCount();
+ if (pointerCount == 0) {
+ return true;
+ }
+
+ final float[] positions = new float[pointerCount * 3]; // pointerId1, x1, y1, pointerId2, etc...
+
+ for (int i = 0; i < pointerCount; i++) {
+ positions[i * 3 + 0] = event.getPointerId(i);
+ positions[i * 3 + 1] = event.getX(i);
+ positions[i * 3 + 2] = event.getY(i);
+ }
+ final int action = event.getActionMasked();
+ final int actionPointerId = event.getPointerId(event.getActionIndex());
+
+ return handleTouchEvent(action, actionPointerId, pointerCount, positions);
+ }
+
+ static boolean handleTouchEvent(int eventAction, float x, float y) {
+ return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y });
+ }
+
+ static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions) {
+ switch (eventAction) {
case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_UP: {
- // we can safely ignore these cases because they are always come beside ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_MOVE:
+ case MotionEvent.ACTION_POINTER_UP:
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions);
return true;
}
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 422c05e5ce..f01bd9c72a 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -254,7 +254,17 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env,
return should_swap_buffers;
}
-void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor) {
+// Called on the UI thread
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative) {
+ if (step.get() <= 0) {
+ return;
+ }
+
+ input_handler->process_mouse_event(p_event_type, p_button_mask, Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y), p_double_click, p_source_mouse_relative);
+}
+
+// Called on the UI thread
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray position) {
if (step.get() <= 0) {
return;
}
@@ -262,50 +272,30 @@ void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev,
Vector<AndroidInputHandler::TouchPos> points;
for (int i = 0; i < pointer_count; i++) {
jfloat p[3];
- env->GetFloatArrayRegion(positions, i * 3, 3, p);
+ env->GetFloatArrayRegion(position, i * 3, 3, p);
AndroidInputHandler::TouchPos tp;
tp.pos = Point2(p[1], p[2]);
tp.id = (int)p[0];
points.push_back(tp);
}
- if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE || (input_device & AINPUT_SOURCE_MOUSE_RELATIVE) == AINPUT_SOURCE_MOUSE_RELATIVE) {
- input_handler->process_mouse_event(input_device, ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor);
- } else {
- input_handler->process_touch(ev, pointer, points);
- }
-}
-// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3F(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position) {
- touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position);
+ input_handler->process_touch_event(ev, pointer, points);
}
// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FI(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position, jint buttons_mask) {
- touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position, buttons_mask);
-}
-
-// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray position, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor) {
- touch_preprocessing(env, clazz, input_device, ev, pointer, pointer_count, position, buttons_mask, vertical_factor, horizontal_factor);
-}
-
-// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor) {
if (step.get() <= 0) {
return;
}
-
- input_handler->process_hover(p_type, Point2(p_x, p_y));
+ input_handler->process_magnify(Point2(p_x, p_y), p_factor);
}
// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y) {
if (step.get() <= 0) {
return;
}
-
- input_handler->process_double_tap(p_button_mask, Point2(p_x, p_y));
+ input_handler->process_pan(Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y));
}
// Called on the UI thread
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 3c48ca0459..e2ed006462 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -45,12 +45,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en
JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ttsCallback(JNIEnv *env, jclass clazz, jint event, jint id, jint pos);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
-void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask = 0, jfloat vertical_factor = 0, jfloat horizontal_factor = 0);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3F(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FI(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value);
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 2d9f077df5..5de6d547d7 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -34,6 +34,10 @@
#include "scene/resources/world_2d.h"
#include "servers/navigation_server_2d.h"
+#ifdef DEBUG_ENABLED
+#include "servers/navigation_server_3d.h"
+#endif // DEBUG_ENABLED
+
HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlapping_coords_and_peering_bits() const {
HashMap<Vector2i, TileSet::CellNeighbor> output;
@@ -1656,14 +1660,6 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
ERR_FAIL_COND(!is_inside_tree());
ERR_FAIL_COND(!tile_set.is_valid());
- // Get colors for debug.
- SceneTree *st = SceneTree::get_singleton();
- Color debug_navigation_color;
- bool debug_navigation = st && st->is_debugging_navigation_hint();
- if (debug_navigation) {
- debug_navigation_color = st->get_debug_navigation_color();
- }
-
Transform2D tilemap_xform = get_global_transform();
SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
while (q_list_element) {
@@ -1766,7 +1762,10 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
RenderingServer *rs = RenderingServer::get_singleton();
- Color color = get_tree()->get_debug_navigation_color();
+ Color color = Color(0.5, 1.0, 1.0, 1.0);
+#ifdef DEBUG_ENABLED
+ color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
+#endif // DEBUG_ENABLED
RandomPCG rand;
Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 29ad1ba93d..049ca4c8a0 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -539,6 +539,7 @@ void NavigationRegion3D::_update_debug_edge_connections_mesh() {
}
Vector<Vector3> vertex_array;
+ vertex_array.resize(connections_count * 6);
for (int i = 0; i < connections_count; i++) {
Vector3 connection_pathway_start = NavigationServer3D::get_singleton()->region_get_connection_pathway_start(region, i);
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 25c9b33ff9..c840e6fd4b 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -722,22 +722,6 @@ float SceneTree::get_debug_paths_width() const {
return debug_paths_width;
}
-void SceneTree::set_debug_navigation_color(const Color &p_color) {
- debug_navigation_color = p_color;
-}
-
-Color SceneTree::get_debug_navigation_color() const {
- return debug_navigation_color;
-}
-
-void SceneTree::set_debug_navigation_disabled_color(const Color &p_color) {
- debug_navigation_disabled_color = p_color;
-}
-
-Color SceneTree::get_debug_navigation_disabled_color() const {
- return debug_navigation_disabled_color;
-}
-
Ref<Material> SceneTree::get_debug_paths_material() {
if (debug_paths_material.is_valid()) {
return debug_paths_material;
@@ -755,40 +739,6 @@ Ref<Material> SceneTree::get_debug_paths_material() {
return debug_paths_material;
}
-Ref<Material> SceneTree::get_debug_navigation_material() {
- if (navigation_material.is_valid()) {
- return navigation_material;
- }
-
- Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
- line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- line_material->set_albedo(get_debug_navigation_color());
-
- navigation_material = line_material;
-
- return navigation_material;
-}
-
-Ref<Material> SceneTree::get_debug_navigation_disabled_material() {
- if (navigation_disabled_material.is_valid()) {
- return navigation_disabled_material;
- }
-
- Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
- line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- line_material->set_albedo(get_debug_navigation_disabled_color());
-
- navigation_disabled_material = line_material;
-
- return navigation_disabled_material;
-}
-
Ref<Material> SceneTree::get_debug_collision_material() {
if (collision_material.is_valid()) {
return collision_material;
@@ -1404,8 +1354,6 @@ SceneTree::SceneTree() {
debug_collision_contact_color = GLOBAL_DEF("debug/shapes/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8));
debug_paths_color = GLOBAL_DEF("debug/shapes/paths/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
debug_paths_width = GLOBAL_DEF("debug/shapes/paths/geometry_width", 2.0);
- debug_navigation_color = GLOBAL_DEF("debug/shapes/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
- debug_navigation_disabled_color = GLOBAL_DEF("debug/shapes/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4));
collision_debug_contacts = GLOBAL_DEF("debug/shapes/collision/max_contacts_displayed", 10000);
ProjectSettings::get_singleton()->set_custom_property_info("debug/shapes/collision/max_contacts_displayed", PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1")); // No negative
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 45653001ca..3440be0aa4 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -334,15 +334,7 @@ public:
void set_debug_paths_width(float p_width);
float get_debug_paths_width() const;
- void set_debug_navigation_color(const Color &p_color);
- Color get_debug_navigation_color() const;
-
- void set_debug_navigation_disabled_color(const Color &p_color);
- Color get_debug_navigation_disabled_color() const;
-
Ref<Material> get_debug_paths_material();
- Ref<Material> get_debug_navigation_material();
- Ref<Material> get_debug_navigation_disabled_material();
Ref<Material> get_debug_collision_material();
Ref<ArrayMesh> get_debug_contact_mesh();
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 6c9c8ffdba..90ea879012 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -32,7 +32,7 @@
#ifdef DEBUG_ENABLED
#include "servers/navigation_server_3d.h"
-#endif
+#endif // DEBUG_ENABLED
void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) {
ERR_FAIL_COND(p_mesh.is_null());
@@ -341,94 +341,8 @@ void NavigationMesh::clear_polygons() {
polygons.clear();
}
-#ifndef DISABLE_DEPRECATED
-Ref<Mesh> NavigationMesh::get_debug_mesh() {
- if (debug_mesh.is_valid()) {
- return debug_mesh;
- }
-
- Vector<Vector3> vertices = get_vertices();
- const Vector3 *vr = vertices.ptr();
- List<Face3> faces;
- for (int i = 0; i < get_polygon_count(); i++) {
- Vector<int> p = get_polygon(i);
-
- for (int j = 2; j < p.size(); j++) {
- Face3 f;
- f.vertex[0] = vr[p[0]];
- f.vertex[1] = vr[p[j - 1]];
- f.vertex[2] = vr[p[j]];
-
- faces.push_back(f);
- }
- }
-
- HashMap<_EdgeKey, bool, _EdgeKey> edge_map;
- Vector<Vector3> tmeshfaces;
- tmeshfaces.resize(faces.size() * 3);
-
- {
- Vector3 *tw = tmeshfaces.ptrw();
- int tidx = 0;
-
- for (const Face3 &f : faces) {
- for (int j = 0; j < 3; j++) {
- tw[tidx++] = f.vertex[j];
- _EdgeKey ek;
- ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
- ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON));
- if (ek.from < ek.to) {
- SWAP(ek.from, ek.to);
- }
-
- HashMap<_EdgeKey, bool, _EdgeKey>::Iterator F = edge_map.find(ek);
-
- if (F) {
- F->value = false;
-
- } else {
- edge_map[ek] = true;
- }
- }
- }
- }
- List<Vector3> lines;
-
- for (const KeyValue<_EdgeKey, bool> &E : edge_map) {
- if (E.value) {
- lines.push_back(E.key.from);
- lines.push_back(E.key.to);
- }
- }
-
- Vector<Vector3> varr;
- varr.resize(lines.size());
- {
- Vector3 *w = varr.ptrw();
- int idx = 0;
- for (const Vector3 &E : lines) {
- w[idx++] = E;
- }
- }
-
- debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
-
- if (!lines.size()) {
- return debug_mesh;
- }
-
- Array arr;
- arr.resize(Mesh::ARRAY_MAX);
- arr[Mesh::ARRAY_VERTEX] = varr;
-
- debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr);
-
- return debug_mesh;
-}
-#endif // DISABLE_DEPRECATED
-
#ifdef DEBUG_ENABLED
-Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() {
+Ref<ArrayMesh> NavigationMesh::get_debug_mesh() {
if (debug_mesh.is_valid()) {
// Blocks further updates for now, code below is intended for dynamic updates e.g. when settings change.
return debug_mesh;
@@ -479,8 +393,6 @@ Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() {
for (int i = 0; i < polygon_count; i++) {
polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf()));
- Vector<int> polygon = get_polygon(i);
-
face_color_array.push_back(polygon_color);
face_color_array.push_back(polygon_color);
face_color_array.push_back(polygon_color);
@@ -490,7 +402,7 @@ Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() {
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
Ref<StandardMaterial3D> debug_geometry_face_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_material();
- debug_mesh->surface_set_material(debug_mesh->get_surface_count(), debug_geometry_face_material);
+ debug_mesh->surface_set_material(0, debug_geometry_face_material);
// if enabled build geometry edge line surface
bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines();
@@ -515,12 +427,12 @@ Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() {
line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array;
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array);
Ref<StandardMaterial3D> debug_geometry_edge_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_material();
- debug_mesh->surface_set_material(debug_mesh->get_surface_count(), debug_geometry_edge_material);
+ debug_mesh->surface_set_material(1, debug_geometry_edge_material);
}
return debug_mesh;
}
-#endif
+#endif // DEBUG_ENABLED
void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type);
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index c66025dc6d..5ddbd75dcb 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -202,11 +202,9 @@ public:
Vector<int> get_polygon(int p_idx);
void clear_polygons();
-#ifndef DISABLE_DEPRECATED
- Ref<Mesh> get_debug_mesh();
-#endif // DISABLE_DEPRECATED
-
- Ref<ArrayMesh> _get_debug_mesh();
+#ifdef DEBUG_ENABLED
+ Ref<ArrayMesh> get_debug_mesh();
+#endif // DEBUG_ENABLED
NavigationMesh();
};