summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/classes/ProjectSettings.xml6
-rw-r--r--editor/editor_settings.cpp5
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp5
-rw-r--r--editor/themes/editor_theme_manager.cpp4
-rw-r--r--main/main.cpp24
-rw-r--r--modules/enet/doc_classes/ENetConnection.xml2
-rw-r--r--platform/android/java/app/AndroidManifest.xml4
-rw-r--r--platform/android/java/app/config.gradle2
-rw-r--r--platform/android/java/editor/build.gradle2
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt12
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt10
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.kt128
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java7
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotIO.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java7
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java49
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt36
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java139
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java18
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/BenchmarkUtils.kt11
-rw-r--r--platform/android/java_godot_lib_jni.cpp7
-rw-r--r--platform/android/java_godot_lib_jni.h1
-rw-r--r--platform/web/web_main.cpp3
-rw-r--r--scene/gui/graph_edit.cpp4
-rw-r--r--scene/gui/graph_frame.cpp4
-rw-r--r--scene/gui/graph_frame.h1
-rw-r--r--servers/rendering_server.cpp34
27 files changed, 332 insertions, 195 deletions
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index b1556783d5..5c97a975fe 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1391,6 +1391,12 @@
Enabling this can greatly improve the responsiveness to input, specially in devices that need to run multiple physics frames per visible (process) frame, because they can't run at the target frame rate.
[b]Note:[/b] Currently implemented only on Android.
</member>
+ <member name="input_devices/buffering/android/use_accumulated_input" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], multiple input events will be accumulated into a single input event when possible.
+ </member>
+ <member name="input_devices/buffering/android/use_input_buffering" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], input events will be buffered prior to being dispatched.
+ </member>
<member name="input_devices/compatibility/legacy_just_pressed_behavior" type="bool" setter="" getter="" default="false">
If [code]true[/code], [method Input.is_action_just_pressed] and [method Input.is_action_just_released] will only return [code]true[/code] if the action is still in the respective state, i.e. an action that is pressed [i]and[/i] released on the same frame will be missed.
If [code]false[/code], no input will be lost.
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index e021be9668..85e60df1dd 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -474,6 +474,11 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/vsync_mode", 1, "Disabled,Enabled,Adaptive,Mailbox")
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/update_continuously", false, "")
+#ifdef ANDROID_ENABLED
+ EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/android/use_accumulated_input", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/android/use_input_buffering", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+#endif
+
// Inspector
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/inspector/max_array_dictionary_items_per_page", 20, "10,100,1")
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/show_low_level_opentype_features", false, "")
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 607c446e1b..2f36198b23 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -133,9 +133,9 @@ void VSRerouteNode::_notification(int p_what) {
connect(SceneStringName(mouse_exited), callable_mp(this, &VSRerouteNode::_on_mouse_exited));
} break;
case NOTIFICATION_DRAW: {
- Vector2 offset = Vector2(0, -16);
+ Vector2 offset = Vector2(0, -16 * EDSCALE);
Color drag_bg_color = get_theme_color(SNAME("drag_background"), SNAME("VSRerouteNode"));
- draw_circle(get_size() * 0.5 + offset, 16, Color(drag_bg_color, selected ? 1 : icon_opacity));
+ draw_circle(get_size() * 0.5 + offset, 16 * EDSCALE, Color(drag_bg_color, selected ? 1 : icon_opacity), true, -1, true);
Ref<Texture2D> icon = get_editor_theme_icon(SNAME("ToolMove"));
Point2 icon_offset = -icon->get_size() * 0.5 + get_size() * 0.5 + offset;
@@ -154,6 +154,7 @@ VSRerouteNode::VSRerouteNode() {
title_lbl->hide();
const Size2 size = Size2(32, 32) * EDSCALE;
+ print_line("VSRerouteNode size: " + size);
Control *slot_area = memnew(Control);
slot_area->set_custom_minimum_size(size);
diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp
index 9f0865d950..03752656c0 100644
--- a/editor/themes/editor_theme_manager.cpp
+++ b/editor/themes/editor_theme_manager.cpp
@@ -1665,7 +1665,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
// GraphFrame's title Label.
p_theme->set_type_variation("GraphFrameTitleLabel", "Label");
p_theme->set_stylebox(CoreStringName(normal), "GraphFrameTitleLabel", memnew(StyleBoxEmpty));
- p_theme->set_font_size(SceneStringName(font_size), "GraphFrameTitleLabel", 22);
+ p_theme->set_font_size(SceneStringName(font_size), "GraphFrameTitleLabel", 22 * EDSCALE);
p_theme->set_color(SceneStringName(font_color), "GraphFrameTitleLabel", Color(1, 1, 1));
p_theme->set_color("font_shadow_color", "GraphFrameTitleLabel", Color(0, 0, 0, 0));
p_theme->set_color("font_outline_color", "GraphFrameTitleLabel", Color(1, 1, 1));
@@ -1680,7 +1680,7 @@ void EditorThemeManager::_populate_standard_styles(const Ref<EditorTheme> &p_the
{
Ref<StyleBox> vs_reroute_panel_style = make_empty_stylebox();
Ref<StyleBox> vs_reroute_titlebar_style = vs_reroute_panel_style->duplicate();
- vs_reroute_titlebar_style->set_content_margin_all(16);
+ vs_reroute_titlebar_style->set_content_margin_all(16 * EDSCALE);
p_theme->set_stylebox(SceneStringName(panel), "VSRerouteNode", vs_reroute_panel_style);
p_theme->set_stylebox("panel_selected", "VSRerouteNode", vs_reroute_panel_style);
p_theme->set_stylebox("titlebar", "VSRerouteNode", vs_reroute_titlebar_style);
diff --git a/main/main.cpp b/main/main.cpp
index 9743a8086f..e6be23034d 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -909,13 +909,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// Benchmark tracking must be done after `OS::get_singleton()->initialize()` as on some
// platforms, it's used to set up the time utilities.
- OS::get_singleton()->benchmark_begin_measure("Startup", "Total");
- OS::get_singleton()->benchmark_begin_measure("Startup", "Setup");
+ OS::get_singleton()->benchmark_begin_measure("Startup", "Main::Setup");
engine = memnew(Engine);
MAIN_PRINT("Main: Initialize CORE");
- OS::get_singleton()->benchmark_begin_measure("Startup", "Core");
register_core_types();
register_core_driver_types();
@@ -2453,8 +2451,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
Thread::release_main_thread(); // If setup2() is called from another thread, that one will become main thread, so preventively release this one.
set_current_thread_safe_for_nodes(false);
- OS::get_singleton()->benchmark_end_measure("Startup", "Core");
-
#if defined(STEAMAPI_ENABLED)
if (editor || project_manager) {
steam_tracker = memnew(SteamTracker);
@@ -2465,7 +2461,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
return setup2();
}
- OS::get_singleton()->benchmark_end_measure("Startup", "Setup");
+ OS::get_singleton()->benchmark_end_measure("Startup", "Main::Setup");
return OK;
error:
@@ -2519,7 +2515,7 @@ error:
}
OS::get_singleton()->benchmark_end_measure("Startup", "Core");
- OS::get_singleton()->benchmark_end_measure("Startup", "Setup");
+ OS::get_singleton()->benchmark_end_measure("Startup", "Main::Setup");
#if defined(STEAMAPI_ENABLED)
if (steam_tracker) {
@@ -2553,6 +2549,8 @@ Error _parse_resource_dummy(void *p_data, VariantParser::Stream *p_stream, Ref<R
}
Error Main::setup2(bool p_show_boot_logo) {
+ OS::get_singleton()->benchmark_begin_measure("Startup", "Main::Setup2");
+
Thread::make_main_thread(); // Make whatever thread call this the main thread.
set_current_thread_safe_for_nodes(true);
@@ -2941,6 +2939,8 @@ Error Main::setup2(bool p_show_boot_logo) {
id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true)));
}
+ GLOBAL_DEF("input_devices/buffering/android/use_accumulated_input", true);
+ GLOBAL_DEF("input_devices/buffering/android/use_input_buffering", true);
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false);
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1);
@@ -3149,7 +3149,7 @@ Error Main::setup2(bool p_show_boot_logo) {
print_verbose("EDITOR API HASH: " + uitos(ClassDB::get_api_hash(ClassDB::API_EDITOR)));
MAIN_PRINT("Main: Done");
- OS::get_singleton()->benchmark_end_measure("Startup", "Setup");
+ OS::get_singleton()->benchmark_end_measure("Startup", "Main::Setup2");
return OK;
}
@@ -3230,6 +3230,8 @@ static MainTimerSync main_timer_sync;
// and should move on to `OS::run`, and EXIT_FAILURE otherwise for
// an early exit with that error code.
int Main::start() {
+ OS::get_singleton()->benchmark_begin_measure("Startup", "Main::Start");
+
ERR_FAIL_COND_V(!_start_success, false);
bool has_icon = false;
@@ -3953,7 +3955,7 @@ int Main::start() {
}
}
- OS::get_singleton()->benchmark_end_measure("Startup", "Total");
+ OS::get_singleton()->benchmark_end_measure("Startup", "Main::Start");
OS::get_singleton()->benchmark_dump();
return EXIT_SUCCESS;
@@ -4221,7 +4223,7 @@ void Main::force_redraw() {
* The order matters as some of those steps are linked with each other.
*/
void Main::cleanup(bool p_force) {
- OS::get_singleton()->benchmark_begin_measure("Shutdown", "Total");
+ OS::get_singleton()->benchmark_begin_measure("Shutdown", "Main::Cleanup");
if (!p_force) {
ERR_FAIL_COND(!_start_success);
}
@@ -4379,7 +4381,7 @@ void Main::cleanup(bool p_force) {
unregister_core_types();
- OS::get_singleton()->benchmark_end_measure("Shutdown", "Total");
+ OS::get_singleton()->benchmark_end_measure("Shutdown", "Main::Cleanup");
OS::get_singleton()->benchmark_dump();
OS::get_singleton()->finalize_core();
diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml
index 5795dd8976..ebd1577172 100644
--- a/modules/enet/doc_classes/ENetConnection.xml
+++ b/modules/enet/doc_classes/ENetConnection.xml
@@ -141,7 +141,7 @@
<return type="Array" />
<param index="0" name="timeout" type="int" default="0" />
<description>
- Waits for events on the host specified and shuttles packets between the host and its peers. The returned [Array] will have 4 elements. An [enum EventType], the [ENetPacketPeer] which generated the event, the event associated data (if any), the event associated channel (if any). If the generated event is [constant EVENT_RECEIVE], the received packet will be queued to the associated [ENetPacketPeer].
+ Waits for events on the specified host and shuttles packets between the host and its peers, with the given [param timeout] (in milliseconds). The returned [Array] will have 4 elements. An [enum EventType], the [ENetPacketPeer] which generated the event, the event associated data (if any), the event associated channel (if any). If the generated event is [constant EVENT_RECEIVE], the received packet will be queued to the associated [ENetPacketPeer].
Call this function regularly to handle connections, disconnections, and to receive new packets.
</description>
</method>
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index 4abc6548bf..0cc929d226 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -24,6 +24,10 @@
android:hasFragileUserData="false"
android:requestLegacyExternalStorage="false"
tools:ignore="GoogleAppIndexingWarning" >
+ <profileable
+ android:shell="true"
+ android:enabled="true"
+ tools:targetApi="29" />
<!-- Records the version of the Godot editor used for building -->
<meta-data
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index 01759a1b2f..eb9ad9de05 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -7,7 +7,7 @@ ext.versions = [
targetSdk : 34,
buildTools : '34.0.0',
kotlinVersion : '1.9.20',
- fragmentVersion : '1.6.2',
+ fragmentVersion : '1.7.1',
nexusPublishVersion: '1.3.0',
javaVersion : JavaVersion.VERSION_17,
// Also update 'platform/android/detect.py#get_ndk_version()' when this is updated.
diff --git a/platform/android/java/editor/build.gradle b/platform/android/java/editor/build.gradle
index 55fe2a22fe..37f68d295a 100644
--- a/platform/android/java/editor/build.gradle
+++ b/platform/android/java/editor/build.gradle
@@ -9,7 +9,7 @@ dependencies {
implementation "androidx.fragment:fragment:$versions.fragmentVersion"
implementation project(":lib")
- implementation "androidx.window:window:1.2.0"
+ implementation "androidx.window:window:1.3.0"
implementation "androidx.core:core-splashscreen:$versions.splashscreenVersion"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
}
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 5515347bd6..dad397de61 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
@@ -117,6 +117,10 @@ open class GodotEditor : GodotActivity() {
val longPressEnabled = enableLongPressGestures()
val panScaleEnabled = enablePanAndScaleGestures()
+ val useInputBuffering = useInputBuffering()
+ val useAccumulatedInput = useAccumulatedInput()
+ GodotLib.updateInputDispatchSettings(useAccumulatedInput, useInputBuffering)
+
checkForProjectPermissionsToEnable()
runOnUiThread {
@@ -124,6 +128,7 @@ open class GodotEditor : GodotActivity() {
godotFragment?.godot?.renderView?.inputHandler?.apply {
enableLongPress(longPressEnabled)
enablePanningAndScalingGestures(panScaleEnabled)
+ enableInputDispatchToRenderThread(!useInputBuffering && !useAccumulatedInput)
}
}
}
@@ -275,6 +280,13 @@ open class GodotEditor : GodotActivity() {
java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/touchscreen/enable_pan_and_scale_gestures"))
/**
+ * Use input buffering for the Godot Android editor.
+ */
+ protected open fun useInputBuffering() = java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/editor/android/use_input_buffering"))
+
+ protected open fun useAccumulatedInput() = java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/editor/android/use_accumulated_input"))
+
+ /**
* Whether we should launch the new godot instance in an adjacent window
* @see https://developer.android.com/reference/android/content/Intent#FLAG_ACTIVITY_LAUNCH_ADJACENT
*/
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 8e4e089211..f50b5577c3 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
@@ -30,6 +30,8 @@
package org.godotengine.editor
+import org.godotengine.godot.GodotLib
+
/**
* Drives the 'run project' window of the Godot Editor.
*/
@@ -39,9 +41,13 @@ class GodotGame : GodotEditor() {
override fun overrideOrientationRequest() = false
- override fun enableLongPressGestures() = false
+ override fun enableLongPressGestures() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_long_press_as_right_click"))
+
+ override fun enablePanAndScaleGestures() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures"))
+
+ override fun useInputBuffering() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_input_buffering"))
- override fun enablePanAndScaleGestures() = false
+ override fun useAccumulatedInput() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_accumulated_input"))
override fun checkForProjectPermissionsToEnable() {
// Nothing to do.. by the time we get here, the project permissions will have already
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
index 290be727ab..c188a97ca5 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
@@ -84,17 +84,20 @@ class Godot(private val context: Context) : SensorEventListener {
private companion object {
private val TAG = Godot::class.java.simpleName
- }
- private val windowManager: WindowManager by lazy {
- requireActivity().getSystemService(Context.WINDOW_SERVICE) as WindowManager
+ // Supported build flavors
+ const val EDITOR_FLAVOR = "editor"
+ const val TEMPLATE_FLAVOR = "template"
}
+
+ private val windowManager: WindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+ private val mSensorManager: SensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
+ private val mClipboard: ClipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ private val vibratorService: Vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
+
private val pluginRegistry: GodotPluginRegistry by lazy {
GodotPluginRegistry.getPluginRegistry()
}
- private val mSensorManager: SensorManager by lazy {
- requireActivity().getSystemService(Context.SENSOR_SERVICE) as SensorManager
- }
private val mAccelerometer: Sensor? by lazy {
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
}
@@ -107,9 +110,6 @@ class Godot(private val context: Context) : SensorEventListener {
private val mGyroscope: Sensor? by lazy {
mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
}
- private val mClipboard: ClipboardManager by lazy {
- requireActivity().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
- }
private val uiChangeListener = View.OnSystemUiVisibilityChangeListener { visibility: Int ->
if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
@@ -192,6 +192,8 @@ class Godot(private val context: Context) : SensorEventListener {
return
}
+ Log.v(TAG, "OnCreate: $primaryHost")
+
darkMode = context.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
beginBenchmarkMeasure("Startup", "Godot::onCreate")
@@ -200,6 +202,8 @@ class Godot(private val context: Context) : SensorEventListener {
val activity = requireActivity()
val window = activity.window
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
+
+ Log.v(TAG, "Initializing Godot plugin registry")
GodotPluginRegistry.initializePluginRegistry(this, primaryHost.getHostPlugins(this))
if (io == null) {
io = GodotIO(activity)
@@ -323,13 +327,17 @@ class Godot(private val context: Context) : SensorEventListener {
return false
}
- if (expansionPackPath.isNotEmpty()) {
- commandLine.add("--main-pack")
- commandLine.add(expansionPackPath)
- }
- val activity = requireActivity()
- if (!nativeLayerInitializeCompleted) {
- nativeLayerInitializeCompleted = GodotLib.initialize(
+ Log.v(TAG, "OnInitNativeLayer: $host")
+
+ beginBenchmarkMeasure("Startup", "Godot::onInitNativeLayer")
+ try {
+ if (expansionPackPath.isNotEmpty()) {
+ commandLine.add("--main-pack")
+ commandLine.add(expansionPackPath)
+ }
+ val activity = requireActivity()
+ if (!nativeLayerInitializeCompleted) {
+ nativeLayerInitializeCompleted = GodotLib.initialize(
activity,
this,
activity.assets,
@@ -338,15 +346,20 @@ class Godot(private val context: Context) : SensorEventListener {
directoryAccessHandler,
fileAccessHandler,
useApkExpansion,
- )
- }
+ )
+ Log.v(TAG, "Godot native layer initialization completed: $nativeLayerInitializeCompleted")
+ }
- if (nativeLayerInitializeCompleted && !nativeLayerSetupCompleted) {
- nativeLayerSetupCompleted = GodotLib.setup(commandLine.toTypedArray(), tts)
- if (!nativeLayerSetupCompleted) {
- Log.e(TAG, "Unable to setup the Godot engine! Aborting...")
- alert(R.string.error_engine_setup_message, R.string.text_error_title, this::forceQuit)
+ if (nativeLayerInitializeCompleted && !nativeLayerSetupCompleted) {
+ nativeLayerSetupCompleted = GodotLib.setup(commandLine.toTypedArray(), tts)
+ if (!nativeLayerSetupCompleted) {
+ throw IllegalStateException("Unable to setup the Godot engine! Aborting...")
+ } else {
+ Log.v(TAG, "Godot native layer setup completed")
+ }
}
+ } finally {
+ endBenchmarkMeasure("Startup", "Godot::onInitNativeLayer")
}
return isNativeInitialized()
}
@@ -370,6 +383,9 @@ class Godot(private val context: Context) : SensorEventListener {
throw IllegalStateException("onInitNativeLayer() must be invoked successfully prior to initializing the render view")
}
+ Log.v(TAG, "OnInitRenderView: $host")
+
+ beginBenchmarkMeasure("Startup", "Godot::onInitRenderView")
try {
val activity: Activity = host.activity
containerLayout = providedContainerLayout
@@ -392,8 +408,7 @@ class Godot(private val context: Context) : SensorEventListener {
containerLayout?.addView(editText)
renderView = if (usesVulkan()) {
if (!meetsVulkanRequirements(activity.packageManager)) {
- alert(R.string.error_missing_vulkan_requirements_message, R.string.text_error_title, this::forceQuit)
- return null
+ throw IllegalStateException(activity.getString(R.string.error_missing_vulkan_requirements_message))
}
GodotVulkanRenderView(host, this)
} else {
@@ -482,11 +497,14 @@ class Godot(private val context: Context) : SensorEventListener {
containerLayout?.removeAllViews()
containerLayout = null
}
+
+ endBenchmarkMeasure("Startup", "Godot::onInitRenderView")
}
return containerLayout
}
fun onStart(host: GodotHost) {
+ Log.v(TAG, "OnStart: $host")
if (host != primaryHost) {
return
}
@@ -495,6 +513,7 @@ class Godot(private val context: Context) : SensorEventListener {
}
fun onResume(host: GodotHost) {
+ Log.v(TAG, "OnResume: $host")
if (host != primaryHost) {
return
}
@@ -527,6 +546,7 @@ class Godot(private val context: Context) : SensorEventListener {
}
fun onPause(host: GodotHost) {
+ Log.v(TAG, "OnPause: $host")
if (host != primaryHost) {
return
}
@@ -539,6 +559,7 @@ class Godot(private val context: Context) : SensorEventListener {
}
fun onStop(host: GodotHost) {
+ Log.v(TAG, "OnStop: $host")
if (host != primaryHost) {
return
}
@@ -547,6 +568,7 @@ class Godot(private val context: Context) : SensorEventListener {
}
fun onDestroy(primaryHost: GodotHost) {
+ Log.v(TAG, "OnDestroy: $primaryHost")
if (this.primaryHost != primaryHost) {
return
}
@@ -604,18 +626,29 @@ class Godot(private val context: Context) : SensorEventListener {
* Invoked on the render thread when the Godot setup is complete.
*/
private fun onGodotSetupCompleted() {
- Log.d(TAG, "OnGodotSetupCompleted")
-
- // These properties are defined after Godot setup completion, so we retrieve them here.
- val longPressEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_long_press_as_right_click"))
- val panScaleEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures"))
- val rotaryInputAxis = java.lang.Integer.parseInt(GodotLib.getGlobal("input_devices/pointing/android/rotary_input_scroll_axis"))
-
- runOnUiThread {
- renderView?.inputHandler?.apply {
- enableLongPress(longPressEnabled)
- enablePanningAndScalingGestures(panScaleEnabled)
- setRotaryInputAxis(rotaryInputAxis)
+ Log.v(TAG, "OnGodotSetupCompleted")
+
+ if (!isEditorBuild()) {
+ // These properties are defined after Godot setup completion, so we retrieve them here.
+ val longPressEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_long_press_as_right_click"))
+ val panScaleEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures"))
+ val rotaryInputAxisValue = GodotLib.getGlobal("input_devices/pointing/android/rotary_input_scroll_axis")
+
+ val useInputBuffering = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_input_buffering"))
+ val useAccumulatedInput = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/buffering/android/use_accumulated_input"))
+ GodotLib.updateInputDispatchSettings(useAccumulatedInput, useInputBuffering)
+
+ runOnUiThread {
+ renderView?.inputHandler?.apply {
+ enableLongPress(longPressEnabled)
+ enablePanningAndScalingGestures(panScaleEnabled)
+ enableInputDispatchToRenderThread(!useInputBuffering && !useAccumulatedInput)
+ try {
+ setRotaryInputAxis(Integer.parseInt(rotaryInputAxisValue))
+ } catch (e: NumberFormatException) {
+ Log.w(TAG, e)
+ }
+ }
}
}
@@ -629,7 +662,7 @@ class Godot(private val context: Context) : SensorEventListener {
* Invoked on the render thread when the Godot main loop has started.
*/
private fun onGodotMainLoopStarted() {
- Log.d(TAG, "OnGodotMainLoopStarted")
+ Log.v(TAG, "OnGodotMainLoopStarted")
for (plugin in pluginRegistry.allPlugins) {
plugin.onGodotMainLoopStarted()
@@ -646,12 +679,7 @@ class Godot(private val context: Context) : SensorEventListener {
decorView.setOnSystemUiVisibilityChangeListener(uiChangeListener)
}
- @Keep
- private fun alert(message: String, title: String) {
- alert(message, title, null)
- }
-
- private fun alert(
+ fun alert(
@StringRes messageResId: Int,
@StringRes titleResId: Int,
okCallback: Runnable?
@@ -660,7 +688,9 @@ class Godot(private val context: Context) : SensorEventListener {
alert(res.getString(messageResId), res.getString(titleResId), okCallback)
}
- private fun alert(message: String, title: String, okCallback: Runnable?) {
+ @JvmOverloads
+ @Keep
+ fun alert(message: String, title: String, okCallback: Runnable? = null) {
val activity: Activity = getActivity() ?: return
runOnUiThread {
val builder = AlertDialog.Builder(activity)
@@ -759,6 +789,11 @@ class Godot(private val context: Context) : SensorEventListener {
return mClipboard.hasPrimaryClip()
}
+ /**
+ * @return true if this is an editor build, false if this is a template build
+ */
+ fun isEditorBuild() = BuildConfig.FLAVOR == EDITOR_FLAVOR
+
fun getClipboard(): String {
val clipData = mClipboard.primaryClip ?: return ""
val text = clipData.getItemAt(0).text ?: return ""
@@ -770,7 +805,7 @@ class Godot(private val context: Context) : SensorEventListener {
mClipboard.setPrimaryClip(clip)
}
- private fun forceQuit() {
+ fun forceQuit() {
forceQuit(0)
}
@@ -881,7 +916,6 @@ class Godot(private val context: Context) : SensorEventListener {
@Keep
private fun vibrate(durationMs: Int, amplitude: Int) {
if (durationMs > 0 && requestPermission("VIBRATE")) {
- val vibratorService = getActivity()?.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator? ?: return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (amplitude <= -1) {
vibratorService.vibrate(
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java b/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java
index a323045e1b..1612ddd0b3 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotFragment.java
@@ -42,6 +42,7 @@ import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.os.Messenger;
+import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -203,6 +204,12 @@ public class GodotFragment extends Fragment implements IDownloaderClient, GodotH
if (godotContainerLayout == null) {
throw new IllegalStateException("Unable to initialize engine render view");
}
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Engine initialization failed", e);
+ final String errorMessage = TextUtils.isEmpty(e.getMessage())
+ ? getString(R.string.error_engine_setup_message)
+ : e.getMessage();
+ godot.alert(errorMessage, getString(R.string.text_error_title), godot::forceQuit);
} catch (IllegalArgumentException ignored) {
final Activity activity = getActivity();
Intent notifierIntent = new Intent(activity, activity.getClass());
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
index 4b51bd778d..219631284a 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
@@ -121,7 +121,7 @@ public class GodotIO {
activity.startActivity(intent);
return 0;
- } catch (ActivityNotFoundException e) {
+ } catch (Exception e) {
Log.e(TAG, "Unable to open uri " + uriString, e);
return 1;
}
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 d0c3d4a687..37e889daf7 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -240,4 +240,11 @@ public class GodotLib {
* @see GodotRenderer#onActivityPaused()
*/
public static native void onRendererPaused();
+
+ /**
+ * Invoked on the GL thread to update the input dispatch settings
+ * @param useAccumulatedInput True to use accumulated input, false otherwise
+ * @param useInputBuffering True to use input buffering, false otherwise
+ */
+ public static native void updateInputDispatchSettings(boolean useAccumulatedInput, boolean useInputBuffering);
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java
index c316812404..c9421a3257 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java
@@ -1704,15 +1704,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
mHasSurface = true;
mFinishedCreatingEglSurface = false;
sGLThreadManager.notifyAll();
- while (mWaitingForSurface
- && !mFinishedCreatingEglSurface
- && !mExited) {
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
}
}
@@ -1723,13 +1714,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
mHasSurface = false;
sGLThreadManager.notifyAll();
- while((!mWaitingForSurface) && (!mExited)) {
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
}
}
@@ -1740,16 +1724,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
mRequestPaused = true;
sGLThreadManager.notifyAll();
- while ((! mExited) && (! mPaused)) {
- if (LOG_PAUSE_RESUME) {
- Log.i("Main thread", "onPause waiting for mPaused.");
- }
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
- }
}
}
@@ -1762,16 +1736,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
mRequestRender = true;
mRenderComplete = false;
sGLThreadManager.notifyAll();
- while ((! mExited) && mPaused && (!mRenderComplete)) {
- if (LOG_PAUSE_RESUME) {
- Log.i("Main thread", "onResume waiting for !mPaused.");
- }
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
- }
}
}
@@ -1793,19 +1757,6 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
}
sGLThreadManager.notifyAll();
-
- // Wait for thread to react to resize and render a frame
- while (! mExited && !mPaused && !mRenderComplete
- && ableToDraw()) {
- if (LOG_SURFACE) {
- Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + getId());
- }
- try {
- sGLThreadManager.wait();
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
- }
}
}
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
index 49b34a5229..4cd3bd8db9 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
@@ -44,7 +44,7 @@ import org.godotengine.godot.GodotLib
* @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 {
+internal class GodotGestureHandler(private val inputHandler: GodotInputHandler) : SimpleOnGestureListener(), OnScaleGestureListener {
companion object {
private val TAG = GodotGestureHandler::class.java.simpleName
@@ -65,13 +65,13 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
private var lastDragY: Float = 0.0f
override fun onDown(event: MotionEvent): Boolean {
- GodotInputHandler.handleMotionEvent(event, MotionEvent.ACTION_DOWN, nextDownIsDoubleTap)
+ inputHandler.handleMotionEvent(event, MotionEvent.ACTION_DOWN, nextDownIsDoubleTap)
nextDownIsDoubleTap = false
return true
}
override fun onSingleTapUp(event: MotionEvent): Boolean {
- GodotInputHandler.handleMotionEvent(event)
+ inputHandler.handleMotionEvent(event)
return true
}
@@ -85,10 +85,10 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}
// Cancel the previous down event
- GodotInputHandler.handleMotionEvent(event, MotionEvent.ACTION_CANCEL)
+ inputHandler.handleMotionEvent(event, MotionEvent.ACTION_CANCEL)
// Turn a context click into a single tap right mouse button click.
- GodotInputHandler.handleMouseEvent(
+ inputHandler.handleMouseEvent(
event,
MotionEvent.ACTION_DOWN,
MotionEvent.BUTTON_SECONDARY,
@@ -104,7 +104,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
if (!hasCapture) {
// Dispatch a mouse relative ACTION_UP event to signal the end of the capture
- GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_UP, true)
+ inputHandler.handleMouseEvent(MotionEvent.ACTION_UP, true)
}
pointerCaptureInProgress = hasCapture
}
@@ -131,9 +131,9 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
if (contextClickInProgress || GodotInputHandler.isMouseEvent(event)) {
// This may be an ACTION_BUTTON_RELEASE event which we don't handle,
// so we convert it to an ACTION_UP event.
- GodotInputHandler.handleMouseEvent(event, MotionEvent.ACTION_UP)
+ inputHandler.handleMouseEvent(event, MotionEvent.ACTION_UP)
} else {
- GodotInputHandler.handleTouchEvent(event)
+ inputHandler.handleTouchEvent(event)
}
pointerCaptureInProgress = false
dragInProgress = false
@@ -148,7 +148,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
private fun onActionMove(event: MotionEvent): Boolean {
if (contextClickInProgress) {
- GodotInputHandler.handleMouseEvent(event, event.actionMasked, MotionEvent.BUTTON_SECONDARY, false)
+ inputHandler.handleMouseEvent(event, event.actionMasked, MotionEvent.BUTTON_SECONDARY, false)
return true
} else if (!scaleInProgress) {
// The 'onScroll' event is triggered with a long delay.
@@ -158,7 +158,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
if (lastDragX != event.getX(0) || lastDragY != event.getY(0)) {
lastDragX = event.getX(0)
lastDragY = event.getY(0)
- GodotInputHandler.handleMotionEvent(event)
+ inputHandler.handleMotionEvent(event)
return true
}
}
@@ -168,9 +168,9 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
override fun onDoubleTapEvent(event: MotionEvent): Boolean {
if (event.actionMasked == MotionEvent.ACTION_UP) {
nextDownIsDoubleTap = false
- GodotInputHandler.handleMotionEvent(event)
+ inputHandler.handleMotionEvent(event)
} else if (event.actionMasked == MotionEvent.ACTION_MOVE && !panningAndScalingEnabled) {
- GodotInputHandler.handleMotionEvent(event)
+ inputHandler.handleMotionEvent(event)
}
return true
@@ -191,7 +191,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
if (dragInProgress || lastDragX != 0.0f || lastDragY != 0.0f) {
if (originEvent != null) {
// Cancel the drag
- GodotInputHandler.handleMotionEvent(originEvent, MotionEvent.ACTION_CANCEL)
+ inputHandler.handleMotionEvent(originEvent, MotionEvent.ACTION_CANCEL)
}
dragInProgress = false
lastDragX = 0.0f
@@ -202,12 +202,12 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
val x = terminusEvent.x
val y = terminusEvent.y
if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled && !pointerCaptureInProgress && !dragInProgress) {
- GodotLib.pan(x, y, distanceX / 5f, distanceY / 5f)
+ inputHandler.handlePanEvent(x, y, distanceX / 5f, distanceY / 5f)
} else if (!scaleInProgress) {
dragInProgress = true
lastDragX = terminusEvent.getX(0)
lastDragY = terminusEvent.getY(0)
- GodotInputHandler.handleMotionEvent(terminusEvent)
+ inputHandler.handleMotionEvent(terminusEvent)
}
return true
}
@@ -218,11 +218,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}
if (detector.scaleFactor >= 0.8f && detector.scaleFactor != 1f && detector.scaleFactor <= 1.2f) {
- GodotLib.magnify(
- detector.focusX,
- detector.focusY,
- detector.scaleFactor
- )
+ inputHandler.handleMagnifyEvent(detector.focusX, detector.focusY, detector.scaleFactor)
}
return true
}
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 83e76e49c9..889618914d 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
@@ -75,7 +75,9 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
*/
private int lastSeenToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
- private static int rotaryInputAxis = ROTARY_INPUT_VERTICAL_AXIS;
+ private int rotaryInputAxis = ROTARY_INPUT_VERTICAL_AXIS;
+
+ private boolean dispatchInputToRenderThread = false;
public GodotInputHandler(GodotRenderView godotView) {
final Context context = godotView.getView().getContext();
@@ -83,7 +85,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
mInputManager = (InputManager)context.getSystemService(Context.INPUT_SERVICE);
mInputManager.registerInputDeviceListener(this, null);
- this.godotGestureHandler = new GodotGestureHandler();
+ this.godotGestureHandler = new GodotGestureHandler(this);
this.gestureDetector = new GestureDetector(context, godotGestureHandler);
this.gestureDetector.setIsLongpressEnabled(false);
this.scaleGestureDetector = new ScaleGestureDetector(context, godotGestureHandler);
@@ -109,6 +111,22 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
/**
+ * Specifies whether input should be dispatch on the UI thread or on the Render thread.
+ * @param enable true to dispatch input on the Render thread, false to dispatch input on the UI thread
+ */
+ public void enableInputDispatchToRenderThread(boolean enable) {
+ this.dispatchInputToRenderThread = enable;
+ }
+
+ /**
+ * @return true if input must be dispatched from the render thread. If false, input is
+ * dispatched from the UI thread.
+ */
+ private boolean shouldDispatchInputToRenderThread() {
+ return dispatchInputToRenderThread;
+ }
+
+ /**
* On Wear OS devices, sets which axis of the mouse wheel rotary input is mapped to. This is 1 (vertical axis) by default.
*/
public void setRotaryInputAxis(int axis) {
@@ -151,14 +169,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
if (mJoystickIds.indexOfKey(deviceId) >= 0) {
final int button = getGodotButton(keyCode);
final int godotJoyId = mJoystickIds.get(deviceId);
- GodotLib.joybutton(godotJoyId, button, false);
+ handleJoystickButtonEvent(godotJoyId, button, false);
}
} else {
// getKeyCode(): The physical key that was pressed.
final int physical_keycode = event.getKeyCode();
final int unicode = event.getUnicodeChar();
final int key_label = event.getDisplayLabel();
- GodotLib.key(physical_keycode, unicode, key_label, false, event.getRepeatCount() > 0);
+ handleKeyEvent(physical_keycode, unicode, key_label, false, event.getRepeatCount() > 0);
};
return true;
@@ -187,13 +205,13 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
if (mJoystickIds.indexOfKey(deviceId) >= 0) {
final int button = getGodotButton(keyCode);
final int godotJoyId = mJoystickIds.get(deviceId);
- GodotLib.joybutton(godotJoyId, button, true);
+ handleJoystickButtonEvent(godotJoyId, button, true);
}
} else {
final int physical_keycode = event.getKeyCode();
final int unicode = event.getUnicodeChar();
final int key_label = event.getDisplayLabel();
- GodotLib.key(physical_keycode, unicode, key_label, true, event.getRepeatCount() > 0);
+ handleKeyEvent(physical_keycode, unicode, key_label, true, event.getRepeatCount() > 0);
}
return true;
@@ -248,7 +266,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
if (joystick.axesValues.indexOfKey(axis) < 0 || (float)joystick.axesValues.get(axis) != value) {
// save value to prevent repeats
joystick.axesValues.put(axis, value);
- GodotLib.joyaxis(godotJoyId, i, value);
+ handleJoystickAxisEvent(godotJoyId, i, value);
}
}
@@ -258,7 +276,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
if (joystick.hatX != hatX || joystick.hatY != hatY) {
joystick.hatX = hatX;
joystick.hatY = hatY;
- GodotLib.joyhat(godotJoyId, hatX, hatY);
+ handleJoystickHatEvent(godotJoyId, hatX, hatY);
}
}
return true;
@@ -284,10 +302,12 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
int[] deviceIds = mInputManager.getInputDeviceIds();
for (int deviceId : deviceIds) {
InputDevice device = mInputManager.getInputDevice(deviceId);
- if (DEBUG) {
- Log.v(TAG, String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName()));
+ if (device != null) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName()));
+ }
+ onInputDeviceAdded(deviceId);
}
- onInputDeviceAdded(deviceId);
}
}
@@ -364,7 +384,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
mJoysticksDevices.put(deviceId, joystick);
- GodotLib.joyconnectionchanged(id, true, joystick.name);
+ handleJoystickConnectionChangedEvent(id, true, joystick.name);
}
@Override
@@ -378,7 +398,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
final int godotJoyId = mJoystickIds.get(deviceId);
mJoystickIds.delete(deviceId);
mJoysticksDevices.delete(deviceId);
- GodotLib.joyconnectionchanged(godotJoyId, false, "");
+ handleJoystickConnectionChangedEvent(godotJoyId, false, "");
}
@Override
@@ -482,15 +502,15 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
}
- static boolean handleMotionEvent(final MotionEvent event) {
+ boolean handleMotionEvent(final MotionEvent event) {
return handleMotionEvent(event, event.getActionMasked());
}
- static boolean handleMotionEvent(final MotionEvent event, int eventActionOverride) {
+ boolean handleMotionEvent(final MotionEvent event, int eventActionOverride) {
return handleMotionEvent(event, eventActionOverride, false);
}
- static boolean handleMotionEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
+ boolean handleMotionEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
if (isMouseEvent(event)) {
return handleMouseEvent(event, eventActionOverride, doubleTap);
}
@@ -523,19 +543,19 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
return (float)Math.cos(orientation) * tiltMult;
}
- static boolean handleMouseEvent(final MotionEvent event) {
+ boolean handleMouseEvent(final MotionEvent event) {
return handleMouseEvent(event, event.getActionMasked());
}
- static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride) {
+ boolean handleMouseEvent(final MotionEvent event, int eventActionOverride) {
return handleMouseEvent(event, eventActionOverride, false);
}
- static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
+ boolean handleMouseEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
return handleMouseEvent(event, eventActionOverride, event.getButtonState(), doubleTap);
}
- static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride, int buttonMaskOverride, boolean doubleTap) {
+ boolean handleMouseEvent(final MotionEvent event, int eventActionOverride, int buttonMaskOverride, boolean doubleTap) {
final float x = event.getX();
final float y = event.getY();
@@ -564,11 +584,11 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
return handleMouseEvent(eventActionOverride, buttonMaskOverride, x, y, horizontalFactor, verticalFactor, doubleTap, sourceMouseRelative, pressure, getEventTiltX(event), getEventTiltY(event));
}
- static boolean handleMouseEvent(int eventAction, boolean sourceMouseRelative) {
+ boolean handleMouseEvent(int eventAction, boolean sourceMouseRelative) {
return handleMouseEvent(eventAction, 0, 0f, 0f, 0f, 0f, false, sourceMouseRelative, 1f, 0f, 0f);
}
- static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative, float pressure, float tiltX, float tiltY) {
+ boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative, float pressure, float tiltX, float tiltY) {
// Fix the buttonsMask
switch (eventAction) {
case MotionEvent.ACTION_CANCEL:
@@ -584,6 +604,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
break;
}
+ final int updatedButtonsMask = buttonsMask;
// We don't handle ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE events as they typically
// follow ACTION_DOWN and ACTION_UP events. As such, handling them would result in duplicate
// stream of events to the engine.
@@ -596,22 +617,26 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
case MotionEvent.ACTION_HOVER_MOVE:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_SCROLL: {
- GodotLib.dispatchMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, pressure, tiltX, tiltY);
+ if (shouldDispatchInputToRenderThread()) {
+ mRenderView.queueOnRenderThread(() -> GodotLib.dispatchMouseEvent(eventAction, updatedButtonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, pressure, tiltX, tiltY));
+ } else {
+ GodotLib.dispatchMouseEvent(eventAction, updatedButtonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, pressure, tiltX, tiltY);
+ }
return true;
}
}
return false;
}
- static boolean handleTouchEvent(final MotionEvent event) {
+ boolean handleTouchEvent(final MotionEvent event) {
return handleTouchEvent(event, event.getActionMasked());
}
- static boolean handleTouchEvent(final MotionEvent event, int eventActionOverride) {
+ boolean handleTouchEvent(final MotionEvent event, int eventActionOverride) {
return handleTouchEvent(event, eventActionOverride, false);
}
- static boolean handleTouchEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
+ boolean handleTouchEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
final int pointerCount = event.getPointerCount();
if (pointerCount == 0) {
return true;
@@ -636,10 +661,70 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN: {
- GodotLib.dispatchTouchEvent(eventActionOverride, actionPointerId, pointerCount, positions, doubleTap);
+ if (shouldDispatchInputToRenderThread()) {
+ mRenderView.queueOnRenderThread(() -> GodotLib.dispatchTouchEvent(eventActionOverride, actionPointerId, pointerCount, positions, doubleTap));
+ } else {
+ GodotLib.dispatchTouchEvent(eventActionOverride, actionPointerId, pointerCount, positions, doubleTap);
+ }
return true;
}
}
return false;
}
+
+ void handleMagnifyEvent(float x, float y, float factor) {
+ if (shouldDispatchInputToRenderThread()) {
+ mRenderView.queueOnRenderThread(() -> GodotLib.magnify(x, y, factor));
+ } else {
+ GodotLib.magnify(x, y, factor);
+ }
+ }
+
+ void handlePanEvent(float x, float y, float deltaX, float deltaY) {
+ if (shouldDispatchInputToRenderThread()) {
+ mRenderView.queueOnRenderThread(() -> GodotLib.pan(x, y, deltaX, deltaY));
+ } else {
+ GodotLib.pan(x, y, deltaX, deltaY);
+ }
+ }
+
+ private void handleJoystickButtonEvent(int device, int button, boolean pressed) {
+ if (shouldDispatchInputToRenderThread()) {
+ mRenderView.queueOnRenderThread(() -> GodotLib.joybutton(device, button, pressed));
+ } else {
+ GodotLib.joybutton(device, button, pressed);
+ }
+ }
+
+ private void handleJoystickAxisEvent(int device, int axis, float value) {
+ if (shouldDispatchInputToRenderThread()) {
+ mRenderView.queueOnRenderThread(() -> GodotLib.joyaxis(device, axis, value));
+ } else {
+ GodotLib.joyaxis(device, axis, value);
+ }
+ }
+
+ private void handleJoystickHatEvent(int device, int hatX, int hatY) {
+ if (shouldDispatchInputToRenderThread()) {
+ mRenderView.queueOnRenderThread(() -> GodotLib.joyhat(device, hatX, hatY));
+ } else {
+ GodotLib.joyhat(device, hatX, hatY);
+ }
+ }
+
+ private void handleJoystickConnectionChangedEvent(int device, boolean connected, String name) {
+ if (shouldDispatchInputToRenderThread()) {
+ mRenderView.queueOnRenderThread(() -> GodotLib.joyconnectionchanged(device, connected, name));
+ } else {
+ GodotLib.joyconnectionchanged(device, connected, name);
+ }
+ }
+
+ void handleKeyEvent(int physicalKeycode, int unicode, int keyLabel, boolean pressed, boolean echo) {
+ if (shouldDispatchInputToRenderThread()) {
+ mRenderView.queueOnRenderThread(() -> GodotLib.key(physicalKeycode, unicode, keyLabel, pressed, echo));
+ } else {
+ GodotLib.key(physicalKeycode, unicode, keyLabel, pressed, echo);
+ }
+ }
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
index 06b565c30f..e545669970 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
@@ -93,8 +93,8 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
@Override
public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) {
for (int i = 0; i < count; ++i) {
- GodotLib.key(KeyEvent.KEYCODE_DEL, 0, 0, true, false);
- GodotLib.key(KeyEvent.KEYCODE_DEL, 0, 0, false, false);
+ mRenderView.getInputHandler().handleKeyEvent(KeyEvent.KEYCODE_DEL, 0, 0, true, false);
+ mRenderView.getInputHandler().handleKeyEvent(KeyEvent.KEYCODE_DEL, 0, 0, false, false);
if (mHasSelection) {
mHasSelection = false;
@@ -115,8 +115,8 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
// Return keys are handled through action events
continue;
}
- GodotLib.key(0, character, 0, true, false);
- GodotLib.key(0, character, 0, false, false);
+ mRenderView.getInputHandler().handleKeyEvent(0, character, 0, true, false);
+ mRenderView.getInputHandler().handleKeyEvent(0, character, 0, false, false);
}
}
@@ -127,18 +127,16 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
if (characters != null) {
for (int i = 0; i < characters.length(); i++) {
final int character = characters.codePointAt(i);
- GodotLib.key(0, character, 0, true, false);
- GodotLib.key(0, character, 0, false, false);
+ mRenderView.getInputHandler().handleKeyEvent(0, character, 0, true, false);
+ mRenderView.getInputHandler().handleKeyEvent(0, character, 0, false, false);
}
}
}
if (pActionID == EditorInfo.IME_ACTION_DONE) {
// Enter key has been pressed
- mRenderView.queueOnRenderThread(() -> {
- GodotLib.key(KeyEvent.KEYCODE_ENTER, 0, 0, true, false);
- GodotLib.key(KeyEvent.KEYCODE_ENTER, 0, 0, false, false);
- });
+ mRenderView.getInputHandler().handleKeyEvent(KeyEvent.KEYCODE_ENTER, 0, 0, true, false);
+ mRenderView.getInputHandler().handleKeyEvent(KeyEvent.KEYCODE_ENTER, 0, 0, false, false);
mRenderView.getView().requestFocus();
return true;
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/BenchmarkUtils.kt b/platform/android/java/lib/src/org/godotengine/godot/utils/BenchmarkUtils.kt
index 69748c0a8d..d39f2309b8 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/BenchmarkUtils.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/BenchmarkUtils.kt
@@ -81,7 +81,8 @@ fun beginBenchmarkMeasure(scope: String, label: String) {
*
* * Note: Only enabled on 'editorDev' build variant.
*/
-fun endBenchmarkMeasure(scope: String, label: String) {
+@JvmOverloads
+fun endBenchmarkMeasure(scope: String, label: String, dumpBenchmark: Boolean = false) {
if (BuildConfig.FLAVOR != "editor" || BuildConfig.BUILD_TYPE != "dev") {
return
}
@@ -93,6 +94,10 @@ fun endBenchmarkMeasure(scope: String, label: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Trace.endAsyncSection("[$scope] $label", 0)
}
+
+ if (dumpBenchmark) {
+ dumpBenchmark()
+ }
}
/**
@@ -102,11 +107,11 @@ fun endBenchmarkMeasure(scope: String, label: String) {
* * Note: Only enabled on 'editorDev' build variant.
*/
@JvmOverloads
-fun dumpBenchmark(fileAccessHandler: FileAccessHandler?, filepath: String? = benchmarkFile) {
+fun dumpBenchmark(fileAccessHandler: FileAccessHandler? = null, filepath: String? = benchmarkFile) {
if (BuildConfig.FLAVOR != "editor" || BuildConfig.BUILD_TYPE != "dev") {
return
}
- if (!useBenchmark) {
+ if (!useBenchmark || benchmarkTracker.isEmpty()) {
return
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 8493a8e932..87d4281c5a 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -549,4 +549,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIE
os_android->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_PAUSED);
}
}
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_updateInputDispatchSettings(JNIEnv *env, jclass clazz, jboolean p_use_accumulated_input, jboolean p_use_input_buffering) {
+ if (Input::get_singleton()) {
+ Input::get_singleton()->set_use_accumulated_input(p_use_accumulated_input);
+ Input::get_singleton()->set_use_input_buffering(p_use_input_buffering);
+ }
+}
}
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index f32ffc291a..852c475e7e 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -69,6 +69,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResu
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onNightModeChanged(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIEnv *env, jclass clazz);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_updateInputDispatchSettings(JNIEnv *env, jclass clazz, jboolean p_use_accumulated_input, jboolean p_use_input_buffering);
}
#endif // JAVA_GODOT_LIB_JNI_H
diff --git a/platform/web/web_main.cpp b/platform/web/web_main.cpp
index 04513f6d57..eb61644066 100644
--- a/platform/web/web_main.cpp
+++ b/platform/web/web_main.cpp
@@ -35,6 +35,7 @@
#include "core/config/engine.h"
#include "core/io/resource_loader.h"
#include "main/main.h"
+#include "scene/main/scene_tree.h"
#include <emscripten/emscripten.h>
#include <stdlib.h>
@@ -130,7 +131,7 @@ extern EMSCRIPTEN_KEEPALIVE int godot_web_main(int argc, char *argv[]) {
if (Engine::get_singleton()->is_project_manager_hint() && FileAccess::exists("/tmp/preload.zip")) {
PackedStringArray ps;
ps.push_back("/tmp/preload.zip");
- os->get_main_loop()->emit_signal(SNAME("files_dropped"), ps, -1);
+ SceneTree::get_singleton()->get_root()->emit_signal(SNAME("files_dropped"), ps);
}
#endif
emscripten_set_main_loop(main_loop_callback, -1, false);
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 33756dc1fd..429fb2e64f 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -782,7 +782,9 @@ Rect2 GraphEdit::_compute_shrinked_frame_rect(const GraphFrame *p_frame) {
return Rect2(p_frame->get_position_offset(), Size2());
}
- min_point -= Size2(autoshrink_margin, autoshrink_margin);
+ const Size2 titlebar_size = p_frame->get_titlebar_size();
+
+ min_point -= Size2(autoshrink_margin, MAX(autoshrink_margin, titlebar_size.y));
max_point += Size2(autoshrink_margin, autoshrink_margin);
return Rect2(min_point, max_point - min_point);
diff --git a/scene/gui/graph_frame.cpp b/scene/gui/graph_frame.cpp
index 8cd7dbbeb5..e85d007262 100644
--- a/scene/gui/graph_frame.cpp
+++ b/scene/gui/graph_frame.cpp
@@ -262,6 +262,10 @@ HBoxContainer *GraphFrame::get_titlebar_hbox() {
return titlebar_hbox;
}
+Size2 GraphFrame::get_titlebar_size() const {
+ return titlebar_hbox->get_size() + theme_cache.titlebar->get_minimum_size();
+}
+
void GraphFrame::set_drag_margin(int p_margin) {
drag_margin = p_margin;
}
diff --git a/scene/gui/graph_frame.h b/scene/gui/graph_frame.h
index 21346586c8..2af09cf872 100644
--- a/scene/gui/graph_frame.h
+++ b/scene/gui/graph_frame.h
@@ -89,6 +89,7 @@ public:
int get_autoshrink_margin() const;
HBoxContainer *get_titlebar_hbox();
+ Size2 get_titlebar_size() const;
void set_drag_margin(int p_margin);
int get_drag_margin() const;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index dd3491f62c..70b585d683 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -347,6 +347,22 @@ void _get_tbn_from_axis_angle(const Vector3 &p_axis, float p_angle, Vector3 &r_n
r_normal = tbn.rows[2];
}
+AABB _compute_aabb_from_points(const Vector3 *p_data, int p_length) {
+ if (p_length == 0) {
+ return AABB();
+ }
+
+ Vector3 min = p_data[0];
+ Vector3 max = p_data[0];
+
+ for (int i = 1; i < p_length; ++i) {
+ min = min.min(p_data[i]);
+ max = max.max(p_data[i]);
+ }
+
+ return AABB(min, max - min);
+}
+
Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_normal_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector<uint8_t> &r_vertex_array, Vector<uint8_t> &r_attrib_array, Vector<uint8_t> &r_skin_array, int p_vertex_array_len, Vector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb, Vector4 &r_uv_scale) {
uint8_t *vw = r_vertex_array.ptrw();
uint8_t *aw = r_attrib_array.ptrw();
@@ -440,18 +456,10 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint
const Vector3 *src = array.ptr();
- r_aabb = AABB();
+ r_aabb = _compute_aabb_from_points(src, p_vertex_array_len);
+ r_aabb.size = r_aabb.size.max(SMALL_VEC3);
if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) {
- // First we need to generate the AABB for the entire surface.
- for (int i = 0; i < p_vertex_array_len; i++) {
- if (i == 0) {
- r_aabb = AABB(src[i], SMALL_VEC3);
- } else {
- r_aabb.expand_to(src[i]);
- }
- }
-
if (!(p_format & RS::ARRAY_FORMAT_NORMAL)) {
// Early out if we are only setting vertex positions.
for (int i = 0; i < p_vertex_array_len; i++) {
@@ -592,12 +600,6 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint
float vector[3] = { (float)src[i].x, (float)src[i].y, (float)src[i].z };
memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(float) * 3);
-
- if (i == 0) {
- r_aabb = AABB(src[i], SMALL_VEC3);
- } else {
- r_aabb.expand_to(src[i]);
- }
}
}
}