mirror of
https://github.com/godotengine/godot.git
synced 2025-11-01 06:01:14 +00:00
Switch to input buffering on Android
Key, touch and joystick events will be passed directly from the UI thread to Godot, so they can benefit from agile input flushing. As another consequence of this new way of passing events, less Java object are created at runtime (`Runnable`), which is good since the garbage collector needs to run less. `AndroidInputHandler` is introduced to have a smaller cross-thread surface. `main_loop_request_go_back()` is removed in favor just inline calling `send_window_event()` at the most caller's convenience (i.e., leveraging the new `p_deferred`` parameter as appropriate). Lastly, `get_mouse_position()` and `get_mouse_button_state()` now just call through `Input` to avoid the need of sync of mouse data tracked on the UI thread.
This commit is contained in:
parent
abdfbef075
commit
e745088f1f
11 changed files with 603 additions and 520 deletions
|
|
@ -34,6 +34,7 @@
|
|||
#include "java_godot_wrapper.h"
|
||||
|
||||
#include "android/asset_manager_jni.h"
|
||||
#include "android_input_handler.h"
|
||||
#include "api/java_class_wrapper.h"
|
||||
#include "api/jni_singleton.h"
|
||||
#include "core/config/engine.h"
|
||||
|
|
@ -56,11 +57,12 @@
|
|||
|
||||
static JavaClassWrapper *java_class_wrapper = nullptr;
|
||||
static OS_Android *os_android = nullptr;
|
||||
static AndroidInputHandler *input_handler = nullptr;
|
||||
static GodotJavaWrapper *godot_java = nullptr;
|
||||
static GodotIOJavaWrapper *godot_io_java = nullptr;
|
||||
|
||||
static bool initialized = false;
|
||||
static int step = 0;
|
||||
static SafeNumeric<int> step; // Shared between UI and render threads
|
||||
|
||||
static Size2 new_size;
|
||||
static Vector3 accelerometer;
|
||||
|
|
@ -111,6 +113,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env
|
|||
if (godot_java) {
|
||||
delete godot_java;
|
||||
}
|
||||
if (input_handler) {
|
||||
delete input_handler;
|
||||
}
|
||||
if (os_android) {
|
||||
delete os_android;
|
||||
}
|
||||
|
|
@ -165,7 +170,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, j
|
|||
os_android->set_display_size(Size2i(p_width, p_height));
|
||||
|
||||
// No need to reset the surface during startup
|
||||
if (step > 0) {
|
||||
if (step.get() > 0) {
|
||||
if (p_surface) {
|
||||
ANativeWindow *native_window = ANativeWindow_fromSurface(env, p_surface);
|
||||
os_android->set_native_window(native_window);
|
||||
|
|
@ -179,7 +184,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, j
|
|||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface, jboolean p_32_bits) {
|
||||
if (os_android) {
|
||||
if (step == 0) {
|
||||
if (step.get() == 0) {
|
||||
// During startup
|
||||
os_android->set_context_is_16_bits(!p_32_bits);
|
||||
if (p_surface) {
|
||||
|
|
@ -188,33 +193,36 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en
|
|||
}
|
||||
} else {
|
||||
// Rendering context recreated because it was lost; restart app to let it reload everything
|
||||
step.set(-1); // Ensure no further steps are attempted and no further events are sent
|
||||
os_android->main_loop_end();
|
||||
godot_java->restart(env);
|
||||
step = -1; // Ensure no further steps are attempted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz) {
|
||||
if (step == 0)
|
||||
if (step.get() == 0)
|
||||
return;
|
||||
|
||||
os_android->main_loop_request_go_back();
|
||||
if (DisplayServerAndroid *dsa = Object::cast_to<DisplayServerAndroid>(DisplayServer::get_singleton())) {
|
||||
dsa->send_window_event(DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz) {
|
||||
if (step == -1)
|
||||
if (step.get() == -1)
|
||||
return;
|
||||
|
||||
if (step == 0) {
|
||||
if (step.get() == 0) {
|
||||
// Since Godot is initialized on the UI thread, main_thread_id was set to that thread's id,
|
||||
// but for Godot purposes, the main thread is the one running the game loop
|
||||
Main::setup2(Thread::get_caller_id());
|
||||
++step;
|
||||
input_handler = new AndroidInputHandler();
|
||||
step.increment();
|
||||
return;
|
||||
}
|
||||
|
||||
if (step == 1) {
|
||||
if (step.get() == 1) {
|
||||
if (!Main::start()) {
|
||||
return; // should exit instead and print the error
|
||||
}
|
||||
|
|
@ -222,7 +230,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl
|
|||
godot_java->on_godot_setup_completed(env);
|
||||
os_android->main_loop_begin();
|
||||
godot_java->on_godot_main_loop_started(env);
|
||||
++step;
|
||||
step.increment();
|
||||
}
|
||||
|
||||
DisplayServerAndroid::get_singleton()->process_accelerometer(accelerometer);
|
||||
|
|
@ -236,91 +244,100 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl
|
|||
}
|
||||
|
||||
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) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
Vector<DisplayServerAndroid::TouchPos> points;
|
||||
Vector<AndroidInputHandler::TouchPos> points;
|
||||
for (int i = 0; i < pointer_count; i++) {
|
||||
jfloat p[3];
|
||||
env->GetFloatArrayRegion(positions, i * 3, 3, p);
|
||||
DisplayServerAndroid::TouchPos tp;
|
||||
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) {
|
||||
DisplayServerAndroid::get_singleton()->process_mouse_event(input_device, ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor);
|
||||
input_handler->process_mouse_event(input_device, ev, buttons_mask, points[0].pos, vertical_factor, horizontal_factor);
|
||||
} else {
|
||||
DisplayServerAndroid::get_singleton()->process_touch(ev, pointer, points);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
DisplayServerAndroid::get_singleton()->process_hover(p_type, Point2(p_x, p_y));
|
||||
input_handler->process_hover(p_type, Point2(p_x, p_y));
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
DisplayServerAndroid::get_singleton()->process_double_tap(p_button_mask, Point2(p_x, p_y));
|
||||
input_handler->process_double_tap(p_button_mask, Point2(p_x, p_y));
|
||||
}
|
||||
|
||||
// Called on the UI thread
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
DisplayServerAndroid::get_singleton()->process_scroll(Point2(p_x, p_y));
|
||||
input_handler->process_scroll(Point2(p_x, p_y));
|
||||
}
|
||||
|
||||
// Called on the UI thread
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
DisplayServerAndroid::JoypadEvent jevent;
|
||||
AndroidInputHandler::JoypadEvent jevent;
|
||||
jevent.device = p_device;
|
||||
jevent.type = DisplayServerAndroid::JOY_EVENT_BUTTON;
|
||||
jevent.type = AndroidInputHandler::JOY_EVENT_BUTTON;
|
||||
jevent.index = p_button;
|
||||
jevent.pressed = p_pressed;
|
||||
|
||||
DisplayServerAndroid::get_singleton()->process_joy_event(jevent);
|
||||
input_handler->process_joy_event(jevent);
|
||||
}
|
||||
|
||||
// Called on the UI thread
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
DisplayServerAndroid::JoypadEvent jevent;
|
||||
AndroidInputHandler::JoypadEvent jevent;
|
||||
jevent.device = p_device;
|
||||
jevent.type = DisplayServerAndroid::JOY_EVENT_AXIS;
|
||||
jevent.type = AndroidInputHandler::JOY_EVENT_AXIS;
|
||||
jevent.index = p_axis;
|
||||
jevent.value = p_value;
|
||||
|
||||
DisplayServerAndroid::get_singleton()->process_joy_event(jevent);
|
||||
input_handler->process_joy_event(jevent);
|
||||
}
|
||||
|
||||
// Called on the UI thread
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
DisplayServerAndroid::JoypadEvent jevent;
|
||||
AndroidInputHandler::JoypadEvent jevent;
|
||||
jevent.device = p_device;
|
||||
jevent.type = DisplayServerAndroid::JOY_EVENT_HAT;
|
||||
jevent.type = AndroidInputHandler::JOY_EVENT_HAT;
|
||||
int hat = 0;
|
||||
if (p_hat_x != 0) {
|
||||
if (p_hat_x < 0)
|
||||
|
|
@ -336,9 +353,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j
|
|||
}
|
||||
jevent.hat = hat;
|
||||
|
||||
DisplayServerAndroid::get_singleton()->process_joy_event(jevent);
|
||||
input_handler->process_joy_event(jevent);
|
||||
}
|
||||
|
||||
// Called on the UI thread
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jclass clazz, jint p_device, jboolean p_connected, jstring p_name) {
|
||||
if (os_android) {
|
||||
String name = jstring_to_string(p_name, env);
|
||||
|
|
@ -346,11 +364,12 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(
|
|||
}
|
||||
}
|
||||
|
||||
// Called on the UI thread
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
DisplayServerAndroid::get_singleton()->process_key_event(p_keycode, p_scancode, p_unicode_char, p_pressed);
|
||||
input_handler->process_key_event(p_keycode, p_scancode, p_unicode_char, p_pressed);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) {
|
||||
|
|
@ -370,14 +389,14 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env
|
|||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jclass clazz) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
os_android->main_loop_focusin();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, jclass clazz) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
os_android->main_loop_focusout();
|
||||
|
|
@ -456,7 +475,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResu
|
|||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
if (os_android->get_main_loop()) {
|
||||
|
|
@ -465,7 +484,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNI
|
|||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIEnv *env, jclass clazz) {
|
||||
if (step == 0)
|
||||
if (step.get() <= 0)
|
||||
return;
|
||||
|
||||
if (os_android->get_main_loop()) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue