diff options
| -rw-r--r-- | core/string/ustring.cpp | 33 | ||||
| -rw-r--r-- | doc/classes/NavigationRegion2D.xml | 8 | ||||
| -rw-r--r-- | doc/classes/NavigationRegion3D.xml | 6 | ||||
| -rw-r--r-- | drivers/gles3/storage/material_storage.cpp | 68 | ||||
| -rw-r--r-- | editor/editor_about.cpp | 1 | ||||
| -rw-r--r-- | modules/noise/noise.cpp | 4 | ||||
| -rw-r--r-- | scene/2d/navigation_region_2d.cpp | 6 | ||||
| -rw-r--r-- | scene/2d/navigation_region_2d.h | 2 | ||||
| -rw-r--r-- | scene/3d/navigation_region_3d.cpp | 6 | ||||
| -rw-r--r-- | scene/3d/navigation_region_3d.h | 2 | ||||
| -rw-r--r-- | scene/animation/tween.cpp | 25 | ||||
| -rw-r--r-- | scene/animation/tween.h | 3 | ||||
| -rw-r--r-- | servers/rendering/renderer_rd/effects/tone_mapper.cpp | 26 | ||||
| -rw-r--r-- | servers/rendering/renderer_rd/storage_rd/material_storage.cpp | 68 | ||||
| -rw-r--r-- | servers/rendering/shader_language.cpp | 42 | ||||
| -rw-r--r-- | tests/core/string/test_string.h | 40 | 
16 files changed, 258 insertions, 82 deletions
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index a2b1e4c428..5d998d22d4 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -4427,7 +4427,7 @@ String String::sprintf(const Array &values, bool *error) const {  	int min_chars = 0;  	int min_decimals = 0;  	bool in_decimals = false; -	bool pad_with_zeroes = false; +	bool pad_with_zeros = false;  	bool left_justified = false;  	bool show_sign = false; @@ -4480,7 +4480,7 @@ String String::sprintf(const Array &values, bool *error) const {  					// Padding.  					int pad_chars_count = (value < 0 || show_sign) ? min_chars - 1 : min_chars; -					String pad_char = pad_with_zeroes ? String("0") : String(" "); +					String pad_char = pad_with_zeros ? String("0") : String(" ");  					if (left_justified) {  						str = str.rpad(pad_chars_count, pad_char);  					} else { @@ -4488,10 +4488,13 @@ String String::sprintf(const Array &values, bool *error) const {  					}  					// Sign. -					if (show_sign && value >= 0) { -						str = str.insert(pad_with_zeroes ? 0 : str.length() - number_len, "+"); -					} else if (value < 0) { -						str = str.insert(pad_with_zeroes ? 0 : str.length() - number_len, "-"); +					if (show_sign || value < 0) { +						String sign_char = value < 0 ? "-" : "+"; +						if (left_justified) { +							str = str.insert(0, sign_char); +						} else { +							str = str.insert(pad_with_zeros ? 0 : str.length() - number_len, sign_char); +						}  					}  					formatted += str; @@ -4520,13 +4523,9 @@ String String::sprintf(const Array &values, bool *error) const {  					// Padding. Leave room for sign later if required.  					int pad_chars_count = (is_negative || show_sign) ? min_chars - 1 : min_chars; -					String pad_char = pad_with_zeroes ? String("0") : String(" "); +					String pad_char = pad_with_zeros ? String("0") : String(" ");  					if (left_justified) { -						if (pad_with_zeroes) { -							return "left justification cannot be used with zeros as the padding"; -						} else { -							str = str.rpad(pad_chars_count, pad_char); -						} +						str = str.rpad(pad_chars_count, pad_char);  					} else {  						str = str.lpad(pad_chars_count, pad_char);  					} @@ -4537,7 +4536,7 @@ String String::sprintf(const Array &values, bool *error) const {  						if (left_justified) {  							str = str.insert(0, sign_char);  						} else { -							str = str.insert(pad_with_zeroes ? 0 : str.length() - initial_len, sign_char); +							str = str.insert(pad_with_zeros ? 0 : str.length() - initial_len, sign_char);  						}  					} @@ -4626,7 +4625,11 @@ String String::sprintf(const Array &values, bool *error) const {  						min_decimals += n;  					} else {  						if (c == '0' && min_chars == 0) { -							pad_with_zeroes = true; +							if (left_justified) { +								WARN_PRINT("'0' flag ignored with '-' flag in string format"); +							} else { +								pad_with_zeros = true; +							}  						} else {  							min_chars *= 10;  							min_chars += n; @@ -4675,7 +4678,7 @@ String String::sprintf(const Array &values, bool *error) const {  					// Back to defaults:  					min_chars = 0;  					min_decimals = 6; -					pad_with_zeroes = false; +					pad_with_zeros = false;  					left_justified = false;  					show_sign = false;  					in_decimals = false; diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml index b1165174a2..5cd2e035b6 100644 --- a/doc/classes/NavigationRegion2D.xml +++ b/doc/classes/NavigationRegion2D.xml @@ -10,6 +10,14 @@  	</description>  	<tutorials>  	</tutorials> +	<methods> +		<method name="get_region_rid" qualifiers="const"> +			<return type="RID" /> +			<description> +				Returns the [RID] of this region on the [NavigationServer2D]. Combined with [method NavigationServer2D.map_get_closest_point_owner] can be used to identify the [NavigationRegion2D] closest to a point on the merged navigation map. +			</description> +		</method> +	</methods>  	<members>  		<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">  			Determines if the [NavigationRegion2D] is enabled or disabled. diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml index e007633a1e..b27410ed74 100644 --- a/doc/classes/NavigationRegion3D.xml +++ b/doc/classes/NavigationRegion3D.xml @@ -16,6 +16,12 @@  				Bakes the [NavigationMesh]. The baking is done in a separate thread because navigation baking is not a cheap operation. This can be done at runtime. When it is completed, it automatically sets the new [NavigationMesh].  			</description>  		</method> +		<method name="get_region_rid" qualifiers="const"> +			<return type="RID" /> +			<description> +				Returns the [RID] of this region on the [NavigationServer3D]. Combined with [method NavigationServer3D.map_get_closest_point_owner] can be used to identify the [NavigationRegion3D] closest to a point on the merged navigation map. +			</description> +		</method>  	</methods>  	<members>  		<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true"> diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index fae23980b6..1b97e268df 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -392,26 +392,60 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy  			float *gui = (float *)data;  			if (p_array_size > 0) { -				const PackedVector3Array &a = value; -				int s = a.size(); +				if (value.get_type() == Variant::PACKED_COLOR_ARRAY) { +					const PackedColorArray &a = value; +					int s = a.size(); -				for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { -					if (i < s) { -						gui[j] = a[i].x; -						gui[j + 1] = a[i].y; -						gui[j + 2] = a[i].z; -					} else { -						gui[j] = 0; -						gui[j + 1] = 0; -						gui[j + 2] = 0; +					for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { +						if (i < s) { +							Color color = a[i]; +							if (p_linear_color) { +								color = color.srgb_to_linear(); +							} +							gui[j] = color.r; +							gui[j + 1] = color.g; +							gui[j + 2] = color.b; +						} else { +							gui[j] = 0; +							gui[j + 1] = 0; +							gui[j + 2] = 0; +						} +						gui[j + 3] = 0; // ignored +					} +				} else { +					const PackedVector3Array &a = value; +					int s = a.size(); + +					for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { +						if (i < s) { +							gui[j] = a[i].x; +							gui[j + 1] = a[i].y; +							gui[j + 2] = a[i].z; +						} else { +							gui[j] = 0; +							gui[j + 1] = 0; +							gui[j + 2] = 0; +						} +						gui[j + 3] = 0; // ignored  					} -					gui[j + 3] = 0; // ignored  				}  			} else { -				Vector3 v = value; -				gui[0] = v.x; -				gui[1] = v.y; -				gui[2] = v.z; +				if (value.get_type() == Variant::COLOR) { +					Color v = value; + +					if (p_linear_color) { +						v = v.srgb_to_linear(); +					} + +					gui[0] = v.r; +					gui[1] = v.g; +					gui[2] = v.b; +				} else { +					Vector3 v = value; +					gui[0] = v.x; +					gui[1] = v.y; +					gui[2] = v.z; +				}  			}  		} break;  		case ShaderLanguage::TYPE_VEC4: { @@ -925,7 +959,7 @@ void MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::S  			//value=E.value.default_value;  		} else {  			//zero because it was not provided -			if (E.value.type == ShaderLanguage::TYPE_VEC4 && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { +			if ((E.value.type == ShaderLanguage::TYPE_VEC3 || E.value.type == ShaderLanguage::TYPE_VEC4) && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {  				//colors must be set as black, with alpha as 1.0  				_fill_std140_variant_ubo_value(E.value.type, E.value.array_size, Color(0, 0, 0, 1), data, p_use_linear_color);  			} else { diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 877af41160..cd5a4f16e4 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -129,6 +129,7 @@ EditorAbout::EditorAbout() {  	vbc->add_child(hbc);  	_logo = memnew(TextureRect); +	_logo->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);  	hbc->add_child(_logo);  	VBoxContainer *version_info_vbc = memnew(VBoxContainer); diff --git a/modules/noise/noise.cpp b/modules/noise/noise.cpp index ad3df0a016..d14b63f7c8 100644 --- a/modules/noise/noise.cpp +++ b/modules/noise/noise.cpp @@ -31,6 +31,8 @@  #include "noise.h"  Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, real_t p_blend_skirt) const { +	ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>()); +  	int skirt_width = p_width * p_blend_skirt;  	int skirt_height = p_height * p_blend_skirt;  	int src_width = p_width + skirt_width; @@ -55,6 +57,8 @@ uint8_t Noise::_alpha_blend<uint8_t>(uint8_t p_bg, uint8_t p_fg, int p_alpha) co  }  Ref<Image> Noise::get_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space) const { +	ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>()); +  	Vector<uint8_t> data;  	data.resize(p_width * p_height); diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 261d371dc4..3cc9f3f2c4 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -387,6 +387,10 @@ uint32_t NavigationRegion2D::get_layers() const {  	return NavigationServer2D::get_singleton()->region_get_layers(region);  } +RID NavigationRegion2D::get_region_rid() const { +	return region; +} +  /////////////////////////////  #ifdef TOOLS_ENABLED  Rect2 NavigationRegion2D::_edit_get_rect() const { @@ -534,6 +538,8 @@ void NavigationRegion2D::_bind_methods() {  	ClassDB::bind_method(D_METHOD("set_layers", "layers"), &NavigationRegion2D::set_layers);  	ClassDB::bind_method(D_METHOD("get_layers"), &NavigationRegion2D::get_layers); +	ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion2D::get_region_rid); +  	ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed);  	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon"); diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 487a578401..3c4a4e81d9 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -117,6 +117,8 @@ public:  	void set_layers(uint32_t p_layers);  	uint32_t get_layers() const; +	RID get_region_rid() const; +  	void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);  	Ref<NavigationPolygon> get_navigation_polygon() const; diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 215e18869a..7f6ecbebb7 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -73,6 +73,10 @@ uint32_t NavigationRegion3D::get_layers() const {  	return NavigationServer3D::get_singleton()->region_get_layers(region);  } +RID NavigationRegion3D::get_region_rid() const { +	return region; +} +  /////////////////////////////  void NavigationRegion3D::_notification(int p_what) { @@ -198,6 +202,8 @@ void NavigationRegion3D::_bind_methods() {  	ClassDB::bind_method(D_METHOD("set_layers", "layers"), &NavigationRegion3D::set_layers);  	ClassDB::bind_method(D_METHOD("get_layers"), &NavigationRegion3D::get_layers); +	ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion3D::get_region_rid); +  	ClassDB::bind_method(D_METHOD("bake_navigation_mesh"), &NavigationRegion3D::bake_navigation_mesh);  	ClassDB::bind_method(D_METHOD("_bake_finished", "nav_mesh"), &NavigationRegion3D::_bake_finished); diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index 1a50bb5f64..1c559bc31a 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -57,6 +57,8 @@ public:  	void set_layers(uint32_t p_layers);  	uint32_t get_layers() const; +	RID get_region_rid() const; +  	void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh);  	Ref<NavigationMesh> get_navigation_mesh() const; diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index c6d59e7de4..24fbc1e431 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -278,14 +278,15 @@ bool Tween::step(float p_delta) {  	bool step_active = false;  	total_time += rem_delta; +#ifdef DEBUG_ENABLED +	float initial_delta = rem_delta; +	bool potential_infinite = false; +#endif +  	while (rem_delta > 0 && running) {  		float step_delta = rem_delta;  		step_active = false; -#ifdef DEBUG_ENABLED -		float prev_delta = rem_delta; -#endif -  		for (Ref<Tweener> &tweener : tweeners.write[current_step]) {  			// Modified inside Tweener.step().  			float temp_delta = rem_delta; @@ -310,17 +311,21 @@ bool Tween::step(float p_delta) {  					emit_signal(SNAME("loop_finished"), loops_done);  					current_step = 0;  					start_tweeners(); +#ifdef DEBUG_ENABLED +					if (loops <= 0 && Math::is_equal_approx(rem_delta, initial_delta)) { +						if (!potential_infinite) { +							potential_infinite = true; +						} else { +							// Looped twice without using any time, this is 100% certain infinite loop. +							ERR_FAIL_V_MSG(false, "Infinite loop detected. Check set_loops() description for more info."); +						} +					} +#endif  				}  			} else {  				start_tweeners();  			}  		} - -#ifdef DEBUG_ENABLED -		if (Math::is_equal_approx(rem_delta, prev_delta) && running && loops <= 0) { -			ERR_FAIL_V_MSG(false, "Infinite loop detected. Check set_loops() description for more info."); -		} -#endif  	}  	return true; diff --git a/scene/animation/tween.h b/scene/animation/tween.h index 5c1567d510..40268405cf 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -116,6 +116,9 @@ private:  	bool valid = false;  	bool default_parallel = false;  	bool parallel_enabled = false; +#ifdef DEBUG_ENABLED +	bool is_infinite = false; +#endif  	typedef real_t (*interpolater)(real_t t, real_t b, real_t c, real_t d);  	static interpolater interpolaters[TRANS_MAX][EASE_MAX]; diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp index 7eb15f418b..e5642116bb 100644 --- a/servers/rendering/renderer_rd/effects/tone_mapper.cpp +++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp @@ -151,37 +151,37 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton  		mode += 6;  	} -	RID default_shader = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -	RID default_mipmap_shader = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +	RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +	RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);  	RD::Uniform u_source_color;  	u_source_color.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;  	u_source_color.binding = 0; -	u_source_color.append_id(default_shader); +	u_source_color.append_id(default_sampler);  	u_source_color.append_id(p_source_color);  	RD::Uniform u_exposure_texture;  	u_exposure_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;  	u_exposure_texture.binding = 0; -	u_exposure_texture.append_id(default_shader); +	u_exposure_texture.append_id(default_sampler);  	u_exposure_texture.append_id(p_settings.exposure_texture);  	RD::Uniform u_glow_texture;  	u_glow_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;  	u_glow_texture.binding = 0; -	u_glow_texture.append_id(default_mipmap_shader); +	u_glow_texture.append_id(default_mipmap_sampler);  	u_glow_texture.append_id(p_settings.glow_texture);  	RD::Uniform u_glow_map;  	u_glow_map.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;  	u_glow_map.binding = 1; -	u_glow_map.append_id(default_mipmap_shader); +	u_glow_map.append_id(default_mipmap_sampler);  	u_glow_map.append_id(p_settings.glow_map);  	RD::Uniform u_color_correction_texture;  	u_color_correction_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;  	u_color_correction_texture.binding = 0; -	u_color_correction_texture.append_id(default_shader); +	u_color_correction_texture.append_id(default_sampler);  	u_color_correction_texture.append_id(p_settings.color_correction_texture);  	RID shader = tonemap.shader.version_get_shader(tonemap.shader_version, mode); @@ -233,8 +233,8 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col  	tonemap.push_constant.use_debanding = p_settings.use_debanding;  	tonemap.push_constant.luminance_multiplier = p_settings.luminance_multiplier; -	RID default_shader = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); -	RID default_mipmap_shader = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +	RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); +	RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);  	RD::Uniform u_source_color;  	u_source_color.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT; @@ -244,25 +244,25 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col  	RD::Uniform u_exposure_texture;  	u_exposure_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;  	u_exposure_texture.binding = 0; -	u_exposure_texture.append_id(default_shader); +	u_exposure_texture.append_id(default_sampler);  	u_exposure_texture.append_id(p_settings.exposure_texture);  	RD::Uniform u_glow_texture;  	u_glow_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;  	u_glow_texture.binding = 0; -	u_glow_texture.append_id(default_mipmap_shader); +	u_glow_texture.append_id(default_mipmap_sampler);  	u_glow_texture.append_id(p_settings.glow_texture);  	RD::Uniform u_glow_map;  	u_glow_map.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;  	u_glow_map.binding = 1; -	u_glow_map.append_id(default_mipmap_shader); +	u_glow_map.append_id(default_mipmap_sampler);  	u_glow_map.append_id(p_settings.glow_map);  	RD::Uniform u_color_correction_texture;  	u_color_correction_texture.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;  	u_color_correction_texture.binding = 0; -	u_color_correction_texture.append_id(default_shader); +	u_color_correction_texture.append_id(default_sampler);  	u_color_correction_texture.append_id(p_settings.color_correction_texture);  	RID shader = tonemap.shader.version_get_shader(tonemap.shader_version, mode); diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index d939a0d641..c3747ffabc 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -388,26 +388,60 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy  			float *gui = reinterpret_cast<float *>(data);  			if (p_array_size > 0) { -				const PackedVector3Array &a = value; -				int s = a.size(); +				if (value.get_type() == Variant::PACKED_COLOR_ARRAY) { +					const PackedColorArray &a = value; +					int s = a.size(); -				for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { -					if (i < s) { -						gui[j] = a[i].x; -						gui[j + 1] = a[i].y; -						gui[j + 2] = a[i].z; -					} else { -						gui[j] = 0; -						gui[j + 1] = 0; -						gui[j + 2] = 0; +					for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { +						if (i < s) { +							Color color = a[i]; +							if (p_linear_color) { +								color = color.srgb_to_linear(); +							} +							gui[j] = color.r; +							gui[j + 1] = color.g; +							gui[j + 2] = color.b; +						} else { +							gui[j] = 0; +							gui[j + 1] = 0; +							gui[j + 2] = 0; +						} +						gui[j + 3] = 0; // ignored +					} +				} else { +					const PackedVector3Array &a = value; +					int s = a.size(); + +					for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { +						if (i < s) { +							gui[j] = a[i].x; +							gui[j + 1] = a[i].y; +							gui[j + 2] = a[i].z; +						} else { +							gui[j] = 0; +							gui[j + 1] = 0; +							gui[j + 2] = 0; +						} +						gui[j + 3] = 0; // ignored  					} -					gui[j + 3] = 0; // ignored  				}  			} else { -				Vector3 v = value; -				gui[0] = v.x; -				gui[1] = v.y; -				gui[2] = v.z; +				if (value.get_type() == Variant::COLOR) { +					Color v = value; + +					if (p_linear_color) { +						v = v.srgb_to_linear(); +					} + +					gui[0] = v.r; +					gui[1] = v.g; +					gui[2] = v.b; +				} else { +					Vector3 v = value; +					gui[0] = v.x; +					gui[1] = v.y; +					gui[2] = v.z; +				}  			}  		} break;  		case ShaderLanguage::TYPE_VEC4: { @@ -921,7 +955,7 @@ void MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::S  			//value=E.value.default_value;  		} else {  			//zero because it was not provided -			if (E.value.type == ShaderLanguage::TYPE_VEC4 && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { +			if ((E.value.type == ShaderLanguage::TYPE_VEC3 || E.value.type == ShaderLanguage::TYPE_VEC4) && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {  				//colors must be set as black, with alpha as 1.0  				_fill_std140_variant_ubo_value(E.value.type, E.value.array_size, Color(0, 0, 0, 1), data, p_use_linear_color);  			} else { diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 54d1a6fd8d..1fd7062d6e 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -3548,13 +3548,25 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C  				if (array_size > 0) {  					array_size *= 3; -					PackedVector3Array array = PackedVector3Array(); -					for (int i = 0; i < array_size; i += 3) { -						array.push_back(Vector3(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real)); +					if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { +						PackedColorArray array = PackedColorArray(); +						for (int i = 0; i < array_size; i += 3) { +							array.push_back(Color(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real)); +						} +						value = Variant(array); +					} else { +						PackedVector3Array array = PackedVector3Array(); +						for (int i = 0; i < array_size; i += 3) { +							array.push_back(Vector3(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real)); +						} +						value = Variant(array);  					} -					value = Variant(array);  				} else { -					value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real)); +					if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { +						value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real)); +					} else { +						value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real)); +					}  				}  				break;  			case ShaderLanguage::TYPE_VEC4: @@ -3760,9 +3772,19 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform  			break;  		case ShaderLanguage::TYPE_VEC3:  			if (p_uniform.array_size > 0) { -				pi.type = Variant::PACKED_VECTOR3_ARRAY; +				if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { +					pi.hint = PROPERTY_HINT_COLOR_NO_ALPHA; +					pi.type = Variant::PACKED_COLOR_ARRAY; +				} else { +					pi.type = Variant::PACKED_VECTOR3_ARRAY; +				}  			} else { -				pi.type = Variant::VECTOR3; +				if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { +					pi.hint = PROPERTY_HINT_COLOR_NO_ALPHA; +					pi.type = Variant::COLOR; +				} else { +					pi.type = Variant::VECTOR3; +				}  			}  			break;  		case ShaderLanguage::TYPE_VEC4: { @@ -8001,8 +8023,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct  							} else if (tk.type == TK_HINT_BLACK_ALBEDO_TEXTURE) {  								uniform2.hint = ShaderNode::Uniform::HINT_BLACK_ALBEDO;  							} else if (tk.type == TK_HINT_COLOR) { -								if (type != TYPE_VEC4) { -									_set_error(vformat(RTR("Color hint is for '%s' only."), "vec4")); +								if (type != TYPE_VEC3 && type != TYPE_VEC4) { +									_set_error(vformat(RTR("Color hint is for '%s' or '%s' only."), "vec3", "vec4"));  									return ERR_PARSE_ERROR;  								}  								uniform2.hint = ShaderNode::Uniform::HINT_COLOR; @@ -9514,7 +9536,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_  		} break;  		case COMPLETION_HINT: { -			if (completion_base == DataType::TYPE_VEC4) { +			if (completion_base == DataType::TYPE_VEC3 || completion_base == DataType::TYPE_VEC4) {  				ScriptLanguage::CodeCompletionOption option("hint_color", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);  				r_options->push_back(option);  			} else if ((completion_base == DataType::TYPE_INT || completion_base == DataType::TYPE_FLOAT) && !completion_base_array) { diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index 87016dddf6..58372a0ed6 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -636,6 +636,38 @@ TEST_CASE("[String] sprintf") {  	REQUIRE(error == false);  	CHECK(output == String("fish -5 frog")); +	// Negative int left padded with spaces. +	format = "fish %5d frog"; +	args.clear(); +	args.push_back(-5); +	output = format.sprintf(args, &error); +	REQUIRE(error == false); +	CHECK(output == String("fish    -5 frog")); + +	// Negative int left padded with zeros. +	format = "fish %05d frog"; +	args.clear(); +	args.push_back(-5); +	output = format.sprintf(args, &error); +	REQUIRE(error == false); +	CHECK(output == String("fish -0005 frog")); + +	// Negative int right padded with spaces. +	format = "fish %-5d frog"; +	args.clear(); +	args.push_back(-5); +	output = format.sprintf(args, &error); +	REQUIRE(error == false); +	CHECK(output == String("fish -5    frog")); + +	// Negative int right padded with zeros. (0 ignored) +	format = "fish %-05d frog"; +	args.clear(); +	args.push_back(-5); +	output = format.sprintf(args, &error); +	REQUIRE(error == false); +	CHECK(output == String("fish -5    frog")); +  	// Hex (lower)  	format = "fish %x frog";  	args.clear(); @@ -726,6 +758,14 @@ TEST_CASE("[String] sprintf") {  	REQUIRE(error == false);  	CHECK(output == String("fish 100 frog")); +	// Negative real right padded with zeros. (0 ignored) +	format = "fish %-011f frog"; +	args.clear(); +	args.push_back(-99.99); +	output = format.sprintf(args, &error); +	REQUIRE(error == false); +	CHECK(output == String("fish -99.990000  frog")); +  	/////// Strings.  	// String  |