Sfoglia il codice sorgente

Add support for generating a Oculus Mobile VR apk with hand tracking support.

fhuya 5 anni fa
parent
commit
5b9631563c
1 ha cambiato i file con 155 aggiunte e 115 eliminazioni
  1. 155 115
      platform/android/export/export.cpp

+ 155 - 115
platform/android/export/export.cpp

@@ -680,7 +680,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
 		bool screen_support_large = p_preset->get("screen/support_large");
 		bool screen_support_xlarge = p_preset->get("screen/support_xlarge");
 
-		int xr_mode_index = p_preset->get("graphics/xr_mode");
+		int xr_mode_index = p_preset->get("xr_features/xr_mode");
 
 		Vector<String> perms;
 
@@ -859,135 +859,174 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
 					uint32_t name = decode_uint32(&p_manifest[iofs + 12]);
 					String tname = string_table[name];
 
-					int dof_index = p_preset->get("graphics/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof
+					if (tname == "uses-feature") {
+						Vector<String> feature_names;
+						Vector<bool> feature_required_list;
+						Vector<int> feature_versions;
 
-					if (tname == "uses-feature" && dof_index > 0) {
-						if (xr_mode_index == 0) {
-							WARN_PRINT("VR DOF feature setting is only valid for oculus HMDs with an XR mode set to VR");
+						if (xr_mode_index == 1 /* XRMode.OVR */) {
+							// Check for degrees of freedom
+							int dof_index = p_preset->get("xr_features/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof
+
+							if (dof_index > 0) {
+								feature_names.push_back("android.hardware.vr.headtracking");
+								feature_required_list.push_back(dof_index == 2);
+								feature_versions.push_back(1);
+							}
+
+							// Check for hand tracking
+							int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
+							if (hand_tracking_index > 0) {
+								feature_names.push_back("oculus.software.handtracking");
+								feature_required_list.push_back(hand_tracking_index == 2);
+								feature_versions.push_back(-1); // no version attribute should be added.
+
+								if (perms.find("oculus.permission.handtracking") == -1) {
+									perms.push_back("oculus.permission.handtracking");
+								}
+							}
 						}
-						ofs += 24; // skip over end tag
 
-						// save manifest ending so we can restore it
-						Vector<uint8_t> manifest_end;
-						uint32_t manifest_cur_size = p_manifest.size();
+						if (feature_names.size() > 0) {
+							ofs += 24; // skip over end tag
 
-						manifest_end.resize(p_manifest.size() - ofs);
-						memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size());
+							// save manifest ending so we can restore it
+							Vector<uint8_t> manifest_end;
+							uint32_t manifest_cur_size = p_manifest.size();
 
-						int32_t attr_name_string = string_table.find("name");
-						ERR_FAIL_COND_MSG(attr_name_string == -1, "Template does not have 'name' attribute.");
+							manifest_end.resize(p_manifest.size() - ofs);
+							memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size());
 
-						int32_t ns_android_string = string_table.find("http://schemas.android.com/apk/res/android");
-						if (ns_android_string == -1) {
-							string_table.push_back("http://schemas.android.com/apk/res/android");
-							ns_android_string = string_table.size() - 1;
-						}
+							int32_t attr_name_string = string_table.find("name");
+							ERR_FAIL_COND_MSG(attr_name_string == -1, "Template does not have 'name' attribute.");
 
-						int32_t attr_uses_feature_string = string_table.find("uses-feature");
-						if (attr_uses_feature_string == -1) {
-							string_table.push_back("uses-feature");
-							attr_uses_feature_string = string_table.size() - 1;
-						}
+							int32_t ns_android_string = string_table.find("http://schemas.android.com/apk/res/android");
+							if (ns_android_string == -1) {
+								string_table.push_back("http://schemas.android.com/apk/res/android");
+								ns_android_string = string_table.size() - 1;
+							}
 
-						int32_t attr_required_string = string_table.find("required");
-						if (attr_required_string == -1) {
-							string_table.push_back("required");
-							attr_required_string = string_table.size() - 1;
-						}
+							int32_t attr_uses_feature_string = string_table.find("uses-feature");
+							if (attr_uses_feature_string == -1) {
+								string_table.push_back("uses-feature");
+								attr_uses_feature_string = string_table.size() - 1;
+							}
 
-						int32_t attr_version_string = string_table.find("version");
-						if (attr_version_string == -1) {
-							string_table.push_back("version");
-							attr_version_string = string_table.size() - 1;
-						}
+							int32_t attr_required_string = string_table.find("required");
+							if (attr_required_string == -1) {
+								string_table.push_back("required");
+								attr_required_string = string_table.size() - 1;
+							}
 
-						String required_value_string;
-						if (dof_index == 1) {
-							required_value_string = "false";
-						} else if (dof_index == 2) {
-							required_value_string = "true";
-						} else {
-							ERR_FAIL_MSG("Unknown DoF index: " + itos(dof_index) + ".");
-						}
-						int32_t required_value = string_table.find(required_value_string);
-						if (required_value == -1) {
-							string_table.push_back(required_value_string);
-							required_value = string_table.size() - 1;
-						}
+							for (int i = 0; i < feature_names.size(); i++) {
+								String feature_name = feature_names[i];
+								bool feature_required = feature_required_list[i];
+								int feature_version = feature_versions[i];
+								bool has_version_attribute = feature_version != -1;
 
-						int32_t version_value = string_table.find("1");
-						if (version_value == -1) {
-							string_table.push_back("1");
-							version_value = string_table.size() - 1;
-						}
+								print_line("Adding feature " + feature_name);
 
-						int32_t feature_string = string_table.find("android.hardware.vr.headtracking");
-						if (feature_string == -1) {
-							string_table.push_back("android.hardware.vr.headtracking");
-							feature_string = string_table.size() - 1;
-						}
+								int32_t feature_string = string_table.find(feature_name);
+								if (feature_string == -1) {
+									string_table.push_back(feature_name);
+									feature_string = string_table.size() - 1;
+								}
 
-						{
-							manifest_cur_size += 96 + 24; // node and three attrs + end node
-							p_manifest.resize(manifest_cur_size);
+								String required_value_string = feature_required ? "true" : "false";
+								int32_t required_value = string_table.find(required_value_string);
+								if (required_value == -1) {
+									string_table.push_back(required_value_string);
+									required_value = string_table.size() - 1;
+								}
 
-							// start tag
-							encode_uint16(0x102, &p_manifest.write[ofs]); // type
-							encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
-							encode_uint32(96, &p_manifest.write[ofs + 4]); // size
-							encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
-							encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
-							encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
-							encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name
-							encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start
-							encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size
-							encode_uint16(3, &p_manifest.write[ofs + 28]); // num_attrs
-							encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index
-							encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index
-							encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index
+								int32_t attr_version_string = -1;
+								int32_t version_value = -1;
+								int tag_size;
+								int attr_count;
+								if (has_version_attribute) {
+									attr_version_string = string_table.find("version");
+									if (attr_version_string == -1) {
+										string_table.push_back("version");
+										attr_version_string = string_table.size() - 1;
+									}
 
-							// android:name attribute
-							encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns
-							encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name'
-							encode_uint32(feature_string, &p_manifest.write[ofs + 44]); // raw_value
-							encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size
-							p_manifest.write[ofs + 50] = 0; // typedvalue_always0
-							p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string)
-							encode_uint32(feature_string, &p_manifest.write[ofs + 52]); // typedvalue reference
-
-							// android:required attribute
-							encode_uint32(ns_android_string, &p_manifest.write[ofs + 56]); // ns
-							encode_uint32(attr_required_string, &p_manifest.write[ofs + 60]); // 'name'
-							encode_uint32(required_value, &p_manifest.write[ofs + 64]); // raw_value
-							encode_uint16(8, &p_manifest.write[ofs + 68]); // typedvalue_size
-							p_manifest.write[ofs + 70] = 0; // typedvalue_always0
-							p_manifest.write[ofs + 71] = 0x03; // typedvalue_type (string)
-							encode_uint32(required_value, &p_manifest.write[ofs + 72]); // typedvalue reference
-
-							// android:version attribute
-							encode_uint32(ns_android_string, &p_manifest.write[ofs + 76]); // ns
-							encode_uint32(attr_version_string, &p_manifest.write[ofs + 80]); // 'name'
-							encode_uint32(version_value, &p_manifest.write[ofs + 84]); // raw_value
-							encode_uint16(8, &p_manifest.write[ofs + 88]); // typedvalue_size
-							p_manifest.write[ofs + 90] = 0; // typedvalue_always0
-							p_manifest.write[ofs + 91] = 0x03; // typedvalue_type (string)
-							encode_uint32(version_value, &p_manifest.write[ofs + 92]); // typedvalue reference
-
-							ofs += 96;
+									version_value = string_table.find(itos(feature_version));
+									if (version_value == -1) {
+										string_table.push_back(itos(feature_version));
+										version_value = string_table.size() - 1;
+									}
 
-							// end tag
-							encode_uint16(0x103, &p_manifest.write[ofs]); // type
-							encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
-							encode_uint32(24, &p_manifest.write[ofs + 4]); // size
-							encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
-							encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
-							encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
-							encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name
+									tag_size = 96; // node and three attrs + end node
+									attr_count = 3;
+								} else {
+									tag_size = 76; // node and two attrs + end node
+									attr_count = 2;
+								}
+								manifest_cur_size += tag_size + 24;
+								p_manifest.resize(manifest_cur_size);
+
+								// start tag
+								encode_uint16(0x102, &p_manifest.write[ofs]); // type
+								encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
+								encode_uint32(tag_size, &p_manifest.write[ofs + 4]); // size
+								encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
+								encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
+								encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
+								encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name
+								encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start
+								encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size
+								encode_uint16(attr_count, &p_manifest.write[ofs + 28]); // num_attrs
+								encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index
+								encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index
+								encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index
+
+								// android:name attribute
+								encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns
+								encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name'
+								encode_uint32(feature_string, &p_manifest.write[ofs + 44]); // raw_value
+								encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size
+								p_manifest.write[ofs + 50] = 0; // typedvalue_always0
+								p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string)
+								encode_uint32(feature_string, &p_manifest.write[ofs + 52]); // typedvalue reference
+
+								// android:required attribute
+								encode_uint32(ns_android_string, &p_manifest.write[ofs + 56]); // ns
+								encode_uint32(attr_required_string, &p_manifest.write[ofs + 60]); // 'name'
+								encode_uint32(required_value, &p_manifest.write[ofs + 64]); // raw_value
+								encode_uint16(8, &p_manifest.write[ofs + 68]); // typedvalue_size
+								p_manifest.write[ofs + 70] = 0; // typedvalue_always0
+								p_manifest.write[ofs + 71] = 0x03; // typedvalue_type (string)
+								encode_uint32(required_value, &p_manifest.write[ofs + 72]); // typedvalue reference
+
+								ofs += 76;
+
+								if (has_version_attribute) {
+									// android:version attribute
+									encode_uint32(ns_android_string, &p_manifest.write[ofs]); // ns
+									encode_uint32(attr_version_string, &p_manifest.write[ofs + 4]); // 'name'
+									encode_uint32(version_value, &p_manifest.write[ofs + 8]); // raw_value
+									encode_uint16(8, &p_manifest.write[ofs + 12]); // typedvalue_size
+									p_manifest.write[ofs + 14] = 0; // typedvalue_always0
+									p_manifest.write[ofs + 15] = 0x03; // typedvalue_type (string)
+									encode_uint32(version_value, &p_manifest.write[ofs + 16]); // typedvalue reference
+
+									ofs += 20;
+								}
 
-							ofs += 24;
+								// end tag
+								encode_uint16(0x103, &p_manifest.write[ofs]); // type
+								encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize
+								encode_uint32(24, &p_manifest.write[ofs + 4]); // size
+								encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno
+								encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment
+								encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns
+								encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name
+
+								ofs += 24;
+							}
+							memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size());
+							ofs -= 24; // go back over back end
 						}
-						memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size());
-						ofs -= 24; // go back over back end
 					}
 					if (tname == "manifest") {
 
@@ -1295,9 +1334,10 @@ public:
 
 	virtual void get_export_options(List<ExportOption> *r_options) {
 
-		r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0));
-		r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "graphics/degrees_of_freedom", PROPERTY_HINT_ENUM, "None,3DOF and 6DOF,6DOF"), 0));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true));
+		r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0));
+		r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/degrees_of_freedom", PROPERTY_HINT_ENUM, "None,3DOF and 6DOF,6DOF"), 0));
+		r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), false));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
 		r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
@@ -2264,7 +2304,7 @@ public:
 			}
 		}
 
-		int xr_mode_index = p_preset->get("graphics/xr_mode");
+		int xr_mode_index = p_preset->get("xr_features/xr_mode");
 		if (xr_mode_index == 1 /* XRMode.OVR */) {
 			cl.push_back("--xr_mode_ovr");
 		} else {