diff options
92 files changed, 542 insertions, 453 deletions
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 41585943b3..afde6863a3 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -31,6 +31,7 @@ #include "class_db.h" #include "core/config/engine.h" +#include "core/object/script_language.h" #include "core/os/mutex.h" #include "core/version.h" @@ -376,7 +377,12 @@ bool ClassDB::is_virtual(const StringName &p_class) { OBJTYPE_RLOCK; ClassInfo *ti = classes.getptr(p_class); - ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'."); + if (!ti) { + if (!ScriptServer::is_global_class(p_class)) { + ERR_FAIL_V_MSG(false, "Cannot get class '" + String(p_class) + "'."); + } + return false; + } #ifdef TOOLS_ENABLED if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) { return false; @@ -1454,7 +1460,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con if (Engine::get_singleton()->has_singleton(p_class)) { c = Engine::get_singleton()->get_singleton_object(p_class); cleanup_c = false; - } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) { + } else if (ClassDB::can_instantiate(p_class)) { // Keep this condition in sync with doc_tools.cpp get_documentation_default_value. c = ClassDB::instantiate(p_class); cleanup_c = true; } diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index c86c8316fe..c6cc4cc4ac 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -1180,9 +1180,14 @@ Vector<String> String::split(const String &p_splitter, bool p_allow_empty, int p int len = length(); while (true) { - int end = find(p_splitter, from); - if (end < 0) { - end = len; + int end; + if (p_splitter.is_empty()) { + end = from + 1; + } else { + end = find(p_splitter, from); + if (end < 0) { + end = len; + } } if (p_allow_empty || (end > from)) { if (p_maxsplit <= 0) { @@ -1223,7 +1228,15 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int break; } - int left_edge = rfind(p_splitter, remaining_len - p_splitter.length()); + int left_edge; + if (p_splitter.is_empty()) { + left_edge = remaining_len - 1; + if (left_edge == 0) { + left_edge--; // Skip to the < 0 condition. + } + } else { + left_edge = rfind(p_splitter, remaining_len - p_splitter.length()); + } if (left_edge < 0) { // no more splitters, we're done diff --git a/core/string/ustring.h b/core/string/ustring.h index 4b6568a502..8af74584f3 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -345,8 +345,8 @@ public: String get_slice(String p_splitter, int p_slice) const; String get_slicec(char32_t p_splitter, int p_slice) const; - Vector<String> split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const; - Vector<String> rsplit(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const; + Vector<String> split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const; + Vector<String> rsplit(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const; Vector<String> split_spaces() const; Vector<float> split_floats(const String &p_splitter, bool p_allow_empty = true) const; Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const; diff --git a/core/variant/callable.h b/core/variant/callable.h index 0305dc55c3..32770bd663 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -73,6 +73,16 @@ public: void call_deferredp(const Variant **p_arguments, int p_argcount) const; Variant callv(const Array &p_arguments) const; + template <typename... VarArgs> + void call_deferred(VarArgs... p_args) const { + Variant args[sizeof...(p_args) + 1] = { p_args..., 0 }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + return call_deferredp(sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + Error rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const; _FORCE_INLINE_ bool is_null() const { diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 7da46a2d05..91af2bab85 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1509,8 +1509,8 @@ static void _register_variant_builtin_methods() { bind_method(String, to_camel_case, sarray(), varray()); bind_method(String, to_pascal_case, sarray(), varray()); bind_method(String, to_snake_case, sarray(), varray()); - bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0)); - bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0)); + bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0)); + bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0)); bind_method(String, split_floats, sarray("delimiter", "allow_empty"), varray(true)); bind_method(String, join, sarray("parts"), varray()); diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml index 638934bc9e..c92e39e08a 100644 --- a/doc/classes/BaseButton.xml +++ b/doc/classes/BaseButton.xml @@ -44,37 +44,38 @@ </method> </methods> <members> - <member name="action_mode" type="int" setter="set_action_mode" getter="get_action_mode" enum="BaseButton.ActionMode"> + <member name="action_mode" type="int" setter="set_action_mode" getter="get_action_mode" enum="BaseButton.ActionMode" default="1"> Determines when the button is considered clicked, one of the [enum ActionMode] constants. </member> <member name="button_group" type="ButtonGroup" setter="set_button_group" getter="get_button_group"> The [ButtonGroup] associated with the button. Not to be confused with node groups. </member> - <member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" enum="MouseButton"> + <member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" enum="MouseButton" default="1"> Binary mask to choose which mouse buttons this button will respond to. To allow both left-click and right-click, use [code]MOUSE_BUTTON_MASK_LEFT | MOUSE_BUTTON_MASK_RIGHT[/code]. </member> - <member name="button_pressed" type="bool" setter="set_pressed" getter="is_pressed"> + <member name="button_pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false"> If [code]true[/code], the button's state is pressed. Means the button is pressed down or toggled (if [member toggle_mode] is active). Only works if [member toggle_mode] is [code]true[/code]. [b]Note:[/b] Setting [member button_pressed] will result in [signal toggled] to be emitted. If you want to change the pressed state without emitting that signal, use [method set_pressed_no_signal]. </member> - <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled"> + <member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false"> If [code]true[/code], the button is in disabled state and can't be clicked or toggled. </member> - <member name="keep_pressed_outside" type="bool" setter="set_keep_pressed_outside" getter="is_keep_pressed_outside"> + <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" /> + <member name="keep_pressed_outside" type="bool" setter="set_keep_pressed_outside" getter="is_keep_pressed_outside" default="false"> If [code]true[/code], the button stays pressed when moving the cursor outside the button while pressing it. [b]Note:[/b] This property only affects the button's visual appearance. Signals will be emitted at the same moment regardless of this property's value. </member> <member name="shortcut" type="Shortcut" setter="set_shortcut" getter="get_shortcut"> [Shortcut] associated to the button. </member> - <member name="shortcut_feedback" type="bool" setter="set_shortcut_feedback" getter="is_shortcut_feedback"> + <member name="shortcut_feedback" type="bool" setter="set_shortcut_feedback" getter="is_shortcut_feedback" default="true"> If [code]true[/code], the button will appear pressed when its shortcut is activated. If [code]false[/code] and [member toggle_mode] is [code]false[/code], the shortcut will activate the button without appearing to press the button. </member> - <member name="shortcut_in_tooltip" type="bool" setter="set_shortcut_in_tooltip" getter="is_shortcut_in_tooltip_enabled"> + <member name="shortcut_in_tooltip" type="bool" setter="set_shortcut_in_tooltip" getter="is_shortcut_in_tooltip_enabled" default="true"> If [code]true[/code], the button will add information about its shortcut in the tooltip. </member> - <member name="toggle_mode" type="bool" setter="set_toggle_mode" getter="is_toggle_mode"> + <member name="toggle_mode" type="bool" setter="set_toggle_mode" getter="is_toggle_mode" default="false"> If [code]true[/code], the button is in toggle mode. Makes the button flip state between pressed and unpressed each time its area is clicked. </member> </members> diff --git a/doc/classes/CameraAttributes.xml b/doc/classes/CameraAttributes.xml index a741728c14..23dc212069 100644 --- a/doc/classes/CameraAttributes.xml +++ b/doc/classes/CameraAttributes.xml @@ -12,19 +12,19 @@ <tutorials> </tutorials> <members> - <member name="auto_exposure_enabled" type="bool" setter="set_auto_exposure_enabled" getter="is_auto_exposure_enabled"> + <member name="auto_exposure_enabled" type="bool" setter="set_auto_exposure_enabled" getter="is_auto_exposure_enabled" default="false"> If [code]true[/code], enables the tonemapping auto exposure mode of the scene renderer. If [code]true[/code], the renderer will automatically determine the exposure setting to adapt to the scene's illumination and the observed light. </member> - <member name="auto_exposure_scale" type="float" setter="set_auto_exposure_scale" getter="get_auto_exposure_scale"> + <member name="auto_exposure_scale" type="float" setter="set_auto_exposure_scale" getter="get_auto_exposure_scale" default="0.4"> The scale of the auto exposure effect. Affects the intensity of auto exposure. </member> - <member name="auto_exposure_speed" type="float" setter="set_auto_exposure_speed" getter="get_auto_exposure_speed"> + <member name="auto_exposure_speed" type="float" setter="set_auto_exposure_speed" getter="get_auto_exposure_speed" default="0.5"> The speed of the auto exposure effect. Affects the time needed for the camera to perform auto exposure. </member> - <member name="exposure_multiplier" type="float" setter="set_exposure_multiplier" getter="get_exposure_multiplier"> + <member name="exposure_multiplier" type="float" setter="set_exposure_multiplier" getter="get_exposure_multiplier" default="1.0"> Multiplier for the exposure amount. A higher value results in a brighter image. </member> - <member name="exposure_sensitivity" type="float" setter="set_exposure_sensitivity" getter="get_exposure_sensitivity"> + <member name="exposure_sensitivity" type="float" setter="set_exposure_sensitivity" getter="get_exposure_sensitivity" default="100.0"> Sensitivity of camera sensors, measured in ISO. A higher sensitivity results in a brighter image. Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled. When [member auto_exposure_enabled] this can be used as a method of exposure compensation, doubling the value will increase the exposure value (measured in EV100) by 1 stop. </member> </members> diff --git a/doc/classes/EditorFeatureProfile.xml b/doc/classes/EditorFeatureProfile.xml index 99e97fc25f..27f61f1bd8 100644 --- a/doc/classes/EditorFeatureProfile.xml +++ b/doc/classes/EditorFeatureProfile.xml @@ -116,7 +116,10 @@ <constant name="FEATURE_IMPORT_DOCK" value="6" enum="Feature"> The Import dock. If this feature is disabled, the Import dock won't be visible. </constant> - <constant name="FEATURE_MAX" value="7" enum="Feature"> + <constant name="FEATURE_HISTORY_DOCK" value="7" enum="Feature"> + The History dock. If this feature is disabled, the History dock won't be visible. + </constant> + <constant name="FEATURE_MAX" value="8" enum="Feature"> Represents the size of the [enum Feature] enum. </constant> </constants> diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml index 9961e11f7d..784a3c1214 100644 --- a/doc/classes/EditorSpinSlider.xml +++ b/doc/classes/EditorSpinSlider.xml @@ -12,6 +12,7 @@ <member name="flat" type="bool" setter="set_flat" getter="is_flat" default="false"> If [code]true[/code], the slider will not draw background. </member> + <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" /> <member name="hide_slider" type="bool" setter="set_hide_slider" getter="is_hiding_slider" default="false"> If [code]true[/code], the slider is hidden. </member> diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml index 4916171900..c7d10078e8 100644 --- a/doc/classes/GPUParticles2D.xml +++ b/doc/classes/GPUParticles2D.xml @@ -89,12 +89,17 @@ Particle texture. If [code]null[/code], particles will be squares. </member> <member name="trail_enabled" type="bool" setter="set_trail_enabled" getter="is_trail_enabled" default="false"> + If [code]true[/code], enables particle trails using a mesh skinning system. + [b]Note:[/b] Unlike [GPUParticles3D], the number of trail sections and subdivisions is set with the [member trail_sections] and [member trail_section_subdivisions] properties. </member> - <member name="trail_length_secs" type="float" setter="set_trail_length" getter="get_trail_length" default="0.3"> + <member name="trail_lifetime" type="float" setter="set_trail_lifetime" getter="get_trail_lifetime" default="0.3"> + The amount of time the particle's trail should represent (in seconds). Only effective if [member trail_enabled] is [code]true[/code]. </member> <member name="trail_section_subdivisions" type="int" setter="set_trail_section_subdivisions" getter="get_trail_section_subdivisions" default="4"> + The number of subdivisions to use for the particle trail rendering. Higher values can result in smoother trail curves, at the cost of performance due to increased mesh complexity. See also [member trail_sections]. Only effective if [member trail_enabled] is [code]true[/code]. </member> <member name="trail_sections" type="int" setter="set_trail_sections" getter="get_trail_sections" default="8"> + The number of sections to use for the particle trail rendering. Higher values can result in smoother trail curves, at the cost of performance due to increased mesh complexity. See also [member trail_section_subdivisions]. Only effective if [member trail_enabled] is [code]true[/code]. </member> <member name="visibility_rect" type="Rect2" setter="set_visibility_rect" getter="get_visibility_rect" default="Rect2(-100, -100, 200, 200)"> The [Rect2] that determines the node's region which needs to be visible on screen for the particle system to be active. diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml index d0be4d784a..ea53c5b4b5 100644 --- a/doc/classes/GPUParticles3D.xml +++ b/doc/classes/GPUParticles3D.xml @@ -116,8 +116,12 @@ <member name="sub_emitter" type="NodePath" setter="set_sub_emitter" getter="get_sub_emitter" default="NodePath("")"> </member> <member name="trail_enabled" type="bool" setter="set_trail_enabled" getter="is_trail_enabled" default="false"> + If [code]true[/code], enables particle trails using a mesh skinning system. Designed to work with [RibbonTrailMesh] and [TubeTrailMesh]. + [b]Note:[/b] [member BaseMaterial3D.use_particle_trails] must also be enabled on the particle mesh's material. Otherwise, setting [member trail_enabled] to [code]true[/code] will have no effect. + [b]Note:[/b] Unlike [GPUParticles2D], the number of trail sections and subdivisions is set in the [RibbonTrailMesh] or the [TubeTrailMesh]'s properties. </member> - <member name="trail_length_secs" type="float" setter="set_trail_length" getter="get_trail_length" default="0.3"> + <member name="trail_lifetime" type="float" setter="set_trail_lifetime" getter="get_trail_lifetime" default="0.3"> + The amount of time the particle's trail should represent (in seconds). Only effective if [member trail_enabled] is [code]true[/code]. </member> <member name="transform_align" type="int" setter="set_transform_align" getter="get_transform_align" enum="GPUParticles3D.TransformAlign" default="0"> </member> diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml index 4d8ab91718..86d52ae9be 100644 --- a/doc/classes/GeometryInstance3D.xml +++ b/doc/classes/GeometryInstance3D.xml @@ -31,22 +31,22 @@ </method> </methods> <members> - <member name="cast_shadow" type="int" setter="set_cast_shadows_setting" getter="get_cast_shadows_setting" enum="GeometryInstance3D.ShadowCastingSetting"> + <member name="cast_shadow" type="int" setter="set_cast_shadows_setting" getter="get_cast_shadows_setting" enum="GeometryInstance3D.ShadowCastingSetting" default="1"> The selected shadow casting flag. See [enum ShadowCastingSetting] for possible values. </member> - <member name="extra_cull_margin" type="float" setter="set_extra_cull_margin" getter="get_extra_cull_margin"> + <member name="extra_cull_margin" type="float" setter="set_extra_cull_margin" getter="get_extra_cull_margin" default="0.0"> The extra distance added to the GeometryInstance3D's bounding box ([AABB]) to increase its cull box. </member> - <member name="gi_lightmap_scale" type="int" setter="set_lightmap_scale" getter="get_lightmap_scale" enum="GeometryInstance3D.LightmapScale"> + <member name="gi_lightmap_scale" type="int" setter="set_lightmap_scale" getter="get_lightmap_scale" enum="GeometryInstance3D.LightmapScale" default="0"> The texel density to use for lightmapping in [LightmapGI]. Greater scale values provide higher resolution in the lightmap, which can result in sharper shadows for lights that have both direct and indirect light baked. However, greater scale values will also increase the space taken by the mesh in the lightmap texture, which increases the memory, storage, and bake time requirements. When using a single mesh at different scales, consider adjusting this value to keep the lightmap texel density consistent across meshes. </member> - <member name="gi_mode" type="int" setter="set_gi_mode" getter="get_gi_mode" enum="GeometryInstance3D.GIMode"> + <member name="gi_mode" type="int" setter="set_gi_mode" getter="get_gi_mode" enum="GeometryInstance3D.GIMode" default="1"> The global illumination mode to use for the whole geometry. To avoid inconsistent results, use a mode that matches the purpose of the mesh during gameplay (static/dynamic). [b]Note:[/b] Lights' bake mode will also affect the global illumination rendering. See [member Light3D.light_bake_mode]. </member> - <member name="ignore_occlusion_culling" type="bool" setter="set_ignore_occlusion_culling" getter="is_ignoring_occlusion_culling"> + <member name="ignore_occlusion_culling" type="bool" setter="set_ignore_occlusion_culling" getter="is_ignoring_occlusion_culling" default="false"> </member> - <member name="lod_bias" type="float" setter="set_lod_bias" getter="get_lod_bias"> + <member name="lod_bias" type="float" setter="set_lod_bias" getter="get_lod_bias" default="1.0"> </member> <member name="material_overlay" type="Material" setter="set_material_overlay" getter="get_material_overlay"> The material overlay for the whole geometry. @@ -56,26 +56,26 @@ The material override for the whole geometry. If a material is assigned to this property, it will be used instead of any material set in any material slot of the mesh. </member> - <member name="transparency" type="float" setter="set_transparency" getter="get_transparency"> + <member name="transparency" type="float" setter="set_transparency" getter="get_transparency" default="0.0"> The transparency applied to the whole geometry (as a multiplier of the materials' existing transparency). [code]0.0[/code] is fully opaque, while [code]1.0[/code] is fully transparent. Values greater than [code]0.0[/code] (exclusive) will force the geometry's materials to go through the transparent pipeline, which is slower to render and can exhibit rendering issues due to incorrect transparency sorting. However, unlike using a transparent material, setting [member transparency] to a value greater than [code]0.0[/code] (exclusive) will [i]not[/i] disable shadow rendering. In spatial shaders, [code]1.0 - transparency[/code] is set as the default value of the [code]ALPHA[/code] built-in. [b]Note:[/b] [member transparency] is clamped between [code]0.0[/code] and [code]1.0[/code], so this property cannot be used to make transparent materials more opaque than they originally are. </member> - <member name="visibility_range_begin" type="float" setter="set_visibility_range_begin" getter="get_visibility_range_begin"> + <member name="visibility_range_begin" type="float" setter="set_visibility_range_begin" getter="get_visibility_range_begin" default="0.0"> Starting distance from which the GeometryInstance3D will be visible, taking [member visibility_range_begin_margin] into account as well. The default value of 0 is used to disable the range check. </member> - <member name="visibility_range_begin_margin" type="float" setter="set_visibility_range_begin_margin" getter="get_visibility_range_begin_margin"> + <member name="visibility_range_begin_margin" type="float" setter="set_visibility_range_begin_margin" getter="get_visibility_range_begin_margin" default="0.0"> Margin for the [member visibility_range_begin] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_begin] threshold by this amount. If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_DISABLED], this acts as an hysteresis distance. If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_SELF] or [constant VISIBILITY_RANGE_FADE_DEPENDENCIES], this acts as a fade transition distance and must be set to a value greater than [code]0.0[/code] for the effect to be noticeable. </member> - <member name="visibility_range_end" type="float" setter="set_visibility_range_end" getter="get_visibility_range_end"> + <member name="visibility_range_end" type="float" setter="set_visibility_range_end" getter="get_visibility_range_end" default="0.0"> Distance from which the GeometryInstance3D will be hidden, taking [member visibility_range_end_margin] into account as well. The default value of 0 is used to disable the range check. </member> - <member name="visibility_range_end_margin" type="float" setter="set_visibility_range_end_margin" getter="get_visibility_range_end_margin"> + <member name="visibility_range_end_margin" type="float" setter="set_visibility_range_end_margin" getter="get_visibility_range_end_margin" default="0.0"> Margin for the [member visibility_range_end] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_end] threshold by this amount. If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_DISABLED], this acts as an hysteresis distance. If [member visibility_range_fade_mode] is [constant VISIBILITY_RANGE_FADE_SELF] or [constant VISIBILITY_RANGE_FADE_DEPENDENCIES], this acts as a fade transition distance and must be set to a value greater than [code]0.0[/code] for the effect to be noticeable. </member> - <member name="visibility_range_fade_mode" type="int" setter="set_visibility_range_fade_mode" getter="get_visibility_range_fade_mode" enum="GeometryInstance3D.VisibilityRangeFadeMode"> + <member name="visibility_range_fade_mode" type="int" setter="set_visibility_range_fade_mode" getter="get_visibility_range_fade_mode" enum="GeometryInstance3D.VisibilityRangeFadeMode" default="0"> Controls which instances will be faded when approaching the limits of the visibility range. See [enum VisibilityRangeFadeMode] for possible values. </member> </members> diff --git a/doc/classes/Label3D.xml b/doc/classes/Label3D.xml index b741dc6e64..0cbca2224e 100644 --- a/doc/classes/Label3D.xml +++ b/doc/classes/Label3D.xml @@ -44,6 +44,7 @@ <member name="billboard" type="int" setter="set_billboard_mode" getter="get_billboard_mode" enum="BaseMaterial3D.BillboardMode" default="0"> The billboard mode to use for the label. See [enum BaseMaterial3D.BillboardMode] for possible values. </member> + <member name="cast_shadow" type="int" setter="set_cast_shadows_setting" getter="get_cast_shadows_setting" overrides="GeometryInstance3D" enum="GeometryInstance3D.ShadowCastingSetting" default="0" /> <member name="double_sided" type="bool" setter="set_draw_flag" getter="get_draw_flag" default="true"> If [code]true[/code], text can be seen from the back as well, if [code]false[/code], it is invisible when looking at it from behind. </member> @@ -57,6 +58,7 @@ Font size of the [Label3D]'s text. To make the font look more detailed when up close, increase [member font_size] while decreasing [member pixel_size] at the same time. Higher font sizes require more time to render new characters, which can cause stuttering during gameplay. </member> + <member name="gi_mode" type="int" setter="set_gi_mode" getter="get_gi_mode" overrides="GeometryInstance3D" enum="GeometryInstance3D.GIMode" default="0" /> <member name="horizontal_alignment" type="int" setter="set_horizontal_alignment" getter="get_horizontal_alignment" enum="HorizontalAlignment" default="1"> Controls the text's horizontal alignment. Supports left, center, right, and fill, or justify. Set it to one of the [enum HorizontalAlignment] constants. </member> diff --git a/doc/classes/LinkButton.xml b/doc/classes/LinkButton.xml index 7c6ff2d4e1..d7701ea184 100644 --- a/doc/classes/LinkButton.xml +++ b/doc/classes/LinkButton.xml @@ -10,9 +10,11 @@ <tutorials> </tutorials> <members> + <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="0" /> <member name="language" type="String" setter="set_language" getter="get_language" default=""""> Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead. </member> + <member name="mouse_default_cursor_shape" type="int" setter="set_default_cursor_shape" getter="get_default_cursor_shape" overrides="Control" enum="Control.CursorShape" default="2" /> <member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="TextServer.StructuredTextParser" default="0"> Set BiDi algorithm override for the structured text. </member> diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index facbe5fd0f..640fa9efec 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -176,7 +176,7 @@ </method> </methods> <members> - <member name="lightmap_size_hint" type="Vector2i" setter="set_lightmap_size_hint" getter="get_lightmap_size_hint"> + <member name="lightmap_size_hint" type="Vector2i" setter="set_lightmap_size_hint" getter="get_lightmap_size_hint" default="Vector2i(0, 0)"> Sets a hint to be used for lightmap resolution. </member> </members> diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml index fdc3a44e9d..80afe3b784 100644 --- a/doc/classes/PhysicsDirectBodyState2D.xml +++ b/doc/classes/PhysicsDirectBodyState2D.xml @@ -207,40 +207,40 @@ </method> </methods> <members> - <member name="angular_velocity" type="float" setter="set_angular_velocity" getter="get_angular_velocity"> + <member name="angular_velocity" type="float" setter="set_angular_velocity" getter="get_angular_velocity" default="0.0"> The body's rotational velocity in [i]radians[/i] per second. </member> - <member name="center_of_mass" type="Vector2" setter="" getter="get_center_of_mass"> + <member name="center_of_mass" type="Vector2" setter="" getter="get_center_of_mass" default="Vector2(0, 0)"> The body's center of mass position relative to the body's center in the global coordinate system. </member> - <member name="center_of_mass_local" type="Vector2" setter="" getter="get_center_of_mass_local"> + <member name="center_of_mass_local" type="Vector2" setter="" getter="get_center_of_mass_local" default="Vector2(0, 0)"> The body's center of mass position in the body's local coordinate system. </member> - <member name="inverse_inertia" type="float" setter="" getter="get_inverse_inertia"> + <member name="inverse_inertia" type="float" setter="" getter="get_inverse_inertia" default="0.0"> The inverse of the inertia of the body. </member> - <member name="inverse_mass" type="float" setter="" getter="get_inverse_mass"> + <member name="inverse_mass" type="float" setter="" getter="get_inverse_mass" default="0.0"> The inverse of the mass of the body. </member> - <member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity"> + <member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector2(0, 0)"> The body's linear velocity in pixels per second. </member> - <member name="sleeping" type="bool" setter="set_sleep_state" getter="is_sleeping"> + <member name="sleeping" type="bool" setter="set_sleep_state" getter="is_sleeping" default="false"> If [code]true[/code], this body is currently sleeping (not active). </member> - <member name="step" type="float" setter="" getter="get_step"> + <member name="step" type="float" setter="" getter="get_step" default="0.0"> The timestep (delta) used for the simulation. </member> - <member name="total_angular_damp" type="float" setter="" getter="get_total_angular_damp"> + <member name="total_angular_damp" type="float" setter="" getter="get_total_angular_damp" default="0.0"> The rate at which the body stops rotating, if there are not any other forces moving it. </member> - <member name="total_gravity" type="Vector2" setter="" getter="get_total_gravity"> + <member name="total_gravity" type="Vector2" setter="" getter="get_total_gravity" default="Vector2(0, 0)"> The total gravity vector being currently applied to this body. </member> - <member name="total_linear_damp" type="float" setter="" getter="get_total_linear_damp"> + <member name="total_linear_damp" type="float" setter="" getter="get_total_linear_damp" default="0.0"> The rate at which the body stops moving, if there are not any other forces moving it. </member> - <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform"> + <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D(1, 0, 0, 1, 0, 0)"> The body's transformation matrix. </member> </members> diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml index 04087cbfb6..3266c02a1e 100644 --- a/doc/classes/PhysicsDirectBodyState3D.xml +++ b/doc/classes/PhysicsDirectBodyState3D.xml @@ -214,45 +214,45 @@ </method> </methods> <members> - <member name="angular_velocity" type="Vector3" setter="set_angular_velocity" getter="get_angular_velocity"> + <member name="angular_velocity" type="Vector3" setter="set_angular_velocity" getter="get_angular_velocity" default="Vector3(0, 0, 0)"> The body's rotational velocity in [i]radians[/i] per second. </member> - <member name="center_of_mass" type="Vector3" setter="" getter="get_center_of_mass"> + <member name="center_of_mass" type="Vector3" setter="" getter="get_center_of_mass" default="Vector3(0, 0, 0)"> The body's center of mass position relative to the body's center in the global coordinate system. </member> - <member name="center_of_mass_local" type="Vector3" setter="" getter="get_center_of_mass_local"> + <member name="center_of_mass_local" type="Vector3" setter="" getter="get_center_of_mass_local" default="Vector3(0, 0, 0)"> The body's center of mass position in the body's local coordinate system. </member> - <member name="inverse_inertia" type="Vector3" setter="" getter="get_inverse_inertia"> + <member name="inverse_inertia" type="Vector3" setter="" getter="get_inverse_inertia" default="Vector3(0, 0, 0)"> The inverse of the inertia of the body. </member> - <member name="inverse_inertia_tensor" type="Basis" setter="" getter="get_inverse_inertia_tensor"> + <member name="inverse_inertia_tensor" type="Basis" setter="" getter="get_inverse_inertia_tensor" default="Basis(1, 0, 0, 0, 1, 0, 0, 0, 1)"> The inverse of the inertia tensor of the body. </member> - <member name="inverse_mass" type="float" setter="" getter="get_inverse_mass"> + <member name="inverse_mass" type="float" setter="" getter="get_inverse_mass" default="0.0"> The inverse of the mass of the body. </member> - <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity"> + <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3(0, 0, 0)"> The body's linear velocity in units per second. </member> - <member name="principal_inertia_axes" type="Basis" setter="" getter="get_principal_inertia_axes"> + <member name="principal_inertia_axes" type="Basis" setter="" getter="get_principal_inertia_axes" default="Basis(1, 0, 0, 0, 1, 0, 0, 0, 1)"> </member> - <member name="sleeping" type="bool" setter="set_sleep_state" getter="is_sleeping"> + <member name="sleeping" type="bool" setter="set_sleep_state" getter="is_sleeping" default="false"> If [code]true[/code], this body is currently sleeping (not active). </member> - <member name="step" type="float" setter="" getter="get_step"> + <member name="step" type="float" setter="" getter="get_step" default="0.0"> The timestep (delta) used for the simulation. </member> - <member name="total_angular_damp" type="float" setter="" getter="get_total_angular_damp"> + <member name="total_angular_damp" type="float" setter="" getter="get_total_angular_damp" default="0.0"> The rate at which the body stops rotating, if there are not any other forces moving it. </member> - <member name="total_gravity" type="Vector3" setter="" getter="get_total_gravity"> + <member name="total_gravity" type="Vector3" setter="" getter="get_total_gravity" default="Vector3(0, 0, 0)"> The total gravity vector being currently applied to this body. </member> - <member name="total_linear_damp" type="float" setter="" getter="get_total_linear_damp"> + <member name="total_linear_damp" type="float" setter="" getter="get_total_linear_damp" default="0.0"> The rate at which the body stops moving, if there are not any other forces moving it. </member> - <member name="transform" type="Transform3D" setter="set_transform" getter="get_transform"> + <member name="transform" type="Transform3D" setter="set_transform" getter="get_transform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> The body's transformation matrix. </member> </members> diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml index 1b9ecdbfa0..7a411b27ac 100644 --- a/doc/classes/PrimitiveMesh.xml +++ b/doc/classes/PrimitiveMesh.xml @@ -34,10 +34,10 @@ </method> </methods> <members> - <member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb"> + <member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB(0, 0, 0, 0, 0, 0)"> Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unexpected culling when using a shader to offset vertices. </member> - <member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces"> + <member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces" default="false"> If set, the order of the vertices in each triangle are reversed resulting in the backside of the mesh being drawn. This gives the same result as using [constant BaseMaterial3D.CULL_FRONT] in [member BaseMaterial3D.cull_mode]. </member> diff --git a/doc/classes/ProgressBar.xml b/doc/classes/ProgressBar.xml index 510b8d5bd1..f8c5dc0e1f 100644 --- a/doc/classes/ProgressBar.xml +++ b/doc/classes/ProgressBar.xml @@ -15,6 +15,8 @@ <member name="show_percentage" type="bool" setter="set_show_percentage" getter="is_percentage_shown" default="true"> If [code]true[/code], the fill percentage is displayed on the bar. </member> + <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" default="0" /> + <member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="0.01" /> </members> <constants> <constant name="FILL_BEGIN_TO_END" value="0" enum="FillMode"> diff --git a/doc/classes/Range.xml b/doc/classes/Range.xml index 9764318ee4..8aa89015c6 100644 --- a/doc/classes/Range.xml +++ b/doc/classes/Range.xml @@ -38,34 +38,34 @@ </method> </methods> <members> - <member name="allow_greater" type="bool" setter="set_allow_greater" getter="is_greater_allowed"> + <member name="allow_greater" type="bool" setter="set_allow_greater" getter="is_greater_allowed" default="false"> If [code]true[/code], [member value] may be greater than [member max_value]. </member> - <member name="allow_lesser" type="bool" setter="set_allow_lesser" getter="is_lesser_allowed"> + <member name="allow_lesser" type="bool" setter="set_allow_lesser" getter="is_lesser_allowed" default="false"> If [code]true[/code], [member value] may be less than [member min_value]. </member> - <member name="exp_edit" type="bool" setter="set_exp_ratio" getter="is_ratio_exp"> + <member name="exp_edit" type="bool" setter="set_exp_ratio" getter="is_ratio_exp" default="false"> If [code]true[/code], and [code]min_value[/code] is greater than 0, [code]value[/code] will be represented exponentially rather than linearly. </member> - <member name="max_value" type="float" setter="set_max" getter="get_max"> + <member name="max_value" type="float" setter="set_max" getter="get_max" default="100.0"> Maximum value. Range is clamped if [code]value[/code] is greater than [code]max_value[/code]. </member> - <member name="min_value" type="float" setter="set_min" getter="get_min"> + <member name="min_value" type="float" setter="set_min" getter="get_min" default="0.0"> Minimum value. Range is clamped if [code]value[/code] is less than [code]min_value[/code]. </member> - <member name="page" type="float" setter="set_page" getter="get_page"> + <member name="page" type="float" setter="set_page" getter="get_page" default="0.0"> Page size. Used mainly for [ScrollBar]. ScrollBar's length is its size multiplied by [code]page[/code] over the difference between [code]min_value[/code] and [code]max_value[/code]. </member> <member name="ratio" type="float" setter="set_as_ratio" getter="get_as_ratio"> The value mapped between 0 and 1. </member> - <member name="rounded" type="bool" setter="set_use_rounded_values" getter="is_using_rounded_values"> + <member name="rounded" type="bool" setter="set_use_rounded_values" getter="is_using_rounded_values" default="false"> If [code]true[/code], [code]value[/code] will always be rounded to the nearest integer. </member> - <member name="step" type="float" setter="set_step" getter="get_step"> + <member name="step" type="float" setter="set_step" getter="get_step" default="1.0"> If greater than 0, [code]value[/code] will always be rounded to a multiple of [code]step[/code]. If [code]rounded[/code] is also [code]true[/code], [code]value[/code] will first be rounded to a multiple of [code]step[/code] then rounded to the nearest integer. </member> - <member name="value" type="float" setter="set_value" getter="get_value"> + <member name="value" type="float" setter="set_value" getter="get_value" default="0.0"> Range's current value. Changing this property (even via code) will trigger [signal value_changed] signal. Use [method set_value_no_signal] if you want to avoid it. </member> </members> diff --git a/doc/classes/ScrollBar.xml b/doc/classes/ScrollBar.xml index d0dd69408e..266787c9c8 100644 --- a/doc/classes/ScrollBar.xml +++ b/doc/classes/ScrollBar.xml @@ -12,6 +12,8 @@ <member name="custom_step" type="float" setter="set_custom_step" getter="get_custom_step" default="-1.0"> Overrides the step used when clicking increment and decrement buttons or when using arrow keys when the [ScrollBar] is focused. </member> + <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" default="0" /> + <member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="0.0" /> </members> <signals> <signal name="scrolling"> diff --git a/doc/classes/Slider.xml b/doc/classes/Slider.xml index c3dbd69e59..0e626842bd 100644 --- a/doc/classes/Slider.xml +++ b/doc/classes/Slider.xml @@ -13,9 +13,11 @@ <member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true"> If [code]true[/code], the slider can be interacted with. If [code]false[/code], the value can be changed only by code. </member> + <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="2" /> <member name="scrollable" type="bool" setter="set_scrollable" getter="is_scrollable" default="true"> If [code]true[/code], the value can be changed using the mouse wheel. </member> + <member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" default="0" /> <member name="tick_count" type="int" setter="set_ticks" getter="get_ticks" default="0"> Number of ticks displayed on the slider, including border ticks. Ticks are uniformly-distributed value markers. </member> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 1ee91b91d2..b0b4f74b46 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -634,11 +634,11 @@ </method> <method name="rsplit" qualifiers="const"> <return type="PackedStringArray" /> - <param index="0" name="delimiter" type="String" /> + <param index="0" name="delimiter" type="String" default="""" /> <param index="1" name="allow_empty" type="bool" default="true" /> <param index="2" name="maxsplit" type="int" default="0" /> <description> - Splits the string by a [param delimiter] string and returns an array of the substrings, starting from right. + Splits the string by a [param delimiter] string and returns an array of the substrings, starting from right. If [param delimiter] is an empty string, each substring will be a single character. The splits in the returned array are sorted in the same order as the original string, from left to right. If [param allow_empty] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position. If [param maxsplit] is specified, it defines the number of splits to do from the right up to [param maxsplit]. The default value of 0 means that all items are split, thus giving the same result as [method split]. @@ -710,11 +710,11 @@ </method> <method name="split" qualifiers="const"> <return type="PackedStringArray" /> - <param index="0" name="delimiter" type="String" /> + <param index="0" name="delimiter" type="String" default="""" /> <param index="1" name="allow_empty" type="bool" default="true" /> <param index="2" name="maxsplit" type="int" default="0" /> <description> - Splits the string by a [param delimiter] string and returns an array of the substrings. The [param delimiter] can be of any length. + Splits the string by a [param delimiter] string and returns an array of the substrings. The [param delimiter] can be of any length. If [param delimiter] is an empty string, each substring will be a single character. If [param allow_empty] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position. If [param maxsplit] is specified, it defines the number of splits to do from the left up to [param maxsplit]. The default value of [code]0[/code] means that all items are split. If you need only one element from the array at a specific index, [method get_slice] is a more performant option. diff --git a/doc/classes/StyleBox.xml b/doc/classes/StyleBox.xml index 8656cde4a0..ff6d4d8821 100644 --- a/doc/classes/StyleBox.xml +++ b/doc/classes/StyleBox.xml @@ -114,21 +114,21 @@ </method> </methods> <members> - <member name="content_margin_bottom" type="float" setter="set_default_margin" getter="get_default_margin"> + <member name="content_margin_bottom" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0"> The bottom margin for the contents of this style box. Increasing this value reduces the space available to the contents from the bottom. If this value is negative, it is ignored and a child-specific margin is used instead. For example for [StyleBoxFlat] the border thickness (if any) is used instead. It is up to the code using this style box to decide what these contents are: for example, a [Button] respects this content margin for the textual contents of the button. [method get_margin] should be used to fetch this value as consumer instead of reading these properties directly. This is because it correctly respects negative values and the fallback mentioned above. </member> - <member name="content_margin_left" type="float" setter="set_default_margin" getter="get_default_margin"> + <member name="content_margin_left" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0"> The left margin for the contents of this style box. Increasing this value reduces the space available to the contents from the left. Refer to [member content_margin_bottom] for extra considerations. </member> - <member name="content_margin_right" type="float" setter="set_default_margin" getter="get_default_margin"> + <member name="content_margin_right" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0"> The right margin for the contents of this style box. Increasing this value reduces the space available to the contents from the right. Refer to [member content_margin_bottom] for extra considerations. </member> - <member name="content_margin_top" type="float" setter="set_default_margin" getter="get_default_margin"> + <member name="content_margin_top" type="float" setter="set_default_margin" getter="get_default_margin" default="-1.0"> The top margin for the contents of this style box. Increasing this value reduces the space available to the contents from the top. Refer to [member content_margin_bottom] for extra considerations. </member> diff --git a/doc/classes/TextureProgressBar.xml b/doc/classes/TextureProgressBar.xml index fcdb18e10d..ded4dac7da 100644 --- a/doc/classes/TextureProgressBar.xml +++ b/doc/classes/TextureProgressBar.xml @@ -27,6 +27,7 @@ <member name="fill_mode" type="int" setter="set_fill_mode" getter="get_fill_mode" default="0"> The fill direction. See [enum FillMode] for possible values. </member> + <member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" overrides="Control" enum="Control.MouseFilter" default="1" /> <member name="nine_patch_stretch" type="bool" setter="set_nine_patch_stretch" getter="get_nine_patch_stretch" default="false"> If [code]true[/code], Godot treats the bar's textures like in [NinePatchRect]. Use the [code]stretch_margin_*[/code] properties like [member stretch_margin_bottom] to set up the nine patch's 3×3 grid. When using a radial [member fill_mode], this setting will enable stretching. </member> diff --git a/doc/classes/ViewportTexture.xml b/doc/classes/ViewportTexture.xml index 6bd64a50bb..955f054cea 100644 --- a/doc/classes/ViewportTexture.xml +++ b/doc/classes/ViewportTexture.xml @@ -15,6 +15,7 @@ <link title="3D Viewport Scaling Demo">https://godotengine.org/asset-library/asset/586</link> </tutorials> <members> + <member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="true" /> <member name="viewport_path" type="NodePath" setter="set_viewport_path_in_scene" getter="get_viewport_path_in_scene" default="NodePath("")"> The path to the [Viewport] node to display. This is relative to the scene root, not to the node which uses the texture. </member> diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml index 94e8c25660..31811f817b 100644 --- a/doc/classes/VisualInstance3D.xml +++ b/doc/classes/VisualInstance3D.xml @@ -56,7 +56,7 @@ </method> </methods> <members> - <member name="layers" type="int" setter="set_layer_mask" getter="get_layer_mask"> + <member name="layers" type="int" setter="set_layer_mask" getter="get_layer_mask" default="1"> The render layer(s) this [VisualInstance3D] is drawn on. This object will only be visible for [Camera3D]s whose cull mask includes the render object this [VisualInstance3D] is set to. For [Light3D]s, this can be used to control which [VisualInstance3D]s are affected by a specific light. For [GPUParticles3D], this can be used to control which particles are effected by a specific attractor. For [Decal]s, this can be used to control which [VisualInstance3D]s are affected by a specific decal. diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 29252c8677..b05817cd8e 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -581,7 +581,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou _record_item_commands(ci, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken); } - if (r_last_index >= index) { + if (index == 0) { // Nothing to render, just return. state.current_batch_index = 0; state.canvas_instance_batches.clear(); @@ -1325,7 +1325,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) { void RasterizerCanvasGLES3::_add_to_batch(uint32_t &r_index, bool &r_batch_broken) { if (r_index >= data.max_instances_per_ubo - 1) { - WARN_PRINT_ONCE("Trying to draw too many items. Please increase maximum number of items in the project settings 'rendering/gl_compatibility/item_buffer_size'"); + ERR_PRINT_ONCE("Trying to draw too many items. Please increase maximum number of items in the project settings 'rendering/gl_compatibility/item_buffer_size'"); return; } diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 1fe31a3c47..66754932ad 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -7751,7 +7751,7 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_ dl->validation.index_array_size = index_array->indices; dl->validation.index_array_offset = index_array->offset; - vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, index_array->offset, index_array->index_type); + vkCmdBindIndexBuffer(dl->command_buffer, index_array->buffer, 0, index_array->index_type); } void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_width) { diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index 9b1ff78727..3b9d6c18eb 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "editor/action_map_editor.h" + #include "editor/editor_scale.h" #include "editor/event_listener_line_edit.h" #include "editor/input_event_configuration_dialog.h" @@ -395,15 +396,9 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info action_tree->clear(); TreeItem *root = action_tree->create_item(); - int uneditable_count = 0; - for (int i = 0; i < actions_cache.size(); i++) { ActionInfo action_info = actions_cache[i]; - if (!action_info.editable) { - uneditable_count++; - } - const Array events = action_info.action["events"]; if (!_should_display_action(action_info.name, events)) { continue; diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 6142856f75..545b0895b0 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -284,12 +284,12 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String bool can_instantiate = (p_type_category == TypeCategory::CPP_TYPE && ClassDB::can_instantiate(p_type)) || p_type_category == TypeCategory::OTHER_TYPE; - if (!can_instantiate) { - r_item->set_custom_color(0, search_options->get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"))); + if (can_instantiate && !ClassDB::is_virtual(p_type)) { + r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, icon_fallback)); + } else { r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, "NodeDisabled")); + r_item->set_custom_color(0, search_options->get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"))); r_item->set_selectable(0, false); - } else { - r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, icon_fallback)); } bool is_deprecated = EditorHelp::get_doc_data()->class_list[p_type].is_deprecated; diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 7d6eb186dc..6e6416e3ca 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -335,7 +335,7 @@ static Variant get_documentation_default_value(const StringName &p_class_name, c Variant default_value = Variant(); r_default_value_valid = false; - if (ClassDB::can_instantiate(p_class_name)) { + if (ClassDB::can_instantiate(p_class_name)) { // Keep this condition in sync with ClassDB::class_get_default_property_value. default_value = ClassDB::class_get_default_property_value(p_class_name, p_property_name, &r_default_value_valid); } else { // Cannot get default value of classes that can't be instantiated diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp index a0913265eb..3f93fa1f41 100644 --- a/editor/editor_command_palette.cpp +++ b/editor/editor_command_palette.cpp @@ -226,7 +226,7 @@ void EditorCommandPalette::_add_command(String p_command_name, String p_key_name void EditorCommandPalette::execute_command(String &p_command_key) { ERR_FAIL_COND_MSG(!commands.has(p_command_key), p_command_key + " not found."); commands[p_command_key].last_used = OS::get_singleton()->get_unix_time(); - commands[p_command_key].callable.call_deferredp(nullptr, 0); + commands[p_command_key].callable.call_deferred(); _save_history(); } diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index 9549ffb09b..49fb16a095 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -47,6 +47,7 @@ const char *EditorFeatureProfile::feature_names[FEATURE_MAX] = { TTRC("Node Dock"), TTRC("FileSystem Dock"), TTRC("Import Dock"), + TTRC("History Dock"), }; const char *EditorFeatureProfile::feature_descriptions[FEATURE_MAX] = { @@ -57,6 +58,7 @@ const char *EditorFeatureProfile::feature_descriptions[FEATURE_MAX] = { TTRC("Allows to work with signals and groups of the node selected in the Scene dock."), TTRC("Allows to browse the local file system via a dedicated dock."), TTRC("Allows to configure import settings for individual assets. Requires the FileSystem dock to function."), + TTRC("Provides an overview of the editor's and each scene's undo history."), }; const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = { @@ -67,6 +69,7 @@ const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = { "node_dock", "filesystem_dock", "import_dock", + "history_dock", }; void EditorFeatureProfile::set_disable_class(const StringName &p_class, bool p_disabled) { @@ -302,6 +305,7 @@ void EditorFeatureProfile::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_NODE_DOCK); BIND_ENUM_CONSTANT(FEATURE_FILESYSTEM_DOCK); BIND_ENUM_CONSTANT(FEATURE_IMPORT_DOCK); + BIND_ENUM_CONSTANT(FEATURE_HISTORY_DOCK); BIND_ENUM_CONSTANT(FEATURE_MAX); } diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h index dab6c951e4..6868c54146 100644 --- a/editor/editor_feature_profile.h +++ b/editor/editor_feature_profile.h @@ -52,6 +52,7 @@ public: FEATURE_NODE_DOCK, FEATURE_FILESYSTEM_DOCK, FEATURE_IMPORT_DOCK, + FEATURE_HISTORY_DOCK, FEATURE_MAX }; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 716e0b454f..bd6bc3ece5 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -244,15 +244,11 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto String full_path = p_full_paths[set_idx]; // Get rid of file extensions and res:// prefixes. - if (scene_name.rfind(".") >= 0) { - scene_name = scene_name.substr(0, scene_name.rfind(".")); - } + scene_name = scene_name.get_basename(); if (full_path.begins_with("res://")) { full_path = full_path.substr(6); } - if (full_path.rfind(".") >= 0) { - full_path = full_path.substr(0, full_path.rfind(".")); - } + full_path = full_path.get_basename(); // Normalize trailing slashes when normalizing directory names. scene_name = scene_name.trim_suffix("/"); @@ -270,7 +266,7 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto String parent = full_path.substr(0, difference); int slash_idx = parent.rfind("/"); slash_idx = parent.rfind("/", slash_idx - 1); - parent = slash_idx >= 0 ? parent.substr(slash_idx + 1) : parent; + parent = (slash_idx >= 0 && parent.length() > 1) ? parent.substr(slash_idx + 1) : parent; r_filenames.write[set_idx] = parent + r_filenames[set_idx]; } } @@ -302,15 +298,11 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto String path = p_full_paths[E->get()]; // Get rid of file extensions and res:// prefixes. - if (scene_name.rfind(".") >= 0) { - scene_name = scene_name.substr(0, scene_name.rfind(".")); - } + scene_name = scene_name.get_basename(); if (path.begins_with("res://")) { path = path.substr(6); } - if (path.rfind(".") >= 0) { - path = path.substr(0, path.rfind(".")); - } + path = path.get_basename(); // Normalize trailing slashes when normalizing directory names. scene_name = scene_name.trim_suffix("/"); @@ -5976,12 +5968,14 @@ void EditorNode::_feature_profile_changed() { TabContainer *import_tabs = cast_to<TabContainer>(ImportDock::get_singleton()->get_parent()); TabContainer *node_tabs = cast_to<TabContainer>(NodeDock::get_singleton()->get_parent()); TabContainer *fs_tabs = cast_to<TabContainer>(FileSystemDock::get_singleton()->get_parent()); + TabContainer *history_tabs = cast_to<TabContainer>(history_dock->get_parent()); if (profile.is_valid()) { node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_NODE_DOCK)); // The Import dock is useless without the FileSystem dock. Ensure the configuration is valid. bool fs_dock_disabled = profile->is_feature_disabled(EditorFeatureProfile::FEATURE_FILESYSTEM_DOCK); fs_tabs->set_tab_hidden(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), fs_dock_disabled); import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), fs_dock_disabled || profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK)); + history_tabs->set_tab_hidden(history_tabs->get_tab_idx_from_control(history_dock), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_HISTORY_DOCK)); main_editor_buttons[EDITOR_3D]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)); main_editor_buttons[EDITOR_SCRIPT]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT)); @@ -5997,6 +5991,8 @@ void EditorNode::_feature_profile_changed() { import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), false); node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), false); fs_tabs->set_tab_hidden(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), false); + history_tabs->set_tab_hidden(history_tabs->get_tab_idx_from_control(history_dock), false); + history_dock->set_visible(true); ImportDock::get_singleton()->set_visible(true); NodeDock::get_singleton()->set_visible(true); FileSystemDock::get_singleton()->set_visible(true); @@ -7108,7 +7104,7 @@ EditorNode::EditorNode() { filesystem_dock->connect("display_mode_changed", callable_mp(this, &EditorNode::_save_docks)); get_project_settings()->connect_filesystem_dock_signals(filesystem_dock); - HistoryDock *hd = memnew(HistoryDock); + history_dock = memnew(HistoryDock); // Scene: Top left. dock_slot[DOCK_SLOT_LEFT_UR]->add_child(SceneTreeDock::get_singleton()); @@ -7131,8 +7127,8 @@ EditorNode::EditorNode() { dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(NodeDock::get_singleton()), TTR("Node")); // History: Full height right, behind Node. - dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(hd); - dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(hd), TTR("History")); + dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(history_dock); + dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(history_dock), TTR("History")); // Hide unused dock slots and vsplits. dock_slot[DOCK_SLOT_LEFT_UL]->hide(); diff --git a/editor/editor_node.h b/editor/editor_node.h index 9c8d564057..f27fe429b9 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -77,6 +77,7 @@ class EditorUndoRedoManager; class ExportTemplateManager; class FileDialog; class FileSystemDock; +class HistoryDock; class HSplitContainer; class ImportDock; class LinkButton; @@ -274,6 +275,7 @@ private: EditorRunNative *run_native = nullptr; EditorSelection *editor_selection = nullptr; EditorSettingsDialog *editor_settings_dialog = nullptr; + HistoryDock *history_dock = nullptr; ProjectExportDialog *project_export = nullptr; ProjectSettingsEditor *project_settings_editor = nullptr; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index d76dce0c1d..d71976a1af 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -1045,7 +1045,6 @@ void EditorPropertyLayersGrid::_notification(int p_what) { const int vofs = (grid_size.height - h) / 2; int layer_index = 0; - int block_index = 0; Point2 arrow_pos; @@ -1112,8 +1111,6 @@ void EditorPropertyLayersGrid::_notification(int p_what) { break; } } - - ++block_index; } if ((expansion_rows != prev_expansion_rows) && expanded) { diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 7c1e3e63ef..0b38996b2d 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -570,13 +570,17 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin for (int i = 0; i < size; i++) { String base = allowed_types[i].strip_edges(); - p_vector->insert(base); + if (!ClassDB::is_virtual(base)) { + p_vector->insert(base); + } // If we hit a familiar base type, take all the data from cache. if (allowed_types_cache.has(base)) { List<StringName> allowed_subtypes = allowed_types_cache[base]; for (const StringName &subtype_name : allowed_subtypes) { - p_vector->insert(subtype_name); + if (!ClassDB::is_virtual(subtype_name)) { + p_vector->insert(subtype_name); + } } } else { List<StringName> allowed_subtypes; @@ -586,13 +590,17 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<Strin ClassDB::get_inheriters_from_class(base, &inheriters); } for (const StringName &subtype_name : inheriters) { - p_vector->insert(subtype_name); + if (!ClassDB::is_virtual(subtype_name)) { + p_vector->insert(subtype_name); + } allowed_subtypes.push_back(subtype_name); } for (const StringName &subtype_name : global_classes) { if (EditorNode::get_editor_data().script_class_is_parent(subtype_name, base)) { - p_vector->insert(subtype_name); + if (!ClassDB::is_virtual(subtype_name)) { + p_vector->insert(subtype_name); + } allowed_subtypes.push_back(subtype_name); } } diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp index 599df12bd3..41d5d1b0d2 100644 --- a/editor/editor_run.cpp +++ b/editor/editor_run.cpp @@ -57,8 +57,11 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) { args.push_back(resource_path.replace(" ", "%20")); } - args.push_back("--remote-debug"); - args.push_back(EditorDebuggerNode::get_singleton()->get_server_uri()); + const String debug_uri = EditorDebuggerNode::get_singleton()->get_server_uri(); + if (debug_uri.size()) { + args.push_back("--remote-debug"); + args.push_back(debug_uri); + } args.push_back("--editor-pid"); args.push_back(itos(OS::get_singleton()->get_process_id())); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index a2bd1223a9..b7605d8e2b 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -422,8 +422,7 @@ void FindInFilesDialog::set_find_in_files_mode(FindInFilesMode p_mode) { } String FindInFilesDialog::get_search_text() const { - String text = _search_text_line_edit->get_text(); - return text.strip_edges(); + return _search_text_line_edit->get_text(); } String FindInFilesDialog::get_replace_text() const { diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 8ede88a888..a6a0eef11b 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -1276,14 +1276,12 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap< } break; } - int idx = 0; for (const Ref<Shape3D> &E : shapes) { CollisionShape3D *cshape = memnew(CollisionShape3D); cshape->set_shape(E); base->add_child(cshape, true); cshape->set_owner(base->get_owner()); - idx++; } } } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 1d6f41d4c4..baf335f5b4 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -928,9 +928,7 @@ void CanvasItemEditor::_add_node_pressed(int p_result) { [[fallthrough]]; } case ADD_MOVE: { - if (p_result == ADD_MOVE) { - nodes_to_move = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list(); - } + nodes_to_move = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list(); if (nodes_to_move.is_empty()) { return; } @@ -1731,22 +1729,16 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) { drag_to = transform.affine_inverse().xform(m->get_position()); - Transform2D xform = ci->get_global_transform_with_canvas().affine_inverse(); + Transform2D xform = ci->get_global_transform_with_canvas(); Point2 drag_to_snapped_begin; Point2 drag_to_snapped_end; - // last call decides which snapping lines are drawn - if (drag_type == DRAG_LEFT || drag_type == DRAG_TOP || drag_type == DRAG_TOP_LEFT) { - drag_to_snapped_end = snap_point(xform.affine_inverse().xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci); - drag_to_snapped_begin = snap_point(xform.affine_inverse().xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci); - } else { - drag_to_snapped_begin = snap_point(xform.affine_inverse().xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci); - drag_to_snapped_end = snap_point(xform.affine_inverse().xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci); - } + drag_to_snapped_end = snap_point(xform.xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci); + drag_to_snapped_begin = snap_point(xform.xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci); - Point2 drag_begin = xform.xform(drag_to_snapped_begin); - Point2 drag_end = xform.xform(drag_to_snapped_end); + Point2 drag_begin = xform.affine_inverse().xform(drag_to_snapped_begin); + Point2 drag_end = xform.affine_inverse().xform(drag_to_snapped_end); // Horizontal resize if (drag_type == DRAG_LEFT || drag_type == DRAG_TOP_LEFT || drag_type == DRAG_BOTTOM_LEFT) { @@ -2068,12 +2060,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { } } - int index = 0; for (CanvasItem *ci : drag_selection) { Transform2D xform = ci->get_global_transform_with_canvas().affine_inverse() * ci->get_transform(); - ci->_edit_set_position(ci->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos)); - index++; } return true; } @@ -2191,12 +2180,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { new_pos = previous_pos + (drag_to - drag_from); } - int index = 0; for (CanvasItem *ci : drag_selection) { Transform2D xform = ci->get_global_transform_with_canvas().affine_inverse() * ci->get_transform(); - ci->_edit_set_position(ci->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos)); - index++; } } return true; diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp index bb6092755e..1791f7b420 100644 --- a/editor/plugins/control_editor_plugin.cpp +++ b/editor/plugins/control_editor_plugin.cpp @@ -810,19 +810,6 @@ void ControlEditorToolbar::_container_flags_selected(int p_flags, bool p_vertica undo_redo->commit_action(); } -Vector2 ControlEditorToolbar::_anchor_to_position(const Control *p_control, Vector2 anchor) { - ERR_FAIL_COND_V(!p_control, Vector2()); - - Transform2D parent_transform = p_control->get_transform().affine_inverse(); - Rect2 parent_rect = p_control->get_parent_anchorable_rect(); - - if (p_control->is_layout_rtl()) { - return parent_transform.xform(parent_rect.position + Vector2(parent_rect.size.x - parent_rect.size.x * anchor.x, parent_rect.size.y * anchor.y)); - } else { - return parent_transform.xform(parent_rect.position + Vector2(parent_rect.size.x * anchor.x, parent_rect.size.y * anchor.y)); - } -} - Vector2 ControlEditorToolbar::_position_to_anchor(const Control *p_control, Vector2 position) { ERR_FAIL_COND_V(!p_control, Vector2()); diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h index 22267cbc04..d78773a509 100644 --- a/editor/plugins/control_editor_plugin.h +++ b/editor/plugins/control_editor_plugin.h @@ -222,7 +222,6 @@ class ControlEditorToolbar : public HBoxContainer { void _anchor_mode_toggled(bool p_status); void _container_flags_selected(int p_flags, bool p_vertical); - Vector2 _anchor_to_position(const Control *p_control, Vector2 anchor); Vector2 _position_to_anchor(const Control *p_control, Vector2 position); bool _is_node_locked(const Node *p_node); List<Control *> _get_edited_controls(); diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp index dc01a52bb3..561dca4fc6 100644 --- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp +++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp @@ -121,13 +121,12 @@ void GradientTexture2DEditorRect::_notification(int p_what) { Size2 rect_size = get_size(); // Get the size and position to draw the texture and handles at. - size = Size2(texture->get_width() * rect_size.height / texture->get_height(), rect_size.height); - if (size.width > rect_size.width) { - size.width = rect_size.width; - size.height = texture->get_height() * size.width / texture->get_width(); - } - offset = ((rect_size - size + handle_size) / 2).round(); - size -= handle_size; + // Subtract handle sizes so they stay inside the preview, but keep the texture's aspect ratio. + Size2 available_size = rect_size - handle_size; + Size2 ratio = available_size / texture->get_size(); + size = MIN(ratio.x, ratio.y) * texture->get_size(); + offset = ((rect_size - size) / 2).round(); + checkerboard->set_rect(Rect2(offset, size)); draw_set_transform(offset); @@ -180,8 +179,9 @@ GradientTexture2DEditorRect::GradientTexture2DEditorRect() { checkerboard = memnew(TextureRect); checkerboard->set_stretch_mode(TextureRect::STRETCH_TILE); + checkerboard->set_ignore_texture_size(true); checkerboard->set_draw_behind_parent(true); - add_child(checkerboard); + add_child(checkerboard, false, INTERNAL_MODE_FRONT); set_custom_minimum_size(Size2(0, 250 * EDSCALE)); } diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index a7a8d526d0..b0c8597adf 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -242,7 +242,7 @@ void TextureRegionEditor::_region_draw() { hscroll->set_value((hscroll->get_min() + hscroll->get_max() - hscroll->get_page()) / 2); vscroll->set_value((vscroll->get_min() + vscroll->get_max() - vscroll->get_page()) / 2); // This ensures that the view is updated correctly. - callable_mp(this, &TextureRegionEditor::_pan_callback).bind(Vector2(1, 0)).call_deferredp(nullptr, 0); + callable_mp(this, &TextureRegionEditor::_pan_callback).bind(Vector2(1, 0)).call_deferred(); request_center = false; } diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 69104cadec..4fe7178e7e 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -192,6 +192,19 @@ void TileAtlasView::_draw_base_tiles() { rect = rect.intersection(Rect2i(Vector2(), texture->get_size())); if (rect.size.x > 0 && rect.size.y > 0) { base_tiles_draw->draw_texture_rect_region(texture, rect, rect); + } + } + } + } + + // Draw dark overlay after for performance reasons. + for (int x = 0; x < grid_size.x; x++) { + for (int y = 0; y < grid_size.y; y++) { + Vector2i coords = Vector2i(x, y); + if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) { + Rect2i rect = Rect2i((texture_region_size + separation) * coords + margins, texture_region_size + separation); + rect = rect.intersection(Rect2i(Vector2(), texture->get_size())); + if (rect.size.x > 0 && rect.size.y > 0) { base_tiles_draw->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.5)); } } @@ -242,23 +255,34 @@ void TileAtlasView::_draw_base_tiles() { // Draw the tile. TileMap::draw_tile(base_tiles_draw->get_canvas_item(), offset_pos, tile_set, source_id, atlas_coords, 0, frame); + } + } - // Draw, the texture in the separation areas - if (separation.x > 0) { - Rect2i right_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(base_frame_rect.size.x, 0), Vector2i(separation.x, base_frame_rect.size.y)); - right_sep_rect = right_sep_rect.intersection(Rect2i(Vector2(), texture->get_size())); - if (right_sep_rect.size.x > 0 && right_sep_rect.size.y > 0) { - base_tiles_draw->draw_texture_rect_region(texture, right_sep_rect, right_sep_rect); - base_tiles_draw->draw_rect(right_sep_rect, Color(0.0, 0.0, 0.0, 0.5)); + // Draw Dark overlay on separation in its own pass. + if (separation.x > 0 || separation.y > 0) { + for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) { + Vector2i atlas_coords = tile_set_atlas_source->get_tile_id(i); + + for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(atlas_coords); frame++) { + // Update the y to max value. + Rect2i base_frame_rect = tile_set_atlas_source->get_tile_texture_region(atlas_coords, frame); + + if (separation.x > 0) { + Rect2i right_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(base_frame_rect.size.x, 0), Vector2i(separation.x, base_frame_rect.size.y)); + right_sep_rect = right_sep_rect.intersection(Rect2i(Vector2(), texture->get_size())); + if (right_sep_rect.size.x > 0 && right_sep_rect.size.y > 0) { + //base_tiles_draw->draw_texture_rect_region(texture, right_sep_rect, right_sep_rect); + base_tiles_draw->draw_rect(right_sep_rect, Color(0.0, 0.0, 0.0, 0.5)); + } } - } - if (separation.y > 0) { - Rect2i bottom_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(0, base_frame_rect.size.y), Vector2i(base_frame_rect.size.x + separation.x, separation.y)); - bottom_sep_rect = bottom_sep_rect.intersection(Rect2i(Vector2(), texture->get_size())); - if (bottom_sep_rect.size.x > 0 && bottom_sep_rect.size.y > 0) { - base_tiles_draw->draw_texture_rect_region(texture, bottom_sep_rect, bottom_sep_rect); - base_tiles_draw->draw_rect(bottom_sep_rect, Color(0.0, 0.0, 0.0, 0.5)); + if (separation.y > 0) { + Rect2i bottom_sep_rect = Rect2i(base_frame_rect.get_position() + Vector2i(0, base_frame_rect.size.y), Vector2i(base_frame_rect.size.x + separation.x, separation.y)); + bottom_sep_rect = bottom_sep_rect.intersection(Rect2i(Vector2(), texture->get_size())); + if (bottom_sep_rect.size.x > 0 && bottom_sep_rect.size.y > 0) { + //base_tiles_draw->draw_texture_rect_region(texture, bottom_sep_rect, bottom_sep_rect); + base_tiles_draw->draw_rect(bottom_sep_rect, Color(0.0, 0.0, 0.0, 0.5)); + } } } } diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 588746bf64..b2a2566ad4 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -546,7 +546,6 @@ private: Vector<String> failed_files; - int idx = 0; while (ret == UNZ_OK) { //get filename unz_file_info info; @@ -585,7 +584,6 @@ private: } } - idx++; ret = unzGoToNextFile(pkg); } diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index cc09c3a432..08c0f0f708 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -275,7 +275,6 @@ String ScriptCreateDialog::_validate_path(const String &p_path, bool p_file_must bool found = false; bool match = false; - int index = 0; for (const String &E : extensions) { if (E.nocasecmp_to(extension) == 0) { found = true; @@ -284,7 +283,6 @@ String ScriptCreateDialog::_validate_path(const String &p_path, bool p_file_must } break; } - index++; } if (!found) { @@ -373,7 +371,7 @@ void ScriptCreateDialog::_create_new() { const ScriptLanguage::ScriptTemplate sinfo = _get_current_template(); String parent_class = parent_name->get_text(); - if (!ClassDB::class_exists(parent_class) && !ScriptServer::is_global_class(parent_class)) { + if (!parent_name->get_text().is_quoted() && !ClassDB::class_exists(parent_class) && !ScriptServer::is_global_class(parent_class)) { // If base is a custom type, replace with script path instead. const EditorData::CustomType *type = EditorNode::get_editor_data().get_custom_type_by_name(parent_class); ERR_FAIL_NULL(type); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs index 088f4e7ecf..b30b6a0752 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs @@ -374,7 +374,7 @@ namespace Godot.NativeInterop public static partial Error godotsharp_array_resize(ref godot_array p_self, int p_new_size); - public static partial Error godotsharp_array_shuffle(ref godot_array p_self); + public static partial void godotsharp_array_shuffle(ref godot_array p_self); public static partial void godotsharp_array_to_string(ref godot_array p_self, out godot_string r_str); diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp index 3bd132bc73..eea015e486 100644 --- a/modules/websocket/emws_peer.cpp +++ b/modules/websocket/emws_peer.cpp @@ -95,6 +95,10 @@ Error EMWSPeer::connect_to_url(const String &p_url, bool p_verify_tls, Ref<X509C requested_url += ":" + String::num(port); } + if (!path.is_empty()) { + requested_url += path; + } + peer_sock = godot_js_websocket_create(this, requested_url.utf8().get_data(), proto_string.utf8().get_data(), &_esws_on_connect, &_esws_on_message, &_esws_on_error, &_esws_on_close); if (peer_sock == -1) { return FAILED; diff --git a/platform/android/android_keys_utils.h b/platform/android/android_keys_utils.h index 5ec3ee17aa..bc633aeade 100644 --- a/platform/android/android_keys_utils.h +++ b/platform/android/android_keys_utils.h @@ -43,7 +43,6 @@ struct AndroidGodotCodePair { static AndroidGodotCodePair android_godot_code_pairs[] = { { AKEYCODE_UNKNOWN, Key::UNKNOWN }, // (0) Unknown key code. - { AKEYCODE_HOME, Key::HOME }, // (3) Home key. { AKEYCODE_BACK, Key::BACK }, // (4) Back key. { AKEYCODE_0, Key::KEY_0 }, // (7) '0' key. { AKEYCODE_1, Key::KEY_1 }, // (8) '1' key. @@ -63,6 +62,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = { { AKEYCODE_DPAD_RIGHT, Key::RIGHT }, // (22) Directional Pad Right key. { AKEYCODE_VOLUME_UP, Key::VOLUMEUP }, // (24) Volume Up key. { AKEYCODE_VOLUME_DOWN, Key::VOLUMEDOWN }, // (25) Volume Down key. + { AKEYCODE_POWER, Key::STANDBY }, // (26) Power key. { AKEYCODE_CLEAR, Key::CLEAR }, // (28) Clear key. { AKEYCODE_A, Key::A }, // (29) 'A' key. { AKEYCODE_B, Key::B }, // (30) 'B' key. @@ -98,6 +98,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = { { AKEYCODE_SHIFT_RIGHT, Key::SHIFT }, // (60) Right Shift modifier key. { AKEYCODE_TAB, Key::TAB }, // (61) Tab key. { AKEYCODE_SPACE, Key::SPACE }, // (62) Space key. + { AKEYCODE_ENVELOPE, Key::LAUNCHMAIL }, // (65) Envelope special function key. { AKEYCODE_ENTER, Key::ENTER }, // (66) Enter key. { AKEYCODE_DEL, Key::BACKSPACE }, // (67) Backspace key. { AKEYCODE_GRAVE, Key::QUOTELEFT }, // (68) '`' (backtick) key. @@ -114,6 +115,7 @@ static AndroidGodotCodePair android_godot_code_pairs[] = { { AKEYCODE_MENU, Key::MENU }, // (82) Menu key. { AKEYCODE_SEARCH, Key::SEARCH }, // (84) Search key. { AKEYCODE_MEDIA_STOP, Key::MEDIASTOP }, // (86) Stop media key. + { AKEYCODE_MEDIA_NEXT, Key::MEDIANEXT }, // (87) Play Next media key. { AKEYCODE_MEDIA_PREVIOUS, Key::MEDIAPREVIOUS }, // (88) Play Previous media key. { AKEYCODE_PAGE_UP, Key::PAGEUP }, // (92) Page Up key. { AKEYCODE_PAGE_DOWN, Key::PAGEDOWN }, // (93) Page Down key. @@ -127,6 +129,8 @@ static AndroidGodotCodePair android_godot_code_pairs[] = { { AKEYCODE_META_RIGHT, Key::META }, // (118) Right Meta modifier key. { AKEYCODE_SYSRQ, Key::PRINT }, // (120) System Request / Print Screen key. { AKEYCODE_BREAK, Key::PAUSE }, // (121) Break / Pause key. + { AKEYCODE_MOVE_HOME, Key::HOME }, // (122) Home Movement key. + { AKEYCODE_MOVE_END, Key::END }, // (123) End Movement key. { AKEYCODE_INSERT, Key::INSERT }, // (124) Insert key. { AKEYCODE_FORWARD, Key::FORWARD }, // (125) Forward key. { AKEYCODE_MEDIA_PLAY, Key::MEDIAPLAY }, // (126) Play media key. diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp index 2c1e87e663..5a1a56b9da 100644 --- a/platform/web/display_server_web.cpp +++ b/platform/web/display_server_web.cpp @@ -758,10 +758,8 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode godot_js_os_request_quit_cb(request_quit_callback); #ifdef GLES3_ENABLED - // TODO "vulkan" defaults to webgl2 for now. - bool wants_webgl2 = p_rendering_driver == "opengl3" || p_rendering_driver == "vulkan"; - bool webgl2_init_failed = wants_webgl2 && !godot_js_display_has_webgl(2); - if (wants_webgl2 && !webgl2_init_failed) { + bool webgl2_inited = false; + if (godot_js_display_has_webgl(2)) { EmscriptenWebGLContextAttributes attributes; emscripten_webgl_init_context_attributes(&attributes); attributes.alpha = OS::get_singleton()->is_layered_allowed(); @@ -770,20 +768,17 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode attributes.explicitSwapControl = true; webgl_ctx = emscripten_webgl_create_context(canvas_id, &attributes); - if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) { - webgl2_init_failed = true; - } else { - if (!emscripten_webgl_enable_extension(webgl_ctx, "OVR_multiview2")) { - // @todo Should we log this? - } - RasterizerGLES3::make_current(); - } + webgl2_inited = webgl_ctx && emscripten_webgl_make_context_current(webgl_ctx) == EMSCRIPTEN_RESULT_SUCCESS; } - if (webgl2_init_failed) { + if (webgl2_inited) { + if (!emscripten_webgl_enable_extension(webgl_ctx, "OVR_multiview2")) { + print_verbose("Failed to enable WebXR extension."); + } + RasterizerGLES3::make_current(); + + } else { OS::get_singleton()->alert("Your browser does not seem to support WebGL2. Please update your browser version.", "Unable to initialize video driver"); - } - if (!wants_webgl2 || webgl2_init_failed) { RasterizerDummy::make_current(); } #else diff --git a/platform/web/js/engine/config.js b/platform/web/js/engine/config.js index 41be7b2512..4560f12b49 100644 --- a/platform/web/js/engine/config.js +++ b/platform/web/js/engine/config.js @@ -275,7 +275,7 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- 'print': this.onPrint, 'printErr': this.onPrintError, 'thisProgram': this.executable, - 'noExitRuntime': true, + 'noExitRuntime': false, 'dynamicLibraries': [`${loadPath}.side.wasm`], 'instantiateWasm': function (imports, onSuccess) { function done(result) { diff --git a/platform/web/web_main.cpp b/platform/web/web_main.cpp index a76b98f4e9..fce782b546 100644 --- a/platform/web/web_main.cpp +++ b/platform/web/web_main.cpp @@ -41,30 +41,25 @@ static OS_Web *os = nullptr; static uint64_t target_ticks = 0; +static bool main_started = false; +static bool shutdown_complete = false; void exit_callback() { - emscripten_cancel_main_loop(); // After this, we can exit! - Main::cleanup(); + if (!shutdown_complete) { + return; // Still waiting. + } + if (main_started) { + Main::cleanup(); + main_started = false; + } int exit_code = OS_Web::get_singleton()->get_exit_code(); memdelete(os); os = nullptr; - emscripten_force_exit(exit_code); // No matter that we call cancel_main_loop, regular "exit" will not work, forcing. + emscripten_force_exit(exit_code); // Exit runtime. } void cleanup_after_sync() { - emscripten_set_main_loop(exit_callback, -1, false); -} - -void early_cleanup() { - emscripten_cancel_main_loop(); // After this, we can exit! - int exit_code = OS_Web::get_singleton()->get_exit_code(); - memdelete(os); - os = nullptr; - emscripten_force_exit(exit_code); // No matter that we call cancel_main_loop, regular "exit" will not work, forcing. -} - -void early_cleanup_sync() { - emscripten_set_main_loop(early_cleanup, -1, false); + shutdown_complete = true; } void main_loop_callback() { @@ -87,7 +82,8 @@ void main_loop_callback() { target_ticks += (uint64_t)(1000000 / max_fps); } if (os->main_loop_iterate()) { - emscripten_cancel_main_loop(); // Cancel current loop and wait for cleanup_after_sync. + emscripten_cancel_main_loop(); // Cancel current loop and set the cleanup one. + emscripten_set_main_loop(exit_callback, -1, false); godot_js_os_finish_async(cleanup_after_sync); } } @@ -109,10 +105,14 @@ extern EMSCRIPTEN_KEEPALIVE int godot_web_main(int argc, char *argv[]) { } os->set_exit_code(exit_code); // Will only exit after sync. - godot_js_os_finish_async(early_cleanup_sync); + emscripten_set_main_loop(exit_callback, -1, false); + godot_js_os_finish_async(cleanup_after_sync); return exit_code; } + os->set_exit_code(0); + main_started = true; + // Ease up compatibility. ResourceLoader::set_abort_on_missing_resources(false); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index 9786b01058..e18f2bd1a1 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -141,16 +141,16 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) { void GPUParticles2D::set_trail_enabled(bool p_enabled) { trail_enabled = p_enabled; - RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length); + RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime); queue_redraw(); RS::get_singleton()->particles_set_transform_align(particles, p_enabled ? RS::PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY : RS::PARTICLES_TRANSFORM_ALIGN_DISABLED); } -void GPUParticles2D::set_trail_length(double p_seconds) { +void GPUParticles2D::set_trail_lifetime(double p_seconds) { ERR_FAIL_COND(p_seconds < 0.001); - trail_length = p_seconds; - RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length); + trail_lifetime = p_seconds; + RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime); queue_redraw(); } @@ -181,8 +181,8 @@ bool GPUParticles2D::is_trail_enabled() const { return trail_enabled; } -double GPUParticles2D::get_trail_length() const { - return trail_length; +double GPUParticles2D::get_trail_lifetime() const { + return trail_lifetime; } void GPUParticles2D::_update_collision_size() { @@ -614,10 +614,10 @@ void GPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles2D::emit_particle); ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles2D::set_trail_enabled); - ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles2D::set_trail_length); + ClassDB::bind_method(D_METHOD("set_trail_lifetime", "secs"), &GPUParticles2D::set_trail_lifetime); ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles2D::is_trail_enabled); - ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles2D::get_trail_length); + ClassDB::bind_method(D_METHOD("get_trail_lifetime"), &GPUParticles2D::get_trail_lifetime); ClassDB::bind_method(D_METHOD("set_trail_sections", "sections"), &GPUParticles2D::set_trail_sections); ClassDB::bind_method(D_METHOD("get_trail_sections"), &GPUParticles2D::get_trail_sections); @@ -647,7 +647,7 @@ void GPUParticles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,Reverse Lifetime"), "set_draw_order", "get_draw_order"); ADD_GROUP("Trails", "trail_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), "set_trail_length", "get_trail_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_lifetime", PROPERTY_HINT_RANGE, "0.01,10,0.01,or_greater,suffix:s"), "set_trail_lifetime", "get_trail_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_trail_sections", "get_trail_sections"); ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_section_subdivisions", PROPERTY_HINT_RANGE, "1,1024,1"), "set_trail_section_subdivisions", "get_trail_section_subdivisions"); ADD_GROUP("Process Material", "process_"); diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index d613b4ef51..7fba174357 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -74,7 +74,7 @@ private: real_t collision_base_size = 1.0; bool trail_enabled = false; - double trail_length = 0.3; + double trail_lifetime = 0.3; int trail_sections = 8; int trail_section_subdivisions = 4; @@ -104,7 +104,7 @@ public: void set_speed_scale(double p_scale); void set_collision_base_size(real_t p_ratio); void set_trail_enabled(bool p_enabled); - void set_trail_length(double p_seconds); + void set_trail_lifetime(double p_seconds); void set_trail_sections(int p_sections); void set_trail_section_subdivisions(int p_subdivisions); @@ -126,7 +126,7 @@ public: real_t get_collision_base_size() const; bool is_trail_enabled() const; - double get_trail_length() const; + double get_trail_lifetime() const; int get_trail_sections() const; int get_trail_section_subdivisions() const; diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index a98be62dfa..ca23fe03a2 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -330,7 +330,7 @@ bool CollisionObject3D::_are_collision_shapes_visible() { void CollisionObject3D::_update_shape_data(uint32_t p_owner) { if (_are_collision_shapes_visible()) { if (debug_shapes_to_update.is_empty()) { - callable_mp(this, &CollisionObject3D::_update_debug_shapes).call_deferredp({}, 0); + callable_mp(this, &CollisionObject3D::_update_debug_shapes).call_deferred(); } debug_shapes_to_update.insert(p_owner); } diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index dbbf196f7a..9d04202c2d 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -176,22 +176,22 @@ void GPUParticles3D::set_draw_order(DrawOrder p_order) { void GPUParticles3D::set_trail_enabled(bool p_enabled) { trail_enabled = p_enabled; - RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length); + RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime); update_configuration_warnings(); } -void GPUParticles3D::set_trail_length(double p_seconds) { +void GPUParticles3D::set_trail_lifetime(double p_seconds) { ERR_FAIL_COND(p_seconds < 0.001); - trail_length = p_seconds; - RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length); + trail_lifetime = p_seconds; + RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_lifetime); } bool GPUParticles3D::is_trail_enabled() const { return trail_enabled; } -double GPUParticles3D::get_trail_length() const { - return trail_length; +double GPUParticles3D::get_trail_lifetime() const { + return trail_lifetime; } GPUParticles3D::DrawOrder GPUParticles3D::get_draw_order() const { @@ -552,10 +552,10 @@ void GPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles3D::emit_particle); ClassDB::bind_method(D_METHOD("set_trail_enabled", "enabled"), &GPUParticles3D::set_trail_enabled); - ClassDB::bind_method(D_METHOD("set_trail_length", "secs"), &GPUParticles3D::set_trail_length); + ClassDB::bind_method(D_METHOD("set_trail_lifetime", "secs"), &GPUParticles3D::set_trail_lifetime); ClassDB::bind_method(D_METHOD("is_trail_enabled"), &GPUParticles3D::is_trail_enabled); - ClassDB::bind_method(D_METHOD("get_trail_length"), &GPUParticles3D::get_trail_length); + ClassDB::bind_method(D_METHOD("get_trail_lifetime"), &GPUParticles3D::get_trail_lifetime); ClassDB::bind_method(D_METHOD("set_transform_align", "align"), &GPUParticles3D::set_transform_align); ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align); @@ -583,7 +583,7 @@ void GPUParticles3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_align", PROPERTY_HINT_ENUM, "Disabled,Z-Billboard,Y to Velocity,Z-Billboard + Y to Velocity"), "set_transform_align", "get_transform_align"); ADD_GROUP("Trails", "trail_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), "set_trail_length", "get_trail_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_lifetime", PROPERTY_HINT_RANGE, "0.01,10,0.01,or_greater,suffix:s"), "set_trail_lifetime", "get_trail_lifetime"); ADD_GROUP("Process Material", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticleProcessMaterial"), "set_process_material", "get_process_material"); ADD_GROUP("Draw Passes", "draw_"); @@ -627,7 +627,7 @@ GPUParticles3D::GPUParticles3D() { set_pre_process_time(0); set_explosiveness_ratio(0); set_randomness_ratio(0); - set_trail_length(0.3); + set_trail_lifetime(0.3); set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8))); set_use_local_coordinates(false); set_draw_passes(1); diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index ef92218e4d..835d71862a 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -76,7 +76,7 @@ private: real_t collision_base_size = 0.01; bool trail_enabled = false; - double trail_length = 0.3; + double trail_lifetime = 0.3; TransformAlign transform_align = TRANSFORM_ALIGN_DISABLED; @@ -112,7 +112,7 @@ public: void set_speed_scale(double p_scale); void set_collision_base_size(real_t p_ratio); void set_trail_enabled(bool p_enabled); - void set_trail_length(double p_seconds); + void set_trail_lifetime(double p_seconds); bool is_emitting() const; int get_amount() const; @@ -127,7 +127,7 @@ public: double get_speed_scale() const; real_t get_collision_base_size() const; bool is_trail_enabled() const; - double get_trail_length() const; + double get_trail_lifetime() const; void set_fixed_fps(int p_count); int get_fixed_fps() const; diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index f5d30c584f..ca7d1dfc1d 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -644,6 +644,12 @@ void XROrigin3D::set_current(bool p_enabled) { origin_nodes[i]->set_current(false); } } + + // update XRServer with our current position + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL(xr_server); + + xr_server->set_world_origin(get_global_transform()); } else { bool found = false; // We no longer have a current origin so find the first one we can make current diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 5f8f25154c..ea310f5a12 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -694,8 +694,8 @@ void CodeEdit::_backspace_internal(int p_caret) { return; } - if (has_selection()) { - delete_selection(); + if (has_selection(p_caret)) { + delete_selection(p_caret); return; } diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 2cbece69f2..0940b4c07b 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -451,7 +451,7 @@ void OptionButton::_queue_refresh_cache() { } cache_refresh_pending = true; - callable_mp(this, &OptionButton::_refresh_size_cache).call_deferredp(nullptr, 0); + callable_mp(this, &OptionButton::_refresh_size_cache).call_deferred(); } void OptionButton::select(int p_idx) { diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index ec34a8d26d..531226f938 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -182,14 +182,12 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) { drag_accum = Vector2(); last_drag_accum = Vector2(); drag_from = Vector2(prev_h_scroll, prev_v_scroll); - drag_touching = screen_is_touchscreen; + drag_touching = true; drag_touching_deaccel = false; beyond_deadzone = false; time_since_motion = 0; - if (drag_touching) { - set_physics_process_internal(true); - time_since_motion = 0; - } + set_physics_process_internal(true); + time_since_motion = 0; } else { if (drag_touching) { diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 1b8444abf4..56f7281721 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1854,6 +1854,12 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } else { if (mb->get_button_index() == MouseButton::LEFT) { if (selection_drag_attempt && is_mouse_over_selection()) { + remove_secondary_carets(); + + Point2i pos = get_line_column_at_pos(get_local_mouse_pos()); + set_caret_line(pos.y, false, true, 0, 0); + set_caret_column(pos.x, true, 0); + deselect(); } dragging_minimap = false; diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp index ca1cd54349..afab44834d 100644 --- a/scene/resources/text_line.cpp +++ b/scene/resources/text_line.cpp @@ -317,11 +317,7 @@ float TextLine::get_width() const { Size2 TextLine::get_size() const { const_cast<TextLine *>(this)->_shape(); - if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) { - return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y); - } else { - return Size2(TS->shaped_text_get_size(rid).x, TS->shaped_text_get_size(rid).y); - } + return TS->shaped_text_get_size(rid); } float TextLine::get_line_ascent() const { diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 07cb59aaee..1897612562 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -302,19 +302,12 @@ void DisplayServer::tts_post_utterance_event(TTSUtteranceEvent p_event, int p_id case DisplayServer::TTS_UTTERANCE_ENDED: case DisplayServer::TTS_UTTERANCE_CANCELED: { if (utterance_callback[p_event].is_valid()) { - Variant args[1]; - args[0] = p_id; - const Variant *argp[] = { &args[0] }; - utterance_callback[p_event].call_deferredp(argp, 1); // Should be deferred, on some platforms utterance events can be called from different threads in a rapid succession. + utterance_callback[p_event].call_deferred(p_id); // Should be deferred, on some platforms utterance events can be called from different threads in a rapid succession. } } break; case DisplayServer::TTS_UTTERANCE_BOUNDARY: { if (utterance_callback[p_event].is_valid()) { - Variant args[2]; - args[0] = p_pos; - args[1] = p_id; - const Variant *argp[] = { &args[0], &args[1] }; - utterance_callback[p_event].call_deferredp(argp, 2); // Should be deferred, on some platforms utterance events can be called from different threads in a rapid succession. + utterance_callback[p_event].call_deferred(p_pos, p_id); // Should be deferred, on some platforms utterance events can be called from different threads in a rapid succession. } } break; default: diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h index b0914e70e4..4399f4ab66 100644 --- a/servers/rendering/dummy/storage/mesh_storage.h +++ b/servers/rendering/dummy/storage/mesh_storage.h @@ -81,6 +81,7 @@ public: s->vertex_count = p_surface.vertex_count; s->index_data = p_surface.index_data; s->index_count = p_surface.index_count; + s->aabb = p_surface.aabb; s->skin_data = p_surface.skin_data; } diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 41d4ca8d5e..16d382a5f3 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -1964,7 +1964,7 @@ void RendererCanvasCull::update_visibility_notifiers() { if (!visibility_notifier->enter_callable.is_null()) { if (RSG::threaded) { - visibility_notifier->enter_callable.call_deferredp(nullptr, 0); + visibility_notifier->enter_callable.call_deferred(); } else { Callable::CallError ce; Variant ret; @@ -1977,7 +1977,7 @@ void RendererCanvasCull::update_visibility_notifiers() { if (!visibility_notifier->exit_callable.is_null()) { if (RSG::threaded) { - visibility_notifier->exit_callable.call_deferredp(nullptr, 0); + visibility_notifier->exit_callable.call_deferred(); } else { Callable::CallError ce; Variant ret; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index 7fa0bb64a3..854976692e 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -425,7 +425,7 @@ void ParticlesStorage::particles_set_trails(RID p_particles, bool p_enable, doub p_length = MIN(10.0, p_length); particles->trails_enabled = p_enable; - particles->trail_length = p_length; + particles->trail_lifetime = p_length; _particles_free_data(particles); @@ -1351,7 +1351,7 @@ void ParticlesStorage::update_particles() { int history_size = 1; int trail_steps = 1; if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { - history_size = MAX(1, int(particles->trail_length * fixed_fps)); + history_size = MAX(1, int(particles->trail_lifetime * fixed_fps)); trail_steps = particles->trail_bind_poses.size(); } diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h index 017844626f..6478e2b5dc 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h @@ -232,7 +232,7 @@ private: Dependency dependency; - double trail_length = 1.0; + double trail_lifetime = 0.3; bool trails_enabled = false; LocalVector<ParticlesFrameParams> frame_history; LocalVector<ParticlesFrameParams> trail_params; diff --git a/servers/rendering/renderer_rd/storage_rd/utilities.cpp b/servers/rendering/renderer_rd/storage_rd/utilities.cpp index 4048c46d28..625f089f66 100644 --- a/servers/rendering/renderer_rd/storage_rd/utilities.cpp +++ b/servers/rendering/renderer_rd/storage_rd/utilities.cpp @@ -200,7 +200,7 @@ void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_de if (p_enter) { if (!vn->enter_callback.is_null()) { if (p_deferred) { - vn->enter_callback.call_deferredp(nullptr, 0); + vn->enter_callback.call_deferred(); } else { Variant r; Callable::CallError ce; @@ -210,7 +210,7 @@ void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_de } else { if (!vn->exit_callback.is_null()) { if (p_deferred) { - vn->exit_callback.call_deferredp(nullptr, 0); + vn->exit_callback.call_deferred(); } else { Variant r; Callable::CallError ce; diff --git a/tests/core/io/test_json.h b/tests/core/io/test_json.h index 478cf1766e..af450da3b8 100644 --- a/tests/core/io/test_json.h +++ b/tests/core/io/test_json.h @@ -83,7 +83,7 @@ TEST_CASE("[JSON] Parsing single data types") { json.get_error_line() == 0, "Parsing a floating-point number as JSON should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(json.get_data()), 0.123456), + double(json.get_data()) == doctest::Approx(0.123456), "Parsing a floating-point number as JSON should return the expected value."); json.parse("\"hello\""); diff --git a/tests/core/math/test_aabb.h b/tests/core/math/test_aabb.h index ebaf441abf..23969556be 100644 --- a/tests/core/math/test_aabb.h +++ b/tests/core/math/test_aabb.h @@ -91,7 +91,7 @@ TEST_CASE("[AABB] Basic setters") { TEST_CASE("[AABB] Volume getters") { AABB aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6)); CHECK_MESSAGE( - Math::is_equal_approx(aabb.get_volume(), 120), + aabb.get_volume() == doctest::Approx(120), "get_volume() should return the expected value with positive size."); CHECK_MESSAGE( aabb.has_volume(), @@ -99,17 +99,17 @@ TEST_CASE("[AABB] Volume getters") { aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(-4, 5, 6)); CHECK_MESSAGE( - Math::is_equal_approx(aabb.get_volume(), -120), + aabb.get_volume() == doctest::Approx(-120), "get_volume() should return the expected value with negative size (1 component)."); aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(-4, -5, 6)); CHECK_MESSAGE( - Math::is_equal_approx(aabb.get_volume(), 120), + aabb.get_volume() == doctest::Approx(120), "get_volume() should return the expected value with negative size (2 components)."); aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(-4, -5, -6)); CHECK_MESSAGE( - Math::is_equal_approx(aabb.get_volume(), -120), + aabb.get_volume() == doctest::Approx(-120), "get_volume() should return the expected value with negative size (3 components)."); aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 0, 6)); diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h index a4099ebf7d..dce9d5cec3 100644 --- a/tests/core/math/test_basis.h +++ b/tests/core/math/test_basis.h @@ -223,7 +223,7 @@ TEST_CASE("[Basis] Set axis angle") { // Testing the singularity when the angle is 180°. Basis singularityPi(-1, 0, 0, 0, 1, 0, 0, 0, -1); singularityPi.get_axis_angle(axis, angle); - CHECK(Math::is_equal_approx(angle, pi)); + CHECK(angle == doctest::Approx(pi)); // Testing reversing the an axis (of an 30° angle). float cos30deg = Math::cos(Math::deg_to_rad((real_t)30.0)); @@ -231,17 +231,17 @@ TEST_CASE("[Basis] Set axis angle") { Basis z_negative(cos30deg, 0.5, 0, -0.5, cos30deg, 0, 0, 0, 1); z_positive.get_axis_angle(axis, angle); - CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0))); + CHECK(angle == doctest::Approx(Math::deg_to_rad((real_t)30.0))); CHECK(axis == Vector3(0, 0, 1)); z_negative.get_axis_angle(axis, angle); - CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0))); + CHECK(angle == doctest::Approx(Math::deg_to_rad((real_t)30.0))); CHECK(axis == Vector3(0, 0, -1)); // Testing a rotation of 90° on x-y-z. Basis x90deg(1, 0, 0, 0, 0, -1, 0, 1, 0); x90deg.get_axis_angle(axis, angle); - CHECK(Math::is_equal_approx(angle, pi / (real_t)2)); + CHECK(angle == doctest::Approx(pi / (real_t)2)); CHECK(axis == Vector3(1, 0, 0)); Basis y90deg(0, 0, 1, 0, 1, 0, -1, 0, 0); @@ -255,7 +255,7 @@ TEST_CASE("[Basis] Set axis angle") { // Regression test: checks that the method returns a small angle (not 0). Basis tiny(1, 0, 0, 0, 0.9999995, -0.001, 0, 001, 0.9999995); // The min angle possible with float is 0.001rad. tiny.get_axis_angle(axis, angle); - CHECK(Math::is_equal_approx(angle, (real_t)0.001, (real_t)0.0001)); + CHECK(angle == doctest::Approx(0.001).epsilon(0.0001)); // Regression test: checks that the method returns an angle which is a number (not NaN) Basis bugNan(1.00000024, 0, 0.000100001693, 0, 1, 0, -0.000100009143, 0, 1.00000024); diff --git a/tests/core/math/test_color.h b/tests/core/math/test_color.h index 51c3bc8bdc..c6550778e8 100644 --- a/tests/core/math/test_color.h +++ b/tests/core/math/test_color.h @@ -101,13 +101,13 @@ TEST_CASE("[Color] Reading methods") { const Color dark_blue = Color(0, 0, 0.5, 0.4); CHECK_MESSAGE( - Math::is_equal_approx(dark_blue.get_h(), 240.0f / 360.0f), + dark_blue.get_h() == doctest::Approx(240.0f / 360.0f), "The returned HSV hue should match the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(dark_blue.get_s(), 1.0f), + dark_blue.get_s() == doctest::Approx(1.0f), "The returned HSV saturation should match the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(dark_blue.get_v(), 0.5f), + dark_blue.get_v() == doctest::Approx(0.5f), "The returned HSV value should match the expected value."); } diff --git a/tests/core/math/test_expression.h b/tests/core/math/test_expression.h index 6e3be541b0..9734fd9f36 100644 --- a/tests/core/math/test_expression.h +++ b/tests/core/math/test_expression.h @@ -83,42 +83,42 @@ TEST_CASE("[Expression] Floating-point arithmetic") { expression.parse("-123.456") == OK, "Float identity should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), -123.456), + double(expression.execute()) == doctest::Approx(-123.456), "Float identity should return the expected result."); CHECK_MESSAGE( expression.parse("2.0 + 3.0") == OK, "Float addition should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 5), + double(expression.execute()) == doctest::Approx(5), "Float addition should return the expected result."); CHECK_MESSAGE( expression.parse("3.0 / 10") == OK, "Float / integer division should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 0.3), + double(expression.execute()) == doctest::Approx(0.3), "Float / integer division should return the expected result."); CHECK_MESSAGE( expression.parse("3 / 10.0") == OK, "Basic integer / float division should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 0.3), + double(expression.execute()) == doctest::Approx(0.3), "Basic integer / float division should return the expected result."); CHECK_MESSAGE( expression.parse("3.0 / 10.0") == OK, "Float / float division should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 0.3), + double(expression.execute()) == doctest::Approx(0.3), "Float / float division should return the expected result."); CHECK_MESSAGE( expression.parse("2.5 * (6.0 + 14.25) / 2.0 - 5.12345") == OK, "Float multiplication-addition-subtraction-division should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 20.18905), + double(expression.execute()) == doctest::Approx(20.18905), "Float multiplication-addition-subtraction-division should return the expected result."); } @@ -129,7 +129,7 @@ TEST_CASE("[Expression] Scientific notation") { expression.parse("2.e5") == OK, "The expression should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 200'000), + double(expression.execute()) == doctest::Approx(200'000), "The expression should return the expected result."); // The middle "e" is ignored here. @@ -137,14 +137,14 @@ TEST_CASE("[Expression] Scientific notation") { expression.parse("2e5") == OK, "The expression should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 2e5), + double(expression.execute()) == doctest::Approx(2e5), "The expression should return the expected result."); CHECK_MESSAGE( expression.parse("2e.5") == OK, "The expression should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 2), + double(expression.execute()) == doctest::Approx(2), "The expression should return the expected result."); } @@ -176,7 +176,7 @@ TEST_CASE("[Expression] Built-in functions") { expression.parse("snapped(sin(0.5), 0.01)") == OK, "The expression should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(double(expression.execute()), 0.48), + double(expression.execute()) == doctest::Approx(0.48), "`snapped(sin(0.5), 0.01)` should return the expected result."); CHECK_MESSAGE( diff --git a/tests/core/math/test_geometry_2d.h b/tests/core/math/test_geometry_2d.h index 54893a0b87..27c9e7f58b 100644 --- a/tests/core/math/test_geometry_2d.h +++ b/tests/core/math/test_geometry_2d.h @@ -171,43 +171,43 @@ TEST_CASE("[Geometry2D] Segment intersection with circle") { real_t one = 1.0; CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(4, 0), Vector2(0, 0), 1.0), one_quarter), + Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(4, 0), Vector2(0, 0), 1.0) == doctest::Approx(one_quarter), "Segment from inside to outside of circle should intersect it."); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(4, 0), Vector2(0, 0), Vector2(0, 0), 1.0), three_quarters), + Geometry2D::segment_intersects_circle(Vector2(4, 0), Vector2(0, 0), Vector2(0, 0), 1.0) == doctest::Approx(three_quarters), "Segment from outside to inside of circle should intersect it."); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(-2, 0), Vector2(2, 0), Vector2(0, 0), 1.0), one_quarter), + Geometry2D::segment_intersects_circle(Vector2(-2, 0), Vector2(2, 0), Vector2(0, 0), 1.0) == doctest::Approx(one_quarter), "Segment running through circle should intersect it."); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(-2, 0), Vector2(0, 0), 1.0), one_quarter), + Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(-2, 0), Vector2(0, 0), 1.0) == doctest::Approx(one_quarter), "Segment running through circle should intersect it."); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(1, 0), Vector2(0, 0), 1.0), one), + Geometry2D::segment_intersects_circle(Vector2(0, 0), Vector2(1, 0), Vector2(0, 0), 1.0) == doctest::Approx(one), "Segment starting inside the circle and ending on the circle should intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(0, 0), Vector2(0, 0), 1.0), zero), + Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(0, 0), Vector2(0, 0), 1.0) == doctest::Approx(zero), "Segment starting on the circle and going inwards should intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(2, 0), Vector2(0, 0), 1.0), zero), + Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(2, 0), Vector2(0, 0), 1.0) == doctest::Approx(zero), "Segment starting on the circle and going outwards should intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(1, 0), Vector2(0, 0), 1.0), one), + Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(1, 0), Vector2(0, 0), 1.0) == doctest::Approx(one), "Segment starting outside the circle and ending on the circle intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(-1, 0), Vector2(1, 0), Vector2(0, 0), 2.0), minus_one), + Geometry2D::segment_intersects_circle(Vector2(-1, 0), Vector2(1, 0), Vector2(0, 0), 2.0) == doctest::Approx(minus_one), "Segment completely within the circle should not intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(-1, 0), Vector2(0, 0), 2.0), minus_one), + Geometry2D::segment_intersects_circle(Vector2(1, 0), Vector2(-1, 0), Vector2(0, 0), 2.0) == doctest::Approx(minus_one), "Segment completely within the circle should not intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(3, 0), Vector2(0, 0), 1.0), minus_one), + Geometry2D::segment_intersects_circle(Vector2(2, 0), Vector2(3, 0), Vector2(0, 0), 1.0) == doctest::Approx(minus_one), "Segment completely outside the circle should not intersect it"); CHECK_MESSAGE( - Math::is_equal_approx(Geometry2D::segment_intersects_circle(Vector2(3, 0), Vector2(2, 0), Vector2(0, 0), 1.0), minus_one), + Geometry2D::segment_intersects_circle(Vector2(3, 0), Vector2(2, 0), Vector2(0, 0), 1.0) == doctest::Approx(minus_one), "Segment completely outside the circle should not intersect it"); } diff --git a/tests/core/math/test_rect2.h b/tests/core/math/test_rect2.h index d784875c1c..9984823331 100644 --- a/tests/core/math/test_rect2.h +++ b/tests/core/math/test_rect2.h @@ -102,16 +102,16 @@ TEST_CASE("[Rect2] Basic setters") { TEST_CASE("[Rect2] Area getters") { CHECK_MESSAGE( - Math::is_equal_approx(Rect2(0, 100, 1280, 720).get_area(), 921'600), + Rect2(0, 100, 1280, 720).get_area() == doctest::Approx(921'600), "get_area() should return the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Rect2(0, 100, -1280, -720).get_area(), 921'600), + Rect2(0, 100, -1280, -720).get_area() == doctest::Approx(921'600), "get_area() should return the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Rect2(0, 100, 1280, -720).get_area(), -921'600), + Rect2(0, 100, 1280, -720).get_area() == doctest::Approx(-921'600), "get_area() should return the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Rect2(0, 100, -1280, 720).get_area(), -921'600), + Rect2(0, 100, -1280, 720).get_area() == doctest::Approx(-921'600), "get_area() should return the expected value."); CHECK_MESSAGE( Math::is_zero_approx(Rect2(0, 100, 0, 720).get_area()), diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h index f7e9259329..8f8fccd717 100644 --- a/tests/core/math/test_vector2.h +++ b/tests/core/math/test_vector2.h @@ -49,16 +49,16 @@ TEST_CASE("[Vector2] Angle methods") { const Vector2 vector_x = Vector2(1, 0); const Vector2 vector_y = Vector2(0, 1); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.angle_to(vector_y), (real_t)Math_TAU / 4), + vector_x.angle_to(vector_y) == doctest::Approx((real_t)Math_TAU / 4), "Vector2 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_y.angle_to(vector_x), (real_t)-Math_TAU / 4), + vector_y.angle_to(vector_x) == doctest::Approx((real_t)-Math_TAU / 4), "Vector2 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.angle_to_point(vector_y), (real_t)Math_TAU * 3 / 8), + vector_x.angle_to_point(vector_y) == doctest::Approx((real_t)Math_TAU * 3 / 8), "Vector2 angle_to_point should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_y.angle_to_point(vector_x), (real_t)-Math_TAU / 8), + vector_y.angle_to_point(vector_x) == doctest::Approx((real_t)-Math_TAU / 8), "Vector2 angle_to_point should work as expected."); } @@ -113,10 +113,10 @@ TEST_CASE("[Vector2] Interpolation methods") { Vector2(4, 6).slerp(Vector2(8, 10), 0.5).is_equal_approx(Vector2(5.9076470794008017626, 8.07918879020090480697)), "Vector2 slerp should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.slerp(vector2, 0.5).length(), (real_t)4.31959610746631919), + vector1.slerp(vector2, 0.5).length() == doctest::Approx((real_t)4.31959610746631919), "Vector2 slerp with different length input should return a vector with an interpolated length."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2, vector1.angle_to(vector2)), + vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2 == doctest::Approx(vector1.angle_to(vector2)), "Vector2 slerp with different length input should return a vector with an interpolated angle."); CHECK_MESSAGE( vector1.cubic_interpolate(vector2, Vector2(), Vector2(7, 7), 0.5) == Vector2(2.375, 3.5), @@ -136,19 +136,19 @@ TEST_CASE("[Vector2] Length methods") { vector1.length_squared() == 200, "Vector2 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 10 * (real_t)Math_SQRT2), + vector1.length() == doctest::Approx(10 * (real_t)Math_SQRT2), "Vector2 length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 1300, "Vector2 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), (real_t)36.05551275463989293119), + vector2.length() == doctest::Approx((real_t)36.05551275463989293119), "Vector2 length should work as expected."); CHECK_MESSAGE( vector1.distance_squared_to(vector2) == 500, "Vector2 distance_squared_to should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.distance_to(vector2), (real_t)22.36067977499789696409), + vector1.distance_to(vector2) == doctest::Approx((real_t)22.36067977499789696409), "Vector2 distance_to should work as expected."); } @@ -294,7 +294,7 @@ TEST_CASE("[Vector2] Operators") { TEST_CASE("[Vector2] Other methods") { const Vector2 vector = Vector2(1.2, 3.4); CHECK_MESSAGE( - Math::is_equal_approx(vector.aspect(), (real_t)1.2 / (real_t)3.4), + vector.aspect() == doctest::Approx((real_t)1.2 / (real_t)3.4), "Vector2 aspect should work as expected."); CHECK_MESSAGE( @@ -443,10 +443,10 @@ TEST_CASE("[Vector2] Linear algebra methods") { vector_y.cross(vector_x) == -1, "Vector2 cross product of Y and X should give negative 1."); CHECK_MESSAGE( - Math::is_equal_approx(a.cross(b), (real_t)-28.1), + a.cross(b) == doctest::Approx((real_t)-28.1), "Vector2 cross should return expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Vector2(-a.x, a.y).cross(Vector2(b.x, -b.y)), (real_t)-28.1), + Vector2(-a.x, a.y).cross(Vector2(b.x, -b.y)) == doctest::Approx((real_t)-28.1), "Vector2 cross should return expected value."); CHECK_MESSAGE( @@ -459,10 +459,10 @@ TEST_CASE("[Vector2] Linear algebra methods") { (vector_x * 10).dot(vector_x * 10) == 100.0, "Vector2 dot product of same direction vectors should behave as expected."); CHECK_MESSAGE( - Math::is_equal_approx(a.dot(b), (real_t)57.3), + a.dot(b) == doctest::Approx((real_t)57.3), "Vector2 dot should return expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Vector2(-a.x, a.y).dot(Vector2(b.x, -b.y)), (real_t)-57.3), + Vector2(-a.x, a.y).dot(Vector2(b.x, -b.y)) == doctest::Approx((real_t)-57.3), "Vector2 dot should return expected value."); } diff --git a/tests/core/math/test_vector2i.h b/tests/core/math/test_vector2i.h index 49b0632e3c..c7a0dccdcc 100644 --- a/tests/core/math/test_vector2i.h +++ b/tests/core/math/test_vector2i.h @@ -79,13 +79,13 @@ TEST_CASE("[Vector2i] Length methods") { vector1.length_squared() == 200, "Vector2i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 10 * Math_SQRT2), + vector1.length() == doctest::Approx(10 * Math_SQRT2), "Vector2i length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 1300, "Vector2i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), 36.05551275463989293119), + vector2.length() == doctest::Approx(36.05551275463989293119), "Vector2i length should work as expected."); } @@ -127,7 +127,7 @@ TEST_CASE("[Vector2i] Operators") { TEST_CASE("[Vector2i] Other methods") { const Vector2i vector = Vector2i(1, 3); CHECK_MESSAGE( - Math::is_equal_approx(vector.aspect(), (real_t)1.0 / (real_t)3.0), + vector.aspect() == doctest::Approx((real_t)1.0 / (real_t)3.0), "Vector2i aspect should work as expected."); CHECK_MESSAGE( diff --git a/tests/core/math/test_vector3.h b/tests/core/math/test_vector3.h index 77d3a9d93c..89d73ee6de 100644 --- a/tests/core/math/test_vector3.h +++ b/tests/core/math/test_vector3.h @@ -52,26 +52,26 @@ TEST_CASE("[Vector3] Angle methods") { const Vector3 vector_y = Vector3(0, 1, 0); const Vector3 vector_yz = Vector3(0, 1, 1); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.angle_to(vector_y), (real_t)Math_TAU / 4), + vector_x.angle_to(vector_y) == doctest::Approx((real_t)Math_TAU / 4), "Vector3 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.angle_to(vector_yz), (real_t)Math_TAU / 4), + vector_x.angle_to(vector_yz) == doctest::Approx((real_t)Math_TAU / 4), "Vector3 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_yz.angle_to(vector_x), (real_t)Math_TAU / 4), + vector_yz.angle_to(vector_x) == doctest::Approx((real_t)Math_TAU / 4), "Vector3 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_y.angle_to(vector_yz), (real_t)Math_TAU / 8), + vector_y.angle_to(vector_yz) == doctest::Approx((real_t)Math_TAU / 8), "Vector3 angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.signed_angle_to(vector_y, vector_y), (real_t)Math_TAU / 4), + vector_x.signed_angle_to(vector_y, vector_y) == doctest::Approx((real_t)Math_TAU / 4), "Vector3 signed_angle_to edge case should be positive."); CHECK_MESSAGE( - Math::is_equal_approx(vector_x.signed_angle_to(vector_yz, vector_y), (real_t)Math_TAU / -4), + vector_x.signed_angle_to(vector_yz, vector_y) == doctest::Approx((real_t)Math_TAU / -4), "Vector3 signed_angle_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector_yz.signed_angle_to(vector_x, vector_y), (real_t)Math_TAU / 4), + vector_yz.signed_angle_to(vector_x, vector_y) == doctest::Approx((real_t)Math_TAU / 4), "Vector3 signed_angle_to should work as expected."); } @@ -130,10 +130,10 @@ TEST_CASE("[Vector3] Interpolation methods") { Vector3(4, 6, 2).slerp(Vector3(8, 10, 3), 0.5).is_equal_approx(Vector3(5.90194219811429941053, 8.06758688849378394534, 2.558307894718317120038)), "Vector3 slerp should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.slerp(vector2, 0.5).length(), (real_t)6.25831088708303172), + vector1.slerp(vector2, 0.5).length() == doctest::Approx((real_t)6.25831088708303172), "Vector3 slerp with different length input should return a vector with an interpolated length."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2, vector1.angle_to(vector2)), + vector1.angle_to(vector1.slerp(vector2, 0.5)) * 2 == doctest::Approx(vector1.angle_to(vector2)), "Vector3 slerp with different length input should return a vector with an interpolated angle."); CHECK_MESSAGE( vector1.cubic_interpolate(vector2, Vector3(), Vector3(7, 7, 7), 0.5) == Vector3(2.375, 3.5, 4.625), @@ -153,19 +153,19 @@ TEST_CASE("[Vector3] Length methods") { vector1.length_squared() == 300, "Vector3 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 10 * (real_t)Math_SQRT3), + vector1.length() == doctest::Approx(10 * (real_t)Math_SQRT3), "Vector3 length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 2900, "Vector3 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), (real_t)53.8516480713450403125), + vector2.length() == doctest::Approx((real_t)53.8516480713450403125), "Vector3 length should work as expected."); CHECK_MESSAGE( vector1.distance_squared_to(vector2) == 1400, "Vector3 distance_squared_to should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.distance_to(vector2), (real_t)37.41657386773941385584), + vector1.distance_to(vector2) == doctest::Approx((real_t)37.41657386773941385584), "Vector3 distance_to should work as expected."); } @@ -473,10 +473,10 @@ TEST_CASE("[Vector3] Linear algebra methods") { (vector_x * 10).dot(vector_x * 10) == 100.0, "Vector3 dot product of same direction vectors should behave as expected."); CHECK_MESSAGE( - Math::is_equal_approx(a.dot(b), (real_t)75.24), + a.dot(b) == doctest::Approx((real_t)75.24), "Vector3 dot should return expected value."); CHECK_MESSAGE( - Math::is_equal_approx(Vector3(-a.x, a.y, -a.z).dot(Vector3(b.x, -b.y, b.z)), (real_t)-75.24), + Vector3(-a.x, a.y, -a.z).dot(Vector3(b.x, -b.y, b.z)) == doctest::Approx((real_t)-75.24), "Vector3 dot should return expected value."); } diff --git a/tests/core/math/test_vector3i.h b/tests/core/math/test_vector3i.h index 2050b222d0..56578f99eb 100644 --- a/tests/core/math/test_vector3i.h +++ b/tests/core/math/test_vector3i.h @@ -82,13 +82,13 @@ TEST_CASE("[Vector3i] Length methods") { vector1.length_squared() == 300, "Vector3i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 10 * Math_SQRT3), + vector1.length() == doctest::Approx(10 * Math_SQRT3), "Vector3i length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 2900, "Vector3i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), 53.8516480713450403125), + vector2.length() == doctest::Approx(53.8516480713450403125), "Vector3i length should work as expected."); } diff --git a/tests/core/math/test_vector4.h b/tests/core/math/test_vector4.h index b31db56f67..6ed85661cb 100644 --- a/tests/core/math/test_vector4.h +++ b/tests/core/math/test_vector4.h @@ -91,19 +91,19 @@ TEST_CASE("[Vector4] Length methods") { vector1.length_squared() == 400, "Vector4 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 20), + vector1.length() == doctest::Approx(20), "Vector4 length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 5400, "Vector4 length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), (real_t)73.484692283495), + vector2.length() == doctest::Approx((real_t)73.484692283495), "Vector4 length should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.distance_to(vector2), (real_t)54.772255750517), + vector1.distance_to(vector2) == doctest::Approx((real_t)54.772255750517), "Vector4 distance_to should work as expected."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.distance_squared_to(vector2), 3000), + vector1.distance_squared_to(vector2) == doctest::Approx(3000), "Vector4 distance_squared_to should work as expected."); } @@ -311,7 +311,7 @@ TEST_CASE("[Vector4] Linear algebra methods") { (vector_x * 10).dot(vector_x * 10) == 100.0, "Vector4 dot product of same direction vectors should behave as expected."); CHECK_MESSAGE( - Math::is_equal_approx((vector1 * 2).dot(vector2 * 4), (real_t)-25.9 * 8), + (vector1 * 2).dot(vector2 * 4) == doctest::Approx((real_t)-25.9 * 8), "Vector4 dot product should work as expected."); } diff --git a/tests/core/math/test_vector4i.h b/tests/core/math/test_vector4i.h index 309162c3f7..30d38607dd 100644 --- a/tests/core/math/test_vector4i.h +++ b/tests/core/math/test_vector4i.h @@ -82,13 +82,13 @@ TEST_CASE("[Vector4i] Length methods") { vector1.length_squared() == 400, "Vector4i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector1.length(), 20), + vector1.length() == doctest::Approx(20), "Vector4i length should work as expected."); CHECK_MESSAGE( vector2.length_squared() == 5400, "Vector4i length_squared should work as expected and return exact result."); CHECK_MESSAGE( - Math::is_equal_approx(vector2.length(), 73.4846922835), + vector2.length() == doctest::Approx(73.4846922835), "Vector4i length should work as expected."); } diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index cd1b421ce8..7e4e3aa9f0 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -485,6 +485,7 @@ TEST_CASE("[String] Splitting") { const char *slices_l[3] = { "Mars", "Jupiter", "Saturn,Uranus" }; const char *slices_r[3] = { "Mars,Jupiter", "Saturn", "Uranus" }; + const char *slices_3[4] = { "t", "e", "s", "t" }; l = s.split(",", true, 2); CHECK(l.size() == 3); @@ -498,6 +499,13 @@ TEST_CASE("[String] Splitting") { CHECK(l[i] == slices_r[i]); } + s = "test"; + l = s.split(); + CHECK(l.size() == 4); + for (int i = 0; i < l.size(); i++) { + CHECK(l[i] == slices_3[i]); + } + s = "Mars Jupiter Saturn Uranus"; const char *slices_s[4] = { "Mars", "Jupiter", "Saturn", "Uranus" }; l = s.split_spaces(); diff --git a/tests/scene/test_animation.h b/tests/scene/test_animation.h index ca80f0ecab..e921779c23 100644 --- a/tests/scene/test_animation.h +++ b/tests/scene/test_animation.h @@ -40,8 +40,8 @@ namespace TestAnimation { TEST_CASE("[Animation] Empty animation getters") { const Ref<Animation> animation = memnew(Animation); - CHECK(Math::is_equal_approx(animation->get_length(), real_t(1.0))); - CHECK(Math::is_equal_approx(animation->get_step(), real_t(0.1))); + CHECK(animation->get_length() == doctest::Approx(real_t(1.0))); + CHECK(animation->get_step() == doctest::Approx(real_t(0.1))); } TEST_CASE("[Animation] Create value track") { @@ -59,33 +59,33 @@ TEST_CASE("[Animation] Create value track") { CHECK(int(animation->track_get_key_value(0, 0)) == 0); CHECK(int(animation->track_get_key_value(0, 1)) == 100); - CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, -0.2), 0.0)); - CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.0), 0.0)); - CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.2), 40.0)); - CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.4), 80.0)); - CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.5), 100.0)); - CHECK(Math::is_equal_approx(animation->value_track_interpolate(0, 0.6), 100.0)); + CHECK(animation->value_track_interpolate(0, -0.2) == doctest::Approx(0.0)); + CHECK(animation->value_track_interpolate(0, 0.0) == doctest::Approx(0.0)); + CHECK(animation->value_track_interpolate(0, 0.2) == doctest::Approx(40.0)); + CHECK(animation->value_track_interpolate(0, 0.4) == doctest::Approx(80.0)); + CHECK(animation->value_track_interpolate(0, 0.5) == doctest::Approx(100.0)); + CHECK(animation->value_track_interpolate(0, 0.6) == doctest::Approx(100.0)); - CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0))); - CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0))); + CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0))); + CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0))); ERR_PRINT_OFF; // Nonexistent keys. CHECK(animation->track_get_key_value(0, 2).is_null()); CHECK(animation->track_get_key_value(0, -1).is_null()); - CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 2), real_t(-1.0))); + CHECK(animation->track_get_key_transition(0, 2) == doctest::Approx(real_t(-1.0))); // Nonexistent track (and keys). CHECK(animation->track_get_key_value(1, 0).is_null()); CHECK(animation->track_get_key_value(1, 1).is_null()); CHECK(animation->track_get_key_value(1, 2).is_null()); CHECK(animation->track_get_key_value(1, -1).is_null()); - CHECK(Math::is_equal_approx(animation->track_get_key_transition(1, 0), real_t(-1.0))); + CHECK(animation->track_get_key_transition(1, 0) == doctest::Approx(real_t(-1.0))); // This is a value track, so the methods below should return errors. CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); - CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0))); + CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0)); CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); ERR_PRINT_ON; } @@ -123,15 +123,15 @@ TEST_CASE("[Animation] Create 3D position track") { CHECK(r_interpolation.is_equal_approx(Vector3(3.5, 4, 5))); // 3D position tracks always use linear interpolation for performance reasons. - CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0))); - CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0))); + CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0))); + CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0))); // This is a 3D position track, so the methods below should return errors. ERR_PRINT_OFF; CHECK(animation->value_track_interpolate(0, 0.0).is_null()); CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); - CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0))); + CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0)); CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); ERR_PRINT_ON; } @@ -169,15 +169,15 @@ TEST_CASE("[Animation] Create 3D rotation track") { CHECK(r_interpolation.is_equal_approx(Quaternion(0.231055, 0.374912, 0.761204, 0.476048))); // 3D rotation tracks always use linear interpolation for performance reasons. - CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0))); - CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0))); + CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0))); + CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0))); // This is a 3D rotation track, so the methods below should return errors. ERR_PRINT_OFF; CHECK(animation->value_track_interpolate(0, 0.0).is_null()); CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); - CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0))); + CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(real_t(0.0))); CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); ERR_PRINT_ON; } @@ -215,15 +215,15 @@ TEST_CASE("[Animation] Create 3D scale track") { CHECK(r_interpolation.is_equal_approx(Vector3(3.5, 4, 5))); // 3D scale tracks always use linear interpolation for performance reasons. - CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0))); - CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0))); + CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(1.0)); + CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(1.0)); // This is a 3D scale track, so the methods below should return errors. ERR_PRINT_OFF; CHECK(animation->value_track_interpolate(0, 0.0).is_null()); CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); - CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0))); + CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0)); CHECK(animation->blend_shape_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); ERR_PRINT_ON; } @@ -242,32 +242,32 @@ TEST_CASE("[Animation] Create blend shape track") { float r_blend = 0.0f; CHECK(animation->blend_shape_track_get_key(0, 0, &r_blend) == OK); - CHECK(Math::is_equal_approx(r_blend, -1.0f)); + CHECK(r_blend == doctest::Approx(-1.0f)); CHECK(animation->blend_shape_track_get_key(0, 1, &r_blend) == OK); - CHECK(Math::is_equal_approx(r_blend, 1.0f)); + CHECK(r_blend == doctest::Approx(1.0f)); CHECK(animation->blend_shape_track_interpolate(0, -0.2, &r_blend) == OK); - CHECK(Math::is_equal_approx(r_blend, -1.0f)); + CHECK(r_blend == doctest::Approx(-1.0f)); CHECK(animation->blend_shape_track_interpolate(0, 0.0, &r_blend) == OK); - CHECK(Math::is_equal_approx(r_blend, -1.0f)); + CHECK(r_blend == doctest::Approx(-1.0f)); CHECK(animation->blend_shape_track_interpolate(0, 0.2, &r_blend) == OK); - CHECK(Math::is_equal_approx(r_blend, -0.2f)); + CHECK(r_blend == doctest::Approx(-0.2f)); CHECK(animation->blend_shape_track_interpolate(0, 0.4, &r_blend) == OK); - CHECK(Math::is_equal_approx(r_blend, 0.6f)); + CHECK(r_blend == doctest::Approx(0.6f)); CHECK(animation->blend_shape_track_interpolate(0, 0.5, &r_blend) == OK); - CHECK(Math::is_equal_approx(r_blend, 1.0f)); + CHECK(r_blend == doctest::Approx(1.0f)); CHECK(animation->blend_shape_track_interpolate(0, 0.6, &r_blend) == OK); - CHECK(Math::is_equal_approx(r_blend, 1.0f)); + CHECK(r_blend == doctest::Approx(1.0f)); // Blend shape tracks always use linear interpolation for performance reasons. - CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 0), real_t(1.0))); - CHECK(Math::is_equal_approx(animation->track_get_key_transition(0, 1), real_t(1.0))); + CHECK(animation->track_get_key_transition(0, 0) == doctest::Approx(real_t(1.0))); + CHECK(animation->track_get_key_transition(0, 1) == doctest::Approx(real_t(1.0))); // This is a blend shape track, so the methods below should return errors. ERR_PRINT_OFF; @@ -275,7 +275,7 @@ TEST_CASE("[Animation] Create blend shape track") { CHECK(animation->position_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); CHECK(animation->rotation_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); CHECK(animation->scale_track_interpolate(0, 0.0, nullptr) == ERR_INVALID_PARAMETER); - CHECK(Math::is_zero_approx(animation->bezier_track_interpolate(0, 0.0))); + CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(0.0)); ERR_PRINT_ON; } @@ -289,15 +289,15 @@ TEST_CASE("[Animation] Create Bezier track") { CHECK(animation->get_track_count() == 1); CHECK(!animation->track_is_compressed(0)); - CHECK(Math::is_equal_approx(animation->bezier_track_get_key_value(0, 0), real_t(-1.0))); - CHECK(Math::is_equal_approx(animation->bezier_track_get_key_value(0, 1), real_t(1.0))); + CHECK(animation->bezier_track_get_key_value(0, 0) == doctest::Approx(real_t(-1.0))); + CHECK(animation->bezier_track_get_key_value(0, 1) == doctest::Approx(real_t(1.0))); - CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, -0.2), real_t(-1.0))); - CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.0), real_t(-1.0))); - CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.2), real_t(-0.76057207584381))); - CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.4), real_t(-0.39975279569626))); - CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.5), real_t(1.0))); - CHECK(Math::is_equal_approx(animation->bezier_track_interpolate(0, 0.6), real_t(1.0))); + CHECK(animation->bezier_track_interpolate(0, -0.2) == doctest::Approx(real_t(-1.0))); + CHECK(animation->bezier_track_interpolate(0, 0.0) == doctest::Approx(real_t(-1.0))); + CHECK(animation->bezier_track_interpolate(0, 0.2) == doctest::Approx(real_t(-0.76057207584381))); + CHECK(animation->bezier_track_interpolate(0, 0.4) == doctest::Approx(real_t(-0.39975279569626))); + CHECK(animation->bezier_track_interpolate(0, 0.5) == doctest::Approx(real_t(1.0))); + CHECK(animation->bezier_track_interpolate(0, 0.6) == doctest::Approx(real_t(1.0))); // This is a bezier track, so the methods below should return errors. ERR_PRINT_OFF; diff --git a/tests/scene/test_audio_stream_wav.h b/tests/scene/test_audio_stream_wav.h index 4ba431dfc2..c84c66b0e6 100644 --- a/tests/scene/test_audio_stream_wav.h +++ b/tests/scene/test_audio_stream_wav.h @@ -138,7 +138,7 @@ void run_test(String file_name, AudioStreamWAV::Format data_format, bool stereo, CHECK(stream->get_data() == test_data); SUBCASE("Stream length is computed properly") { - CHECK(Math::is_equal_approx(stream->get_length(), double(wav_count / wav_rate))); + CHECK(stream->get_length() == doctest::Approx(double(wav_count / wav_rate))); } SUBCASE("Stream can be saved as .wav") { diff --git a/tests/scene/test_curve.h b/tests/scene/test_curve.h index ad7625ddc5..36ec0c0a4d 100644 --- a/tests/scene/test_curve.h +++ b/tests/scene/test_curve.h @@ -83,54 +83,54 @@ TEST_CASE("[Curve] Custom curve with free tangents") { Math::is_zero_approx(curve->sample(-0.1)), "Custom free curve should return the expected value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(0.1), (real_t)0.352), + curve->sample(0.1) == doctest::Approx((real_t)0.352), "Custom free curve should return the expected value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(0.4), (real_t)0.352), + curve->sample(0.4) == doctest::Approx((real_t)0.352), "Custom free curve should return the expected value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(0.7), (real_t)0.896), + curve->sample(0.7) == doctest::Approx((real_t)0.896), "Custom free curve should return the expected value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(1), 1), + curve->sample(1) == doctest::Approx(1), "Custom free curve should return the expected value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(2), 1), + curve->sample(2) == doctest::Approx(1), "Custom free curve should return the expected value at offset 0.1."); CHECK_MESSAGE( Math::is_zero_approx(curve->sample_baked(-0.1)), "Custom free curve should return the expected baked value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(0.1), (real_t)0.352), + curve->sample_baked(0.1) == doctest::Approx((real_t)0.352), "Custom free curve should return the expected baked value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(0.4), (real_t)0.352), + curve->sample_baked(0.4) == doctest::Approx((real_t)0.352), "Custom free curve should return the expected baked value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.896), + curve->sample_baked(0.7) == doctest::Approx((real_t)0.896), "Custom free curve should return the expected baked value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(1), 1), + curve->sample_baked(1) == doctest::Approx(1), "Custom free curve should return the expected baked value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(2), 1), + curve->sample_baked(2) == doctest::Approx(1), "Custom free curve should return the expected baked value at offset 0.1."); curve->remove_point(1); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(0.1), 0), + curve->sample(0.1) == doctest::Approx(0), "Custom free curve should return the expected value at offset 0.1 after removing point at index 1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(0.1), 0), + curve->sample_baked(0.1) == doctest::Approx(0), "Custom free curve should return the expected baked value at offset 0.1 after removing point at index 1."); curve->clear_points(); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(0.6), 0), + curve->sample(0.6) == doctest::Approx(0), "Custom free curve should return the expected value at offset 0.6 after clearing all points."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(0.6), 0), + curve->sample_baked(0.6) == doctest::Approx(0), "Custom free curve should return the expected baked value at offset 0.6 after clearing all points."); } @@ -143,7 +143,7 @@ TEST_CASE("[Curve] Custom curve with linear tangents") { curve->add_point(Vector2(0.75, 1), 0, 0, Curve::TangentMode::TANGENT_LINEAR, Curve::TangentMode::TANGENT_LINEAR); CHECK_MESSAGE( - Math::is_equal_approx(curve->get_point_left_tangent(3), 4), + curve->get_point_left_tangent(3) == doctest::Approx(4), "get_point_left_tangent() should return the expected value for point index 3."); CHECK_MESSAGE( Math::is_zero_approx(curve->get_point_right_tangent(3)), @@ -172,48 +172,48 @@ TEST_CASE("[Curve] Custom curve with linear tangents") { Math::is_zero_approx(curve->sample(-0.1)), "Custom linear curve should return the expected value at offset -0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(0.1), (real_t)0.4), + curve->sample(0.1) == doctest::Approx((real_t)0.4), "Custom linear curve should return the expected value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(0.4), (real_t)0.4), + curve->sample(0.4) == doctest::Approx((real_t)0.4), "Custom linear curve should return the expected value at offset 0.4."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(0.7), (real_t)0.8), + curve->sample(0.7) == doctest::Approx((real_t)0.8), "Custom linear curve should return the expected value at offset 0.7."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(1), 1), + curve->sample(1) == doctest::Approx(1), "Custom linear curve should return the expected value at offset 1.0."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(2), 1), + curve->sample(2) == doctest::Approx(1), "Custom linear curve should return the expected value at offset 2.0."); CHECK_MESSAGE( Math::is_zero_approx(curve->sample_baked(-0.1)), "Custom linear curve should return the expected baked value at offset -0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(0.1), (real_t)0.4), + curve->sample_baked(0.1) == doctest::Approx((real_t)0.4), "Custom linear curve should return the expected baked value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(0.4), (real_t)0.4), + curve->sample_baked(0.4) == doctest::Approx((real_t)0.4), "Custom linear curve should return the expected baked value at offset 0.4."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.8), + curve->sample_baked(0.7) == doctest::Approx((real_t)0.8), "Custom linear curve should return the expected baked value at offset 0.7."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(1), 1), + curve->sample_baked(1) == doctest::Approx(1), "Custom linear curve should return the expected baked value at offset 1.0."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(2), 1), + curve->sample_baked(2) == doctest::Approx(1), "Custom linear curve should return the expected baked value at offset 2.0."); ERR_PRINT_OFF; curve->remove_point(10); ERR_PRINT_ON; CHECK_MESSAGE( - Math::is_equal_approx(curve->sample(0.7), (real_t)0.8), + curve->sample(0.7) == doctest::Approx((real_t)0.8), "Custom free curve should return the expected value at offset 0.7 after removing point at invalid index 10."); CHECK_MESSAGE( - Math::is_equal_approx(curve->sample_baked(0.7), (real_t)0.8), + curve->sample_baked(0.7) == doctest::Approx((real_t)0.8), "Custom free curve should return the expected baked value at offset 0.7 after removing point at invalid index 10."); } diff --git a/tests/scene/test_primitives.h b/tests/scene/test_primitives.h index ceec117700..8bac903d93 100644 --- a/tests/scene/test_primitives.h +++ b/tests/scene/test_primitives.h @@ -57,9 +57,9 @@ TEST_CASE("[SceneTree][Primitive][Capsule] Capsule Primitive") { capsule->set_radial_segments(16); capsule->set_rings(32); - CHECK_MESSAGE(Math::is_equal_approx(capsule->get_radius(), 1.3f), + CHECK_MESSAGE(capsule->get_radius() == doctest::Approx(1.3f), "Get/Set radius work with one set."); - CHECK_MESSAGE(Math::is_equal_approx(capsule->get_height(), 7.1f), + CHECK_MESSAGE(capsule->get_height() == doctest::Approx(7.1f), "Get/Set radius work with one set."); CHECK_MESSAGE(capsule->get_radial_segments() == 16, "Get/Set radius work with one set."); @@ -129,7 +129,7 @@ TEST_CASE("[SceneTree][Primitive][Capsule] Capsule Primitive") { if (normals[ii].y == 0.f) { float mag_of_normal = Math::sqrt(normals[ii].x * normals[ii].x + normals[ii].z * normals[ii].z); Vector3 normalized_normal = normals[ii] / mag_of_normal; - CHECK_MESSAGE(Math::is_equal_approx(point_dist_from_yaxis, radius), + CHECK_MESSAGE(point_dist_from_yaxis == doctest::Approx(radius), "Points on the tube of the capsule are radius away from y-axis."); CHECK_MESSAGE(normalized_normal.is_equal_approx(yaxis_to_point), "Normal points orthogonal from mid cylinder."); @@ -244,9 +244,9 @@ TEST_CASE("[SceneTree][Primitive][Cylinder] Cylinder Primitive") { cylinder->set_cap_top(false); cylinder->set_cap_bottom(false); - CHECK(Math::is_equal_approx(cylinder->get_top_radius(), 4.3f)); - CHECK(Math::is_equal_approx(cylinder->get_bottom_radius(), 1.2f)); - CHECK(Math::is_equal_approx(cylinder->get_height(), 9.77f)); + CHECK(cylinder->get_top_radius() == doctest::Approx(4.3f)); + CHECK(cylinder->get_bottom_radius() == doctest::Approx(1.2f)); + CHECK(cylinder->get_height() == doctest::Approx(9.77f)); CHECK(cylinder->get_radial_segments() == 12); CHECK(cylinder->get_rings() == 16); CHECK(!cylinder->is_cap_top()); @@ -478,7 +478,7 @@ TEST_CASE("[SceneTree][Primitive][Prism] Prism Primitive") { prism->set_subdivide_height(5); prism->set_subdivide_depth(64); - CHECK(Math::is_equal_approx(prism->get_left_to_right(), 3.4f)); + CHECK(prism->get_left_to_right() == doctest::Approx(3.4f)); CHECK(prism->get_size().is_equal_approx(size)); CHECK(prism->get_subdivide_width() == 36); CHECK(prism->get_subdivide_height() == 5); @@ -513,8 +513,8 @@ TEST_CASE("[SceneTree][Primitive][Sphere] Sphere Primitive") { sphere->set_rings(5); sphere->set_is_hemisphere(true); - CHECK(Math::is_equal_approx(sphere->get_radius(), 3.4f)); - CHECK(Math::is_equal_approx(sphere->get_height(), 2.2f)); + CHECK(sphere->get_radius() == doctest::Approx(3.4f)); + CHECK(sphere->get_height() == doctest::Approx(2.2f)); CHECK(sphere->get_radial_segments() == 36); CHECK(sphere->get_rings() == 5); CHECK(sphere->get_is_hemisphere()); @@ -581,8 +581,8 @@ TEST_CASE("[SceneTree][Primitive][Torus] Torus Primitive") { torus->set_rings(19); torus->set_ring_segments(43); - CHECK(Math::is_equal_approx(torus->get_inner_radius(), 3.2f)); - CHECK(Math::is_equal_approx(torus->get_outer_radius(), 9.5f)); + CHECK(torus->get_inner_radius() == doctest::Approx(3.2f)); + CHECK(torus->get_outer_radius() == doctest::Approx(9.5f)); CHECK(torus->get_rings() == 19); CHECK(torus->get_ring_segments() == 43); } @@ -610,8 +610,8 @@ TEST_CASE("[SceneTree][Primitive][TubeTrail] TubeTrail Primitive") { Ref<Curve> curve = memnew(Curve); tube->set_curve(curve); - CHECK(Math::is_equal_approx(tube->get_radius(), 7.2f)); - CHECK(Math::is_equal_approx(tube->get_section_length(), 5.5f)); + CHECK(tube->get_radius() == doctest::Approx(7.2f)); + CHECK(tube->get_section_length() == doctest::Approx(5.5f)); CHECK(tube->get_radial_steps() == 9); CHECK(tube->get_sections() == 33); CHECK(tube->get_section_rings() == 12); @@ -670,8 +670,8 @@ TEST_CASE("[SceneTree][Primitive][RibbonTrail] RibbonTrail Primitive") { ribbon->set_section_segments(9); ribbon->set_curve(curve); - CHECK(Math::is_equal_approx(ribbon->get_size(), 4.3f)); - CHECK(Math::is_equal_approx(ribbon->get_section_length(), 1.3f)); + CHECK(ribbon->get_size() == doctest::Approx(4.3f)); + CHECK(ribbon->get_section_length() == doctest::Approx(1.3f)); CHECK(ribbon->get_sections() == 16); CHECK(ribbon->get_section_segments() == 9); CHECK(ribbon->get_curve() == curve); @@ -781,11 +781,11 @@ TEST_CASE("[SceneTree][Primitive][Text] Text Primitive") { CHECK(text->get_structured_text_bidi_override_options() == options); CHECK(text->is_uppercase() == true); CHECK(text->get_offset() == offset); - CHECK(Math::is_equal_approx(text->get_line_spacing(), 1.7f)); - CHECK(Math::is_equal_approx(text->get_width(), width)); - CHECK(Math::is_equal_approx(text->get_depth(), depth)); - CHECK(Math::is_equal_approx(text->get_curve_step(), curve_step)); - CHECK(Math::is_equal_approx(text->get_pixel_size(), pixel_size)); + CHECK(text->get_line_spacing() == doctest::Approx(1.7f)); + CHECK(text->get_width() == doctest::Approx(width)); + CHECK(text->get_depth() == doctest::Approx(depth)); + CHECK(text->get_curve_step() == doctest::Approx(curve_step)); + CHECK(text->get_pixel_size() == doctest::Approx(pixel_size)); } SUBCASE("[Primitive][Text] Set objects multiple times.") { diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h index e34f2970d4..5dad7d06e1 100644 --- a/tests/scene/test_text_edit.h +++ b/tests/scene/test_text_edit.h @@ -734,13 +734,20 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { } SUBCASE("[TextEdit] add selection for next occurrence") { - text_edit->set_text("\ntest other_test\nrandom test\nword test word"); + text_edit->set_text("\ntest other_test\nrandom test\nword test word nonrandom"); text_edit->set_caret_column(0); text_edit->set_caret_line(1); - text_edit->select_word_under_caret(); - CHECK(text_edit->has_selection(0)); + // First selection made by the implicit select_word_under_caret call + text_edit->add_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 1); CHECK(text_edit->get_selected_text(0) == "test"); + CHECK(text_edit->get_selection_from_line(0) == 1); + CHECK(text_edit->get_selection_from_column(0) == 0); + CHECK(text_edit->get_selection_to_line(0) == 1); + CHECK(text_edit->get_selection_to_column(0) == 4); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 4); text_edit->add_selection_for_next_occurrence(); CHECK(text_edit->get_caret_count() == 2); @@ -771,6 +778,27 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_selection_to_column(3) == 9); CHECK(text_edit->get_caret_line(3) == 3); CHECK(text_edit->get_caret_column(3) == 9); + + // A different word with a new manually added caret + text_edit->add_caret(2, 1); + text_edit->select(2, 0, 2, 4, 4); + CHECK(text_edit->get_selected_text(4) == "rand"); + + text_edit->add_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 6); + CHECK(text_edit->get_selected_text(5) == "rand"); + CHECK(text_edit->get_selection_from_line(5) == 3); + CHECK(text_edit->get_selection_from_column(5) == 18); + CHECK(text_edit->get_selection_to_line(5) == 3); + CHECK(text_edit->get_selection_to_column(5) == 22); + CHECK(text_edit->get_caret_line(5) == 3); + CHECK(text_edit->get_caret_column(5) == 22); + + // Make sure the previous selections are still active + CHECK(text_edit->get_selected_text(0) == "test"); + CHECK(text_edit->get_selected_text(1) == "test"); + CHECK(text_edit->get_selected_text(2) == "test"); + CHECK(text_edit->get_selected_text(3) == "test"); } SUBCASE("[TextEdit] deselect on focus loss") { |