diff options
34 files changed, 471 insertions, 95 deletions
diff --git a/SConstruct b/SConstruct index f7d589e799..83bd1560ff 100644 --- a/SConstruct +++ b/SConstruct @@ -300,6 +300,13 @@ opts.Update(env_base)  env_base["platform"] = selected_platform  # Must always be re-set after calling opts.Update().  Help(opts.GenerateHelpText(env_base)) +# Detect and print a warning listing unknown SCons variables to ease troubleshooting. +unknown = opts.UnknownVariables() +if unknown: +    print("WARNING: Unknown SCons variables were passed and will be ignored:") +    for item in unknown.items(): +        print("    " + item[0] + "=" + item[1]) +  # add default include paths  env_base.Prepend(CPPPATH=["#"]) diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp index 4a76f0191d..d34b5b6fe3 100644 --- a/core/io/packed_data_container.cpp +++ b/core/io/packed_data_container.cpp @@ -100,6 +100,7 @@ Variant PackedDataContainer::_iter_get_ofs(const Variant &p_iter, uint32_t p_off  }  Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, bool &err) const { +	ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), Variant());  	uint32_t type = decode_uint32(p_buf + p_ofs);  	if (type == TYPE_ARRAY || type == TYPE_DICT) { @@ -122,6 +123,7 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, b  }  uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const { +	ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), 0);  	const uint8_t *rd = data.ptr();  	ERR_FAIL_COND_V(!rd, 0);  	const uint8_t *r = &rd[p_ofs]; @@ -131,6 +133,7 @@ uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const {  }  int PackedDataContainer::_size(uint32_t p_ofs) const { +	ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), 0);  	const uint8_t *rd = data.ptr();  	ERR_FAIL_COND_V(!rd, 0);  	const uint8_t *r = &rd[p_ofs]; @@ -149,6 +152,7 @@ int PackedDataContainer::_size(uint32_t p_ofs) const {  }  Variant PackedDataContainer::_key_at_ofs(uint32_t p_ofs, const Variant &p_key, bool &err) const { +	ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), Variant());  	const uint8_t *rd = data.ptr();  	if (!rd) {  		err = true; diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index f6bb812070..668912b6bd 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -654,6 +654,12 @@  				See [method add_theme_stylebox_override].  			</description>  		</method> +		<method name="is_drag_successful" qualifiers="const"> +			<return type="bool" /> +			<description> +				Returns [code]true[/code] if drag operation is successful. +			</description> +		</method>  		<method name="is_layout_rtl" qualifiers="const">  			<return type="bool" />  			<description> diff --git a/doc/classes/FontData.xml b/doc/classes/FontData.xml index ccfe861c92..c403d238c5 100644 --- a/doc/classes/FontData.xml +++ b/doc/classes/FontData.xml @@ -93,6 +93,12 @@  				Returns font descent (number of pixels below the baseline).  			</description>  		</method> +		<method name="get_fixed_size" qualifiers="const"> +			<return type="int" /> +			<description> +				Returns font fixed size. +			</description> +		</method>  		<method name="get_font_name" qualifiers="const">  			<return type="String" />  			<description> @@ -481,6 +487,13 @@  				Sets the font descent (number of pixels below the baseline).  			</description>  		</method> +		<method name="set_fixed_size"> +			<return type="void" /> +			<argument index="0" name="fixed_size" type="int" /> +			<description> +				Sets the fixed size for the font. +			</description> +		</method>  		<method name="set_font_name">  			<return type="void" />  			<argument index="0" name="name" type="String" /> diff --git a/doc/classes/PhysicalSkyMaterial.xml b/doc/classes/PhysicalSkyMaterial.xml index b90f52a70d..e1e50a2b51 100644 --- a/doc/classes/PhysicalSkyMaterial.xml +++ b/doc/classes/PhysicalSkyMaterial.xml @@ -23,7 +23,7 @@  		<member name="mie_coefficient" type="float" setter="set_mie_coefficient" getter="get_mie_coefficient" default="0.005">  			Controls the strength of mie scattering for the sky. Mie scattering results from light colliding with larger particles (like water). On earth, mie scattering results in a whitish color around the sun and horizon.  		</member> -		<member name="mie_color" type="Color" setter="set_mie_color" getter="get_mie_color" default="Color(0.36, 0.56, 0.82, 1)"> +		<member name="mie_color" type="Color" setter="set_mie_color" getter="get_mie_color" default="Color(0.63, 0.77, 0.92, 1)">  			Controls the [Color] of the mie scattering effect. While not physically accurate, this allows for the creation of alien looking planets.  		</member>  		<member name="mie_eccentricity" type="float" setter="set_mie_eccentricity" getter="get_mie_eccentricity" default="0.8"> @@ -35,7 +35,7 @@  		<member name="rayleigh_coefficient" type="float" setter="set_rayleigh_coefficient" getter="get_rayleigh_coefficient" default="2.0">  			Controls the strength of the Rayleigh scattering. Rayleigh scattering results from light colliding with small particles. It is responsible for the blue color of the sky.  		</member> -		<member name="rayleigh_color" type="Color" setter="set_rayleigh_color" getter="get_rayleigh_color" default="Color(0.056, 0.14, 0.3, 1)"> +		<member name="rayleigh_color" type="Color" setter="set_rayleigh_color" getter="get_rayleigh_color" default="Color(0.26, 0.41, 0.58, 1)">  			Controls the [Color] of the Rayleigh scattering. While not physically accurate, this allows for the creation of alien looking planets. For example, setting this to a red [Color] results in a Mars looking atmosphere with a corresponding blue sunset.  		</member>  		<member name="sun_disk_scale" type="float" setter="set_sun_disk_scale" getter="get_sun_disk_scale" default="1.0"> diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 8e75b474ed..d83645a8af 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -107,6 +107,12 @@  				Returns the drag data from the GUI, that was previously returned by [method Control._get_drag_data].  			</description>  		</method> +		<method name="gui_is_drag_successful" qualifiers="const"> +			<return type="bool" /> +			<description> +				Returns [code]true[/code] if the drag operation is successful. +			</description> +		</method>  		<method name="gui_is_dragging" qualifiers="const">  			<return type="bool" />  			<description> diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 368b7e6ab3..dc175a3148 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6882,10 +6882,12 @@ EditorNode::EditorNode() {  	file_export_lib->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action));  	file_export_lib_merge = memnew(CheckBox);  	file_export_lib_merge->set_text(TTR("Merge With Existing")); +	file_export_lib_merge->set_h_size_flags(Control::SIZE_SHRINK_CENTER);  	file_export_lib_merge->set_pressed(true);  	file_export_lib->get_vbox()->add_child(file_export_lib_merge);  	file_export_lib_apply_xforms = memnew(CheckBox);  	file_export_lib_apply_xforms->set_text(TTR("Apply MeshInstance Transforms")); +	file_export_lib_apply_xforms->set_h_size_flags(Control::SIZE_SHRINK_CENTER);  	file_export_lib_apply_xforms->set_pressed(false);  	file_export_lib->get_vbox()->add_child(file_export_lib_apply_xforms);  	gui_base->add_child(file_export_lib); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index d48d45d848..a97d38323e 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -1277,11 +1277,13 @@ ProjectExportDialog::ProjectExportDialog() {  	export_debug = memnew(CheckBox);  	export_debug->set_text(TTR("Export With Debug"));  	export_debug->set_pressed(true); +	export_debug->set_h_size_flags(Control::SIZE_SHRINK_CENTER);  	export_project->get_vbox()->add_child(export_debug);  	export_pck_zip_debug = memnew(CheckBox);  	export_pck_zip_debug->set_text(TTR("Export With Debug"));  	export_pck_zip_debug->set_pressed(true); +	export_pck_zip_debug->set_h_size_flags(Control::SIZE_SHRINK_CENTER);  	export_pck_zip->get_vbox()->add_child(export_pck_zip_debug);  	set_hide_on_ok(false); diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp index 1c49029570..435069e25c 100644 --- a/modules/bullet/area_bullet.cpp +++ b/modules/bullet/area_bullet.cpp @@ -92,8 +92,8 @@ void AreaBullet::dispatch_callbacks() {  				overlapping_shapes.remove(i); // Remove after callback  				break;  			case OVERLAP_STATE_INSIDE: { -				if (otherObj.object->getType() == TYPE_RIGID_BODY) { -					RigidBodyBullet *body = static_cast<RigidBodyBullet *>(otherObj.object); +				if (overlapping_shape.other_object->getType() == TYPE_RIGID_BODY) { +					RigidBodyBullet *body = static_cast<RigidBodyBullet *>(overlapping_shape.other_object);  					body->scratch_space_override_modificator();  				}  				break; @@ -276,7 +276,7 @@ void AreaBullet::set_param(PhysicsServer3D::AreaParameter p_param, const Variant  		default:  			WARN_PRINT("Area doesn't support this parameter in the Bullet backend: " + itos(p_param));  	} -	scratch(); +	isScratched = true;  }  Variant AreaBullet::get_param(PhysicsServer3D::AreaParameter p_param) const { @@ -312,7 +312,7 @@ void AreaBullet::set_event_callback(Type p_callbackObjectType, const Callable &p  		set_godot_object_flags(get_godot_object_flags() | GOF_IS_MONITORING_AREA);  	} else {  		set_godot_object_flags(get_godot_object_flags() & (~GOF_IS_MONITORING_AREA)); -		clear_overlaps(true); +		clear_overlaps();  	}  } diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl index 158cd960c4..7bb8346c47 100644 --- a/modules/lightmapper_rd/lm_compute.glsl +++ b/modules/lightmapper_rd/lm_compute.glsl @@ -235,19 +235,39 @@ uint trace_ray(vec3 p_from, vec3 p_to  	return RAY_MISS;  } +// https://www.reedbeta.com/blog/hash-functions-for-gpu-rendering/ +uint hash(uint value) { +	uint state = value * 747796405u + 2891336453u; +	uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; +	return (word >> 22u) ^ word; +} + +uint random_seed(ivec3 seed) { +	return hash(seed.x ^ hash(seed.y ^ hash(seed.z))); +} + +// generates a random value in range [0.0, 1.0) +float randomize(inout uint value) { +	value = hash(value); +	return float(value / 4294967296.0); +} +  const float PI = 3.14159265f; -const float GOLDEN_ANGLE = PI * (3.0 - sqrt(5.0)); - -vec3 vogel_hemisphere(uint p_index, uint p_count, float p_offset) { -	float r = sqrt(float(p_index) + 0.5f) / sqrt(float(p_count)); -	float theta = float(p_index) * GOLDEN_ANGLE + p_offset; -	float y = cos(r * PI * 0.5); -	float l = sin(r * PI * 0.5); -	return vec3(l * cos(theta), l * sin(theta), y); + +// http://www.realtimerendering.com/raytracinggems/unofficial_RayTracingGems_v1.4.pdf (chapter 15) +vec3 generate_hemisphere_uniform_direction(inout uint noise) { +	float noise1 = randomize(noise); +	float noise2 = randomize(noise) * 2.0 * PI; + +	float factor = sqrt(1 - (noise1 * noise1)); +	return vec3(factor * cos(noise2), factor * sin(noise2), noise1);  } -float quick_hash(vec2 pos) { -	return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237); +vec3 generate_hemisphere_cosine_weighted_direction(inout uint noise) { +	float noise1 = randomize(noise); +	float noise2 = randomize(noise) * 2.0 * PI; + +	return vec3(sqrt(noise1) * cos(noise2), sqrt(noise1) * sin(noise2), sqrt(1.0 - noise1));  }  float get_omni_attenuation(float distance, float inv_range, float decay) { @@ -404,8 +424,9 @@ void main() {  #endif  	vec3 light_average = vec3(0.0);  	float active_rays = 0.0; +	uint noise = random_seed(ivec3(params.ray_from, atlas_pos));  	for (uint i = params.ray_from; i < params.ray_to; i++) { -		vec3 ray_dir = normal_mat * vogel_hemisphere(i, params.ray_count, quick_hash(vec2(atlas_pos))); +		vec3 ray_dir = normal_mat * generate_hemisphere_cosine_weighted_direction(noise);  		uint tidx;  		vec3 barycentric; @@ -550,8 +571,9 @@ void main() {  			vec4(0.0),  			vec4(0.0)); +	uint noise = random_seed(ivec3(params.ray_from, probe_index, 49502741 /* some prime */));  	for (uint i = params.ray_from; i < params.ray_to; i++) { -		vec3 ray_dir = vogel_hemisphere(i, params.ray_count, quick_hash(vec2(float(probe_index), 0.0))); +		vec3 ray_dir = generate_hemisphere_uniform_direction(noise);  		if (bool(i & 1)) {  			//throw to both sides, so alternate them  			ray_dir.z *= -1.0; diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 34f0064a5e..505e7ac0eb 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -119,7 +119,9 @@ DisplayServer::ScreenOrientation DisplayServerAndroid::screen_get_orientation(in  	GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();  	ERR_FAIL_COND_V(!godot_io_java, SCREEN_LANDSCAPE); -	return (ScreenOrientation)godot_io_java->get_screen_orientation(); +	const int orientation = godot_io_java->get_screen_orientation(); +	ERR_FAIL_INDEX_V_MSG(orientation, 7, SCREEN_LANDSCAPE, "Unrecognized screen orientation"); +	return (ScreenOrientation)orientation;  }  int DisplayServerAndroid::get_screen_count() const { diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 18e9e20948..05cd63d935 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -751,9 +751,9 @@ void EditorExportPlatformAndroid::_get_permissions(const Ref<EditorExportPreset>  	}  	int xr_mode_index = p_preset->get("xr_features/xr_mode"); -	if (xr_mode_index == 1 /* XRMode.OVR */) { +	if (xr_mode_index == XR_MODE_OPENXR) {  		int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required -		if (hand_tracking_index > 0) { +		if (hand_tracking_index > XR_HAND_TRACKING_NONE) {  			if (r_permissions.find("com.oculus.permission.HAND_TRACKING") == -1) {  				r_permissions.push_back("com.oculus.permission.HAND_TRACKING");  			} @@ -964,6 +964,20 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p  						}  					} +					if (tname == "meta-data" && attrname == "name" && value == "xr_mode_metadata_name") { +						// Update the meta-data 'android:name' attribute based on the selected XR mode. +						if (xr_mode_index == XR_MODE_OPENXR) { +							string_table.write[attr_value] = "com.samsung.android.vr.application.mode"; +						} +					} + +					if (tname == "meta-data" && attrname == "value" && value == "xr_mode_metadata_value") { +						// Update the meta-data 'android:value' attribute based on the selected XR mode. +						if (xr_mode_index == XR_MODE_OPENXR) { +							string_table.write[attr_value] = "vr_only"; +						} +					} +  					iofs += 20;  				} @@ -978,7 +992,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p  					Vector<bool> feature_required_list;  					Vector<int> feature_versions; -					if (xr_mode_index == 1 /* XRMode.OVR */) { +					if (xr_mode_index == XR_MODE_OPENXR) {  						// Set degrees of freedom  						feature_names.push_back("android.hardware.vr.headtracking");  						feature_required_list.push_back(true); @@ -986,11 +1000,19 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p  						// 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) { +						if (hand_tracking_index > XR_HAND_TRACKING_NONE) {  							feature_names.push_back("oculus.software.handtracking"); -							feature_required_list.push_back(hand_tracking_index == 2); +							feature_required_list.push_back(hand_tracking_index == XR_HAND_TRACKING_REQUIRED);  							feature_versions.push_back(-1); // no version attribute should be added.  						} + +						// Check for passthrough +						int passthrough_mode = p_preset->get("xr_features/passthrough"); +						if (passthrough_mode > XR_PASSTHROUGH_NONE) { +							feature_names.push_back("com.oculus.feature.PASSTHROUGH"); +							feature_required_list.push_back(passthrough_mode == XR_PASSTHROUGH_REQUIRED); +							feature_versions.push_back(-1); +						}  					}  					if (feature_names.size() > 0) { @@ -1669,8 +1691,9 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio  	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/opengl_debug"), false)); -	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/xr_mode", PROPERTY_HINT_ENUM, "Regular,OpenXR"), 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::INT, "xr_features/passthrough", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0));  	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true));  	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true)); @@ -2137,10 +2160,17 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr  	// Validate the Xr features are properly populated  	int xr_mode_index = p_preset->get("xr_features/xr_mode");  	int hand_tracking = p_preset->get("xr_features/hand_tracking"); -	if (xr_mode_index != /* XRMode.OVR*/ 1) { -		if (hand_tracking > 0) { +	int passthrough_mode = p_preset->get("xr_features/passthrough"); +	if (xr_mode_index != XR_MODE_OPENXR) { +		if (hand_tracking > XR_HAND_TRACKING_NONE) { +			valid = false; +			err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"OpenXR\"."); +			err += "\n"; +		} + +		if (passthrough_mode > XR_PASSTHROUGH_NONE) {  			valid = false; -			err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."); +			err += TTR("\"Passthrough\" is only valid when \"Xr Mode\" is \"OpenXR\".");  			err += "\n";  		}  	} @@ -2202,8 +2232,8 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP  	}  	int xr_mode_index = p_preset->get("xr_features/xr_mode"); -	if (xr_mode_index == 1) { -		command_line_strings.push_back("--xr_mode_ovr"); +	if (xr_mode_index == XR_MODE_OPENXR) { +		command_line_strings.push_back("--xr_mode_openxr");  	} else { // XRMode.REGULAR is the default.  		command_line_strings.push_back("--xr_mode_regular");  	} diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index b0d623827e..658c0ecd0a 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -211,16 +211,24 @@ String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) {  String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) {  	String manifest_xr_features; -	bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1; +	int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode")); +	bool uses_xr = xr_mode_index == XR_MODE_OPENXR;  	if (uses_xr) {  		manifest_xr_features += "    <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"true\" android:version=\"1\" />\n";  		int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required -		if (hand_tracking_index == 1) { +		if (hand_tracking_index == XR_HAND_TRACKING_OPTIONAL) {  			manifest_xr_features += "    <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n"; -		} else if (hand_tracking_index == 2) { +		} else if (hand_tracking_index == XR_HAND_TRACKING_REQUIRED) {  			manifest_xr_features += "    <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"true\" />\n";  		} + +		int passthrough_mode = p_preset->get("xr_features/passthrough"); +		if (passthrough_mode == XR_PASSTHROUGH_OPTIONAL) { +			manifest_xr_features += "    <uses-feature tools:node=\"replace\" android:name=\"com.oculus.feature.PASSTHROUGH\" android:required=\"false\" />\n"; +		} else if (passthrough_mode == XR_PASSTHROUGH_REQUIRED) { +			manifest_xr_features += "    <uses-feature tools:node=\"replace\" android:name=\"com.oculus.feature.PASSTHROUGH\" android:required=\"true\" />\n"; +		}  	}  	return manifest_xr_features;  } @@ -239,7 +247,8 @@ String _get_instrumentation_tag(const Ref<EditorExportPreset> &p_preset) {  }  String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) { -	bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1; +	int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode")); +	bool uses_xr = xr_mode_index == XR_MODE_OPENXR;  	String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation"))));  	String manifest_activity_text = vformat(  			"        <activity android:name=\"com.godot.game.GodotApp\" " @@ -256,6 +265,8 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {  }  String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_storage_permission) { +	int xr_mode_index = (int)(p_preset->get("xr_features/xr_mode")); +	bool uses_xr = xr_mode_index == XR_MODE_OPENXR;  	String manifest_application_text = vformat(  			"    <application android:label=\"@string/godot_project_name_string\"\n"  			"        android:allowBackup=\"%s\"\n" @@ -270,6 +281,9 @@ String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_  			bool_to_string(p_preset->get("package/retain_data_on_uninstall")),  			bool_to_string(p_has_storage_permission)); +	if (uses_xr) { +		manifest_application_text += "        <meta-data tools:node=\"replace\" android:name=\"com.samsung.android.vr.application.mode\" android:value=\"vr_only\" />\n"; +	}  	manifest_application_text += _get_activity_tag(p_preset);  	manifest_application_text += "    </application>\n";  	return manifest_application_text; diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 744022f1f9..db05c7534c 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -44,6 +44,21 @@ const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="ut  </resources>  )"; +// Supported XR modes. +// 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; + +// Supported XR hand tracking modes. +static const int XR_HAND_TRACKING_NONE = 0; +static const int XR_HAND_TRACKING_OPTIONAL = 1; +static const int XR_HAND_TRACKING_REQUIRED = 2; + +// Supported XR passthrough modes. +static const int XR_PASSTHROUGH_NONE = 0; +static const int XR_PASSTHROUGH_OPTIONAL = 1; +static const int XR_PASSTHROUGH_REQUIRED = 2; +  struct CustomExportData {  	String assets_directory;  	bool debug; diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml index d7bf6cef30..9ae6367b42 100644 --- a/platform/android/java/app/AndroidManifest.xml +++ b/platform/android/java/app/AndroidManifest.xml @@ -33,6 +33,11 @@          <!-- The following metadata values are replaced when Godot exports, modifying them here has no effect. -->          <!-- Do these changes in the export preset. Adding new ones is fine. --> +        <!-- XR mode metadata. This is modified by the exporter based on the selected xr mode. DO NOT CHANGE the values here. --> +        <meta-data +            android:name="xr_mode_metadata_name" +            android:value="xr_mode_metadata_value" /> +          <activity              android:name=".GodotApp"              android:label="@string/godot_project_name_string" diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index b6476fa61a..17ff3c75c0 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -502,8 +502,8 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC  			boolean has_extra = i < command_line.length - 1;  			if (command_line[i].equals(XRMode.REGULAR.cmdLineArg)) {  				xrMode = XRMode.REGULAR; -			} else if (command_line[i].equals(XRMode.OVR.cmdLineArg)) { -				xrMode = XRMode.OVR; +			} else if (command_line[i].equals(XRMode.OPENXR.cmdLineArg)) { +				xrMode = XRMode.OPENXR;  			} else if (command_line[i].equals("--debug_opengl")) {  				use_debug_opengl = true;  			} else if (command_line[i].equals("--use_immersive")) { 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 088b048502..d5b0b67903 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java @@ -174,7 +174,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView  		setPreserveEGLContextOnPause(true);  		setFocusableInTouchMode(true);  		switch (xrMode) { -			case OVR: +			case OPENXR:  				// Replace the default egl config chooser.  				setEGLConfigChooser(new OvrConfigChooser()); 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 d85d88ec6c..5f354b6b4c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -288,7 +288,34 @@ public class GodotIO {  	}  	public int getScreenOrientation() { -		return activity.getRequestedOrientation(); +		int orientation = activity.getRequestedOrientation(); +		switch (orientation) { +			case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: +				return SCREEN_LANDSCAPE; +			case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: +				return SCREEN_PORTRAIT; +			case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE: +				return SCREEN_REVERSE_LANDSCAPE; +			case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT: +				return SCREEN_REVERSE_PORTRAIT; +			case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: +			case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE: +				return SCREEN_SENSOR_LANDSCAPE; +			case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: +			case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT: +				return SCREEN_SENSOR_PORTRAIT; +			case ActivityInfo.SCREEN_ORIENTATION_SENSOR: +			case ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR: +			case ActivityInfo.SCREEN_ORIENTATION_FULL_USER: +				return SCREEN_SENSOR; +			case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED: +			case ActivityInfo.SCREEN_ORIENTATION_USER: +			case ActivityInfo.SCREEN_ORIENTATION_BEHIND: +			case ActivityInfo.SCREEN_ORIENTATION_NOSENSOR: +			case ActivityInfo.SCREEN_ORIENTATION_LOCKED: +			default: +				return -1; +		}  	}  	public void setEdit(GodotEditText _edit) { 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 0995477baf..58f02b0396 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,7 @@ package org.godotengine.godot.xr;   */  public enum XRMode {  	REGULAR(0, "Regular", "--xr_mode_regular", "Default Android Gamepad"), // Regular/flatscreen -	OVR(1, "Oculus Mobile VR", "--xr_mode_ovr", ""); +	OPENXR(1, "OpenXR", "--xr_mode_openxr", "");  	final int index;  	final String label; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 582c8e5860..fdf10e2f42 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -810,6 +810,10 @@ void Control::set_drag_preview(Control *p_control) {  	get_viewport()->_gui_set_drag_preview(this, p_control);  } +bool Control::is_drag_successful() const { +	return is_inside_tree() && get_viewport()->gui_is_drag_successful(); +} +  void Control::_call_gui_input(const Ref<InputEvent> &p_event) {  	emit_signal(SceneStringNames::get_singleton()->gui_input, p_event); //signal should be first, so it's possible to override an event (and then accept it)  	if (!is_inside_tree() || get_viewport()->is_input_handled()) { @@ -2964,6 +2968,7 @@ void Control::_bind_methods() {  	ClassDB::bind_method(D_METHOD("set_drag_forwarding", "target"), &Control::set_drag_forwarding);  	ClassDB::bind_method(D_METHOD("set_drag_preview", "control"), &Control::set_drag_preview); +	ClassDB::bind_method(D_METHOD("is_drag_successful"), &Control::is_drag_successful);  	ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Control::warp_mouse); diff --git a/scene/gui/control.h b/scene/gui/control.h index 02ab336ef0..2eb714eae6 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -357,6 +357,7 @@ public:  	virtual void drop_data(const Point2 &p_point, const Variant &p_data);  	void set_drag_preview(Control *p_control);  	void force_drag(const Variant &p_data, Control *p_control); +	bool is_drag_successful() const;  	void set_custom_minimum_size(const Size2 &p_custom);  	Size2 get_custom_minimum_size() const; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 124d5c7821..4a85cf2c45 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -268,7 +268,9 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {  				return;  			} -			shift_selection_check_pre(b->is_shift_pressed()); +			if (b->is_shift_pressed()) { +				shift_selection_check_pre(true); +			}  			set_caret_at_pixel_pos(b->get_position().x); @@ -345,6 +347,9 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {  			}  			selection.creating = false;  			selection.double_click = false; +			if (!drag_action) { +				selection.drag_attempt = false; +			}  			show_virtual_keyboard();  		} @@ -369,6 +374,11 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {  				selection_fill_at_caret();  			}  		} + +		if (drag_action && can_drop_data(m->get_position(), get_viewport()->gui_get_drag_data())) { +			drag_caret_force_displayed = true; +			set_caret_at_pixel_pos(m->get_position().x); +		}  	}  	Ref<InputEventKey> k = p_event; @@ -569,21 +579,44 @@ bool LineEdit::can_drop_data(const Point2 &p_point, const Variant &p_data) const  		return drop_override;  	} -	return p_data.get_type() == Variant::STRING; +	return is_editable() && p_data.get_type() == Variant::STRING;  }  void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {  	Control::drop_data(p_point, p_data); -	if (p_data.get_type() == Variant::STRING) { +	if (p_data.get_type() == Variant::STRING && is_editable()) {  		set_caret_at_pixel_pos(p_point.x); +		int caret_column_tmp = caret_column; +		if (selection.drag_attempt) { +			selection.drag_attempt = false; +			if (caret_column < selection.begin || caret_column > selection.end) { +				if (caret_column_tmp > selection.end) { +					caret_column_tmp = caret_column_tmp - (selection.end - selection.begin); +				} +				selection_delete(); -		text = text.left(selection.begin) + text.substr(selection.end); -		_shape(); - -		insert_text_at_caret(p_data); -		selection.begin = caret_column - (selection.end - selection.begin); -		selection.end = caret_column; +				set_caret_column(caret_column_tmp); +				insert_text_at_caret(p_data); +			} +		} else if (selection.enabled && caret_column >= selection.begin && caret_column <= selection.end) { +			caret_column_tmp = selection.begin; +			selection_delete(); +			set_caret_column(caret_column_tmp); +			insert_text_at_caret(p_data); +			grab_focus(); +		} else { +			insert_text_at_caret(p_data); +			grab_focus(); +		} +		select(caret_column_tmp, caret_column); +		if (!text_changed_dirty) { +			if (is_inside_tree()) { +				MessageQueue::get_singleton()->push_call(this, "_text_changed"); +			} +			text_changed_dirty = true; +		} +		update();  	}  } @@ -803,7 +836,7 @@ void LineEdit::_notification(int p_what) {  			// Draw carets.  			ofs.x = x_ofs + scroll_offset; -			if (draw_caret) { +			if (draw_caret || drag_caret_force_displayed) {  				if (ime_text.length() == 0) {  					// Normal caret.  					CaretInfo caret = TS->shaped_text_get_carets(text_rid, caret_column); @@ -921,7 +954,7 @@ void LineEdit::_notification(int p_what) {  				DisplayServer::get_singleton()->virtual_keyboard_hide();  			} -			if (deselect_on_focus_loss_enabled) { +			if (deselect_on_focus_loss_enabled && !selection.drag_attempt) {  				deselect();  			}  		} break; @@ -935,6 +968,25 @@ void LineEdit::_notification(int p_what) {  				update();  			}  		} break; +		case Control::NOTIFICATION_DRAG_BEGIN: { +			drag_action = true; +		} break; +		case Control::NOTIFICATION_DRAG_END: { +			if (is_drag_successful()) { +				if (selection.drag_attempt) { +					selection.drag_attempt = false; +					if (is_editable()) { +						selection_delete(); +					} else if (deselect_on_focus_loss_enabled) { +						deselect(); +					} +				} +			} else { +				selection.drag_attempt = false; +			} +			drag_action = false; +			drag_caret_force_displayed = false; +		} break;  	}  } @@ -999,6 +1051,9 @@ void LineEdit::undo() {  	} else if (undo_stack_pos == undo_stack.front()) {  		return;  	} + +	deselect(); +  	undo_stack_pos = undo_stack_pos->prev();  	TextOperation op = undo_stack_pos->get();  	text = op.text; @@ -1020,6 +1075,9 @@ void LineEdit::redo() {  	if (undo_stack_pos == undo_stack.back()) {  		return;  	} + +	deselect(); +  	undo_stack_pos = undo_stack_pos->next();  	TextOperation op = undo_stack_pos->get();  	text = op.text; diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 134d5f8f76..221dd9eb2e 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -129,6 +129,9 @@ private:  	bool middle_mouse_paste_enabled = true; +	bool drag_action = false; +	bool drag_caret_force_displayed = false; +  	Ref<Texture2D> right_icon;  	bool flat = false; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 1ecc3c762a..48a672b310 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1515,8 +1515,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {  			if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MouseButton::LEFT) {  				// Alternate drop use (when using force_drag(), as proposed by #5342). +				gui.drag_successful = false;  				if (gui.mouse_focus) { -					_gui_drop(gui.mouse_focus, pos, false); +					gui.drag_successful = _gui_drop(gui.mouse_focus, pos, false);  				}  				gui.drag_data = Variant(); @@ -1534,8 +1535,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {  			_gui_cancel_tooltip();  		} else {  			if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MouseButton::LEFT) { +				gui.drag_successful = false;  				if (gui.drag_mouse_over) { -					_gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false); +					gui.drag_successful = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false);  				}  				Control *drag_preview = _gui_get_drag_preview(); @@ -2895,6 +2897,10 @@ bool Viewport::gui_is_dragging() const {  	return gui.dragging;  } +bool Viewport::gui_is_drag_successful() const { +	return gui.drag_successful; +} +  void Viewport::set_input_as_handled() {  	_drop_physics_mouseover(); @@ -3534,6 +3540,7 @@ void Viewport::_bind_methods() {  	ClassDB::bind_method(D_METHOD("gui_get_drag_data"), &Viewport::gui_get_drag_data);  	ClassDB::bind_method(D_METHOD("gui_is_dragging"), &Viewport::gui_is_dragging); +	ClassDB::bind_method(D_METHOD("gui_is_drag_successful"), &Viewport::gui_is_drag_successful);  	ClassDB::bind_method(D_METHOD("set_disable_input", "disable"), &Viewport::set_disable_input);  	ClassDB::bind_method(D_METHOD("is_input_disabled"), &Viewport::is_input_disabled); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 5320aea02a..11b76b32eb 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -348,6 +348,7 @@ private:  		List<Control *> roots;  		int canvas_sort_index = 0; //for sorting items with canvas as root  		bool dragging = false; +		bool drag_successful = false;  		bool embed_subwindows_hint = false;  		bool embedding_subwindows = false; @@ -556,6 +557,7 @@ public:  	bool is_handling_input_locally() const;  	bool gui_is_dragging() const; +	bool gui_is_drag_successful() const;  	Control *gui_find_control(const Point2 &p_global); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 29aca6b321..d31771e71a 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -335,7 +335,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {  						bt->values.write[i].value.in_handle.y = rv[i * 6 + 2];  						bt->values.write[i].value.out_handle.x = rv[i * 6 + 3];  						bt->values.write[i].value.out_handle.y = rv[i * 6 + 4]; -						bt->values.write[i].value.handle_mode = (HandleMode)rv[i * 6 + 5]; +						bt->values.write[i].value.handle_mode = static_cast<HandleMode>((int)rv[i * 6 + 5]);  					}  				} @@ -1634,7 +1634,7 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke  			k.value.in_handle.y = arr[2];  			k.value.out_handle.x = arr[3];  			k.value.out_handle.y = arr[4]; -			k.value.handle_mode = (HandleMode) int(arr[5]); +			k.value.handle_mode = static_cast<HandleMode>((int)arr[5]);  			_insert(p_time, bt->values, k);  		} break; @@ -2155,7 +2155,7 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p  			bt->values.write[p_key_idx].value.in_handle.y = arr[2];  			bt->values.write[p_key_idx].value.out_handle.x = arr[3];  			bt->values.write[p_key_idx].value.out_handle.y = arr[4]; -			bt->values.write[p_key_idx].value.handle_mode = (HandleMode) int(arr[5]); +			bt->values.write[p_key_idx].value.handle_mode = static_cast<HandleMode>((int)arr[5]);  		} break;  		case TYPE_AUDIO: { diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index d9de47afc7..6cd42e1456 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -88,6 +88,9 @@ void FontData::_bind_methods() {  	ClassDB::bind_method(D_METHOD("set_msdf_size", "msdf_size"), &FontData::set_msdf_size);  	ClassDB::bind_method(D_METHOD("get_msdf_size"), &FontData::get_msdf_size); +	ClassDB::bind_method(D_METHOD("set_fixed_size", "fixed_size"), &FontData::set_fixed_size); +	ClassDB::bind_method(D_METHOD("get_fixed_size"), &FontData::get_fixed_size); +  	ClassDB::bind_method(D_METHOD("set_force_autohinter", "force_autohinter"), &FontData::set_force_autohinter);  	ClassDB::bind_method(D_METHOD("is_force_autohinter"), &FontData::is_force_autohinter); diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index ed9ccd168d..ff388e288c 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -564,10 +564,10 @@ void PhysicalSkyMaterial::_update_shader() {  shader_type sky;  uniform float rayleigh : hint_range(0, 64) = 2.0; -uniform vec4 rayleigh_color : hint_color = vec4(0.056, 0.14, 0.3, 1.0); +uniform vec4 rayleigh_color : hint_color = vec4(0.26, 0.41, 0.58, 1.0);  uniform float mie : hint_range(0, 1) = 0.005;  uniform float mie_eccentricity : hint_range(-1, 1) = 0.8; -uniform vec4 mie_color : hint_color = vec4(0.36, 0.56, 0.82, 1.0); +uniform vec4 mie_color : hint_color = vec4(0.63, 0.77, 0.92, 1.0);  uniform float turbidity : hint_range(0, 1000) = 10.0;  uniform float sun_disk_scale : hint_range(0, 360) = 1.0; @@ -661,10 +661,10 @@ void sky() {  PhysicalSkyMaterial::PhysicalSkyMaterial() {  	set_rayleigh_coefficient(2.0); -	set_rayleigh_color(Color(0.056, 0.14, 0.3)); +	set_rayleigh_color(Color(0.26, 0.41, 0.58));  	set_mie_coefficient(0.005);  	set_mie_eccentricity(0.8); -	set_mie_color(Color(0.36, 0.56, 0.82)); +	set_mie_color(Color(0.63, 0.77, 0.92));  	set_turbidity(10.0);  	set_sun_disk_scale(1.0);  	set_ground_color(Color(1.0, 1.0, 1.0)); diff --git a/thirdparty/README.md b/thirdparty/README.md index 18da4d6a63..6ebcffb7ae 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -333,7 +333,7 @@ File extracted from upstream release tarball:  ## meshoptimizer  - Upstream: https://github.com/zeux/meshoptimizer -- Version: git (f5d83e879c48f8664783a69b4f50711d27549b66, 2021) +- Version: git (f4c356d79fadb99cbf432f7e199d823581b0e19e, 2021)  - License: MIT  Files extracted from upstream repository: diff --git a/thirdparty/meshoptimizer/clusterizer.cpp b/thirdparty/meshoptimizer/clusterizer.cpp index f8aad7b49c..b1f7b359c1 100644 --- a/thirdparty/meshoptimizer/clusterizer.cpp +++ b/thirdparty/meshoptimizer/clusterizer.cpp @@ -368,8 +368,7 @@ static size_t kdtreeBuild(size_t offset, KDNode* nodes, size_t node_count, const  	}  	// split axis is one where the variance is largest -	unsigned int axis = vars[0] >= vars[1] && vars[0] >= vars[2] ? 0 : vars[1] >= vars[2] ? 1 -	                                                                                      : 2; +	unsigned int axis = vars[0] >= vars[1] && vars[0] >= vars[2] ? 0 : vars[1] >= vars[2] ? 1 : 2;  	float split = mean[axis];  	size_t middle = kdtreePartition(indices, count, points, stride, axis, split); diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h index e44b99ce52..a420eb1098 100644 --- a/thirdparty/meshoptimizer/meshoptimizer.h +++ b/thirdparty/meshoptimizer/meshoptimizer.h @@ -278,9 +278,30 @@ MESHOPTIMIZER_API int meshopt_decodeVertexBuffer(void* destination, size_t verte   * meshopt_decodeFilterExp decodes exponential encoding of floating-point data with 8-bit exponent and 24-bit integer mantissa as 2^E*M.   * Each 32-bit component is decoded in isolation; stride must be divisible by 4.   */ -MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterOct(void* buffer, size_t vertex_count, size_t vertex_size); -MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterQuat(void* buffer, size_t vertex_count, size_t vertex_size); -MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterExp(void* buffer, size_t vertex_count, size_t vertex_size); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterOct(void* buffer, size_t count, size_t stride); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterQuat(void* buffer, size_t count, size_t stride); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterExp(void* buffer, size_t count, size_t stride); + +/** + * Vertex buffer filter encoders + * These functions can be used to encode data in a format that meshopt_decodeFilter can decode + *  + * meshopt_encodeFilterOct encodes unit vectors with K-bit (K <= 16) signed X/Y as an output. + * Each component is stored as an 8-bit or 16-bit normalized integer; stride must be equal to 4 or 8. W is preserved as is. + * Input data must contain 4 floats for every vector (count*4 total). + *  + * meshopt_encodeFilterQuat encodes unit quaternions with K-bit (4 <= K <= 16) component encoding. + * Each component is stored as an 16-bit integer; stride must be equal to 8. + * Input data must contain 4 floats for every quaternion (count*4 total). + *  + * meshopt_encodeFilterExp encodes arbitrary (finite) floating-point data with 8-bit exponent and K-bit integer mantissa (1 <= K <= 24). + * Mantissa is shared between all components of a given vector as defined by stride; stride must be divisible by 4. + * Input data must contain stride/4 floats for every vector (count*stride/4 total). + * When individual (scalar) encoding is desired, simply pass stride=4 and adjust count accordingly. + */ +MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeFilterOct(void* destination, size_t count, size_t stride, int bits, const float* data); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeFilterQuat(void* destination, size_t count, size_t stride, int bits, const float* data); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeFilterExp(void* destination, size_t count, size_t stride, int bits, const float* data);  /**   * Experimental: Mesh simplifier @@ -305,7 +326,7 @@ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* d  /**   * Experimental: Mesh simplifier (sloppy) - * Reduces the number of triangles in the mesh, sacrificing mesh apperance for simplification performance + * Reduces the number of triangles in the mesh, sacrificing mesh appearance for simplification performance   * The algorithm doesn't preserve mesh topology but can stop short of the target goal based on target error.   * Returns the number of indices after simplification, with destination containing new index data   * The resulting index buffer references vertices from the original vertex buffer. diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp index cf5db4e119..ccc99edb1a 100644 --- a/thirdparty/meshoptimizer/simplifier.cpp +++ b/thirdparty/meshoptimizer/simplifier.cpp @@ -358,7 +358,7 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned  #if TRACE  	printf("locked: many open edges %d, disconnected seam %d, many seam edges %d, many wedges %d\n", -	       int(stats[0]), int(stats[1]), int(stats[2]), int(stats[3])); +	    int(stats[0]), int(stats[1]), int(stats[2]), int(stats[3]));  #endif  } @@ -1114,8 +1114,8 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char*  	float error_goal_perfect = edge_collapse_goal < collapse_count ? collapses[collapse_order[edge_collapse_goal]].error : 0.f;  	printf("removed %d triangles, error %e (goal %e); evaluated %d/%d collapses (done %d, skipped %d, invalid %d)\n", -		int(triangle_collapses), sqrtf(result_error), sqrtf(error_goal_perfect), -		int(stats[0]), int(collapse_count), int(edge_collapses), int(stats[1]), int(stats[2])); +	    int(triangle_collapses), sqrtf(result_error), sqrtf(error_goal_perfect), +	    int(stats[0]), int(collapse_count), int(edge_collapses), int(stats[1]), int(stats[2]));  #endif  	return edge_collapses; @@ -1473,7 +1473,7 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned  		kinds[vertex_kind[i]] += remap[i] == i;  	printf("kinds: manifold %d, border %d, seam %d, complex %d, locked %d\n", -	       int(kinds[Kind_Manifold]), int(kinds[Kind_Border]), int(kinds[Kind_Seam]), int(kinds[Kind_Complex]), int(kinds[Kind_Locked])); +	    int(kinds[Kind_Manifold]), int(kinds[Kind_Border]), int(kinds[Kind_Seam]), int(kinds[Kind_Complex]), int(kinds[Kind_Locked]));  #endif  	Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count); @@ -1649,9 +1649,9 @@ size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* ind  #if TRACE  		printf("pass %d (%s): grid size %d, triangles %d, %s\n", -		       pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary", -		       grid_size, int(triangles), -		       (triangles <= target_index_count / 3) ? "under" : "over"); +		    pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary", +		    grid_size, int(triangles), +		    (triangles <= target_index_count / 3) ? "under" : "over");  #endif  		float tip = interpolate(float(target_index_count / 3), float(min_grid), float(min_triangles), float(grid_size), float(triangles), float(max_grid), float(max_triangles)); @@ -1778,9 +1778,9 @@ size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_pos  #if TRACE  		printf("pass %d (%s): grid size %d, vertices %d, %s\n", -		       pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary", -		       grid_size, int(vertices), -		       (vertices <= target_vertex_count) ? "under" : "over"); +		    pass, (pass == 0) ? "guess" : (pass <= kInterpolationPasses) ? "lerp" : "binary", +		    grid_size, int(vertices), +		    (vertices <= target_vertex_count) ? "under" : "over");  #endif  		float tip = interpolate(float(target_vertex_count), float(min_grid), float(min_vertices), float(grid_size), float(vertices), float(max_grid), float(max_vertices)); diff --git a/thirdparty/meshoptimizer/vertexcodec.cpp b/thirdparty/meshoptimizer/vertexcodec.cpp index 5f3ec204ab..7925ea862c 100644 --- a/thirdparty/meshoptimizer/vertexcodec.cpp +++ b/thirdparty/meshoptimizer/vertexcodec.cpp @@ -77,6 +77,8 @@  #endif  #ifdef SIMD_WASM +#undef __DEPRECATED +#pragma clang diagnostic ignored "-Wdeprecated-declarations"  #include <wasm_simd128.h>  #endif @@ -1028,7 +1030,7 @@ static unsigned int getCpuFeatures()  	return cpuinfo[2];  } -unsigned int cpuid = getCpuFeatures(); +static unsigned int cpuid = getCpuFeatures();  #endif  } // namespace meshopt diff --git a/thirdparty/meshoptimizer/vertexfilter.cpp b/thirdparty/meshoptimizer/vertexfilter.cpp index 39946f46ed..606a280aa9 100644 --- a/thirdparty/meshoptimizer/vertexfilter.cpp +++ b/thirdparty/meshoptimizer/vertexfilter.cpp @@ -52,6 +52,7 @@  #endif  #ifdef SIMD_WASM +#undef __DEPRECATED  #include <wasm_simd128.h>  #endif @@ -160,7 +161,8 @@ static void decodeFilterExp(unsigned int* data, size_t count)  #endif  #if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) -template <typename T> static void dispatchSimd(void (*process)(T*, size_t), T* data, size_t count, size_t stride) +template <typename T> +static void dispatchSimd(void (*process)(T*, size_t), T* data, size_t count, size_t stride)  {  	assert(stride <= 4); @@ -791,52 +793,170 @@ static void decodeFilterExpSimd(unsigned int* data, size_t count)  } // namespace meshopt -void meshopt_decodeFilterOct(void* buffer, size_t vertex_count, size_t vertex_size) +void meshopt_decodeFilterOct(void* buffer, size_t count, size_t stride)  {  	using namespace meshopt; -	assert(vertex_size == 4 || vertex_size == 8); +	assert(stride == 4 || stride == 8);  #if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) -	if (vertex_size == 4) -		dispatchSimd(decodeFilterOctSimd, static_cast<signed char*>(buffer), vertex_count, 4); +	if (stride == 4) +		dispatchSimd(decodeFilterOctSimd, static_cast<signed char*>(buffer), count, 4);  	else -		dispatchSimd(decodeFilterOctSimd, static_cast<short*>(buffer), vertex_count, 4); +		dispatchSimd(decodeFilterOctSimd, static_cast<short*>(buffer), count, 4);  #else -	if (vertex_size == 4) -		decodeFilterOct(static_cast<signed char*>(buffer), vertex_count); +	if (stride == 4) +		decodeFilterOct(static_cast<signed char*>(buffer), count);  	else -		decodeFilterOct(static_cast<short*>(buffer), vertex_count); +		decodeFilterOct(static_cast<short*>(buffer), count);  #endif  } -void meshopt_decodeFilterQuat(void* buffer, size_t vertex_count, size_t vertex_size) +void meshopt_decodeFilterQuat(void* buffer, size_t count, size_t stride)  {  	using namespace meshopt; -	assert(vertex_size == 8); -	(void)vertex_size; +	assert(stride == 8); +	(void)stride;  #if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) -	dispatchSimd(decodeFilterQuatSimd, static_cast<short*>(buffer), vertex_count, 4); +	dispatchSimd(decodeFilterQuatSimd, static_cast<short*>(buffer), count, 4);  #else -	decodeFilterQuat(static_cast<short*>(buffer), vertex_count); +	decodeFilterQuat(static_cast<short*>(buffer), count);  #endif  } -void meshopt_decodeFilterExp(void* buffer, size_t vertex_count, size_t vertex_size) +void meshopt_decodeFilterExp(void* buffer, size_t count, size_t stride)  {  	using namespace meshopt; -	assert(vertex_size % 4 == 0); +	assert(stride > 0 && stride % 4 == 0);  #if defined(SIMD_SSE) || defined(SIMD_NEON) || defined(SIMD_WASM) -	dispatchSimd(decodeFilterExpSimd, static_cast<unsigned int*>(buffer), vertex_count * (vertex_size / 4), 1); +	dispatchSimd(decodeFilterExpSimd, static_cast<unsigned int*>(buffer), count * (stride / 4), 1);  #else -	decodeFilterExp(static_cast<unsigned int*>(buffer), vertex_count * (vertex_size / 4)); +	decodeFilterExp(static_cast<unsigned int*>(buffer), count * (stride / 4));  #endif  } +void meshopt_encodeFilterOct(void* destination, size_t count, size_t stride, int bits, const float* data) +{ +	assert(stride == 4 || stride == 8); +	assert(bits >= 1 && bits <= 16); + +	signed char* d8 = static_cast<signed char*>(destination); +	short* d16 = static_cast<short*>(destination); + +	int bytebits = int(stride * 2); + +	for (size_t i = 0; i < count; ++i) +	{ +		const float* n = &data[i * 4]; + +		// octahedral encoding of a unit vector +		float nx = n[0], ny = n[1], nz = n[2], nw = n[3]; +		float nl = fabsf(nx) + fabsf(ny) + fabsf(nz); +		float ns = nl == 0.f ? 0.f : 1.f / nl; + +		nx *= ns; +		ny *= ns; + +		float u = (nz >= 0.f) ? nx : (1 - fabsf(ny)) * (nx >= 0.f ? 1.f : -1.f); +		float v = (nz >= 0.f) ? ny : (1 - fabsf(nx)) * (ny >= 0.f ? 1.f : -1.f); + +		int fu = meshopt_quantizeSnorm(u, bits); +		int fv = meshopt_quantizeSnorm(v, bits); +		int fo = meshopt_quantizeSnorm(1.f, bits); +		int fw = meshopt_quantizeSnorm(nw, bytebits); + +		if (stride == 4) +		{ +			d8[i * 4 + 0] = (signed char)(fu); +			d8[i * 4 + 1] = (signed char)(fv); +			d8[i * 4 + 2] = (signed char)(fo); +			d8[i * 4 + 3] = (signed char)(fw); +		} +		else +		{ +			d16[i * 4 + 0] = short(fu); +			d16[i * 4 + 1] = short(fv); +			d16[i * 4 + 2] = short(fo); +			d16[i * 4 + 3] = short(fw); +		} +	} +} + +void meshopt_encodeFilterQuat(void* destination_, size_t count, size_t stride, int bits, const float* data) +{ +	assert(stride == 8); +	assert(bits >= 4 && bits <= 16); +	(void)stride; + +	short* destination = static_cast<short*>(destination_); + +	const float scaler = sqrtf(2.f); + +	for (size_t i = 0; i < count; ++i) +	{ +		const float* q = &data[i * 4]; +		short* d = &destination[i * 4]; + +		// establish maximum quaternion component +		int qc = 0; +		qc = fabsf(q[1]) > fabsf(q[qc]) ? 1 : qc; +		qc = fabsf(q[2]) > fabsf(q[qc]) ? 2 : qc; +		qc = fabsf(q[3]) > fabsf(q[qc]) ? 3 : qc; + +		// we use double-cover properties to discard the sign +		float sign = q[qc] < 0.f ? -1.f : 1.f; + +		// note: we always encode a cyclical swizzle to be able to recover the order via rotation +		d[0] = short(meshopt_quantizeSnorm(q[(qc + 1) & 3] * scaler * sign, bits)); +		d[1] = short(meshopt_quantizeSnorm(q[(qc + 2) & 3] * scaler * sign, bits)); +		d[2] = short(meshopt_quantizeSnorm(q[(qc + 3) & 3] * scaler * sign, bits)); +		d[3] = short((meshopt_quantizeSnorm(1.f, bits) & ~3) | qc); +	} +} + +void meshopt_encodeFilterExp(void* destination_, size_t count, size_t stride, int bits, const float* data) +{ +	assert(stride > 0 && stride % 4 == 0); +	assert(bits >= 1 && bits <= 24); + +	unsigned int* destination = static_cast<unsigned int*>(destination_); +	size_t stride_float = stride / sizeof(float); + +	for (size_t i = 0; i < count; ++i) +	{ +		const float* v = &data[i * stride_float]; +		unsigned int* d = &destination[i * stride_float]; + +		// use maximum exponent to encode values; this guarantess that mantissa is [-1, 1] +		int exp = -100; + +		for (size_t j = 0; j < stride_float; ++j) +		{ +			int e; +			frexp(v[j], &e); + +			exp = (exp < e) ? e : exp; +		} + +		// note that we additionally scale the mantissa to make it a K-bit signed integer (K-1 bits for magnitude) +		exp -= (bits - 1); + +		// compute renormalized rounded mantissa for each component +		int mmask = (1 << 24) - 1; + +		for (size_t j = 0; j < stride_float; ++j) +		{ +			int m = int(ldexp(v[j], -exp) + (v[j] >= 0 ? 0.5f : -0.5f)); + +			d[j] = (m & mmask) | (unsigned(exp) << 24); +		} +	} +} +  #undef SIMD_SSE  #undef SIMD_NEON  #undef SIMD_WASM  |