diff options
27 files changed, 293 insertions, 71 deletions
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 9753ac2c4e..200d5fafde 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -53,9 +53,9 @@ enum { VARIANT_PLANE = 13, VARIANT_QUATERNION = 14, VARIANT_AABB = 15, - VARIANT_MATRIX3 = 16, + VARIANT_BASIS = 16, VARIANT_TRANSFORM3D = 17, - VARIANT_MATRIX32 = 18, + VARIANT_TRANSFORM2D = 18, VARIANT_COLOR = 20, VARIANT_NODE_PATH = 22, VARIANT_RID = 23, @@ -220,7 +220,7 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { r_v = v; } break; - case VARIANT_MATRIX32: { + case VARIANT_TRANSFORM2D: { Transform2D v; v.elements[0].x = f->get_real(); v.elements[0].y = f->get_real(); @@ -231,7 +231,7 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { r_v = v; } break; - case VARIANT_MATRIX3: { + case VARIANT_BASIS: { Basis v; v.elements[0].x = f->get_real(); v.elements[0].y = f->get_real(); @@ -1476,7 +1476,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia } break; case Variant::TRANSFORM2D: { - f->store_32(VARIANT_MATRIX32); + f->store_32(VARIANT_TRANSFORM2D); Transform2D val = p_property; f->store_real(val.elements[0].x); f->store_real(val.elements[0].y); @@ -1487,7 +1487,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia } break; case Variant::BASIS: { - f->store_32(VARIANT_MATRIX3); + f->store_32(VARIANT_BASIS); Basis val = p_property; f->store_real(val.elements[0].x); f->store_real(val.elements[0].y); diff --git a/core/math/octree.h b/core/math/octree.h index 7861c35e07..23ba4c1aa3 100644 --- a/core/math/octree.h +++ b/core/math/octree.h @@ -103,7 +103,7 @@ private: Octant *parent = nullptr; Octant *children[8] = { nullptr }; - int children_count = 0; // cache for amount of childrens (fast check for removal) + int children_count = 0; // cache for amount of children (fast check for removal) int parent_index = -1; // cache for parent index (fast check for removal) List<Element *, AL> pairable_elements; diff --git a/core/math/vector2.h b/core/math/vector2.h index 588c0201fb..a340036ac7 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -261,11 +261,16 @@ Vector2 Vector2::lerp(const Vector2 &p_to, const real_t p_weight) const { } Vector2 Vector2::slerp(const Vector2 &p_to, const real_t p_weight) const { -#ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Vector2(), "The start Vector2 must be normalized."); -#endif - real_t theta = angle_to(p_to); - return rotated(theta * p_weight); + real_t start_length_sq = length_squared(); + real_t end_length_sq = p_to.length_squared(); + if (unlikely(start_length_sq == 0.0 || end_length_sq == 0.0)) { + // Zero length vectors have no angle, so the best we can do is either lerp or throw an error. + return lerp(p_to, p_weight); + } + real_t start_length = Math::sqrt(start_length_sq); + real_t result_length = Math::lerp(start_length, Math::sqrt(end_length_sq), p_weight); + real_t angle = angle_to(p_to); + return rotated(angle * p_weight) * (result_length / start_length); } Vector2 Vector2::direction_to(const Vector2 &p_to) const { diff --git a/core/math/vector3.h b/core/math/vector3.h index 1861627718..d7a72b05a8 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -240,8 +240,16 @@ Vector3 Vector3::lerp(const Vector3 &p_to, const real_t p_weight) const { } Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const { - real_t theta = angle_to(p_to); - return rotated(cross(p_to).normalized(), theta * p_weight); + real_t start_length_sq = length_squared(); + real_t end_length_sq = p_to.length_squared(); + if (unlikely(start_length_sq == 0.0 || end_length_sq == 0.0)) { + // Zero length vectors have no angle, so the best we can do is either lerp or throw an error. + return lerp(p_to, p_weight); + } + real_t start_length = Math::sqrt(start_length_sq); + real_t result_length = Math::lerp(start_length, Math::sqrt(end_length_sq), p_weight); + real_t angle = angle_to(p_to); + return rotated(cross(p_to).normalized(), angle * p_weight) * (result_length / start_length); } real_t Vector3::distance_to(const Vector3 &p_to) const { diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index c432410d3b..be6d9e07c3 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -109,6 +109,14 @@ Removes the connection between the [code]from_port[/code] slot of the [code]from[/code] GraphNode and the [code]to_port[/code] slot of the [code]to[/code] GraphNode. If the connection does not exist, no connection is removed. </description> </method> + <method name="force_connection_drag_end"> + <return type="void" /> + <description> + Ends the creation of the current connection. In other words, if you are dragging a connection you can use this method to abort the process and remove the line that followed your cursor. + This is best used together with [signal connection_drag_begun] and [signal connection_drag_ended] to add custom behavior like node addition through shortcuts. + [b]Note:[/b] This method suppresses any other connection request signals apart from [signal connection_drag_ended]. + </description> + </method> <method name="get_connection_line"> <return type="PackedVector2Array" /> <argument index="0" name="from" type="Vector2" /> @@ -241,6 +249,19 @@ Emitted at the beginning of a GraphNode movement. </description> </signal> + <signal name="connection_drag_begun"> + <argument index="0" name="from" type="String" /> + <argument index="1" name="slot" type="String" /> + <argument index="2" name="is_output" type="bool" /> + <description> + Emitted at the beginning of a connection drag. + </description> + </signal> + <signal name="connection_drag_ended"> + <description> + Emitted at the end of a connection drag. + </description> + </signal> <signal name="connection_from_empty"> <argument index="0" name="to" type="StringName" /> <argument index="1" name="to_slot" type="int" /> diff --git a/doc/classes/HMACContext.xml b/doc/classes/HMACContext.xml index b29f821da5..0b2d65d339 100644 --- a/doc/classes/HMACContext.xml +++ b/doc/classes/HMACContext.xml @@ -15,7 +15,7 @@ var err = ctx.start(HashingContext.HASH_SHA256, key) assert(err == OK) var msg1 = "this is ".to_utf8() - var msg2 = "vewy vewy secret".to_utf8() + var msg2 = "super duper secret".to_utf8() err = ctx.update(msg1) assert(err == OK) err = ctx.update(msg2) @@ -38,7 +38,7 @@ Error err = ctx.Start(HashingContext.HASH_SHA256, key); GD.Assert(err == OK); PackedByteArray msg1 = String("this is ").to_utf8(); - PackedByteArray msg2 = String("vewy vew secret").to_utf8(); + PackedByteArray msg2 = String("super duper secret").to_utf8(); err = ctx.Update(msg1); GD.Assert(err == OK); err = ctx.Update(msg2); diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 2065c59d18..7034fc1f75 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1691,6 +1691,8 @@ <member name="rendering/gles2/compatibility/enable_high_float.Android" type="bool" setter="" getter="" default="false"> </member> <member name="rendering/global_illumination/gi/use_half_resolution" type="bool" setter="" getter="" default="false"> + If [code]true[/code], renders [VoxelGI] and SDFGI ([member Environment.sdfgi_enabled]) buffers at halved resolution (e.g. 960×540 when the viewport size is 1920×1080). This improves performance significantly when VoxelGI or SDFGI is enabled, at the cost of artifacts that may be visible on polygon edges. The loss in quality becomes less noticeable as the viewport resolution increases. [LightmapGI] rendering is not affected by this setting. + [b]Note:[/b] This property is only read when the project starts. To set half-resolution GI at run-time, call [method RenderingServer.gi_set_use_half_resolution] instead. </member> <member name="rendering/global_illumination/sdfgi/frames_to_converge" type="int" setter="" getter="" default="4"> </member> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index f17f6293bc..009e9d3df4 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -1068,7 +1068,7 @@ <argument index="8" name="light_affect" type="float" /> <argument index="9" name="ao_channel_affect" type="float" /> <description> - Sets the variables to be used with the "screen space ambient occlusion" post-process effect. See [Environment] for more details. + Sets the variables to be used with the screen-space ambient occlusion (SSAO) post-process effect. See [Environment] for more details. </description> </method> <method name="environment_set_ssao_quality"> @@ -1080,6 +1080,19 @@ <argument index="4" name="fadeout_from" type="float" /> <argument index="5" name="fadeout_to" type="float" /> <description> + Sets the quality level of the screen-space ambient occlusion (SSAO) post-process effect. See [Environment] for more details. + </description> + </method> + <method name="environment_set_ssil_quality"> + <return type="void" /> + <argument index="0" name="quality" type="int" enum="RenderingServer.EnvironmentSSILQuality" /> + <argument index="1" name="half_size" type="bool" /> + <argument index="2" name="adaptive_target" type="float" /> + <argument index="3" name="blur_passes" type="int" /> + <argument index="4" name="fadeout_from" type="float" /> + <argument index="5" name="fadeout_to" type="float" /> + <description> + Sets the quality level of the screen-space indirect lighting (SSIL) post-process effect. See [Environment] for more details. </description> </method> <method name="environment_set_ssr"> @@ -1252,6 +1265,13 @@ Returns the id of a white texture. Creates one if none exists. </description> </method> + <method name="gi_set_use_half_resolution"> + <return type="void" /> + <argument index="0" name="half_resolution" type="bool" /> + <description> + If [code]half_resolution[/code] is [code]true[/code], renders [VoxelGI] and SDFGI ([member Environment.sdfgi_enabled]) buffers at halved resolution (e.g. 960×540 when the viewport size is 1920×1080). This improves performance significantly when VoxelGI or SDFGI is enabled, at the cost of artifacts that may be visible on polygon edges. The loss in quality becomes less noticeable as the viewport resolution increases. [LightmapGI] rendering is not affected by this setting. See also [member ProjectSettings.rendering/global_illumination/gi/use_half_resolution]. + </description> + </method> <method name="global_variable_add"> <return type="void" /> <argument index="0" name="name" type="StringName" /> @@ -4131,19 +4151,34 @@ <constant name="ENV_SSR_ROUGNESS_QUALITY_HIGH" value="3" enum="EnvironmentSSRRoughnessQuality"> </constant> <constant name="ENV_SSAO_QUALITY_VERY_LOW" value="0" enum="EnvironmentSSAOQuality"> - Lowest quality of screen space ambient occlusion. + Lowest quality of screen-space ambient occlusion. </constant> <constant name="ENV_SSAO_QUALITY_LOW" value="1" enum="EnvironmentSSAOQuality"> - Low quality screen space ambient occlusion. + Low quality screen-space ambient occlusion. </constant> <constant name="ENV_SSAO_QUALITY_MEDIUM" value="2" enum="EnvironmentSSAOQuality"> - Medium quality screen space ambient occlusion. + Medium quality screen-space ambient occlusion. </constant> <constant name="ENV_SSAO_QUALITY_HIGH" value="3" enum="EnvironmentSSAOQuality"> - High quality screen space ambient occlusion. + High quality screen-space ambient occlusion. </constant> <constant name="ENV_SSAO_QUALITY_ULTRA" value="4" enum="EnvironmentSSAOQuality"> - Highest quality screen space ambient occlusion. Uses the adaptive setting which can be dynamically adjusted to smoothly balance performance and visual quality. + Highest quality screen-space ambient occlusion. Uses the adaptive target setting which can be dynamically adjusted to smoothly balance performance and visual quality. + </constant> + <constant name="ENV_SSIL_QUALITY_VERY_LOW" value="0" enum="EnvironmentSSILQuality"> + Lowest quality of screen-space indirect lighting. + </constant> + <constant name="ENV_SSIL_QUALITY_LOW" value="1" enum="EnvironmentSSILQuality"> + Low quality screen-space indirect lighting. + </constant> + <constant name="ENV_SSIL_QUALITY_MEDIUM" value="2" enum="EnvironmentSSILQuality"> + High quality screen-space indirect lighting. + </constant> + <constant name="ENV_SSIL_QUALITY_HIGH" value="3" enum="EnvironmentSSILQuality"> + High quality screen-space indirect lighting. + </constant> + <constant name="ENV_SSIL_QUALITY_ULTRA" value="4" enum="EnvironmentSSILQuality"> + Highest quality screen-space indirect lighting. Uses the adaptive target setting which can be dynamically adjusted to smoothly balance performance and visual quality. </constant> <constant name="ENV_SDFGI_CASCADES_4" value="0" enum="EnvironmentSDFGICascades"> </constant> diff --git a/doc/classes/TabBar.xml b/doc/classes/TabBar.xml index f97b3e08d1..d0976be4b5 100644 --- a/doc/classes/TabBar.xml +++ b/doc/classes/TabBar.xml @@ -49,19 +49,6 @@ Returns [code]true[/code] if select with right mouse button is enabled. </description> </method> - <method name="get_tab_count" qualifiers="const"> - <return type="int" /> - <description> - Returns the number of tabs. - </description> - </method> - <method name="get_tab_disabled" qualifiers="const"> - <return type="bool" /> - <argument index="0" name="tab_idx" type="int" /> - <description> - Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is disabled. - </description> - </method> <method name="get_tab_icon" qualifiers="const"> <return type="Texture2D" /> <argument index="0" name="tab_idx" type="int" /> @@ -117,6 +104,13 @@ Returns the [TabBar]'s rearrange group ID. </description> </method> + <method name="is_tab_disabled" qualifiers="const"> + <return type="bool" /> + <argument index="0" name="tab_idx" type="int" /> + <description> + Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is disabled. + </description> + </method> <method name="move_tab"> <return type="void" /> <argument index="0" name="from" type="int" /> @@ -214,6 +208,9 @@ <member name="tab_close_display_policy" type="int" setter="set_tab_close_display_policy" getter="get_tab_close_display_policy" enum="TabBar.CloseButtonDisplayPolicy" default="0"> Sets when the close button will appear on the tabs. See [enum CloseButtonDisplayPolicy] for details. </member> + <member name="tab_count" type="int" setter="set_tab_count" getter="get_tab_count" default="0"> + The number of tabs currently in the bar. + </member> </members> <signals> <signal name="active_tab_rearranged"> diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index e7faa3ef0f..64256f33fd 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -299,7 +299,7 @@ <argument index="1" name="weight" type="float" /> <description> Returns the result of spherical linear interpolation between this vector and [code]to[/code], by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation. - [b]Note:[/b] Both vectors must be normalized. + This method also handles interpolating the lengths if the input vectors have different lengths. For the special case of one or both input vectors having zero length, this method behaves like [method lerp]. </description> </method> <method name="slide" qualifiers="const"> diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index 8d2ef0ecd9..ead08d86df 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -290,7 +290,7 @@ <argument index="1" name="weight" type="float" /> <description> Returns the result of spherical linear interpolation between this vector and [code]to[/code], by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation. - [b]Note:[/b] Both vectors must be normalized. + This method also handles interpolating the lengths if the input vectors have different lengths. For the special case of one or both input vectors having zero length, this method behaves like [method lerp]. </description> </method> <method name="slide" qualifiers="const"> diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 69af0f6578..807789586b 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -1325,7 +1325,7 @@ public: struct Frame { RenderTarget *current_rt; - // these 2 may have been superceded by the equivalents in the render target. + // these 2 may have been superseded by the equivalents in the render target. // these may be able to be removed. bool clear_request; Color clear_request_color; diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index ab1be7f41b..10654cfe43 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -297,6 +297,8 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) { _set_dirty(false); import_as->set_disabled(false); preset->set_disabled(false); + content->show(); + select_a_resource->hide(); imported->set_text(vformat(TTR("%d Files"), p_paths.size())); diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp index be17fc238a..2126ca1bc9 100644 --- a/editor/plugins/lightmap_gi_editor_plugin.cpp +++ b/editor/plugins/lightmap_gi_editor_plugin.cpp @@ -33,13 +33,14 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) { if (lightmap) { LightmapGI::BakeError err; + const uint64_t time_started = OS::get_singleton()->get_ticks_msec(); if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == lightmap) { err = lightmap->bake(lightmap, p_file, bake_func_step); } else { err = lightmap->bake(lightmap->get_parent(), p_file, bake_func_step); } - bake_func_end(); + bake_func_end(time_started); switch (err) { case LightmapGI::BAKE_ERROR_NO_SAVE_PATH: { @@ -104,11 +105,18 @@ bool LightmapGIEditorPlugin::bake_func_step(float p_progress, const String &p_de return tmp_progress->step(p_description, p_progress * 1000, p_refresh); } -void LightmapGIEditorPlugin::bake_func_end() { +void LightmapGIEditorPlugin::bake_func_end(uint64_t p_time_started) { if (tmp_progress != nullptr) { memdelete(tmp_progress); tmp_progress = nullptr; } + + const int time_taken = (OS::get_singleton()->get_ticks_msec() - p_time_started) * 0.001; + print_line(vformat("Done baking lightmaps in %02d:%02d:%02d.", time_taken / 3600, (time_taken % 3600) / 60, time_taken % 60)); + // Request attention in case the user was doing something else. + // Baking lightmaps is likely the editor task that can take the most time, + // so only request the attention for baking lightmaps. + DisplayServer::get_singleton()->window_request_attention(); } void LightmapGIEditorPlugin::_bind_methods() { diff --git a/editor/plugins/lightmap_gi_editor_plugin.h b/editor/plugins/lightmap_gi_editor_plugin.h index d0edf9f324..5eec972228 100644 --- a/editor/plugins/lightmap_gi_editor_plugin.h +++ b/editor/plugins/lightmap_gi_editor_plugin.h @@ -47,7 +47,7 @@ class LightmapGIEditorPlugin : public EditorPlugin { EditorFileDialog *file_dialog; static EditorProgress *tmp_progress; static bool bake_func_step(float p_progress, const String &p_description, void *, bool p_refresh); - static void bake_func_end(); + static void bake_func_end(uint64_t p_time_started); void _bake_select_file(const String &p_file); void _bake(); diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index 490605e9ed..9d45c365a8 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -261,7 +261,7 @@ void EditorInspectorPluginMaterial::_undo_redo_inspector_callback(Object *p_undo } // For BaseMaterial3D, if a roughness or metallic textures is being assigned to an empty slot, - // set the respective metallic or roughness factor to 1.0 as a convinence feature + // set the respective metallic or roughness factor to 1.0 as a convenience feature BaseMaterial3D *base_material = Object::cast_to<StandardMaterial3D>(p_edited); if (base_material) { Texture2D *texture = Object::cast_to<Texture2D>(p_new_value); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 20c6aafc7f..2098fa2c85 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -353,15 +353,15 @@ void ScriptCreateDialog::_load_exist() { } Vector<String> ScriptCreateDialog::get_hierarchy(String p_object) const { - Vector<String> hierachy; - hierachy.append(p_object); + Vector<String> hierarchy; + hierarchy.append(p_object); String parent_class = ClassDB::get_parent_class(p_object); while (parent_class.is_valid_identifier()) { - hierachy.append(parent_class); + hierarchy.append(parent_class); parent_class = ClassDB::get_parent_class(parent_class); } - return hierachy; + return hierarchy; } void ScriptCreateDialog::_language_changed(int l) { @@ -544,7 +544,7 @@ void ScriptCreateDialog::_update_template_menu() { template_list.clear(); if (is_language_using_templates) { - // Get the lastest templates used for each type of node from project settings then global settings. + // Get the latest templates used for each type of node from project settings then global settings. Dictionary last_local_templates = EditorSettings::get_singleton()->get_project_metadata("script_setup", "templates_dictionary", Dictionary()); Dictionary last_global_templates; if (EditorSettings::get_singleton()->has_meta("script_setup/templates_dictionary")) { diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 81aaef09dc..9db76861ff 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1164,6 +1164,10 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::ExpressionNode *p_expression, GDScriptCompletionIdentifier &r_type) { bool found = false; + if (p_expression == nullptr) { + return false; + } + if (p_expression->is_constant) { // Already has a value, so just use that. r_type = _type_from_variant(p_expression->reduced_value); diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 728f9a1616..57603c6655 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -443,7 +443,7 @@ String OS_UWP::get_name() const { OS::Date OS_UWP::get_date(bool p_utc) const { SYSTEMTIME systemtime; - if (utc) { + if (p_utc) { GetSystemTime(&systemtime); } else { GetLocalTime(&systemtime); @@ -460,10 +460,11 @@ OS::Date OS_UWP::get_date(bool p_utc) const { OS::Time OS_UWP::get_time(bool p_utc) const { SYSTEMTIME systemtime; - if (utc) + if (p_utc) { GetSystemTime(&systemtime); - else + } else { GetLocalTime(&systemtime); + } Time time; time.hour = systemtime.wHour; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index a942fc90aa..128c6cae8b 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -625,7 +625,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double pa->object->set_indexed(pa->subpath, value, &valid); //you are not speshul #ifdef DEBUG_ENABLED if (!valid) { - ERR_PRINT("Failed setting track value '" + String(pa->owner->path) + "'. Check if property exists or the type of key is valid. Animation '" + a->get_name() + "' at node '" + get_path() + "'."); + ERR_PRINT("Failed setting track value '" + String(pa->owner->path) + "'. Check if the property exists or the type of key is valid. Animation '" + a->get_name() + "' at node '" + get_path() + "'."); } #endif @@ -1070,8 +1070,24 @@ void AnimationPlayer::_animation_update_transforms() { bool valid; pa->object->set_indexed(pa->subpath, pa->value_accum, &valid); //you are not speshul #ifdef DEBUG_ENABLED + if (!valid) { - ERR_PRINT("Failed setting key at time " + rtos(playback.current.pos) + " in Animation '" + get_current_animation() + "' at Node '" + get_path() + "', Track '" + String(pa->owner->path) + "'. Check if property exists or the type of key is right for the property"); + // Get subpath as string for printing the error + // Cannot use `String::join(Vector<String>)` because this is a vector of StringName + String key_debug; + if (pa->subpath.size() > 0) { + key_debug = pa->subpath[0]; + for (int subpath_index = 1; subpath_index < pa->subpath.size(); ++subpath_index) { + key_debug += "."; + key_debug += pa->subpath[subpath_index]; + } + } + ERR_PRINT("Failed setting key '" + key_debug + + "' at time " + rtos(playback.current.pos) + + " in Animation '" + get_current_animation() + + "' at Node '" + get_path() + + "', Track '" + String(pa->owner->path) + + "'. Check if the property exists or the type of key is right for the property."); } #endif diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 1ddec4f587..92c770429b 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -600,6 +600,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { to = get_node(String(connecting_from)); //maybe it was erased if (Object::cast_to<GraphNode>(to)) { connecting = true; + emit_signal(SNAME("connection_drag_begun"), connecting_from, connecting_index, false); } return; } @@ -616,6 +617,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { connecting_target = false; connecting_to = pos; just_disconnected = false; + emit_signal(SNAME("connection_drag_begun"), connecting_from, connecting_index, true); return; } } @@ -642,6 +644,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { fr = get_node(String(connecting_from)); //maybe it was erased if (Object::cast_to<GraphNode>(fr)) { connecting = true; + emit_signal(SNAME("connection_drag_begun"), connecting_from, connecting_index, true); } return; } @@ -658,7 +661,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { connecting_target = false; connecting_to = pos; just_disconnected = false; - + emit_signal(SNAME("connection_drag_begun"), connecting_from, connecting_index, false); return; } } @@ -740,11 +743,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { } } - connecting = false; - top_layer->update(); - minimap->update(); - update(); - connections_layer->update(); + if (connecting) { + force_connection_drag_end(); + } } } @@ -1162,9 +1163,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { minimap->update(); } else { if (connecting) { - connecting = false; - top_layer->update(); - minimap->update(); + force_connection_drag_end(); } else { emit_signal(SNAME("popup_request"), get_screen_position() + b->get_position()); } @@ -1394,6 +1393,17 @@ void GraphEdit::clear_connections() { connections_layer->update(); } +void GraphEdit::force_connection_drag_end() { + ERR_FAIL_COND_MSG(!connecting, "Drag end requested without active drag!"); + connecting = false; + connecting_valid = false; + top_layer->update(); + minimap->update(); + update(); + connections_layer->update(); + emit_signal(SNAME("connection_drag_ended")); +} + void GraphEdit::set_zoom(float p_zoom) { set_zoom_custom(p_zoom, get_size() / 2); } @@ -2165,6 +2175,7 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_connection_activity", "from", "from_port", "to", "to_port", "amount"), &GraphEdit::set_connection_activity); ClassDB::bind_method(D_METHOD("get_connection_list"), &GraphEdit::_get_connection_list); ClassDB::bind_method(D_METHOD("clear_connections"), &GraphEdit::clear_connections); + ClassDB::bind_method(D_METHOD("force_connection_drag_end"), &GraphEdit::force_connection_drag_end); ClassDB::bind_method(D_METHOD("get_scroll_ofs"), &GraphEdit::get_scroll_ofs); ClassDB::bind_method(D_METHOD("set_scroll_ofs", "ofs"), &GraphEdit::set_scroll_ofs); @@ -2262,6 +2273,8 @@ void GraphEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("begin_node_move")); ADD_SIGNAL(MethodInfo("end_node_move")); ADD_SIGNAL(MethodInfo("scroll_offset_changed", PropertyInfo(Variant::VECTOR2, "ofs"))); + ADD_SIGNAL(MethodInfo("connection_drag_begun", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::STRING, "slot"), PropertyInfo(Variant::BOOL, "is_output"))); + ADD_SIGNAL(MethodInfo("connection_drag_ended")); } GraphEdit::GraphEdit() { diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index 7cbd0d179d..f1c4e95e38 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -267,6 +267,7 @@ public: bool is_node_connected(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); void disconnect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); void clear_connections(); + void force_connection_drag_end(); void set_connection_activity(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port, float p_activity); diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index f4a0a2fa56..f7ae101690 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -510,6 +510,13 @@ void TabBar::_notification(int p_what) { } } +void TabBar::set_tab_count(int p_count) { + ERR_FAIL_COND(p_count < 0); + tabs.resize(p_count); + update(); + notify_property_list_changed(); +} + int TabBar::get_tab_count() const { return tabs.size(); } @@ -635,7 +642,7 @@ void TabBar::set_tab_disabled(int p_tab, bool p_disabled) { update(); } -bool TabBar::get_tab_disabled(int p_tab) const { +bool TabBar::is_tab_disabled(int p_tab) const { ERR_FAIL_INDEX_V(p_tab, tabs.size(), false); return tabs[p_tab].disabled; } @@ -765,13 +772,9 @@ void TabBar::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) { Tab t; t.text = p_str; t.xl_text = atr(p_str); - t.text_buf.instantiate(); t.text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); t.text_buf->add_string(t.xl_text, get_theme_font(SNAME("font")), get_theme_font_size(SNAME("font_size")), Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); t.icon = p_icon; - t.disabled = false; - t.ofs_cache = 0; - t.size_cache = 0; tabs.push_back(t); _update_cache(); @@ -786,6 +789,7 @@ void TabBar::clear_tabs() { previous = 0; call_deferred(SNAME("_update_hover")); update(); + notify_property_list_changed(); } void TabBar::remove_tab(int p_idx) { @@ -808,6 +812,7 @@ void TabBar::remove_tab(int p_idx) { } _ensure_no_over_offset(); + notify_property_list_changed(); } Variant TabBar::get_drag_data(const Point2 &p_point) { @@ -966,6 +971,7 @@ void TabBar::move_tab(int from, int to) { _update_cache(); update(); + notify_property_list_changed(); } int TabBar::get_tab_width(int p_idx) const { @@ -1128,8 +1134,61 @@ bool TabBar::get_select_with_rmb() const { return select_with_rmb; } +bool TabBar::_set(const StringName &p_name, const Variant &p_value) { + Vector<String> components = String(p_name).split("/", true, 2); + if (components.size() >= 2 && components[0].begins_with("tab_") && components[0].trim_prefix("tab_").is_valid_int()) { + int tab_index = components[0].trim_prefix("tab_").to_int(); + String property = components[1]; + if (property == "title") { + set_tab_title(tab_index, p_value); + return true; + } else if (property == "icon") { + set_tab_icon(tab_index, p_value); + return true; + } else if (components[1] == "disabled") { + set_tab_disabled(tab_index, p_value); + return true; + } + } + return false; +} + +bool TabBar::_get(const StringName &p_name, Variant &r_ret) const { + Vector<String> components = String(p_name).split("/", true, 2); + if (components.size() >= 2 && components[0].begins_with("tab_") && components[0].trim_prefix("tab_").is_valid_int()) { + int tab_index = components[0].trim_prefix("tab_").to_int(); + String property = components[1]; + if (property == "title") { + r_ret = get_tab_title(tab_index); + return true; + } else if (property == "icon") { + r_ret = get_tab_icon(tab_index); + return true; + } else if (components[1] == "disabled") { + r_ret = is_tab_disabled(tab_index); + return true; + } + } + return false; +} + +void TabBar::_get_property_list(List<PropertyInfo> *p_list) const { + for (int i = 0; i < tabs.size(); i++) { + p_list->push_back(PropertyInfo(Variant::STRING, vformat("tab_%d/title", i))); + + PropertyInfo pi = PropertyInfo(Variant::OBJECT, vformat("tab_%d/icon", i), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"); + pi.usage &= ~(get_tab_icon(i).is_null() ? PROPERTY_USAGE_STORAGE : 0); + p_list->push_back(pi); + + pi = PropertyInfo(Variant::BOOL, vformat("tab_%d/disabled", i)); + pi.usage &= ~(!is_tab_disabled(i) ? PROPERTY_USAGE_STORAGE : 0); + p_list->push_back(pi); + } +} + void TabBar::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_hover"), &TabBar::_update_hover); + ClassDB::bind_method(D_METHOD("set_tab_count"), &TabBar::set_tab_count); ClassDB::bind_method(D_METHOD("get_tab_count"), &TabBar::get_tab_count); ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &TabBar::set_current_tab); ClassDB::bind_method(D_METHOD("get_current_tab"), &TabBar::get_current_tab); @@ -1146,7 +1205,7 @@ void TabBar::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &TabBar::set_tab_icon); ClassDB::bind_method(D_METHOD("get_tab_icon", "tab_idx"), &TabBar::get_tab_icon); ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &TabBar::set_tab_disabled); - ClassDB::bind_method(D_METHOD("get_tab_disabled", "tab_idx"), &TabBar::get_tab_disabled); + ClassDB::bind_method(D_METHOD("is_tab_disabled", "tab_idx"), &TabBar::is_tab_disabled); ClassDB::bind_method(D_METHOD("remove_tab", "tab_idx"), &TabBar::remove_tab); ClassDB::bind_method(D_METHOD("add_tab", "title", "icon"), &TabBar::add_tab, DEFVAL(""), DEFVAL(Ref<Texture2D>())); ClassDB::bind_method(D_METHOD("set_tab_alignment", "alignment"), &TabBar::set_tab_alignment); @@ -1184,6 +1243,8 @@ void TabBar::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrolling_enabled"), "set_scrolling_enabled", "get_scrolling_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled"); + ADD_ARRAY_COUNT("Tabs", "tab_count", "set_tab_count", "get_tab_count", "tab_"); + BIND_ENUM_CONSTANT(ALIGNMENT_LEFT); BIND_ENUM_CONSTANT(ALIGNMENT_CENTER); BIND_ENUM_CONSTANT(ALIGNMENT_RIGHT); diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h index d9f9cca305..1741481b40 100644 --- a/scene/gui/tab_bar.h +++ b/scene/gui/tab_bar.h @@ -73,6 +73,10 @@ private: Ref<Texture2D> right_button; Rect2 rb_rect; Rect2 cb_rect; + + Tab() { + text_buf.instantiate(); + } }; int offset = 0; @@ -112,6 +116,9 @@ private: protected: virtual void gui_input(const Ref<InputEvent> &p_event) override; + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; void _notification(int p_what); static void _bind_methods(); @@ -140,7 +147,7 @@ public: Ref<Texture2D> get_tab_icon(int p_tab) const; void set_tab_disabled(int p_tab, bool p_disabled); - bool get_tab_disabled(int p_tab) const; + bool is_tab_disabled(int p_tab) const; void set_tab_right_button(int p_tab, const Ref<Texture2D> &p_right_button); Ref<Texture2D> get_tab_right_button(int p_tab) const; @@ -156,7 +163,9 @@ public: void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy); CloseButtonDisplayPolicy get_tab_close_display_policy() const; + void set_tab_count(int p_count); int get_tab_count() const; + void set_current_tab(int p_current); int get_current_tab() const; int get_previous_tab() const; diff --git a/scene/property_utils.cpp b/scene/property_utils.cpp index e2f1ac8224..2540a633a9 100644 --- a/scene/property_utils.cpp +++ b/scene/property_utils.cpp @@ -111,10 +111,37 @@ Variant PropertyUtils::get_property_default_value(const Object *p_object, const } // Fall back to the default from the native class - if (r_is_class_default) { - *r_is_class_default = true; + { + if (r_is_class_default) { + *r_is_class_default = true; + } + bool valid = false; + Variant value = ClassDB::class_get_default_property_value(p_object->get_class_name(), p_property, &valid); + if (valid) { + if (r_is_valid) { + *r_is_valid = true; + } + return value; + } else { + // Heuristically check if this is a synthetic property (whatever/0, whatever/1, etc.) + // because they are not in the class DB yet must have a default (null). + String prop_str = String(p_property); + int p = prop_str.rfind("/"); + if (p != -1 && p < prop_str.length() - 1) { + bool all_digits = true; + for (int i = p + 1; i < prop_str.length(); i++) { + if (prop_str[i] < '0' || prop_str[i] > '9') { + all_digits = false; + break; + } + } + if (r_is_valid) { + *r_is_valid = all_digits; + } + } + return Variant(); + } } - return ClassDB::class_get_default_property_value(p_object->get_class_name(), p_property, r_is_valid); } // Like SceneState::PackState, but using a raw pointer to avoid the cost of diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 1db9593473..a94f70e20f 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2000,6 +2000,10 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(DECAL_FILTER_LINEAR_MIPMAPS); BIND_ENUM_CONSTANT(DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC); + /* GI API (affects VoxelGI and SDFGI) */ + + ClassDB::bind_method(D_METHOD("gi_set_use_half_resolution", "half_resolution"), &RenderingServer::gi_set_use_half_resolution); + /* VOXEL GI API */ ClassDB::bind_method(D_METHOD("voxel_gi_create"), &RenderingServer::voxel_gi_create); @@ -2325,6 +2329,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_glow_set_use_high_quality", "enable"), &RenderingServer::environment_glow_set_use_high_quality); ClassDB::bind_method(D_METHOD("environment_set_ssr_roughness_quality", "quality"), &RenderingServer::environment_set_ssr_roughness_quality); ClassDB::bind_method(D_METHOD("environment_set_ssao_quality", "quality", "half_size", "adaptive_target", "blur_passes", "fadeout_from", "fadeout_to"), &RenderingServer::environment_set_ssao_quality); + ClassDB::bind_method(D_METHOD("environment_set_ssil_quality", "quality", "half_size", "adaptive_target", "blur_passes", "fadeout_from", "fadeout_to"), &RenderingServer::environment_set_ssil_quality); ClassDB::bind_method(D_METHOD("environment_set_sdfgi_ray_count", "ray_count"), &RenderingServer::environment_set_sdfgi_ray_count); ClassDB::bind_method(D_METHOD("environment_set_sdfgi_frames_to_converge", "frames"), &RenderingServer::environment_set_sdfgi_frames_to_converge); ClassDB::bind_method(D_METHOD("environment_set_sdfgi_frames_to_update_light", "frames"), &RenderingServer::environment_set_sdfgi_frames_to_update_light); @@ -2376,6 +2381,12 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_HIGH); BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_ULTRA); + BIND_ENUM_CONSTANT(ENV_SSIL_QUALITY_VERY_LOW); + BIND_ENUM_CONSTANT(ENV_SSIL_QUALITY_LOW); + BIND_ENUM_CONSTANT(ENV_SSIL_QUALITY_MEDIUM); + BIND_ENUM_CONSTANT(ENV_SSIL_QUALITY_HIGH); + BIND_ENUM_CONSTANT(ENV_SSIL_QUALITY_ULTRA); + BIND_ENUM_CONSTANT(ENV_SDFGI_CASCADES_4); BIND_ENUM_CONSTANT(ENV_SDFGI_CASCADES_6); BIND_ENUM_CONSTANT(ENV_SDFGI_CASCADES_8); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index d36784dbab..ada50292fc 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1608,6 +1608,7 @@ VARIANT_ENUM_CAST(RenderingServer::EnvironmentGlowBlendMode); VARIANT_ENUM_CAST(RenderingServer::EnvironmentToneMapper); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSRRoughnessQuality); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSAOQuality); +VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSILQuality); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGICascades); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGIFramesToConverge); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGIRayCount); |