diff --git a/docs/make_rst.py b/docs/make_rst.py
index dc2b0309..b345aba2 100755
--- a/docs/make_rst.py
+++ b/docs/make_rst.py
@@ -66,6 +66,8 @@
STYLES: Dict[str, str] = {}
SKIP_CLASSES: List[str] = [
+ "AndroidEditorExportPlugin",
+ "AndroidEditorPlugin",
"KhronosEditorExportPlugin",
"KhronosEditorPlugin",
"LynxEditorPlugin",
diff --git a/plugin/build.gradle b/plugin/build.gradle
index e4ebf618..3aad954e 100644
--- a/plugin/build.gradle
+++ b/plugin/build.gradle
@@ -36,6 +36,18 @@ android {
flavorDimensions = ["vendor"]
productFlavors {
+ android {
+ dimension "vendor"
+ ndk {
+ //noinspection ChromeOsAbiSupport
+ abiFilters 'arm64-v8a', 'x86_64'
+ }
+ externalNativeBuild {
+ cmake {
+ arguments "-DFLAVOR=android"
+ }
+ }
+ }
khronos {
dimension "vendor"
ndk {
@@ -100,6 +112,11 @@ android {
}
publishing {
+ singleVariant("androidRelease") {
+ withSourcesJar()
+ withJavadocJar()
+ }
+
singleVariant("khronosRelease") {
withSourcesJar()
withJavadocJar()
@@ -141,6 +158,9 @@ android {
dependencies {
compileOnly libraries.godotAndroidLib
+ // AndroidXR dependencies
+ androidImplementation "org.khronos.openxr:openxr_loader_for_android:$versions.openxrVersion"
+
// Khronos dependencies
khronosImplementation "org.khronos.openxr:openxr_loader_for_android:$versions.openxrVersion"
diff --git a/plugin/src/android/AndroidManifest.xml b/plugin/src/android/AndroidManifest.xml
new file mode 100644
index 00000000..ea9076de
--- /dev/null
+++ b/plugin/src/android/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugin/src/android/android.cmake b/plugin/src/android/android.cmake
new file mode 100644
index 00000000..3795bbe9
--- /dev/null
+++ b/plugin/src/android/android.cmake
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.22.1)
+
+## Android OpenXR loader library
+find_package(OpenXR REQUIRED CONFIG)
+
+set(VENDOR_HEADERS_DIR "")
+set(OPENXR_LOADER "OpenXR::openxr_loader")
+
+## Setup the project sources
+file(GLOB_RECURSE ANDROID_SOURCES ${CMAKE_CURRENT_LIST_DIR}/cpp/*.c**)
+file(GLOB_RECURSE ANDROID_HEADERS ${CMAKE_CURRENT_LIST_DIR}/cpp/*.h**)
+
+add_definitions(-DANDROID_VENDOR_ENABLED)
diff --git a/plugin/src/android/java/org/godotengine/openxr/vendors/android/GodotOpenXRAndroid.kt b/plugin/src/android/java/org/godotengine/openxr/vendors/android/GodotOpenXRAndroid.kt
new file mode 100644
index 00000000..fa8b6b3a
--- /dev/null
+++ b/plugin/src/android/java/org/godotengine/openxr/vendors/android/GodotOpenXRAndroid.kt
@@ -0,0 +1,108 @@
+/**************************************************************************/
+/* GodotOpenXRAndroid.kt */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT XR */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2022-present Godot XR contributors (see CONTRIBUTORS.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.openxr.vendors.android
+
+import org.godotengine.godot.Godot
+import org.godotengine.godot.utils.PermissionsUtil
+import org.godotengine.openxr.vendors.GodotOpenXR
+
+/**
+ * Godot OpenXR plugin for the Android XR platform.
+ */
+class GodotOpenXRAndroid(godot: Godot?) : GodotOpenXR(godot) {
+ companion object {
+ /**
+ * Representing the user's eye pose and orientation, for the purposes of avatars
+ */
+ private const val EYE_TRACKING_PERMISSION = "android.permission.EYE_TRACKING"
+
+ /**
+ * Eye gaze input and interactions
+ */
+ private const val EYE_TRACKING_FINE_PERMISSION = "android.permission.EYE_TRACKING_FINE"
+
+ /**
+ * Tracking and rendering facial expressions
+ */
+ private const val FACE_TRACKING_PERMISSION = "android.permission.FACE_TRACKING"
+
+ /**
+ * Tracking hand joint poses and angular and linear velocities; Using a mesh representation of the user's hands
+ */
+ private const val HAND_TRACKING_PERMISSION = "android.permission.HAND_TRACKING"
+
+ /**
+ * - Light estimation
+ * - projecting passthrough onto mesh surfaces
+ * - performing raycasts against trackables in the environment
+ * - plane tracking
+ * - object tracking
+ * - working with depth for occlusion and hit testing
+ * - persistent anchors
+ */
+ private const val SCENE_UNDERSTANDING_PERMISSION = "android.permission.SCENE_UNDERSTANDING"
+
+ private val ANDROID_XR_PERMISSIONS_LIST = listOf(
+ EYE_TRACKING_PERMISSION,
+ EYE_TRACKING_FINE_PERMISSION,
+ FACE_TRACKING_PERMISSION,
+ HAND_TRACKING_PERMISSION,
+ SCENE_UNDERSTANDING_PERMISSION,
+ )
+ }
+ override fun getPluginName() = "GodotOpenXRAndroid"
+
+ override fun getPluginPermissionsToEnable(): MutableList {
+ val permissionsToEnable = super.getPluginPermissionsToEnable()
+
+ // Go through the list of permissions, and request the ones that are included in the
+ // manifest.
+ for (permission in ANDROID_XR_PERMISSIONS_LIST) {
+ if (PermissionsUtil.hasManifestPermission(activity, permission)) {
+ permissionsToEnable.add(permission)
+ }
+ }
+ return permissionsToEnable
+ }
+
+ override fun supportsFeature(featureTag: String): Boolean {
+ if ("PERMISSION_XR_EXT_eye_gaze_interaction" == featureTag) {
+ val grantedPermissions = godot?.getGrantedPermissions()
+ if (grantedPermissions != null) {
+ for (permission in grantedPermissions) {
+ if (EYE_TRACKING_FINE_PERMISSION == permission) {
+ return true
+ }
+ }
+ }
+ }
+ return false
+ }
+}
diff --git a/plugin/src/main/cpp/export/android_export_plugin.cpp b/plugin/src/main/cpp/export/android_export_plugin.cpp
new file mode 100644
index 00000000..891ad70f
--- /dev/null
+++ b/plugin/src/main/cpp/export/android_export_plugin.cpp
@@ -0,0 +1,204 @@
+/**************************************************************************/
+/* android_export_plugin.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT XR */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2022-present Godot XR contributors (see CONTRIBUTORS.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. */
+/**************************************************************************/
+
+#include "export/android_export_plugin.h"
+
+#include
+
+using namespace godot;
+
+void AndroidEditorPlugin::_bind_methods() {}
+
+void AndroidEditorPlugin::_enter_tree() {
+ // Initialize the editor export plugin
+ android_export_plugin.instantiate();
+ add_export_plugin(android_export_plugin);
+}
+
+void AndroidEditorPlugin::_exit_tree() {
+ // Clean up the editor export plugin
+ remove_export_plugin(android_export_plugin);
+ android_export_plugin.unref();
+}
+
+AndroidEditorExportPlugin::AndroidEditorExportPlugin() {
+ set_vendor_name(ANDROID_VENDOR_NAME);
+
+ _eye_tracking_option = _generate_export_option(
+ "android_xr_features/eye_tracking",
+ "",
+ Variant::Type::INT,
+ PROPERTY_HINT_ENUM,
+ "None,Optional,Required",
+ PROPERTY_USAGE_DEFAULT,
+ EYE_TRACKING_NONE_VALUE,
+ false);
+ _hand_tracking_option = _generate_export_option(
+ "android_xr_features/hand_tracking",
+ "",
+ Variant::Type::INT,
+ PROPERTY_HINT_ENUM,
+ "None,Optional,Required",
+ PROPERTY_USAGE_DEFAULT,
+ HAND_TRACKING_NONE_VALUE,
+ false);
+}
+
+void AndroidEditorExportPlugin::_bind_methods() {}
+
+TypedArray AndroidEditorExportPlugin::_get_export_options(const Ref &platform) const {
+ TypedArray export_options;
+ if (!_supports_platform(platform)) {
+ return export_options;
+ }
+
+ export_options.append(_get_vendor_toggle_option());
+ export_options.append(_eye_tracking_option);
+ export_options.append(_hand_tracking_option);
+
+ return export_options;
+}
+
+Dictionary AndroidEditorExportPlugin::_get_export_options_overrides(const Ref &p_platform) const {
+ Dictionary overrides;
+ if (!_supports_platform(p_platform)) {
+ return overrides;
+ }
+
+ if (!_is_vendor_plugin_enabled()) {
+ overrides["android_xr_features/eye_tracking"] = EYE_TRACKING_NONE_VALUE;
+ overrides["android_xr_features/hand_tracking"] = HAND_TRACKING_NONE_VALUE;
+ }
+
+ return overrides;
+}
+
+bool AndroidEditorExportPlugin::_is_eye_tracking_enabled() const {
+ bool eye_tracking_project_setting_enabled = ProjectSettings::get_singleton()->get_setting_with_override("xr/openxr/extensions/eye_gaze_interaction");
+ if (!eye_tracking_project_setting_enabled) {
+ return false;
+ }
+
+ int eye_tracking_option_value = _get_int_option("android_xr_features/eye_tracking", EYE_TRACKING_NONE_VALUE);
+ return eye_tracking_option_value > EYE_TRACKING_NONE_VALUE;
+}
+
+PackedStringArray AndroidEditorExportPlugin::_get_export_features(const Ref &platform, bool debug) const {
+ PackedStringArray features;
+ if (!_supports_platform(platform) || !_is_vendor_plugin_enabled()) {
+ return features;
+ }
+
+ // Add the eye tracking feature if necessary
+ if (_is_eye_tracking_enabled()) {
+ features.append(EYE_GAZE_INTERACTION_FEATURE);
+ }
+
+ return features;
+}
+
+String AndroidEditorExportPlugin::_get_export_option_warning(const Ref &platform, const String &option) const {
+ if (!_supports_platform(platform) || !_is_vendor_plugin_enabled()) {
+ return "";
+ }
+
+ bool openxr_enabled = _is_openxr_enabled();
+ if (option == "android_xr_features/eye_tracking") {
+ bool eye_tracking_project_setting_enabled = ProjectSettings::get_singleton()->get_setting_with_override("xr/openxr/extensions/eye_gaze_interaction");
+ int eye_tracking_option_value = _get_int_option("android_xr_features/eye_tracking", EYE_TRACKING_NONE_VALUE);
+ if (eye_tracking_option_value > EYE_TRACKING_NONE_VALUE && !eye_tracking_project_setting_enabled) {
+ return "\"Eye Tracking\" project setting must be enabled!\n";
+ }
+ } else if (option == "android_xr_features/hand_tracking") {
+ if (!openxr_enabled && _get_int_option(option, HAND_TRACKING_NONE_VALUE) > HAND_TRACKING_NONE_VALUE) {
+ return "\"Hand Tracking\" requires \"XR Mode\" to be \"OpenXR\".\n";
+ }
+ }
+
+ return OpenXREditorExportPlugin::_get_export_option_warning(platform, option);
+}
+
+String AndroidEditorExportPlugin::_get_android_manifest_activity_element_contents(const Ref &platform, bool debug) const {
+ if (!_supports_platform(platform) || !_is_vendor_plugin_enabled()) {
+ return "";
+ }
+
+ return R"(
+
+
+
+
+
+
+
+
+)";
+}
+
+String AndroidEditorExportPlugin::_get_android_manifest_element_contents(const Ref &platform, bool debug) const {
+ String contents;
+ if (!_supports_platform(platform) || !_is_vendor_plugin_enabled()) {
+ return contents;
+ }
+
+ // Android XR required
+ contents += " \n";
+
+ // 6DoF motion controllers required
+ contents += " \n";
+
+ // Check for eye tracking
+ if (_is_eye_tracking_enabled()) {
+ contents += " \n";
+
+ int eye_tracking_value = _get_int_option("android_xr_features/eye_tracking", EYE_TRACKING_NONE_VALUE);
+ if (eye_tracking_value == EYE_TRACKING_OPTIONAL_VALUE) {
+ contents += " \n";
+ } else if (eye_tracking_value == EYE_TRACKING_REQUIRED_VALUE) {
+ contents += " \n";
+ }
+ }
+
+ // Check for hand tracking
+ int hand_tracking_value = _get_int_option("android_xr_features/hand_tracking", HAND_TRACKING_NONE_VALUE);
+ if (hand_tracking_value > HAND_TRACKING_NONE_VALUE) {
+ contents += " \n";
+
+ if (hand_tracking_value == HAND_TRACKING_OPTIONAL_VALUE) {
+ contents += " \n";
+ } else if (hand_tracking_value == HAND_TRACKING_REQUIRED_VALUE) {
+ contents += " \n";
+ }
+ }
+
+ return contents;
+}
diff --git a/plugin/src/main/cpp/export/export_plugin.cpp b/plugin/src/main/cpp/export/export_plugin.cpp
index 6fa620be..81dffe82 100644
--- a/plugin/src/main/cpp/export/export_plugin.cpp
+++ b/plugin/src/main/cpp/export/export_plugin.cpp
@@ -87,7 +87,7 @@ Dictionary OpenXREditorExportPlugin::_get_vendor_toggle_option(const String &ven
"",
PROPERTY_USAGE_DEFAULT,
false,
- false);
+ true);
}
bool OpenXREditorExportPlugin::_is_openxr_enabled() const {
diff --git a/plugin/src/main/cpp/export/pico_export_plugin.cpp b/plugin/src/main/cpp/export/pico_export_plugin.cpp
index f8efc53b..2f741c11 100644
--- a/plugin/src/main/cpp/export/pico_export_plugin.cpp
+++ b/plugin/src/main/cpp/export/pico_export_plugin.cpp
@@ -58,7 +58,7 @@ PicoEditorExportPlugin::PicoEditorExportPlugin() {
PROPERTY_HINT_ENUM,
"No,Yes",
PROPERTY_USAGE_DEFAULT,
- pico::MANIFEST_FALSE_VALUE,
+ MANIFEST_FALSE_VALUE,
false);
_face_tracking_option = _generate_export_option(
@@ -68,7 +68,7 @@ PicoEditorExportPlugin::PicoEditorExportPlugin() {
PROPERTY_HINT_ENUM,
"No,Face only,Lipsync only,Hybrid",
PROPERTY_USAGE_DEFAULT,
- pico::FACE_TRACKING_NONE_VALUE,
+ FACE_TRACKING_NONE_VALUE,
false);
_hand_tracking_option = _generate_export_option(
@@ -78,7 +78,7 @@ PicoEditorExportPlugin::PicoEditorExportPlugin() {
PROPERTY_HINT_ENUM,
"No,Low frequency,High frequency (60Hz)",
PROPERTY_USAGE_DEFAULT,
- pico::HAND_TRACKING_NONE_VALUE,
+ HAND_TRACKING_NONE_VALUE,
false);
}
@@ -104,8 +104,8 @@ bool PicoEditorExportPlugin::_is_eye_tracking_enabled() const {
return false;
}
- int eye_tracking_option_value = _get_int_option("pico_xr_features/eye_tracking", pico::MANIFEST_FALSE_VALUE);
- return eye_tracking_option_value == pico::MANIFEST_TRUE_VALUE;
+ int eye_tracking_option_value = _get_int_option("pico_xr_features/eye_tracking", MANIFEST_FALSE_VALUE);
+ return eye_tracking_option_value == MANIFEST_TRUE_VALUE;
}
PackedStringArray PicoEditorExportPlugin::_get_export_features(const Ref &platform, bool debug) const {
@@ -129,24 +129,24 @@ String PicoEditorExportPlugin::_get_export_option_warning(const Ref pico::FACE_TRACKING_NONE_VALUE) {
+ int face_tracking = _get_int_option(option, FACE_TRACKING_NONE_VALUE);
+ if (!openxr_enabled && face_tracking > FACE_TRACKING_NONE_VALUE) {
return "\"Face tracking\" requires \"XR Mode\" to be \"OpenXR\".\n";
}
bool record_audio = _get_bool_option("permissions/record_audio");
- if (!record_audio && face_tracking == pico::FACE_TRACKING_LIPSYNCONLY_VALUE) {
+ if (!record_audio && face_tracking == FACE_TRACKING_LIPSYNCONLY_VALUE) {
return "\"Lipsync face tracking\" requires \"Record Audio\" to be checked.\n";
}
- if (!record_audio && face_tracking == pico::FACE_TRACKING_HYBRID_VALUE) {
+ if (!record_audio && face_tracking == FACE_TRACKING_HYBRID_VALUE) {
return "\"Hybrid face tracking\" requires \"Record Audio\" to be checked.\n";
}
} else if (option == "pico_xr_features/hand_tracking") {
- int hand_tracking = _get_int_option(option, pico::HAND_TRACKING_NONE_VALUE);
- if (!openxr_enabled && hand_tracking > pico::HAND_TRACKING_NONE_VALUE) {
+ int hand_tracking = _get_int_option(option, HAND_TRACKING_NONE_VALUE);
+ if (!openxr_enabled && hand_tracking > HAND_TRACKING_NONE_VALUE) {
return "\"Hand tracking\" requires \"XR Mode\" to be \"OpenXR\".\n";
}
}
@@ -166,8 +166,8 @@ String PicoEditorExportPlugin::_get_android_manifest_element_contents(const Ref<
}
// Face tracking
- int face_tracking = _get_int_option("pico_xr_features/face_tracking", pico::FACE_TRACKING_NONE_VALUE);
- if (face_tracking == pico::FACE_TRACKING_FACEONLY_VALUE || face_tracking == pico::FACE_TRACKING_HYBRID_VALUE) {
+ int face_tracking = _get_int_option("pico_xr_features/face_tracking", FACE_TRACKING_NONE_VALUE);
+ if (face_tracking == FACE_TRACKING_FACEONLY_VALUE || face_tracking == FACE_TRACKING_HYBRID_VALUE) {
contents += " \n";
}
@@ -186,17 +186,17 @@ String PicoEditorExportPlugin::_get_android_manifest_application_element_content
}
// Face tracking
- int face_tracking = _get_int_option("pico_xr_features/face_tracking", pico::FACE_TRACKING_NONE_VALUE);
- if (face_tracking > pico::FACE_TRACKING_NONE_VALUE) {
+ int face_tracking = _get_int_option("pico_xr_features/face_tracking", FACE_TRACKING_NONE_VALUE);
+ if (face_tracking > FACE_TRACKING_NONE_VALUE) {
contents += " \n";
}
//Hand tracking
- int hand_tracking = _get_int_option("pico_xr_features/hand_tracking", pico::HAND_TRACKING_NONE_VALUE);
- if (hand_tracking > pico::HAND_TRACKING_NONE_VALUE) {
+ int hand_tracking = _get_int_option("pico_xr_features/hand_tracking", HAND_TRACKING_NONE_VALUE);
+ if (hand_tracking > HAND_TRACKING_NONE_VALUE) {
contents += " \n";
}
- if (hand_tracking > pico::HAND_TRACKING_LOWFREQUENCY_VALUE) {
+ if (hand_tracking > HAND_TRACKING_LOWFREQUENCY_VALUE) {
contents += " \n";
}
diff --git a/plugin/src/main/cpp/include/export/android_export_plugin.h b/plugin/src/main/cpp/include/export/android_export_plugin.h
new file mode 100644
index 00000000..7816c1d8
--- /dev/null
+++ b/plugin/src/main/cpp/include/export/android_export_plugin.h
@@ -0,0 +1,85 @@
+/**************************************************************************/
+/* android_export_plugin.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT XR */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2022-present Godot XR contributors (see CONTRIBUTORS.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. */
+/**************************************************************************/
+
+#pragma once
+
+#include
+
+#include "export_plugin.h"
+
+using namespace godot;
+
+class AndroidEditorExportPlugin : public OpenXREditorExportPlugin {
+ GDCLASS(AndroidEditorExportPlugin, OpenXREditorExportPlugin)
+
+ static const int EYE_TRACKING_NONE_VALUE = 0;
+ static const int EYE_TRACKING_OPTIONAL_VALUE = 1;
+ static const int EYE_TRACKING_REQUIRED_VALUE = 2;
+
+ static const int HAND_TRACKING_NONE_VALUE = 0;
+ static const int HAND_TRACKING_OPTIONAL_VALUE = 1;
+ static const int HAND_TRACKING_REQUIRED_VALUE = 2;
+
+public:
+ AndroidEditorExportPlugin();
+
+ TypedArray _get_export_options(const Ref &platform) const override;
+
+ Dictionary _get_export_options_overrides(const Ref &p_platform) const override;
+
+ PackedStringArray _get_export_features(const Ref &platform, bool debug) const override;
+
+ String _get_export_option_warning(const Ref &platform, const String &option) const override;
+
+ String _get_android_manifest_activity_element_contents(const Ref &platform, bool debug) const override;
+ String _get_android_manifest_element_contents(const Ref &platform, bool debug) const override;
+
+protected:
+ static void _bind_methods();
+
+ Dictionary _eye_tracking_option;
+ Dictionary _hand_tracking_option;
+
+private:
+ bool _is_eye_tracking_enabled() const;
+};
+
+class AndroidEditorPlugin : public EditorPlugin {
+ GDCLASS(AndroidEditorPlugin, EditorPlugin)
+
+public:
+ void _enter_tree() override;
+ void _exit_tree() override;
+
+protected:
+ static void _bind_methods();
+
+private:
+ Ref android_export_plugin;
+};
diff --git a/plugin/src/main/cpp/include/export/export_plugin.h b/plugin/src/main/cpp/include/export/export_plugin.h
index 5458fb4b..7e13ad2d 100644
--- a/plugin/src/main/cpp/include/export/export_plugin.h
+++ b/plugin/src/main/cpp/include/export/export_plugin.h
@@ -45,6 +45,7 @@ static const char *PICO_VENDOR_NAME = "pico";
static const char *LYNX_VENDOR_NAME = "lynx";
static const char *KHRONOS_VENDOR_NAME = "khronos";
static const char *MAGICLEAP_VENDOR_NAME = "magicleap";
+static const char *ANDROID_VENDOR_NAME = "android";
static const char *VENDORS_LIST[] = {
META_VENDOR_NAME,
@@ -52,6 +53,7 @@ static const char *VENDORS_LIST[] = {
LYNX_VENDOR_NAME,
KHRONOS_VENDOR_NAME,
MAGICLEAP_VENDOR_NAME,
+ ANDROID_VENDOR_NAME,
};
// Set of custom feature tags supported by the plugin
diff --git a/plugin/src/main/cpp/include/export/meta_export_plugin.h b/plugin/src/main/cpp/include/export/meta_export_plugin.h
index df971802..1a8d814e 100644
--- a/plugin/src/main/cpp/include/export/meta_export_plugin.h
+++ b/plugin/src/main/cpp/include/export/meta_export_plugin.h
@@ -35,40 +35,38 @@
using namespace godot;
-namespace {
-static const int EYE_TRACKING_NONE_VALUE = 0;
-static const int EYE_TRACKING_OPTIONAL_VALUE = 1;
-static const int EYE_TRACKING_REQUIRED_VALUE = 2;
+class MetaEditorExportPlugin : public OpenXREditorExportPlugin {
+ GDCLASS(MetaEditorExportPlugin, OpenXREditorExportPlugin)
-static const int FACE_TRACKING_NONE_VALUE = 0;
-static const int FACE_TRACKING_OPTIONAL_VALUE = 1;
-static const int FACE_TRACKING_REQUIRED_VALUE = 2;
+ static const int EYE_TRACKING_NONE_VALUE = 0;
+ static const int EYE_TRACKING_OPTIONAL_VALUE = 1;
+ static const int EYE_TRACKING_REQUIRED_VALUE = 2;
-static const int BODY_TRACKING_NONE_VALUE = 0;
-static const int BODY_TRACKING_OPTIONAL_VALUE = 1;
-static const int BODY_TRACKING_REQUIRED_VALUE = 2;
+ static const int FACE_TRACKING_NONE_VALUE = 0;
+ static const int FACE_TRACKING_OPTIONAL_VALUE = 1;
+ static const int FACE_TRACKING_REQUIRED_VALUE = 2;
-static const int PASSTHROUGH_NONE_VALUE = 0;
-static const int PASSTHROUGH_OPTIONAL_VALUE = 1;
-static const int PASSTHROUGH_REQUIRED_VALUE = 2;
+ static const int BODY_TRACKING_NONE_VALUE = 0;
+ static const int BODY_TRACKING_OPTIONAL_VALUE = 1;
+ static const int BODY_TRACKING_REQUIRED_VALUE = 2;
-static const int RENDER_MODEL_NONE_VALUE = 0;
-static const int RENDER_MODEL_OPTIONAL_VALUE = 1;
-static const int RENDER_MODEL_REQUIRED_VALUE = 2;
+ static const int PASSTHROUGH_NONE_VALUE = 0;
+ static const int PASSTHROUGH_OPTIONAL_VALUE = 1;
+ static const int PASSTHROUGH_REQUIRED_VALUE = 2;
-static const int HAND_TRACKING_NONE_VALUE = 0;
-static const int HAND_TRACKING_OPTIONAL_VALUE = 1;
-static const int HAND_TRACKING_REQUIRED_VALUE = 2;
+ static const int RENDER_MODEL_NONE_VALUE = 0;
+ static const int RENDER_MODEL_OPTIONAL_VALUE = 1;
+ static const int RENDER_MODEL_REQUIRED_VALUE = 2;
-static const int HAND_TRACKING_FREQUENCY_LOW_VALUE = 0;
-static const int HAND_TRACKING_FREQUENCY_HIGH_VALUE = 1;
+ static const int HAND_TRACKING_NONE_VALUE = 0;
+ static const int HAND_TRACKING_OPTIONAL_VALUE = 1;
+ static const int HAND_TRACKING_REQUIRED_VALUE = 2;
-static const int BOUNDARY_ENABLED_VALUE = 0;
-static const int BOUNDARY_DISABLED_VALUE = 1;
-} // namespace
+ static const int HAND_TRACKING_FREQUENCY_LOW_VALUE = 0;
+ static const int HAND_TRACKING_FREQUENCY_HIGH_VALUE = 1;
-class MetaEditorExportPlugin : public OpenXREditorExportPlugin {
- GDCLASS(MetaEditorExportPlugin, OpenXREditorExportPlugin)
+ static const int BOUNDARY_ENABLED_VALUE = 0;
+ static const int BOUNDARY_DISABLED_VALUE = 1;
public:
MetaEditorExportPlugin();
diff --git a/plugin/src/main/cpp/include/export/pico_export_plugin.h b/plugin/src/main/cpp/include/export/pico_export_plugin.h
index 6bd332f6..55bfb060 100644
--- a/plugin/src/main/cpp/include/export/pico_export_plugin.h
+++ b/plugin/src/main/cpp/include/export/pico_export_plugin.h
@@ -35,22 +35,20 @@
using namespace godot;
-namespace pico {
-static const int MANIFEST_FALSE_VALUE = 0;
-static const int MANIFEST_TRUE_VALUE = 1;
+class PicoEditorExportPlugin : public OpenXREditorExportPlugin {
+ GDCLASS(PicoEditorExportPlugin, OpenXREditorExportPlugin)
-static const int FACE_TRACKING_NONE_VALUE = 0;
-static const int FACE_TRACKING_FACEONLY_VALUE = 1;
-static const int FACE_TRACKING_LIPSYNCONLY_VALUE = 2;
-static const int FACE_TRACKING_HYBRID_VALUE = 3;
+ static const int MANIFEST_FALSE_VALUE = 0;
+ static const int MANIFEST_TRUE_VALUE = 1;
-static const int HAND_TRACKING_NONE_VALUE = 0;
-static const int HAND_TRACKING_LOWFREQUENCY_VALUE = 1;
-static const int HAND_TRACKING_HIGHFREQUENCY_VALUE = 2;
-} //namespace pico
+ static const int FACE_TRACKING_NONE_VALUE = 0;
+ static const int FACE_TRACKING_FACEONLY_VALUE = 1;
+ static const int FACE_TRACKING_LIPSYNCONLY_VALUE = 2;
+ static const int FACE_TRACKING_HYBRID_VALUE = 3;
-class PicoEditorExportPlugin : public OpenXREditorExportPlugin {
- GDCLASS(PicoEditorExportPlugin, OpenXREditorExportPlugin)
+ static const int HAND_TRACKING_NONE_VALUE = 0;
+ static const int HAND_TRACKING_LOWFREQUENCY_VALUE = 1;
+ static const int HAND_TRACKING_HIGHFREQUENCY_VALUE = 2;
public:
PicoEditorExportPlugin();
diff --git a/plugin/src/main/cpp/register_types.cpp b/plugin/src/main/cpp/register_types.cpp
index 6c7075e3..90cbf11d 100644
--- a/plugin/src/main/cpp/register_types.cpp
+++ b/plugin/src/main/cpp/register_types.cpp
@@ -38,6 +38,7 @@
#include
#include
+#include "export/android_export_plugin.h"
#include "export/export_plugin.h"
#include "export/khronos_export_plugin.h"
#include "export/lynx_export_plugin.h"
@@ -189,6 +190,10 @@ void initialize_plugin_module(ModuleInitializationLevel p_level) {
case MODULE_INITIALIZATION_LEVEL_EDITOR: {
ClassDB::register_class();
+ ClassDB::register_class();
+ ClassDB::register_class();
+ EditorPlugins::add_by_type();
+
ClassDB::register_class();
ClassDB::register_class();
EditorPlugins::add_by_type();