diff --git a/doc/classes/CameraFeed.xml b/doc/classes/CameraFeed.xml
index 974f6d4a334c..96f393fee3fa 100644
--- a/doc/classes/CameraFeed.xml
+++ b/doc/classes/CameraFeed.xml
@@ -56,6 +56,9 @@
Feed supplies separate Y and CbCr images that need to be combined and converted to RGB.
+
+ Feed external images.
+
Unspecified position.
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 21de46f4fc78..b5a6fbc860f0 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -2475,6 +2475,8 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Refget("xr_features/xr_mode");
if (xr_mode_index == XR_MODE_OPENXR) {
command_line_strings.push_back("--xr_mode_openxr");
+ } else if (xr_mode_index == XR_MODE_ARCORE) {
+ command_line_strings.push_back("--xr_mode_arcore");
} else { // XRMode.REGULAR is the default.
command_line_strings.push_back("--xr_mode_regular");
}
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index 2498394adda1..872ff0314cec 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -60,6 +60,7 @@ static const int APP_CATEGORY_VIDEO = 8;
// This should match the entries in 'platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java'
static const int XR_MODE_REGULAR = 0;
static const int XR_MODE_OPENXR = 1;
+static const int XR_MODE_ARCORE = 2;
struct CustomExportData {
String assets_directory;
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 52350c12a6d3..c06e0e88a597 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
@@ -250,6 +250,7 @@ private void init(XRMode xrMode, boolean translucent, boolean useDebugOpengl) {
break;
case REGULAR:
+ case ARCORE:
default:
/* By default, GLSurfaceView() creates a RGB_565 opaque surface.
* If we want a translucent one, we should change the surface's
diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java b/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java
index 2c2c9f39d649..d020940a5584 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java
@@ -35,7 +35,8 @@
*/
public enum XRMode {
REGULAR(0, "Regular", "--xr_mode_regular", "Default Android Gamepad"), // Regular/flatscreen
- OPENXR(1, "OpenXR", "--xr_mode_openxr", "");
+ OPENXR(1, "OpenXR", "--xr_mode_openxr", ""),
+ ARCORE(2, "AR Core", "--xr_mode_arcore", "Default Android Gamepad");
final int index;
final String label;
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 79ba2528ba79..67840ea5d811 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -331,3 +331,13 @@ void GodotJavaWrapper::dump_benchmark(const String &benchmark_file) {
env->CallVoidMethod(godot_instance, _dump_benchmark, j_benchmark_file);
}
}
+
+int GodotJavaWrapper::get_display_rotation() {
+ if (_get_display_rotation) {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL_V(env, 0);
+ return env->CallIntMethod(godot_instance, _get_display_rotation);
+ } else {
+ return 0;
+ }
+}
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index ba42d5dccd66..e9d8d373bcd8 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -70,6 +70,7 @@ class GodotJavaWrapper {
jmethodID _begin_benchmark_measure = nullptr;
jmethodID _end_benchmark_measure = nullptr;
jmethodID _dump_benchmark = nullptr;
+ jmethodID _get_display_rotation = nullptr;
public:
GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_godot_instance);
@@ -102,6 +103,7 @@ class GodotJavaWrapper {
void begin_benchmark_measure(const String &p_label);
void end_benchmark_measure(const String &p_label);
void dump_benchmark(const String &benchmark_file);
+ int get_display_rotation();
};
#endif // JAVA_GODOT_WRAPPER_H
diff --git a/servers/camera/camera_feed.cpp b/servers/camera/camera_feed.cpp
index 0661ffd576df..b08fa4f446c3 100644
--- a/servers/camera/camera_feed.cpp
+++ b/servers/camera/camera_feed.cpp
@@ -53,6 +53,7 @@ void CameraFeed::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_RGB_img", "rgb_img"), &CameraFeed::set_RGB_img);
ClassDB::bind_method(D_METHOD("_set_YCbCr_img", "ycbcr_img"), &CameraFeed::set_YCbCr_img);
+ ClassDB::bind_method(D_METHOD("_set_external", "external_img"), &CameraFeed::set_external);
ClassDB::bind_method(D_METHOD("get_datatype"), &CameraFeed::get_datatype);
@@ -64,6 +65,7 @@ void CameraFeed::_bind_methods() {
BIND_ENUM_CONSTANT(FEED_RGB);
BIND_ENUM_CONSTANT(FEED_YCBCR);
BIND_ENUM_CONSTANT(FEED_YCBCR_SEP);
+ BIND_ENUM_CONSTANT(FEED_EXTERNAL);
BIND_ENUM_CONSTANT(FEED_UNSPECIFIED);
BIND_ENUM_CONSTANT(FEED_FRONT);
@@ -147,6 +149,7 @@ CameraFeed::CameraFeed() {
transform = Transform2D(1.0, 0.0, 0.0, -1.0, 0.0, 1.0);
texture[CameraServer::FEED_Y_IMAGE] = RenderingServer::get_singleton()->texture_2d_placeholder_create();
texture[CameraServer::FEED_CBCR_IMAGE] = RenderingServer::get_singleton()->texture_2d_placeholder_create();
+ texture[CameraServer::FEED_EXTERNAL] = RenderingServer::get_singleton()->texture_2d_placeholder_create();
}
CameraFeed::CameraFeed(String p_name, FeedPosition p_position) {
@@ -244,6 +247,28 @@ void CameraFeed::set_YCbCr_imgs(const Ref &p_y_img, const Ref &p_c
}
}
+void CameraFeed::set_external(const Ref &p_external_img) {
+ ERR_FAIL_COND(p_external_img.is_null());
+
+ if (active) {
+ int new_external_width = p_external_img->get_width();
+ int new_external_height = p_external_img->get_height();
+
+ if ((base_width != new_external_width) || (base_height != new_external_height)) {
+ // assume that camera image doesn't change formats etc.
+ base_width = new_external_width;
+ base_height = new_external_height;
+
+ {
+ RID new_texture = RenderingServer::get_singleton()->texture_2d_create(p_external_img);
+ RenderingServer::get_singleton()->texture_replace(texture[CameraServer::FEED_EXTERNAL], new_texture);
+ }
+ } else {
+ RenderingServer::get_singleton()->texture_2d_update(texture[CameraServer::FEED_EXTERNAL], p_external_img);
+ }
+ }
+}
+
bool CameraFeed::activate_feed() {
// nothing to do here
return true;
diff --git a/servers/camera/camera_feed.h b/servers/camera/camera_feed.h
index b85a44cfaec1..d40d61d5c995 100644
--- a/servers/camera/camera_feed.h
+++ b/servers/camera/camera_feed.h
@@ -49,7 +49,8 @@ class CameraFeed : public RefCounted {
FEED_NOIMAGE, // we don't have an image yet
FEED_RGB, // our texture will contain a normal RGB texture that can be used directly
FEED_YCBCR, // our texture will contain a YCbCr texture that needs to be converted to RGB before output
- FEED_YCBCR_SEP // our camera is split into two textures, first plane contains Y data, second plane contains CbCr data
+ FEED_YCBCR_SEP, // our camera is split into two textures, first plane contains Y data, second plane contains CbCr data
+ FEED_EXTERNAL // specific for android, camera feed is managed externally, assumed RGB
};
enum FeedPosition {
@@ -101,6 +102,7 @@ class CameraFeed : public RefCounted {
void set_RGB_img(const Ref &p_rgb_img);
void set_YCbCr_img(const Ref &p_ycbcr_img);
void set_YCbCr_imgs(const Ref &p_y_img, const Ref &p_cbcr_img);
+ void set_external(const Ref &p_external_img);
virtual bool activate_feed();
virtual void deactivate_feed();
diff --git a/servers/camera_server.h b/servers/camera_server.h
index 4e0b75fbf618..abdb70565a40 100644
--- a/servers/camera_server.h
+++ b/servers/camera_server.h
@@ -56,7 +56,8 @@ class CameraServer : public Object {
FEED_YCBCR_IMAGE = 0,
FEED_Y_IMAGE = 0,
FEED_CBCR_IMAGE = 1,
- FEED_IMAGES = 2
+ FEED_EXTERNAL = 2,
+ FEED_IMAGES = 3
};
typedef CameraServer *(*CreateFunc)();