From ee3a87caf1b274644265a8a3e07dfd11c8ef378b Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Wed, 6 Dec 2023 08:39:21 +0200 Subject: [PATCH 01/95] Fix CanvasOcclusionShaderRD format error with double precision build. (cherry picked from commit c0a1c5ae6190468a15626de2fd5aac5bdc52ed70) --- .../renderer_rd/renderer_canvas_render_rd.cpp | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 6ec9f0768a8d..6cb8a710193d 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1981,8 +1981,7 @@ void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Ve if (oc->vertex_array.is_null()) { //create from scratch //vertices - // TODO: geometry is always of length lc * 6 * sizeof(float), so in doubles builds this will receive half the data it needs - oc->vertex_buffer = RD::get_singleton()->vertex_buffer_create(lc * 6 * sizeof(real_t), geometry); + oc->vertex_buffer = RD::get_singleton()->vertex_buffer_create(lc * 6 * sizeof(float), geometry); Vector buffer; buffer.push_back(oc->vertex_buffer); @@ -2043,7 +2042,18 @@ void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Ve if (oc->sdf_vertex_array.is_null()) { //create from scratch //vertices - oc->sdf_vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_points.size() * 2 * sizeof(real_t), p_points.to_byte_array()); +#ifdef REAL_T_IS_DOUBLE + PackedFloat32Array float_points; + float_points.resize(p_points.size() * 2); + float *float_points_ptr = (float *)float_points.ptrw(); + for (int i = 0; i < p_points.size(); i++) { + float_points_ptr[i * 2] = p_points[i].x; + float_points_ptr[i * 2 + 1] = p_points[i].y; + } + oc->sdf_vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_points.size() * 2 * sizeof(float), float_points.to_byte_array()); +#else + oc->sdf_vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_points.size() * 2 * sizeof(float), p_points.to_byte_array()); +#endif oc->sdf_index_buffer = RD::get_singleton()->index_buffer_create(sdf_indices.size(), RD::INDEX_BUFFER_FORMAT_UINT32, sdf_indices.to_byte_array()); oc->sdf_index_array = RD::get_singleton()->index_array_create(oc->sdf_index_buffer, 0, sdf_indices.size()); @@ -2054,7 +2064,18 @@ void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Ve } else { //update existing - RD::get_singleton()->buffer_update(oc->sdf_vertex_buffer, 0, sizeof(real_t) * 2 * p_points.size(), p_points.ptr()); +#ifdef REAL_T_IS_DOUBLE + PackedFloat32Array float_points; + float_points.resize(p_points.size() * 2); + float *float_points_ptr = (float *)float_points.ptrw(); + for (int i = 0; i < p_points.size(); i++) { + float_points_ptr[i * 2] = p_points[i].x; + float_points_ptr[i * 2 + 1] = p_points[i].y; + } + RD::get_singleton()->buffer_update(oc->sdf_vertex_buffer, 0, sizeof(float) * 2 * p_points.size(), float_points.ptr()); +#else + RD::get_singleton()->buffer_update(oc->sdf_vertex_buffer, 0, sizeof(float) * 2 * p_points.size(), p_points.ptr()); +#endif RD::get_singleton()->buffer_update(oc->sdf_index_buffer, 0, sdf_indices.size() * sizeof(int32_t), sdf_indices.ptr()); } } @@ -2578,15 +2599,15 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() { //pipelines Vector vf; RD::VertexAttribute vd; - vd.format = sizeof(real_t) == sizeof(float) ? RD::DATA_FORMAT_R32G32B32_SFLOAT : RD::DATA_FORMAT_R64G64B64_SFLOAT; + vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + vd.stride = sizeof(float) * 3; vd.location = 0; vd.offset = 0; - vd.stride = sizeof(real_t) * 3; vf.push_back(vd); shadow_render.vertex_format = RD::get_singleton()->vertex_format_create(vf); - vd.format = sizeof(real_t) == sizeof(float) ? RD::DATA_FORMAT_R32G32_SFLOAT : RD::DATA_FORMAT_R64G64_SFLOAT; - vd.stride = sizeof(real_t) * 2; + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + vd.stride = sizeof(float) * 2; vf.write[0] = vd; shadow_render.sdf_vertex_format = RD::get_singleton()->vertex_format_create(vf); From 29811357a307143f95f5c0a175e61c1359cd15ba Mon Sep 17 00:00:00 2001 From: kit Date: Thu, 23 Nov 2023 22:38:34 -0500 Subject: [PATCH 02/95] fix crash on hiding grandparent on mouse exit (cherry picked from commit 78e1702adbfe9313a3747703c5e7abe6864cbcdf) --- scene/main/viewport.cpp | 27 ++++++++++++++++++++++++++- scene/main/viewport.h | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 714c639bf3c3..3330eded6785 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2459,6 +2459,14 @@ void Viewport::_gui_update_mouse_over() { return; } + if (gui.sending_mouse_enter_exit_notifications) { + // If notifications are already being sent, delay call to next frame. + if (get_tree() && !get_tree()->is_connected(SNAME("process_frame"), callable_mp(this, &Viewport::_gui_update_mouse_over))) { + get_tree()->connect(SNAME("process_frame"), callable_mp(this, &Viewport::_gui_update_mouse_over), CONNECT_ONE_SHOT); + } + return; + } + // Rebuild the mouse over hierarchy. LocalVector new_mouse_over_hierarchy; LocalVector needs_enter; @@ -2515,6 +2523,8 @@ void Viewport::_gui_update_mouse_over() { return; } + gui.sending_mouse_enter_exit_notifications = true; + // Send Mouse Exit Self notification. if (gui.mouse_over && !needs_exit.is_empty() && needs_exit[0] == (int)gui.mouse_over_hierarchy.size() - 1) { gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT_SELF); @@ -2536,6 +2546,8 @@ void Viewport::_gui_update_mouse_over() { for (int i = needs_enter.size() - 1; i >= 0; i--) { needs_enter[i]->notification(Control::NOTIFICATION_MOUSE_ENTER); } + + gui.sending_mouse_enter_exit_notifications = false; } Window *Viewport::get_base_window() const { @@ -3208,10 +3220,12 @@ void Viewport::_update_mouse_over(Vector2 p_pos) { gui.mouse_over = over; gui.mouse_over_hierarchy.reserve(gui.mouse_over_hierarchy.size() + over_ancestors.size()); + gui.sending_mouse_enter_exit_notifications = true; + // Send Mouse Enter notifications to parents first. for (int i = over_ancestors.size() - 1; i >= 0; i--) { - over_ancestors[i]->notification(Control::NOTIFICATION_MOUSE_ENTER); gui.mouse_over_hierarchy.push_back(over_ancestors[i]); + over_ancestors[i]->notification(Control::NOTIFICATION_MOUSE_ENTER); } // Send Mouse Enter Self notification. @@ -3219,6 +3233,8 @@ void Viewport::_update_mouse_over(Vector2 p_pos) { gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_ENTER_SELF); } + gui.sending_mouse_enter_exit_notifications = false; + notify_embedded_viewports = true; } } @@ -3260,6 +3276,12 @@ void Viewport::_mouse_leave_viewport() { } void Viewport::_drop_mouse_over(Control *p_until_control) { + if (gui.sending_mouse_enter_exit_notifications) { + // If notifications are already being sent, defer call. + callable_mp(this, &Viewport::_drop_mouse_over).call_deferred(p_until_control); + return; + } + _gui_cancel_tooltip(); SubViewportContainer *c = Object::cast_to(gui.mouse_over); if (c) { @@ -3271,6 +3293,8 @@ void Viewport::_drop_mouse_over(Control *p_until_control) { v->_mouse_leave_viewport(); } } + + gui.sending_mouse_enter_exit_notifications = true; if (gui.mouse_over && gui.mouse_over->is_inside_tree()) { gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT_SELF); } @@ -3284,6 +3308,7 @@ void Viewport::_drop_mouse_over(Control *p_until_control) { } } gui.mouse_over_hierarchy.resize(notification_until); + gui.sending_mouse_enter_exit_notifications = false; } void Viewport::push_input(const Ref &p_event, bool p_local_coords) { diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 82a9bfc438dc..6efa98ece85e 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -362,6 +362,7 @@ class Viewport : public Node { Control *key_focus = nullptr; Control *mouse_over = nullptr; LocalVector mouse_over_hierarchy; + bool sending_mouse_enter_exit_notifications = false; Window *subwindow_over = nullptr; // mouse_over and subwindow_over are mutually exclusive. At all times at least one of them is nullptr. Window *windowmanager_window_over = nullptr; // Only used in root Viewport. Control *drag_mouse_over = nullptr; From d41639a4cbf556ec957350335d2f7880a1011047 Mon Sep 17 00:00:00 2001 From: jsjtxietian Date: Thu, 14 Dec 2023 11:38:46 +0800 Subject: [PATCH 03/95] Use render method from OS in compositor RD; Update related UI (cherry picked from commit 453c2246b6bce66bf0320839095529943fe17e09) --- editor/editor_node.cpp | 71 +++++++++++-------- editor/editor_node.h | 1 + .../renderer_rd/renderer_compositor_rd.cpp | 2 +- 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 5159e76921db..98b170c9a163 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6582,6 +6582,23 @@ void EditorNode::_renderer_selected(int p_which) { _update_renderer_color(); } +void EditorNode::_add_renderer_entry(const String &p_renderer_name, bool p_mark_overridden) { + String item_text; + if (p_renderer_name == "forward_plus") { + item_text = TTR("Forward+"); + } + if (p_renderer_name == "mobile") { + item_text = TTR("Mobile"); + } + if (p_renderer_name == "gl_compatibility") { + item_text = TTR("Compatibility"); + } + if (p_mark_overridden) { + item_text += " " + TTR("(Overridden)"); + } + renderer->add_item(item_text); +} + void EditorNode::_resource_saved(Ref p_resource, const String &p_path) { if (singleton->saving_resources_in_path.has(p_resource)) { // This is going to be handled by save_resource_in_path when the time is right. @@ -7506,7 +7523,6 @@ EditorNode::EditorNode() { renderer->set_flat(true); renderer->set_fit_to_longest_item(false); renderer->set_focus_mode(Control::FOCUS_NONE); - renderer->connect("item_selected", callable_mp(this, &EditorNode::_renderer_selected)); renderer->add_theme_font_override("font", theme->get_font(SNAME("bold"), EditorStringName(EditorFonts))); renderer->add_theme_font_size_override("font_size", theme->get_font_size(SNAME("bold_size"), EditorStringName(EditorFonts))); renderer->set_tooltip_text(TTR("Choose a rendering method.\n\nNotes:\n- On mobile platforms, the Mobile rendering method is used if Forward+ is selected here.\n- On the web platform, the Compatibility rendering method is always used.")); @@ -7520,36 +7536,33 @@ EditorNode::EditorNode() { title_bar->add_child(right_menu_spacer); } - String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method"); - - PackedStringArray renderers = ProjectSettings::get_singleton()->get_custom_property_info().get(StringName("rendering/renderer/rendering_method")).hint_string.split(",", false); - - // As we are doing string comparisons, keep in standard case to prevent problems with capitals - // "vulkan" in particular uses lowercase "v" in the code, and uppercase in the UI. - current_renderer = current_renderer.to_lower(); + String current_renderer_ps = GLOBAL_GET("rendering/renderer/rendering_method"); + current_renderer_ps = current_renderer_ps.to_lower(); + String current_renderer_os = OS::get_singleton()->get_current_rendering_method().to_lower(); - for (int i = 0; i < renderers.size(); i++) { - String rendering_method = renderers[i]; - - // Add the renderers name to the UI. - if (rendering_method == "forward_plus") { - renderer->add_item(TTR("Forward+")); - } - if (rendering_method == "mobile") { - renderer->add_item(TTR("Mobile")); - } - if (rendering_method == "gl_compatibility") { - renderer->add_item(TTR("Compatibility")); - } - renderer->set_item_metadata(i, rendering_method); - - // Lowercase for standard comparison. - rendering_method = rendering_method.to_lower(); - - if (current_renderer == rendering_method) { - renderer->select(i); - renderer_current = i; + // Add the renderers name to the UI. + if (current_renderer_ps == current_renderer_os) { + renderer->connect("item_selected", callable_mp(this, &EditorNode::_renderer_selected)); + // As we are doing string comparisons, keep in standard case to prevent problems with capitals + // "vulkan" in particular uses lowercase "v" in the code, and uppercase in the UI. + PackedStringArray renderers = ProjectSettings::get_singleton()->get_custom_property_info().get(StringName("rendering/renderer/rendering_method")).hint_string.split(",", false); + for (int i = 0; i < renderers.size(); i++) { + String rendering_method = renderers[i]; + _add_renderer_entry(rendering_method, false); + renderer->set_item_metadata(i, rendering_method); + // Lowercase for standard comparison. + rendering_method = rendering_method.to_lower(); + if (current_renderer_ps == rendering_method) { + renderer->select(i); + renderer_current = i; + } } + } else { + // It's an CLI-overridden rendering method. + _add_renderer_entry(current_renderer_os, true); + renderer->set_item_metadata(0, current_renderer_os); + renderer->select(0); + renderer_current = 0; } _update_renderer_color(); diff --git a/editor/editor_node.h b/editor/editor_node.h index 84fb6beb97f8..745111dda79f 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -612,6 +612,7 @@ class EditorNode : public Node { void _renderer_selected(int); void _update_renderer_color(); + void _add_renderer_entry(const String &p_renderer_name, bool p_mark_overridden); void _exit_editor(int p_exit_code); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 49c4d08b86ab..a69877e68001 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -306,7 +306,7 @@ RendererCompositorRD::RendererCompositorRD() { fog = memnew(RendererRD::Fog); canvas = memnew(RendererCanvasRenderRD()); - String rendering_method = GLOBAL_GET("rendering/renderer/rendering_method"); + String rendering_method = OS::get_singleton()->get_current_rendering_method(); uint64_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); if (rendering_method == "mobile" || textures_per_stage < 48) { From f1f56746b9a12900fb9c401e40f58b17c00fb266 Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Tue, 7 Nov 2023 23:31:32 +0800 Subject: [PATCH 04/95] Make AnimationTree reference AnimationPlayer instead of AnimationMixer (cherry picked from commit 7946e8418793b2f673e2df31c5f8f509cddce056) --- scene/animation/animation_tree.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index bdadc4ecac5e..630882da3dbb 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -33,6 +33,7 @@ #include "animation_blend_tree.h" #include "core/config/engine.h" +#include "scene/animation/animation_player.h" #include "scene/scene_string_names.h" void AnimationNode::get_parameter_list(List *r_list) const { @@ -764,15 +765,16 @@ void AnimationTree::_setup_animation_player() { return; } - AnimationMixer *mixer = Object::cast_to(get_node_or_null(animation_player)); - if (mixer) { - if (!mixer->is_connected(SNAME("caches_cleared"), callable_mp(this, &AnimationTree::_setup_animation_player))) { - mixer->connect(SNAME("caches_cleared"), callable_mp(this, &AnimationTree::_setup_animation_player), CONNECT_DEFERRED); + // Using AnimationPlayer here is for compatibility. Changing to AnimationMixer needs extra work like error handling. + AnimationPlayer *player = Object::cast_to(get_node_or_null(animation_player)); + if (player) { + if (!player->is_connected(SNAME("caches_cleared"), callable_mp(this, &AnimationTree::_setup_animation_player))) { + player->connect(SNAME("caches_cleared"), callable_mp(this, &AnimationTree::_setup_animation_player), CONNECT_DEFERRED); } - if (!mixer->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationTree::_setup_animation_player))) { - mixer->connect(SNAME("animation_list_changed"), callable_mp(this, &AnimationTree::_setup_animation_player), CONNECT_DEFERRED); + if (!player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationTree::_setup_animation_player))) { + player->connect(SNAME("animation_list_changed"), callable_mp(this, &AnimationTree::_setup_animation_player), CONNECT_DEFERRED); } - Node *root = mixer->get_node_or_null(mixer->get_root_node()); + Node *root = player->get_node_or_null(player->get_root_node()); if (root) { set_root_node(get_path_to(root, true)); } @@ -780,9 +782,9 @@ void AnimationTree::_setup_animation_player() { remove_animation_library(animation_libraries[0].name); } List list; - mixer->get_animation_library_list(&list); + player->get_animation_library_list(&list); for (int i = 0; i < list.size(); i++) { - Ref lib = mixer->get_animation_library(list[i]); + Ref lib = player->get_animation_library(list[i]); if (lib.is_valid()) { add_animation_library(list[i], lib); } From ba23081eb758e9f4b8a5a2e10bd742bba41f04c4 Mon Sep 17 00:00:00 2001 From: Markus Sauermann <6299227+Sauermann@users.noreply.github.com> Date: Mon, 3 Jul 2023 21:18:12 +0200 Subject: [PATCH 05/95] Fix crash caused by stale owner Adjust `NOTIFICATION_PREDELETE` in `Node` to clean up owned nodes. Also print a warning, when the owner becomes invalid. (cherry picked from commit d3d00c703994394005f1a2f92791e075858fe9ee) --- scene/main/node.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/scene/main/node.cpp b/scene/main/node.cpp index e730f47607ec..9a3e7a22ca9f 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -202,6 +202,11 @@ void Node::_notification(int p_notification) { _clean_up_owner(); } + while (!data.owned.is_empty()) { + Node *n = data.owned.back()->get(); + n->_clean_up_owner(); // This will change data.owned. So it's impossible to loop over the list in the usual manner. + } + if (data.parent) { data.parent->remove_child(this); } @@ -1415,6 +1420,14 @@ void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_i ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `add_child()` failed. Consider using `add_child.call_deferred(child)` instead."); _validate_child_name(p_child, p_force_readable_name); + +#ifdef DEBUG_ENABLED + if (p_child->data.owner && !p_child->data.owner->is_ancestor_of(p_child)) { + // Owner of p_child should be ancestor of p_child. + WARN_PRINT(vformat("Adding '%s' as child to '%s' will make owner '%s' inconsistent. Consider unsetting the owner beforehand.", p_child->get_name(), get_name(), p_child->data.owner->get_name())); + } +#endif // DEBUG_ENABLED + _add_child_nocheck(p_child, p_child->data.name, p_internal); } From 36f34c8f86008fd2ac535ec8af6227a74232656a Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Wed, 20 Dec 2023 13:19:46 +0100 Subject: [PATCH 06/95] Avoid crashes when engine leaks canvas items and friends (cherry picked from commit 34ecfff6722be4819707b128ccae561eacf101fc) --- servers/rendering/renderer_canvas_cull.cpp | 24 +++++++++++++++++++ servers/rendering/renderer_canvas_cull.h | 6 +++++ servers/rendering/renderer_canvas_render.cpp | 2 ++ servers/rendering/renderer_compositor.cpp | 4 ---- .../rendering/rendering_server_default.cpp | 1 + 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index c3958b2c0d84..429ffbea9961 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -2167,6 +2167,30 @@ bool RendererCanvasCull::free(RID p_rid) { return true; } +template +void RendererCanvasCull::_free_rids(T &p_owner, const char *p_type) { + List owned; + p_owner.get_owned_list(&owned); + if (owned.size()) { + if (owned.size() == 1) { + WARN_PRINT(vformat("1 RID of type \"%s\" was leaked.", p_type)); + } else { + WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type)); + } + for (const RID &E : owned) { + free(E); + } + } +} + +void RendererCanvasCull::finalize() { + _free_rids(canvas_owner, "Canvas"); + _free_rids(canvas_item_owner, "CanvasItem"); + _free_rids(canvas_light_owner, "CanvasLight"); + _free_rids(canvas_light_occluder_owner, "CanvasLightOccluder"); + _free_rids(canvas_light_occluder_polygon_owner, "CanvasLightOccluderPolygon"); +} + RendererCanvasCull::RendererCanvasCull() { z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index aabaa4289093..15d3a63c4997 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -170,6 +170,9 @@ class RendererCanvasCull { RID_Owner canvas_item_owner; RID_Owner canvas_light_owner; + template + void _free_rids(T &p_owner, const char *p_type); + bool disable_scale; bool sdf_used = false; bool snapping_2d_transforms_to_pixel = false; @@ -329,6 +332,9 @@ class RendererCanvasCull { Rect2 _debug_canvas_item_get_rect(RID p_item); bool free(RID p_rid); + + void finalize(); + RendererCanvasCull(); ~RendererCanvasCull(); }; diff --git a/servers/rendering/renderer_canvas_render.cpp b/servers/rendering/renderer_canvas_render.cpp index af0ec621e5e7..6eb7bab9c999 100644 --- a/servers/rendering/renderer_canvas_render.cpp +++ b/servers/rendering/renderer_canvas_render.cpp @@ -31,6 +31,8 @@ #include "renderer_canvas_render.h" #include "servers/rendering/rendering_server_globals.h" +RendererCanvasRender *RendererCanvasRender::singleton = nullptr; + const Rect2 &RendererCanvasRender::Item::get_rect() const { if (custom_rect || (!rect_dirty && !update_when_visible && skeleton == RID())) { return rect; diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp index a6083fe70dfd..c36da51e5064 100644 --- a/servers/rendering/renderer_compositor.cpp +++ b/servers/rendering/renderer_compositor.cpp @@ -31,8 +31,6 @@ #include "renderer_compositor.h" #include "core/config/project_settings.h" -#include "core/os/os.h" -#include "core/string/print_string.h" #include "servers/xr_server.h" RendererCompositor *RendererCompositor::singleton = nullptr; @@ -57,5 +55,3 @@ RendererCompositor::RendererCompositor() { xr_enabled = XRServer::get_xr_mode() == XRServer::XRMODE_ON; } } - -RendererCanvasRender *RendererCanvasRender::singleton = nullptr; diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index 65a6da8ac308..0c054900c790 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -214,6 +214,7 @@ void RenderingServerDefault::_finish() { free(test_cube); } + RSG::canvas->finalize(); RSG::rasterizer->finalize(); } From 776938f7317e4df688ebce5d088f19e44f26a988 Mon Sep 17 00:00:00 2001 From: Leo Belda Date: Sun, 7 Jan 2024 17:10:50 +0100 Subject: [PATCH 07/95] Fix PrismMesh::_create_mesh_array division by 0 (cherry picked from commit 83992fd7bd346f9673e1e9c9dd38d1c8d2cc09c3) --- scene/resources/primitive_meshes.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 13791d8c2b9e..ffa96d03eeda 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -1476,15 +1476,15 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const { thisrow = point; prevrow = 0; for (j = 0; j <= (subdivide_h + 1); j++) { - float scale = (y - start_pos.y) / size.y; + float scale = j / (subdivide_h + 1.0); float scaled_size_x = size.x * scale; float start_x = start_pos.x + (1.0 - scale) * size.x * left_to_right; float offset_front = (1.0 - scale) * onethird * left_to_right; float offset_back = (1.0 - scale) * onethird * (1.0 - left_to_right); float v = j; - float v2 = j / (subdivide_h + 1.0); - v /= (2.0 * (subdivide_h + 1.0)); + float v2 = scale; + v /= 2.0 * (subdivide_h + 1.0); x = 0.0; for (i = 0; i <= (subdivide_w + 1); i++) { @@ -1566,16 +1566,16 @@ void PrismMesh::_create_mesh_array(Array &p_arr) const { thisrow = point; prevrow = 0; for (j = 0; j <= (subdivide_h + 1); j++) { - float v = j; - float v2 = j / (subdivide_h + 1.0); - v /= (2.0 * (subdivide_h + 1.0)); - float left, right; - float scale = (y - start_pos.y) / size.y; + float scale = j / (subdivide_h + 1.0); left = start_pos.x + (size.x * (1.0 - scale) * left_to_right); right = left + (size.x * scale); + float v = j; + float v2 = scale; + v /= 2.0 * (subdivide_h + 1.0); + z = start_pos.z; for (i = 0; i <= (subdivide_d + 1); i++) { float u = i; From 4d3e25d09da6d19a2098f4e1d465364343ff4edc Mon Sep 17 00:00:00 2001 From: Nicholas Foo Date: Wed, 1 Nov 2023 22:25:01 +0800 Subject: [PATCH 08/95] Fix RichTextLabel.remove_paragraph crash by popping current (cherry picked from commit c0f8e0061d5e8b60247101df02c0e9ec8a68df80) --- scene/gui/rich_text_label.cpp | 11 +++++++---- scene/gui/rich_text_label.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 41f4de5b3b1b..0b9e02b82565 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -3151,7 +3151,7 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline) queue_redraw(); } -void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_subitem_line) { +void RichTextLabel::_remove_item(Item *p_item, const int p_line) { int size = p_item->subitems.size(); if (size == 0) { p_item->parent->subitems.erase(p_item); @@ -3160,7 +3160,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub current_frame->lines.remove_at(p_line); if (p_line < (int)current_frame->lines.size() && current_frame->lines[p_line].from) { for (List::Element *E = current_frame->lines[p_line].from->E; E; E = E->next()) { - if (E->get()->line > p_subitem_line) { + if (E->get()->line > p_line) { E->get()->line--; } } @@ -3169,7 +3169,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub } else { // First, remove all child items for the provided item. while (p_item->subitems.size()) { - _remove_item(p_item->subitems.front()->get(), p_line, p_subitem_line); + _remove_item(p_item->subitems.front()->get(), p_line); } // Then remove the provided item itself. p_item->parent->subitems.erase(p_item); @@ -3377,7 +3377,10 @@ bool RichTextLabel::remove_paragraph(const int p_paragraph) { for (int i = subitem_to_remove.size() - 1; i >= 0; i--) { List::Element *subitem = subitem_to_remove[i]; had_newline = had_newline || subitem->get()->type == ITEM_NEWLINE; - _remove_item(subitem->get(), subitem->get()->line, p_paragraph); + if (subitem->get() == current) { + pop(); + } + _remove_item(subitem->get(), p_paragraph); } if (!had_newline) { diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 2f4860058349..5c8585565d78 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -461,7 +461,7 @@ class RichTextLabel : public Control { _FORCE_INLINE_ float _update_scroll_exceeds(float p_total_height, float p_ctrl_height, float p_width, int p_idx, float p_old_scroll, float p_text_rect_height); void _add_item(Item *p_item, bool p_enter = false, bool p_ensure_newline = false); - void _remove_item(Item *p_item, const int p_line, const int p_subitem_line); + void _remove_item(Item *p_item, const int p_line); String language; TextDirection text_direction = TEXT_DIRECTION_AUTO; From 79179351a3edfc56377d63d3d686daa06611e95d Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Mon, 22 Jan 2024 13:44:36 +0100 Subject: [PATCH 09/95] [Editor] Fix threading problems with `TileMap` preview (cherry picked from commit dbcd82ba674182fbf5bf5ae0a9701da2b11e6fe9) --- editor/plugins/tiles/tiles_editor_plugin.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index b96f3f21b8ae..e56c0e108c54 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -68,6 +68,9 @@ void TilesEditorUtils::_thread_func(void *ud) { } void TilesEditorUtils::_thread() { + CallQueue queue; + MessageQueue::set_thread_singleton_override(&queue); + pattern_thread_exited.clear(); while (!pattern_thread_exit.is_set()) { pattern_preview_sem.wait(); @@ -127,6 +130,8 @@ void TilesEditorUtils::_thread() { // Add the viewport at the last moment to avoid rendering too early. EditorNode::get_singleton()->call_deferred("add_child", viewport); + MessageQueue::get_singleton()->flush(); + RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast(this), &TilesEditorUtils::_preview_frame_started), Object::CONNECT_ONE_SHOT); pattern_preview_done.wait(); @@ -139,7 +144,11 @@ void TilesEditorUtils::_thread() { viewport->queue_free(); } } + + MessageQueue::get_singleton()->flush(); } + + MessageQueue::get_singleton()->flush(); pattern_thread_exited.set(); } From 1b8d1048adf03e58a1423a71c46b1be59aea14d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20W=C3=B6rner?= Date: Mon, 11 Dec 2023 22:41:16 +0100 Subject: [PATCH 10/95] Restored the ability for linear interpolation to work on a mix of integer and float keyframes. (cherry picked from commit 12ce2e33b237d7aec91ef314a23edae5dde3fd4f) --- scene/resources/animation.cpp | 46 +++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index b1b3bab93775..52850cac4a85 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -5485,7 +5485,7 @@ Variant Animation::cast_to_blendwise(const Variant p_value) { switch (p_value.get_type()) { case Variant::BOOL: case Variant::INT: { - return p_value.operator real_t(); + return p_value.operator double(); } break; case Variant::STRING: case Variant::STRING_NAME: { @@ -5521,7 +5521,7 @@ Variant Animation::cast_from_blendwise(const Variant p_value, const Variant::Typ return p_value.operator real_t() >= 0.5; } break; case Variant::INT: { - return (int)Math::round(p_value.operator real_t()); + return (int64_t)Math::round(p_value.operator double()); } break; case Variant::STRING: { return array_to_string(p_value); @@ -5594,8 +5594,12 @@ Variant Animation::array_to_string(const Variant p_value) { } Variant Animation::add_variant(const Variant &a, const Variant &b) { - if (a.get_type() != b.get_type() && !a.is_array()) { - return a; + if (a.get_type() != b.get_type()) { + if (a.is_num() && b.is_num()) { + return add_variant(cast_to_blendwise(a), cast_to_blendwise(b)); + } else if (!a.is_array()) { + return a; + } } switch (a.get_type()) { @@ -5603,7 +5607,7 @@ Variant Animation::add_variant(const Variant &a, const Variant &b) { return Variant(); } break; case Variant::FLOAT: { - return (a.operator real_t()) + (b.operator real_t()); + return (a.operator double()) + (b.operator double()); } break; case Variant::RECT2: { const Rect2 ra = a.operator Rect2(); @@ -5704,8 +5708,12 @@ Variant Animation::add_variant(const Variant &a, const Variant &b) { } Variant Animation::subtract_variant(const Variant &a, const Variant &b) { - if (a.get_type() != b.get_type() && !a.is_array()) { - return a; + if (a.get_type() != b.get_type()) { + if (a.is_num() && b.is_num()) { + return subtract_variant(cast_to_blendwise(a), cast_to_blendwise(b)); + } else if (!a.is_array()) { + return a; + } } switch (a.get_type()) { @@ -5713,7 +5721,7 @@ Variant Animation::subtract_variant(const Variant &a, const Variant &b) { return Variant(); } break; case Variant::FLOAT: { - return (a.operator real_t()) - (b.operator real_t()); + return (a.operator double()) - (b.operator double()); } break; case Variant::RECT2: { const Rect2 ra = a.operator Rect2(); @@ -5814,8 +5822,12 @@ Variant Animation::subtract_variant(const Variant &a, const Variant &b) { } Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) { - if (a.get_type() != b.get_type() && !a.is_array()) { - return a; + if (a.get_type() != b.get_type()) { + if (a.is_num() && b.is_num()) { + return blend_variant(cast_to_blendwise(a), cast_to_blendwise(b), c); + } else if (!a.is_array()) { + return a; + } } switch (a.get_type()) { @@ -5823,7 +5835,7 @@ Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) { return Variant(); } break; case Variant::FLOAT: { - return (a.operator real_t()) + (b.operator real_t()) * c; + return (a.operator double()) + (b.operator double()) * c; } break; case Variant::VECTOR2: { return (a.operator Vector2()) + (b.operator Vector2()) * c; @@ -5947,8 +5959,12 @@ Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) { } Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float c, bool p_snap_array_element) { - if (a.get_type() != b.get_type() && !a.is_array()) { - return a; + if (a.get_type() != b.get_type()) { + if (a.is_num() && b.is_num()) { + return interpolate_variant(cast_to_blendwise(a), cast_to_blendwise(b), c); + } else if (!a.is_array()) { + return a; + } } switch (a.get_type()) { @@ -5956,8 +5972,8 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float return Variant(); } break; case Variant::FLOAT: { - const real_t va = a.operator real_t(); - return va + ((b.operator real_t()) - va) * c; + const double va = a.operator double(); + return va + ((b.operator double()) - va) * c; } break; case Variant::VECTOR2: { return (a.operator Vector2()).lerp(b.operator Vector2(), c); From 7c22d5444a6df745a7c92a2a2c6cc26e49259188 Mon Sep 17 00:00:00 2001 From: HolonProduction Date: Wed, 13 Dec 2023 10:51:07 +0100 Subject: [PATCH 11/95] Fix regression when autocompleting subscript on get node (cherry picked from commit 5f72254d4db824b50dc30548fd031874fc5a418c) --- modules/gdscript/gdscript_editor.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index faaff5334410..4ab3e9f5ad29 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -2676,10 +2676,6 @@ static bool _get_subscript_type(GDScriptParser::CompletionContext &p_context, co if (p_context.base == nullptr) { return false; } - if (p_subscript->base->datatype.type_source == GDScriptParser::DataType::ANNOTATED_EXPLICIT) { - // Annotated type takes precedence. - return false; - } const GDScriptParser::GetNodeNode *get_node = nullptr; @@ -2689,6 +2685,11 @@ static bool _get_subscript_type(GDScriptParser::CompletionContext &p_context, co } break; case GDScriptParser::Node::IDENTIFIER: { + if (p_subscript->base->datatype.type_source == GDScriptParser::DataType::ANNOTATED_EXPLICIT) { + // Annotated type takes precedence. + return false; + } + const GDScriptParser::IdentifierNode *identifier_node = static_cast(p_subscript->base); switch (identifier_node->source) { From c285b726bb06f8d160f2c4b5505bbe76431b3cee Mon Sep 17 00:00:00 2001 From: kobewi Date: Thu, 14 Dec 2023 22:28:48 +0100 Subject: [PATCH 12/95] Fix file disappearing when renaming dependencies (cherry picked from commit 397f0b31e4bd255e9f707a1d5d9ce2ac0b2ef409) --- core/io/resource_format_binary.cpp | 6 ++++-- scene/resources/resource_format_text.cpp | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 2a33f723dc8a..20c494516bee 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -1454,8 +1454,10 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons fw.unref(); Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - da->remove(p_path); - da->rename(p_path + ".depren", p_path); + if (da->exists(p_path + ".depren")) { + da->remove(p_path); + da->rename(p_path + ".depren", p_path); + } return OK; } diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 19718f12be22..fe2da8b79016 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1791,8 +1791,8 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const err = loader.rename_dependencies(f, p_path, p_map); } - if (err == OK) { - Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (err == OK && da->file_exists(p_path + ".depren")) { da->remove(p_path); da->rename(p_path + ".depren", p_path); } From 19bb93513a2762ceaf80a12b7cbc4a6e8d2a4e27 Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Fri, 1 Dec 2023 04:50:58 +0900 Subject: [PATCH 13/95] Make unstore AnimationLibrary if AnimationTree is assigned Player (cherry picked from commit c380b1296a665979a2a200b13b3282e45a83d8c9) --- scene/animation/animation_tree.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 630882da3dbb..42b550f089df 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -801,6 +801,9 @@ void AnimationTree::_validate_property(PropertyInfo &p_property) const { if (p_property.name == "root_node" || p_property.name.begins_with("libraries")) { p_property.usage |= PROPERTY_USAGE_READ_ONLY; } + if (p_property.name.begins_with("libraries")) { + p_property.usage &= ~PROPERTY_USAGE_STORAGE; + } } } From b20ba6bd12902e89df9f84b3a4daa503a10d24dd Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Sat, 16 Dec 2023 14:19:50 +0900 Subject: [PATCH 14/95] Fix discrete key retrieval method after start (cherry picked from commit b438e28509a266dc1b57a83ae63f8f8bf62dc052) --- scene/animation/animation_player.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index a4b6d1ce5004..31dd4e45b489 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -233,7 +233,9 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f pi.delta = delta; pi.seeked = p_seeked; } - pi.is_external_seeking = true; // AnimationPlayer doesn't have internal seeking. + // AnimationPlayer doesn't have internal seeking. + // However, immediately after playback, discrete keys should be retrieved with EXACT mode since behind keys must be ignored at that time. + pi.is_external_seeking = !p_started; pi.looped_flag = looped_flag; pi.weight = p_blend; make_animation_instance(cd.from->name, pi); From 89fd2c30e1087b7aae36c37cb4c2e4fd23ed00b7 Mon Sep 17 00:00:00 2001 From: "S.V.I. Vilcrow" Date: Wed, 20 Dec 2023 00:27:01 +0300 Subject: [PATCH 15/95] Fix the autocomplete function for the 'self' keyword. (cherry picked from commit c8fc824608efde15ae05a36ab6bab314ebcad01d) --- modules/gdscript/gdscript_editor.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 4ab3e9f5ad29..62065b56a330 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1494,11 +1494,8 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, } break; case GDScriptParser::Node::SELF: { if (p_context.current_class) { - if (p_context.type != GDScriptParser::COMPLETION_SUPER_METHOD) { - r_type.type = p_context.current_class->get_datatype(); - } else { - r_type.type = p_context.current_class->base_type; - } + r_type.type = p_context.current_class->get_datatype(); + r_type.type.is_meta_type = false; found = true; } } break; From a1c32a946241e978bad7e5abdd41de2a8988c303 Mon Sep 17 00:00:00 2001 From: kobewi Date: Sat, 23 Dec 2023 18:04:24 +0100 Subject: [PATCH 16/95] Only update particle velocity when it changes (cherry picked from commit cb0a37f61aa772341e63e8ae8ee5bece211613f8) --- scene/2d/gpu_particles_2d.cpp | 13 ++++++++----- scene/2d/gpu_particles_2d.h | 1 + scene/3d/gpu_particles_3d.cpp | 7 ++++++- scene/3d/gpu_particles_3d.h | 1 + 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index ee33ff88d4eb..71da9cc520a0 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -712,12 +712,15 @@ void GPUParticles2D::_notification(int p_what) { } break; case NOTIFICATION_INTERNAL_PROCESS: { - RS::get_singleton()->particles_set_emitter_velocity(particles, - Vector3((get_global_position() - previous_position).x, - (get_global_position() - previous_position).y, - 0.0) / - get_process_delta_time()); + const Vector3 velocity = Vector3((get_global_position() - previous_position).x, (get_global_position() - previous_position).y, 0.0) / + get_process_delta_time(); + + if (velocity != previous_velocity) { + RS::get_singleton()->particles_set_emitter_velocity(particles, velocity); + previous_velocity = velocity; + } previous_position = get_global_position(); + if (one_shot) { time += get_process_delta_time(); if (time > emission_time) { diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index 40831cd30e8c..58996b0327b6 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -64,6 +64,7 @@ class GPUParticles2D : public Node2D { bool fractional_delta = false; bool interpolate = true; float interp_to_end_factor = 0; + Vector3 previous_velocity; Vector2 previous_position; #ifdef TOOLS_ENABLED bool show_visibility_rect = false; diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index fc84b3308ebc..dfb039d7093c 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -460,7 +460,12 @@ void GPUParticles3D::_notification(int p_what) { // Use internal process when emitting and one_shot is on so that when // the shot ends the editor can properly update. case NOTIFICATION_INTERNAL_PROCESS: { - RS::get_singleton()->particles_set_emitter_velocity(particles, (get_global_position() - previous_position) / get_process_delta_time()); + const Vector3 velocity = (get_global_position() - previous_position) / get_process_delta_time(); + + if (velocity != previous_velocity) { + RS::get_singleton()->particles_set_emitter_velocity(particles, velocity); + previous_velocity = velocity; + } previous_position = get_global_position(); if (one_shot) { diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index ae9349817c44..0c9f2c13783f 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -95,6 +95,7 @@ class GPUParticles3D : public GeometryInstance3D { double emission_time = 0.0; double active_time = 0.0; float interp_to_end_factor = 0; + Vector3 previous_velocity; Vector3 previous_position; void _attach_sub_emitter(); From 4a036b5fe7b0802bb4d8f12265f715efe6461f17 Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Tue, 9 Jan 2024 13:46:16 +0800 Subject: [PATCH 17/95] Fix ZIPPacker storing file permissions unexpectedly (cherry picked from commit 7a833c9b2e6ab12b2b55d828a36a37a494746b30) --- modules/zip/zip_packer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/zip/zip_packer.cpp b/modules/zip/zip_packer.cpp index e67c65d4d1cc..e96d9da7a938 100644 --- a/modules/zip/zip_packer.cpp +++ b/modules/zip/zip_packer.cpp @@ -88,7 +88,7 @@ Error ZIPPacker::start_file(const String &p_path) { Z_DEFAULT_STRATEGY, nullptr, 0, - 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions. + 0, // "version made by", indicates the compatibility of the file attribute information (the `external_fa` field above). 1 << 11); // Bit 11 is the language encoding flag. When set, filename and comment fields must be encoded using UTF-8. return err == ZIP_OK ? OK : FAILED; } From 41dcabb0cfefc0ba232a0006e3127187d033b5ce Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Tue, 9 Jan 2024 23:06:36 +1100 Subject: [PATCH 18/95] Fix SSR not working properly in stereo (cherry picked from commit 10a8b8816556680587db9c524da870c5b9a14731) --- .../rendering/renderer_rd/shaders/effects/specular_merge.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl b/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl index db710b7cddc3..e87f644bb048 100644 --- a/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl @@ -30,7 +30,7 @@ void main() { vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0)); gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0); uv_interp.xy = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0 -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW uv_interp.z = ViewIndex; #endif } From 894d6291857993d9947519a8da7c1be60ceb6940 Mon Sep 17 00:00:00 2001 From: Fredia Huya-Kouadio Date: Thu, 11 Jan 2024 08:04:09 -0800 Subject: [PATCH 19/95] Disable automatic permissions request The feature was added in Godot 4.2, but it goes against recommended best practices for permissions request, as such it's being reverted. In its place, developers now have to explicitly request the permissions they need to access. (cherry picked from commit df4f9e8e64321cf31a1cffd71fe8fe1879c7cd49) --- .../java/org/godotengine/editor/GodotEditor.kt | 4 ++++ .../lib/src/org/godotengine/godot/GodotActivity.kt | 8 ++------ .../godotengine/godot/utils/PermissionsUtil.java | 14 +++++++------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt index 0d7017ae71b4..caf64bc933fd 100644 --- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt @@ -91,6 +91,10 @@ open class GodotEditor : GodotActivity() { private val commandLineParams = ArrayList() override fun onCreate(savedInstanceState: Bundle?) { + // We exclude certain permissions from the set we request at startup, as they'll be + // requested on demand based on use-cases. + PermissionsUtil.requestManifestPermissions(this, setOf(Manifest.permission.RECORD_AUDIO)) + val params = intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS) Log.d(TAG, "Received parameters ${params.contentToString()}") updateCommandLineParams(params) diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt b/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt index a60f6e997ec7..e01c5481d518 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt @@ -30,7 +30,6 @@ package org.godotengine.godot -import android.Manifest import android.app.Activity import android.content.Intent import android.content.pm.PackageManager @@ -65,10 +64,6 @@ abstract class GodotActivity : FragmentActivity(), GodotHost { private set override fun onCreate(savedInstanceState: Bundle?) { - // We exclude certain permissions from the set we request at startup, as they'll be - // requested on demand based on use-cases. - PermissionsUtil.requestManifestPermissions(this, setOf(Manifest.permission.RECORD_AUDIO)) - super.onCreate(savedInstanceState) setContentView(R.layout.godot_app_layout) @@ -156,7 +151,8 @@ abstract class GodotActivity : FragmentActivity(), GodotHost { super.onRequestPermissionsResult(requestCode, permissions, grantResults) godotFragment?.onRequestPermissionsResult(requestCode, permissions, grantResults) - if (requestCode == PermissionsUtil.REQUEST_ALL_PERMISSION_REQ_CODE) { + // Logging the result of permission requests + if (requestCode == PermissionsUtil.REQUEST_ALL_PERMISSION_REQ_CODE || requestCode == PermissionsUtil.REQUEST_SINGLE_PERMISSION_REQ_CODE) { Log.d(TAG, "Received permissions request result..") for (i in permissions.indices) { val permissionGranted = grantResults[i] == PackageManager.PERMISSION_GRANTED diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java index 9a82204467fc..737b4ac20bda 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java @@ -56,9 +56,9 @@ public final class PermissionsUtil { private static final String TAG = PermissionsUtil.class.getSimpleName(); - static final int REQUEST_RECORD_AUDIO_PERMISSION = 1; - static final int REQUEST_CAMERA_PERMISSION = 2; - static final int REQUEST_VIBRATE_PERMISSION = 3; + public static final int REQUEST_RECORD_AUDIO_PERMISSION = 1; + public static final int REQUEST_CAMERA_PERMISSION = 2; + public static final int REQUEST_VIBRATE_PERMISSION = 3; public static final int REQUEST_ALL_PERMISSION_REQ_CODE = 1001; public static final int REQUEST_SINGLE_PERMISSION_REQ_CODE = 1002; public static final int REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE = 2002; @@ -70,7 +70,7 @@ private PermissionsUtil() { * Request a dangerous permission. name must be specified in this * @param permissionName the name of the requested permission. * @param activity the caller activity for this method. - * @return true/false. "true" if permission was granted otherwise returns "false". + * @return true/false. "true" if permission is already granted, "false" if a permission request was dispatched. */ public static boolean requestPermission(String permissionName, Activity activity) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { @@ -124,7 +124,7 @@ public static boolean requestPermission(String permissionName, Activity activity /** * Request dangerous permissions which are defined in the Android manifest file from the user. * @param activity the caller activity for this method. - * @return true/false. "true" if all permissions were granted otherwise returns "false". + * @return true/false. "true" if all permissions were already granted, returns "false" if permissions requests were dispatched. */ public static boolean requestManifestPermissions(Activity activity) { return requestManifestPermissions(activity, null); @@ -134,7 +134,7 @@ public static boolean requestManifestPermissions(Activity activity) { * Request dangerous permissions which are defined in the Android manifest file from the user. * @param activity the caller activity for this method. * @param excludes Set of permissions to exclude from the request - * @return true/false. "true" if all permissions were granted otherwise returns "false". + * @return true/false. "true" if all permissions were already granted, returns "false" if permissions requests were dispatched. */ public static boolean requestManifestPermissions(Activity activity, @Nullable Set excludes) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { @@ -235,7 +235,7 @@ public static String[] getGrantedPermissions(Context context) { /** * Check if the given permission is in the AndroidManifest.xml file. * @param context the caller context for this method. - * @param permission the permession to look for in the manifest file. + * @param permission the permission to look for in the manifest file. * @return "true" if the permission is in the manifest file of the activity, "false" otherwise. */ public static boolean hasManifestPermission(Context context, String permission) { From f5ecaec1a4ca110c515fda4312d609e7add6d5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E9=9D=92=E5=B1=B1?= Date: Thu, 14 Dec 2023 10:41:22 +0800 Subject: [PATCH 20/95] Set an appropriate minimum size for labels in windows that display incorrectly When the label's `autowrap_mode` is `AUTOWRAP_WORD_SMART` and the initial `text` is set at the same time, it may have a higher height. Set an appropriate minimum size for labels in windows that display incorrectly so that these controls display properly. (cherry picked from commit f932c6548eedb56c6d1fba20477848f854633608) --- editor/export/project_export.cpp | 1 + editor/import/dynamic_font_import_settings.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index cacdf108cf95..1c9f55e5b69d 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -1274,6 +1274,7 @@ ProjectExportDialog::ProjectExportDialog() { server_strip_message = memnew(Label); server_strip_message->set_visible(false); server_strip_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + server_strip_message->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); resources_vb->add_child(server_strip_message); { diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index 9e584cd4178e..4da3a1f5fda7 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -1345,6 +1345,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { page2_description->set_text(TTR("Add font size, and variation coordinates, and select glyphs to pre-render:")); page2_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); page2_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + page2_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); page2_vb->add_child(page2_description); HSplitContainer *page2_hb = memnew(HSplitContainer); @@ -1418,6 +1419,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { page2_0_description->set_text(TTR("Select translations to add all required glyphs to pre-render list:")); page2_0_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); page2_0_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + page2_0_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); page2_0_vb->add_child(page2_0_description); locale_tree = memnew(Tree); @@ -1449,6 +1451,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { page2_1_description->set_text(TTR("Enter a text and select OpenType features to shape and add all required glyphs to pre-render list:")); page2_1_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); page2_1_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + page2_1_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); page2_1_vb->add_child(page2_1_description); HSplitContainer *page2_1_hb = memnew(HSplitContainer); @@ -1486,6 +1489,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { page2_2_description->set_text(TTR("Add or remove glyphs from the character map to pre-render list:\nNote: Some stylistic alternatives and glyph variants do not have one-to-one correspondence to character, and not shown in this map, use \"Glyphs from the text\" tab to add these.")); page2_2_description->set_h_size_flags(Control::SIZE_EXPAND_FILL); page2_2_description->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART); + page2_2_description->set_custom_minimum_size(Size2(300 * EDSCALE, 1)); page2_2_vb->add_child(page2_2_description); HSplitContainer *glyphs_split = memnew(HSplitContainer); From 209aa9821a07fd555629534f6c7712903802fcac Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Sat, 16 Dec 2023 09:42:48 +0900 Subject: [PATCH 21/95] Make default blend_left consider current blend amount (cherry picked from commit f8da9460c1e1eccabde863785abcb1a4d3a1fbda) --- scene/animation/animation_player.cpp | 23 +++++++++++++---------- scene/animation/animation_player.h | 2 ++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 31dd4e45b489..ad6caca32b53 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -241,6 +241,16 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f make_animation_instance(cd.from->name, pi); } +float AnimationPlayer::get_current_blend_amount() { + Playback &c = playback; + float blend = 1.0; + for (List::Element *E = c.blend.front(); E; E = E->next()) { + Blend &b = E->get(); + blend = blend - b.blend_left; + } + return MAX(0, blend); +} + void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) { Playback &c = playback; @@ -250,16 +260,8 @@ void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) { c.seeked = false; } - // First, calc all blends weight. - float blend = 1.0; - for (List::Element *E = c.blend.front(); E; E = E->next()) { - Blend &b = E->get(); - blend = MAX(0, blend - b.blend_left); - b.blend_left = MAX(0, b.blend_left - Math::absf(speed_scale * p_delta) / b.blend_time); - } - // Second, process current animation to check if the animation end reached. - _process_playback_data(c.current, p_delta, blend, seeked, p_started, true); + _process_playback_data(c.current, p_delta, get_current_blend_amount(), seeked, p_started, true); // Finally, if not end the animation, do blending. if (end_reached) { @@ -269,6 +271,7 @@ void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) { List::Element *> to_erase; for (List::Element *E = c.blend.front(); E; E = E->next()) { Blend &b = E->get(); + b.blend_left = MAX(0, b.blend_left - Math::absf(speed_scale * p_delta) / b.blend_time); if (b.blend_left <= 0) { to_erase.push_back(E); b.blend_left = CMP_EPSILON; // May want to play last frame. @@ -405,7 +408,7 @@ void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, floa if (blend_time > 0) { Blend b; b.data = c.current; - b.blend_left = 1.0; + b.blend_left = get_current_blend_amount(); b.blend_time = blend_time; c.blend.push_back(b); } else { diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 74f9323e2b66..16bca45d4b7b 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -113,6 +113,8 @@ class AnimationPlayer : public AnimationMixer { void _stop_internal(bool p_reset, bool p_keep_state); void _check_immediately_after_start(); + float get_current_blend_amount(); + bool playing = false; protected: From 032d96042dff838976b2b4b725cbd6b3ca1e3b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gilles=20Roudi=C3=A8re?= Date: Fri, 5 Jan 2024 16:55:16 +0100 Subject: [PATCH 22/95] Fixes global transform being wrong on entering tree (cherry picked from commit 0a726d692a13214f7e3ee63dbc38a727ba0e8eb1) --- scene/main/canvas_item.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 4ee81e5cb099..8eae67e8375c 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -315,6 +315,7 @@ void CanvasItem::_notification(int p_what) { } } + _set_global_invalid(true); _enter_canvas(); RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, is_visible_in_tree()); // The visibility of the parent may change. From 2ba4a7dd3df6b8418e299c887379cf12df3a5865 Mon Sep 17 00:00:00 2001 From: jsjtxietian Date: Sat, 7 Oct 2023 18:53:02 +0800 Subject: [PATCH 23/95] Add thread guard for force_draw and update relared doc force_draw must be called from main thread (cherry picked from commit b88b84ce18c8620a1b451a635f12daa90db5209f) --- doc/classes/RenderingServer.xml | 2 +- servers/rendering/rendering_server_default.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 3bbf94af9446..dd3d190d7842 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -1370,7 +1370,7 @@ - Forces redrawing of all viewports at once. + Forces redrawing of all viewports at once. Must be called from the main thread. diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index 0c054900c790..5b526fc6283d 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -380,6 +380,7 @@ void RenderingServerDefault::sync() { } void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) { + ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Manually triggering the draw function from the RenderingServer can only be done on the main thread. Call this function from the main thread or use call_deferred()."); if (create_thread) { command_queue.push(this, &RenderingServerDefault::_thread_draw, p_swap_buffers, frame_step); } else { From cf767ddf290585de3c95a8e40ccfbfd8f68af560 Mon Sep 17 00:00:00 2001 From: Ricardo Buring Date: Tue, 12 Dec 2023 18:55:31 +0100 Subject: [PATCH 24/95] Fix operator documentation in GDExtension API dump with docs The type of the right operand is now taken into account. (cherry picked from commit 82afe58aca533c0ec95c3db0629a287700c48b30) --- core/extension/extension_api_dump.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index f3e988633c45..543dabfb16a4 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -742,14 +742,19 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) { Dictionary d2; String operator_name = Variant::get_operator_name(Variant::Operator(k)); d2["name"] = operator_name; - if (k != Variant::OP_NEGATE && k != Variant::OP_POSITIVE && k != Variant::OP_NOT && k != Variant::OP_BIT_NEGATE) { - d2["right_type"] = get_builtin_or_variant_type_name(Variant::Type(j)); + + String right_type_name = get_builtin_or_variant_type_name(Variant::Type(j)); + bool is_unary = k == Variant::OP_NEGATE || k == Variant::OP_POSITIVE || k == Variant::OP_NOT || k == Variant::OP_BIT_NEGATE; + if (!is_unary) { + d2["right_type"] = right_type_name; } + d2["return_type"] = get_builtin_or_variant_type_name(Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j))); if (p_include_docs && builtin_doc != nullptr) { for (const DocData::MethodDoc &operator_doc : builtin_doc->operators) { - if (operator_doc.name == "operator " + operator_name) { + if (operator_doc.name == "operator " + operator_name && + (is_unary || operator_doc.arguments[0].type == right_type_name)) { d2["description"] = fix_doc_description(operator_doc.description); break; } From d4114f163189bbb1d11ac99f421116a08d258aff Mon Sep 17 00:00:00 2001 From: ZeferinoI <95325186+ZeferinoI@users.noreply.github.com> Date: Thu, 14 Dec 2023 23:09:43 +0800 Subject: [PATCH 25/95] Update the description of the method get_connection_line in GraphEdit.xml The form should be like { from_port: 0, from_node: "GraphNode name 0", to_port: 1, to_node: "GraphNode name 1" } (cherry picked from commit 53ab38a34e8f7069ac5cabcc059319243079d950) --- doc/classes/GraphEdit.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index 410efd6389b7..9765b10d227b 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -154,7 +154,7 @@ - Returns an Array containing the list of connections. A connection consists in a structure of the form [code]{ from_port: 0, from: "GraphNode name 0", to_port: 1, to: "GraphNode name 1" }[/code]. + Returns an Array containing the list of connections. A connection consists in a structure of the form [code]{ from_port: 0, from_node: "GraphNode name 0", to_port: 1, to_node: "GraphNode name 1" }[/code]. From e00f2e598a93e4271e615feed29772d87aece341 Mon Sep 17 00:00:00 2001 From: Micky Date: Sun, 31 Dec 2023 14:04:38 +0100 Subject: [PATCH 26/95] Link to the "article" in the docs instead of saying "article" (cherry picked from commit 78c9e2c53adcdca21e7cda94145927474f8d53d3) --- doc/classes/Basis.xml | 2 +- doc/classes/InputEventMIDI.xml | 2 +- doc/classes/Transform2D.xml | 2 +- doc/classes/Transform3D.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index f98c207a6e03..fb6cf5a25876 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -7,7 +7,7 @@ A 3×3 matrix used for representing 3D rotation and scale. Usually used as an orthogonal basis for a [Transform3D]. Contains 3 vector fields X, Y and Z as its columns, which are typically interpreted as the local basis vectors of a transformation. For such use, it is composed of a scaling and a rotation matrix, in that order (M = R.S). Basis can also be accessed as an array of 3D vectors. These vectors are usually orthogonal to each other, but are not necessarily normalized (due to scaling). - For more information, read the "Matrices and transforms" documentation article. + For a general introduction, see the [url=$DOCS_URL/tutorials/math/matrices_and_transforms.html]Matrices and transforms[/url] tutorial. $DOCS_URL/tutorials/math/index.html diff --git a/doc/classes/InputEventMIDI.xml b/doc/classes/InputEventMIDI.xml index d685fdfa4147..8e2ad5280184 100644 --- a/doc/classes/InputEventMIDI.xml +++ b/doc/classes/InputEventMIDI.xml @@ -75,7 +75,7 @@ If the message is [constant MIDI_MESSAGE_CONTROL_CHANGE], this indicates the controller value, otherwise this is zero. Controllers include devices such as pedals and levers. - The instrument of this input event. This value ranges from 0 to 127. Refer to the instrument list on the General MIDI wikipedia article to see a list of instruments, except that this value is 0-index, so subtract one from every number on that chart. A standard piano will have an instrument number of 0. + The instrument of this input event. This value ranges from 0 to 127. Refer to the instrument list for [url=https://en.wikipedia.org/wiki/General_MIDI#Program_change_events]General MIDI[/url] to see a list of instruments, except that this value is 0-index, so subtract one from every number on that chart. A standard piano will have an instrument number of 0. Returns a value indicating the type of message for this MIDI signal. This is a member of the [enum MIDIMessage] enum. diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml index aee70f6b5986..19a4973f4a82 100644 --- a/doc/classes/Transform2D.xml +++ b/doc/classes/Transform2D.xml @@ -5,7 +5,7 @@ A 2×3 matrix (2 rows, 3 columns) used for 2D linear transformations. It can represent transformations such as translation, rotation, and scaling. It consists of three [Vector2] values: [member x], [member y], and the [member origin]. - For more information, read the "Matrices and transforms" documentation article. + For a general introduction, see the [url=$DOCS_URL/tutorials/math/matrices_and_transforms.html]Matrices and transforms[/url] tutorial. $DOCS_URL/tutorials/math/index.html diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml index 85da629d7051..91ece6943ce1 100644 --- a/doc/classes/Transform3D.xml +++ b/doc/classes/Transform3D.xml @@ -5,7 +5,7 @@ A 3×4 matrix (3 rows, 4 columns) used for 3D linear transformations. It can represent transformations such as translation, rotation, and scaling. It consists of a [member basis] (first 3 columns) and a [Vector3] for the [member origin] (last column). - For more information, read the "Matrices and transforms" documentation article. + For a general introduction, see the [url=$DOCS_URL/tutorials/math/matrices_and_transforms.html]Matrices and transforms[/url] tutorial. $DOCS_URL/tutorials/math/index.html From e35bbb2f8576057868328b51cd1fa760ec1a6981 Mon Sep 17 00:00:00 2001 From: Septian Date: Wed, 27 Dec 2023 20:37:37 +0700 Subject: [PATCH 27/95] Fix various typos in documentation (cherry picked from commit d83cad6d9b15460509dfca027a46aba4969cf750) --- doc/classes/BaseMaterial3D.xml | 2 +- doc/classes/CameraAttributesPractical.xml | 2 +- doc/classes/CompressedCubemap.xml | 2 +- doc/classes/CompressedCubemapArray.xml | 2 +- doc/classes/CompressedTexture2DArray.xml | 2 +- doc/classes/EditorPlugin.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index 653397ebc30e..e3a7eda56370 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -383,7 +383,7 @@ If [code]true[/code], enables subsurface scattering transmittance. Only effective if [member subsurf_scatter_enabled] is [code]true[/code]. See also [member backlight_enabled]. - The texture to use for multiplying the intensity of the subsurface scattering transmitteance intensity. See also [member subsurf_scatter_texture]. Ignored if [member subsurf_scatter_skin_mode] is [code]true[/code]. + The texture to use for multiplying the intensity of the subsurface scattering transmittance intensity. See also [member subsurf_scatter_texture]. Ignored if [member subsurf_scatter_skin_mode] is [code]true[/code]. Filter flags for the texture. See [enum TextureFilter] for options. diff --git a/doc/classes/CameraAttributesPractical.xml b/doc/classes/CameraAttributesPractical.xml index 8a5956cc8706..893bc27f91e2 100644 --- a/doc/classes/CameraAttributesPractical.xml +++ b/doc/classes/CameraAttributesPractical.xml @@ -17,7 +17,7 @@ The minimum sensitivity (in ISO) used when calculating auto exposure. When calculating scene average luminance, color values will be clamped to at least this value. This limits the auto-exposure from exposing above a certain brightness, resulting in a cut off point where the scene will remain dark. - Sets the maximum amount of blur. When using physically-based blur amounts, will instead act as a multiplier. High values lead to an increased amount of bluriness, but can be much more expensive to calculate. It is best to keep this as low as possible for a given art style. + Sets the maximum amount of blur. When using physically-based blur amounts, will instead act as a multiplier. High values lead to an increased amount of blurriness, but can be much more expensive to calculate. It is best to keep this as low as possible for a given art style. Objects further from the [Camera3D] by this amount will be blurred by the depth of field effect. Measured in meters. diff --git a/doc/classes/CompressedCubemap.xml b/doc/classes/CompressedCubemap.xml index 6ab0cc5d88df..406ab4909ab3 100644 --- a/doc/classes/CompressedCubemap.xml +++ b/doc/classes/CompressedCubemap.xml @@ -4,7 +4,7 @@ An optionally compressed [Cubemap]. - A cubemap that is loaded from a [code].ccube[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemap] can use one of 4 compresson methods: + A cubemap that is loaded from a [code].ccube[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemap] can use one of 4 compression methods: - Lossless (WebP or PNG, uncompressed on the GPU) - Lossy (WebP, uncompressed on the GPU) - VRAM Compressed (compressed on the GPU) diff --git a/doc/classes/CompressedCubemapArray.xml b/doc/classes/CompressedCubemapArray.xml index 32687229ed7e..195449ee99bc 100644 --- a/doc/classes/CompressedCubemapArray.xml +++ b/doc/classes/CompressedCubemapArray.xml @@ -4,7 +4,7 @@ An optionally compressed [CubemapArray]. - A cubemap array that is loaded from a [code].ccubearray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemapArray] can use one of 4 compresson methods: + A cubemap array that is loaded from a [code].ccubearray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemapArray] can use one of 4 compression methods: - Lossless (WebP or PNG, uncompressed on the GPU) - Lossy (WebP, uncompressed on the GPU) - VRAM Compressed (compressed on the GPU) diff --git a/doc/classes/CompressedTexture2DArray.xml b/doc/classes/CompressedTexture2DArray.xml index ab0684fa06ac..6570e8f93189 100644 --- a/doc/classes/CompressedTexture2DArray.xml +++ b/doc/classes/CompressedTexture2DArray.xml @@ -4,7 +4,7 @@ Array of 2-dimensional textures, optionally compressed. - A texture array that is loaded from a [code].ctexarray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedTexture2DArray] can use one of 4 compresson methods: + A texture array that is loaded from a [code].ctexarray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedTexture2DArray] can use one of 4 compression methods: - Lossless (WebP or PNG, uncompressed on the GPU) - Lossy (WebP, uncompressed on the GPU) - VRAM Compressed (compressed on the GPU) diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 50709f9ef5cc..148a6541a2bc 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -327,7 +327,7 @@ Implement this function if your plugin edits a specific type of object (Resource or Node). If you return [code]true[/code], then you will get the functions [method _edit] and [method _make_visible] called when the editor requests them. If you have declared the methods [method _forward_canvas_gui_input] and [method _forward_3d_gui_input] these will be called too. - [b]Note:[/b] Each plugin should handle only one type of objects at a time. If a plugin handes more types of objects and they are edited at the same time, it will result in errors. + [b]Note:[/b] Each plugin should handle only one type of objects at a time. If a plugin handles more types of objects and they are edited at the same time, it will result in errors. From cc90979f35e2ba24501c593261017439595eff35 Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Thu, 9 Nov 2023 12:21:36 +0100 Subject: [PATCH 28/95] Clarify that `@GlobalScope.clamp` does not do component-wise clamping (cherry picked from commit e7dbb7a267feb1e467ce160e4b431a3b8807fa67) --- doc/classes/@GlobalScope.xml | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 193284896aae..75fe10d1fc08 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -234,20 +234,9 @@ var b = clamp(8.1, 0.9, 5.5) # b is 5.5 - - var c = clamp(Vector2(-3.5, -4), Vector2(-3.2, -2), Vector2(2, 6.5)) - # c is (-3.2, -2) - - var d = clamp(Vector2i(7, 8), Vector2i(-3, -2), Vector2i(2, 6)) - # d is (2, 6) - - var e = clamp(Vector3(-7, 8.5, -3.8), Vector3(-3, -2, 5.4), Vector3(-2, 6, -4.1)) - # e is (-3, -2, 5.4) - - var f = clamp(Vector3i(-7, -8, -9), Vector3i(-1, 2, 3), Vector3i(-4, -5, -6)) - # f is (-4, -5, -6) [/codeblock] - [b]Note:[/b] For better type safety, use [method clampf], [method clampi], [method Vector2.clamp], [method Vector2i.clamp], [method Vector3.clamp], [method Vector3i.clamp], [method Vector4.clamp], [method Vector4i.clamp], or [method Color.clamp]. + [b]Note:[/b] For better type safety, use [method clampf], [method clampi], [method Vector2.clamp], [method Vector2i.clamp], [method Vector3.clamp], [method Vector3i.clamp], [method Vector4.clamp], [method Vector4i.clamp], or [method Color.clamp] (not currently supported by this method). + [b]Note:[/b] When using this on vectors it will [i]not[/i] perform component-wise clamping, and will pick [param min] if [code]value < min[/code] or [param max] if [code]value > max[/code]. To perform component-wise clamping use the methods listed above. From bb8b208ede2f33754e943c0a63b77d033ed2372a Mon Sep 17 00:00:00 2001 From: Markus Sauermann <6299227+Sauermann@users.noreply.github.com> Date: Mon, 31 Jul 2023 21:49:18 +0200 Subject: [PATCH 29/95] Explain which nodes receive `NOTIFICATION_WM_SIZE_CHANGED` (cherry picked from commit 361aa909da10d2bee04b46b48923ebb4c8a416c7) --- doc/classes/Node.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 0ace4357fa30..58b73f231d56 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -1073,7 +1073,8 @@ Specific to the Android platform. - Notification received from the OS when the window is resized. + Notification received when the window is resized. + [b]Note:[/b] Only the resized [Window] node receives this notification, and it's not propagated to the child nodes. Notification received from the OS when the screen's DPI has been changed. Only implemented on macOS. From 49cec88ff9f004dce0865221835764f48b000172 Mon Sep 17 00:00:00 2001 From: Nico Date: Sun, 29 Oct 2023 15:29:41 +0100 Subject: [PATCH 30/95] Complete the docs for Quaternion (cherry picked from commit d67e7f872980011114f237c103e984c8772611ba) --- doc/classes/Quaternion.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/classes/Quaternion.xml b/doc/classes/Quaternion.xml index 74dfae77fc2e..61bc4f472041 100644 --- a/doc/classes/Quaternion.xml +++ b/doc/classes/Quaternion.xml @@ -79,6 +79,7 @@ + Returns the exponential of this quaternion. The rotation axis of the result is the normalized rotation axis of this quaternion, the angle of the result is the length of the vector part of this quaternion. @@ -91,11 +92,14 @@ + Returns the angle of the rotation represented by this quaternion. + [b]Note:[/b] The quaternion must be normalized. + Returns the rotation axis of the rotation represented by this quaternion. @@ -145,6 +149,7 @@ + Returns the logarithm of this quaternion. The vector part of the result is the rotation axis of this quaternion multiplied by its rotation angle, the real part of the result is zero. From 27d08e2d87916c47e89aa89c7c80d28b77729425 Mon Sep 17 00:00:00 2001 From: Gwen <50772474+SGiygas@users.noreply.github.com> Date: Sat, 30 Dec 2023 19:13:58 +0100 Subject: [PATCH 31/95] Correct C# syntax in _validate_property example for the Object class (cherry picked from commit e40b23c619bacf92d3ebd2ea5cf5d49508947cb2) --- doc/classes/Object.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index 2ffb02096da6..e4f4d7682b9e 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -314,7 +314,7 @@ { if (property["name"].AsStringName() == PropertyName.Number && IsNumberEditable) { - var usage = property["usage"].As>PropertyUsageFlags<() | PropertyUsageFlags.ReadOnly; + var usage = property["usage"].As<PropertyUsageFlags>() | PropertyUsageFlags.ReadOnly; property["usage"] = (int)usage; } } From 3b2cdc2cc59ee6ba8c9e4e3d56421bbbacb3ceba Mon Sep 17 00:00:00 2001 From: Micky Date: Fri, 28 Oct 2022 15:52:46 +0200 Subject: [PATCH 32/95] Overhaul Node Documentation (cherry picked from commit b5ca06c9ca2e7184e54606585fde8e07334b1b80) --- doc/classes/Node.xml | 434 +++++++++++++++++++++++-------------------- 1 file changed, 232 insertions(+), 202 deletions(-) diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 58b73f231d56..c61ae3f8881a 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -11,11 +11,11 @@ This means that when adding a node to the scene tree, the following order will be used for the callbacks: [method _enter_tree] of the parent, [method _enter_tree] of the children, [method _ready] of the children and finally [method _ready] of the parent (recursively for the entire scene tree). [b]Processing:[/b] Nodes can override the "process" state, so that they receive a callback on each frame requesting them to process (do something). Normal processing (callback [method _process], toggled with [method set_process]) happens as fast as possible and is dependent on the frame rate, so the processing time [i]delta[/i] (in seconds) is passed as an argument. Physics processing (callback [method _physics_process], toggled with [method set_physics_process]) happens a fixed number of times per second (60 by default) and is useful for code related to the physics engine. Nodes can also process input events. When present, the [method _input] function will be called for each input that the program receives. In many cases, this can be overkill (unless used for simple projects), and the [method _unhandled_input] function might be preferred; it is called when the input event was not handled by anyone else (typically, GUI [Control] nodes), ensuring that the node only receives the events that were meant for it. - To keep track of the scene hierarchy (especially when instancing scenes into other scenes), an "owner" can be set for the node with the [member owner] property. This keeps track of who instantiated what. This is mostly useful when writing editors and tools, though. + To keep track of the scene hierarchy (especially when instantiating scenes into other scenes), an "owner" can be set for the node with the [member owner] property. This keeps track of who instantiated what. This is mostly useful when writing editors and tools, though. Finally, when a node is freed with [method Object.free] or [method queue_free], it will also free all its children. [b]Groups:[/b] Nodes can be added to as many groups as you want to be easy to manage, you could create groups like "enemies" or "collectables" for example, depending on your game. See [method add_to_group], [method is_in_group] and [method remove_from_group]. You can then retrieve all nodes in these groups, iterate them and even call methods on groups via the methods on [SceneTree]. [b]Networking with nodes:[/b] After connecting to a server (or making one, see [ENetMultiplayerPeer]), it is possible to use the built-in RPC (remote procedure call) system to communicate over the network. By calling [method rpc] with a method name, it will be called locally and in all connected peers (peers = clients and the server that accepts connections). To identify which node receives the RPC call, Godot will use its [NodePath] (make sure node names are the same on all peers). Also, take a look at the high-level networking tutorial and corresponding demos. - [b]Note:[/b] The [code]script[/code] property is part of the [Object] class, not [Node]. It isn't exposed like most properties but does have a setter and getter ([code]set_script()[/code] and [code]get_script()[/code]). + [b]Note:[/b] The [code]script[/code] property is part of the [Object] class, not [Node]. It isn't exposed like most properties but does have a setter and getter (see [method Object.set_script] and [method Object.get_script]). $DOCS_URL/getting_started/step_by_step/nodes_and_scenes.html @@ -25,7 +25,7 @@ - Called when the node enters the [SceneTree] (e.g. upon instancing, scene changing, or after calling [method add_child] in a script). If the node has children, its [method _enter_tree] callback will be called first, and then that of the children. + Called when the node enters the [SceneTree] (e.g. upon instantiating, scene changing, or after calling [method add_child] in a script). If the node has children, its [method _enter_tree] callback will be called first, and then that of the children. Corresponds to the [constant NOTIFICATION_ENTER_TREE] notification in [method Object._notification]. @@ -93,7 +93,7 @@ Called when the node is "ready", i.e. when both the node and its children have entered the scene tree. If the node has children, their [method _ready] callbacks get triggered first, and the parent node will receive the ready notification afterwards. Corresponds to the [constant NOTIFICATION_READY] notification in [method Object._notification]. See also the [code]@onready[/code] annotation for variables. Usually used for initialization. For even earlier initialization, [method Object._init] may be used. See also [method _enter_tree]. - [b]Note:[/b] [method _ready] may be called only once for each node. After removing a node from the scene tree and adding it again, [method _ready] will not be called a second time. This can be bypassed by requesting another call with [method request_ready], which may be called anywhere before adding the node again. + [b]Note:[/b] This method may be called only once for each node. After removing a node from the scene tree and adding it again, [method _ready] will [b]not[/b] be called a second time. This can be bypassed by requesting another call with [method request_ready], which may be called anywhere before adding the node again. @@ -138,8 +138,8 @@ Adds a child [param node]. Nodes can have any number of children, but every child must have a unique name. Child nodes are automatically deleted when the parent node is deleted, so an entire scene can be removed by deleting its topmost node. If [param force_readable_name] is [code]true[/code], improves the readability of the added [param node]. If not named, the [param node] is renamed to its type, and if it shares [member name] with a sibling, a number is suffixed more appropriately. This operation is very slow. As such, it is recommended leaving this to [code]false[/code], which assigns a dummy name featuring [code]@[/code] in both situations. - If [param internal] is different than [constant INTERNAL_MODE_DISABLED], the child will be added as internal node. Such nodes are ignored by methods like [method get_children], unless their parameter [code]include_internal[/code] is [code]true[/code]. The intended usage is to hide the internal nodes from the user, so the user won't accidentally delete or modify them. Used by some GUI nodes, e.g. [ColorPicker]. See [enum InternalMode] for available modes. - [b]Note:[/b] If the child node already has a parent, the function will fail. Use [method remove_child] first to remove the node from its current parent. For example: + If [param internal] is different than [constant INTERNAL_MODE_DISABLED], the child will be added as internal node. These nodes are ignored by methods like [method get_children], unless their parameter [code]include_internal[/code] is [code]true[/code]. The intended usage is to hide the internal nodes from the user, so the user won't accidentally delete or modify them. Used by some GUI nodes, e.g. [ColorPicker]. See [enum InternalMode] for available modes. + [b]Note:[/b] If [param node] already has a parent, this method will fail. Use [method remove_child] first to remove [param node] from its current parent. For example: [codeblocks] [gdscript] var child_node = get_child(0) @@ -165,10 +165,10 @@ - Adds a [param sibling] node to current's node parent, at the same level as that node, right below it. + Adds a [param sibling] node to this node's parent, and moves the added sibling right below this node. If [param force_readable_name] is [code]true[/code], improves the readability of the added [param sibling]. If not named, the [param sibling] is renamed to its type, and if it shares [member name] with a sibling, a number is suffixed more appropriately. This operation is very slow. As such, it is recommended leaving this to [code]false[/code], which assigns a dummy name featuring [code]@[/code] in both situations. Use [method add_child] instead of this method if you don't need the child node to be added below a specific node in the list of children. - [b]Note:[/b] If this node is internal, the new sibling will be internal too (see [code]internal[/code] parameter in [method add_child]). + [b]Note:[/b] If this node is internal, the added sibling will be internal too (see [method add_child]'s [code]internal[/code] parameter). @@ -176,9 +176,10 @@ - Adds the node to a group. Groups are helpers to name and organize a subset of nodes, for example "enemies" or "collectables". A node can be in any number of groups. Nodes can be assigned a group at any time, but will not be added until they are inside the scene tree (see [method is_inside_tree]). See notes in the description, and the group methods in [SceneTree]. - The [param persistent] option is used when packing node to [PackedScene] and saving to file. Non-persistent groups aren't stored. - [b]Note:[/b] For performance reasons, the order of node groups is [i]not[/i] guaranteed. The order of node groups should not be relied upon as it can vary across project runs. + Adds the node to the [param group]. Groups can be helpful to organize a subset of nodes, for example [code]"enemies"[/code] or [code]"collectables"[/code]. See notes in the description, and the group methods in [SceneTree]. + If [param persistent] is [code]true[/code], the group will be stored when saved inside a [PackedScene]. All groups created and displayed in the Node dock are persistent. + [b]Note:[/b] To improve performance, the order of group names is [i]not[/i] guaranteed and may vary between project runs. Therefore, do not rely on the group order. + [b]Note:[/b] [SceneTree]'s group methods will [i]not[/i] work on this node if not inside the tree (see [method is_inside_tree]). @@ -198,13 +199,14 @@ - Returns [code]true[/code] if the node can process while the scene tree is paused (see [member process_mode]). Always returns [code]true[/code] if the scene tree is not paused, and [code]false[/code] if the node is not in the tree. + Returns [code]true[/code] if the node can receive processing notifications and input callbacks ([constant NOTIFICATION_PROCESS], [method _input], etc) from the [SceneTree] and [Viewport]. The value depends on both the current [member process_mode] and [member SceneTree.paused]. Returns [code]false[/code] if the node is not inside the tree. - Creates a new [Tween] and binds it to this node. This is equivalent of doing: + Creates a new [Tween] and binds it to this node. Fails if the node is not inside the tree. + This is the equivalent of doing: [codeblocks] [gdscript] get_tree().create_tween().bind_node(self) @@ -220,9 +222,8 @@ - Duplicates the node, returning a new node. - You can fine-tune the behavior using the [param flags] (see [enum DuplicateFlags]). - [b]Note:[/b] It will not work properly if the node contains a script with constructor arguments (i.e. needs to supply arguments to [method Object._init] method). In that case, the node will be duplicated without a script. + Duplicates the node, returning a new node with all of its properties, signals and groups copied from the original. The behavior can be tweaked through the [param flags] (see [enum DuplicateFlags]). + [b]Note:[/b] For nodes with a [Script] attached, if [method Object._init] has been defined with required parameters, the duplicated node will not have a [Script]. @@ -231,12 +232,10 @@ - Finds the first descendant of this node whose name matches [param pattern] as in [method String.match]. Internal children are also searched over (see [code]internal[/code] parameter in [method add_child]). - [param pattern] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]). - If [param recursive] is [code]true[/code], all child nodes are included, even if deeply nested. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. If [param recursive] is [code]false[/code], only this node's direct children are matched. - If [param owned] is [code]true[/code], this method only finds nodes who have an assigned [member Node.owner]. This is especially important for scenes instantiated through a script, because those scenes don't have an owner. - Returns [code]null[/code] if no matching [Node] is found. - [b]Note:[/b] As this method walks through all the descendants of the node, it is the slowest way to get a reference to another node. Whenever possible, consider using [method get_node] with unique names instead (see [member unique_name_in_owner]), or caching the node references into variable. + Finds the first descendant of this node whose [member name] matches [param pattern], returning [code]null[/code] if no match is found. The matching is done against node names, [i]not[/i] their paths, through [method String.match]. As such, it is case-sensitive, [code]"*"[/code] matches zero or more characters, and [code]"?"[/code] matches any single character. + If [param recursive] is [code]false[/code], only this node's direct children are checked. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. Internal children are also included in the search (see [code]internal[/code] parameter in [method add_child]). + If [param owned] is [code]true[/code], only descendants with a valid [member owner] node are checked. + [b]Note:[/b] This method can be very slow. Consider storing a reference to the found node in a variable. Alternatively, use [method get_node] with unique names (see [member unique_name_in_owner]). [b]Note:[/b] To find all descendant nodes matching a pattern or a class type, see [method find_children]. @@ -247,23 +246,20 @@ - Finds descendants of this node whose name matches [param pattern] as in [method String.match], and/or type matches [param type] as in [method Object.is_class]. Internal children are also searched over (see [code]internal[/code] parameter in [method add_child]). - [param pattern] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]). - [param type] will check equality or inheritance, and is case-sensitive. [code]"Object"[/code] will match a node whose type is [code]"Node"[/code] but not the other way around. - If [param recursive] is [code]true[/code], all child nodes are included, even if deeply nested. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. If [param recursive] is [code]false[/code], only this node's direct children are matched. - If [param owned] is [code]true[/code], this method only finds nodes who have an assigned [member Node.owner]. This is especially important for scenes instantiated through a script, because those scenes don't have an owner. - Returns an empty array if no matching nodes are found. - [b]Note:[/b] As this method walks through all the descendants of the node, it is the slowest way to get references to other nodes. Whenever possible, consider caching the node references into variables. - [b]Note:[/b] If you only want to find the first descendant node that matches a pattern, see [method find_child]. + Finds all descendants of this node whose names match [param pattern], returning an empty [Array] if no match is found. The matching is done against node names, [i]not[/i] their paths, through [method String.match]. As such, it is case-sensitive, [code]"*"[/code] matches zero or more characters, and [code]"?"[/code] matches any single character. + If [param type] is not empty, only ancestors inheriting from [param type] are included (see [method Object.is_class]). + If [param recursive] is [code]false[/code], only this node's direct children are checked. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. Internal children are also included in the search (see [code]internal[/code] parameter in [method add_child]). + If [param owned] is [code]true[/code], only descendants with a valid [member owner] node are checked. + [b]Note:[/b] This method can be very slow. Consider storing references to the found nodes in a variable. + [b]Note:[/b] To find a single descendant node matching a pattern, see [method find_child]. - Finds the first parent of the current node whose name matches [param pattern] as in [method String.match]. - [param pattern] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]). - [b]Note:[/b] As this method walks upwards in the scene tree, it can be slow in large, deeply nested scene trees. Whenever possible, consider using [method get_node] with unique names instead (see [member unique_name_in_owner]), or caching the node references into variable. + Finds the first ancestor of this node whose [member name] matches [param pattern], returning [code]null[/code] if no match is found. The matching is done through [method String.match]. As such, it is case-sensitive, [code]"*"[/code] matches zero or more characters, and [code]"?"[/code] matches any single character. See also [method find_child] and [method find_children]. + [b]Note:[/b] As this method walks upwards in the scene tree, it can be slow in large, deeply nested nodes. Consider storing a reference to the found node in a variable. Alternatively, use [method get_node] with unique names (see [member unique_name_in_owner]). @@ -271,44 +267,52 @@ - Returns a child node by its index (see [method get_child_count]). This method is often used for iterating all children of a node. - Negative indices access the children from the last one. - If [param include_internal] is [code]false[/code], internal children are skipped (see [code]internal[/code] parameter in [method add_child]). - To access a child node via its name, use [method get_node]. + Fetches a child node by its index. Each child node has an index relative its siblings (see [method get_index]). The first child is at index 0. Negative values can also be used to start from the end of the list. This method can be used in combination with [method get_child_count] to iterate over this node's children. + If [param include_internal] is [code]false[/code], internal children are ignored (see [method add_child]'s [code]internal[/code] parameter). + [codeblock] + # Assuming the following are children of this node, in order: + # First, Middle, Last. + + var a = get_child(0).name # a is "First" + var b = get_child(1).name # b is "Middle" + var b = get_child(2).name # b is "Last" + var c = get_child(-1).name # c is "Last" + [/codeblock] + [b]Note:[/b] To fetch a node by [NodePath], use [method get_node]. - Returns the number of child nodes. - If [param include_internal] is [code]false[/code], internal children aren't counted (see [code]internal[/code] parameter in [method add_child]). + Returns the number of children of this node. + If [param include_internal] is [code]false[/code], internal children are not counted (see [method add_child]'s [code]internal[/code] parameter). - Returns an array of references to node's children. - If [param include_internal] is [code]false[/code], the returned array won't include internal children (see [code]internal[/code] parameter in [method add_child]). + Returns all children of this node inside an [Array]. + If [param include_internal] is [code]false[/code], excludes internal children from the returned array (see [method add_child]'s [code]internal[/code] parameter). - Returns an array listing the groups that the node is a member of. - [b]Note:[/b] For performance reasons, the order of node groups is [i]not[/i] guaranteed. The order of node groups should not be relied upon as it can vary across project runs. - [b]Note:[/b] The engine uses some group names internally (all starting with an underscore). To avoid conflicts with internal groups, do not add custom groups whose name starts with an underscore. To exclude internal groups while looping over [method get_groups], use the following snippet: + Returns an [Array] of group names that the node has been added to. + [b]Note:[/b] To improve performance, the order of group names is [i]not[/i] guaranteed and may vary between project runs. Therefore, do not rely on the group order. + [b]Note:[/b] This method may also return some group names starting with an underscore ([code]_[/code]). These are internally used by the engine. To avoid conflicts, do not use custom groups starting with underscores. To exclude internal groups, see the following code snippet: [codeblocks] [gdscript] - # Stores the node's non-internal groups only (as an array of Strings). + # Stores the node's non-internal groups only (as an array of StringNames). var non_internal_groups = [] for group in get_groups(): - if not group.begins_with("_"): + if not str(group).begins_with("_"): non_internal_groups.push_back(group) [/gdscript] [csharp] - // Stores the node's non-internal groups only (as a List of strings). + // Stores the node's non-internal groups only (as a List of StringNames). List<string> nonInternalGroups = new List<string>(); foreach (string group in GetGroups()) { @@ -323,8 +327,8 @@ - Returns the node's order in the scene tree branch. For example, if called on the first child node the position is [code]0[/code]. - If [param include_internal] is [code]false[/code], the index won't take internal children into account, i.e. first non-internal child will have index of 0 (see [code]internal[/code] parameter in [method add_child]). + Returns this node's order among its siblings. The first node's index is [code]0[/code]. See also [method get_child]. + If [param include_internal] is [code]false[/code], returns the index ignoring internal children. The first, non-internal child will have an index of [code]0[/code] (see [method add_child]'s [code]internal[/code] parameter). @@ -343,20 +347,22 @@ - Fetches a node. The [NodePath] can be either a relative path (from the current node) or an absolute path (in the scene tree) to a node. If the path does not exist, [code]null[/code] is returned and an error is logged. Attempts to access methods on the return value will result in an "Attempt to call <method> on a null instance." error. - [b]Note:[/b] Fetching absolute paths only works when the node is inside the scene tree (see [method is_inside_tree]). - [b]Example:[/b] Assume your current node is Character and the following tree: + Fetches a node. The [NodePath] can either be a relative path (from this node), or an absolute path (from the [member SceneTree.root]) to a node. If [param path] does not point to a valid node, generates an error and returns [code]null[/code]. Attempts to access methods on the return value will result in an [i]"Attempt to call <method> on a null instance."[/i] error. + [b]Note:[/b] Fetching by absolute path only works when the node is inside the scene tree (see [method is_inside_tree]). + [b]Example:[/b] Assume this method is called from the Character node, inside the following tree: [codeblock] - /root - /root/Character - /root/Character/Sword - /root/Character/Backpack/Dagger - /root/MyGame - /root/Swamp/Alligator - /root/Swamp/Mosquito - /root/Swamp/Goblin + ┖╴root + ┠╴Character (you are here!) + ┃ ┠╴Sword + ┃ ┖╴Backpack + ┃ ┖╴Dagger + ┠╴MyGame + ┖╴Swamp + ┠╴Alligator + ┠╴Mosquito + ┖╴Goblin [/codeblock] - Possible paths are: + The following calls will return a valid node: [codeblocks] [gdscript] get_node("Sword") @@ -377,19 +383,43 @@ - Fetches a node and one of its resources as specified by the [NodePath]'s subname (e.g. [code]Area2D/CollisionShape2D:shape[/code]). If several nested resources are specified in the [NodePath], the last one will be fetched. - The return value is an array of size 3: the first index points to the [Node] (or [code]null[/code] if not found), the second index points to the [Resource] (or [code]null[/code] if not found), and the third index is the remaining [NodePath], if any. - For example, assuming that [code]Area2D/CollisionShape2D[/code] is a valid node and that its [code]shape[/code] property has been assigned a [RectangleShape2D] resource, one could have this kind of output: + Fetches a node and its most nested resource as specified by the [NodePath]'s subname. Returns an [Array] of size [code]3[/code] where: + - Element [code]0[/code] is the [Node], or [code]null[/code] if not found; + - Element [code]1[/code] is the subname's last nested [Resource], or [code]null[/code] if not found; + - Element [code]2[/code] is the remaining [NodePath], referring to an existing, non-[Resource] property (see [method Object.get_indexed]). + [b]Example:[/b] Assume that the child's [member Sprite2D.texture] has been assigned a [AtlasTexture]: [codeblocks] [gdscript] - print(get_node_and_resource("Area2D/CollisionShape2D")) # [[CollisionShape2D:1161], Null, ] - print(get_node_and_resource("Area2D/CollisionShape2D:shape")) # [[CollisionShape2D:1161], [RectangleShape2D:1156], ] - print(get_node_and_resource("Area2D/CollisionShape2D:shape:extents")) # [[CollisionShape2D:1161], [RectangleShape2D:1156], :extents] + var a = get_node_and_resource("Area2D/Sprite2D") + print(a[0].name) # Prints Sprite2D + print(a[1]) # Prints <null> + print(a[2]) # Prints ^"" + + var b = get_node_and_resource("Area2D/Sprite2D:texture:atlas") + print(b[0].name) # Prints Sprite2D + print(b[1].get_class()) # Prints AtlasTexture + print(b[2]) # Prints ^"" + + var c = get_node_and_resource("Area2D/Sprite2D:texture:atlas:region") + print(c[0].name) # Prints Sprite2D + print(c[1].get_class()) # Prints AtlasTexture + print(c[2]) # Prints ^":region" [/gdscript] [csharp] - GD.Print(GetNodeAndResource("Area2D/CollisionShape2D")); // [[CollisionShape2D:1161], Null, ] - GD.Print(GetNodeAndResource("Area2D/CollisionShape2D:shape")); // [[CollisionShape2D:1161], [RectangleShape2D:1156], ] - GD.Print(GetNodeAndResource("Area2D/CollisionShape2D:shape:extents")); // [[CollisionShape2D:1161], [RectangleShape2D:1156], :extents] + var a = GetNodeAndResource(NodePath("Area2D/Sprite2D")); + GD.Print(a[0].Name); // Prints Sprite2D + GD.Print(a[1]); // Prints <null> + GD.Print(a[2]); // Prints ^" + + var b = GetNodeAndResource(NodePath("Area2D/Sprite2D:texture:atlas")); + GD.Print(b[0].name); // Prints Sprite2D + GD.Print(b[1].get_class()); // Prints AtlasTexture + GD.Print(b[2]); // Prints ^"" + + var c = GetNodeAndResource(NodePath("Area2D/Sprite2D:texture:atlas:region")); + GD.Print(c[0].name); // Prints Sprite2D + GD.Print(c[1].get_class()); // Prints AtlasTexture + GD.Print(c[2]); // Prints ^":region" [/csharp] [/codeblocks] @@ -398,19 +428,19 @@ - Similar to [method get_node], but does not log an error if [param path] does not point to a valid [Node]. + Fetches a node by [NodePath]. Similar to [method get_node], but does not generate an error if [param path] does not point to a valid node. - Returns the parent node of the current node, or [code]null[/code] if the node lacks a parent. + Returns this node's parent node, or [code]null[/code] if the node doesn't have a parent. - Returns the absolute path of the current node. This only works if the current node is inside the scene tree (see [method is_inside_tree]). + Returns the node's absolute path, relative to the [member SceneTree.root]. If the node is not inside the scene tree, this method fails and returns an empty [NodePath]. @@ -418,33 +448,33 @@ - Returns the relative [NodePath] from this node to the specified [param node]. Both nodes must be in the same scene or the function will fail. - If [param use_unique_path] is [code]true[/code], returns the shortest path considering unique node. - [b]Note:[/b] If you get a relative path which starts from a unique node, the path may be longer than a normal relative path due to the addition of the unique node's name. + Returns the relative [NodePath] from this node to the specified [param node]. Both nodes must be in the same [SceneTree], otherwise this method fails and returns an empty [NodePath]. + If [param use_unique_path] is [code]true[/code], returns the shortest path accounting for this node's unique name (see [member unique_name_in_owner]). + [b]Note:[/b] If you get a relative path which starts from a unique node, the path may be longer than a normal relative path, due to the addition of the unique node's name. - Returns the time elapsed (in seconds) since the last physics-bound frame (see [method _physics_process]). This is always a constant value in physics processing unless the frames per second is changed via [member Engine.physics_ticks_per_second]. + Returns the time elapsed (in seconds) since the last physics callback. This value is identical to [method _physics_process]'s [code]delta[/code] parameter, and is often consistent at run-time, unless [member Engine.physics_ticks_per_second] is changed. See also [constant NOTIFICATION_PHYSICS_PROCESS]. - Returns the time elapsed (in seconds) since the last process callback. This value may vary from frame to frame. + Returns the time elapsed (in seconds) since the last process callback. This value is identical to [method _process]'s [code]delta[/code] parameter, and may vary from frame to frame. See also [constant NOTIFICATION_PROCESS]. - Returns [code]true[/code] if this is an instance load placeholder. See [InstancePlaceholder]. + Returns [code]true[/code] if this node is an instance load placeholder. See [InstancePlaceholder] and [method set_scene_instance_load_placeholder]. - Returns the [SceneTree] that contains this node. Returns [code]null[/code] and prints an error if this node is not inside the scene tree. See also [method is_inside_tree]. + Returns the [SceneTree] that contains this node. If this node is not inside the tree, generates an error and returns [code]null[/code]. See also [method is_inside_tree]. @@ -480,7 +510,7 @@ - Returns the node's [Viewport]. + Returns the node's closest [Viewport] ancestor, if the node is inside the tree. Otherwise, returns [code]null[/code]. @@ -493,54 +523,54 @@ - Returns [code]true[/code] if the node that the [NodePath] points to exists. + Returns [code]true[/code] if the [param path] points to a valid node. See also [method get_node]. - Returns [code]true[/code] if the [NodePath] points to a valid node and its subname points to a valid resource, e.g. [code]Area2D/CollisionShape2D:shape[/code]. Properties with a non-[Resource] type (e.g. nodes or primitive math types) are not considered resources. + Returns [code]true[/code] if [param path] points to a valid node and its subnames point to a valid [Resource], e.g. [code]Area2D/CollisionShape2D:shape[/code]. Properties that are not [Resource] types (such as nodes or other [Variant] types) are not considered. See also [method get_node_and_resource]. - Returns [code]true[/code] if the given node is a direct or indirect child of the current node. + Returns [code]true[/code] if the given [param node] is a direct or indirect child of this node. - Returns [code]true[/code] if the node is folded (collapsed) in the Scene dock. This method is only intended for use with editor tooling. + Returns [code]true[/code] if the node is folded (collapsed) in the Scene dock. This method is intended to be used in editor plugins and tools. See also [method set_display_folded]. - Returns [code]true[/code] if [param node] has editable children enabled relative to this node. This method is only intended for use with editor tooling. + Returns [code]true[/code] if [param node] has editable children enabled relative to this node. This method is intended to be used in editor plugins and tools. See also [method set_editable_instance]. - Returns [code]true[/code] if the given node occurs later in the scene hierarchy than the current node. + Returns [code]true[/code] if the given [param node] occurs later in the scene hierarchy than this node. A node occurring later is usually processed last. - Returns [code]true[/code] if this node is in the specified group. See notes in the description, and the group methods in [SceneTree]. + Returns [code]true[/code] if this node has been added to the given [param group]. See [method add_to_group] and [method remove_from_group]. See also notes in the description, and the [SceneTree]'s group methods. - Returns [code]true[/code] if this node is currently inside a [SceneTree]. + Returns [code]true[/code] if this node is currently inside a [SceneTree]. See also [method get_tree]. @@ -609,8 +639,8 @@ - Moves a child node to a different index (order) among the other children. Since calls, signals, etc. are performed by tree order, changing the order of children nodes may be useful. If [param to_index] is negative, the index will be counted from the end. - [b]Note:[/b] Internal children can only be moved within their expected "internal range" (see [code]internal[/code] parameter in [method add_child]). + Moves [param child_node] to the given index. A node's index is the order among its siblings. If [param to_index] is negative, the index is counted from the end of the list. See also [method get_child] and [method get_index]. + [b]Note:[/b] The processing order of several engine callbacks ([method _ready], [method _process], etc.) and notifications sent through [method propagate_notification] is affected by tree order. [CanvasItem] nodes are also rendered in tree order. See also [member process_priority]. @@ -630,29 +660,29 @@ - Prints all orphan nodes (nodes outside the [SceneTree]). Used for debugging. - [b]Note:[/b] [method print_orphan_nodes] only works in debug builds. When called in a project exported in release mode, [method print_orphan_nodes] will not print anything. + Prints all orphan nodes (nodes outside the [SceneTree]). Useful for debugging. + [b]Note:[/b] This method only works in debug builds. Does nothing in a project exported in release mode. - Prints the tree to stdout. Used mainly for debugging purposes. This version displays the path relative to the current node, and is good for copy/pasting into the [method get_node] function. + Prints the node and its children to the console, recursively. The node does not have to be inside the tree. This method outputs [NodePath]s relative to this node, and is good for copy/pasting into [method get_node]. See also [method print_tree_pretty]. [b]Example output:[/b] [codeblock] - TheGame - TheGame/Menu - TheGame/Menu/Label - TheGame/Menu/Camera2D - TheGame/SplashScreen - TheGame/SplashScreen/Camera2D + . + Menu + Menu/Label + Menu/Camera2D + SplashScreen + SplashScreen/Camera2D [/codeblock] - Similar to [method print_tree], this prints the tree to stdout. This version displays a more graphical representation similar to what is displayed in the Scene Dock. It is useful for inspecting larger trees. + Prints the node and its children to the console, recursively. The node does not have to be inside the tree. Similar to [method print_tree], but the graphical representation looks like what is displayed in the editor's Scene dock. It is useful for inspecting larger trees. [b]Example output:[/b] [codeblock] ┖╴TheGame @@ -670,37 +700,38 @@ - Calls the given method (if present) with the arguments given in [param args] on this node and recursively on all its children. If the [param parent_first] argument is [code]true[/code], the method will be called on the current node first, then on all its children. If [param parent_first] is [code]false[/code], the children will be called first. + Calls the given [param method] name, passing [param args] as arguments, on this node and all of its children, recursively. + If [param parent_first] is [code]true[/code], the method is called on this node first, then on all of its children. If [code]false[/code], the children's methods are called first. - Notifies the current node and all its children recursively by calling [method Object.notification] on all of them. + Calls [method Object.notification] with [param what] on this node and all of its children, recursively. - Queues a node for deletion at the end of the current frame. When deleted, all of its child nodes will be deleted as well, and all references to the node and its children will become invalid, see [method Object.free]. - It is safe to call [method queue_free] multiple times per frame on a node, and to [method Object.free] a node that is currently queued for deletion. Use [method Object.is_queued_for_deletion] to check whether a node will be deleted at the end of the frame. - The node will only be freed after all other deferred calls are finished, so using [method queue_free] is not always the same as calling [method Object.free] through [method Object.call_deferred]. + Queues this node to be deleted at the end of the current frame. When deleted, all of its children are deleted as well, and all references to the node and its children become invalid. + Unlike with [method Object.free], the node is not deleted instantly, and it can still be accessed before deletion. It is also safe to call [method queue_free] multiple times. Use [method Object.is_queued_for_deletion] to check if the node will be deleted at the end of the frame. + [b]Note:[/b] The node will only be freed after all other deferred calls are finished. Using this method is not always the same as calling [method Object.free] through [method Object.call_deferred]. - Removes a child node. The node is NOT deleted and must be deleted manually. - [b]Note:[/b] This function may set the [member owner] of the removed Node (or its descendants) to be [code]null[/code], if that [member owner] is no longer a parent or ancestor. + Removes a child [param node]. The [param node], along with its children, are [b]not[/b] deleted. To delete a node, see [method queue_free]. + [b]Note:[/b] When this node is inside the tree, this method sets the [member owner] of the removed [param node] (or its descendants) to [code]null[/code], if their [member owner] is no longer an ancestor (see [method is_ancestor_of]). - Removes a node from the [param group]. Does nothing if the node is not in the [param group]. See notes in the description, and the group methods in [SceneTree]. + Removes the node from the given [param group]. Does nothing if the node is not in the [param group]. See also notes in the description, and the [SceneTree]'s group methods. @@ -717,24 +748,25 @@ - Replaces a node in a scene by the given one. Subscriptions that pass through this node will be lost. - If [param keep_groups] is [code]true[/code], the [param node] is added to the same groups that the replaced node is in. - [b]Note:[/b] The given node will become the new parent of any child nodes that the replaced node had. - [b]Note:[/b] The replaced node is not automatically freed, so you either need to keep it in a variable for later use or free it using [method Object.free]. + Replaces this node by the given [param node]. All children of this node are moved to [param node]. + If [param keep_groups] is [code]true[/code], the [param node] is added to the same groups that the replaced node is in (see [method add_to_group]). + [b]Warning:[/b] The replaced node is removed from the tree, but it is [b]not[/b] deleted. To prevent memory leaks, store a reference to the node in a variable, or use [method Object.free]. - Requests that [method _ready] be called again. Note that the method won't be called immediately, but is scheduled for when the node is added to the scene tree again. [method _ready] is called only for the node which requested it, which means that you need to request ready for each child if you want them to call [method _ready] too (in which case, [method _ready] will be called in the same order as it would normally). + Requests [method _ready] to be called again the next time the node enters the tree. Does [b]not[/b] immediately call [method _ready]. + [b]Note:[/b] This method only affects the current node. If the node's children also need to request ready, this method needs to be called for each one of them. When the node and its children enter the tree again, the order of [method _ready] callbacks will be the same as normal. - Sends a remote procedure call request for the given [param method] to peers on the network (and locally), optionally sending all additional arguments as arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same node name. Behavior depends on the RPC configuration for the given method, see [method rpc_config] and [annotation @GDScript.@rpc]. Methods are not exposed to RPCs by default. Returns [code]null[/code]. - [b]Note:[/b] You can only safely use RPCs on clients after you received the [code]connected_to_server[/code] signal from the [MultiplayerAPI]. You also need to keep track of the connection state, either by the [MultiplayerAPI] signals like [code]server_disconnected[/code] or by checking [code]get_multiplayer().peer.get_connection_status() == CONNECTION_CONNECTED[/code]. + Sends a remote procedure call request for the given [param method] to peers on the network (and locally), sending additional arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same [member name]. Behavior depends on the RPC configuration for the given [param method] (see [method rpc_config] and [annotation @GDScript.@rpc]). By default, methods are not exposed to RPCs. + May return [constant OK] if the call is successful, [constant ERR_INVALID_PARAMETER] if the arguments passed in the [param method] do not match, [constant ERR_UNCONFIGURED] if the node's [member multiplayer] cannot be fetched (such as when the node is not inside the tree), [constant ERR_CONNECTION_ERROR] if [member multiplayer]'s connection is not available. + [b]Note:[/b] You can only safely use RPCs on clients after you received the [signal MultiplayerAPI.connected_to_server] signal from the [MultiplayerAPI]. You also need to keep track of the connection state, either by the [MultiplayerAPI] signals like [signal MultiplayerAPI.server_disconnected] or by checking ([code]get_multiplayer().peer.get_connection_status() == CONNECTION_CONNECTED[/code]). @@ -742,16 +774,12 @@ - Changes the RPC mode for the given [param method] with the given [param config] which should be [code]null[/code] (to disable) or a [Dictionary] in the form: - [codeblock] - { - rpc_mode = MultiplayerAPI.RPCMode, - transfer_mode = MultiplayerPeer.TransferMode, - call_local = false, - channel = 0, - } - [/codeblock] - See [enum MultiplayerAPI.RPCMode] and [enum MultiplayerPeer.TransferMode]. An alternative is annotating methods and properties with the corresponding [annotation @GDScript.@rpc] annotation ([code]@rpc("any_peer")[/code], [code]@rpc("authority")[/code]). By default, methods are not exposed to networking (and RPCs). + Changes the RPC configuration for the given [param method]. [param config] should either be [code]null[/code] to disable the feature (as by default), or a [Dictionary] containing the following entries: + - [code]rpc_mode[/code]: see [enum MultiplayerAPI.RPCMode]; + - [code]transfer_mode[/code]: see [enum MultiplayerPeer.TransferMode]; + - [code]call_local[/code]: if [code]true[/code], the method will also be called locally; + - [code]channel[/code]: an [int] representing the channel to send the RPC on. + [b]Note:[/b] In GDScript, this method corresponds to the [annotation @GDScript.@rpc] annotation, with various parameters passed ([code]@rpc(any)[/code], [code]@rpc(authority)[/code]...). See also the [url=$DOCS_URL/tutorials/networking/high_level_multiplayer.html]high-level multiplayer[/url] tutorial. @@ -759,7 +787,8 @@ - Sends a [method rpc] to a specific peer identified by [param peer_id] (see [method MultiplayerPeer.set_target_peer]). Returns [code]null[/code]. + Sends a [method rpc] to a specific peer identified by [param peer_id] (see [method MultiplayerPeer.set_target_peer]). + May return [constant OK] if the call is successful, [constant ERR_INVALID_PARAMETER] if the arguments passed in the [param method] do not match, [constant ERR_UNCONFIGURED] if the node's [member multiplayer] cannot be fetched (such as when the node is not inside the tree), [constant ERR_CONNECTION_ERROR] if [member multiplayer]'s connection is not available. @@ -774,7 +803,7 @@ - Sets the folded state of the node in the Scene dock. This method is only intended for use with editor tooling. + If set to [code]true[/code], the node appears folded in the Scene dock. As a result, all of its children are hidden. This method is intended to be used in editor plugins and tools, but it also works in release builds. See also [method is_displayed_folded]. @@ -782,7 +811,7 @@ - Sets the editable children state of [param node] relative to this node. This method is only intended for use with editor tooling. + Set to [code]true[/code] to allow all nodes owned by [param node] to be available, and editable, in the Scene dock, even if their [member owner] is not the scene root. This method is intended to be used in editor plugins and tools, but it also works in release builds. See also [method is_editable_instance]. @@ -790,73 +819,74 @@ - Sets the node's multiplayer authority to the peer with the given peer ID. The multiplayer authority is the peer that has authority over the node on the network. Useful in conjunction with [method rpc_config] and the [MultiplayerAPI]. Defaults to peer ID 1 (the server). If [param recursive], the given peer is recursively set as the authority for all children of this node. - [b]Warning:[/b] This does [b]not[/b] automatically replicate the new authority to other peers. It is developer's responsibility to do so. You can propagate the information about the new authority using [member MultiplayerSpawner.spawn_function], an RPC, or using a [MultiplayerSynchronizer]. Also, the parent's authority does [b]not[/b] propagate to newly added children. + Sets the node's multiplayer authority to the peer with the given peer [param id]. The multiplayer authority is the peer that has authority over the node on the network. Defaults to peer ID 1 (the server). Useful in conjunction with [method rpc_config] and the [MultiplayerAPI]. + If [param recursive] is [code]true[/code], the given peer is recursively set as the authority for all children of this node. + [b]Warning:[/b] This does [b]not[/b] automatically replicate the new authority to other peers. It is the developer's responsibility to do so. You may replicate the new authority's information using [member MultiplayerSpawner.spawn_function], an RPC, or a [MultiplayerSynchronizer]. Furthermore, the parent's authority does [b]not[/b] propagate to newly added children. - Enables or disables physics (i.e. fixed framerate) processing. When a node is being processed, it will receive a [constant NOTIFICATION_PHYSICS_PROCESS] at a fixed (usually 60 FPS, see [member Engine.physics_ticks_per_second] to change) interval (and the [method _physics_process] callback will be called if exists). Enabled automatically if [method _physics_process] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables physics (fixed framerate) processing. When a node is being processed, it will receive a [constant NOTIFICATION_PHYSICS_PROCESS] at a fixed (usually 60 FPS, see [member Engine.physics_ticks_per_second] to change) interval (and the [method _physics_process] callback will be called if exists). Enabled automatically if [method _physics_process] is overridden. - Enables or disables internal physics for this node. Internal physics processing happens in isolation from the normal [method _physics_process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or physics processing is disabled for scripting ([method set_physics_process]). Only useful for advanced uses to manipulate built-in nodes' behavior. - [b]Warning:[/b] Built-in Nodes rely on the internal processing for their own logic, so changing this value from your code may lead to unexpected behavior. Script access to this internal logic is provided for specific advanced uses, but is unsafe and not supported. + If set to [code]true[/code], enables internal physics for this node. Internal physics processing happens in isolation from the normal [method _physics_process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or physics processing is disabled for scripting ([method set_physics_process]). + [b]Warning:[/b] Built-in nodes rely on internal processing for their internal logic. Disabling it is unsafe and may lead to unexpected behavior. Use this method if you know what you are doing. - Enables or disables processing. When a node is being processed, it will receive a [constant NOTIFICATION_PROCESS] on every drawn frame (and the [method _process] callback will be called if exists). Enabled automatically if [method _process] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables processing. When a node is being processed, it will receive a [constant NOTIFICATION_PROCESS] on every drawn frame (and the [method _process] callback will be called if exists). Enabled automatically if [method _process] is overridden. - Enables or disables input processing. This is not required for GUI controls! Enabled automatically if [method _input] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables input processing. This is not required for GUI controls! Enabled automatically if [method _input] is overridden. - Enables or disabled internal processing for this node. Internal processing happens in isolation from the normal [method _process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or processing is disabled for scripting ([method set_process]). Only useful for advanced uses to manipulate built-in nodes' behavior. - [b]Warning:[/b] Built-in Nodes rely on the internal processing for their own logic, so changing this value from your code may lead to unexpected behavior. Script access to this internal logic is provided for specific advanced uses, but is unsafe and not supported. + If set to [code]true[/code], enables internal processing for this node. Internal processing happens in isolation from the normal [method _process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or processing is disabled for scripting ([method set_process]). + [b]Warning:[/b] Built-in nodes rely on internal processing for their internal logic. Disabling it is unsafe and may lead to unexpected behavior. Use this method if you know what you are doing. - Enables shortcut processing. Enabled automatically if [method _shortcut_input] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables shortcut processing for this node. Enabled automatically if [method _shortcut_input] is overridden. - Enables unhandled input processing. This is not required for GUI controls! It enables the node to receive all input that was not previously handled (usually by a [Control]). Enabled automatically if [method _unhandled_input] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables unhandled input processing. This is not required for GUI controls! It enables the node to receive all input that was not previously handled (usually by a [Control]). Enabled automatically if [method _unhandled_input] is overridden. - Enables unhandled key input processing. Enabled automatically if [method _unhandled_key_input] is overridden. Any calls to this before [method _ready] will be ignored. + If set to [code]true[/code], enables unhandled key input processing. Enabled automatically if [method _unhandled_key_input] is overridden. - Sets whether this is an instance load placeholder. See [InstancePlaceholder]. + If set to [code]true[/code], the node becomes a [InstancePlaceholder] when packed and instantiated from a [PackedScene]. See also [method get_scene_instance_load_placeholder]. @@ -870,35 +900,34 @@ - Updates the warning displayed for this node in the Scene Dock. - Use [method _get_configuration_warnings] to setup the warning message to display. + Refreshes the warnings displayed for this node in the Scene dock. Use [method _get_configuration_warnings] to customize the warning messages to display. - Add a custom description to a node. It will be displayed in a tooltip when hovered in editor's scene tree. + An optional description to the node. It will be displayed as a tooltip when hovering over the node in the editor's Scene dock. The [MultiplayerAPI] instance associated with this node. See [method SceneTree.get_multiplayer]. [b]Note:[/b] Renaming the node, or moving it in the tree, will not move the [MultiplayerAPI] to the new path, you will have to update this manually. - The name of the node. This name is unique among the siblings (other child nodes from the same parent). When set to an existing name, the node will be automatically renamed. - [b]Note:[/b] Auto-generated names might include the [code]@[/code] character, which is reserved for unique names when using [method add_child]. When setting the name manually, any [code]@[/code] will be removed. + The name of the node. This name must be unique among the siblings (other child nodes from the same parent). When set to an existing sibling's name, the node is automatically renamed. + [b]Note:[/b] When changing the name, the following characters will be removed: ([code].[/code] [code]:[/code] [code]@[/code] [code]/[/code] [code]"[/code] [code]%[/code]). In particular, the [code]@[/code] character is reserved for auto-generated names. See also [method String.validate_node_name]. - The node owner. A node can have any ancestor node as owner (i.e. a parent, grandparent, etc. node ascending in the tree). This implies that [method add_child] should be called before setting the owner, so that this relationship of parenting exists. When saving a node (using [PackedScene]), all the nodes it owns will be saved with it. This allows for the creation of complex scene trees, with instancing and subinstancing. - [b]Note:[/b] If you want a child to be persisted to a [PackedScene], you must set [member owner] in addition to calling [method add_child]. This is typically relevant for [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]tool scripts[/url] and [url=$DOCS_URL/tutorials/plugins/editor/index.html]editor plugins[/url]. If a new node is added to the tree without setting its owner as an ancestor in that tree, it will be visible in the 2D/3D view, but not in the scene tree (and not persisted when packing or saving). + The owner of this node. The owner must be an ancestor of this node. When packing the owner node in a [PackedScene], all the nodes it owns are also saved with it. + [b]Note:[/b] In the editor, nodes not owned by the scene root are usually not displayed in the Scene dock, and will [b]not[/b] be saved. To prevent this, remember to set the owner after calling [method add_child]. See also (see [member unique_name_in_owner]) - Can be used to pause or unpause the node, or make the node paused based on the [SceneTree], or make it inherit the process mode from its parent (default). + The node's processing behavior (see [enum ProcessMode]). To check if the node is able to process, with the current mode and [member SceneTree.paused], use [method can_process]. Similar to [member process_priority] but for [constant NOTIFICATION_PHYSICS_PROCESS], [method _physics_process] or the internal version. - The node's priority in the execution order of the enabled processing callbacks (i.e. [constant NOTIFICATION_PROCESS], [constant NOTIFICATION_PHYSICS_PROCESS] and their internal counterparts). Nodes whose process priority value is [i]lower[/i] will have their processing callbacks executed first. + The node's execution order of the process callbacks ([method _process], [method _physics_process], and internal processing). Nodes whose priority value is [i]lower[/i] call their process callbacks first, regardless of tree order. Set the process thread group for this node (basically, whether it receives [constant NOTIFICATION_PROCESS], [constant NOTIFICATION_PHYSICS_PROCESS], [method _process] or [method _physics_process] (and the internal versions) on the main thread or in a sub-thread. @@ -913,26 +942,26 @@ Set whether the current thread group will process messages (calls to [method call_deferred_thread_group] on threads, and whether it wants to receive them during regular process or physics process callbacks. - If a scene is instantiated from a file, its topmost node contains the absolute file path from which it was loaded in [member scene_file_path] (e.g. [code]res://levels/1.tscn[/code]). Otherwise, [member scene_file_path] is set to an empty string. + The original scene's file path, if the node has been instantiated from a [PackedScene] file. Only scene root nodes contains this. - Sets this node's name as a unique name in its [member owner]. This allows the node to be accessed as [code]%Name[/code] instead of the full path, from any node within that scene. - If another node with the same owner already had that name declared as unique, that other node's name will no longer be set as having a unique name. + If [code]true[/code], the node can be accessed from any node sharing the same [member owner] or from the [member owner] itself, with special [code]%Name[/code] syntax in [method get_node]. + [b]Note:[/b] If another node with the same [member owner] shares the same [member name] as this node, the other node will no longer be accessible as unique. - Emitted when a child node enters the scene tree, either because it entered on its own or because this node entered with it. + Emitted when the child [param node] enters the [SceneTree], usually because this node entered the tree (see [signal tree_entered]), or [method add_child] has been called. This signal is emitted [i]after[/i] the child node's own [constant NOTIFICATION_ENTER_TREE] and [signal tree_entered]. - Emitted when a child node is about to exit the scene tree, either because it is being removed or freed directly, or because this node is exiting the tree. - When this signal is received, the child [param node] is still in the tree and valid. This signal is emitted [i]after[/i] the child node's own [signal tree_exiting] and [constant NOTIFICATION_EXIT_TREE]. + Emitted when the child [param node] is about to exit the [SceneTree], usually because this node is exiting the tree (see [signal tree_exiting]), or because the child [param node] is being removed or freed. + When this signal is received, the child [param node] is still accessible inside the tree. This signal is emitted [i]after[/i] the child node's own [signal tree_exiting] and [constant NOTIFICATION_EXIT_TREE]. @@ -942,12 +971,12 @@ - Emitted when the node is ready. Comes after [method _ready] callback and follows the same rules. + Emitted when the node is considered ready, after [method _ready] is called. - Emitted when the node is renamed. + Emitted when the node's [member name] is changed, if the node is inside the tree. @@ -966,23 +995,24 @@ Emitted after the node exits the tree and is no longer active. + This signal is emitted [i]after[/i] the related [constant NOTIFICATION_EXIT_TREE] notification. - Emitted when the node is still active but about to exit the tree. This is the right place for de-initialization (or a "destructor", if you will). - This signal is emitted [i]before[/i] the related [constant NOTIFICATION_EXIT_TREE] notification. + Emitted when the node is just about to exit the tree. The node is still valid. As such, this is the right place for de-initialization (or a "destructor", if you will). + This signal is emitted [i]after[/i] the node's [method _exit_tree], and [i]before[/i] the related [constant NOTIFICATION_EXIT_TREE]. - Notification received when the node enters a [SceneTree]. - This notification is emitted [i]before[/i] the related [signal tree_entered]. + Notification received when the node enters a [SceneTree]. See [method _enter_tree]. + This notification is received [i]before[/i] the related [signal tree_entered] signal. - Notification received when the node is about to exit a [SceneTree]. - This notification is emitted [i]after[/i] the related [signal tree_exiting]. + Notification received when the node is about to exit a [SceneTree]. See [method _exit_tree]. + This notification is received [i]after[/i] the related [signal tree_exiting] signal. [i]Deprecated.[/i] This notification is no longer emitted. Use [constant NOTIFICATION_CHILD_ORDER_CHANGED] instead. @@ -991,26 +1021,27 @@ Notification received when the node is ready. See [method _ready]. - Notification received when the node is paused. + Notification received when the node is paused. See [member process_mode]. - Notification received when the node is unpaused. + Notification received when the node is unpaused. See [member process_mode]. - Notification received every frame when the physics process flag is set (see [method set_physics_process]). + Notification received from the tree every physics frame when [method is_physics_processing] returns [code]true[/code]. See [method _physics_process]. - Notification received every frame when the process flag is set (see [method set_process]). + Notification received from the tree every rendered frame when [method is_processing] returns [code]true[/code]. See [method _process]. - Notification received when a node is set as a child of another node. - [b]Note:[/b] This doesn't mean that a node entered the [SceneTree]. + Notification received when the node is set as a child of another node (see [method add_child] and [method add_sibling]). + [b]Note:[/b] This does [i]not[/i] mean that the node entered the [SceneTree]. - Notification received when a node is unparented (parent removed it from the list of children). + Notification received when the parent node calls [method remove_child] on this node. + [b]Note:[/b] This does [i]not[/i] mean that the node exited the [SceneTree]. - Notification received by scene owner when its scene is instantiated. + Notification received [i]only[/i] by the newly instantiated scene root node, when [method PackedScene.instantiate] is completed. Notification received when a drag operation begins. All nodes receive this notification, not only the dragged one. @@ -1022,19 +1053,19 @@ Use [method Viewport.gui_is_drag_successful] to check if the drag succeeded. - Notification received when the node's name or one of its parents' name is changed. This notification is [i]not[/i] received when the node is removed from the scene tree to be added to another parent later on. + Notification received when the node's [member name] or one of its ancestors' [member name] is changed. This notification is [i]not[/i] received when the node is removed from the [SceneTree]. Notification received when the list of children is changed. This happens when child nodes are added, moved or removed. - Notification received every frame when the internal process flag is set (see [method set_process_internal]). + Notification received from the tree every rendered frame when [method is_processing_internal] returns [code]true[/code]. - Notification received every frame when the internal physics process flag is set (see [method set_physics_process_internal]). + Notification received from the tree every physics frame when [method is_physics_processing_internal] returns [code]true[/code]. - Notification received when the node is ready, just before [constant NOTIFICATION_READY] is received. Unlike the latter, it's sent every time the node enters the tree, instead of only once. + Notification received when the node enters the tree, just before [constant NOTIFICATION_READY] may be received. Unlike the latter, it is sent every time the node enters tree, not just once. Notification received when the node is disabled. See [constant PROCESS_MODE_DISABLED]. @@ -1057,11 +1088,11 @@ Implemented for embedded windows and on desktop and web platforms. - Notification received when the node's parent [Window] is focused. This may be a change of focus between two windows of the same engine instance, or from the OS desktop or a third-party application to a window of the game (in which case [constant NOTIFICATION_APPLICATION_FOCUS_IN] is also emitted). + Notification received from the OS when the node's [Window] ancestor is focused. This may be a change of focus between two windows of the same engine instance, or from the OS desktop or a third-party application to a window of the game (in which case [constant NOTIFICATION_APPLICATION_FOCUS_IN] is also received). A [Window] node receives this notification when it is focused. - Notification received when the node's parent [Window] is defocused. This may be a change of focus between two windows of the same engine instance, or from a window of the game to the OS desktop or a third-party application (in which case [constant NOTIFICATION_APPLICATION_FOCUS_OUT] is also emitted). + Notification received from the OS when the node's [Window] ancestor is defocused. This may be a change of focus between two windows of the same engine instance, or from a window of the game to the OS desktop or a third-party application (in which case [constant NOTIFICATION_APPLICATION_FOCUS_OUT] is also received). A [Window] node receives this notification when it is defocused. @@ -1070,14 +1101,14 @@ Notification received from the OS when a go back request is sent (e.g. pressing the "Back" button on Android). - Specific to the Android platform. + Implemented only on iOS. Notification received when the window is resized. [b]Note:[/b] Only the resized [Window] node receives this notification, and it's not propagated to the child nodes. - Notification received from the OS when the screen's DPI has been changed. Only implemented on macOS. + Notification received from the OS when the screen's dots per inch (DPI) scale is changed. Only implemented on macOS. Notification received when the mouse cursor enters the [Viewport]'s visible area, that is not occluded behind other [Control]s or [Window]s, provided its [member Viewport.gui_disable_input] is [code]false[/code] and regardless if it's currently focused or not. @@ -1087,56 +1118,56 @@ Notification received from the OS when the application is exceeding its allocated memory. - Specific to the iOS platform. + Implemented only on iOS. Notification received when translations may have changed. Can be triggered by the user changing the locale. Can be used to respond to language changes, for example to change the UI strings on the fly. Useful when working with the built-in translation support, like [method Object.tr]. Notification received from the OS when a request for "About" information is sent. - Specific to the macOS platform. + Implemented only on macOS. Notification received from Godot's crash handler when the engine is about to crash. - Implemented on desktop platforms if the crash handler is enabled. + Implemented on desktop platforms, if the crash handler is enabled. Notification received from the OS when an update of the Input Method Engine occurs (e.g. change of IME cursor position or composition string). - Specific to the macOS platform. + Implemented only on macOS. Notification received from the OS when the application is resumed. - Specific to the Android platform. + Implemented only on Android. Notification received from the OS when the application is paused. - Specific to the Android platform. + Implemented only on Android. - Notification received from the OS when the application is focused, i.e. when changing the focus from the OS desktop or a thirdparty application to any open window of the Godot instance. + Notification received from the OS when the application is focused, i.e. when changing the focus from the OS desktop or a third-party application to any open window of the Godot instance. Implemented on desktop platforms. - Notification received from the OS when the application is defocused, i.e. when changing the focus from any open window of the Godot instance to the OS desktop or a thirdparty application. + Notification received from the OS when the application is defocused, i.e. when changing the focus from any open window of the Godot instance to the OS desktop or a third-party application. Implemented on desktop platforms. - Notification received when text server is changed. + Notification received when the [TextServer] is changed. - Inherits process mode from the node's parent. For the root node, it is equivalent to [constant PROCESS_MODE_PAUSABLE]. Default. + Inherits [member process_mode] from the node's parent. For the root node, it is equivalent to [constant PROCESS_MODE_PAUSABLE]. This is the default for any newly created node. - Stops processing when the [SceneTree] is paused (process when unpaused). This is the inverse of [constant PROCESS_MODE_WHEN_PAUSED]. + Stops processing when [member SceneTree.paused] is [code]true[/code]. This is the inverse of [constant PROCESS_MODE_WHEN_PAUSED]. - Only process when the [SceneTree] is paused (don't process when unpaused). This is the inverse of [constant PROCESS_MODE_PAUSABLE]. + Process [b]only[/b] when [member SceneTree.paused] is [code]true[/code]. This is the inverse of [constant PROCESS_MODE_PAUSABLE]. - Always process. Continue processing always, ignoring the [SceneTree]'s paused property. This is the inverse of [constant PROCESS_MODE_DISABLED]. + Always process. Keeps processing, ignoring [member SceneTree.paused]. This is the inverse of [constant PROCESS_MODE_DISABLED]. - Never process. Completely disables processing, ignoring the [SceneTree]'s paused property. This is the inverse of [constant PROCESS_MODE_ALWAYS]. + Never process. Completely disables processing, ignoring [member SceneTree.paused]. This is the inverse of [constant PROCESS_MODE_ALWAYS]. If the [member process_thread_group] property is sent to this, the node will belong to any parent (or grandparent) node that has a thread group mode that is not inherit. See [member process_thread_group] for more information. @@ -1154,26 +1185,25 @@ - Duplicate the node's signals. + Duplicate the node's signal connections. Duplicate the node's groups. - Duplicate the node's scripts. + Duplicate the node's script (including the ancestor's script, if combined with [constant DUPLICATE_USE_INSTANTIATION]). - Duplicate using instancing. - An instance stays linked to the original so when the original changes, the instance changes too. + Duplicate using [method PackedScene.instantiate]. If the node comes from a scene saved on disk, re-uses [method PackedScene.instantiate] as the base for the duplicated node and its children. - Node will not be internal. + The node will not be internal. - Node will be placed at the front of parent's node list, before any non-internal sibling. + The node will be placed at the beginning of the parent's children list, before any non-internal sibling. - Node will be placed at the back of parent's node list, after any non-internal sibling. + The node will be placed at the end of the parent's children list, after any non-internal sibling. From e19f2c6b76421acae10b8f618af453f887cfcf35 Mon Sep 17 00:00:00 2001 From: Steven Schoen Date: Tue, 19 Dec 2023 21:22:39 -0500 Subject: [PATCH 33/95] Clarify Node doc: get_child returns null for invalid index (cherry picked from commit 3c416f3a643cf9df01b7076a052e2dd9d5f29717) --- doc/classes/Node.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index c61ae3f8881a..d660b94ef9d2 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -267,7 +267,7 @@ - Fetches a child node by its index. Each child node has an index relative its siblings (see [method get_index]). The first child is at index 0. Negative values can also be used to start from the end of the list. This method can be used in combination with [method get_child_count] to iterate over this node's children. + Fetches a child node by its index. Each child node has an index relative its siblings (see [method get_index]). The first child is at index 0. Negative values can also be used to start from the end of the list. This method can be used in combination with [method get_child_count] to iterate over this node's children. If no child exists at the given index, this method returns [code]null[/code] and an error is generated. If [param include_internal] is [code]false[/code], internal children are ignored (see [method add_child]'s [code]internal[/code] parameter). [codeblock] # Assuming the following are children of this node, in order: From 4f60f850f79e44daa7edcdba80549d569071157a Mon Sep 17 00:00:00 2001 From: Micky Date: Fri, 5 Jan 2024 21:55:59 +0100 Subject: [PATCH 34/95] Specify how CanvasTexture does not work in 3D (cherry picked from commit 52d062560b11bf3e3ddda5d5f2d24ec9b9b9cfdd) --- doc/classes/CanvasTexture.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/classes/CanvasTexture.xml b/doc/classes/CanvasTexture.xml index 1b22adb7234f..a14f71cc46b1 100644 --- a/doc/classes/CanvasTexture.xml +++ b/doc/classes/CanvasTexture.xml @@ -5,7 +5,7 @@ [CanvasTexture] is an alternative to [ImageTexture] for 2D rendering. It allows using normal maps and specular maps in any node that inherits from [CanvasItem]. [CanvasTexture] also allows overriding the texture's filter and repeat mode independently of the node's properties (or the project settings). - [b]Note:[/b] [CanvasTexture] cannot be used in 3D rendering. For physically-based materials in 3D, use [BaseMaterial3D] instead. + [b]Note:[/b] [CanvasTexture] cannot be used in 3D. It will not display correctly when applied to any [VisualInstance3D], such as [Sprite3D] or [Decal]. For physically-based materials in 3D, use [BaseMaterial3D] instead. $DOCS_URL/tutorials/2d/2d_lights_and_shadows.html From b0318cfb3d4cb4cc84f10c8da6952de678e9eba0 Mon Sep 17 00:00:00 2001 From: Micky Date: Thu, 11 Jan 2024 20:29:35 +0100 Subject: [PATCH 35/95] Overhaul AABB's documentation (cherry picked from commit 8467245526e3bb4ebfcadb2ada56c3e313f5df6b) --- doc/classes/AABB.xml | 217 +++++++++++++++++++++++++++++++++---------- 1 file changed, 170 insertions(+), 47 deletions(-) diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml index c1c637d2d66c..427d38d421d6 100644 --- a/doc/classes/AABB.xml +++ b/doc/classes/AABB.xml @@ -4,10 +4,10 @@ A 3D axis-aligned bounding box. - [AABB] consists of a position, a size, and several utility functions. It is typically used for fast overlap tests. - It uses floating-point coordinates. The 2D counterpart to [AABB] is [Rect2]. - Negative values for [member size] are not supported and will not work for most methods. Use [method abs] to get an AABB with a positive size. - [b]Note:[/b] Unlike [Rect2], [AABB] does not have a variant that uses integer coordinates. + The [AABB] built-in [Variant] type represents an axis-aligned bounding box in a 3D space. It is defined by its [member position] and [member size], which are [Vector3]. It is frequently used for fast overlap tests (see [method intersects]). Although [AABB] itself is axis-aligned, it can be combined with [Transform3D] to represent a rotated or skewed bounding box. + It uses floating-point coordinates. The 2D counterpart to [AABB] is [Rect2]. There is no version of [AABB] that uses integer coordinates. + [b]Note:[/b] Negative values for [member size] are not supported. With negative size, most [AABB] methods do not work correctly. Use [method abs] to get an equivalent [AABB] with a non-negative size. + [b]Note:[/b] In a boolean context, a [AABB] evaluates to [code]false[/code] if both [member position] and [member size] are zero (equal to [constant Vector3.ZERO]). Otherwise, it always evaluates to [code]true[/code]. $DOCS_URL/tutorials/math/index.html @@ -18,7 +18,7 @@ - Constructs a default-initialized [AABB] with default (zero) values of [member position] and [member size]. + Constructs an [AABB] with its [member position] and [member size] set to [constant Vector3.ZERO]. @@ -33,7 +33,7 @@ - Constructs an [AABB] from a position and size. + Constructs an [AABB] by [param position] and [param size]. @@ -41,34 +41,78 @@ - Returns an AABB with equivalent position and size, modified so that the most-negative corner is the origin and the size is positive. + Returns an [AABB] equivalent to this bounding box, with its width, height, and depth modified to be non-negative values. + [codeblocks] + [gdscript] + var box = AABB(Vector3(5, 0, 5), Vector3(-20, -10, -5)) + var absolute = box.abs() + print(absolute.position) # Prints (-15, -10, 0) + print(absolute.size) # Prints (20, 10, 5) + [/gdscript] + [csharp] + var box = new Aabb(new Vector3(5, 0, 5), new Vector3(-20, -10, -5)); + var absolute = box.Abs(); + GD.Print(absolute.Position); // Prints (-15, -10, 0) + GD.Print(absolute.Size); // Prints (20, 10, 5) + [/csharp] + [/codeblocks] + [b]Note:[/b] It's recommended to use this method when [member size] is negative, as most other methods in Godot assume that the [member size]'s components are greater than [code]0[/code]. - Returns [code]true[/code] if this [AABB] completely encloses another one. + Returns [code]true[/code] if this bounding box [i]completely[/i] encloses the [param with] box. The edges of both boxes are included. + [codeblocks] + [gdscript] + var a = AABB(Vector3(0, 0, 0), Vector3(4, 4, 4)) + var b = AABB(Vector3(1, 1, 1), Vector3(3, 3, 3)) + var c = AABB(Vector3(2, 2, 2), Vector3(8, 8, 8)) + + print(a.encloses(a)) # Prints true + print(a.encloses(b)) # Prints true + print(a.encloses(c)) # Prints false + [/gdscript] + [csharp] + var a = new Aabb(new Vector3(0, 0, 0), new Vector3(4, 4, 4)); + var b = new Aabb(new Vector3(1, 1, 1), new Vector3(3, 3, 3)); + var c = new Aabb(new Vector3(2, 2, 2), new Vector3(8, 8, 8)); + + GD.Print(a.Encloses(a)); // Prints True + GD.Print(a.Encloses(b)); // Prints True + GD.Print(a.Encloses(c)); // Prints False + [/csharp] + [/codeblocks] - Returns a copy of this [AABB] expanded to include a given point. - [b]Example:[/b] + Returns a copy of this bounding box expanded to align the edges with the given [param to_point], if necessary. [codeblocks] [gdscript] - # position (-3, 2, 0), size (1, 1, 1) - var box = AABB(Vector3(-3, 2, 0), Vector3(1, 1, 1)) - # position (-3, -1, 0), size (3, 4, 2), so we fit both the original AABB and Vector3(0, -1, 2) - var box2 = box.expand(Vector3(0, -1, 2)) + var box = AABB(Vector3(0, 0, 0), Vector3(5, 2, 5)) + + box = box.expand(Vector3(10, 0, 0)) + print(box.position) # Prints (0, 0, 0) + print(box.size) # Prints (10, 2, 5) + + box = box.expand(Vector3(-5, 0, 5)) + print(box.position) # Prints (-5, 0, 0) + print(box.size) # Prints (15, 2, 5) [/gdscript] [csharp] - // position (-3, 2, 0), size (1, 1, 1) - var box = new Aabb(new Vector3(-3, 2, 0), new Vector3(1, 1, 1)); - // position (-3, -1, 0), size (3, 4, 2), so we fit both the original AABB and Vector3(0, -1, 2) - var box2 = box.Expand(new Vector3(0, -1, 2)); + var box = new Aabb(new Vector3(0, 0, 0), new Vector3(5, 2, 5)); + + box = box.Expand(new Vector3(10, 0, 0)); + GD.Print(box.Position); // Prints (0, 0, 0) + GD.Print(box.Size); // Prints (10, 2, 5) + + box = box.Expand(new Vector3(-5, 0, 5)); + GD.Print(box.Position); // Prints (-5, 0, 0) + GD.Print(box.Size); // Prints (15, 2, 5) [/csharp] [/codeblocks] @@ -76,111 +120,188 @@ - Returns the center of the [AABB], which is equal to [member position] + ([member size] / 2). + Returns the center point of the bounding box. This is the same as [code]position + (size / 2.0)[/code]. - Gets the position of the 8 endpoints of the [AABB] in space. + Returns the position of one of the 8 vertices that compose this bounding box. With a [param idx] of [code]0[/code] this is the same as [member position], and a [param idx] of [code]7[/code] is the same as [member end]. - Returns the normalized longest axis of the [AABB]. + Returns the longest normalized axis of this bounding box's [member size], as a [Vector3] ([constant Vector3.RIGHT], [constant Vector3.UP], or [constant Vector3.BACK]). + [codeblocks] + [gdscript] + var box = AABB(Vector3(0, 0, 0), Vector3(2, 4, 8)) + + print(box.get_longest_axis()) # Prints (0, 0, 1) + print(box.get_longest_axis_index()) # Prints 2 + print(box.get_longest_axis_size()) # Prints 8 + [/gdscript] + [csharp] + var box = new Aabb(new Vector3(0, 0, 0), new Vector3(2, 4, 8)); + + GD.Print(box.GetLongestAxis()); // Prints (0, 0, 1) + GD.Print(box.GetLongestAxisIndex()); // Prints 2 + GD.Print(box.GetLongestAxisSize()); // Prints 8 + [/csharp] + [/codeblocks] + See also [method get_longest_axis_index] and [method get_longest_axis_size]. - Returns the index of the longest axis of the [AABB] (according to [Vector3]'s [code]AXIS_*[/code] constants). + Returns the index to the longest axis of this bounding box's [member size] (see [constant Vector3.AXIS_X], [constant Vector3.AXIS_Y], and [constant Vector3.AXIS_Z]). + For an example, see [method get_longest_axis]. - Returns the scalar length of the longest axis of the [AABB]. + Returns the longest dimension of this bounding box's [member size]. + For an example, see [method get_longest_axis]. - Returns the normalized shortest axis of the [AABB]. + Returns the shortest normaalized axis of this bounding box's [member size], as a [Vector3] ([constant Vector3.RIGHT], [constant Vector3.UP], or [constant Vector3.BACK]). + [codeblocks] + [gdscript] + var box = AABB(Vector3(0, 0, 0), Vector3(2, 4, 8)) + + print(box.get_shortest_axis()) # Prints (1, 0, 0) + print(box.get_shortest_axis_index()) # Prints 0 + print(box.get_shortest_axis_size()) # Prints 2 + [/gdscript] + [csharp] + var box = new Aabb(new Vector3(0, 0, 0), new Vector3(2, 4, 8)); + + GD.Print(box.GetShortestAxis()); // Prints (1, 0, 0) + GD.Print(box.GetShortestAxisIndex()); // Prints 0 + GD.Print(box.GetShortestAxisSize()); // Prints 2 + [/csharp] + [/codeblocks] + See also [method get_shortest_axis_index] and [method get_shortest_axis_size]. - Returns the index of the shortest axis of the [AABB] (according to [Vector3]::AXIS* enum). + Returns the index to the shortest axis of this bounding box's [member size] (see [constant Vector3.AXIS_X], [constant Vector3.AXIS_Y], and [constant Vector3.AXIS_Z]). + For an example, see [method get_shortest_axis]. - Returns the scalar length of the shortest axis of the [AABB]. + Returns the shortest dimension of this bounding box's [member size]. + For an example, see [method get_shortest_axis]. - Returns the vertex of the AABB that's the farthest in a given direction. This point is commonly known as the support point in collision detection algorithms. + Returns the vertex's position of this bounding box that's the farthest in the given direction. This point is commonly known as the support point in collision detection algorithms. - Returns the volume of the [AABB]. + Returns the bounding box's volume. This is equivalent to [code]size.x * size.y * size.z[/code]. See also [method has_volume]. - Returns a copy of the [AABB] grown a given number of units towards all the sides. + Returns a copy of this bounding box extended on all sides by the given amount [param by]. A negative amount shrinks the box instead. + [codeblocks] + [gdscript] + var a = AABB(Vector3(4, 4, 4), Vector3(8, 8, 8)).grow(4) + print(a.position) # Prints (0, 0, 0) + print(a.size) # Prints (16, 16, 16) + + var b = AABB(Vector3(0, 0, 0), Vector3(8, 4, 2)).grow(2) + print(b.position) # Prints (-2, -2, -2) + print(b.size) # Prints (12, 8, 6) + [/gdscript] + [csharp] + var a = new Aabb(new Vector3(4, 4, 4), new Vector3(8, 8, 8)).Grow(4); + GD.Print(a.Position); // Prints (0, 0, 0) + GD.Print(a.Size); // Prints (16, 16, 16) + + var b = new Aabb(new Vector3(0, 0, 0), new Vector3(8, 4, 2)).Grow(2); + GD.Print(b.Position); // Prints (-2, -2, -2) + GD.Print(b.Size); // Prints (12, 8, 6) + [/csharp] + [/codeblocks] - Returns [code]true[/code] if the [AABB] contains a point. Points on the faces of the AABB are considered included, though float-point precision errors may impact the accuracy of such checks. - [b]Note:[/b] This method is not reliable for [AABB] with a [i]negative size[/i]. Use [method abs] to get a positive sized equivalent [AABB] to check for contained points. + Returns [code]true[/code] if the bounding box contains the given [param point]. By convention, points exactly on the right, top, and front sides are [b]not[/b] included. + [b]Note:[/b] This method is not reliable for [AABB] with a [i]negative[/i] [member size]. Use [method abs] first to get a valid bounding box. - Returns [code]true[/code] if the [AABB] has a surface or a length, and [code]false[/code] if the [AABB] is empty (all components of [member size] are zero or negative). + Returns [code]true[/code] if this bounding box has a surface or a length, that is, at least one component of [member size] is greater than [code]0[/code]. Otherwise, returns [code]false[/code]. - Returns [code]true[/code] if the [AABB] has a volume, and [code]false[/code] if the [AABB] is flat, empty, or has a negative [member size]. + Returns [code]true[/code] if this bounding box's width, height, and depth are all positive. See also [method get_volume]. - Returns the intersection between two [AABB]. An empty AABB (size [code](0, 0, 0)[/code]) is returned on failure. + Returns the intersection between this bounding box and [param with]. If the boxes do not intersect, returns an empty [AABB]. If the boxes intersect at the edge, returns a flat [AABB] with no volume (see [method has_surface] and [method has_volume]). + [codeblocks] + [gdscript] + var box1 = AABB(Vector3(0, 0, 0), Vector3(5, 2, 8)) + var box2 = AABB(Vector3(2, 0, 2), Vector3(8, 4, 4)) + + var intersection = box1.intersection(box2) + print(intersection.position) # Prints (2, 0, 2) + print(intersection.size) # Prints (3, 2, 4) + [/gdscript] + [csharp] + var box1 = new Aabb(new Vector3(0, 0, 0), new Vector3(5, 2, 8)); + var box2 = new Aabb(new Vector3(2, 0, 2), new Vector3(8, 4, 4)); + + var intersection = box1.Intersection(box2); + GD.Print(intersection.Position); // Prints (2, 0, 2) + GD.Print(intersection.Size); // Prints (3, 2, 4) + [/csharp] + [/codeblocks] + [b]Note:[/b] If you only need to know whether two bounding boxes are intersecting, use [method intersects], instead. - Returns [code]true[/code] if the [AABB] overlaps with another. + Returns [code]true[/code] if this bounding box overlaps with the box [param with]. The edges of both boxes are [i]always[/i] excluded. - Returns [code]true[/code] if the [AABB] is on both sides of a plane. + Returns [code]true[/code] if this bounding box is on both sides of the given [param plane]. @@ -188,7 +309,8 @@ - Returns the point of intersection of the given ray with this [AABB] or [code]null[/code] if there is no intersection. Ray length is infinite. + Returns the first point where this bounding box and the given ray intersect, as a [Vector3]. If no intersection occurs, returns [code]null[/code]. + The ray begin at [param from], faces [param dir] and extends towards infinity. @@ -196,40 +318,41 @@ - Returns the point of intersection between [param from] and [param to] with this [AABB] or [code]null[/code] if there is no intersection. + Returns the first point where this bounding box and the given segment intersect, as a [Vector3]. If no intersection occurs, returns [code]null[/code]. + The segment begins at [param from] and ends at [param to]. - Returns [code]true[/code] if this [AABB] and [param aabb] are approximately equal, by calling [method @GlobalScope.is_equal_approx] on each component. + Returns [code]true[/code] if this bounding box and [param aabb] are approximately equal, by calling [method Vector2.is_equal_approx] on the [member position] and the [member size]. - Returns [code]true[/code] if this [AABB] is finite, by calling [method @GlobalScope.is_finite] on each component. + Returns [code]true[/code] if this bounding box's values are finite, by calling [method Vector2.is_finite] on the [member position] and the [member size]. - Returns a larger [AABB] that contains both this [AABB] and [param with]. + Returns an [AABB] that encloses both this bounding box and [param with] around the edges. See also [method encloses]. - Ending corner. This is calculated as [code]position + size[/code]. Setting this value will change the size. + The ending point. This is usually the corner on the top-right and forward of the bounding box, and is equivalent to [code]position + size[/code]. Setting this point affects the [member size]. - Beginning corner. Typically has values lower than [member end]. + The origin point. This is usually the corner on the bottom-left and back of the bounding box. - Size from [member position] to [member end]. Typically, all components are positive. - If the size is negative, you can use [method abs] to fix it. + The bounding box's width, height, and depth starting from [member position]. Setting this value also affects the [member end] point. + [b]Note:[/b] It's recommended setting the width, height, and depth to non-negative values. This is because most methods in Godot assume that the [member position] is the bottom-left-back corner, and the [member end] is the top-right-forward corner. To get an equivalent bounding box with non-negative size, use [method abs]. @@ -237,7 +360,7 @@ - Returns [code]true[/code] if the AABBs are not equal. + Returns [code]true[/code] if the [member position] or [member size] of both bounding boxes are not equal. [b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable. @@ -254,7 +377,7 @@ - Returns [code]true[/code] if the AABBs are exactly equal. + Returns [code]true[/code] if both [member position] and [member size] of the bounding boxes are exactly equal, respectively. [b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable. From 58dd33e3d0c2f25b6c5015e55dd31588b5f32265 Mon Sep 17 00:00:00 2001 From: Alex Drozd Date: Tue, 19 Dec 2023 23:13:42 +0100 Subject: [PATCH 36/95] Add note that a large value for outline_size is not recommended (cherry picked from commit daa8942f41c76bdc159731ef03053de4be68ba72) --- doc/classes/Label.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml index f13f1bdcf409..20e9efd35885 100644 --- a/doc/classes/Label.xml +++ b/doc/classes/Label.xml @@ -117,6 +117,7 @@ Text outline size. [b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended. + [b]Note:[/b] Using a value that is larger than half the font size is not recommended, as the font outline may fail to be fully closed in this case. The horizontal offset of the text's shadow. From 7e33c6bf228bbf9a837020ccef65744d972cb2db Mon Sep 17 00:00:00 2001 From: jsjtxietian Date: Tue, 2 Jan 2024 11:31:38 +0800 Subject: [PATCH 37/95] Update get_image doc to mention that it will return an empty image with invalid texture (cherry picked from commit d73312d5e9756e77f13653013e1d00211cb555ae) --- doc/classes/Texture2D.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml index 087f3a70f8cb..7254a92e36d2 100644 --- a/doc/classes/Texture2D.xml +++ b/doc/classes/Texture2D.xml @@ -123,6 +123,7 @@ Returns an [Image] that is a copy of data from this [Texture2D] (a new [Image] is created each time). [Image]s can be accessed and manipulated directly. + [b]Note:[/b] This will return [code]null[/code] if this [Texture2D] is invalid. [b]Note:[/b] This will fetch the texture data from the GPU, which might cause performance problems when overused. From 06ccf2bbb5125ae078132fbdd8eb88e2a368577f Mon Sep 17 00:00:00 2001 From: MewPurPur Date: Thu, 9 Nov 2023 16:17:18 +0200 Subject: [PATCH 38/95] Add performance note to Array.resize() (cherry picked from commit 80b636069ae8a19e8e652c5f28cdb6d1e543cdb0) --- doc/classes/Array.xml | 1 + doc/classes/PackedByteArray.xml | 2 +- doc/classes/PackedColorArray.xml | 2 +- doc/classes/PackedFloat32Array.xml | 2 +- doc/classes/PackedFloat64Array.xml | 2 +- doc/classes/PackedInt32Array.xml | 2 +- doc/classes/PackedInt64Array.xml | 2 +- doc/classes/PackedStringArray.xml | 2 +- doc/classes/PackedVector2Array.xml | 2 +- doc/classes/PackedVector3Array.xml | 2 +- 10 files changed, 10 insertions(+), 9 deletions(-) diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index fccf16fcaa77..3252cbf840eb 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -544,6 +544,7 @@ Resizes the array to contain a different number of elements. If the array size is smaller, elements are cleared, if bigger, new elements are [code]null[/code]. Returns [constant OK] on success, or one of the other [enum Error] values if the operation failed. + Calling [method resize] once and assigning the new values is faster than adding new elements one by one. [b]Note:[/b] This method acts in-place and doesn't return a modified array. diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml index 97b9374e75ec..c5f522ba1056 100644 --- a/doc/classes/PackedByteArray.xml +++ b/doc/classes/PackedByteArray.xml @@ -399,7 +399,7 @@ - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml index 4908a861b3ee..ad96ba249039 100644 --- a/doc/classes/PackedColorArray.xml +++ b/doc/classes/PackedColorArray.xml @@ -131,7 +131,7 @@ - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. diff --git a/doc/classes/PackedFloat32Array.xml b/doc/classes/PackedFloat32Array.xml index 56f9633533f6..6f1ecacca453 100644 --- a/doc/classes/PackedFloat32Array.xml +++ b/doc/classes/PackedFloat32Array.xml @@ -132,7 +132,7 @@ - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. diff --git a/doc/classes/PackedFloat64Array.xml b/doc/classes/PackedFloat64Array.xml index b08bdafc8309..aef5ab90ac3b 100644 --- a/doc/classes/PackedFloat64Array.xml +++ b/doc/classes/PackedFloat64Array.xml @@ -132,7 +132,7 @@ - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. diff --git a/doc/classes/PackedInt32Array.xml b/doc/classes/PackedInt32Array.xml index c70cadc2fe73..e6396e2a938a 100644 --- a/doc/classes/PackedInt32Array.xml +++ b/doc/classes/PackedInt32Array.xml @@ -128,7 +128,7 @@ - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml index 339ab26a6811..55024341c19e 100644 --- a/doc/classes/PackedInt64Array.xml +++ b/doc/classes/PackedInt64Array.xml @@ -128,7 +128,7 @@ - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. diff --git a/doc/classes/PackedStringArray.xml b/doc/classes/PackedStringArray.xml index c2ae3cf3d3cb..f1b02272f3d0 100644 --- a/doc/classes/PackedStringArray.xml +++ b/doc/classes/PackedStringArray.xml @@ -134,7 +134,7 @@ - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml index 0e5bb12d0281..c73fea9114e7 100644 --- a/doc/classes/PackedVector2Array.xml +++ b/doc/classes/PackedVector2Array.xml @@ -136,7 +136,7 @@ - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml index ce7ae4f3965d..89f258eaea5d 100644 --- a/doc/classes/PackedVector3Array.xml +++ b/doc/classes/PackedVector3Array.xml @@ -135,7 +135,7 @@ - Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. + Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size. Calling [method resize] once and assigning the new values is faster than adding new elements one by one. From 93fd2f7768749cf949a1f7b024df21de182ad09c Mon Sep 17 00:00:00 2001 From: Micky Date: Mon, 15 Jan 2024 15:23:17 +0100 Subject: [PATCH 39/95] Replace some "uncommon" words in class reference (cherry picked from commit 61bdbdd9eeb7143e877fc9fe184b2d6428f4b0db) --- doc/classes/AnimationNodeStateMachine.xml | 2 +- doc/classes/Array.xml | 2 +- doc/classes/AudioEffectPitchShift.xml | 2 +- doc/classes/CanvasItem.xml | 2 +- doc/classes/DisplayServer.xml | 10 +++++----- doc/classes/Engine.xml | 2 +- doc/classes/GeometryInstance3D.xml | 2 +- doc/classes/MainLoop.xml | 2 +- doc/classes/NavigationServer2D.xml | 2 +- doc/classes/NavigationServer3D.xml | 2 +- doc/classes/ProceduralSkyMaterial.xml | 2 +- doc/classes/ProjectSettings.xml | 4 ++-- doc/classes/RandomNumberGenerator.xml | 2 +- doc/classes/ResourceImporterOBJ.xml | 2 +- doc/classes/ResourceImporterScene.xml | 2 +- doc/classes/SurfaceTool.xml | 2 +- doc/classes/SystemFont.xml | 2 +- doc/classes/TextEdit.xml | 2 +- doc/classes/Tween.xml | 2 +- 19 files changed, 24 insertions(+), 24 deletions(-) diff --git a/doc/classes/AnimationNodeStateMachine.xml b/doc/classes/AnimationNodeStateMachine.xml index 0a1a7df2f445..a9fa9c9cefa6 100644 --- a/doc/classes/AnimationNodeStateMachine.xml +++ b/doc/classes/AnimationNodeStateMachine.xml @@ -181,7 +181,7 @@ Seeking to the beginning is treated as seeking to the beginning of the animation in the current state. Transition to the end state, or the absence of transitions in each state, is treated as exiting the state machine. - This is a grouped state machine that can be controlled from a parent state machine. It does not work on standalone. There must be a state machine with [member state_machine_type] of [constant STATE_MACHINE_TYPE_ROOT] or [constant STATE_MACHINE_TYPE_NESTED] in the parent or ancestor. + This is a grouped state machine that can be controlled from a parent state machine. It does not work independently. There must be a state machine with [member state_machine_type] of [constant STATE_MACHINE_TYPE_ROOT] or [constant STATE_MACHINE_TYPE_NESTED] in the parent or ancestor. diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 3252cbf840eb..39b9dde04377 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -479,7 +479,7 @@ - Removes and returns the element of the array at index [param position]. If negative, [param position] is considered relative to the end of the array. Leaves the array untouched and returns [code]null[/code] if the array is empty or if it's accessed out of bounds. An error message is printed when the array is accessed out of bounds, but not when the array is empty. + Removes and returns the element of the array at index [param position]. If negative, [param position] is considered relative to the end of the array. Leaves the array unchanged and returns [code]null[/code] if the array is empty or if it's accessed out of bounds. An error message is printed when the array is accessed out of bounds, but not when the array is empty. [b]Note:[/b] On large arrays, this method can be slower than [method pop_back] as it will reindex the array's elements that are located after the removed element. The larger the array and the lower the index of the removed element, the slower [method pop_at] will be. diff --git a/doc/classes/AudioEffectPitchShift.xml b/doc/classes/AudioEffectPitchShift.xml index ec60e6a75a18..4d4baa34abdf 100644 --- a/doc/classes/AudioEffectPitchShift.xml +++ b/doc/classes/AudioEffectPitchShift.xml @@ -18,7 +18,7 @@ The oversampling factor to use. Higher values result in better quality, but are more demanding on the CPU and may cause audio cracking if the CPU can't keep up. - The pitch scale to use. [code]1.0[/code] is the default pitch and plays sounds unaltered. [member pitch_scale] can range from [code]0.0[/code] (infinitely low pitch, inaudible) to [code]16[/code] (16 times higher than the initial pitch). + The pitch scale to use. [code]1.0[/code] is the default pitch and plays sounds unaffected. [member pitch_scale] can range from [code]0.0[/code] (infinitely low pitch, inaudible) to [code]16[/code] (16 times higher than the initial pitch). diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 2f76f64cffba..6f4dc47fb942 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -501,7 +501,7 @@ - Returns [code]true[/code] if the node is present in the [SceneTree], its [member visible] property is [code]true[/code] and all its ancestors are also visible. If any ancestor is hidden, this node will not be visible in the scene tree, and is consequently not drawn (see [method _draw]). + Returns [code]true[/code] if the node is present in the [SceneTree], its [member visible] property is [code]true[/code] and all its ancestors are also visible. If any ancestor is hidden, this node will not be visible in the scene tree, and is therefore not drawn (see [method _draw]). diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 7f7dc1d288cd..57259e98eef1 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -1713,7 +1713,7 @@ The ID of the main window spawned by the engine, which can be passed to methods expecting a [code]window_id[/code]. - The ID that refers to a nonexisting window. This is be returned by some [DisplayServer] methods if no window matches the requested result. + The ID that refers to a nonexistent window. This is returned by some [DisplayServer] methods if no window matches the requested result. Default landscape orientation. @@ -1914,16 +1914,16 @@ [b]Note:[/b] This flag is implemented only on macOS. - No vertical synchronization, which means the engine will display frames as fast as possible (tearing may be visible). Framerate is unlimited (notwithstanding [member Engine.max_fps]). + No vertical synchronization, which means the engine will display frames as fast as possible (tearing may be visible). Framerate is unlimited (regardless of [member Engine.max_fps]). - Default vertical synchronization mode, the image is displayed only on vertical blanking intervals (no tearing is visible). Framerate is limited by the monitor refresh rate (notwithstanding [member Engine.max_fps]). + Default vertical synchronization mode, the image is displayed only on vertical blanking intervals (no tearing is visible). Framerate is limited by the monitor refresh rate (regardless of [member Engine.max_fps]). - Behaves like [constant VSYNC_DISABLED] when the framerate drops below the screen's refresh rate to reduce stuttering (tearing may be visible). Otherwise, vertical synchronization is enabled to avoid tearing. Framerate is limited by the monitor refresh rate (notwithstanding [member Engine.max_fps]). Behaves like [constant VSYNC_ENABLED] when using the Compatibility rendering method. + Behaves like [constant VSYNC_DISABLED] when the framerate drops below the screen's refresh rate to reduce stuttering (tearing may be visible). Otherwise, vertical synchronization is enabled to avoid tearing. Framerate is limited by the monitor refresh rate (regardless of [member Engine.max_fps]). Behaves like [constant VSYNC_ENABLED] when using the Compatibility rendering method. - Displays the most recent image in the queue on vertical blanking intervals, while rendering to the other images (no tearing is visible). Framerate is unlimited (notwithstanding [member Engine.max_fps]). + Displays the most recent image in the queue on vertical blanking intervals, while rendering to the other images (no tearing is visible). Framerate is unlimited (regardless of [member Engine.max_fps]). Although not guaranteed, the images can be rendered as fast as possible, which may reduce input lag (also called "Fast" V-Sync mode). [constant VSYNC_MAILBOX] works best when at least twice as many frames as the display refresh rate are rendered. Behaves like [constant VSYNC_ENABLED] when using the Compatibility rendering method. diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index 207cd0bccc73..98d433431a6b 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -293,7 +293,7 @@ Controls the maximum number of physics steps that can be simulated each rendered frame. The default value is tuned to avoid "spiral of death" situations where expensive physics simulations trigger more expensive simulations indefinitely. However, the game will appear to slow down if the rendering FPS is less than [code]1 / max_physics_steps_per_frame[/code] of [member physics_ticks_per_second]. This occurs even if [code]delta[/code] is consistently used in physics calculations. To avoid this, increase [member max_physics_steps_per_frame] if you have increased [member physics_ticks_per_second] significantly above its default value. - Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of the in-game clock and real clock but smooth out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended. + Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of the in-game clock and real clock but smooth out framerate jitters. The default value of 0.5 should be good enough for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended. [b]Note:[/b] For best results, when using a custom physics interpolation solution, the physics jitter fix should be disabled by setting [member physics_jitter_fix] to [code]0[/code]. diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml index 990efbb3a4cd..6b0d2e4a62be 100644 --- a/doc/classes/GeometryInstance3D.xml +++ b/doc/classes/GeometryInstance3D.xml @@ -34,7 +34,7 @@ The selected shadow casting flag. See [enum ShadowCastingSetting] for possible values. - Overrides the bounding box of this node with a custom one. This can be used to avoid the expensive [AABB] recalculation that happens when a skeleton is used with a [MeshInstance3D] or to have fine control over the [MeshInstance3D]'s bounding box. To use the default AABB, set value to an [AABB] with all fields set to [code]0.0[/code]. To avoid frustum culling, set [member custom_aabb] to a very large AABB that covers your entire game world such as [code]AABB(-10000, -10000, -10000, 20000, 20000, 20000)[/code]. To disable all forms of culling (including occlusion culling), call [method RenderingServer.instance_set_ignore_culling] on the [GeometryInstance3D]'s [RID]. + Overrides the bounding box of this node with a custom one. This can be used to avoid the expensive [AABB] recalculation that happens when a skeleton is used with a [MeshInstance3D] or to have precise control over the [MeshInstance3D]'s bounding box. To use the default AABB, set value to an [AABB] with all fields set to [code]0.0[/code]. To avoid frustum culling, set [member custom_aabb] to a very large AABB that covers your entire game world such as [code]AABB(-10000, -10000, -10000, 20000, 20000, 20000)[/code]. To disable all forms of culling (including occlusion culling), call [method RenderingServer.instance_set_ignore_culling] on the [GeometryInstance3D]'s [RID]. The extra distance added to the GeometryInstance3D's bounding box ([AABB]) to increase its cull box. diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml index 4c6c9d35241a..b01a3f7a0e69 100644 --- a/doc/classes/MainLoop.xml +++ b/doc/classes/MainLoop.xml @@ -5,7 +5,7 @@ [MainLoop] is the abstract base class for a Godot project's game loop. It is inherited by [SceneTree], which is the default game loop implementation used in Godot projects, though it is also possible to write and use one's own [MainLoop] subclass instead of the scene tree. - Upon the application start, a [MainLoop] implementation must be provided to the OS; otherwise, the application will exit. This happens automatically (and a [SceneTree] is created) unless a [MainLoop] [Script] is provided from the command line (with e.g. [code]godot -s my_loop.gd[/code] or the "Main Loop Type" project setting is overwritten. + Upon the application start, a [MainLoop] implementation must be provided to the OS; otherwise, the application will exit. This happens automatically (and a [SceneTree] is created) unless a [MainLoop] [Script] is provided from the command line (with e.g. [code]godot -s my_loop.gd[/code]) or the "Main Loop Type" project setting is overwritten. Here is an example script implementing a simple [MainLoop]: [codeblocks] [gdscript] diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml index a25f048df3f2..15e926a8aeee 100644 --- a/doc/classes/NavigationServer2D.xml +++ b/doc/classes/NavigationServer2D.xml @@ -372,7 +372,7 @@ This function immediately forces synchronization of the specified navigation [param map] [RID]. By default navigation maps are only synchronized at the end of each physics frame. This function can be used to immediately (re)calculate all the navigation meshes and region connections of the navigation map. This makes it possible to query a navigation path for a changed map immediately and in the same frame (multiple times if needed). Due to technical restrictions the current NavigationServer command queue will be flushed. This means all already queued update commands for this physics frame will be executed, even those intended for other maps, regions and agents not part of the specified map. The expensive computation of the navigation meshes and region connections of a map will only be done for the specified map. Other maps will receive the normal synchronization at the end of the physics frame. Should the specified map receive changes after the forced update it will update again as well when the other maps receive their update. - Avoidance processing and dispatch of the [code]safe_velocity[/code] signals is untouched by this function and continues to happen for all maps and agents at the end of the physics frame. + Avoidance processing and dispatch of the [code]safe_velocity[/code] signals is unaffected by this function and continues to happen for all maps and agents at the end of the physics frame. [b]Note:[/b] With great power comes great responsibility. This function should only be used by users that really know what they are doing and have a good reason for it. Forcing an immediate update of a navigation map requires locking the NavigationServer and flushing the entire NavigationServer command queue. Not only can this severely impact the performance of a game but it can also introduce bugs if used inappropriately without much foresight. diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index b56b86f435db..f3ddccca2048 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -404,7 +404,7 @@ This function immediately forces synchronization of the specified navigation [param map] [RID]. By default navigation maps are only synchronized at the end of each physics frame. This function can be used to immediately (re)calculate all the navigation meshes and region connections of the navigation map. This makes it possible to query a navigation path for a changed map immediately and in the same frame (multiple times if needed). Due to technical restrictions the current NavigationServer command queue will be flushed. This means all already queued update commands for this physics frame will be executed, even those intended for other maps, regions and agents not part of the specified map. The expensive computation of the navigation meshes and region connections of a map will only be done for the specified map. Other maps will receive the normal synchronization at the end of the physics frame. Should the specified map receive changes after the forced update it will update again as well when the other maps receive their update. - Avoidance processing and dispatch of the [code]safe_velocity[/code] signals is untouched by this function and continues to happen for all maps and agents at the end of the physics frame. + Avoidance processing and dispatch of the [code]safe_velocity[/code] signals is unaffected by this function and continues to happen for all maps and agents at the end of the physics frame. [b]Note:[/b] With great power comes great responsibility. This function should only be used by users that really know what they are doing and have a good reason for it. Forcing an immediate update of a navigation map requires locking the NavigationServer and flushing the entire NavigationServer command queue. Not only can this severely impact the performance of a game but it can also introduce bugs if used inappropriately without much foresight. diff --git a/doc/classes/ProceduralSkyMaterial.xml b/doc/classes/ProceduralSkyMaterial.xml index 54bffd009fb6..6fea12b46eda 100644 --- a/doc/classes/ProceduralSkyMaterial.xml +++ b/doc/classes/ProceduralSkyMaterial.xml @@ -6,7 +6,7 @@ [ProceduralSkyMaterial] provides a way to create an effective background quickly by defining procedural parameters for the sun, the sky and the ground. The sky and ground are defined by a main color, a color at the horizon, and an easing curve to interpolate between them. Suns are described by a position in the sky, a color, and a max angle from the sun at which the easing curve ends. The max angle therefore defines the size of the sun in the sky. [ProceduralSkyMaterial] supports up to 4 suns, using the color, and energy, direction, and angular distance of the first four [DirectionalLight3D] nodes in the scene. This means that the suns are defined individually by the properties of their corresponding [DirectionalLight3D]s and globally by [member sun_angle_max] and [member sun_curve]. - [ProceduralSkyMaterial] uses a lightweight shader to draw the sky and is therefore suited for real time updates. This makes it a great option for a sky that is simple and computationally cheap, but unrealistic. If you need a more realistic procedural option, use [PhysicalSkyMaterial]. + [ProceduralSkyMaterial] uses a lightweight shader to draw the sky and is therefore suited for real-time updates. This makes it a great option for a sky that is simple and computationally cheap, but unrealistic. If you need a more realistic procedural option, use [PhysicalSkyMaterial]. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index b62e50df1e04..ccb9657934c8 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -406,7 +406,7 @@ [b]Note:[/b] Enabling TTS can cause addition idle CPU usage and interfere with the sleep mode, so consider disabling it if TTS is not used. - Setting to hardcode audio delay when playing video. Best to leave this untouched unless you know what you are doing. + Setting to hardcode audio delay when playing video. Best to leave this unchanged unless you know what you are doing. If [code]true[/code], ambient lights will be imported from COLLADA models as [DirectionalLight3D]. If [code]false[/code], ambient lights will be ignored. @@ -2213,7 +2213,7 @@ [b]Note:[/b] This property is only read when the project starts. To change the maximum number of simulated physics steps per frame at runtime, set [member Engine.max_physics_steps_per_frame] instead. - Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows smoothing out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended. + Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows smoothing out framerate jitters. The default value of 0.5 should be good enough for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended. [b]Note:[/b] For best results, when using a custom physics interpolation solution, the physics jitter fix should be disabled by setting [member physics/common/physics_jitter_fix] to [code]0[/code]. [b]Note:[/b] This property is only read when the project starts. To change the physics jitter fix at runtime, set [member Engine.physics_jitter_fix] instead. diff --git a/doc/classes/RandomNumberGenerator.xml b/doc/classes/RandomNumberGenerator.xml index 54f18a1ab4f2..2b6e6af596d8 100644 --- a/doc/classes/RandomNumberGenerator.xml +++ b/doc/classes/RandomNumberGenerator.xml @@ -6,7 +6,7 @@ RandomNumberGenerator is a class for generating pseudo-random numbers. It currently uses [url=https://www.pcg-random.org/]PCG32[/url]. [b]Note:[/b] The underlying algorithm is an implementation detail and should not be depended upon. - To generate a random float number (within a given range) based on a time-dependant seed: + To generate a random float number (within a given range) based on a time-dependent seed: [codeblock] var rng = RandomNumberGenerator.new() func _ready(): diff --git a/doc/classes/ResourceImporterOBJ.xml b/doc/classes/ResourceImporterOBJ.xml index fa964e50162a..55043a311ceb 100644 --- a/doc/classes/ResourceImporterOBJ.xml +++ b/doc/classes/ResourceImporterOBJ.xml @@ -1,7 +1,7 @@ - Imports an OBJ 3D model as a standalone [Mesh] or scene. + Imports an OBJ 3D model as an independent [Mesh] or scene. Unlike [ResourceImporterScene], [ResourceImporterOBJ] will import a single [Mesh] resource by default instead of importing a [PackedScene]. This makes it easier to use the [Mesh] resource in nodes that expect direct [Mesh] resources, such as [GridMap], [GPUParticles3D] or [CPUParticles3D]. Note that it is still possible to save mesh resources from 3D scenes using the [b]Advanced Import Settings[/b] dialog, regardless of the source format. diff --git a/doc/classes/ResourceImporterScene.xml b/doc/classes/ResourceImporterScene.xml index 1769da9f247e..6a88adf4216f 100644 --- a/doc/classes/ResourceImporterScene.xml +++ b/doc/classes/ResourceImporterScene.xml @@ -4,7 +4,7 @@ Imports a glTF, FBX, Collada or Blender 3D scene. - See also [ResourceImporterOBJ], which is used for OBJ models that can be imported as a standalone [Mesh] or a scene. + See also [ResourceImporterOBJ], which is used for OBJ models that can be imported as an independent [Mesh] or a scene. Additional options (such as extracting individual meshes or materials to files) are available in the [b]Advanced Import Settings[/b] dialog. This dialog can be accessed by double-clicking a 3D scene in the FileSystem dock or by selecting a 3D scene in the FileSystem dock, going to the Import dock and choosing [b]Advanced[/b]. [b]Note:[/b] [ResourceImporterScene] is [i]not[/i] used for [PackedScene]s, such as [code].tscn[/code] and [code].scn[/code] files. diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml index 5562342eacf4..32c5f8dff745 100644 --- a/doc/classes/SurfaceTool.xml +++ b/doc/classes/SurfaceTool.xml @@ -125,7 +125,7 @@ Generates a LOD for a given [param nd_threshold] in linear units (square root of quadric error metric), using at most [param target_index_count] indices. - [i]Deprecated.[/i] Unused internally and neglects to preserve normals or UVs. Consider using [method ImporterMesh.generate_lods] instead. + [i]Deprecated.[/i] Unused internally and fails to preserve normals or UVs. Consider using [method ImporterMesh.generate_lods] instead. diff --git a/doc/classes/SystemFont.xml b/doc/classes/SystemFont.xml index 239bcc257cc4..fe93571fbe48 100644 --- a/doc/classes/SystemFont.xml +++ b/doc/classes/SystemFont.xml @@ -7,7 +7,7 @@ [SystemFont] loads a font from a system font with the first matching name from [member font_names]. It will attempt to match font style, but it's not guaranteed. The returned font might be part of a font collection or be a variable font with OpenType "weight", "width" and/or "italic" features set. - You can create [FontVariation] of the system font for fine control over its features. + You can create [FontVariation] of the system font for precise control over its features. [b]Note:[/b] This class is implemented on iOS, Linux, macOS and Windows, on other platforms it will fallback to default theme font. diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 4148c4eb093a..ea8185fff4af 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -1106,7 +1106,7 @@ If [code]true[/code], a right-click moves the caret at the mouse position before displaying the context menu. - If [code]false[/code], the context menu disregards mouse location. + If [code]false[/code], the context menu ignores mouse location. Sets if multiple carets are allowed. diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml index 0ecfe5312380..b265f8ba11e8 100644 --- a/doc/classes/Tween.xml +++ b/doc/classes/Tween.xml @@ -5,7 +5,7 @@ Tweens are mostly useful for animations requiring a numerical property to be interpolated over a range of values. The name [i]tween[/i] comes from [i]in-betweening[/i], an animation technique where you specify [i]keyframes[/i] and the computer interpolates the frames that appear between them. Animating something with a [Tween] is called tweening. - [Tween] is more suited than [AnimationPlayer] for animations where you don't know the final values in advance. For example, interpolating a dynamically-chosen camera zoom value is best done with a [Tween]; it would be difficult to do the same thing with an [AnimationPlayer] node. Tweens are also more light-weight than [AnimationPlayer], so they are very much suited for simple animations or general tasks that don't require visual tweaking provided by the editor. They can be used in a fire-and-forget manner for some logic that normally would be done by code. You can e.g. make something shoot periodically by using a looped [CallbackTweener] with a delay. + [Tween] is more suited than [AnimationPlayer] for animations where you don't know the final values in advance. For example, interpolating a dynamically-chosen camera zoom value is best done with a [Tween]; it would be difficult to do the same thing with an [AnimationPlayer] node. Tweens are also more light-weight than [AnimationPlayer], so they are very much suited for simple animations or general tasks that don't require visual tweaking provided by the editor. They can be used in a "fire-and-forget" manner for some logic that normally would be done by code. You can e.g. make something shoot periodically by using a looped [CallbackTweener] with a delay. A [Tween] can be created by using either [method SceneTree.create_tween] or [method Node.create_tween]. [Tween]s created manually (i.e. by using [code]Tween.new()[/code]) are invalid and can't be used for tweening values. A tween animation is created by adding [Tweener]s to the [Tween] object, using [method tween_property], [method tween_interval], [method tween_callback] or [method tween_method]: [codeblocks] From 6b3e4bb0ec277a6e95889983096c8b05af1e84bb Mon Sep 17 00:00:00 2001 From: Septian Date: Fri, 5 Jan 2024 15:47:58 +0700 Subject: [PATCH 40/95] Fix various typos in documentation (cherry picked from commit d3e7b8c8a87733ca773ca8b6dc4f2a0b395b1646) --- doc/classes/Image.xml | 2 +- doc/classes/NavigationServer3D.xml | 2 +- doc/classes/ProjectSettings.xml | 8 ++++---- doc/classes/RenderingDevice.xml | 2 +- doc/classes/String.xml | 2 +- doc/classes/StringName.xml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 6a9de9a80ce5..6c1ecb3aea70 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -736,7 +736,7 @@ On the other hand, if the image already has mipmaps, they will be used, and a new set will be generated for the resulting image. - Performs Lanczos interpolation. This is the slowest image resizing mode, but it typically gives the best results, especially when downscalng images. + Performs Lanczos interpolation. This is the slowest image resizing mode, but it typically gives the best results, especially when downscaling images. Image does not have alpha. diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index f3ddccca2048..395d6822322f 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -187,7 +187,7 @@ Sets if the agent uses the 2D avoidance or the 3D avoidance while avoidance is enabled. - If [code]true[/code] the agent calculates avoidance velocities in 3D for the xyz-axis, e.g. for games that take place in air, unterwater or space. The 3D using agent only avoids other 3D avoidance using agent's. The 3D using agent only reacts to radius based avoidance obstacles. The 3D using agent ignores any vertices based obstacles. The 3D using agent only avoids other 3D using agent's. + If [code]true[/code] the agent calculates avoidance velocities in 3D for the xyz-axis, e.g. for games that take place in air, underwater or space. The 3D using agent only avoids other 3D avoidance using agent's. The 3D using agent only reacts to radius based avoidance obstacles. The 3D using agent ignores any vertices based obstacles. The 3D using agent only avoids other 3D using agent's. If [code]false[/code] the agent calculates avoidance velocities in 2D along the xz-axis ignoring the y-axis. The 2D using agent only avoids other 2D avoidance using agent's. The 2D using agent reacts to radius avoidance obstacles. The 2D using agent reacts to vertices based avoidance obstacles. The 2D using agent only avoids other 2D using agent's. 2D using agents will ignore other 2D using agents or obstacles that are below their current position or above their current position including the agents height in 2D avoidance. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index ccb9657934c8..94a9e1864f9e 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1110,7 +1110,7 @@ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. - Default [InputEventAction] to swap input direction, i.e. change between left-to-right to right-to-left modes. Affects text-editting controls ([LineEdit], [TextEdit]). + Default [InputEventAction] to swap input direction, i.e. change between left-to-right to right-to-left modes. Affects text-editing controls ([LineEdit], [TextEdit]). If a selection is currently active with the last caret in text fields, searches for the next occurrence of the selection, adds a caret and selects the next occurrence. @@ -1221,15 +1221,15 @@ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. - Default [InputEventAction] to accept an autocompetion hint. + Default [InputEventAction] to accept an autocompletion hint. [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. - Default [InputEventAction] to request autocompetion. + Default [InputEventAction] to request autocompletion. [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. - Default [InputEventAction] to accept an autocompetion hint, replacing existing text. + Default [InputEventAction] to accept an autocompletion hint, replacing existing text. [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index 20faa702267f..0e6264afafaf 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -205,7 +205,7 @@ A simple drawing operation might look like this (code is not a complete example): [codeblock] var rd = RenderingDevice.new() - var clear_colors = PackedColorArray([Color(0, 0, 0, 0), Color(0, 0, 0, 0), Color(0, 0, 0, 0)] + var clear_colors = PackedColorArray([Color(0, 0, 0, 0), Color(0, 0, 0, 0), Color(0, 0, 0, 0)]) var draw_list = rd.draw_list_begin(framebuffers[i], RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_READ, RenderingDevice.INITIAL_ACTION_CLEAR, RenderingDevice.FINAL_ACTION_DISCARD, clear_colors) # Draw opaque. diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 86424975bcd3..e1b60b1656fc 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -319,7 +319,7 @@ Returns the 32-bit hash value representing the string's contents. - [b]Note:[/b] Strings with equal hash values are [i]not[/i] guaranteed to be the same, as a result of hash collisions. On the countrary, strings with different hash values are guaranteed to be different. + [b]Note:[/b] Strings with equal hash values are [i]not[/i] guaranteed to be the same, as a result of hash collisions. On the contrary, strings with different hash values are guaranteed to be different. diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml index 0cc72e9a7f38..844782eb9a96 100644 --- a/doc/classes/StringName.xml +++ b/doc/classes/StringName.xml @@ -303,7 +303,7 @@ Returns the 32-bit hash value representing the string's contents. - [b]Note:[/b] Strings with equal hash values are [i]not[/i] guaranteed to be the same, as a result of hash collisions. On the countrary, strings with different hash values are guaranteed to be different. + [b]Note:[/b] Strings with equal hash values are [i]not[/i] guaranteed to be the same, as a result of hash collisions. On the contrary, strings with different hash values are guaranteed to be different. From b6d78d8eb7bcf57f0ae2d7ca7fdd129b5cde2c10 Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Wed, 16 Aug 2023 13:57:54 +0200 Subject: [PATCH 41/95] Clarify that `Callable` will not be encoded with `var_to_bytes` (cherry picked from commit c909354396f1e35b9558178a48274e77ecb0f815) --- doc/classes/@GlobalScope.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 75fe10d1fc08..0e2d8ba374a8 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1428,6 +1428,7 @@ Encodes a [Variant] value to a byte array, without encoding objects. Deserialization can be done with [method bytes_to_var]. [b]Note:[/b] If you need object serialization, see [method var_to_bytes_with_objects]. + [b]Note:[/b] Encoding [Callable] is not supported and will result in an empty value, regardless of the data. @@ -1435,6 +1436,7 @@ Encodes a [Variant] value to a byte array. Encoding objects is allowed (and can potentially include executable code). Deserialization can be done with [method bytes_to_var_with_objects]. + [b]Note:[/b] Encoding [Callable] is not supported and will result in an empty value, regardless of the data. From f7f86cf5db46ffa47938a322860527889051fcbe Mon Sep 17 00:00:00 2001 From: Micky Date: Wed, 10 Jan 2024 17:31:17 +0100 Subject: [PATCH 42/95] Add missing descriptions to remaining signals. (cherry picked from commit 8f10d7dd194d205e1991be222c9afdc49a5f78a1) --- doc/classes/GraphEdit.xml | 16 +++++++++------- doc/classes/Skeleton3D.xml | 6 ++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index 9765b10d227b..77d4be2a086e 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -298,7 +298,7 @@ - Emitted at the beginning of a GraphNode movement. + Emitted at the beginning of a [GraphElement]'s movement. @@ -341,13 +341,14 @@ - Emitted when the user presses [kbd]Ctrl + C[/kbd]. + Emitted when this [GraphEdit] captures a [code]ui_copy[/code] action ([kbd]Ctrl + C[/kbd] by default). In general, this signal indicates that the selected [GraphElement]s should be copied. - Emitted when attempting to remove a GraphNode from the GraphEdit. Provides a list of node names to be removed (all selected nodes, excluding nodes without closing button). + Emitted when this [GraphEdit] captures a [code]ui_graph_delete[/code] action ([kbd]Delete[/kbd] by default). + [param nodes] is an array of node names that should be removed. These usually include all selected nodes. @@ -361,28 +362,29 @@ - Emitted when a GraphNode is attempted to be duplicated in the GraphEdit. + Emitted when this [GraphEdit] captures a [code]ui_graph_duplicate[/code] action ([kbd]Ctrl + D[/kbd] by default). In general, this signal indicates that the selected [GraphElement]s should be duplicated. - Emitted at the end of a GraphNode movement. + Emitted at the end of a [GraphElement]'s movement. + Emitted when the given [GraphElement] node is deselected. - Emitted when a GraphNode is selected. + Emitted when the given [GraphElement] node is selected. - Emitted when the user presses [kbd]Ctrl + V[/kbd]. + Emitted when this [GraphEdit] captures a [code]ui_paste[/code] action ([kbd]Ctrl + V[/kbd] by default). In general, this signal indicates that previously copied [GraphElement]s should be pasted. diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml index 6cb1c948ea2f..2a629abc0db3 100644 --- a/doc/classes/Skeleton3D.xml +++ b/doc/classes/Skeleton3D.xml @@ -310,12 +310,14 @@ [b]Note:[/b] Unless this value is [code]1.0[/code], the key value in animation will not match the actual position value. + If [code]true[/code], forces the bones in their default rest pose, regardless of their values. In the editor, this also prevents the bones from being edited. + Emitted when the bone at [param bone_idx] is toggled with [method set_bone_enabled]. Use [method is_bone_enabled] to check the new value. @@ -326,15 +328,19 @@ + Emitted when the pose is updated, after [constant NOTIFICATION_UPDATE_SKELETON] is received. + Emitted when the value of [member show_rest_only] changes. + Notification received when this skeleton's pose needs to be updated. + This notification is received [i]before[/i] the related [signal pose_updated] signal. From 50eaeec2f7e75ead88b974b3cfc357b1beb52696 Mon Sep 17 00:00:00 2001 From: DevPoodle Date: Sat, 13 Jan 2024 11:09:44 -0800 Subject: [PATCH 43/95] Add descriptions to the remaining properties of RDPipelineDepthStencilState (cherry picked from commit 0bb744e555f131cf884bea4d3c5eb4e9e462978b) --- doc/classes/RDPipelineDepthStencilState.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/classes/RDPipelineDepthStencilState.xml b/doc/classes/RDPipelineDepthStencilState.xml index fa2a4e17c969..b8245f97af23 100644 --- a/doc/classes/RDPipelineDepthStencilState.xml +++ b/doc/classes/RDPipelineDepthStencilState.xml @@ -10,47 +10,67 @@ + The method used for comparing the previous back stencil value and [member back_op_reference]. + Selects which bits from the back stencil value will be compared. + The operation to perform on the stencil buffer for back pixels that pass the stencil test but fail the depth test. + The operation to perform on the stencil buffer for back pixels that fail the stencil test + The operation to perform on the stencil buffer for back pixels that pass the stencil test. + The value the previous back stencil value will be compared to. + Selects which bits from the back stencil value will be changed. + The method used for comparing the previous and current depth values. + The maximum depth that returns true for [member enable_depth_range]. + The minimum depth that returns true for [member enable_depth_range]. + If [code]true[/code], each depth value will be tested to see if it is between [member depth_range_min] and [member depth_range_max]. If it is outside of these values, it is discarded. If [code]true[/code], enables depth testing which allows objects to be automatically occluded by other objects based on their depth. This also allows objects to be partially occluded by other objects. If [code]false[/code], objects will appear in the order they were drawn (like in Godot's 2D renderer). + If [code]true[/code], writes to the depth buffer whenever the depth test returns true. Only works when enable_depth_test is also true. + If [code]true[/code], enables stencil testing. There are separate stencil buffers for front-facing triangles and back-facing triangles. See properties that begin with "front_op" and properties with "back_op" for each. + The method used for comparing the previous front stencil value and [member front_op_reference]. + Selects which bits from the front stencil value will be compared. + The operation to perform on the stencil buffer for front pixels that pass the stencil test but fail the depth test. + The operation to perform on the stencil buffer for front pixels that fail the stencil test. + The operation to perform on the stencil buffer for front pixels that pass the stencil test. + The value the previous front stencil value will be compared to. + Selects which bits from the front stencil value will be changed. From 7827a3945b23764c48659caf7b170f5142c991e4 Mon Sep 17 00:00:00 2001 From: Martin Capitanio Date: Sat, 30 Dec 2023 02:19:05 +0100 Subject: [PATCH 44/95] ThorVG: update from v0.11.2 to v0.11.6 https://github.com/thorvg/thorvg/releases/tag/v0.11.6 Godot related: + [Renderer] Improved the internal structure for compact scene-hierarchy traversing. + [SwEngine] Improved trigonometric & image scaler performance. + [SwEngine] Fixed a loss of image pixels during image down-scaling. + [Renderer/Engine] Improved safety measures. + [SwEngine] Resolved a bug causing strokes to be improperly invisible due to clipping. thorvg/thorvg#1785 + [Renderer] Rectified the precision of rounded rectangle corners. thorvg/thorvg#1824 + [Portability] Resolved compiler shadowing warnings. thorvg/thorvg#1811 Fixes godotengine#85465 Clipped strokes from outside the canvas. Fixes godotengine#86012 Rounded rectangles in SVG files rendering incorrectly. (cherry picked from commit 74ed6d63bfc7cd022737b3356999789d4ef5d5ec) --- thirdparty/README.md | 2 +- thirdparty/thorvg/inc/config.h | 2 +- thirdparty/thorvg/inc/thorvg.h | 37 +- thirdparty/thorvg/src/common/tvgArray.h | 1 + .../src/loaders/external_png/tvgPngLoader.cpp | 6 +- thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp | 6 +- .../src/renderer/sw_engine/tvgSwCommon.h | 11 +- .../src/renderer/sw_engine/tvgSwMath.cpp | 272 +++------------ .../src/renderer/sw_engine/tvgSwRaster.cpp | 316 +++++++----------- .../src/renderer/sw_engine/tvgSwRenderer.cpp | 4 +- .../src/renderer/sw_engine/tvgSwShape.cpp | 4 + .../thorvg/src/renderer/tvgAnimation.cpp | 6 +- thirdparty/thorvg/src/renderer/tvgCanvas.cpp | 8 +- thirdparty/thorvg/src/renderer/tvgCommon.h | 2 +- .../thorvg/src/renderer/tvgFrameModule.h | 7 +- thirdparty/thorvg/src/renderer/tvgLoader.cpp | 4 +- thirdparty/thorvg/src/renderer/tvgPaint.cpp | 81 +++-- thirdparty/thorvg/src/renderer/tvgPaint.h | 97 +----- thirdparty/thorvg/src/renderer/tvgPicture.cpp | 1 - thirdparty/thorvg/src/renderer/tvgRender.cpp | 19 +- thirdparty/thorvg/src/renderer/tvgRender.h | 6 +- .../thorvg/src/renderer/tvgSaveModule.h | 1 + thirdparty/thorvg/src/renderer/tvgSaver.cpp | 48 ++- thirdparty/thorvg/src/renderer/tvgScene.cpp | 1 - thirdparty/thorvg/src/renderer/tvgScene.h | 5 +- thirdparty/thorvg/src/renderer/tvgShape.cpp | 15 +- thirdparty/thorvg/src/renderer/tvgShape.h | 3 +- thirdparty/thorvg/update-thorvg.sh | 7 +- 28 files changed, 382 insertions(+), 590 deletions(-) diff --git a/thirdparty/README.md b/thirdparty/README.md index 013273284154..e3390d7eaca4 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -825,7 +825,7 @@ instead of `miniz.h` as an external dependency. ## thorvg - Upstream: https://github.com/thorvg/thorvg -- Version: 0.11.2 (b01fe9bf4461146304d3520d6dc699cf580a3744, 2023) +- Version: 0.11.6 (3dba4f12f8f05f86acbc51096ca3a15f5d96bc06, 2023) - License: MIT Files extracted from upstream source: diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index 818739b113f9..98f35a6e457a 100644 --- a/thirdparty/thorvg/inc/config.h +++ b/thirdparty/thorvg/inc/config.h @@ -9,5 +9,5 @@ // For internal debugging: //#define THORVG_LOG_ENABLED -#define THORVG_VERSION_STRING "0.11.2" +#define THORVG_VERSION_STRING "0.11.6" #endif diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h index 1b9c2d70d339..20acda7667fe 100644 --- a/thirdparty/thorvg/inc/thorvg.h +++ b/thirdparty/thorvg/inc/thorvg.h @@ -1664,14 +1664,14 @@ class TVG_API Animation * @param[in] no The index of the animation frame to be displayed. The index should be less than the totalFrame(). * * @retval Result::Success Successfully set the frame. - * @retval Result::InsufficientCondition No animatable data loaded from the Picture. - * @retval Result::NonSupport The Picture data does not support animations. + * @retval Result::InsufficientCondition if the given @p no is the same as the current frame value. + * @retval Result::NonSupport The current Picture data does not support animations. * * @see totalFrame() * * @BETA_API */ - Result frame(uint32_t no) noexcept; + Result frame(float no) noexcept; /** * @brief Retrieves a picture instance associated with this animation instance. @@ -1695,12 +1695,12 @@ class TVG_API Animation * * @note If the Picture is not properly configured, this function will return 0. * - * @see Animation::frame(uint32_t no) + * @see Animation::frame(float no) * @see Animation::totalFrame() * * @BETA_API */ - uint32_t curFrame() const noexcept; + float curFrame() const noexcept; /** * @brief Retrieves the total number of frames in the animation. @@ -1712,7 +1712,7 @@ class TVG_API Animation * * @BETA_API */ - uint32_t totalFrame() const noexcept; + float totalFrame() const noexcept; /** * @brief Retrieves the duration of the animation in seconds. @@ -1784,6 +1784,31 @@ class TVG_API Saver final */ Result save(std::unique_ptr paint, const std::string& path, bool compress = true) noexcept; + /** + * @brief Export the provided animation data to the specified file path. + * + * This function exports the given animation data to the provided file path. You can also specify the desired frame rate in frames per second (FPS) by providing the fps parameter. + * + * @param[in] animation The animation to be saved, including all associated properties. + * @param[in] path The path to the file where the animation will be saved. + * @param[in] quality The encoded quality level. @c 0 is the minimum, @c 100 is the maximum value(recommended). + * @param[in] fps The desired frames per second (FPS). For example, to encode data at 60 FPS, pass 60. Pass 0 to keep the original frame data. + * + * @return Result::Success if the export succeeds. + * @return Result::InsufficientCondition if there are ongoing resource-saving operations. + * @return Result::NonSupport if an attempt is made to save the file with an unknown extension or in an unsupported format. + * @return Result::MemoryCorruption in case of an internal error. + * @return Result::Unknown if attempting to save an empty paint. + * + * @note A higher frames per second (FPS) would result in a larger file size. It is recommended to use the default value. + * @note Saving can be asynchronous if the assigned thread number is greater than zero. To guarantee the saving is done, call sync() afterwards. + * + * @see Saver::sync() + * + * @note: Experimental API + */ + Result save(std::unique_ptr animation, const std::string& path, uint32_t quality = 100, uint32_t fps = 0) noexcept; + /** * @brief Guarantees that the saving task is finished. * diff --git a/thirdparty/thorvg/src/common/tvgArray.h b/thirdparty/thorvg/src/common/tvgArray.h index 08eb25329cf7..1afc647b6889 100644 --- a/thirdparty/thorvg/src/common/tvgArray.h +++ b/thirdparty/thorvg/src/common/tvgArray.h @@ -25,6 +25,7 @@ #include #include +#include namespace tvg { diff --git a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp index b0a9fdd57995..30a66f9cada6 100644 --- a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp +++ b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp @@ -107,9 +107,9 @@ unique_ptr PngLoader::bitmap() //TODO: It's better to keep this surface instance in the loader side auto surface = new Surface; surface->buf32 = content; - surface->stride = w; - surface->w = w; - surface->h = h; + surface->stride = (uint32_t)w; + surface->w = (uint32_t)w; + surface->h = (uint32_t)h; surface->cs = cs; surface->channelSize = sizeof(uint32_t); surface->owner = true; diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp index 61a5dc1c0ffd..3cd852a4bb8d 100644 --- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp +++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp @@ -1456,7 +1456,11 @@ void jpeg_decoder::locate_sof_marker() int c = process_markers(); switch (c) { - case M_SOF2: m_progressive_flag = true; + case M_SOF2: { + m_progressive_flag = true; + read_sof_marker(); + break; + } case M_SOF0: /* baseline DCT */ case M_SOF1: { /* extended sequential DCT */ read_sof_marker(); diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h index c6dcf79a4849..8fe7b77edd28 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h @@ -43,11 +43,16 @@ static double timeStamp() #define SW_ANGLE_PI (180L << 16) #define SW_ANGLE_2PI (SW_ANGLE_PI << 1) #define SW_ANGLE_PI2 (SW_ANGLE_PI >> 1) -#define SW_ANGLE_PI4 (SW_ANGLE_PI >> 2) using SwCoord = signed long; using SwFixed = signed long long; + +static inline float TO_FLOAT(SwCoord val) +{ + return static_cast(val) / 64.0f; +} + struct SwPoint { SwCoord x, y; @@ -92,6 +97,10 @@ struct SwPoint else return false; } + Point toPoint() const + { + return {TO_FLOAT(x), TO_FLOAT(y)}; + } }; struct SwSize diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp index dbcfa754f31e..d58dd9e3c5aa 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp @@ -20,7 +20,7 @@ * SOFTWARE. */ -#include +#include "tvgMath.h" #include "tvgSwCommon.h" @@ -28,173 +28,9 @@ /* Internal Class Implementation */ /************************************************************************/ -//clz: count leading zero’s -#if defined(_MSC_VER) && !defined(__clang__) - #include - static uint32_t __inline _clz(uint32_t value) - { - unsigned long leadingZero = 0; - if (_BitScanReverse(&leadingZero, value)) return 31 - leadingZero; - else return 32; - } -#else - #define _clz(x) __builtin_clz((x)) -#endif - - -constexpr SwFixed CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32 - -//this table was generated for SW_FT_PI = 180L << 16, i.e. degrees -constexpr static auto ATAN_MAX = 23; -constexpr static SwFixed ATAN_TBL[] = { - 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, - 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, - 57L, 29L, 14L, 7L, 4L, 2L, 1L}; - -static inline SwCoord SATURATE(const SwCoord x) -{ - return (x >> (sizeof(SwCoord) * 8 - 1)); -} - - -static inline SwFixed PAD_ROUND(const SwFixed x, int32_t n) -{ - return (((x) + ((n)/2)) & ~((n)-1)); -} - - -static SwCoord _downscale(SwFixed x) +static float TO_RADIAN(SwFixed angle) { - //multiply a give value by the CORDIC shrink factor - auto s = abs(x); - int64_t t = (s * static_cast(CORDIC_FACTOR)) + 0x100000000UL; - s = static_cast(t >> 32); - if (x < 0) s = -s; - return s; -} - - -static int32_t _normalize(SwPoint& pt) -{ - /* the highest bit in overflow-safe vector components - MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */ - constexpr auto SAFE_MSB = 29; - - auto v = pt; - - //High order bit(MSB) - int32_t shift = 31 - _clz(abs(v.x) | abs(v.y)); - - if (shift <= SAFE_MSB) { - shift = SAFE_MSB - shift; - pt.x = static_cast((unsigned long)v.x << shift); - pt.y = static_cast((unsigned long)v.y << shift); - } else { - shift -= SAFE_MSB; - pt.x = v.x >> shift; - pt.y = v.y >> shift; - shift = -shift; - } - return shift; -} - - -static void _polarize(SwPoint& pt) -{ - auto v = pt; - SwFixed theta; - - //Get the vector into [-PI/4, PI/4] sector - if (v.y > v.x) { - if (v.y > -v.x) { - auto tmp = v.y; - v.y = -v.x; - v.x = tmp; - theta = SW_ANGLE_PI2; - } else { - theta = v.y > 0 ? SW_ANGLE_PI : -SW_ANGLE_PI; - v.x = -v.x; - v.y = -v.y; - } - } else { - if (v.y < -v.x) { - theta = -SW_ANGLE_PI2; - auto tmp = -v.y; - v.y = v.x; - v.x = tmp; - } else { - theta = 0; - } - } - - auto atan = ATAN_TBL; - uint32_t i; - SwFixed j; - - //Pseudorotations. with right shifts - for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { - if (v.y > 0) { - auto tmp = v.x + ((v.y + j) >> i); - v.y = v.y - ((v.x + j) >> i); - v.x = tmp; - theta += *atan++; - } else { - auto tmp = v.x - ((v.y + j) >> i); - v.y = v.y + ((v.x + j) >> i); - v.x = tmp; - theta -= *atan++; - } - } - - //round theta - if (theta >= 0) theta = PAD_ROUND(theta, 32); - else theta = -PAD_ROUND(-theta, 32); - - pt.x = v.x; - pt.y = theta; -} - - -static void _rotate(SwPoint& pt, SwFixed theta) -{ - SwFixed x = pt.x; - SwFixed y = pt.y; - - //Rotate inside [-PI/4, PI/4] sector - while (theta < -SW_ANGLE_PI4) { - auto tmp = y; - y = -x; - x = tmp; - theta += SW_ANGLE_PI2; - } - - while (theta > SW_ANGLE_PI4) { - auto tmp = -y; - y = x; - x = tmp; - theta -= SW_ANGLE_PI2; - } - - auto atan = ATAN_TBL; - uint32_t i; - SwFixed j; - - for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) { - if (theta < 0) { - auto tmp = x + ((y + j) >> i); - y = y - ((x + j) >> i); - x = tmp; - theta += *atan++; - } else { - auto tmp = x - ((y + j) >> i); - y = y + ((x + j) >> i); - x = tmp; - theta -= *atan++; - } - } - - pt.x = static_cast(x); - pt.y = static_cast(y); + return (float(angle) / 65536.0f) * (MATH_PI / 180.0f); } @@ -214,11 +50,17 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw auto d2 = base[1] - base[2]; auto d3 = base[0] - base[1]; + if (d1 == d2 || d2 == d3) { + if (d3.small()) angleIn = angleMid = angleOut = 0; + else angleIn = angleMid = angleOut = mathAtan(d3); + return true; + } + if (d1.small()) { if (d2.small()) { if (d3.small()) { - //basically a point. - //do nothing to retain original direction + angleIn = angleMid = angleOut = 0; + return true; } else { angleIn = angleMid = angleOut = mathAtan(d3); } @@ -320,77 +162,63 @@ int64_t mathMulDiv(int64_t a, int64_t b, int64_t c) void mathRotate(SwPoint& pt, SwFixed angle) { - if (angle == 0 || (pt.x == 0 && pt.y == 0)) return; - - auto v = pt; - auto shift = _normalize(v); + if (angle == 0 || pt.zero()) return; - auto theta = angle; - _rotate(v, theta); + Point v = pt.toPoint(); - v.x = _downscale(v.x); - v.y = _downscale(v.y); + auto radian = TO_RADIAN(angle); + auto cosv = cosf(radian); + auto sinv = sinf(radian); - if (shift > 0) { - auto half = static_cast(1L << (shift - 1)); - pt.x = (v.x + half + SATURATE(v.x)) >> shift; - pt.y = (v.y + half + SATURATE(v.y)) >> shift; - } else { - shift = -shift; - pt.x = static_cast((unsigned long)v.x << shift); - pt.y = static_cast((unsigned long)v.y << shift); - } + pt.x = SwCoord(roundf((v.x * cosv - v.y * sinv) * 64.0f)); + pt.y = SwCoord(roundf((v.x * sinv + v.y * cosv) * 64.0f)); } + SwFixed mathTan(SwFixed angle) { - SwPoint v = {CORDIC_FACTOR >> 8, 0}; - _rotate(v, angle); - return mathDivide(v.y, v.x); + if (angle == 0) return 0; + return SwFixed(tanf(TO_RADIAN(angle)) * 65536.0f); } SwFixed mathAtan(const SwPoint& pt) { - if (pt.x == 0 && pt.y == 0) return 0; - - auto v = pt; - _normalize(v); - _polarize(v); - - return v.y; + if (pt.zero()) return 0; + return SwFixed(atan2f(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f); } SwFixed mathSin(SwFixed angle) { + if (angle == 0) return 0; return mathCos(SW_ANGLE_PI2 - angle); } SwFixed mathCos(SwFixed angle) { - SwPoint v = {CORDIC_FACTOR >> 8, 0}; - _rotate(v, angle); - return (v.x + 0x80L) >> 8; + return SwFixed(cosf(TO_RADIAN(angle)) * 65536.0f); } SwFixed mathLength(const SwPoint& pt) { - auto v = pt; + if (pt.zero()) return 0; //trivial case - if (v.x == 0) return abs(v.y); - if (v.y == 0) return abs(v.x); - - //general case - auto shift = _normalize(v); - _polarize(v); - v.x = _downscale(v.x); - - if (shift > 0) return (v.x + (static_cast(1) << (shift -1))) >> shift; - return static_cast((uint32_t)v.x << -shift); + if (pt.x == 0) return abs(pt.y); + if (pt.y == 0) return abs(pt.x); + + auto v = pt.toPoint(); + //return static_cast(sqrtf(v.x * v.x + v.y * v.y) * 65536.0f); + + /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. + With alpha = 1, beta = 3/8, giving results with the largest error less + than 7% compared to the exact value. */ + if (v.x < 0) v.x = -v.x; + if (v.y < 0) v.y = -v.y; + return static_cast((v.x > v.y) ? (v.x + v.y * 0.375f) : (v.y + v.x * 0.375f)); } @@ -401,22 +229,22 @@ void mathSplitCubic(SwPoint* base) base[6].x = base[3].x; c = base[1].x; d = base[2].x; - base[1].x = a = (base[0].x + c) / 2; - base[5].x = b = (base[3].x + d) / 2; - c = (c + d) / 2; - base[2].x = a = (a + c) / 2; - base[4].x = b = (b + c) / 2; - base[3].x = (a + b) / 2; + base[1].x = a = (base[0].x + c) >> 1; + base[5].x = b = (base[3].x + d) >> 1; + c = (c + d) >> 1; + base[2].x = a = (a + c) >> 1; + base[4].x = b = (b + c) >> 1; + base[3].x = (a + b) >> 1; base[6].y = base[3].y; c = base[1].y; d = base[2].y; - base[1].y = a = (base[0].y + c) / 2; - base[5].y = b = (base[3].y + d) / 2; - c = (c + d) / 2; - base[2].y = a = (a + c) / 2; - base[4].y = b = (b + c) / 2; - base[3].y = (a + b) / 2; + base[1].y = a = (base[0].y + c) >> 1; + base[5].y = b = (base[3].y + d) >> 1; + c = (c + d) >> 1; + base[2].y = a = (a + c) >> 1; + base[4].y = b = (b + c) >> 1; + base[3].y = (a + b) >> 1; } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp index 4b1ba59100d1..96a0ed35ad85 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp @@ -248,17 +248,17 @@ static inline uint32_t _sampleSize(float scale) //Bilinear Interpolation //OPTIMIZE_ME: Skip the function pointer access -static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, TVG_UNUSED uint32_t n, TVG_UNUSED uint32_t n2) +static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, TVG_UNUSED int32_t miny, TVG_UNUSED int32_t maxy, TVG_UNUSED int32_t n) { - auto rx = (uint32_t)(sx); - auto ry = (uint32_t)(sy); + auto rx = (size_t)(sx); + auto ry = (size_t)(sy); auto rx2 = rx + 1; if (rx2 >= w) rx2 = w - 1; auto ry2 = ry + 1; if (ry2 >= h) ry2 = h - 1; - auto dx = static_cast((sx - rx) * 255.0f); - auto dy = static_cast((sy - ry) * 255.0f); + auto dx = static_cast((sx - rx) * 255.0f); + auto dy = static_cast((sy - ry) * 255.0f); auto c1 = img[rx + ry * w]; auto c2 = img[rx2 + ry * w]; @@ -271,18 +271,21 @@ static uint32_t _interpUpScaler(const uint32_t *img, TVG_UNUSED uint32_t stride, //2n x 2n Mean Kernel //OPTIMIZE_ME: Skip the function pointer access -static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t w, uint32_t h, float sx, float sy, uint32_t n, uint32_t n2) +static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t w, uint32_t h, float sx, TVG_UNUSED float sy, int32_t miny, int32_t maxy, int32_t n) { - uint32_t rx = lroundf(sx); - uint32_t ry = lroundf(sy); - uint32_t c[4] = {0, 0, 0, 0}; - auto src = img + rx - n + (ry - n) * stride; + size_t c[4] = {0, 0, 0, 0}; - for (auto y = ry - n; y < ry + n; ++y) { - if (y >= h) continue; + int32_t minx = (int32_t)sx - n; + if (minx < 0) minx = 0; + + int32_t maxx = (int32_t)sx + n; + if (maxx >= (int32_t)w) maxx = w; + + auto src = img + minx + miny * stride; + + for (auto y = miny; y < maxy; ++y) { auto p = src; - for (auto x = rx - n; x < rx + n; ++x, ++p) { - if (x >= w) continue; + for (auto x = minx; x < maxx; ++x, ++p) { c[0] += *p >> 24; c[1] += (*p >> 16) & 0xff; c[2] += (*p >> 8) & 0xff; @@ -290,9 +293,14 @@ static uint32_t _interpDownScaler(const uint32_t *img, uint32_t stride, uint32_t } src += stride; } - for (auto i = 0; i < 4; ++i) { - c[i] = (c[i] >> 2) / n2; - } + + n = (maxy - miny) * (maxx - minx); + + c[0] /= n; + c[1] /= n; + c[2] /= n; + c[3] /= n; + return (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; } @@ -660,34 +668,39 @@ static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint8_t r, uint8_t g, /* RLE Scaled Image */ /************************************************************************/ +#define SCALED_IMAGE_RANGE_Y(y) \ + auto sy = (y) * itransform->e22 + itransform->e23; \ + auto my = (int32_t)round(sy); \ + if (my < 0 || (uint32_t)sy >= image->h) continue; \ + if (scaleMethod == _interpDownScaler) { \ + miny = my - (int32_t)sampleSize; \ + if (miny < 0) miny = 0; \ + maxy = my + (int32_t)sampleSize; \ + if (maxy >= (int32_t)image->h) maxy = (int32_t)image->h; \ + } + +#define SCALED_IMAGE_RANGE_X \ + auto sx = x * itransform->e11 + itransform->e13; \ + if ((int32_t)round(sx) < 0 || (uint32_t) sx >= image->w) continue; + + #if 0 //Enable it when GRAYSCALE image is supported static bool _rasterCompositeScaledMaskedRleImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, SwMask maskOp, uint8_t opacity) { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; auto span = image->rle->spans; + int32_t miny = 0, maxy = 0; for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto sy = span->y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(span->y) auto cmp = &surface->compositor->image.buf8[span->y * surface->compositor->image.stride + span->x]; auto a = MULTIPLY(span->coverage, opacity); - if (a == 255) { - for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++cmp) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - *cmp = maskOp(src, *cmp, ~src); - } - } else { - for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++cmp) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = MULTIPLY(src, a); - *cmp = maskOp(tmp, *cmp, ~tmp); - } + for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++cmp) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (a < 255) src = MULTIPLY(src, a); + *cmp = maskOp(src, *cmp, ~src); } } return true; @@ -698,31 +711,20 @@ static bool _rasterDirectScaledMaskedRleImage(SwSurface* surface, const SwImage* { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; auto span = image->rle->spans; + int32_t miny = 0, maxy = 0; - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto sy = span->y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { + SCALED_IMAGE_RANGE_Y(span->y) auto cmp = &surface->compositor->image.buf8[span->y * surface->compositor->image.stride + span->x]; auto dst = &surface->buf8[span->y * surface->stride + span->x]; auto a = MULTIPLY(span->coverage, opacity); - if (a == 255) { - for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++cmp, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = maskOp(src, *cmp, 0); //not use alpha - *dst = tmp + MULTIPLY(*dst, ~tmp); - } - } else { - for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++cmp, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = maskOp(MULTIPLY(src, a), *cmp, 0); //not use alpha - *dst = tmp + MULTIPLY(*dst, ~tmp); - } + for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++cmp, ++dst) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (a < 255) src = MULTIPLY(src, a); + src = maskOp(src, *cmp, 0); //not use alpha + *dst = src + MULTIPLY(*dst, ~src); } } return _compositeMaskImage(surface, &surface->compositor->image, surface->compositor->bbox); @@ -752,32 +754,20 @@ static bool _rasterScaledMattedRleImage(SwSurface* surface, const SwImage* image auto span = image->rle->spans; auto csize = surface->compositor->image.channelSize; auto alpha = surface->alpha(surface->compositor->method); - auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto sy = span->y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(span->y) auto dst = &surface->buf32[span->y * surface->stride + span->x]; auto cmp = &surface->compositor->image.buf8[(span->y * surface->compositor->image.stride + span->x) * csize]; auto a = MULTIPLY(span->coverage, opacity); - if (a == 255) { - for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++dst, cmp += csize) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto tmp = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), alpha(cmp)); - *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); - } - } else { - for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++dst, cmp += csize) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = ALPHA_BLEND(src, MULTIPLY(alpha(cmp), a)); - *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); - } + for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++dst, cmp += csize) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + src = ALPHA_BLEND(src, (a == 255) ? alpha(cmp) : MULTIPLY(alpha(cmp), a)); + *dst = src + ALPHA_BLEND(*dst, IA(src)); } } @@ -790,34 +780,24 @@ static bool _rasterScaledBlendingRleImage(SwSurface* surface, const SwImage* ima auto span = image->rle->spans; auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto sy = span->y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(span->y) auto dst = &surface->buf32[span->y * surface->stride + span->x]; auto alpha = MULTIPLY(span->coverage, opacity); if (alpha == 255) { for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); auto tmp = surface->blender(src, *dst, 255); *dst = INTERPOLATE(tmp, *dst, A(src)); } - } else if (opacity == 255) { - for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = surface->blender(src, *dst, 255); - *dst = INTERPOLATE(tmp, *dst, MULTIPLY(span->coverage, A(src))); - } } else { for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity); + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (opacity < 255) src = ALPHA_BLEND(src, opacity); auto tmp = surface->blender(src, *dst, 255); *dst = INTERPOLATE(tmp, *dst, MULTIPLY(span->coverage, A(src))); } @@ -832,27 +812,17 @@ static bool _rasterScaledRleImage(SwSurface* surface, const SwImage* image, cons auto span = image->rle->spans; auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto sy = span->y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(span->y) auto dst = &surface->buf32[span->y * surface->stride + span->x]; auto alpha = MULTIPLY(span->coverage, opacity); - if (alpha == 255) { - for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - *dst = src + ALPHA_BLEND(*dst, IA(src)); - } - } else { - for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), alpha); - *dst = src + ALPHA_BLEND(*dst, IA(src)); - } + for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++dst) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (alpha < 255) src = ALPHA_BLEND(src, alpha); + *dst = src + ALPHA_BLEND(*dst, IA(src)); } } return true; @@ -1067,29 +1037,18 @@ static bool _rasterCompositeScaledMaskedImage(SwSurface* surface, const SwImage* { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; auto cstride = surface->compositor->image.stride; auto cbuffer = surface->compositor->image.buf8 + (region.min.y * cstride + region.min.x); + int32_t miny = 0, maxy = 0; for (auto y = region.min.y; y < region.max.y; ++y) { - auto sy = y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(y) auto cmp = cbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; ++x, ++cmp) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - *cmp = maskOp(src, *cmp, ~src); - } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++cmp) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = MULTIPLY(src, opacity); - *cmp = maskOp(tmp, *cmp, ~tmp); - } + for (auto x = region.min.x; x < region.max.x; ++x, ++cmp) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (opacity < 255) src = MULTIPLY(src, opacity); + *cmp = maskOp(src, *cmp, ~src); } cbuffer += cstride; } @@ -1101,33 +1060,21 @@ static bool _rasterDirectScaledMaskedImage(SwSurface* surface, const SwImage* im { auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; auto cstride = surface->compositor->image.stride; auto cbuffer = surface->compositor->image.buf8 + (region.min.y * cstride + region.min.x); auto dbuffer = surface->buf8 + (region.min.y * surface->stride + region.min.x); + int32_t miny = 0, maxy = 0; for (auto y = region.min.y; y < region.max.y; ++y) { - auto sy = y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(y) auto cmp = cbuffer; auto dst = dbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; ++x, ++cmp, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = maskOp(src, *cmp, 0); //not use alpha - *dst = tmp + MULTIPLY(*dst, ~tmp); - } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++cmp, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = MULTIPLY(src, opacity); - auto tmp2 = maskOp(tmp, *cmp, 0); //not use alpha - *dst = tmp2 + MULTIPLY(*dst, ~tmp2); - } + for (auto x = region.min.x; x < region.max.x; ++x, ++cmp, ++dst) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf8, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (opacity < 255) src = MULTIPLY(src, opacity); + src = maskOp(src, *cmp, 0); //not use alpha + *dst = src + MULTIPLY(*dst, ~src); } cbuffer += cstride; dbuffer += surface->stride; @@ -1160,29 +1107,17 @@ static bool _rasterScaledMattedImage(SwSurface* surface, const SwImage* image, c auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (auto y = region.min.y; y < region.max.y; ++y) { - auto sy = y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(y) auto dst = dbuffer; auto cmp = cbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto temp = ALPHA_BLEND(src, alpha(cmp)); - *dst = temp + ALPHA_BLEND(*dst, IA(temp)); - } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto temp = ALPHA_BLEND(src, MULTIPLY(opacity, alpha(cmp))); - *dst = temp + ALPHA_BLEND(*dst, IA(temp)); - } + for (auto x = region.min.x; x < region.max.x; ++x, ++dst, cmp += csize) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + auto tmp = ALPHA_BLEND(src, opacity == 255 ? alpha(cmp) : MULTIPLY(opacity, alpha(cmp))); + *dst = tmp + ALPHA_BLEND(*dst, IA(tmp)); } dbuffer += surface->stride; cbuffer += surface->compositor->image.stride * csize; @@ -1196,28 +1131,17 @@ static bool _rasterScaledBlendingImage(SwSurface* surface, const SwImage* image, auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x); auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) { - auto sy = y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(y) auto dst = dbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - auto tmp = surface->blender(src, *dst, 255); - *dst = INTERPOLATE(tmp, *dst, A(src)); - } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity); - auto tmp = surface->blender(src, *dst, 255); - *dst = INTERPOLATE(tmp, *dst, A(src)); - } + for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (opacity < 255) ALPHA_BLEND(src, opacity); + auto tmp = surface->blender(src, *dst, 255); + *dst = INTERPOLATE(tmp, *dst, A(src)); } } return true; @@ -1229,26 +1153,16 @@ static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const M auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x); auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler; auto sampleSize = _sampleSize(image->scale); - auto sampleSize2 = sampleSize * sampleSize; + int32_t miny = 0, maxy = 0; for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) { - auto sy = y * itransform->e22 + itransform->e23; - if ((uint32_t)sy >= image->h) continue; + SCALED_IMAGE_RANGE_Y(y) auto dst = dbuffer; - if (opacity == 255) { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2); - *dst = src + ALPHA_BLEND(*dst, IA(src)); - } - } else { - for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { - auto sx = x * itransform->e11 + itransform->e13; - if ((uint32_t)sx >= image->w) continue; - auto src = ALPHA_BLEND(scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, sampleSize, sampleSize2), opacity); - *dst = src + ALPHA_BLEND(*dst, IA(src)); - } + for (auto x = region.min.x; x < region.max.x; ++x, ++dst) { + SCALED_IMAGE_RANGE_X + auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize); + if (opacity < 255) src = ALPHA_BLEND(src, opacity); + *dst = src + ALPHA_BLEND(*dst, IA(src)); } } return true; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp index 049aa3d1d0fa..18815e69a940 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -139,7 +139,9 @@ struct SwShapeTask : SwTask visibleFill = (alpha > 0 || rshape->fill); if (visibleFill || clipper) { shapeReset(&shape); - if (!shapePrepare(&shape, rshape, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err; + if (!shapePrepare(&shape, rshape, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) { + visibleFill = false; + } } } //Fill diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp index 4f66cdacc06a..ae2ddd2af79f 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp @@ -558,11 +558,15 @@ void shapeReset(SwShape* shape) void shapeFree(SwShape* shape) { rleFree(shape->rle); + shape->rle = nullptr; + shapeDelFill(shape); if (shape->stroke) { rleFree(shape->strokeRle); + shape->strokeRle = nullptr; strokeFree(shape->stroke); + shape->stroke = nullptr; } } diff --git a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp index 7a29ecf973c8..b4ea534b91f7 100644 --- a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp +++ b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp @@ -62,7 +62,7 @@ Animation::Animation() : pImpl(new Impl) } -Result Animation::frame(uint32_t no) noexcept +Result Animation::frame(float no) noexcept { auto loader = pImpl->picture->pImpl->loader.get(); @@ -80,7 +80,7 @@ Picture* Animation::picture() const noexcept } -uint32_t Animation::curFrame() const noexcept +float Animation::curFrame() const noexcept { auto loader = pImpl->picture->pImpl->loader.get(); @@ -91,7 +91,7 @@ uint32_t Animation::curFrame() const noexcept } -uint32_t Animation::totalFrame() const noexcept +float Animation::totalFrame() const noexcept { auto loader = pImpl->picture->pImpl->loader.get(); diff --git a/thirdparty/thorvg/src/renderer/tvgCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgCanvas.cpp index 2d4cbd048fae..25741f611df5 100644 --- a/thirdparty/thorvg/src/renderer/tvgCanvas.cpp +++ b/thirdparty/thorvg/src/renderer/tvgCanvas.cpp @@ -63,9 +63,9 @@ Result Canvas::clear(bool free) noexcept Result Canvas::draw() noexcept { - TVGLOG("COMMON", "Draw S. -------------------------------- Canvas(%p)", this); + TVGLOG("RENDERER", "Draw S. -------------------------------- Canvas(%p)", this); auto ret = pImpl->draw(); - TVGLOG("COMMON", "Draw E. -------------------------------- Canvas(%p)", this); + TVGLOG("RENDERER", "Draw E. -------------------------------- Canvas(%p)", this); return ret; } @@ -73,9 +73,9 @@ Result Canvas::draw() noexcept Result Canvas::update(Paint* paint) noexcept { - TVGLOG("COMMON", "Update S. ------------------------------ Canvas(%p)", this); + TVGLOG("RENDERER", "Update S. ------------------------------ Canvas(%p)", this); auto ret = pImpl->update(paint, false); - TVGLOG("COMMON", "Update E. ------------------------------ Canvas(%p)", this); + TVGLOG("RENDERER", "Update E. ------------------------------ Canvas(%p)", this); return ret; } diff --git a/thirdparty/thorvg/src/renderer/tvgCommon.h b/thirdparty/thorvg/src/renderer/tvgCommon.h index f36b4b9b305b..2b67681a4034 100644 --- a/thirdparty/thorvg/src/renderer/tvgCommon.h +++ b/thirdparty/thorvg/src/renderer/tvgCommon.h @@ -62,7 +62,7 @@ using namespace tvg; #define TVG_CLASS_ID_LINEAR 4 #define TVG_CLASS_ID_RADIAL 5 -enum class FileType { Tvg = 0, Svg, Lottie, Raw, Png, Jpg, Webp, Unknown }; +enum class FileType { Tvg = 0, Svg, Lottie, Raw, Png, Jpg, Webp, Gif, Unknown }; using Size = Point; diff --git a/thirdparty/thorvg/src/renderer/tvgFrameModule.h b/thirdparty/thorvg/src/renderer/tvgFrameModule.h index 857c6caeb950..332cca30908f 100644 --- a/thirdparty/thorvg/src/renderer/tvgFrameModule.h +++ b/thirdparty/thorvg/src/renderer/tvgFrameModule.h @@ -33,10 +33,9 @@ class FrameModule: public LoadModule public: virtual ~FrameModule() {} - virtual bool frame(uint32_t frameNo) = 0; //set the current frame number - - virtual uint32_t totalFrame() = 0; //return the total frame count - virtual uint32_t curFrame() = 0; //return the current frame number + virtual bool frame(float no) = 0; //set the current frame number + virtual float totalFrame() = 0; //return the total frame count + virtual float curFrame() = 0; //return the current frame number virtual float duration() = 0; //return the animation duration in seconds virtual bool animatable() override { return true; } diff --git a/thirdparty/thorvg/src/renderer/tvgLoader.cpp b/thirdparty/thorvg/src/renderer/tvgLoader.cpp index 52bdb91d6a8d..65330e9e778c 100644 --- a/thirdparty/thorvg/src/renderer/tvgLoader.cpp +++ b/thirdparty/thorvg/src/renderer/tvgLoader.cpp @@ -136,7 +136,7 @@ static LoadModule* _find(FileType type) break; } } - TVGLOG("LOADER", "%s format is not supported", format); + TVGLOG("RENDERER", "%s format is not supported", format); #endif return nullptr; } @@ -170,7 +170,7 @@ static LoadModule* _findByType(const string& mimeType) else if (mimeType == "jpg" || mimeType == "jpeg") type = FileType::Jpg; else if (mimeType == "webp") type = FileType::Webp; else { - TVGLOG("LOADER", "Given mimetype is unknown = \"%s\".", mimeType.c_str()); + TVGLOG("RENDERER", "Given mimetype is unknown = \"%s\".", mimeType.c_str()); return nullptr; } diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.cpp b/thirdparty/thorvg/src/renderer/tvgPaint.cpp index 37df906dac52..008e6589b5d1 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPaint.cpp @@ -22,11 +22,22 @@ #include "tvgMath.h" #include "tvgPaint.h" +#include "tvgShape.h" +#include "tvgPicture.h" +#include "tvgScene.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +#define PAINT_METHOD(ret, METHOD) \ + switch (id) { \ + case TVG_CLASS_ID_SHAPE: ret = P((Shape*)paint)->METHOD; break; \ + case TVG_CLASS_ID_SCENE: ret = P((Scene*)paint)->METHOD; break; \ + case TVG_CLASS_ID_PICTURE: ret = P((Picture*)paint)->METHOD; break; \ + default: ret = {}; \ + } + static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport) { @@ -93,9 +104,36 @@ static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, } +RenderRegion Paint::Impl::bounds(RenderMethod& renderer) const +{ + RenderRegion ret; + PAINT_METHOD(ret, bounds(renderer)); + return ret; +} + + +bool Paint::Impl::dispose(RenderMethod& renderer) +{ + if (compData) compData->target->pImpl->dispose(renderer); + + bool ret; + PAINT_METHOD(ret, dispose(renderer)); + return ret; +} + + +Iterator* Paint::Impl::iterator() +{ + Iterator* ret; + PAINT_METHOD(ret, iterator()); + return ret; +} + + Paint* Paint::Impl::duplicate() { - auto ret = smethod->duplicate(); + Paint* ret; + PAINT_METHOD(ret, duplicate()); //duplicate Transform if (rTransform) { @@ -165,8 +203,10 @@ bool Paint::Impl::render(RenderMethod& renderer) /* Note: only ClipPath is processed in update() step. Create a composition image. */ if (compData && compData->method != CompositeMethod::ClipPath && !(compData->target->pImpl->ctxFlag & ContextFlag::FastTrack)) { - auto region = smethod->bounds(renderer); - if (MASK_REGION_MERGING(compData->method)) region.add(compData->target->pImpl->smethod->bounds(renderer)); + RenderRegion region; + PAINT_METHOD(region, bounds(renderer)); + + if (MASK_REGION_MERGING(compData->method)) region.add(P(compData->target)->bounds(renderer)); if (region.w == 0 || region.h == 0) return true; cmp = renderer.target(region, COMPOSITE_TO_COLORSPACE(renderer, compData->method)); if (renderer.beginComposite(cmp, CompositeMethod::None, 255)) { @@ -177,7 +217,9 @@ bool Paint::Impl::render(RenderMethod& renderer) if (cmp) renderer.beginComposite(cmp, compData->method, compData->target->pImpl->opacity); renderer.blend(blendMethod); - auto ret = smethod->render(renderer); + + bool ret; + PAINT_METHOD(ret, render(renderer)); if (cmp) renderer.endComposite(cmp); @@ -189,10 +231,7 @@ RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pT { if (renderFlag & RenderUpdateFlag::Transform) { if (!rTransform) return nullptr; - if (!rTransform->update()) { - delete(rTransform); - rTransform = nullptr; - } + rTransform->update(); } /* 1. Composition Pre Processing */ @@ -239,18 +278,13 @@ RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pT } /* 2. Main Update */ - RenderData rd = nullptr; auto newFlag = static_cast(pFlag | renderFlag); renderFlag = RenderUpdateFlag::None; opacity = MULTIPLY(opacity, this->opacity); - if (rTransform && pTransform) { - RenderTransform outTransform(pTransform, rTransform); - rd = smethod->update(renderer, &outTransform, clips, opacity, newFlag, clipper); - } else { - auto outTransform = pTransform ? pTransform : rTransform; - rd = smethod->update(renderer, outTransform, clips, opacity, newFlag, clipper); - } + RenderData rd = nullptr; + RenderTransform outTransform(pTransform, rTransform); + PAINT_METHOD(rd, update(renderer, &outTransform, clips, opacity, newFlag, clipper)); /* 3. Composition Post Processing */ if (compFastTrack) renderer.viewport(viewport); @@ -263,9 +297,13 @@ RenderData Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pT bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transformed, bool stroking) { Matrix* m = nullptr; + bool ret; //Case: No transformed, quick return! - if (!transformed || !(m = this->transform())) return smethod->bounds(x, y, w, h, stroking); + if (!transformed || !(m = this->transform())) { + PAINT_METHOD(ret, bounds(x, y, w, h, stroking)); + return ret; + } //Case: Transformed auto tx = 0.0f; @@ -273,7 +311,7 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme auto tw = 0.0f; auto th = 0.0f; - auto ret = smethod->bounds(&tx, &ty, &tw, &th, stroking); + PAINT_METHOD(ret, bounds(&tx, &ty, &tw, &th, stroking)); //Get vertices Point pt[4] = {{tx, ty}, {tx + tw, ty}, {tx + tw, ty + th}, {tx, ty + th}}; @@ -307,7 +345,7 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme /* External Class Implementation */ /************************************************************************/ -Paint :: Paint() : pImpl(new Impl()) +Paint :: Paint() : pImpl(new Impl(this)) { } @@ -419,7 +457,10 @@ uint32_t Paint::identifier() const noexcept Result Paint::blend(BlendMethod method) const noexcept { - pImpl->blendMethod = method; + if (pImpl->blendMethod != method) { + pImpl->blendMethod = method; + pImpl->renderFlag |= RenderUpdateFlag::Blend; + } return Result::Success; } diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.h b/thirdparty/thorvg/src/renderer/tvgPaint.h index 0ee07fedff97..f4721f8e15b1 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.h +++ b/thirdparty/thorvg/src/renderer/tvgPaint.h @@ -38,19 +38,6 @@ namespace tvg virtual void begin() = 0; }; - struct StrategyMethod - { - virtual ~StrategyMethod() {} - - virtual bool dispose(RenderMethod& renderer) = 0; //return true if the deletion is allowed. - virtual void* update(RenderMethod& renderer, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) = 0; //Return engine data if it has. - virtual bool render(RenderMethod& renderer) = 0; - virtual bool bounds(float* x, float* y, float* w, float* h, bool stroking) = 0; - virtual RenderRegion bounds(RenderMethod& renderer) const = 0; - virtual Paint* duplicate() = 0; - virtual Iterator* iterator() = 0; - }; - struct Composite { Paint* target; @@ -60,7 +47,7 @@ namespace tvg struct Paint::Impl { - StrategyMethod* smethod = nullptr; + Paint* paint = nullptr; RenderTransform* rTransform = nullptr; Composite* compData = nullptr; BlendMethod blendMethod = BlendMethod::Normal; //uint8_t @@ -70,13 +57,16 @@ namespace tvg uint8_t opacity = 255; uint8_t refCnt = 0; + Impl(Paint* pnt) : paint(pnt) + { + } + ~Impl() { if (compData) { - delete(compData->target); + if (P(compData->target)->unref() == 0) delete(compData->target); free(compData); } - delete(smethod); delete(rTransform); } @@ -92,11 +82,6 @@ namespace tvg return (--refCnt); } - void method(StrategyMethod* method) - { - smethod = method; - } - bool transform(const Matrix& m) { if (!rTransform) { @@ -119,29 +104,16 @@ namespace tvg return nullptr; } - RenderRegion bounds(RenderMethod& renderer) const - { - return smethod->bounds(renderer); - } - - bool dispose(RenderMethod& renderer) - { - if (compData) compData->target->pImpl->dispose(renderer); - return smethod->dispose(renderer); - } - - Iterator* iterator() - { - return smethod->iterator(); - } - bool composite(Paint* source, Paint* target, CompositeMethod method) { //Invalid case if ((!target && method != CompositeMethod::None) || (target && method == CompositeMethod::None)) return false; if (compData) { - delete(compData->target); + P(compData->target)->unref(); + if ((compData->target != target) && P(compData->target)->refCnt == 0) { + delete(compData->target); + } //Reset scenario if (!target && method == CompositeMethod::None) { free(compData); @@ -152,12 +124,16 @@ namespace tvg if (!target && method == CompositeMethod::None) return true; compData = static_cast(calloc(1, sizeof(Composite))); } + P(target)->ref(); compData->target = target; compData->source = source; compData->method = method; return true; } + RenderRegion bounds(RenderMethod& renderer) const; + bool dispose(RenderMethod& renderer); + Iterator* iterator(); bool rotate(float degree); bool scale(float factor); bool translate(float x, float y); @@ -166,51 +142,6 @@ namespace tvg bool render(RenderMethod& renderer); Paint* duplicate(); }; - - - template - struct PaintMethod : StrategyMethod - { - T* inst = nullptr; - - PaintMethod(T* _inst) : inst(_inst) {} - ~PaintMethod() {} - - bool bounds(float* x, float* y, float* w, float* h, bool stroking) override - { - return inst->bounds(x, y, w, h, stroking); - } - - RenderRegion bounds(RenderMethod& renderer) const override - { - return inst->bounds(renderer); - } - - bool dispose(RenderMethod& renderer) override - { - return inst->dispose(renderer); - } - - RenderData update(RenderMethod& renderer, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag renderFlag, bool clipper) override - { - return inst->update(renderer, transform, clips, opacity, renderFlag, clipper); - } - - bool render(RenderMethod& renderer) override - { - return inst->render(renderer); - } - - Paint* duplicate() override - { - return inst->duplicate(); - } - - Iterator* iterator() override - { - return inst->iterator(); - } - }; } #endif //_TVG_PAINT_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.cpp b/thirdparty/thorvg/src/renderer/tvgPicture.cpp index 07877b92de1d..e38279569820 100644 --- a/thirdparty/thorvg/src/renderer/tvgPicture.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPicture.cpp @@ -62,7 +62,6 @@ RenderUpdateFlag Picture::Impl::load() Picture::Picture() : pImpl(new Impl(this)) { Paint::pImpl->id = TVG_CLASS_ID_PICTURE; - Paint::pImpl->method(new PaintMethod(pImpl)); } diff --git a/thirdparty/thorvg/src/renderer/tvgRender.cpp b/thirdparty/thorvg/src/renderer/tvgRender.cpp index 9768b5ede092..64d76d356207 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.cpp +++ b/thirdparty/thorvg/src/renderer/tvgRender.cpp @@ -39,12 +39,9 @@ void RenderTransform::override(const Matrix& m) } -bool RenderTransform::update() +void RenderTransform::update() { - if (overriding) return true; - - //Init Status - if (mathZero(x) && mathZero(y) && mathZero(degree) && mathEqual(scale, 1)) return false; + if (overriding) return; mathIdentity(&m); @@ -53,17 +50,13 @@ bool RenderTransform::update() if (!mathZero(degree)) mathRotate(&m, degree); mathTranslate(&m, x, y); - - return true; -} - - -RenderTransform::RenderTransform() -{ } RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs) { - m = mathMultiply(&lhs->m, &rhs->m); + if (lhs && rhs) m = mathMultiply(&lhs->m, &rhs->m); + else if (lhs) m = lhs->m; + else if (rhs) m = rhs->m; + else mathIdentity(&m); } diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h index 1231089ff526..6c0a7d5f1351 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.h +++ b/thirdparty/thorvg/src/renderer/tvgRender.h @@ -32,7 +32,7 @@ namespace tvg using RenderData = void*; using pixel_t = uint32_t; -enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, All = 255}; +enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, Blend = 128, All = 255}; struct Surface; @@ -123,10 +123,10 @@ struct RenderTransform float scale = 1.0f; //scale factor bool overriding = false; //user transform? - bool update(); + void update(); void override(const Matrix& m); - RenderTransform(); + RenderTransform() {} RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs); }; diff --git a/thirdparty/thorvg/src/renderer/tvgSaveModule.h b/thirdparty/thorvg/src/renderer/tvgSaveModule.h index a997b644a71f..09e7bde72bb5 100644 --- a/thirdparty/thorvg/src/renderer/tvgSaveModule.h +++ b/thirdparty/thorvg/src/renderer/tvgSaveModule.h @@ -34,6 +34,7 @@ class SaveModule virtual ~SaveModule() {} virtual bool save(Paint* paint, const string& path, bool compress) = 0; + virtual bool save(Animation* animation, const string& path, uint32_t quality, uint32_t fps) = 0; virtual bool close() = 0; }; diff --git a/thirdparty/thorvg/src/renderer/tvgSaver.cpp b/thirdparty/thorvg/src/renderer/tvgSaver.cpp index 3b4dfddcc234..038d1ad097b9 100644 --- a/thirdparty/thorvg/src/renderer/tvgSaver.cpp +++ b/thirdparty/thorvg/src/renderer/tvgSaver.cpp @@ -26,6 +26,9 @@ #ifdef THORVG_TVG_SAVER_SUPPORT #include "tvgTvgSaver.h" #endif +#ifdef THORVG_GIF_SAVER_SUPPORT + #include "tvgGifSaver.h" +#endif /************************************************************************/ /* Internal Class Implementation */ @@ -47,6 +50,12 @@ static SaveModule* _find(FileType type) case FileType::Tvg: { #ifdef THORVG_TVG_SAVER_SUPPORT return new TvgSaver; +#endif + break; + } + case FileType::Gif: { +#ifdef THORVG_GIF_SAVER_SUPPORT + return new GifSaver; #endif break; } @@ -62,12 +71,16 @@ static SaveModule* _find(FileType type) format = "TVG"; break; } + case FileType::Gif: { + format = "GIF"; + break; + } default: { format = "???"; break; } } - TVGLOG("SAVER", "%s format is not supported", format); + TVGLOG("RENDERER", "%s format is not supported", format); #endif return nullptr; } @@ -78,6 +91,8 @@ static SaveModule* _find(const string& path) auto ext = path.substr(path.find_last_of(".") + 1); if (!ext.compare("tvg")) { return _find(FileType::Tvg); + } else if (!ext.compare("gif")) { + return _find(FileType::Gif); } return nullptr; } @@ -124,6 +139,37 @@ Result Saver::save(std::unique_ptr paint, const string& path, bool compre } +Result Saver::save(std::unique_ptr animation, const string& path, uint32_t quality, uint32_t fps) noexcept +{ + auto a = animation.release(); + if (!a) return Result::MemoryCorruption; + + if (mathZero(a->totalFrame())) { + delete(a); + return Result::InsufficientCondition; + } + + //Already on saving an other resource. + if (pImpl->saveModule) { + delete(a); + return Result::InsufficientCondition; + } + + if (auto saveModule = _find(path)) { + if (saveModule->save(a, path, quality, fps)) { + pImpl->saveModule = saveModule; + return Result::Success; + } else { + delete(a); + delete(saveModule); + return Result::Unknown; + } + } + delete(a); + return Result::NonSupport; +} + + Result Saver::sync() noexcept { if (!pImpl->saveModule) return Result::InsufficientCondition; diff --git a/thirdparty/thorvg/src/renderer/tvgScene.cpp b/thirdparty/thorvg/src/renderer/tvgScene.cpp index 52e7ea2bf691..cd73913b303f 100644 --- a/thirdparty/thorvg/src/renderer/tvgScene.cpp +++ b/thirdparty/thorvg/src/renderer/tvgScene.cpp @@ -29,7 +29,6 @@ Scene::Scene() : pImpl(new Impl(this)) { Paint::pImpl->id = TVG_CLASS_ID_SCENE; - Paint::pImpl->method(new PaintMethod(pImpl)); } diff --git a/thirdparty/thorvg/src/renderer/tvgScene.h b/thirdparty/thorvg/src/renderer/tvgScene.h index 10daa49a99b7..b558e95a2f58 100644 --- a/thirdparty/thorvg/src/renderer/tvgScene.h +++ b/thirdparty/thorvg/src/renderer/tvgScene.h @@ -66,7 +66,7 @@ struct Scene::Impl RenderData rd = nullptr; Scene* scene = nullptr; uint8_t opacity; //for composition - bool needComp; //composite or not + bool needComp = false; //composite or not Impl(Scene* s) : scene(s) { @@ -75,7 +75,7 @@ struct Scene::Impl ~Impl() { for (auto paint : paints) { - if (paint->pImpl->unref() == 0) delete(paint); + if (P(paint)->unref() == 0) delete(paint); } } @@ -148,6 +148,7 @@ struct Scene::Impl if (needComp) { cmp = renderer.target(bounds(renderer), renderer.colorSpace()); renderer.beginComposite(cmp, CompositeMethod::None, opacity); + needComp = false; } for (auto paint : paints) { diff --git a/thirdparty/thorvg/src/renderer/tvgShape.cpp b/thirdparty/thorvg/src/renderer/tvgShape.cpp index efb7666b296a..9a64c7df9fa3 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.cpp +++ b/thirdparty/thorvg/src/renderer/tvgShape.cpp @@ -35,7 +35,6 @@ constexpr auto PATH_KAPPA = 0.552284f; Shape :: Shape() : pImpl(new Impl(this)) { Paint::pImpl->id = TVG_CLASS_ID_SHAPE; - Paint::pImpl->method(new PaintMethod(pImpl)); } @@ -62,7 +61,7 @@ Result Shape::reset() noexcept pImpl->rs.path.cmds.clear(); pImpl->rs.path.pts.clear(); - pImpl->flag = RenderUpdateFlag::Path; + pImpl->flag |= RenderUpdateFlag::Path; return Result::Success; } @@ -70,18 +69,14 @@ Result Shape::reset() noexcept uint32_t Shape::pathCommands(const PathCommand** cmds) const noexcept { - if (!cmds) return 0; - - *cmds = pImpl->rs.path.cmds.data; + if (cmds) *cmds = pImpl->rs.path.cmds.data; return pImpl->rs.path.cmds.count; } uint32_t Shape::pathCoords(const Point** pts) const noexcept { - if (!pts) return 0; - - *pts = pImpl->rs.path.pts.data; + if (pts) *pts = pImpl->rs.path.pts.data; return pImpl->rs.path.pts.count; } @@ -224,8 +219,8 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) } else if (mathEqual(rx, halfW) && mathEqual(ry, halfH)) { return appendCircle(x + (w * 0.5f), y + (h * 0.5f), rx, ry); } else { - auto hrx = rx * 0.5f; - auto hry = ry * 0.5f; + auto hrx = rx * PATH_KAPPA; + auto hry = ry * PATH_KAPPA; pImpl->grow(10, 17); pImpl->moveTo(x + rx, y); pImpl->lineTo(x + w - rx, y); diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h index bb266866d0e2..46b2d7d0dbdc 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.h +++ b/thirdparty/thorvg/src/renderer/tvgShape.h @@ -38,7 +38,7 @@ struct Shape::Impl Shape* shape; uint8_t flag = RenderUpdateFlag::None; uint8_t opacity; //for composition - bool needComp; //composite or not + bool needComp = false; //composite or not Impl(Shape* s) : shape(s) { @@ -59,6 +59,7 @@ struct Shape::Impl if (needComp) { cmp = renderer.target(bounds(renderer), renderer.colorSpace()); renderer.beginComposite(cmp, CompositeMethod::None, opacity); + needComp = false; } ret = renderer.renderShape(rd); if (cmp) renderer.endComposite(cmp); diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index 04d1dd0b9afd..d4323848da78 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/thirdparty/thorvg/update-thorvg.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -VERSION=0.11.2 +VERSION=0.11.6 cd thirdparty/thorvg/ || true rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/ @@ -56,9 +56,8 @@ rm -rfv ../src/renderer/gl_engine # Enabled embedded loaders: raw, JPEG, PNG. mkdir ../src/loaders cp -rv src/loaders/svg src/loaders/raw ../src/loaders/ -cp -rv src/loaders/svg src/loaders/jpg ../src/loaders/ -cp -rv src/loaders/svg src/loaders/png ../src/loaders/ -cp -rv src/loaders/svg src/loaders/external_png ../src/loaders/ +cp -rv src/loaders/jpg ../src/loaders/ +cp -rv src/loaders/png src/loaders/external_png ../src/loaders/ popd rm -rf tmp From 08772e3fd39772c58f75e5a5681a6ab72fce15b0 Mon Sep 17 00:00:00 2001 From: Martin Capitanio Date: Fri, 5 Jan 2024 18:01:00 +0100 Subject: [PATCH 45/95] ThorVG: update from v0.11.6 to v0.12.0 https://github.com/thorvg/thorvg/releases/tag/v0.12.0 Godot-related SVG bug fixes: + [SwEngine] Fixed a linear filling scaling issue. thorvg/thorvg#1834 + [SwEngine] Path data not invalid even though it doesn't start with MoveTo. thorvg/thorvg#1848 Fixes #86128 Gradient issue. (cherry picked from commit e090b112efe049233ea4b36e83f901ca507ac14e) --- COPYRIGHT.txt | 2 +- modules/svg/SCsub | 2 + .../gdextension_build/SConstruct | 2 + .../gdextension_build/SConstruct | 2 + thirdparty/README.md | 2 +- thirdparty/thorvg/AUTHORS | 2 + thirdparty/thorvg/LICENSE | 2 +- thirdparty/thorvg/inc/config.h | 2 +- thirdparty/thorvg/inc/thorvg.h | 355 +++++++++++++----- thirdparty/thorvg/src/common/tvgArray.h | 7 +- thirdparty/thorvg/src/common/tvgBezier.cpp | 2 +- thirdparty/thorvg/src/common/tvgBezier.h | 2 +- .../thorvg/src/common/tvgCompressor.cpp | 2 +- thirdparty/thorvg/src/common/tvgCompressor.h | 2 +- thirdparty/thorvg/src/common/tvgInlist.h | 111 ++++++ thirdparty/thorvg/src/common/tvgList.h | 90 ----- thirdparty/thorvg/src/common/tvgMath.cpp | 2 +- thirdparty/thorvg/src/common/tvgMath.h | 14 +- thirdparty/thorvg/src/common/tvgStr.cpp | 2 +- thirdparty/thorvg/src/common/tvgStr.h | 2 +- .../src/loaders/external_png/tvgPngLoader.cpp | 62 ++- .../src/loaders/external_png/tvgPngLoader.h | 12 +- .../thorvg/src/loaders/jpg/tvgJpgLoader.cpp | 67 ++-- .../thorvg/src/loaders/jpg/tvgJpgLoader.h | 12 +- thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp | 2 +- thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h | 2 +- .../thorvg/src/loaders/png/tvgLodePng.cpp | 2 +- .../thorvg/src/loaders/png/tvgLodePng.h | 2 +- .../thorvg/src/loaders/png/tvgPngLoader.cpp | 91 ++--- .../thorvg/src/loaders/png/tvgPngLoader.h | 12 +- .../thorvg/src/loaders/raw/tvgRawLoader.cpp | 55 ++- .../thorvg/src/loaders/raw/tvgRawLoader.h | 11 +- .../thorvg/src/loaders/svg/tvgSvgCssStyle.cpp | 2 +- .../thorvg/src/loaders/svg/tvgSvgCssStyle.h | 2 +- .../thorvg/src/loaders/svg/tvgSvgLoader.cpp | 24 +- .../thorvg/src/loaders/svg/tvgSvgLoader.h | 9 +- .../src/loaders/svg/tvgSvgLoaderCommon.h | 2 +- .../thorvg/src/loaders/svg/tvgSvgPath.cpp | 10 +- .../thorvg/src/loaders/svg/tvgSvgPath.h | 4 +- .../src/loaders/svg/tvgSvgSceneBuilder.cpp | 16 +- .../src/loaders/svg/tvgSvgSceneBuilder.h | 4 +- .../thorvg/src/loaders/svg/tvgSvgUtil.cpp | 2 +- .../thorvg/src/loaders/svg/tvgSvgUtil.h | 2 +- .../thorvg/src/loaders/svg/tvgXmlParser.cpp | 2 +- .../thorvg/src/loaders/svg/tvgXmlParser.h | 2 +- .../src/renderer/sw_engine/tvgSwCommon.h | 17 +- .../src/renderer/sw_engine/tvgSwFill.cpp | 3 +- .../src/renderer/sw_engine/tvgSwImage.cpp | 2 +- .../src/renderer/sw_engine/tvgSwMath.cpp | 2 +- .../src/renderer/sw_engine/tvgSwMemPool.cpp | 2 +- .../src/renderer/sw_engine/tvgSwRaster.cpp | 13 +- .../src/renderer/sw_engine/tvgSwRasterAvx.h | 2 +- .../src/renderer/sw_engine/tvgSwRasterC.h | 2 +- .../src/renderer/sw_engine/tvgSwRasterNeon.h | 2 +- .../renderer/sw_engine/tvgSwRasterTexmap.h | 2 +- .../src/renderer/sw_engine/tvgSwRenderer.cpp | 19 +- .../src/renderer/sw_engine/tvgSwRenderer.h | 2 +- .../src/renderer/sw_engine/tvgSwRle.cpp | 2 +- .../src/renderer/sw_engine/tvgSwShape.cpp | 2 +- .../src/renderer/sw_engine/tvgSwStroke.cpp | 2 +- .../thorvg/src/renderer/tvgAccessor.cpp | 2 +- .../thorvg/src/renderer/tvgAnimation.cpp | 10 +- .../thorvg/src/renderer/tvgBinaryDesc.h | 4 +- thirdparty/thorvg/src/renderer/tvgCanvas.cpp | 2 +- thirdparty/thorvg/src/renderer/tvgCanvas.h | 11 +- thirdparty/thorvg/src/renderer/tvgCommon.h | 5 +- thirdparty/thorvg/src/renderer/tvgFill.cpp | 2 +- thirdparty/thorvg/src/renderer/tvgFill.h | 2 +- .../thorvg/src/renderer/tvgFrameModule.h | 5 +- .../thorvg/src/renderer/tvgGlCanvas.cpp | 2 +- .../thorvg/src/renderer/tvgInitializer.cpp | 35 +- .../thorvg/src/renderer/tvgIteratorAccessor.h | 2 +- .../thorvg/src/renderer/tvgLoadModule.h | 74 +++- thirdparty/thorvg/src/renderer/tvgLoader.cpp | 184 +++++++-- thirdparty/thorvg/src/renderer/tvgLoader.h | 11 +- thirdparty/thorvg/src/renderer/tvgPaint.cpp | 4 +- thirdparty/thorvg/src/renderer/tvgPaint.h | 2 +- thirdparty/thorvg/src/renderer/tvgPicture.cpp | 99 ++++- thirdparty/thorvg/src/renderer/tvgPicture.h | 124 ++---- thirdparty/thorvg/src/renderer/tvgRender.cpp | 2 +- thirdparty/thorvg/src/renderer/tvgRender.h | 37 +- .../thorvg/src/renderer/tvgSaveModule.h | 4 +- thirdparty/thorvg/src/renderer/tvgSaver.cpp | 18 +- thirdparty/thorvg/src/renderer/tvgScene.cpp | 2 +- thirdparty/thorvg/src/renderer/tvgScene.h | 21 +- thirdparty/thorvg/src/renderer/tvgShape.cpp | 2 +- thirdparty/thorvg/src/renderer/tvgShape.h | 17 +- .../thorvg/src/renderer/tvgSwCanvas.cpp | 2 +- .../thorvg/src/renderer/tvgTaskScheduler.cpp | 62 +-- .../thorvg/src/renderer/tvgTaskScheduler.h | 5 +- thirdparty/thorvg/src/renderer/tvgText.cpp | 109 ++++++ thirdparty/thorvg/src/renderer/tvgText.h | 191 ++++++++++ .../thorvg/src/renderer/tvgWgCanvas.cpp | 81 ++++ thirdparty/thorvg/update-thorvg.sh | 3 +- 94 files changed, 1513 insertions(+), 715 deletions(-) create mode 100644 thirdparty/thorvg/src/common/tvgInlist.h delete mode 100644 thirdparty/thorvg/src/common/tvgList.h create mode 100644 thirdparty/thorvg/src/renderer/tvgText.cpp create mode 100644 thirdparty/thorvg/src/renderer/tvgText.h create mode 100644 thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index a7d539224156..91f227d40507 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -473,7 +473,7 @@ License: Expat Files: ./thirdparty/thorvg/ Comment: ThorVG -Copyright: 2020-2023, The ThorVG Project +Copyright: 2020-2024, The ThorVG Project License: Expat Files: ./thirdparty/tinyexr/ diff --git a/modules/svg/SCsub b/modules/svg/SCsub index d0c6250b11d3..ff0c3c9141c6 100644 --- a/modules/svg/SCsub +++ b/modules/svg/SCsub @@ -43,6 +43,8 @@ thirdparty_sources = [ "src/renderer/tvgShape.cpp", "src/renderer/tvgSwCanvas.cpp", "src/renderer/tvgTaskScheduler.cpp", + "src/renderer/tvgText.cpp", + # "src/renderer/tvgWgCanvas.cpp", # renderer sw_engine "src/renderer/sw_engine/tvgSwFill.cpp", "src/renderer/sw_engine/tvgSwImage.cpp", diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct index 4093842650f1..b2fd139a2b5a 100644 --- a/modules/text_server_adv/gdextension_build/SConstruct +++ b/modules/text_server_adv/gdextension_build/SConstruct @@ -74,6 +74,8 @@ if env["thorvg_enabled"] and env["freetype_enabled"]: "src/renderer/tvgShape.cpp", "src/renderer/tvgSwCanvas.cpp", "src/renderer/tvgTaskScheduler.cpp", + "src/renderer/tvgText.cpp", + # "src/renderer/tvgWgCanvas.cpp", # renderer sw_engine "src/renderer/sw_engine/tvgSwFill.cpp", "src/renderer/sw_engine/tvgSwImage.cpp", diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct index 0d2fbd97fd07..0efced0bfc11 100644 --- a/modules/text_server_fb/gdextension_build/SConstruct +++ b/modules/text_server_fb/gdextension_build/SConstruct @@ -69,6 +69,8 @@ if env["thorvg_enabled"] and env["freetype_enabled"]: "src/renderer/tvgShape.cpp", "src/renderer/tvgSwCanvas.cpp", "src/renderer/tvgTaskScheduler.cpp", + "src/renderer/tvgText.cpp", + # "src/renderer/tvgWgCanvas.cpp", # renderer sw_engine "src/renderer/sw_engine/tvgSwFill.cpp", "src/renderer/sw_engine/tvgSwImage.cpp", diff --git a/thirdparty/README.md b/thirdparty/README.md index e3390d7eaca4..f73666f01ce1 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -825,7 +825,7 @@ instead of `miniz.h` as an external dependency. ## thorvg - Upstream: https://github.com/thorvg/thorvg -- Version: 0.11.6 (3dba4f12f8f05f86acbc51096ca3a15f5d96bc06, 2023) +- Version: 0.12.0 (25ea242d3867ed66807714f5a52d080984d3c8cc, 2024) - License: MIT Files extracted from upstream source: diff --git a/thirdparty/thorvg/AUTHORS b/thirdparty/thorvg/AUTHORS index 3a459e9bb494..d5d5e9be97d9 100644 --- a/thirdparty/thorvg/AUTHORS +++ b/thirdparty/thorvg/AUTHORS @@ -23,3 +23,5 @@ Rafał Mikrut Martin Capitanio RuiwenTang YouJin Lee +SergeyLebedkin +Jinny You diff --git a/thirdparty/thorvg/LICENSE b/thirdparty/thorvg/LICENSE index d056ff6cbfff..f97be650054f 100644 --- a/thirdparty/thorvg/LICENSE +++ b/thirdparty/thorvg/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2020 - 2023 notice for the ThorVG Project (see AUTHORS) +Copyright (c) 2020 - 2024 notice for the ThorVG Project (see AUTHORS) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index 98f35a6e457a..d1abc5a29018 100644 --- a/thirdparty/thorvg/inc/config.h +++ b/thirdparty/thorvg/inc/config.h @@ -9,5 +9,5 @@ // For internal debugging: //#define THORVG_LOG_ENABLED -#define THORVG_VERSION_STRING "0.11.6" +#define THORVG_VERSION_STRING "0.12.0" #endif diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h index 20acda7667fe..6aee53f7e07d 100644 --- a/thirdparty/thorvg/inc/thorvg.h +++ b/thirdparty/thorvg/inc/thorvg.h @@ -1,17 +1,3 @@ -/*! - * @file thorvg.h - * - * The main APIs enabling the TVG initialization, preparation of the canvas and provisioning of its content: - * - drawing shapes: line, arc, curve, path, polygon... - * - drawing pictures: tvg, svg, png, jpg, bitmap... - * - drawing fillings: solid, linear and radial gradient... - * - drawing stroking: continuous stroking with arbitrary width, join, cap, dash styles. - * - drawing composition: blending, masking, path clipping... - * - drawing scene graph & affine transformation (translation, rotation, scale, ...) - * and finally drawing the canvas and TVG termination. - */ - - #ifndef _THORVG_H_ #define _THORVG_H_ @@ -172,10 +158,10 @@ enum class CompositeMethod InvAlphaMask, ///< Alpha Masking using the complement to the compositing target's pixels as an alpha value. LumaMask, ///< Alpha Masking using the grayscale (0.2125R + 0.7154G + 0.0721*B) of the compositing target's pixels. @since 0.9 InvLumaMask, ///< Alpha Masking using the grayscale (0.2125R + 0.7154G + 0.0721*B) of the complement to the compositing target's pixels. - AddMask, ///< Combines the target and source objects pixels using target alpha. (T * TA) + (S * (255 - TA)) @BETA_API - SubtractMask, ///< Subtracts the source color from the target color while considering their respective target alpha. (T * TA) - (S * (255 - TA)) @BETA_API - IntersectMask, ///< Computes the result by taking the minimum value between the target alpha and the source alpha and multiplies it with the target color. (T * min(TA, SA)) @BETA_API - DifferenceMask ///< Calculates the absolute difference between the target color and the source color multiplied by the complement of the target alpha. abs(T - S * (255 - TA)) @BETA_API + AddMask, ///< Combines the target and source objects pixels using target alpha. (T * TA) + (S * (255 - TA)) (Experimental API) + SubtractMask, ///< Subtracts the source color from the target color while considering their respective target alpha. (T * TA) - (S * (255 - TA)) (Experimental API) + IntersectMask, ///< Computes the result by taking the minimum value between the target alpha and the source alpha and multiplies it with the target color. (T * min(TA, SA)) (Experimental API) + DifferenceMask ///< Calculates the absolute difference between the target color and the source color multiplied by the complement of the target alpha. abs(T - S * (255 - TA)) (Experimental API) }; @@ -186,7 +172,7 @@ enum class CompositeMethod * * @see Paint::blend() * - * @BETA_API + * @note Experimental API */ enum class BlendMethod : uint8_t { @@ -213,7 +199,8 @@ enum class BlendMethod : uint8_t enum class CanvasEngine { Sw = (1 << 1), ///< CPU rasterizer. - Gl = (1 << 2) ///< OpenGL rasterizer. + Gl = (1 << 2), ///< OpenGL rasterizer. + Wg = (1 << 3), ///< WebGPU rasterizer. (Experimental API) }; @@ -247,7 +234,7 @@ struct Matrix * @param pt The vertex coordinate * @param uv The normalized texture coordinate in the range (0.0..1.0, 0.0..1.0) * - * @BETA_API + * @note Experimental API */ struct Vertex { @@ -261,7 +248,7 @@ struct Vertex * * @param vertex The three vertices that make up the polygon * - * @BETA_API + * @note Experimental API */ struct Polygon { @@ -291,7 +278,7 @@ class TVG_API Paint * * @param[in] degree The value of the angle in degrees. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result rotate(float degree) noexcept; @@ -300,7 +287,7 @@ class TVG_API Paint * * @param[in] factor The value of the scaling factor. The default value is 1. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result scale(float factor) noexcept; @@ -313,7 +300,7 @@ class TVG_API Paint * @param[in] x The value of the horizontal shift. * @param[in] y The value of the vertical shift. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result translate(float x, float y) noexcept; @@ -324,7 +311,7 @@ class TVG_API Paint * * @param[in] m The 3x3 augmented matrix. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result transform(const Matrix& m) noexcept; @@ -345,7 +332,7 @@ class TVG_API Paint * * @param[in] o The opacity value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note Setting the opacity with this API may require multiple render pass for composition. It is recommended to avoid changing the opacity if possible. * @note ClipPath won't use the opacity value. (see: enum class CompositeMethod::ClipPath) @@ -358,7 +345,7 @@ class TVG_API Paint * @param[in] target The paint of the target object. * @param[in] method The method used to composite the source object with the target. * - * @return Result::Success when succeed, Result::InvalidArguments otherwise. + * @retval Result::Success when succeed, Result::InvalidArguments otherwise. */ Result composite(std::unique_ptr target, CompositeMethod method) noexcept; @@ -371,9 +358,9 @@ class TVG_API Paint * * @param[in] method The blending method to be set. * - * @return Result::Success when the blending method is successfully set. + * @retval Result::Success when the blending method is successfully set. * - * @BETA_API + * @note Experimental API */ Result blend(BlendMethod method) const noexcept; @@ -404,7 +391,7 @@ class TVG_API Paint * @param[out] h The height of the object. * @param[in] transformed If @c true, the paint's transformations are taken into account, otherwise they aren't. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. * * @note The bounding box doesn't indicate the actual drawing region. It's the smallest rectangle that encloses the object. */ @@ -442,7 +429,7 @@ class TVG_API Paint * * @return The blending method * - * @BETA_API + * @note Experimental API */ BlendMethod blend() const noexcept; @@ -493,7 +480,7 @@ class TVG_API Fill * @param[in] colorStops An array of ColorStop data structure. * @param[in] cnt The count of the @p colorStops array equal to the colors number used in the gradient. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result colorStops(const ColorStop* colorStops, uint32_t cnt) noexcept; @@ -502,7 +489,7 @@ class TVG_API Fill * * @param[in] s The FillSpread value. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result spread(FillSpread s) noexcept; @@ -513,7 +500,7 @@ class TVG_API Fill * * @param[in] m The 3x3 augmented matrix. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result transform(const Matrix& m) noexcept; @@ -538,7 +525,7 @@ class TVG_API Fill * * In case no transformation was applied, the identity matrix is returned. * - * @retval The augmented transformation matrix. + * @return The augmented transformation matrix. */ Matrix transform() const noexcept; @@ -600,7 +587,7 @@ class TVG_API Canvas * @warning Please avoid accessing the paints during Canvas update/draw. You can access them after calling sync(). * @see Canvas::sync() * - * @BETA_API + * @note Experimental API */ std::list& paints() noexcept; @@ -631,7 +618,7 @@ class TVG_API Canvas * * @param[in] free If @c true, the memory occupied by paints is deallocated, otherwise it is not. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. * * @see Canvas::push() * @see Canvas::paints() @@ -646,7 +633,7 @@ class TVG_API Canvas * * @param[in] paint A pointer to the Paint object or @c nullptr. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. * * @note The Update behavior can be asynchronous if the assigned thread number is greater than zero. */ @@ -655,7 +642,7 @@ class TVG_API Canvas /** * @brief Requests the canvas to draw the Paint objects. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. * * @note Drawing can be asynchronous if the assigned thread number is greater than zero. To guarantee the drawing is done, call sync() afterwards. * @see Canvas::sync() @@ -668,7 +655,7 @@ class TVG_API Canvas * The Canvas rendering can be performed asynchronously. To make sure that rendering is finished, * the sync() must be called after the draw() regardless of threading. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. * @see Canvas::draw() */ virtual Result sync() noexcept; @@ -702,7 +689,7 @@ class TVG_API LinearGradient final : public Fill * @param[in] x2 The horizontal coordinate of the second point used to determine the gradient bounds. * @param[in] y2 The vertical coordinate of the second point used to determine the gradient bounds. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note In case the first and the second points are equal, an object filled with such a gradient fill is not rendered. */ @@ -720,7 +707,7 @@ class TVG_API LinearGradient final : public Fill * @param[out] x2 The horizontal coordinate of the second point used to determine the gradient bounds. * @param[out] y2 The vertical coordinate of the second point used to determine the gradient bounds. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result linear(float* x1, float* y1, float* x2, float* y2) const noexcept; @@ -764,7 +751,7 @@ class TVG_API RadialGradient final : public Fill * @param[in] cy The vertical coordinate of the center of the bounding circle. * @param[in] radius The radius of the bounding circle. * - * @return Result::Success when succeed, Result::InvalidArguments in case the @p radius value is zero or less. + * @retval Result::Success when succeed, Result::InvalidArguments in case the @p radius value is zero or less. */ Result radial(float cx, float cy, float radius) noexcept; @@ -777,7 +764,7 @@ class TVG_API RadialGradient final : public Fill * @param[out] cy The vertical coordinate of the center of the bounding circle. * @param[out] radius The radius of the bounding circle. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result radial(float* cx, float* cy, float* radius) const noexcept; @@ -823,7 +810,7 @@ class TVG_API Shape final : public Paint * * The transformation matrix, the color, the fill and the stroke properties are retained. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note The memory, where the path data is stored, is not deallocated at this stage for caching effect. */ @@ -837,7 +824,7 @@ class TVG_API Shape final : public Paint * @param[in] x The horizontal coordinate of the initial point of the sub-path. * @param[in] y The vertical coordinate of the initial point of the sub-path. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result moveTo(float x, float y) noexcept; @@ -849,7 +836,7 @@ class TVG_API Shape final : public Paint * @param[in] x The horizontal coordinate of the end-point of the line. * @param[in] y The vertical coordinate of the end-point of the line. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note In case this is the first command in the path, it corresponds to the moveTo() call. */ @@ -868,7 +855,7 @@ class TVG_API Shape final : public Paint * @param[in] x The horizontal coordinate of the end-point of the curve. * @param[in] y The vertical coordinate of the end-point of the curve. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note In case this is the first command in the path, no data from the path are rendered. */ @@ -879,7 +866,7 @@ class TVG_API Shape final : public Paint * * The value of the current point is set to the initial point of the closed sub-path. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note In case the sub-path does not contain any points, this function has no effect. */ @@ -905,7 +892,7 @@ class TVG_API Shape final : public Paint * @param[in] rx The x-axis radius of the ellipse defining the rounded corners of the rectangle. * @param[in] ry The y-axis radius of the ellipse defining the rounded corners of the rectangle. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note For @p rx and @p ry greater than or equal to the half of @p w and the half of @p h, respectively, the shape become an ellipse. */ @@ -925,7 +912,7 @@ class TVG_API Shape final : public Paint * @param[in] rx The x-axis radius of the ellipse. * @param[in] ry The y-axis radius of the ellipse. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result appendCircle(float cx, float cy, float rx, float ry) noexcept; @@ -942,7 +929,7 @@ class TVG_API Shape final : public Paint * @param[in] sweep The central angle of the arc given in degrees, measured counter-clockwise from @p startAngle. * @param[in] pie Specifies whether to draw radii from the arc's center to both of its end-point - drawn if @c true. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note Setting @p sweep value greater than 360 degrees, is equivalent to calling appendCircle(cx, cy, radius, radius). */ @@ -960,7 +947,7 @@ class TVG_API Shape final : public Paint * @param[in] pts The array of the two-dimensional points. * @param[in] ptsCnt The number of the points in the @p pts array. * - * @return Result::Success when succeed, Result::InvalidArguments otherwise. + * @retval Result::Success when succeed, Result::InvalidArguments otherwise. * * @note The interface is designed for optimal path setting if the caller has a completed path commands already. */ @@ -971,7 +958,7 @@ class TVG_API Shape final : public Paint * * @param[in] width The width of the stroke. The default value is 0. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result stroke(float width) noexcept; @@ -983,7 +970,7 @@ class TVG_API Shape final : public Paint * @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0. * @param[in] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. The default value is 0. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255) noexcept; @@ -1018,7 +1005,7 @@ class TVG_API Shape final : public Paint * * @param[in] cap The cap style value. The default value is @c StrokeCap::Square. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result stroke(StrokeCap cap) noexcept; @@ -1029,7 +1016,7 @@ class TVG_API Shape final : public Paint * * @param[in] join The join style value. The default value is @c StrokeJoin::Bevel. * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. */ Result stroke(StrokeJoin join) noexcept; @@ -1039,7 +1026,7 @@ class TVG_API Shape final : public Paint * * @param[in] miterlimit The miterlimit imposes a limit on the extent of the stroke join, when the @c StrokeJoin::Miter join style is set. The default value is 4. * - * @return Result::Success when succeed, Result::NonSupport unsupported value, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::NonSupport unsupported value, Result::FailedAllocation otherwise. * * @since 0.11 */ @@ -1055,7 +1042,7 @@ class TVG_API Shape final : public Paint * @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0. * @param[in] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. The default value is 0. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. * * @note Either a solid color or a gradient fill is applied, depending on what was set as last. * @note ClipPath won't use the fill values. (see: enum class CompositeMethod::ClipPath) @@ -1069,7 +1056,7 @@ class TVG_API Shape final : public Paint * * @param[in] f The unique pointer to the gradient fill. * - * @return Result::Success when succeed, Result::MemoryCorruption otherwise. + * @retval Result::Success when succeed, Result::MemoryCorruption otherwise. * * @note Either a solid color or a gradient fill is applied, depending on what was set as last. */ @@ -1080,7 +1067,7 @@ class TVG_API Shape final : public Paint * * @param[in] r The fill rule value. The default value is @c FillRule::Winding. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result fill(FillRule r) noexcept; @@ -1090,7 +1077,7 @@ class TVG_API Shape final : public Paint * * @param[in] strokeFirst If @c true the stroke is rendered before the fill, otherwise the stroke is rendered as the second one (the default option). * - * @return Result::Success when succeed, Result::FailedAllocation otherwise. + * @retval Result::Success when succeed, Result::FailedAllocation otherwise. * * @since 0.10 */ @@ -1156,7 +1143,7 @@ class TVG_API Shape final : public Paint * @param[out] b The blue color channel value in the range [0 ~ 255]. * @param[out] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. */ Result strokeColor(uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* a = nullptr) const noexcept; @@ -1295,7 +1282,7 @@ class TVG_API Picture final : public Paint * @param[in] w A new width of the image in pixels. * @param[in] h A new height of the image in pixels. * - * @return Result::Success when succeed, Result::InsufficientCondition otherwise. + * @retval Result::Success when succeed, Result::InsufficientCondition otherwise. */ Result size(float w, float h) noexcept; @@ -1305,13 +1292,20 @@ class TVG_API Picture final : public Paint * @param[out] w The width of the image in pixels. * @param[out] h The height of the image in pixels. * - * @return Result::Success when succeed. + * @retval Result::Success when succeed. */ Result size(float* w, float* h) const noexcept; /** * @brief Loads a raw data from a memory block with a given size. * + * @param[in] paint A Tvg_Paint pointer to the picture object. + * @param[in] data A pointer to a memory location where the content of the picture raw data is stored. + * @param[in] w The width of the image @p data in pixels. + * @param[in] h The height of the image @p data in pixels. + * @param[in] premultiplied If @c true, the given image data is alpha-premultiplied. + * @param[in] copy If @c true the data are copied into the engine local buffer, otherwise they are not. + * * @retval Result::Success When succeed, Result::InsufficientCondition otherwise. * @retval Result::FailedAllocation An internal error possibly with memory allocation. * @@ -1339,7 +1333,7 @@ class TVG_API Picture final : public Paint * @note The Polygons are copied internally, so modifying them after calling Mesh::mesh has no affect. * @warning Please do not use it, this API is not official one. It could be modified in the next version. * - * @BETA_API + * @note Experimental API */ Result mesh(const Polygon* triangles, uint32_t triangleCnt) noexcept; @@ -1348,12 +1342,12 @@ class TVG_API Picture final : public Paint * * @param[out] triangles Optional. A pointer to the array of Polygons used by this mesh. * - * @return uint32_t The number of polygons in the array. + * @return The number of polygons in the array. * * @note Modifying the triangles returned by this method will modify them directly within the mesh. * @warning Please do not use it, this API is not official one. It could be modified in the next version. * - * @BETA_API + * @note Experimental API */ uint32_t mesh(const Polygon** triangles) const noexcept; @@ -1402,7 +1396,7 @@ class TVG_API Scene final : public Paint * * @param[in] paint A Paint object to be drawn. * - * @return Result::Success when succeed, Result::MemoryCorruption otherwise. + * @retval Result::Success when succeed, Result::MemoryCorruption otherwise. * * @note The rendering order of the paints is the same as the order as they were pushed. Consider sorting the paints before pushing them if you intend to use layering. * @see Scene::paints() @@ -1432,7 +1426,7 @@ class TVG_API Scene final : public Paint * @see Scene::push() * @see Scene::clear() * - * @BETA_API + * @note Experimental API */ std::list& paints() noexcept; @@ -1442,7 +1436,7 @@ class TVG_API Scene final : public Paint * * @param[in] free If @c true, the memory occupied by paints is deallocated, otherwise it is not. * - * @return Result::Success when succeed + * @retval Result::Success when succeed * * @warning If you don't free the paints they become dangled. They are supposed to be reused, otherwise you are responsible for their lives. Thus please use the @p free argument only when you know how it works, otherwise it's not recommended. * @@ -1470,6 +1464,138 @@ class TVG_API Scene final : public Paint }; +/** + * @class Text + * + * @brief A class to represent text objects in a graphical context, allowing for rendering and manipulation of unicode text. + * + * @note Experimental API + */ +class TVG_API Text final : public Paint +{ +public: + ~Text(); + + /** + * @brief Sets the font properties for the text. + * + * This function allows you to define the font characteristics used for text rendering. + * It sets the font name, size and optionally the style. + * + * @param[in] name The name of the font. This should correspond to a font available in the canvas. + * @param[in] size The size of the font in points. This determines how large the text will appear. + * @param[in] style The style of the font. It can be used to set the font to 'italic'. + * If not specified, the default style is used. Only 'italic' style is supported currently. + * + * @retval Result::Success when the font properties are set successfully. + * @retval Result::InsufficientCondition when the specified @p name cannot be found. + * + * @note Experimental API + */ + Result font(const char* name, float size, const char* style = nullptr) noexcept; + + /** + * @brief Assigns the given unicode text to be rendered. + * + * This function sets the unicode string that will be displayed by the rendering system. + * The text is set according to the specified UTF encoding method, which defaults to UTF-8. + * + * @param[in] text The multi-byte text encoded with utf8 string to be rendered. + * + * @retval Result::Success when succeed. + * + * @note Experimental API + */ + Result text(const char* text) noexcept; + + /** + * @brief Sets the text color. + * + * @param[in] r The red color channel value in the range [0 ~ 255]. The default value is 0. + * @param[in] g The green color channel value in the range [0 ~ 255]. The default value is 0. + * @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0. + * + * @retval Result::Success when succeed. + * @retval Result::InsufficientCondition when the font has not been set up prior to this operation. + * + * @see Text::font() + * + * @note Experimental API + */ + Result fill(uint8_t r, uint8_t g, uint8_t b) noexcept; + + /** + * @brief Sets the gradient fill for all of the figures from the text. + * + * The parts of the text defined as inner are filled. + * + * @param[in] f The unique pointer to the gradient fill. + * + * @retval Result::Success when succeed, Result::MemoryCorruption otherwise. + * @retval Result::InsufficientCondition when the font has not been set up prior to this operation. + * + * @note Either a solid color or a gradient fill is applied, depending on what was set as last. + * @note Experimental API + * + * @see Text::font() + */ + Result fill(std::unique_ptr f) noexcept; + + /** + * @brief Loads a scalable font data(ttf) from a file. + * + * @param[in] path The path to the font file. + * + * @retval Result::Success When succeed. + * @retval Result::InvalidArguments In case the @p path is invalid. + * @retval Result::NonSupport When trying to load a file with an unknown extension. + * @retval Result::Unknown If an error occurs at a later stage. + * + * @note Experimental API + * + * @see Text::unload(const std::string& path) + */ + static Result load(const std::string& path) noexcept; + + /** + * @brief Unloads the specified scalable font data (TTF) that was previously loaded. + * + * This function is used to release resources associated with a font file that has been loaded into memory. + * + * @param[in] path The file path of the loaded font. + * + * @retval Result::Success Successfully unloads the font data. + * @retval Result::InsufficientCondition Fails if the loader is not initialized. + * + * @note If the font data is currently in use, it will not be immediately unloaded. + * @note Experimental API + * + * @see Text::load(const std::string& path) + */ + static Result unload(const std::string& path) noexcept; + + /** + * @brief Creates a new Text object. + * + * @return A new Text object. + * + * @note Experimental API + */ + static std::unique_ptr gen() noexcept; + + /** + * @brief Return the unique id value of this class. + * + * This method can be referred for identifying the Text class type. + * + * @return The type id of the Text class. + */ + static uint32_t identifier() noexcept; + + _TVG_DECLARE_PRIVATE(Text); +}; + + /** * @class SwCanvas * @@ -1487,8 +1613,8 @@ class TVG_API SwCanvas final : public Canvas { ABGR8888 = 0, ///< The channels are joined in the order: alpha, blue, green, red. Colors are alpha-premultiplied. (a << 24 | b << 16 | g << 8 | r) ARGB8888, ///< The channels are joined in the order: alpha, red, green, blue. Colors are alpha-premultiplied. (a << 24 | r << 16 | g << 8 | b) - ABGR8888S, ///< @BETA_API The channels are joined in the order: alpha, blue, green, red. Colors are un-alpha-premultiplied. - ARGB8888S, ///< @BETA_API The channels are joined in the order: alpha, red, green, blue. Colors are un-alpha-premultiplied. + ABGR8888S, ///< The channels are joined in the order: alpha, blue, green, red. Colors are un-alpha-premultiplied. @since 0.12 + ARGB8888S, ///< The channels are joined in the order: alpha, red, green, blue. Colors are un-alpha-premultiplied. @since 0.12 }; /** @@ -1564,7 +1690,7 @@ class TVG_API SwCanvas final : public Canvas * * @warning Please do not use it. This class is not fully supported yet. * - * @BETA_API + * @note Experimental API */ class TVG_API GlCanvas final : public Canvas { @@ -1576,7 +1702,7 @@ class TVG_API GlCanvas final : public Canvas * * @warning Please do not use it, this API is not official one. It could be modified in the next version. * - * @BETA_API + * @note Experimental API */ Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; @@ -1585,7 +1711,7 @@ class TVG_API GlCanvas final : public Canvas * * @return A new GlCanvas object. * - * @BETA_API + * @note Experimental API */ static std::unique_ptr gen() noexcept; @@ -1593,6 +1719,42 @@ class TVG_API GlCanvas final : public Canvas }; +/** + * @class WgCanvas + * + * @brief A class for the rendering graphic elements with a WebGPU raster engine. + * + * @warning Please do not use it. This class is not fully supported yet. + * + * @note Experimental API + */ +class TVG_API WgCanvas final : public Canvas +{ +public: + ~WgCanvas(); + + /** + * @brief Sets the target window for the rasterization. + * + * @warning Please do not use it, this API is not official one. It could be modified in the next version. + * + * @note Experimental API + */ + Result target(void* window, uint32_t w, uint32_t h) noexcept; + + /** + * @brief Creates a new WgCanvas object. + * + * @return A new WgCanvas object. + * + * @note Experimental API + */ + static std::unique_ptr gen() noexcept; + + _TVG_DECLARE_PRIVATE(WgCanvas); +}; + + /** * @class Initializer * @@ -1650,7 +1812,7 @@ class TVG_API Initializer final * * This class supports the display and control of animation frames. * - * @BETA_API + * @note Experimental API */ class TVG_API Animation @@ -1669,7 +1831,7 @@ class TVG_API Animation * * @see totalFrame() * - * @BETA_API + * @note Experimental API */ Result frame(float no) noexcept; @@ -1684,7 +1846,7 @@ class TVG_API Animation * * @warning The picture instance is owned by Animation. It should not be deleted manually. * - * @BETA_API + * @note Experimental API */ Picture* picture() const noexcept; @@ -1698,7 +1860,7 @@ class TVG_API Animation * @see Animation::frame(float no) * @see Animation::totalFrame() * - * @BETA_API + * @note Experimental API */ float curFrame() const noexcept; @@ -1710,7 +1872,7 @@ class TVG_API Animation * @note Frame numbering starts from 0. * @note If the Picture is not properly configured, this function will return 0. * - * @BETA_API + * @note Experimental API */ float totalFrame() const noexcept; @@ -1721,7 +1883,7 @@ class TVG_API Animation * * @note If the Picture is not properly configured, this function will return 0. * - * @BETA_API + * @% Experimental API */ float duration() const noexcept; @@ -1730,7 +1892,7 @@ class TVG_API Animation * * @return A new Animation object. * - * @BETA_API + * @note Experimental API */ static std::unique_ptr gen() noexcept; @@ -1760,6 +1922,15 @@ class TVG_API Saver final public: ~Saver(); + /** + * @brief Sets the base background content for the saved image. + * + * @param[in] paint The paint to be drawn as the background image for the saving paint. + * + * @note Experimental API + */ + Result background(std::unique_ptr paint) noexcept; + /** * @brief Exports the given @p paint data to the given @p path * @@ -1794,18 +1965,18 @@ class TVG_API Saver final * @param[in] quality The encoded quality level. @c 0 is the minimum, @c 100 is the maximum value(recommended). * @param[in] fps The desired frames per second (FPS). For example, to encode data at 60 FPS, pass 60. Pass 0 to keep the original frame data. * - * @return Result::Success if the export succeeds. - * @return Result::InsufficientCondition if there are ongoing resource-saving operations. - * @return Result::NonSupport if an attempt is made to save the file with an unknown extension or in an unsupported format. - * @return Result::MemoryCorruption in case of an internal error. - * @return Result::Unknown if attempting to save an empty paint. + * @retval Result::Success if the export succeeds. + * @retval Result::InsufficientCondition if there are ongoing resource-saving operations. + * @retval Result::NonSupport if an attempt is made to save the file with an unknown extension or in an unsupported format. + * @retval Result::MemoryCorruption in case of an internal error. + * @retval Result::Unknown if attempting to save an empty paint. * * @note A higher frames per second (FPS) would result in a larger file size. It is recommended to use the default value. * @note Saving can be asynchronous if the assigned thread number is greater than zero. To guarantee the saving is done, call sync() afterwards. * * @see Saver::sync() * - * @note: Experimental API + * @note Experimental API */ Result save(std::unique_ptr animation, const std::string& path, uint32_t quality = 100, uint32_t fps = 0) noexcept; @@ -1882,7 +2053,7 @@ class TVG_API Accessor final * @brief The cast() function is a utility function used to cast a 'Paint' to type 'T'. * @since 0.11 */ -template +template std::unique_ptr cast(Paint* paint) { return std::unique_ptr(static_cast(paint)); @@ -1893,7 +2064,7 @@ std::unique_ptr cast(Paint* paint) * @brief The cast() function is a utility function used to cast a 'Fill' to type 'T'. * @since 0.11 */ -template +template std::unique_ptr cast(Fill* fill) { return std::unique_ptr(static_cast(fill)); diff --git a/thirdparty/thorvg/src/common/tvgArray.h b/thirdparty/thorvg/src/common/tvgArray.h index 1afc647b6889..acb3a41b9732 100644 --- a/thirdparty/thorvg/src/common/tvgArray.h +++ b/thirdparty/thorvg/src/common/tvgArray.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -39,6 +39,11 @@ struct Array Array(){} + Array(int32_t size) + { + reserve(size); + } + Array(const Array& rhs) { reset(); diff --git a/thirdparty/thorvg/src/common/tvgBezier.cpp b/thirdparty/thorvg/src/common/tvgBezier.cpp index f9daf07b84c9..5fb501721e2c 100644 --- a/thirdparty/thorvg/src/common/tvgBezier.cpp +++ b/thirdparty/thorvg/src/common/tvgBezier.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgBezier.h b/thirdparty/thorvg/src/common/tvgBezier.h index 539a63bdd32d..cb2766c50553 100644 --- a/thirdparty/thorvg/src/common/tvgBezier.h +++ b/thirdparty/thorvg/src/common/tvgBezier.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgCompressor.cpp b/thirdparty/thorvg/src/common/tvgCompressor.cpp index e38940f3d002..778fc4d0a230 100644 --- a/thirdparty/thorvg/src/common/tvgCompressor.cpp +++ b/thirdparty/thorvg/src/common/tvgCompressor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgCompressor.h b/thirdparty/thorvg/src/common/tvgCompressor.h index 05d23f429323..0756127ec610 100644 --- a/thirdparty/thorvg/src/common/tvgCompressor.h +++ b/thirdparty/thorvg/src/common/tvgCompressor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgInlist.h b/thirdparty/thorvg/src/common/tvgInlist.h new file mode 100644 index 000000000000..ff28cfd48ea4 --- /dev/null +++ b/thirdparty/thorvg/src/common/tvgInlist.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _TVG_INLIST_H_ +#define _TVG_INLIST_H_ + +namespace tvg { + +//NOTE: declare this in your list item +#define INLIST_ITEM(T) \ + T* prev; \ + T* next + +template +struct Inlist +{ + T* head = nullptr; + T* tail = nullptr; + + void free() + { + while (head) { + auto t = head; + head = t->next; + delete(t); + } + head = tail = nullptr; + } + + void back(T* element) + { + if (tail) { + tail->next = element; + element->prev = tail; + element->next = nullptr; + tail = element; + } else { + head = tail = element; + element->prev = nullptr; + element->next = nullptr; + } + } + + void front(T* element) + { + if (head) { + head->prev = element; + element->prev = nullptr; + element->next = head; + head = element; + } else { + head = tail = element; + element->prev = nullptr; + element->next = nullptr; + } + } + + T* back() + { + if (!tail) return nullptr; + auto t = tail; + tail = t->prev; + if (!tail) head = nullptr; + return t; + } + + T* front() + { + if (!head) return nullptr; + auto t = head; + head = t->next; + if (!head) tail = nullptr; + return t; + } + + void remove(T* element) + { + if (element->prev) element->prev->next = element->next; + if (element->next) element->next->prev = element->prev; + if (element == head) head = element->next; + if (element == tail) tail = element->prev; + } + + bool empty() + { + return head ? false : true; + } +}; + +} + +#endif // _TVG_INLIST_H_ diff --git a/thirdparty/thorvg/src/common/tvgList.h b/thirdparty/thorvg/src/common/tvgList.h deleted file mode 100644 index 01e87a840fa5..000000000000 --- a/thirdparty/thorvg/src/common/tvgList.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2023 the ThorVG project. All rights reserved. - - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _TVG_LIST_H_ -#define _TVG_LIST_H_ - -namespace tvg { - -template -struct LinkedList -{ - T *head = nullptr; - T *tail = nullptr; - - LinkedList() = default; - LinkedList(T *head, T *tail) : head(head), tail(tail) - { - } - - template - static void insert(T *t, T *prev, T *next, T **head, T **tail) - { - t->*Prev = prev; - t->*Next = next; - - if (prev) { - prev->*Next = t; - } else if (head) { - *head = t; - } - - if (next) { - next->*Prev = t; - } else if (tail) { - *tail = t; - } - } - - template - static void remove(T *t, T **head, T **tail) - { - if (t->*Prev) { - t->*Prev->*Next = t->*Next; - } else if (head) { - *head = t->*Next; - } - - if (t->*Next) { - t->*Next->*Prev = t->*Prev; - } else if (tail) { - *tail = t->*Prev; - } - - t->*Prev = t->*Next = nullptr; - } - - template - static bool contains(T *t, T **head, T **tail) { - for (T *it = *head; it; it = it->*Next) { - if (it == t) { - return true; - } - } - - return false; - } -}; - -} - -#endif // _TVG_LIST_H_ diff --git a/thirdparty/thorvg/src/common/tvgMath.cpp b/thirdparty/thorvg/src/common/tvgMath.cpp index a9463c80773e..42bc2cf4aafe 100644 --- a/thirdparty/thorvg/src/common/tvgMath.cpp +++ b/thirdparty/thorvg/src/common/tvgMath.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgMath.h b/thirdparty/thorvg/src/common/tvgMath.h index 004fff1e7b09..50c3458efc82 100644 --- a/thirdparty/thorvg/src/common/tvgMath.h +++ b/thirdparty/thorvg/src/common/tvgMath.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -174,6 +174,18 @@ static inline Point operator*(const Point& lhs, float rhs) } +static inline Point operator*(const float& lhs, const Point& rhs) +{ + return {lhs * rhs.x, lhs * rhs.y}; +} + + +static inline Point operator/(const Point& lhs, const float rhs) +{ + return {lhs.x / rhs, lhs.y / rhs}; +} + + template static inline T mathLerp(const T &start, const T &end, float t) { diff --git a/thirdparty/thorvg/src/common/tvgStr.cpp b/thirdparty/thorvg/src/common/tvgStr.cpp index eeed4fc404bb..311b98651132 100644 --- a/thirdparty/thorvg/src/common/tvgStr.cpp +++ b/thirdparty/thorvg/src/common/tvgStr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/common/tvgStr.h b/thirdparty/thorvg/src/common/tvgStr.h index 448cc69336f2..9e5f9ba9b570 100644 --- a/thirdparty/thorvg/src/common/tvgStr.h +++ b/thirdparty/thorvg/src/common/tvgStr.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp index 30a66f9cada6..10277f846d7f 100644 --- a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp +++ b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,19 +20,25 @@ * SOFTWARE. */ -#include "tvgLoader.h" #include "tvgPngLoader.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +void PngLoader::clear() +{ + png_image_free(image); + free(image); + image = nullptr; +} + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -PngLoader::PngLoader() +PngLoader::PngLoader() : ImageLoader(FileType::Png) { image = static_cast(calloc(1, sizeof(png_image))); image->version = PNG_IMAGE_VERSION; @@ -41,13 +47,11 @@ PngLoader::PngLoader() PngLoader::~PngLoader() { - if (content) { - free((void*)content); - content = nullptr; - } - free(image); + clear(); + free((void*)surface.buf32); } + bool PngLoader::open(const string& path) { image->opaque = NULL; @@ -56,11 +60,11 @@ bool PngLoader::open(const string& path) w = (float)image->width; h = (float)image->height; - cs = ColorSpace::ARGB8888; return true; } + bool PngLoader::open(const char* data, uint32_t size, bool copy) { image->opaque = NULL; @@ -69,7 +73,6 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) w = (float)image->width; h = (float)image->height; - cs = ColorSpace::ARGB8888; return true; } @@ -77,6 +80,10 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) bool PngLoader::read() { + if (!LoadModule::read()) return true; + + if (w == 0 || h == 0) return false; + png_bytep buffer; image->format = PNG_FORMAT_BGRA; buffer = static_cast(malloc(PNG_IMAGE_SIZE((*image)))); @@ -89,32 +96,17 @@ bool PngLoader::read() free(buffer); return false; } - content = reinterpret_cast(buffer); - return true; -} + //setup the surface + surface.buf32 = reinterpret_cast(buffer); + surface.stride = (uint32_t)w; + surface.w = (uint32_t)w; + surface.h = (uint32_t)h; + surface.channelSize = sizeof(uint32_t); + surface.cs = ColorSpace::ARGB8888; + surface.premultiplied = false; -bool PngLoader::close() -{ - png_image_free(image); - return true; -} + clear(); -unique_ptr PngLoader::bitmap() -{ - if (!content) return nullptr; - - //TODO: It's better to keep this surface instance in the loader side - auto surface = new Surface; - surface->buf32 = content; - surface->stride = (uint32_t)w; - surface->w = (uint32_t)w; - surface->h = (uint32_t)h; - surface->cs = cs; - surface->channelSize = sizeof(uint32_t); - surface->owner = true; - surface->premultiplied = false; - - return unique_ptr(surface); + return true; } - diff --git a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h index 5354e1bdd609..c45544eb07c5 100644 --- a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h +++ b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,24 +24,22 @@ #define _TVG_PNG_LOADER_H_ #include +#include "tvgLoader.h" -class PngLoader : public LoadModule +class PngLoader : public ImageLoader { public: PngLoader(); ~PngLoader(); - using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; bool read() override; - bool close() override; - - unique_ptr bitmap() override; private: + void clear(); + png_imagep image = nullptr; - uint32_t* content = nullptr; }; #endif //_TVG_PNG_LOADER_H_ diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp index 6edda86cc13e..86a46245d988 100644 --- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,7 +21,6 @@ */ #include -#include "tvgLoader.h" #include "tvgJpgLoader.h" /************************************************************************/ @@ -38,30 +37,45 @@ void JpgLoader::clear() } +void JpgLoader::run(unsigned tid) +{ + surface.buf8 = jpgdDecompress(decoder); + surface.stride = static_cast(w); + surface.w = static_cast(w); + surface.h = static_cast(h); + surface.cs = ColorSpace::ARGB8888; + surface.channelSize = sizeof(uint32_t); + surface.premultiplied = true; + + clear(); +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ +JpgLoader::JpgLoader() : ImageLoader(FileType::Jpg) +{ + +} + JpgLoader::~JpgLoader() { - jpgdDelete(decoder); - if (freeData) free(data); - free(image); + clear(); + free(surface.buf8); } bool JpgLoader::open(const string& path) { - clear(); - int width, height; decoder = jpgdHeader(path.c_str(), &width, &height); if (!decoder) return false; w = static_cast(width); h = static_cast(height); - cs = ColorSpace::ARGB8888; return true; } @@ -69,8 +83,6 @@ bool JpgLoader::open(const string& path) bool JpgLoader::open(const char* data, uint32_t size, bool copy) { - clear(); - if (copy) { this->data = (char *) malloc(size); if (!this->data) return false; @@ -87,7 +99,6 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy) w = static_cast(width); h = static_cast(height); - cs = ColorSpace::ARGB8888; return true; } @@ -96,7 +107,9 @@ bool JpgLoader::open(const char* data, uint32_t size, bool copy) bool JpgLoader::read() { - if (!decoder || w <= 0 || h <= 0) return false; + if (!LoadModule::read()) return true; + + if (!decoder || w == 0 || h == 0) return false; TaskScheduler::request(this); @@ -106,38 +119,14 @@ bool JpgLoader::read() bool JpgLoader::close() { + if (!LoadModule::close()) return false; this->done(); - clear(); return true; } -unique_ptr JpgLoader::bitmap() +Surface* JpgLoader::bitmap() { this->done(); - - if (!image) return nullptr; - - //TODO: It's better to keep this surface instance in the loader side - auto surface = new Surface; - surface->buf8 = image; - surface->stride = static_cast(w); - surface->w = static_cast(w); - surface->h = static_cast(h); - surface->cs = cs; - surface->channelSize = sizeof(uint32_t); - surface->premultiplied = true; - surface->owner = true; - - return unique_ptr(surface); -} - - -void JpgLoader::run(unsigned tid) -{ - if (image) { - free(image); - image = nullptr; - } - image = jpgdDecompress(decoder); + return ImageLoader::bitmap(); } diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h index 6d2febe94f01..05cbb54c852f 100644 --- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h +++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,30 +23,30 @@ #ifndef _TVG_JPG_LOADER_H_ #define _TVG_JPG_LOADER_H_ +#include "tvgLoader.h" #include "tvgTaskScheduler.h" #include "tvgJpgd.h" -class JpgLoader : public LoadModule, public Task +class JpgLoader : public ImageLoader, public Task { private: jpeg_decoder* decoder = nullptr; char* data = nullptr; - unsigned char *image = nullptr; bool freeData = false; void clear(); + void run(unsigned tid) override; public: + JpgLoader(); ~JpgLoader(); - using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; bool read() override; bool close() override; - unique_ptr bitmap() override; - void run(unsigned tid) override; + Surface* bitmap() override; }; #endif //_TVG_JPG_LOADER_H_ diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp index 3cd852a4bb8d..6f2bd916d5ea 100644 --- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp +++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h index 030fdc294666..e1fe35f48872 100644 --- a/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h +++ b/thirdparty/thorvg/src/loaders/jpg/tvgJpgd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp b/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp index fc4cce40610c..fb7527f04532 100644 --- a/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp +++ b/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/png/tvgLodePng.h b/thirdparty/thorvg/src/loaders/png/tvgLodePng.h index 7254a5547747..cd3efacf9872 100644 --- a/thirdparty/thorvg/src/loaders/png/tvgLodePng.h +++ b/thirdparty/thorvg/src/loaders/png/tvgLodePng.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp index 32ff57c5c382..111180b6571f 100644 --- a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp +++ b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,14 +29,22 @@ /* Internal Class Implementation */ /************************************************************************/ -void PngLoader::clear() + +void PngLoader::run(unsigned tid) { - lodepng_state_cleanup(&state); + auto width = static_cast(w); + auto height = static_cast(h); - if (freeData) free(data); - data = nullptr; - size = 0; - freeData = false; + if (lodepng_decode(&surface.buf8, &width, &height, &state, data, size)) { + TVGERR("PNG", "Failed to decode image"); + } + + //setup the surface + surface.stride = width; + surface.w = width; + surface.h = height; + surface.channelSize = sizeof(uint32_t); + surface.premultiplied = false; } @@ -44,7 +52,7 @@ void PngLoader::clear() /* External Class Implementation */ /************************************************************************/ -PngLoader::PngLoader() +PngLoader::PngLoader() : ImageLoader(FileType::Png) { lodepng_state_init(&state); } @@ -53,14 +61,13 @@ PngLoader::PngLoader() PngLoader::~PngLoader() { if (freeData) free(data); - free(image); + free(surface.buf8); + lodepng_state_cleanup(&state); } bool PngLoader::open(const string& path) { - clear(); - auto pngFile = fopen(path.c_str(), "rb"); if (!pngFile) return false; @@ -76,26 +83,23 @@ bool PngLoader::open(const string& path) freeData = true; - if (fread(data, size, 1, pngFile) < 1) goto failure; + if (fread(data, size, 1, pngFile) < 1) goto finalize; lodepng_state_init(&state); unsigned int width, height; - if (lodepng_inspect(&width, &height, &state, data, size) > 0) goto failure; + if (lodepng_inspect(&width, &height, &state, data, size) > 0) goto finalize; w = static_cast(width); h = static_cast(height); - if (state.info_png.color.colortype == LCT_RGBA) cs = ColorSpace::ABGR8888; - else cs = ColorSpace::ARGB8888; + if (state.info_png.color.colortype == LCT_RGBA) surface.cs = ColorSpace::ABGR8888; + else surface.cs = ColorSpace::ARGB8888; ret = true; goto finalize; -failure: - clear(); - finalize: fclose(pngFile); return ret; @@ -104,10 +108,6 @@ bool PngLoader::open(const string& path) bool PngLoader::open(const char* data, uint32_t size, bool copy) { - clear(); - - lodepng_state_init(&state); - unsigned int width, height; if (lodepng_inspect(&width, &height, &state, (unsigned char*)(data), size) > 0) return false; @@ -125,7 +125,7 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) h = static_cast(height); this->size = size; - cs = ColorSpace::ABGR8888; + surface.cs = ColorSpace::ABGR8888; return true; } @@ -133,53 +133,18 @@ bool PngLoader::open(const char* data, uint32_t size, bool copy) bool PngLoader::read() { - if (!data || w <= 0 || h <= 0) return false; - - TaskScheduler::request(this); + if (!data || w == 0 || h == 0) return false; - return true; -} + if (!LoadModule::read()) return true; + TaskScheduler::request(this); -bool PngLoader::close() -{ - this->done(); - clear(); return true; } -unique_ptr PngLoader::bitmap() +Surface* PngLoader::bitmap() { this->done(); - - if (!image) return nullptr; - - //TODO: It's better to keep this surface instance in the loader side - auto surface = new Surface; - surface->buf8 = image; - surface->stride = static_cast(w); - surface->w = static_cast(w); - surface->h = static_cast(h); - surface->cs = cs; - surface->channelSize = sizeof(uint32_t); - surface->premultiplied = false; - surface->owner = true; - - return unique_ptr(surface); -} - - -void PngLoader::run(unsigned tid) -{ - if (image) { - free(image); - image = nullptr; - } - auto width = static_cast(w); - auto height = static_cast(h); - - if (lodepng_decode(&image, &width, &height, &state, data, size)) { - TVGERR("PNG", "Failed to decode image"); - } + return ImageLoader::bitmap(); } diff --git a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h index 579d197ad655..06fbbf734955 100644 --- a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h +++ b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,29 +27,25 @@ #include "tvgTaskScheduler.h" -class PngLoader : public LoadModule, public Task +class PngLoader : public ImageLoader, public Task { private: LodePNGState state; unsigned char* data = nullptr; - unsigned char *image = nullptr; unsigned long size = 0; bool freeData = false; - void clear(); + void run(unsigned tid) override; public: PngLoader(); ~PngLoader(); - using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; bool read() override; - bool close() override; - unique_ptr bitmap() override; - void run(unsigned tid) override; + Surface* bitmap() override; }; #endif //_TVG_PNG_LOADER_H_ diff --git a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp index 5f5e72b0ddc1..b797f98218ee 100644 --- a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp +++ b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,17 +34,21 @@ /* External Class Implementation */ /************************************************************************/ +RawLoader::RawLoader() : ImageLoader(FileType::Raw) +{ +} + + RawLoader::~RawLoader() { - if (copy && content) { - free((void*)content); - content = nullptr; - } + if (copy) free(surface.buf32); } bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) { + if (!LoadModule::read()) return true; + if (!data || w == 0 || h == 0) return false; this->w = (float)w; @@ -52,13 +56,19 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) this->copy = copy; if (copy) { - content = (uint32_t*)malloc(sizeof(uint32_t) * w * h); - if (!content) return false; - memcpy((void*)content, data, sizeof(uint32_t) * w * h); + surface.buf32 = (uint32_t*)malloc(sizeof(uint32_t) * w * h); + if (!surface.buf32) return false; + memcpy((void*)surface.buf32, data, sizeof(uint32_t) * w * h); } - else content = const_cast(data); + else surface.buf32 = const_cast(data); - cs = ColorSpace::ARGB8888; + //setup the surface + surface.stride = w; + surface.w = w; + surface.h = h; + surface.cs = ColorSpace::ARGB8888; + surface.channelSize = sizeof(uint32_t); + surface.premultiplied = true; return true; } @@ -66,30 +76,7 @@ bool RawLoader::open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) bool RawLoader::read() { - return true; -} - + LoadModule::read(); -bool RawLoader::close() -{ return true; } - - -unique_ptr RawLoader::bitmap() -{ - if (!content) return nullptr; - - //TODO: It's better to keep this surface instance in the loader side - auto surface = new Surface; - surface->buf32 = content; - surface->stride = static_cast(w); - surface->w = static_cast(w); - surface->h = static_cast(h); - surface->cs = cs; - surface->channelSize = sizeof(uint32_t); - surface->premultiplied = true; - surface->owner = true; - - return unique_ptr(surface); -} diff --git a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h index 69f9bdc47a73..970cdd9c8329 100644 --- a/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h +++ b/thirdparty/thorvg/src/loaders/raw/tvgRawLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,20 +23,17 @@ #ifndef _TVG_RAW_LOADER_H_ #define _TVG_RAW_LOADER_H_ -class RawLoader : public LoadModule +class RawLoader : public ImageLoader { public: - uint32_t* content = nullptr; bool copy = false; + RawLoader(); ~RawLoader(); using LoadModule::open; - bool open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) override; + bool open(const uint32_t* data, uint32_t w, uint32_t h, bool copy); bool read() override; - bool close() override; - - unique_ptr bitmap() override; }; diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp index c3c477a263cf..2826dc913422 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2022 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h index 228c5996daf7..7d8dcfa94a08 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgCssStyle.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2022 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp index be99ec085ca9..6e5247662578 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -3528,6 +3528,10 @@ void SvgLoader::clear(bool all) loaderData.images.reset(); if (copy) free((char*)content); + + delete(root); + root = nullptr; + size = 0; content = nullptr; copy = false; @@ -3538,14 +3542,15 @@ void SvgLoader::clear(bool all) /* External Class Implementation */ /************************************************************************/ -SvgLoader::SvgLoader() +SvgLoader::SvgLoader() : ImageLoader(FileType::Svg) { } SvgLoader::~SvgLoader() { - close(); + this->done(); + clear(); } @@ -3554,7 +3559,7 @@ void SvgLoader::run(unsigned tid) //According to the SVG standard the value of the width/height of the viewbox set to 0 disables rendering if ((viewFlag & SvgViewFlag::Viewbox) && (fabsf(vw) <= FLT_EPSILON || fabsf(vh) <= FLT_EPSILON)) { TVGLOG("SVG", "The width and/or height set to 0 - rendering disabled."); - root = Scene::gen(); + root = Scene::gen().release(); return; } @@ -3727,6 +3732,8 @@ bool SvgLoader::read() { if (!content || size == 0) return false; + if (!LoadModule::read()) return true; + //the loading has been already completed in header() if (root) return true; @@ -3738,16 +3745,17 @@ bool SvgLoader::read() bool SvgLoader::close() { + if (!LoadModule::close()) return false; this->done(); - clear(); - return true; } -unique_ptr SvgLoader::paint() +Paint* SvgLoader::paint() { this->done(); - return std::move(root); + auto ret = root; + root = nullptr; + return ret; } diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h index 4bac52e0b97e..e0cba8b11ef5 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,7 +26,7 @@ #include "tvgTaskScheduler.h" #include "tvgSvgLoaderCommon.h" -class SvgLoader : public LoadModule, public Task +class SvgLoader : public ImageLoader, public Task { public: string filePath; @@ -35,21 +35,20 @@ class SvgLoader : public LoadModule, public Task uint32_t size = 0; SvgLoaderData loaderData; - unique_ptr root; + Scene* root = nullptr; bool copy = false; SvgLoader(); ~SvgLoader(); - using LoadModule::open; bool open(const string& path) override; bool open(const char* data, uint32_t size, bool copy) override; bool resize(Paint* paint, float w, float h) override; bool read() override; bool close() override; - unique_ptr paint() override; + Paint* paint() override; private: SvgViewFlag viewFlag = SvgViewFlag::None; diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h index b4ee3e8e0d11..d6febd682551 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp index 79a9c0771dd6..f618a3c827c2 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -53,6 +53,7 @@ #include #include #include +#include "tvgShape.h" #include "tvgSvgLoaderCommon.h" #include "tvgSvgPath.h" #include "tvgStr.h" @@ -534,7 +535,7 @@ static char* _nextCommand(char* path, char* cmd, float* arr, int* count) /************************************************************************/ -bool svgPathToTvgPath(const char* svgPath, Array& cmds, Array& pts) +bool svgPathToShape(const char* svgPath, Shape* shape) { float numberArray[7]; int numberCount = 0; @@ -545,11 +546,16 @@ bool svgPathToTvgPath(const char* svgPath, Array& cmds, Arrayrs.path.pts; + auto& cmds = P(shape)->rs.path.cmds; + auto lastCmds = cmds.count; + while ((path[0] != '\0')) { path = _nextCommand(path, &cmd, numberArray, &numberCount); if (!path) break; if (!_processCommand(&cmds, &pts, cmd, numberArray, numberCount, &cur, &curCtl, &startPoint, &isQuadratic)) break; } + if (cmds.count > lastCmds && cmds[lastCmds] != PathCommand::MoveTo) return false; return true; } diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h index 4199088dc104..b8641dd16581 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,6 @@ #include -bool svgPathToTvgPath(const char* svgPath, Array& cmds, Array& pts); +bool svgPathToShape(const char* svgPath, Shape* shape); #endif //_TVG_SVG_PATH_H_ diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp index 1791df57f0da..674c30f5bd58 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -396,10 +396,9 @@ static bool _recognizeShape(SvgNode* node, Shape* shape) switch (node->type) { case SvgNodeType::Path: { if (node->node.path.path) { - Array cmds; - Array pts; - if (svgPathToTvgPath(node->node.path.path, cmds, pts)) { - shape->appendPath(cmds.data, cmds.count, pts.data, pts.count); + if (!svgPathToShape(node->node.path.path, shape)) { + TVGERR("SVG", "Invalid path information."); + return false; } } break; @@ -845,7 +844,7 @@ static void _updateInvalidViewSize(const Scene* scene, Box& vBox, float& w, floa /* External Class Implementation */ /************************************************************************/ -unique_ptr svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag) +Scene* svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag) { //TODO: aspect ratio is valid only if viewBox was set @@ -863,8 +862,7 @@ unique_ptr svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, fl } auto viewBoxClip = Shape::gen(); - viewBoxClip->appendRect(0, 0, w, h, 0, 0); - viewBoxClip->fill(0, 0, 0); + viewBoxClip->appendRect(0, 0, w, h); auto compositeLayer = Scene::gen(); compositeLayer->composite(std::move(viewBoxClip), CompositeMethod::ClipPath); @@ -880,5 +878,5 @@ unique_ptr svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, fl loaderData.doc->node.doc.w = w; loaderData.doc->node.doc.h = h; - return root; + return root.release(); } diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h index f6a60f850d93..0663a37f05a6 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,6 @@ #include "tvgCommon.h" -unique_ptr svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag); +Scene* svgSceneBuild(SvgLoaderData& loaderData, Box vBox, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath, SvgViewFlag viewFlag); #endif //_TVG_SVG_SCENE_BUILDER_H_ diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp index 7940188ade93..32affd04c658 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h index ee0e3f88610c..220a4b3e552c 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgUtil.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp index dbc3b17b70ed..aec30d2384c4 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h index 7333bb09fb3f..30ca23b565f3 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h index 8fe7b77edd28..3d73075a4a43 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -261,13 +261,26 @@ struct SwSurface : Surface SwAlpha alphas[4]; //Alpha:2, InvAlpha:3, Luma:4, InvLuma:5 SwBlender blender = nullptr; //blender (optional) SwCompositor* compositor = nullptr; //compositor (optional) - BlendMethod blendMethod; //blending method (uint8_t) + BlendMethod blendMethod; //blending method (uint8_t) SwAlpha alpha(CompositeMethod method) { auto idx = (int)(method) - 2; //0: None, 1: ClipPath return alphas[idx > 3 ? 0 : idx]; //CompositeMethod has only four Matting methods. } + + SwSurface() + { + } + + SwSurface(const SwSurface* rhs) : Surface(rhs) + { + join = rhs->join; + memcpy(alphas, rhs->alphas, sizeof(alphas)); + blender = rhs->blender; + compositor = rhs->compositor; + blendMethod = rhs->blendMethod; + } }; struct SwCompositor : Compositor diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp index cede9e6eb7a9..8956cd9f2464 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -167,7 +167,6 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr fill->linear.dy = dx * invTransform.e12 + fill->linear.dy * invTransform.e22; fill->linear.len = fill->linear.dx * fill->linear.dx + fill->linear.dy * fill->linear.dy; - if (fill->linear.len < FLT_EPSILON) return true; } return true; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp index b1624037bc1f..c1629455017b 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwImage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp index d58dd9e3c5aa..42e405195eb0 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp index 54ae594bffdc..68eb7a5a6fed 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp index 96a0ed35ad85..9a6dc459501b 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -1714,7 +1714,7 @@ static bool _rasterSolidGradientRle(SwSurface* surface, const SwRleData* rle, co static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { - if (!rle || fill->linear.len < FLT_EPSILON) return false; + if (!rle) return false; if (_compositing(surface)) { if (_matting(surface)) return _rasterGradientMattedRle(surface, rle, fill); @@ -1855,7 +1855,9 @@ void rasterUnpremultiply(Surface* surface) void rasterPremultiply(Surface* surface) { - if (surface->channelSize != sizeof(uint32_t)) return; + unique_lock lock{surface->mtx}; + if (surface->premultiplied || (surface->channelSize != sizeof(uint32_t))) return; + surface->premultiplied = true; TVGLOG("SW_ENGINE", "Premultiply [Size: %d x %d]", surface->w, surface->h); @@ -1869,7 +1871,6 @@ void rasterPremultiply(Surface* surface) *dst = (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff); } } - surface->premultiplied = true; } @@ -1935,6 +1936,9 @@ bool rasterImage(SwSurface* surface, SwImage* image, const RenderMesh* mesh, con bool rasterConvertCS(Surface* surface, ColorSpace to) { + unique_lock lock{surface->mtx}; + if (surface->cs == to) return true; + //TOOD: Support SIMD accelerations auto from = surface->cs; @@ -1946,6 +1950,5 @@ bool rasterConvertCS(Surface* surface, ColorSpace to) surface->cs = to; return cRasterARGBtoABGR(surface); } - return false; } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h index 090fa29a7aa4..177c7b847f80 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterAvx.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h index da3c7077e8f3..6d0bd9383dad 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterC.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h index ba77ed53cf62..cfbeb0cacac7 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterNeon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h index 698ab37da297..04e382b842ae 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp index 18815e69a940..c9c543fbb58c 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -45,8 +45,11 @@ struct SwTask : Task bool pushed = false; //Pushed into task list? bool disposed = false; //Disposed task? - RenderRegion bounds() const + RenderRegion bounds() { + //Can we skip the synchronization? + done(); + RenderRegion region; //Range over? @@ -278,10 +281,8 @@ struct SwImageTask : SwTask auto clipRegion = bbox; //Convert colorspace if it's not aligned. - if (source->owner) { - if (source->cs != surface->cs) rasterConvertCS(source, surface->cs); - if (!source->premultiplied) rasterPremultiply(source); - } + rasterConvertCS(source, surface->cs); + rasterPremultiply(source); image.data = source->data; image.w = source->w; @@ -433,7 +434,6 @@ bool SwRenderer::target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h, surface->cs = cs; surface->channelSize = CHANNEL_SIZE(cs); surface->premultiplied = true; - surface->owner = true; vport.x = vport.y = 0; vport.w = surface->w; @@ -635,11 +635,8 @@ Compositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs) //New Composition if (!cmp) { - cmp = new SwSurface; - //Inherits attributes from main surface - *cmp = *surface; - + cmp = new SwSurface(surface); cmp->compositor = new SwCompositor; //TODO: We can optimize compositor surface size from (surface->stride x surface->h) to Parameter(w x h) diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h index 4393740bd992..83d942388fd2 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp index a4a7fabdee1f..33c94e106383 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp index ae2ddd2af79f..e001ced2a826 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp index 75c5fa566708..8f44cf36164e 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgAccessor.cpp b/thirdparty/thorvg/src/renderer/tvgAccessor.cpp index 0c636979b58a..903437f29d3a 100644 --- a/thirdparty/thorvg/src/renderer/tvgAccessor.cpp +++ b/thirdparty/thorvg/src/renderer/tvgAccessor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp index b4ea534b91f7..995eca7f415a 100644 --- a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp +++ b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -64,7 +64,7 @@ Animation::Animation() : pImpl(new Impl) Result Animation::frame(float no) noexcept { - auto loader = pImpl->picture->pImpl->loader.get(); + auto loader = pImpl->picture->pImpl->loader; if (!loader) return Result::InsufficientCondition; if (!loader->animatable()) return Result::NonSupport; @@ -82,7 +82,7 @@ Picture* Animation::picture() const noexcept float Animation::curFrame() const noexcept { - auto loader = pImpl->picture->pImpl->loader.get(); + auto loader = pImpl->picture->pImpl->loader; if (!loader) return 0; if (!loader->animatable()) return 0; @@ -93,7 +93,7 @@ float Animation::curFrame() const noexcept float Animation::totalFrame() const noexcept { - auto loader = pImpl->picture->pImpl->loader.get(); + auto loader = pImpl->picture->pImpl->loader; if (!loader) return 0; if (!loader->animatable()) return 0; @@ -104,7 +104,7 @@ float Animation::totalFrame() const noexcept float Animation::duration() const noexcept { - auto loader = pImpl->picture->pImpl->loader.get(); + auto loader = pImpl->picture->pImpl->loader; if (!loader) return 0; if (!loader->animatable()) return 0; diff --git a/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h b/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h index b1468148d674..29f84eb82a6d 100644 --- a/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h +++ b/thirdparty/thorvg/src/renderer/tvgBinaryDesc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,7 +36,7 @@ using TvgBinFlag = TvgBinByte; #define TVG_HEADER_SIZE 33 //TVG_HEADER_SIGNATURE_LENGTH + TVG_HEADER_VERSION_LENGTH + 2*SIZE(float) + TVG_HEADER_RESERVED_LENGTH + TVG_HEADER_COMPRESS_SIZE #define TVG_HEADER_SIGNATURE "ThorVG" #define TVG_HEADER_SIGNATURE_LENGTH 6 -#define TVG_HEADER_VERSION "001100" //Major 00, Minor 11, Micro 00 +#define TVG_HEADER_VERSION "001200" //Major 00, Minor 12, Micro 00 #define TVG_HEADER_VERSION_LENGTH 6 #define TVG_HEADER_RESERVED_LENGTH 1 //Storing flags for extensions #define TVG_HEADER_COMPRESS_SIZE 12 //TVG_HEADER_UNCOMPRESSED_SIZE + TVG_HEADER_COMPRESSED_SIZE + TVG_HEADER_COMPRESSED_SIZE_BITS diff --git a/thirdparty/thorvg/src/renderer/tvgCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgCanvas.cpp index 25741f611df5..11d6b778f740 100644 --- a/thirdparty/thorvg/src/renderer/tvgCanvas.cpp +++ b/thirdparty/thorvg/src/renderer/tvgCanvas.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgCanvas.h b/thirdparty/thorvg/src/renderer/tvgCanvas.h index f893f9f7c059..25181de47e15 100644 --- a/thirdparty/thorvg/src/renderer/tvgCanvas.h +++ b/thirdparty/thorvg/src/renderer/tvgCanvas.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,14 +20,11 @@ * SOFTWARE. */ -#ifndef _TVG_CANVAS_IMPL_H_ -#define _TVG_CANVAS_IMPL_H_ +#ifndef _TVG_CANVAS_H_ +#define _TVG_CANVAS_H_ #include "tvgPaint.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ struct Canvas::Impl { @@ -143,4 +140,4 @@ struct Canvas::Impl } }; -#endif /* _TVG_CANVAS_IMPL_H_ */ +#endif /* _TVG_CANVAS_H_ */ diff --git a/thirdparty/thorvg/src/renderer/tvgCommon.h b/thirdparty/thorvg/src/renderer/tvgCommon.h index 2b67681a4034..deb419bc65e2 100644 --- a/thirdparty/thorvg/src/renderer/tvgCommon.h +++ b/thirdparty/thorvg/src/renderer/tvgCommon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -61,8 +61,9 @@ using namespace tvg; #define TVG_CLASS_ID_PICTURE 3 #define TVG_CLASS_ID_LINEAR 4 #define TVG_CLASS_ID_RADIAL 5 +#define TVG_CLASS_ID_TEXT 6 -enum class FileType { Tvg = 0, Svg, Lottie, Raw, Png, Jpg, Webp, Gif, Unknown }; +enum class FileType { Tvg = 0, Svg, Ttf, Lottie, Raw, Png, Jpg, Webp, Gif, Unknown }; using Size = Point; diff --git a/thirdparty/thorvg/src/renderer/tvgFill.cpp b/thirdparty/thorvg/src/renderer/tvgFill.cpp index 9215882c8d92..ea1010051ee5 100644 --- a/thirdparty/thorvg/src/renderer/tvgFill.cpp +++ b/thirdparty/thorvg/src/renderer/tvgFill.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgFill.h b/thirdparty/thorvg/src/renderer/tvgFill.h index ff3dd48c4927..47f0c051c025 100644 --- a/thirdparty/thorvg/src/renderer/tvgFill.h +++ b/thirdparty/thorvg/src/renderer/tvgFill.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgFrameModule.h b/thirdparty/thorvg/src/renderer/tvgFrameModule.h index 332cca30908f..df97ccb89470 100644 --- a/thirdparty/thorvg/src/renderer/tvgFrameModule.h +++ b/thirdparty/thorvg/src/renderer/tvgFrameModule.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,9 +28,10 @@ namespace tvg { -class FrameModule: public LoadModule +class FrameModule: public ImageLoader { public: + FrameModule(FileType type) : ImageLoader(type) {} virtual ~FrameModule() {} virtual bool frame(float no) = 0; //set the current frame number diff --git a/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp index aa7f8dbe2ab4..f6f0d354d1cf 100644 --- a/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp +++ b/thirdparty/thorvg/src/renderer/tvgGlCanvas.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgInitializer.cpp b/thirdparty/thorvg/src/renderer/tvgInitializer.cpp index b7326a9fbc4c..76d89b40edb7 100644 --- a/thirdparty/thorvg/src/renderer/tvgInitializer.cpp +++ b/thirdparty/thorvg/src/renderer/tvgInitializer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,6 +36,10 @@ #include "tvgGlRenderer.h" #endif +#ifdef THORVG_WG_RASTER_SUPPORT + #include "tvgWgRenderer.h" +#endif + /************************************************************************/ /* Internal Class Implementation */ @@ -91,19 +95,27 @@ static bool _buildVersionInfo() Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept { auto nonSupport = true; + if (static_cast(engine) == 0) return Result::InvalidArguments; if (engine & CanvasEngine::Sw) { #ifdef THORVG_SW_RASTER_SUPPORT if (!SwRenderer::init(threads)) return Result::FailedAllocation; nonSupport = false; #endif - } else if (engine & CanvasEngine::Gl) { + } + + if (engine & CanvasEngine::Gl) { #ifdef THORVG_GL_RASTER_SUPPORT if (!GlRenderer::init(threads)) return Result::FailedAllocation; nonSupport = false; #endif - } else { - return Result::InvalidArguments; + } + + if (engine & CanvasEngine::Wg) { + #ifdef THORVG_WG_RASTER_SUPPORT + if (!WgRenderer::init(threads)) return Result::FailedAllocation; + nonSupport = false; + #endif } if (nonSupport) return Result::NonSupport; @@ -125,19 +137,27 @@ Result Initializer::term(CanvasEngine engine) noexcept if (_initCnt == 0) return Result::InsufficientCondition; auto nonSupport = true; + if (static_cast(engine) == 0) return Result::InvalidArguments; if (engine & CanvasEngine::Sw) { #ifdef THORVG_SW_RASTER_SUPPORT if (!SwRenderer::term()) return Result::InsufficientCondition; nonSupport = false; #endif - } else if (engine & CanvasEngine::Gl) { + } + + if (engine & CanvasEngine::Gl) { #ifdef THORVG_GL_RASTER_SUPPORT if (!GlRenderer::term()) return Result::InsufficientCondition; nonSupport = false; #endif - } else { - return Result::InvalidArguments; + } + + if (engine & CanvasEngine::Wg) { + #ifdef THORVG_WG_RASTER_SUPPORT + if (!WgRenderer::term()) return Result::InsufficientCondition; + nonSupport = false; + #endif } if (nonSupport) return Result::NonSupport; @@ -156,3 +176,4 @@ uint16_t THORVG_VERSION_NUMBER() { return _version; } + diff --git a/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h b/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h index 2347613ed83e..46e900a58282 100644 --- a/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h +++ b/thirdparty/thorvg/src/renderer/tvgIteratorAccessor.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgLoadModule.h b/thirdparty/thorvg/src/renderer/tvgLoadModule.h index 29ceba3fcc59..0ea766395e12 100644 --- a/thirdparty/thorvg/src/renderer/tvgLoadModule.h +++ b/thirdparty/thorvg/src/renderer/tvgLoadModule.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,35 +24,73 @@ #define _TVG_LOAD_MODULE_H_ #include "tvgRender.h" +#include "tvgInlist.h" -namespace tvg -{ -class LoadModule +struct LoadModule { -public: - float w = 0, h = 0; //default image size - ColorSpace cs = ColorSpace::Unsupported; //must be clarified at open() + INLIST_ITEM(LoadModule); + + //Use either hashkey(data) or hashpath(path) + uint64_t hashkey; + char* hashpath = nullptr; - virtual ~LoadModule() {} + FileType type; //current loader file type + uint16_t sharing = 0; //reference count + bool readied = false; //read done already. + + LoadModule(FileType type) : type(type) {} + virtual ~LoadModule() + { + free(hashpath); + } virtual bool open(const string& path) { return false; } virtual bool open(const char* data, uint32_t size, bool copy) { return false; } - virtual bool open(const uint32_t* data, uint32_t w, uint32_t h, bool copy) { return false; } - - //Override this if the vector-format has own resizing policy. virtual bool resize(Paint* paint, float w, float h) { return false; } - - virtual bool animatable() { return false; } //true if this loader supports animation. virtual void sync() {}; //finish immediately if any async update jobs. - virtual bool read() = 0; - virtual bool close() = 0; + virtual bool read() + { + if (readied) return false; + readied = true; + return true; + } - virtual unique_ptr bitmap() { return nullptr; } - virtual unique_ptr paint() { return nullptr; } + virtual bool close() + { + if (sharing == 0) return true; + --sharing; + return false; + } }; -} + +struct ImageLoader : LoadModule +{ + float w = 0, h = 0; //default image size + Surface surface; + + ImageLoader(FileType type) : LoadModule(type) {} + + virtual bool animatable() { return false; } //true if this loader supports animation. + virtual Paint* paint() { return nullptr; } + + virtual Surface* bitmap() + { + if (surface.data) return &surface; + return nullptr; + } +}; + + +struct FontLoader : LoadModule +{ + float scale = 1.0f; + + FontLoader(FileType type) : LoadModule(type) {} + + virtual bool request(Shape* shape, char* text, bool italic = false) = 0; +}; #endif //_TVG_LOAD_MODULE_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgLoader.cpp b/thirdparty/thorvg/src/renderer/tvgLoader.cpp index 65330e9e778c..628b0fa17f81 100644 --- a/thirdparty/thorvg/src/renderer/tvgLoader.cpp +++ b/thirdparty/thorvg/src/renderer/tvgLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,6 +20,9 @@ * SOFTWARE. */ +#include + +#include "tvgInlist.h" #include "tvgLoader.h" #ifdef THORVG_SVG_LOADER_SUPPORT @@ -42,16 +45,30 @@ #include "tvgWebpLoader.h" #endif +#ifdef THORVG_TTF_LOADER_SUPPORT + #include "tvgTtfLoader.h" +#endif + #ifdef THORVG_LOTTIE_LOADER_SUPPORT #include "tvgLottieLoader.h" #endif #include "tvgRawLoader.h" + +uint64_t HASH_KEY(const char* data, uint64_t size) +{ + return (((uint64_t) data) << 32) | size; +} + /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +static mutex mtx; +static Inlist _activeLoaders; + + static LoadModule* _find(FileType type) { switch(type) { @@ -64,6 +81,12 @@ static LoadModule* _find(FileType type) case FileType::Svg: { #ifdef THORVG_SVG_LOADER_SUPPORT return new SvgLoader; +#endif + break; + } + case FileType::Ttf: { +#ifdef THORVG_TTF_LOADER_SUPPORT + return new TtfLoader; #endif break; } @@ -111,6 +134,10 @@ static LoadModule* _find(FileType type) format = "SVG"; break; } + case FileType::Ttf: { + format = "TTF"; + break; + } case FileType::Lottie: { format = "lottie(json)"; break; @@ -152,29 +179,71 @@ static LoadModule* _findByPath(const string& path) if (!ext.compare("png")) return _find(FileType::Png); if (!ext.compare("jpg")) return _find(FileType::Jpg); if (!ext.compare("webp")) return _find(FileType::Webp); + if (!ext.compare("ttf") || !ext.compare("ttc")) return _find(FileType::Ttf); + if (!ext.compare("otf") || !ext.compare("otc")) return _find(FileType::Ttf); return nullptr; } -static LoadModule* _findByType(const string& mimeType) +static FileType _convert(const string& mimeType) { - if (mimeType.empty()) return nullptr; - auto type = FileType::Unknown; if (mimeType == "tvg") type = FileType::Tvg; else if (mimeType == "svg" || mimeType == "svg+xml") type = FileType::Svg; + else if (mimeType == "ttf" || mimeType == "otf") type = FileType::Ttf; else if (mimeType == "lottie") type = FileType::Lottie; else if (mimeType == "raw") type = FileType::Raw; else if (mimeType == "png") type = FileType::Png; else if (mimeType == "jpg" || mimeType == "jpeg") type = FileType::Jpg; else if (mimeType == "webp") type = FileType::Webp; - else { - TVGLOG("RENDERER", "Given mimetype is unknown = \"%s\".", mimeType.c_str()); - return nullptr; + else TVGLOG("RENDERER", "Given mimetype is unknown = \"%s\".", mimeType.c_str()); + + return type; +} + + +static LoadModule* _findByType(const string& mimeType) +{ + return _find(_convert(mimeType)); +} + + +static LoadModule* _findFromCache(const string& path) +{ + unique_lock lock{mtx}; + + auto loader = _activeLoaders.head; + + while (loader) { + if (loader->hashpath && !strcmp(loader->hashpath, path.c_str())) { + ++loader->sharing; + return loader; + } + loader = loader->next; } + return nullptr; +} + + +static LoadModule* _findFromCache(const char* data, uint32_t size, const string& mimeType) +{ + auto type = _convert(mimeType); + if (type == FileType::Unknown) return nullptr; - return _find(type); + unique_lock lock{mtx}; + auto loader = _activeLoaders.head; + + auto key = HASH_KEY(data, size); + + while (loader) { + if (loader->type == type && loader->hashkey == key) { + ++loader->sharing; + return loader; + } + loader = loader->next; + } + return nullptr; } @@ -185,40 +254,95 @@ static LoadModule* _findByType(const string& mimeType) bool LoaderMgr::init() { - //TODO: - return true; } bool LoaderMgr::term() { - //TODO: + auto loader = _activeLoaders.head; + + //clean up the remained font loaders which is globally used. + while (loader && loader->type == FileType::Ttf) { + auto ret = loader->close(); + auto tmp = loader; + loader = loader->next; + _activeLoaders.remove(tmp); + if (ret) delete(loader); + } + return true; +} + +bool LoaderMgr::retrieve(LoadModule* loader) +{ + if (!loader) return false; + if (loader->close()) { + { + unique_lock lock{mtx}; + _activeLoaders.remove(loader); + } + delete(loader); + } return true; } -shared_ptr LoaderMgr::loader(const string& path, bool* invalid) +LoadModule* LoaderMgr::loader(const string& path, bool* invalid) { *invalid = false; + if (auto loader = _findFromCache(path)) return loader; + if (auto loader = _findByPath(path)) { - if (loader->open(path)) return shared_ptr(loader); - else delete(loader); + if (loader->open(path)) { + loader->hashpath = strdup(path.c_str()); + { + unique_lock lock{mtx}; + _activeLoaders.back(loader); + } + return loader; + } + delete(loader); *invalid = true; } return nullptr; } -shared_ptr LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy) +bool LoaderMgr::retrieve(const string& path) +{ + return retrieve(_findFromCache(path)); +} + + +LoadModule* LoaderMgr::loader(const char* key) +{ + auto loader = _activeLoaders.head; + + while (loader) { + if (loader->hashpath && strstr(loader->hashpath, key)) { + ++loader->sharing; + return loader; + } + loader = loader->next; + } + return nullptr; +} + + +LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy) { + if (auto loader = _findFromCache(data, size, mimeType)) return loader; + //Try with the given MimeType if (!mimeType.empty()) { if (auto loader = _findByType(mimeType)) { if (loader->open(data, size, copy)) { - return shared_ptr(loader); + loader->hashkey = HASH_KEY(data, size); + unique_lock lock{mtx}; + _activeLoaders.back(loader); + return loader; } else { TVGLOG("LOADER", "Given mimetype \"%s\" seems incorrect or not supported.", mimeType.c_str()); delete(loader); @@ -229,8 +353,15 @@ shared_ptr LoaderMgr::loader(const char* data, uint32_t size, const for (int i = 0; i < static_cast(FileType::Unknown); i++) { auto loader = _find(static_cast(i)); if (loader) { - if (loader->open(data, size, copy)) return shared_ptr(loader); - else delete(loader); + if (loader->open(data, size, copy)) { + loader->hashkey = HASH_KEY(data, size); + { + unique_lock lock{mtx}; + _activeLoaders.back(loader); + } + return loader; + } + delete(loader); } } } @@ -238,12 +369,21 @@ shared_ptr LoaderMgr::loader(const char* data, uint32_t size, const } -shared_ptr LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool copy) +LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool copy) { + //TODO: should we check premultiplied?? + if (auto loader = _findFromCache((const char*)(data), w * h, "raw")) return loader; + //function is dedicated for raw images only auto loader = new RawLoader; - if (loader->open(data, w, h, copy)) return shared_ptr(loader); - else delete(loader); - + if (loader->open(data, w, h, copy)) { + loader->hashkey = HASH_KEY((const char*)data, w * h); + { + unique_lock lock{mtx}; + _activeLoaders.back(loader); + } + return loader; + } + delete(loader); return nullptr; } diff --git a/thirdparty/thorvg/src/renderer/tvgLoader.h b/thirdparty/thorvg/src/renderer/tvgLoader.h index 17ff9e2637c8..b15032df274a 100644 --- a/thirdparty/thorvg/src/renderer/tvgLoader.h +++ b/thirdparty/thorvg/src/renderer/tvgLoader.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -29,9 +29,12 @@ struct LoaderMgr { static bool init(); static bool term(); - static shared_ptr loader(const string& path, bool* invalid); - static shared_ptr loader(const char* data, uint32_t size, const string& mimeType, bool copy); - static shared_ptr loader(const uint32_t* data, uint32_t w, uint32_t h, bool copy); + static LoadModule* loader(const string& path, bool* invalid); + static LoadModule* loader(const char* data, uint32_t size, const string& mimeType, bool copy); + static LoadModule* loader(const uint32_t* data, uint32_t w, uint32_t h, bool copy); + static LoadModule* loader(const char* key); + static bool retrieve(const string& path); + static bool retrieve(LoadModule* loader); }; #endif //_TVG_LOADER_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.cpp b/thirdparty/thorvg/src/renderer/tvgPaint.cpp index 008e6589b5d1..563db3b44a0a 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPaint.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,7 @@ #include "tvgShape.h" #include "tvgPicture.h" #include "tvgScene.h" +#include "tvgText.h" /************************************************************************/ /* Internal Class Implementation */ @@ -35,6 +36,7 @@ case TVG_CLASS_ID_SHAPE: ret = P((Shape*)paint)->METHOD; break; \ case TVG_CLASS_ID_SCENE: ret = P((Scene*)paint)->METHOD; break; \ case TVG_CLASS_ID_PICTURE: ret = P((Picture*)paint)->METHOD; break; \ + case TVG_CLASS_ID_TEXT: ret = P((Text*)paint)->METHOD; break; \ default: ret = {}; \ } diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.h b/thirdparty/thorvg/src/renderer/tvgPaint.h index f4721f8e15b1..4ec9fa7f7e9c 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.h +++ b/thirdparty/thorvg/src/renderer/tvgPaint.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.cpp b/thirdparty/thorvg/src/renderer/tvgPicture.cpp index e38279569820..7f120593f45f 100644 --- a/thirdparty/thorvg/src/renderer/tvgPicture.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPicture.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,9 +30,8 @@ RenderUpdateFlag Picture::Impl::load() { if (loader) { if (!paint) { - if (auto p = loader->paint()) { - paint = p.release(); - loader->close(); + paint = loader->paint(); + if (paint) { if (w != loader->w || h != loader->h) { if (!resizing) { w = loader->w; @@ -41,13 +40,12 @@ RenderUpdateFlag Picture::Impl::load() loader->resize(paint, w, h); resizing = false; } - if (paint) return RenderUpdateFlag::None; + return RenderUpdateFlag::None; } } else loader->sync(); if (!surface) { - if ((surface = loader->bitmap().release())) { - loader->close(); + if ((surface = loader->bitmap())) { return RenderUpdateFlag::Image; } } @@ -55,6 +53,93 @@ RenderUpdateFlag Picture::Impl::load() return RenderUpdateFlag::None; } + +bool Picture::Impl::needComposition(uint8_t opacity) +{ + //In this case, paint(scene) would try composition itself. + if (opacity < 255) return false; + + //Composition test + const Paint* target; + auto method = picture->composite(&target); + if (!target || method == tvg::CompositeMethod::ClipPath) return false; + if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return false; + + return true; +} + + +bool Picture::Impl::render(RenderMethod &renderer) +{ + bool ret = false; + if (surface) return renderer.renderImage(rd); + else if (paint) { + Compositor* cmp = nullptr; + if (needComp) { + cmp = renderer.target(bounds(renderer), renderer.colorSpace()); + renderer.beginComposite(cmp, CompositeMethod::None, 255); + } + ret = paint->pImpl->render(renderer); + if (cmp) renderer.endComposite(cmp); + } + return ret; +} + + +bool Picture::Impl::size(float w, float h) +{ + this->w = w; + this->h = h; + resizing = true; + return true; +} + + +RenderRegion Picture::Impl::bounds(RenderMethod& renderer) +{ + if (rd) return renderer.region(rd); + if (paint) return paint->pImpl->bounds(renderer); + return {0, 0, 0, 0}; +} + + +RenderTransform Picture::Impl::resizeTransform(const RenderTransform* pTransform) +{ + //Overriding Transformation by the desired image size + auto sx = w / loader->w; + auto sy = h / loader->h; + auto scale = sx < sy ? sx : sy; + + RenderTransform tmp; + tmp.m = {scale, 0, 0, 0, scale, 0, 0, 0, 1}; + + if (!pTransform) return tmp; + else return RenderTransform(pTransform, &tmp); +} + + +Result Picture::Impl::load(ImageLoader* loader) +{ + //Same resource has been loaded. + if (this->loader == loader) { + this->loader->sharing--; //make it sure the reference counting. + return Result::Success; + } else if (this->loader) { + LoaderMgr::retrieve(this->loader); + } + + this->loader = loader; + + if (!loader->read()) return Result::Unknown; + + this->w = loader->w; + this->h = loader->h; + + return Result::Success; +} + + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ diff --git a/thirdparty/thorvg/src/renderer/tvgPicture.h b/thirdparty/thorvg/src/renderer/tvgPicture.h index 447f56ecb799..26a171ba663b 100644 --- a/thirdparty/thorvg/src/renderer/tvgPicture.h +++ b/thirdparty/thorvg/src/renderer/tvgPicture.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,16 +20,13 @@ * SOFTWARE. */ -#ifndef _TVG_PICTURE_IMPL_H_ -#define _TVG_PICTURE_IMPL_H_ +#ifndef _TVG_PICTURE_H_ +#define _TVG_PICTURE_H_ #include #include "tvgPaint.h" #include "tvgLoader.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ struct PictureIterator : Iterator { @@ -60,7 +57,7 @@ struct PictureIterator : Iterator struct Picture::Impl { - shared_ptr loader = nullptr; + ImageLoader* loader = nullptr; Paint* paint = nullptr; //vector picture uses Surface* surface = nullptr; //bitmap picture uses @@ -71,14 +68,21 @@ struct Picture::Impl bool resizing = false; bool needComp = false; //need composition + RenderTransform resizeTransform(const RenderTransform* pTransform); + bool needComposition(uint8_t opacity); + bool render(RenderMethod &renderer); + bool size(float w, float h); + RenderRegion bounds(RenderMethod& renderer); + Result load(ImageLoader* ploader); + Impl(Picture* p) : picture(p) { } ~Impl() { + LoaderMgr::retrieve(loader); delete(paint); - delete(surface); } bool dispose(RenderMethod& renderer) @@ -89,34 +93,6 @@ struct Picture::Impl return true; } - RenderTransform resizeTransform(const RenderTransform* pTransform) - { - //Overriding Transformation by the desired image size - auto sx = w / loader->w; - auto sy = h / loader->h; - auto scale = sx < sy ? sx : sy; - - RenderTransform tmp; - tmp.m = {scale, 0, 0, 0, scale, 0, 0, 0, 1}; - - if (!pTransform) return tmp; - else return RenderTransform(pTransform, &tmp); - } - - bool needComposition(uint8_t opacity) - { - //In this case, paint(scene) would try composition itself. - if (opacity < 255) return false; - - //Composition test - const Paint* target; - auto method = picture->composite(&target); - if (!target || method == tvg::CompositeMethod::ClipPath) return false; - if (target->pImpl->opacity == 255 || target->pImpl->opacity == 0) return false; - - return true; - } - RenderData update(RenderMethod &renderer, const RenderTransform* pTransform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) { auto flag = load(); @@ -135,30 +111,6 @@ struct Picture::Impl return rd; } - bool render(RenderMethod &renderer) - { - bool ret = false; - if (surface) return renderer.renderImage(rd); - else if (paint) { - Compositor* cmp = nullptr; - if (needComp) { - cmp = renderer.target(bounds(renderer), renderer.colorSpace()); - renderer.beginComposite(cmp, CompositeMethod::None, 255); - } - ret = paint->pImpl->render(renderer); - if (cmp) renderer.endComposite(cmp); - } - return ret; - } - - bool size(float w, float h) - { - this->w = w; - this->h = h; - resizing = true; - return true; - } - bool bounds(float* x, float* y, float* w, float* h, bool stroking) { if (rm.triangleCnt > 0) { @@ -195,50 +147,35 @@ struct Picture::Impl return true; } - RenderRegion bounds(RenderMethod& renderer) - { - if (rd) return renderer.region(rd); - if (paint) return paint->pImpl->bounds(renderer); - return {0, 0, 0, 0}; - } - Result load(const string& path) { if (paint || surface) return Result::InsufficientCondition; - if (loader) loader->close(); + bool invalid; //Invalid Path - loader = LoaderMgr::loader(path, &invalid); + auto loader = static_cast(LoaderMgr::loader(path, &invalid)); if (!loader) { if (invalid) return Result::InvalidArguments; return Result::NonSupport; } - if (!loader->read()) return Result::Unknown; - w = loader->w; - h = loader->h; - return Result::Success; + return load(loader); } Result load(const char* data, uint32_t size, const string& mimeType, bool copy) { if (paint || surface) return Result::InsufficientCondition; - if (loader) loader->close(); - loader = LoaderMgr::loader(data, size, mimeType, copy); + auto loader = static_cast(LoaderMgr::loader(data, size, mimeType, copy)); if (!loader) return Result::NonSupport; - if (!loader->read()) return Result::Unknown; - w = loader->w; - h = loader->h; - return Result::Success; + return load(loader); } Result load(uint32_t* data, uint32_t w, uint32_t h, bool copy) { if (paint || surface) return Result::InsufficientCondition; - if (loader) loader->close(); - loader = LoaderMgr::loader(data, w, h, copy); + + auto loader = static_cast(LoaderMgr::loader(data, w, h, copy)); if (!loader) return Result::FailedAllocation; - this->w = loader->w; - this->h = loader->h; - return Result::Success; + + return load(loader); } void mesh(const Polygon* triangles, const uint32_t triangleCnt) @@ -258,18 +195,17 @@ struct Picture::Impl { load(); - auto ret = Picture::gen(); + auto ret = Picture::gen().release(); + auto dup = ret->pImpl; - auto dup = ret.get()->pImpl; if (paint) dup->paint = paint->duplicate(); - dup->loader = loader; - if (surface) { - dup->surface = new Surface; - *dup->surface = *surface; - //TODO: A dupilcation is not a proxy... it needs copy of the pixel data? - dup->surface->owner = false; + if (loader) { + dup->loader = loader; + ++dup->loader->sharing; } + + dup->surface = surface; dup->w = w; dup->h = h; dup->resizing = resizing; @@ -280,7 +216,7 @@ struct Picture::Impl memcpy(dup->rm.triangles, rm.triangles, sizeof(Polygon) * rm.triangleCnt); } - return ret.release(); + return ret; } Iterator* iterator() @@ -308,4 +244,4 @@ struct Picture::Impl RenderUpdateFlag load(); }; -#endif //_TVG_PICTURE_IMPL_H_ +#endif //_TVG_PICTURE_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgRender.cpp b/thirdparty/thorvg/src/renderer/tvgRender.cpp index 64d76d356207..bdfb9f322eb5 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.cpp +++ b/thirdparty/thorvg/src/renderer/tvgRender.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h index 6c0a7d5f1351..1e70b5349403 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.h +++ b/thirdparty/thorvg/src/renderer/tvgRender.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,6 +23,7 @@ #ifndef _TVG_RENDER_H_ #define _TVG_RENDER_H_ +#include #include "tvgCommon.h" #include "tvgArray.h" @@ -49,17 +50,33 @@ enum ColorSpace struct Surface { union { - pixel_t* data; //system based data pointer - uint32_t* buf32; //for explicit 32bits channels - uint8_t* buf8; //for explicit 8bits grayscale + pixel_t* data = nullptr; //system based data pointer + uint32_t* buf32; //for explicit 32bits channels + uint8_t* buf8; //for explicit 8bits grayscale }; - uint32_t stride; - uint32_t w, h; - ColorSpace cs; - uint8_t channelSize; + mutex mtx; //used for thread safety + uint32_t stride = 0; + uint32_t w = 0, h = 0; + ColorSpace cs = ColorSpace::Unsupported; + uint8_t channelSize = 0; + bool premultiplied = 0; //Alpha-premultiplied + + Surface() + { + } + + Surface(const Surface* rhs) + { + data = rhs->data; + stride = rhs->stride; + w = rhs->w; + h = rhs->h; + cs = rhs->cs; + channelSize = rhs->channelSize; + premultiplied = rhs->premultiplied; + } + - bool premultiplied; //Alpha-premultiplied - bool owner; //Only owner could modify the buffer }; struct Compositor diff --git a/thirdparty/thorvg/src/renderer/tvgSaveModule.h b/thirdparty/thorvg/src/renderer/tvgSaveModule.h index 09e7bde72bb5..fed05c52dfd7 100644 --- a/thirdparty/thorvg/src/renderer/tvgSaveModule.h +++ b/thirdparty/thorvg/src/renderer/tvgSaveModule.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,7 +34,7 @@ class SaveModule virtual ~SaveModule() {} virtual bool save(Paint* paint, const string& path, bool compress) = 0; - virtual bool save(Animation* animation, const string& path, uint32_t quality, uint32_t fps) = 0; + virtual bool save(Animation* animation, Paint* bg, const string& path, uint32_t quality, uint32_t fps) = 0; virtual bool close() = 0; }; diff --git a/thirdparty/thorvg/src/renderer/tvgSaver.cpp b/thirdparty/thorvg/src/renderer/tvgSaver.cpp index 038d1ad097b9..11eb24d43790 100644 --- a/thirdparty/thorvg/src/renderer/tvgSaver.cpp +++ b/thirdparty/thorvg/src/renderer/tvgSaver.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,9 +37,12 @@ struct Saver::Impl { SaveModule* saveModule = nullptr; + Paint* bg = nullptr; + ~Impl() { delete(saveModule); + delete(bg); } }; @@ -139,7 +142,16 @@ Result Saver::save(std::unique_ptr paint, const string& path, bool compre } -Result Saver::save(std::unique_ptr animation, const string& path, uint32_t quality, uint32_t fps) noexcept +Result Saver::background(unique_ptr paint) noexcept +{ + delete(pImpl->bg); + pImpl->bg = paint.release(); + + return Result::Success; +} + + +Result Saver::save(unique_ptr animation, const string& path, uint32_t quality, uint32_t fps) noexcept { auto a = animation.release(); if (!a) return Result::MemoryCorruption; @@ -156,7 +168,7 @@ Result Saver::save(std::unique_ptr animation, const string& path, uin } if (auto saveModule = _find(path)) { - if (saveModule->save(a, path, quality, fps)) { + if (saveModule->save(a, pImpl->bg, path, quality, fps)) { pImpl->saveModule = saveModule; return Result::Success; } else { diff --git a/thirdparty/thorvg/src/renderer/tvgScene.cpp b/thirdparty/thorvg/src/renderer/tvgScene.cpp index cd73913b303f..f5809cf93b56 100644 --- a/thirdparty/thorvg/src/renderer/tvgScene.cpp +++ b/thirdparty/thorvg/src/renderer/tvgScene.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgScene.h b/thirdparty/thorvg/src/renderer/tvgScene.h index b558e95a2f58..1a5600c231bb 100644 --- a/thirdparty/thorvg/src/renderer/tvgScene.h +++ b/thirdparty/thorvg/src/renderer/tvgScene.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,15 +20,12 @@ * SOFTWARE. */ -#ifndef _TVG_SCENE_IMPL_H_ -#define _TVG_SCENE_IMPL_H_ +#ifndef _TVG_SCENE_H_ +#define _TVG_SCENE_H_ #include #include "tvgPaint.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ struct SceneIterator : Iterator { @@ -126,8 +123,7 @@ struct Scene::Impl this->renderer = &renderer; if (clipper) { - Array rds; - rds.reserve(paints.size()); + Array rds(paints.size()); for (auto paint : paints) { rds.push(paint->pImpl->update(renderer, transform, clips, opacity, flag, true)); } @@ -216,9 +212,8 @@ struct Scene::Impl Paint* duplicate() { - auto ret = Scene::gen(); - - auto dup = ret.get()->pImpl; + auto ret = Scene::gen().release(); + auto dup = ret->pImpl; for (auto paint : paints) { auto cdup = paint->duplicate(); @@ -226,7 +221,7 @@ struct Scene::Impl dup->paints.push_back(cdup); } - return ret.release(); + return ret; } void clear(bool free) @@ -247,4 +242,4 @@ struct Scene::Impl } }; -#endif //_TVG_SCENE_IMPL_H_ +#endif //_TVG_SCENE_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgShape.cpp b/thirdparty/thorvg/src/renderer/tvgShape.cpp index 9a64c7df9fa3..23b8006dd99b 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.cpp +++ b/thirdparty/thorvg/src/renderer/tvgShape.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h index 46b2d7d0dbdc..a7f122669005 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.h +++ b/thirdparty/thorvg/src/renderer/tvgShape.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,16 +20,13 @@ * SOFTWARE. */ -#ifndef _TVG_SHAPE_IMPL_H_ -#define _TVG_SHAPE_IMPL_H_ +#ifndef _TVG_SHAPE_H_ +#define _TVG_SHAPE_H_ #include #include "tvgMath.h" #include "tvgPaint.h" -/************************************************************************/ -/* Internal Class Implementation */ -/************************************************************************/ struct Shape::Impl { @@ -341,9 +338,9 @@ struct Shape::Impl Paint* duplicate() { - auto ret = Shape::gen(); + auto ret = Shape::gen().release(); + auto dup = ret->pImpl; - auto dup = ret.get()->pImpl; dup->rs.rule = rs.rule; //Color @@ -379,7 +376,7 @@ struct Shape::Impl dup->flag |= RenderUpdateFlag::Gradient; } - return ret.release(); + return ret; } Iterator* iterator() @@ -388,4 +385,4 @@ struct Shape::Impl } }; -#endif //_TVG_SHAPE_IMPL_H_ +#endif //_TVG_SHAPE_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp index 95df6b486da9..44040570496b 100644 --- a/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp +++ b/thirdparty/thorvg/src/renderer/tvgSwCanvas.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp index e3887c60fc38..36d1ce1f8b09 100644 --- a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp +++ b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,11 +20,11 @@ * SOFTWARE. */ -#include #include -#include #include #include +#include "tvgArray.h" +#include "tvgInlist.h" #include "tvgTaskScheduler.h" /************************************************************************/ @@ -34,7 +34,7 @@ namespace tvg { struct TaskQueue { - deque taskDeque; + Inlist taskDeque; mutex mtx; condition_variable ready; bool done = false; @@ -44,8 +44,6 @@ struct TaskQueue { unique_lock lock{mtx, try_to_lock}; if (!lock || taskDeque.empty()) return false; *task = taskDeque.front(); - taskDeque.pop_front(); - return true; } @@ -54,11 +52,9 @@ struct TaskQueue { { unique_lock lock{mtx, try_to_lock}; if (!lock) return false; - taskDeque.push_back(task); + taskDeque.back(task); } - ready.notify_one(); - return true; } @@ -82,8 +78,6 @@ struct TaskQueue { if (taskDeque.empty()) return false; *task = taskDeque.front(); - taskDeque.pop_front(); - return true; } @@ -91,12 +85,10 @@ struct TaskQueue { { { unique_lock lock{mtx}; - taskDeque.push_back(task); + taskDeque.back(task); } - ready.notify_one(); } - }; @@ -105,24 +97,36 @@ static thread_local bool _async = true; //toggle async tasking for each thread struct TaskSchedulerImpl { - uint32_t threadCnt; - vector threads; - vector taskQueues; + Array threads; + Array taskQueues; atomic idx{0}; - TaskSchedulerImpl(unsigned threadCnt) : threadCnt(threadCnt), taskQueues(threadCnt) + TaskSchedulerImpl(unsigned threadCnt) { threads.reserve(threadCnt); + taskQueues.reserve(threadCnt); for (unsigned i = 0; i < threadCnt; ++i) { - threads.emplace_back([&, i] { run(i); }); + taskQueues.push(new TaskQueue); + threads.push(new thread); + } + for (unsigned i = 0; i < threadCnt; ++i) { + *threads.data[i] = thread([&, i] { run(i); }); } } ~TaskSchedulerImpl() { - for (auto& queue : taskQueues) queue.complete(); - for (auto& thread : threads) thread.join(); + for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) { + (*tq)->complete(); + } + for (auto thread = threads.data; thread < threads.end(); ++thread) { + (*thread)->join(); + delete(*thread); + } + for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) { + delete(*tq); + } } void run(unsigned i) @@ -132,14 +136,14 @@ struct TaskSchedulerImpl //Thread Loop while (true) { auto success = false; - for (unsigned x = 0; x < threadCnt * 2; ++x) { - if (taskQueues[(i + x) % threadCnt].tryPop(&task)) { + for (unsigned x = 0; x < threads.count * 2; ++x) { + if (taskQueues[(i + x) % threads.count]->tryPop(&task)) { success = true; break; } } - if (!success && !taskQueues[i].pop(&task)) break; + if (!success && !taskQueues[i]->pop(&task)) break; (*task)(i + 1); } } @@ -147,13 +151,13 @@ struct TaskSchedulerImpl void request(Task* task) { //Async - if (threadCnt > 0 && _async) { + if (threads.count > 0 && _async) { task->prepare(); auto i = idx++; - for (unsigned n = 0; n < threadCnt; ++n) { - if (taskQueues[(i + n) % threadCnt].tryPush(task)) return; + for (unsigned n = 0; n < threads.count; ++n) { + if (taskQueues[(i + n) % threads.count]->tryPush(task)) return; } - taskQueues[i % threadCnt].push(task); + taskQueues[i % threads.count]->push(task); //Sync } else { task->run(0); @@ -192,7 +196,7 @@ void TaskScheduler::request(Task* task) unsigned TaskScheduler::threads() { - if (inst) return inst->threadCnt; + if (inst) return inst->threads.count; return 0; } diff --git a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h index 2dad80f5d040..483e08488036 100644 --- a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h +++ b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. + * Copyright (c) 2020 - 2024 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ #include #include #include "tvgCommon.h" +#include "tvgInlist.h" namespace tvg { @@ -50,6 +51,8 @@ struct Task bool pending = false; public: + INLIST_ITEM(Task); + virtual ~Task() = default; void done() diff --git a/thirdparty/thorvg/src/renderer/tvgText.cpp b/thirdparty/thorvg/src/renderer/tvgText.cpp new file mode 100644 index 000000000000..1fe244c11d39 --- /dev/null +++ b/thirdparty/thorvg/src/renderer/tvgText.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "tvgText.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + + +Text::Text() : pImpl(new Impl) +{ + Paint::pImpl->id = TVG_CLASS_ID_TEXT; +} + + +Text::~Text() +{ + delete(pImpl); +} + + +Result Text::text(const char* text) noexcept +{ + return pImpl->text(text); +} + + +Result Text::font(const char* name, float size, const char* style) noexcept +{ + return pImpl->font(name, size, style); +} + + +Result Text::load(const std::string& path) noexcept +{ + bool invalid; //invalid path + if (!LoaderMgr::loader(path, &invalid)) { + if (invalid) return Result::InvalidArguments; + else return Result::NonSupport; + } + + return Result::Success; +} + + +Result Text::unload(const std::string& path) noexcept +{ + if (LoaderMgr::retrieve(path)) return Result::Success; + return Result::InsufficientCondition; +} + + +Result Text::fill(uint8_t r, uint8_t g, uint8_t b) noexcept +{ + if (!pImpl->paint) return Result::InsufficientCondition; + + return pImpl->fill(r, g, b); +} + + +Result Text::fill(unique_ptr f) noexcept +{ + if (!pImpl->paint) return Result::InsufficientCondition; + + auto p = f.release(); + if (!p) return Result::MemoryCorruption; + + return pImpl->fill(p); +} + + +unique_ptr Text::gen() noexcept +{ + return unique_ptr(new Text); +} + + +uint32_t Text::identifier() noexcept +{ + return TVG_CLASS_ID_TEXT; +} diff --git a/thirdparty/thorvg/src/renderer/tvgText.h b/thirdparty/thorvg/src/renderer/tvgText.h new file mode 100644 index 000000000000..b9f7ef60794b --- /dev/null +++ b/thirdparty/thorvg/src/renderer/tvgText.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _TVG_TEXT_H +#define _TVG_TEXT_H + +#include +#include "tvgShape.h" +#include "tvgFill.h" + +#ifdef THORVG_TTF_LOADER_SUPPORT + #include "tvgTtfLoader.h" +#else + #include "tvgLoader.h" +#endif + +struct Text::Impl +{ + RenderData rd = nullptr; + FontLoader* loader = nullptr; + Shape* paint = nullptr; + char* utf8 = nullptr; + float fontSize; + bool italic = false; + bool changed = false; + + ~Impl() + { + free(utf8); + LoaderMgr::retrieve(loader); + delete(paint); + } + + Result fill(uint8_t r, uint8_t g, uint8_t b) + { + return paint->fill(r, g, b); + } + + Result fill(Fill* f) + { + return paint->fill(cast(f)); + } + + Result text(const char* utf8) + { + free(this->utf8); + if (utf8) this->utf8 = strdup(utf8); + else this->utf8 = nullptr; + changed = true; + + return Result::Success; + } + + Result font(const char* name, float size, const char* style) + { + auto loader = LoaderMgr::loader(name); + if (!loader) return Result::InsufficientCondition; + + //Same resource has been loaded. + if (this->loader == loader) { + this->loader->sharing--; //make it sure the reference counting. + return Result::Success; + } else if (this->loader) { + LoaderMgr::retrieve(this->loader); + } + this->loader = static_cast(loader); + + if (!paint) paint = Shape::gen().release(); + + fontSize = size; + if (style && strstr(style, "italic")) italic = true; + changed = true; + return Result::Success; + } + + RenderRegion bounds(RenderMethod& renderer) + { + return renderer.region(rd); + } + + bool render(RenderMethod& renderer) + { + if (paint) return PP(paint)->render(renderer); + return false; + } + + bool load() + { + if (!loader) return false; + + //reload + if (changed) { + loader->request(paint, utf8, italic); + loader->read(); + changed = false; + } + if (paint) { + loader->resize(paint, fontSize, fontSize); + return true; + } + return false; + } + + RenderData update(RenderMethod& renderer, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag pFlag, bool clipper) + { + if (!load()) return nullptr; + + //transform the gradient coordinates based on the final scaled font. + if (P(paint)->flag & RenderUpdateFlag::Gradient) { + auto fill = P(paint)->rs.fill; + auto scale = 1.0f / loader->scale; + if (fill->identifier() == TVG_CLASS_ID_LINEAR) { + P(static_cast(fill))->x1 *= scale; + P(static_cast(fill))->y1 *= scale; + P(static_cast(fill))->x2 *= scale; + P(static_cast(fill))->y2 *= scale; + } else { + P(static_cast(fill))->cx *= scale; + P(static_cast(fill))->cy *= scale; + P(static_cast(fill))->r *= scale; + P(static_cast(fill))->fx *= scale; + P(static_cast(fill))->fy *= scale; + P(static_cast(fill))->fr *= scale; + } + } + rd = PP(paint)->update(renderer, transform, clips, opacity, pFlag, clipper); + return rd; + } + + bool bounds(float* x, float* y, float* w, float* h, TVG_UNUSED bool stroking) + { + if (!load() || !paint) return false; + paint->bounds(x, y, w, h, true); + return true; + } + + bool dispose(RenderMethod& renderer) + { + renderer.dispose(rd); + this->rd = nullptr; + return true; + } + + Paint* duplicate() + { + load(); + + auto ret = Text::gen().release(); + auto dup = ret->pImpl; + if (paint) dup->paint = static_cast(paint->duplicate()); + + if (loader) { + dup->loader = loader; + ++dup->loader->sharing; + } + + dup->utf8 = strdup(utf8); + dup->italic = italic; + dup->fontSize = fontSize; + + return ret; + } + + Iterator* iterator() + { + return nullptr; + } +}; + + + +#endif //_TVG_TEXT_H diff --git a/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp b/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp new file mode 100644 index 000000000000..5205df173722 --- /dev/null +++ b/thirdparty/thorvg/src/renderer/tvgWgCanvas.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023 - 2024 the ThorVG project. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "tvgCanvas.h" + +#ifdef THORVG_WG_RASTER_SUPPORT + #include "tvgWgRenderer.h" +#endif + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +struct WgCanvas::Impl +{ +}; + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +#ifdef THORVG_WG_RASTER_SUPPORT +WgCanvas::WgCanvas() : Canvas(WgRenderer::gen()), pImpl(new Impl) +#else +WgCanvas::WgCanvas() : Canvas(nullptr), pImpl(nullptr) +#endif +{ +} + +WgCanvas::~WgCanvas() +{ + delete pImpl; +} + +Result WgCanvas::target(void* window, uint32_t w, uint32_t h) noexcept +{ +#ifdef THORVG_WG_RASTER_SUPPORT + if (!window) return Result::InvalidArguments; + if ((w == 0) || (h == 0)) return Result::InvalidArguments; + + //We know renderer type, avoid dynamic_cast for performance. + auto renderer = static_cast(Canvas::pImpl->renderer); + if (!renderer) return Result::MemoryCorruption; + + if (!renderer->target(window, w, h)) return Result::Unknown; + + //Paints must be updated again with this new target. + Canvas::pImpl->needRefresh(); + + return Result::Success; +#endif + return Result::NonSupport; +} + +unique_ptr WgCanvas::gen() noexcept +{ +#ifdef THORVG_WG_RASTER_SUPPORT + return unique_ptr(new WgCanvas); +#endif + return nullptr; +} diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index d4323848da78..a1732d5157b5 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/thirdparty/thorvg/update-thorvg.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -VERSION=0.11.6 +VERSION=0.12.0 cd thirdparty/thorvg/ || true rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/ @@ -52,6 +52,7 @@ cp -rv src/renderer ../src/ # Only sw_engine is enabled. rm -rfv ../src/renderer/gl_engine +rm -rfv ../src/renderer/wg_engine # Enabled embedded loaders: raw, JPEG, PNG. mkdir ../src/loaders From c4fb3bc342c42d64ec1c515664ce7d711b0c4d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Thu, 25 Jan 2024 13:47:18 +0100 Subject: [PATCH 46/95] certs: Sync with Mozilla bundle as of Dec 13, 2023 https://github.com/bagder/ca-bundle/commit/bef37a977ccb45fb4c1b213b79dd6ba438077561 (cherry picked from commit c6e829b4c6ff39d65da9309ccfe083722e9399c5) --- thirdparty/README.md | 2 +- thirdparty/certs/ca-certificates.crt | 381 +++++++++++++++++++-------- 2 files changed, 277 insertions(+), 106 deletions(-) diff --git a/thirdparty/README.md b/thirdparty/README.md index f73666f01ce1..9a3faa084774 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -87,7 +87,7 @@ Files extracted from upstream source: ## certs - Upstream: Mozilla, via https://github.com/bagder/ca-bundle -- Version: git (3aaca635bad074a0ce5c15fa8aa0dff47f5c639a, 2023) +- Version: git (bef37a977ccb45fb4c1b213b79dd6ba438077561, 2023) - License: MPL 2.0 diff --git a/thirdparty/certs/ca-certificates.crt b/thirdparty/certs/ca-certificates.crt index f08a6766c666..df7a026bed97 100644 --- a/thirdparty/certs/ca-certificates.crt +++ b/thirdparty/certs/ca-certificates.crt @@ -1,7 +1,7 @@ ## ## Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Fri Jun 2 21:47:52 2023 GMT +## Certificate data from Mozilla as of: Wed Dec 13 07:16:08 2023 GMT ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates @@ -14,7 +14,7 @@ ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl version 1.29. -## SHA256: c47475103fb05bb562bbadff0d1e72346b03236154e1448a6ca191b740f83507 +## SHA256: 1970dd65858925d68498d2356aea6d03f764422523c5887deca8ce3ba9e1f845 ## @@ -200,27 +200,6 @@ vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- -Security Communication Root CA -============================== ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP -U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw -HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP -U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw -8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM -DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX -5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd -DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 -JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw -DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g -0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a -mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ -s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ -6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi -FL39vmwLAw== ------END CERTIFICATE----- - XRamp Global CA Root ==================== -----BEGIN CERTIFICATE----- @@ -669,39 +648,6 @@ YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r kpeDMdmztcpHWD9f -----END CERTIFICATE----- -Autoridad de Certificacion Firmaprofesional CIF A62634068 -========================================================= ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA -BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 -MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw -QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB -NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD -Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P -B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY -7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH -ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI -plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX -MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX -LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK -bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU -vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud -EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH -DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp -cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA -bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx -ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx -51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk -R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP -T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f -Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl -osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR -crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR -saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD -KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi -6Et8Vcad+qMUu2WFbm5PEn4KPJ2V ------END CERTIFICATE----- - Izenpe.com ========== -----BEGIN CERTIFICATE----- @@ -3222,55 +3168,6 @@ AwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8 rgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR -----END CERTIFICATE----- -E-Tugra Global Root CA RSA v3 -============================= ------BEGIN CERTIFICATE----- -MIIF8zCCA9ugAwIBAgIUDU3FzRYilZYIfrgLfxUGNPt5EDQwDQYJKoZIhvcNAQELBQAwgYAxCzAJ -BgNVBAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUtVHVncmEgRUJHIEEuUy4xHTAb -BgNVBAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYwJAYDVQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290 -IENBIFJTQSB2MzAeFw0yMDAzMTgwOTA3MTdaFw00NTAzMTIwOTA3MTdaMIGAMQswCQYDVQQGEwJU -UjEPMA0GA1UEBxMGQW5rYXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRF -LVR1Z3JhIFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBDQSBSU0Eg -djMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCiZvCJt3J77gnJY9LTQ91ew6aEOErx -jYG7FL1H6EAX8z3DeEVypi6Q3po61CBxyryfHUuXCscxuj7X/iWpKo429NEvx7epXTPcMHD4QGxL -sqYxYdE0PD0xesevxKenhOGXpOhL9hd87jwH7eKKV9y2+/hDJVDqJ4GohryPUkqWOmAalrv9c/SF -/YP9f4RtNGx/ardLAQO/rWm31zLZ9Vdq6YaCPqVmMbMWPcLzJmAy01IesGykNz709a/r4d+ABs8q -QedmCeFLl+d3vSFtKbZnwy1+7dZ5ZdHPOrbRsV5WYVB6Ws5OUDGAA5hH5+QYfERaxqSzO8bGwzrw -bMOLyKSRBfP12baqBqG3q+Sx6iEUXIOk/P+2UNOMEiaZdnDpwA+mdPy70Bt4znKS4iicvObpCdg6 -04nmvi533wEKb5b25Y08TVJ2Glbhc34XrD2tbKNSEhhw5oBOM/J+JjKsBY04pOZ2PJ8QaQ5tndLB -eSBrW88zjdGUdjXnXVXHt6woq0bM5zshtQoK5EpZ3IE1S0SVEgpnpaH/WwAH0sDM+T/8nzPyAPiM -bIedBi3x7+PmBvrFZhNb/FAHnnGGstpvdDDPk1Po3CLW3iAfYY2jLqN4MpBs3KwytQXk9TwzDdbg -h3cXTJ2w2AmoDVf3RIXwyAS+XF1a4xeOVGNpf0l0ZAWMowIDAQABo2MwYTAPBgNVHRMBAf8EBTAD -AQH/MB8GA1UdIwQYMBaAFLK0ruYt9ybVqnUtdkvAG1Mh0EjvMB0GA1UdDgQWBBSytK7mLfcm1ap1 -LXZLwBtTIdBI7zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAImocn+M684uGMQQ -gC0QDP/7FM0E4BQ8Tpr7nym/Ip5XuYJzEmMmtcyQ6dIqKe6cLcwsmb5FJ+Sxce3kOJUxQfJ9emN4 -38o2Fi+CiJ+8EUdPdk3ILY7r3y18Tjvarvbj2l0Upq7ohUSdBm6O++96SmotKygY/r+QLHUWnw/q -ln0F7psTpURs+APQ3SPh/QMSEgj0GDSz4DcLdxEBSL9htLX4GdnLTeqjjO/98Aa1bZL0SmFQhO3s -SdPkvmjmLuMxC1QLGpLWgti2omU8ZgT5Vdps+9u1FGZNlIM7zR6mK7L+d0CGq+ffCsn99t2HVhjY -sCxVYJb6CH5SkPVLpi6HfMsg2wY+oF0Dd32iPBMbKaITVaA9FCKvb7jQmhty3QUBjYZgv6Rn7rWl -DdF/5horYmbDB7rnoEgcOMPpRfunf/ztAmgayncSd6YAVSgU7NbHEqIbZULpkejLPoeJVF3Zr52X -nGnnCv8PWniLYypMfUeUP95L6VPQMPHF9p5J3zugkaOj/s1YzOrfr28oO6Bpm4/srK4rVJ2bBLFH -IK+WEj5jlB0E5y67hscMmoi/dkfv97ALl2bSRM9gUgfh1SxKOidhd8rXj+eHDjD/DLsE4mHDosiX -YY60MGo8bcIHX0pzLz/5FooBZu+6kcpSV3uu1OYP3Qt6f4ueJiDPO++BcYNZ ------END CERTIFICATE----- - -E-Tugra Global Root CA ECC v3 -============================= ------BEGIN CERTIFICATE----- -MIICpTCCAiqgAwIBAgIUJkYZdzHhT28oNt45UYbm1JeIIsEwCgYIKoZIzj0EAwMwgYAxCzAJBgNV -BAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUtVHVncmEgRUJHIEEuUy4xHTAbBgNV -BAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYwJAYDVQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290IENB -IEVDQyB2MzAeFw0yMDAzMTgwOTQ2NThaFw00NTAzMTIwOTQ2NThaMIGAMQswCQYDVQQGEwJUUjEP -MA0GA1UEBxMGQW5rYXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRFLVR1 -Z3JhIFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBDQSBFQ0MgdjMw -djAQBgcqhkjOPQIBBgUrgQQAIgNiAASOmCm/xxAeJ9urA8woLNheSBkQKczLWYHMjLiSF4mDKpL2 -w6QdTGLVn9agRtwcvHbB40fQWxPa56WzZkjnIZpKT4YKfWzqTTKACrJ6CZtpS5iB4i7sAnCWH/31 -Rs7K3IKjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU/4Ixcj75xGZsrTie0bBRiKWQ -zPUwHQYDVR0OBBYEFP+CMXI++cRmbK04ntGwUYilkMz1MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjO -PQQDAwNpADBmAjEA5gVYaWHlLcoNy/EZCL3W/VGSGn5jVASQkZo1kTmZ+gepZpO6yGjUij/67W4W -Aie3AjEA3VoXK3YdZUKWpqxdinlW2Iob35reX8dQj7FbcQwm32pAAOwzkSFxvmjkI6TZraE3 ------END CERTIFICATE----- - Security Communication RootCA3 ============================== -----BEGIN CERTIFICATE----- @@ -3361,3 +3258,277 @@ SR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g UXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== -----END CERTIFICATE----- + +Sectigo Public Server Authentication Root E46 +============================================= +-----BEGIN CERTIFICATE----- +MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH +QjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2 +ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5 +WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0 +aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr +gQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0 +NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud +DgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH +lAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U +SAGKcw== +-----END CERTIFICATE----- + +Sectigo Public Server Authentication Root R46 +============================================= +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT +ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1 +OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T +ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3 +DQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k +1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf +GExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP +FF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu +ZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz +Yw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A +wSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF +plhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ +EoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW +6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI +IUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c +mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp +E0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4 +exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M +0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI +84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m +pFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd +Vw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b +E/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm +J1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL +-----END CERTIFICATE----- + +SSL.com TLS RSA Root CA 2022 +============================ +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG +EwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg +Um9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC +VVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u +9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y +7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac +oOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M +R7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG +D6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW +TO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk +8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq +g+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk +7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu +N+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN +j8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by +iB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU +o3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo +ENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib +MOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi +vRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7 +P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0 +9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE----- + +SSL.com TLS ECC Root CA 2022 +============================ +-----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV +UzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v +dCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx +GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy +JGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1 +5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7 +81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG +MAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w +7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5 +Zn6g6g== +-----END CERTIFICATE----- + +Atos TrustedRoot Root CA ECC TLS 2021 +===================================== +-----BEGIN CERTIFICATE----- +MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB +dG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD +VQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg +VHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT +AkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K +DP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS +b+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX +NtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+ +uDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY +a3cpetskz2VAv9LcjBHo9H1/IISpQuQo +-----END CERTIFICATE----- + +Atos TrustedRoot Root CA RSA TLS 2021 +===================================== +-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD +DCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw +CQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0 +b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV +BAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB +l01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG +vevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK +ZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt +0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK +PNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY +sluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY +Br3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+ +rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa +fJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G +CSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS +4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl +Q3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX +AdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G +slA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt +afcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q +TFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj +1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l +PqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W +HYMfRsCbvUOZ58SWLs5fyQ== +-----END CERTIFICATE----- + +TrustAsia Global Root CA G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG +A1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM +G1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw +MTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu +MSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz +lZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ +Q0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V +P68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag +dB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm +9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc +D0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg +WmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea +mseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF +TIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj +7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E +BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1 +D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T +G3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj +duMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl +cHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys ++TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli +2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y +aFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS +ZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR +JQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH +-----END CERTIFICATE----- + +TrustAsia Global Root CA G4 +=========================== +-----BEGIN CERTIFICATE----- +MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE +BhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry +dXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa +MFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw +IgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8 +m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/ +pDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA +bbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk +dUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== +-----END CERTIFICATE----- + +CommScope Public Trust ECC Root-01 +================================== +-----BEGIN CERTIFICATE----- +MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMwTjELMAkGA1UE +BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz +dCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNaFw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYT +AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg +RUNDIFJvb3QtMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLx +eP0CflfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJEhRGnSjot +6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggqhkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2 +Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liW +pDVfG2XqYZpwI7UNo5uSUm9poIyNStDuiw7LR47QjRE= +-----END CERTIFICATE----- + +CommScope Public Trust ECC Root-02 +================================== +-----BEGIN CERTIFICATE----- +MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMwTjELMAkGA1UE +BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz +dCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRaFw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYT +AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg +RUNDIFJvb3QtMDIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/M +MDALj2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmUv4RDsNuE +SgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggqhkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9 +Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/nich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs7 +3u1Z/GtMMH9ZzkXpc2AVmkzw5l4lIhVtwodZ0LKOag== +-----END CERTIFICATE----- + +CommScope Public Trust RSA Root-01 +================================== +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQELBQAwTjELMAkG +A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU +cnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNV +BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 +c3QgUlNBIFJvb3QtMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45Ft +nYSkYZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslhsuitQDy6 +uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0alDrJLpA6lfO741GIDuZNq +ihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3OjWiE260f6GBfZumbCk6SP/F2krfxQapWs +vCQz0b2If4b19bJzKo98rwjyGpg/qYFlP8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/c +Zip8UlF1y5mO6D1cv547KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTif +BSeolz7pUcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/kQO9 +lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JOHg9O5j9ZpSPcPYeo +KFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkBEa801M/XrmLTBQe0MXXgDW1XT2mH ++VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6UCBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm4 +5P3luG0wDQYJKoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6 +NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQnmhUQo8mUuJM +3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+QgvfKNmwrZggvkN80V4aCRck +jXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2vtrV0KnahP/t1MJ+UXjulYPPLXAziDslg+Mkf +Foom3ecnf+slpoq9uC02EJqxWE2aaE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/W +NyVntHKLr4W96ioDj8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+ +o/E4Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0wlREQKC6/ +oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHnYfkUyq+Dj7+vsQpZXdxc +1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVocicCMb3SgazNNtQEo/a2tiRc7ppqEvOuM +6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw +-----END CERTIFICATE----- + +CommScope Public Trust RSA Root-02 +================================== +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQELBQAwTjELMAkG +A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU +cnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNV +BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 +c3QgUlNBIFJvb3QtMDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3V +rCLENQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0kyI9p+Kx +7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1CrWDaSWqVcN3SAOLMV2MC +e5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxzhkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2W +Wy09X6GDRl224yW4fKcZgBzqZUPckXk2LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rp +M9kzXzehxfCrPfp4sOcsn/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIf +hs1w/tkuFT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5kQMr +eyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3wNemKfrb3vOTlycE +VS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6vwQcQeKwRoi9C8DfF8rhW3Q5iLc4t +Vn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7Gx +cJXvYXowDQYJKoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB +KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3+VGXu6TwYofF +1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbymeAPnCKfWxkxlSaRosTKCL4BWa +MS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3NyqpgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xd +gSGn2rtO/+YHqP65DSdsu3BaVXoT6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2O +HG1QAk8mGEPej1WFsQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+Nm +YWvtPjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2dlklyALKr +dVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ +iRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN +lM47ni3niAIi9G7oyOzWPPO5std3eqx7 +-----END CERTIFICATE----- From 571cb746f9936cc5d636eef49afc102e5b4e9871 Mon Sep 17 00:00:00 2001 From: HolonProduction Date: Sun, 31 Dec 2023 14:25:07 +0100 Subject: [PATCH 47/95] Improve sorting of enum autocompletion (cherry picked from commit 76fd7ec3940df3975508bb6d374a1fe2d1000433) --- modules/gdscript/gdscript_editor.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 62065b56a330..fa81110b9180 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1210,6 +1210,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base return; } + int location = ScriptLanguage::LOCATION_OTHER; + if (!p_only_functions) { List members; if (p_base.value.get_type() != Variant::NIL) { @@ -1223,7 +1225,11 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base continue; } if (!String(E.name).contains("/")) { - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location); + if (base_type.kind == GDScriptParser::DataType::ENUM) { + // Sort enum members in their declaration order. + location += 1; + } if (GDScriptParser::theme_color_names.has(E.name)) { option.theme_color_name = GDScriptParser::theme_color_names[E.name]; } @@ -1239,7 +1245,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base // Enum types are static and cannot change, therefore we skip non-const dictionary methods. continue; } - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location); if (E.arguments.size()) { option.insert_text += "("; } else { From 771db18a5da33d626cb3b212f4fcc8f508afd4d9 Mon Sep 17 00:00:00 2001 From: clayjohn Date: Tue, 24 Oct 2023 18:02:36 +0200 Subject: [PATCH 48/95] Uses screen-aligned quads for origin lines to avoid issues on NVidia While we are add it, use alpha-antialised lines to make them look nice (cherry picked from commit 5591f289d75ffa8f39a946f1ffa64bd3b6b34975) --- editor/plugins/node_3d_editor_plugin.cpp | 148 +++++++++++++++-------- editor/plugins/node_3d_editor_plugin.h | 5 +- 2 files changed, 102 insertions(+), 51 deletions(-) diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index ad7ef2b6ef65..aaed0257d860 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -6490,25 +6490,91 @@ void Node3DEditor::_init_indicators() { origin_enabled = true; grid_enabled = true; - indicator_mat.instantiate(); - indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); - indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); - indicator_mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true); - indicator_mat->set_transparency(StandardMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS); - - Vector origin_colors; + Ref origin_shader = memnew(Shader); + origin_shader->set_code(R"( +// 3D editor origin line shader. + +shader_type spatial; +render_mode blend_mix,cull_disabled,unshaded, fog_disabled; + +void vertex() { + vec3 point_a = MODEL_MATRIX[3].xyz; + // Encoded in scale. + vec3 point_b = vec3(MODEL_MATRIX[0].x, MODEL_MATRIX[1].y, MODEL_MATRIX[2].z); + + // Points are already in world space, so no need for MODEL_MATRIX anymore. + vec4 clip_a = PROJECTION_MATRIX * (VIEW_MATRIX * vec4(point_a, 1.0)); + vec4 clip_b = PROJECTION_MATRIX * (VIEW_MATRIX * vec4(point_b, 1.0)); + + vec2 screen_a = VIEWPORT_SIZE * (0.5 * clip_a.xy / clip_a.w + 0.5); + vec2 screen_b = VIEWPORT_SIZE * (0.5 * clip_b.xy / clip_b.w + 0.5); + + vec2 x_basis = normalize(screen_b - screen_a); + vec2 y_basis = vec2(-x_basis.y, x_basis.x); + + float width = 3.0; + vec2 screen_point_a = screen_a + width * (VERTEX.x * x_basis + VERTEX.y * y_basis); + vec2 screen_point_b = screen_b + width * (VERTEX.x * x_basis + VERTEX.y * y_basis); + vec2 screen_point_final = mix(screen_point_a, screen_point_b, VERTEX.z); + + vec4 clip_final = mix(clip_a, clip_b, VERTEX.z); + + POSITION = vec4(clip_final.w * ((2.0 * screen_point_final) / VIEWPORT_SIZE - 1.0), clip_final.z, clip_final.w); + UV = VERTEX.yz * clip_final.w; + + if (!OUTPUT_IS_SRGB) { + COLOR.rgb = mix(pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb * (1.0 / 12.92), lessThan(COLOR.rgb, vec3(0.04045))); + } +} + +void fragment() { + // Multiply by 0.5 since UV is actually UV is [-1, 1]. + float line_width = fwidth(UV.x * 0.5); + float line_uv = abs(UV.x * 0.5); + float line = smoothstep(line_width * 1.0, line_width * 0.25, line_uv); + + ALBEDO = COLOR.rgb; + ALPHA *= COLOR.a * line; +} +)"); + + origin_mat.instantiate(); + origin_mat->set_shader(origin_shader); + Vector origin_points; + origin_points.resize(6); + + origin_points.set(0, Vector3(0.0, -0.5, 0.0)); + origin_points.set(1, Vector3(0.0, -0.5, 1.0)); + origin_points.set(2, Vector3(0.0, 0.5, 1.0)); + + origin_points.set(3, Vector3(0.0, -0.5, 0.0)); + origin_points.set(4, Vector3(0.0, 0.5, 1.0)); + origin_points.set(5, Vector3(0.0, 0.5, 0.0)); + + Array d; + d.resize(RS::ARRAY_MAX); + d[RenderingServer::ARRAY_VERTEX] = origin_points; + + origin_mesh = RenderingServer::get_singleton()->mesh_create(); - const int count_of_elements = 3 * 6; - origin_colors.resize(count_of_elements); - origin_points.resize(count_of_elements); + RenderingServer::get_singleton()->mesh_add_surface_from_arrays(origin_mesh, RenderingServer::PRIMITIVE_TRIANGLES, d); + RenderingServer::get_singleton()->mesh_surface_set_material(origin_mesh, 0, origin_mat->get_rid()); - int x = 0; + origin_multimesh = RenderingServer::get_singleton()->multimesh_create(); + RenderingServer::get_singleton()->multimesh_set_mesh(origin_multimesh, origin_mesh); + RenderingServer::get_singleton()->multimesh_allocate_data(origin_multimesh, 12, RS::MultimeshTransformFormat::MULTIMESH_TRANSFORM_3D, true, false); + RenderingServer::get_singleton()->multimesh_set_visible_instances(origin_multimesh, -1); + + LocalVector distances; + distances.resize(5); + distances[0] = -1000000.0; + distances[1] = -1000.0; + distances[2] = 0.0; + distances[3] = 1000.0; + distances[4] = 1000000.0; for (int i = 0; i < 3; i++) { - Vector3 axis; - axis[i] = 1; Color origin_color; switch (i) { case 0: @@ -6525,27 +6591,26 @@ void Node3DEditor::_init_indicators() { break; } - grid_enable[i] = false; - grid_visible[i] = false; + Vector3 axis; + axis[i] = 1; - origin_colors.set(x, origin_color); - origin_colors.set(x + 1, origin_color); - origin_colors.set(x + 2, origin_color); - origin_colors.set(x + 3, origin_color); - origin_colors.set(x + 4, origin_color); - origin_colors.set(x + 5, origin_color); - // To both allow having a large origin size and avoid jitter - // at small scales, we should segment the line into pieces. - // 3 pieces seems to do the trick, and let's use powers of 2. - origin_points.set(x, axis * 1048576); - origin_points.set(x + 1, axis * 1024); - origin_points.set(x + 2, axis * 1024); - origin_points.set(x + 3, axis * -1024); - origin_points.set(x + 4, axis * -1024); - origin_points.set(x + 5, axis * -1048576); - x += 6; + for (int j = 0; j < 4; j++) { + Transform3D t = Transform3D(); + t = t.scaled(axis * distances[j + 1]); + t = t.translated(axis * distances[j]); + RenderingServer::get_singleton()->multimesh_instance_set_transform(origin_multimesh, i * 4 + j, t); + RenderingServer::get_singleton()->multimesh_instance_set_color(origin_multimesh, i * 4 + j, origin_color); + } } + origin_instance = RenderingServer::get_singleton()->instance_create2(origin_multimesh, get_tree()->get_root()->get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << Node3DEditorViewport::GIZMO_GRID_LAYER); + RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true); + RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false); + RS::get_singleton()->instance_set_ignore_culling(origin_instance, true); + + RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, RS::SHADOW_CASTING_SETTING_OFF); + Ref grid_shader = memnew(Shader); grid_shader->set_code(R"( // 3D editor grid shader. @@ -6594,22 +6659,6 @@ void fragment() { grid_visible[2] = grid_enable[2]; _init_grid(); - - origin = RenderingServer::get_singleton()->mesh_create(); - Array d; - d.resize(RS::ARRAY_MAX); - d[RenderingServer::ARRAY_VERTEX] = origin_points; - d[RenderingServer::ARRAY_COLOR] = origin_colors; - - RenderingServer::get_singleton()->mesh_add_surface_from_arrays(origin, RenderingServer::PRIMITIVE_LINES, d); - RenderingServer::get_singleton()->mesh_surface_set_material(origin, 0, indicator_mat->get_rid()); - - origin_instance = RenderingServer::get_singleton()->instance_create2(origin, get_tree()->get_root()->get_world_3d()->get_scenario()); - RS::get_singleton()->instance_set_layer_mask(origin_instance, 1 << Node3DEditorViewport::GIZMO_GRID_LAYER); - RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true); - RS::get_singleton()->instance_geometry_set_flag(origin_instance, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false); - - RenderingServer::get_singleton()->instance_geometry_set_cast_shadows_setting(origin_instance, RS::SHADOW_CASTING_SETTING_OFF); } { @@ -7227,7 +7276,8 @@ void Node3DEditor::_init_grid() { void Node3DEditor::_finish_indicators() { RenderingServer::get_singleton()->free(origin_instance); - RenderingServer::get_singleton()->free(origin); + RenderingServer::get_singleton()->free(origin_multimesh); + RenderingServer::get_singleton()->free(origin_mesh); _finish_grid(); } diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 1ce09a2bcb60..0f6ea7157116 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -597,7 +597,8 @@ class Node3DEditor : public VBoxContainer { ToolMode tool_mode; - RID origin; + RID origin_mesh; + RID origin_multimesh; RID origin_instance; bool origin_enabled = false; RID grid[3]; @@ -631,7 +632,7 @@ class Node3DEditor : public VBoxContainer { RID indicators_instance; RID cursor_mesh; RID cursor_instance; - Ref indicator_mat; + Ref origin_mat; Ref grid_mat[3]; Ref cursor_material; From b247151af26cd4038b92e8de3c40d4d321675b3f Mon Sep 17 00:00:00 2001 From: BlueCube3310 <53150244+BlueCube3310@users.noreply.github.com> Date: Fri, 20 Oct 2023 22:10:39 +0200 Subject: [PATCH 49/95] Improve Curve3D Debug Drawing (cherry picked from commit 982ce34a58aca97d9bcaeaf95881eb9587997084) --- scene/3d/path_3d.cpp | 59 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 6aea06309684..e38375d339c4 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -93,24 +93,63 @@ void Path3D::_update_debug_mesh() { return; } - Vector vertex_array; + real_t interval = 0.1; + const real_t length = curve->get_baked_length(); - for (int i = 1; i < curve->get_point_count(); i++) { - Vector3 line_end = curve->get_point_position(i); - Vector3 line_start = curve->get_point_position(i - 1); - vertex_array.push_back(line_start); - vertex_array.push_back(line_end); + if (length <= CMP_EPSILON) { + RS::get_singleton()->instance_set_visible(debug_instance, false); + return; } - Array mesh_array; - mesh_array.resize(Mesh::ARRAY_MAX); - mesh_array[Mesh::ARRAY_VERTEX] = vertex_array; + const int sample_count = int(length / interval) + 2; + interval = length / (sample_count - 1); + + Vector ribbon; + ribbon.resize(sample_count); + Vector3 *ribbon_ptr = ribbon.ptrw(); + + Vector bones; + bones.resize(sample_count * 4); + Vector3 *bones_ptr = bones.ptrw(); + + for (int i = 0; i < sample_count; i++) { + const Transform3D r = curve->sample_baked_with_rotation(i * interval, true, true); + + const Vector3 p1 = r.origin; + const Vector3 side = r.basis.get_column(0); + const Vector3 up = r.basis.get_column(1); + const Vector3 forward = r.basis.get_column(2); + + // Path3D as a ribbon. + ribbon_ptr[i] = p1; + + // Fish Bone. + const Vector3 p_left = p1 + (side + forward - up * 0.3) * 0.06; + const Vector3 p_right = p1 + (-side + forward - up * 0.3) * 0.06; + + const int bone_idx = i * 4; + + bones_ptr[bone_idx] = p1; + bones_ptr[bone_idx + 1] = p_left; + bones_ptr[bone_idx + 2] = p1; + bones_ptr[bone_idx + 3] = p_right; + } + + Array ribbon_array; + ribbon_array.resize(Mesh::ARRAY_MAX); + ribbon_array[Mesh::ARRAY_VERTEX] = ribbon; + + Array bone_array; + bone_array.resize(Mesh::ARRAY_MAX); + bone_array[Mesh::ARRAY_VERTEX] = bones; debug_mesh->clear_surfaces(); - debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, mesh_array); + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINE_STRIP, ribbon_array); + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, bone_array); RS::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid()); RS::get_singleton()->mesh_surface_set_material(debug_mesh->get_rid(), 0, st->get_debug_paths_material()->get_rid()); + RS::get_singleton()->mesh_surface_set_material(debug_mesh->get_rid(), 1, st->get_debug_paths_material()->get_rid()); if (is_inside_tree()) { RS::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario()); RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform()); From 28818d1d6c503471ce3fc35e7727fbf23a9ca466 Mon Sep 17 00:00:00 2001 From: MewPurPur Date: Wed, 30 Aug 2023 17:35:22 +0300 Subject: [PATCH 50/95] Add Texture2D and Texture3D icons (cherry picked from commit 6cdd406c3d331854c63720ebf443c319a0c2fa0e) --- editor/icons/Texture2D.svg | 1 + editor/icons/Texture3D.svg | 1 + 2 files changed, 2 insertions(+) create mode 100644 editor/icons/Texture2D.svg create mode 100644 editor/icons/Texture3D.svg diff --git a/editor/icons/Texture2D.svg b/editor/icons/Texture2D.svg new file mode 100644 index 000000000000..635547ba0308 --- /dev/null +++ b/editor/icons/Texture2D.svg @@ -0,0 +1 @@ + diff --git a/editor/icons/Texture3D.svg b/editor/icons/Texture3D.svg new file mode 100644 index 000000000000..208fa41b6114 --- /dev/null +++ b/editor/icons/Texture3D.svg @@ -0,0 +1 @@ + From d01c60c1782f3d19bfa50bdc741cbef96670336c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20W=C3=B6rner?= Date: Mon, 4 Dec 2023 17:19:39 +0100 Subject: [PATCH 51/95] Changed HTML input color_changed logic. Made the HTML field send change events based on whether the new color's string is different from the previous color's string (instead of whether the new string parses to the current color value). Previously, updating the color value even when the corresponding string hadn't changed would unnecessarily quantize the color value to 8 bits just by opening/closing the Color Picker. (cherry picked from commit 21d778b0c3f7b1cb20f07dfe1e16a90097d7012e) --- scene/gui/color_picker.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index f250662be054..bd0b58c9efae 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -556,16 +556,17 @@ void ColorPicker::_html_submitted(const String &p_html) { return; } - const Color previous_color = color; - color = Color::from_string(p_html.strip_edges(), previous_color); + Color new_color = Color::from_string(p_html.strip_edges(), color); if (!is_editing_alpha()) { - color.a = previous_color.a; + new_color.a = color.a; } - if (color == previous_color) { + if (new_color.to_argb32() == color.to_argb32()) { return; } + color = new_color; + if (!is_inside_tree()) { return; } From 6e4cbdc14466199a84e22467b716dfb30cd31f91 Mon Sep 17 00:00:00 2001 From: nikitalita <69168929+nikitalita@users.noreply.github.com> Date: Mon, 20 Mar 2023 18:39:07 -0700 Subject: [PATCH 52/95] SCons: Add `stack_size` and `default_pthread_stack_size` options to Web target (cherry picked from commit 6788bc6bc2be68db9b9f1a37bf5edb8497eafb93) --- platform/web/detect.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/platform/web/detect.py b/platform/web/detect.py index 579eaaff03fd..53fae67f6a45 100644 --- a/platform/web/detect.py +++ b/platform/web/detect.py @@ -30,6 +30,9 @@ def get_opts(): return [ ("initial_memory", "Initial WASM memory (in MiB)", 32), + # Matches default values from before Emscripten 3.1.27. New defaults are too low for Godot. + ("stack_size", "WASM stack size (in KiB)", 5120), + ("default_pthread_stack_size", "WASM pthread default stack size (in KiB)", 2048), BoolVariable("use_assertions", "Use Emscripten runtime assertions", False), BoolVariable("use_ubsan", "Use Emscripten undefined behavior sanitizer (UBSAN)", False), BoolVariable("use_asan", "Use Emscripten address sanitizer (ASAN)", False), @@ -193,11 +196,6 @@ def configure(env: "Environment"): env.Prepend(CPPPATH=["#platform/web"]) env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"]) - if cc_semver >= (3, 1, 25): - env.Append(LINKFLAGS=["-s", "STACK_SIZE=5MB"]) - else: - env.Append(LINKFLAGS=["-s", "TOTAL_STACK=5MB"]) - if env["opengl3"]: env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"]) # This setting just makes WebGL 2 APIs available, it does NOT disable WebGL 1. @@ -208,11 +206,14 @@ def configure(env: "Environment"): if env["javascript_eval"]: env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"]) + stack_size_opt = "STACK_SIZE" if cc_semver >= (3, 1, 25) else "TOTAL_STACK" + env.Append(LINKFLAGS=["-s", "%s=%sKB" % (stack_size_opt, env["stack_size"])]) + # Thread support (via SharedArrayBuffer). env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"]) env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"]) env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"]) - env.Append(LINKFLAGS=["-s", "DEFAULT_PTHREAD_STACK_SIZE=2MB"]) + env.Append(LINKFLAGS=["-s", "DEFAULT_PTHREAD_STACK_SIZE=%sKB" % env["default_pthread_stack_size"]]) env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"]) env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"]) From 8544106b7e4d9add7905da08e3cd3bf720f3cb20 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Sun, 10 Dec 2023 14:40:18 +0100 Subject: [PATCH 53/95] [MP] Handle cleanup of "scene cache" nodes Make sure we delete the relevant ObjectID from the cache when the nodes are removed from tree. (cherry picked from commit 853df2895ad652fb9bbc4d4a38f33ccdc7ec8e54) --- modules/multiplayer/scene_cache_interface.cpp | 164 ++++++++++-------- modules/multiplayer/scene_cache_interface.h | 27 ++- 2 files changed, 109 insertions(+), 82 deletions(-) diff --git a/modules/multiplayer/scene_cache_interface.cpp b/modules/multiplayer/scene_cache_interface.cpp index 56cd0bec18b6..33b05d4cc21d 100644 --- a/modules/multiplayer/scene_cache_interface.cpp +++ b/modules/multiplayer/scene_cache_interface.cpp @@ -35,25 +35,61 @@ #include "core/io/marshalls.h" #include "scene/main/node.h" #include "scene/main/window.h" +#include "scene/scene_string_names.h" + +SceneCacheInterface::NodeCache &SceneCacheInterface::_track(Node *p_node) { + const ObjectID oid = p_node->get_instance_id(); + NodeCache *nc = nodes_cache.getptr(oid); + if (!nc) { + nodes_cache[oid] = NodeCache(); + p_node->connect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneCacheInterface::_remove_node_cache).bind(oid), Object::CONNECT_ONE_SHOT); + } + return nodes_cache[oid]; +} + +void SceneCacheInterface::_remove_node_cache(ObjectID p_oid) { + NodeCache *nc = nodes_cache.getptr(p_oid); + if (!nc) { + return; + } + for (KeyValue &E : nc->recv_ids) { + PeerInfo *pinfo = peers_info.getptr(E.key); + ERR_CONTINUE(!pinfo); + pinfo->recv_nodes.erase(E.value); + } + for (KeyValue &E : nc->confirmed_peers) { + PeerInfo *pinfo = peers_info.getptr(E.key); + ERR_CONTINUE(!pinfo); + pinfo->sent_nodes.erase(p_oid); + } + nodes_cache.erase(p_oid); +} void SceneCacheInterface::on_peer_change(int p_id, bool p_connected) { if (p_connected) { - path_get_cache.insert(p_id, PathGetCache()); + peers_info.insert(p_id, PeerInfo()); } else { - // Cleanup get cache. - path_get_cache.erase(p_id); - // Cleanup sent cache. - // Some refactoring is needed to make this faster and do paths GC. - for (KeyValue &E : path_send_cache) { - E.value.confirmed_peers.erase(p_id); + PeerInfo *pinfo = peers_info.getptr(p_id); + ERR_FAIL_NULL(pinfo); // Bug. + for (KeyValue E : pinfo->recv_nodes) { + NodeCache *nc = nodes_cache.getptr(E.value); + ERR_CONTINUE(!nc); + nc->recv_ids.erase(E.key); + } + for (const ObjectID &oid : pinfo->sent_nodes) { + NodeCache *nc = nodes_cache.getptr(oid); + ERR_CONTINUE(!nc); + nc->confirmed_peers.erase(p_id); } + peers_info.erase(p_id); } } void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) { + ERR_FAIL_COND(!peers_info.has(p_from)); // Bug. + ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small."); Node *root_node = SceneTree::get_singleton()->get_root()->get_node(multiplayer->get_root_path()); ERR_FAIL_NULL(root_node); - ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small."); int ofs = 1; String methods_md5; @@ -63,15 +99,13 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac int id = decode_uint32(&p_packet[ofs]); ofs += 4; + ERR_FAIL_COND_MSG(peers_info[p_from].recv_nodes.has(id), vformat("Duplicate remote cache ID %d for peer %d", id, p_from)); + String paths; paths.parse_utf8((const char *)(p_packet + ofs), p_packet_len - ofs); const NodePath path = paths; - if (!path_get_cache.has(p_from)) { - path_get_cache[p_from] = PathGetCache(); - } - Node *node = root_node->get_node(path); ERR_FAIL_NULL(node); const bool valid_rpc_checksum = multiplayer->get_rpc_md5(node) == methods_md5; @@ -79,10 +113,9 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path); } - PathGetCache::NodeInfo ni; - ni.path = node->get_path(); - - path_get_cache[p_from].nodes[id] = ni; + peers_info[p_from].recv_nodes.insert(id, node->get_instance_id()); + NodeCache &cache = _track(node); + cache.recv_ids.insert(p_from, id); // Encode path to send ack. CharString pname = String(path).utf8(); @@ -122,15 +155,15 @@ void SceneCacheInterface::process_confirm_path(int p_from, const uint8_t *p_pack Node *node = root_node->get_node(path); ERR_FAIL_NULL(node); - PathSentCache *psc = path_send_cache.getptr(node->get_instance_id()); - ERR_FAIL_NULL_MSG(psc, "Invalid packet received. Tries to confirm a path which was not found in cache."); + NodeCache *cache = nodes_cache.getptr(node->get_instance_id()); + ERR_FAIL_NULL_MSG(cache, "Invalid packet received. Tries to confirm a node which was not requested."); - HashMap::Iterator E = psc->confirmed_peers.find(p_from); - ERR_FAIL_COND_MSG(!E, "Invalid packet received. Source peer was not found in cache for the given path."); - E->value = true; + bool *confirmed = cache->confirmed_peers.getptr(p_from); + ERR_FAIL_NULL_MSG(confirmed, "Invalid packet received. Tries to confirm a node which was not requested."); + *confirmed = true; } -Error SceneCacheInterface::_send_confirm_path(Node *p_node, PathSentCache *psc, const List &p_peers) { +Error SceneCacheInterface::_send_confirm_path(Node *p_node, NodeCache &p_cache, const List &p_peers) { // Encode function name. const CharString path = String(multiplayer->get_root_path().rel_path_to(p_node->get_path())).utf8(); const int path_len = encode_cstring(path.get_data(), nullptr); @@ -148,7 +181,7 @@ Error SceneCacheInterface::_send_confirm_path(Node *p_node, PathSentCache *psc, ofs += encode_cstring(methods_md5.utf8().get_data(), &packet.write[ofs]); - ofs += encode_uint32(psc->id, &packet.write[ofs]); + ofs += encode_uint32(p_cache.cache_id, &packet.write[ofs]); ofs += encode_cstring(path.get_data(), &packet.write[ofs]); @@ -162,80 +195,74 @@ Error SceneCacheInterface::_send_confirm_path(Node *p_node, PathSentCache *psc, err = multiplayer->send_command(peer_id, packet.ptr(), packet.size()); ERR_FAIL_COND_V(err != OK, err); // Insert into confirmed, but as false since it was not confirmed. - psc->confirmed_peers.insert(peer_id, false); + p_cache.confirmed_peers.insert(peer_id, false); + ERR_CONTINUE(!peers_info.has(peer_id)); + peers_info[peer_id].sent_nodes.insert(p_node->get_instance_id()); } return err; } bool SceneCacheInterface::is_cache_confirmed(Node *p_node, int p_peer) { ERR_FAIL_NULL_V(p_node, false); - const PathSentCache *psc = path_send_cache.getptr(p_node->get_instance_id()); - ERR_FAIL_NULL_V(psc, false); - HashMap::ConstIterator F = psc->confirmed_peers.find(p_peer); - ERR_FAIL_COND_V(!F, false); // Should never happen. - return F->value; + const ObjectID oid = p_node->get_instance_id(); + NodeCache *cache = nodes_cache.getptr(oid); + bool *confirmed = cache ? cache->confirmed_peers.getptr(p_peer) : nullptr; + return confirmed && *confirmed; } int SceneCacheInterface::make_object_cache(Object *p_obj) { Node *node = Object::cast_to(p_obj); ERR_FAIL_NULL_V(node, -1); - const ObjectID oid = node->get_instance_id(); - // See if the path is cached. - PathSentCache *psc = path_send_cache.getptr(oid); - if (!psc) { - // Path is not cached, create. - path_send_cache[oid] = PathSentCache(); - psc = path_send_cache.getptr(oid); - psc->id = last_send_cache_id++; + NodeCache &cache = _track(node); + if (cache.cache_id == 0) { + cache.cache_id = last_send_cache_id++; } - return psc->id; + return cache.cache_id; } bool SceneCacheInterface::send_object_cache(Object *p_obj, int p_peer_id, int &r_id) { Node *node = Object::cast_to(p_obj); ERR_FAIL_NULL_V(node, false); - const ObjectID oid = node->get_instance_id(); // See if the path is cached. - PathSentCache *psc = path_send_cache.getptr(oid); - if (!psc) { - // Path is not cached, create. - path_send_cache[oid] = PathSentCache(); - psc = path_send_cache.getptr(oid); - psc->id = last_send_cache_id++; + NodeCache &cache = _track(node); + if (cache.cache_id == 0) { + cache.cache_id = last_send_cache_id++; } - r_id = psc->id; + r_id = cache.cache_id; bool has_all_peers = true; List peers_to_add; // If one is missing, take note to add it. if (p_peer_id > 0) { // Fast single peer check. - HashMap::Iterator F = psc->confirmed_peers.find(p_peer_id); - if (!F) { + ERR_FAIL_COND_V_MSG(!peers_info.has(p_peer_id), false, "Peer doesn't exist: " + itos(p_peer_id)); + + bool *confirmed = cache.confirmed_peers.getptr(p_peer_id); + if (!confirmed) { peers_to_add.push_back(p_peer_id); // Need to also be notified. has_all_peers = false; - } else if (!F->value) { + } else if (!(*confirmed)) { has_all_peers = false; } } else { // Long and painful. - for (const int &E : multiplayer->get_connected_peers()) { - if (p_peer_id < 0 && E == -p_peer_id) { + for (KeyValue &E : peers_info) { + if (p_peer_id < 0 && E.key == -p_peer_id) { continue; // Continue, excluded. } - HashMap::Iterator F = psc->confirmed_peers.find(E); - if (!F) { - peers_to_add.push_back(E); // Need to also be notified. + bool *confirmed = cache.confirmed_peers.getptr(E.key); + if (!confirmed) { + peers_to_add.push_back(E.key); // Need to also be notified. has_all_peers = false; - } else if (!F->value) { + } else if (!(*confirmed)) { has_all_peers = false; } } } if (peers_to_add.size()) { - _send_confirm_path(node, psc, peers_to_add); + _send_confirm_path(node, cache, peers_to_add); } return has_all_peers; @@ -244,22 +271,23 @@ bool SceneCacheInterface::send_object_cache(Object *p_obj, int p_peer_id, int &r Object *SceneCacheInterface::get_cached_object(int p_from, uint32_t p_cache_id) { Node *root_node = SceneTree::get_singleton()->get_root()->get_node(multiplayer->get_root_path()); ERR_FAIL_NULL_V(root_node, nullptr); - HashMap::Iterator E = path_get_cache.find(p_from); - ERR_FAIL_COND_V_MSG(!E, nullptr, vformat("No cache found for peer %d.", p_from)); - - HashMap::Iterator F = E->value.nodes.find(p_cache_id); - ERR_FAIL_COND_V_MSG(!F, nullptr, vformat("ID %d not found in cache of peer %d.", p_cache_id, p_from)); + PeerInfo *pinfo = peers_info.getptr(p_from); + ERR_FAIL_NULL_V(pinfo, nullptr); - PathGetCache::NodeInfo *ni = &F->value; - Node *node = root_node->get_node(ni->path); - if (!node) { - ERR_PRINT("Failed to get cached path: " + String(ni->path) + "."); - } + const ObjectID *oid = pinfo->recv_nodes.getptr(p_cache_id); + ERR_FAIL_NULL_V_MSG(oid, nullptr, vformat("ID %d not found in cache of peer %d.", p_cache_id, p_from)); + Node *node = Object::cast_to(ObjectDB::get_instance(*oid)); + ERR_FAIL_NULL_V_MSG(node, nullptr, vformat("Failed to get cached node from peer %d with cache ID %d.", p_from, p_cache_id)); return node; } void SceneCacheInterface::clear() { - path_get_cache.clear(); - path_send_cache.clear(); + for (KeyValue &E : nodes_cache) { + Object *obj = ObjectDB::get_instance(E.key); + ERR_CONTINUE(!obj); + obj->disconnect(SceneStringNames::get_singleton()->tree_exited, callable_mp(this, &SceneCacheInterface::_remove_node_cache)); + } + peers_info.clear(); + nodes_cache.clear(); last_send_cache_id = 1; } diff --git a/modules/multiplayer/scene_cache_interface.h b/modules/multiplayer/scene_cache_interface.h index e63beb5f84f8..ab4a20c078dc 100644 --- a/modules/multiplayer/scene_cache_interface.h +++ b/modules/multiplayer/scene_cache_interface.h @@ -43,27 +43,26 @@ class SceneCacheInterface : public RefCounted { SceneMultiplayer *multiplayer = nullptr; //path sent caches - struct PathSentCache { - HashMap confirmed_peers; - int id; + struct NodeCache { + int cache_id; + HashMap recv_ids; // peer id, remote cache id + HashMap confirmed_peers; // peer id, confirmed }; - //path get caches - struct PathGetCache { - struct NodeInfo { - NodePath path; - ObjectID instance; - }; - - HashMap nodes; + struct PeerInfo { + HashMap recv_nodes; // remote cache id, ObjectID + HashSet sent_nodes; }; - HashMap path_send_cache; - HashMap path_get_cache; + HashMap nodes_cache; + HashMap peers_info; int last_send_cache_id = 1; + void _remove_node_cache(ObjectID p_oid); + NodeCache &_track(Node *p_node); + protected: - Error _send_confirm_path(Node *p_node, PathSentCache *psc, const List &p_peers); + Error _send_confirm_path(Node *p_node, NodeCache &p_cache, const List &p_peers); public: void clear(); From 5a7c19f6c4192734a36c665d80a3cbea03b843d4 Mon Sep 17 00:00:00 2001 From: jsjtxietian Date: Tue, 12 Dec 2023 18:00:37 +0800 Subject: [PATCH 54/95] Fix "Class name cannot be empty" error when sorting no import files by type (cherry picked from commit 5b57db263777388899847cd0a3f27421fee61e93) --- editor/filesystem_dock.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index a47bbd321d92..31f9b3e56f22 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -859,18 +859,7 @@ void FileSystemDock::_search(EditorFileSystemDirectory *p_path, List * struct FileSystemDock::FileInfoTypeComparator { bool operator()(const FileInfo &p_a, const FileInfo &p_b) const { - // Uses the extension, then the icon name to distinguish file types. - String icon_path_a = ""; - String icon_path_b = ""; - Ref icon_a = EditorNode::get_singleton()->get_class_icon(p_a.type); - if (icon_a.is_valid()) { - icon_path_a = icon_a->get_name(); - } - Ref icon_b = EditorNode::get_singleton()->get_class_icon(p_b.type); - if (icon_b.is_valid()) { - icon_path_b = icon_b->get_name(); - } - return NaturalNoCaseComparator()(p_a.name.get_extension() + icon_path_a + p_a.name.get_basename(), p_b.name.get_extension() + icon_path_b + p_b.name.get_basename()); + return NaturalNoCaseComparator()(p_a.name.get_extension() + p_a.type + p_a.name.get_basename(), p_b.name.get_extension() + p_b.type + p_b.name.get_basename()); } }; From cd29fb22a007b6cbdadde9cb3f912f0b47b786fa Mon Sep 17 00:00:00 2001 From: Sofox Date: Tue, 5 Dec 2023 13:21:57 +0000 Subject: [PATCH 55/95] Fixed RegEx search_all for zero length matches/lookahead/lookbehind (cherry picked from commit 7b2fd342e32a87ae57c16f568709dc4bb3fae2a5) --- modules/regex/regex.cpp | 12 +-- modules/regex/tests/test_regex.h | 139 ++++++++++++++++++++++++++++++- 2 files changed, 145 insertions(+), 6 deletions(-) diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp index 704c107f2042..d49578d2a9bf 100644 --- a/modules/regex/regex.cpp +++ b/modules/regex/regex.cpp @@ -270,16 +270,18 @@ Ref RegEx::search(const String &p_subject, int p_offset, int p_end) TypedArray RegEx::search_all(const String &p_subject, int p_offset, int p_end) const { ERR_FAIL_COND_V_MSG(p_offset < 0, Array(), "RegEx search offset must be >= 0"); - int last_end = -1; + int last_end = 0; TypedArray result; Ref match = search(p_subject, p_offset, p_end); + while (match.is_valid()) { - if (last_end == match->get_end(0)) { - break; + last_end = match->get_end(0); + if (match->get_start(0) == last_end) { + last_end++; } + result.push_back(match); - last_end = match->get_end(0); - match = search(p_subject, match->get_end(0), p_end); + match = search(p_subject, last_end, p_end); } return result; } diff --git a/modules/regex/tests/test_regex.h b/modules/regex/tests/test_regex.h index 3e4d76937710..0b401da831c4 100644 --- a/modules/regex/tests/test_regex.h +++ b/modules/regex/tests/test_regex.h @@ -164,7 +164,7 @@ TEST_CASE("[RegEx] Uninitialized use") { ERR_PRINT_ON } -TEST_CASE("[RegEx] Empty Pattern") { +TEST_CASE("[RegEx] Empty pattern") { const String s = "Godot"; RegEx re; @@ -222,6 +222,143 @@ TEST_CASE("[RegEx] Match start and end positions") { CHECK(match->get_start("vowel") == 2); CHECK(match->get_end("vowel") == 3); } + +TEST_CASE("[RegEx] Asterisk search all") { + const String s = "Godot Engine"; + + RegEx re("o*"); + REQUIRE(re.is_valid()); + Ref match; + const Array all_results = re.search_all(s); + CHECK(all_results.size() == 13); + + match = all_results[0]; + CHECK(match->get_string(0) == ""); + match = all_results[1]; + CHECK(match->get_string(0) == "o"); + match = all_results[2]; + CHECK(match->get_string(0) == ""); + match = all_results[3]; + CHECK(match->get_string(0) == "o"); + + for (int i = 4; i < 13; i++) { + match = all_results[i]; + CHECK(match->get_string(0) == ""); + } +} + +TEST_CASE("[RegEx] Simple lookahead") { + const String s = "Godot Engine"; + + RegEx re("o(?=t)"); + REQUIRE(re.is_valid()); + Ref match = re.search(s); + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 3); + CHECK(match->get_end(0) == 4); +} + +TEST_CASE("[RegEx] Lookahead groups empty matches") { + const String s = "12"; + + RegEx re("(?=(\\d+))"); + REQUIRE(re.is_valid()); + Ref match = re.search(s); + CHECK(match->get_string(0) == ""); + CHECK(match->get_string(1) == "12"); + + const Array all_results = re.search_all(s); + CHECK(all_results.size() == 2); + + match = all_results[0]; + REQUIRE(match != nullptr); + CHECK(match->get_string(0) == String("")); + CHECK(match->get_string(1) == String("12")); + + match = all_results[1]; + REQUIRE(match != nullptr); + CHECK(match->get_string(0) == String("")); + CHECK(match->get_string(1) == String("2")); +} + +TEST_CASE("[RegEx] Simple lookbehind") { + const String s = "Godot Engine"; + + RegEx re("(?<=d)o"); + REQUIRE(re.is_valid()); + Ref match = re.search(s); + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 3); + CHECK(match->get_end(0) == 4); +} + +TEST_CASE("[RegEx] Simple lookbehind search all") { + const String s = "ababbaabab"; + + RegEx re("(?<=a)b"); + REQUIRE(re.is_valid()); + const Array all_results = re.search_all(s); + CHECK(all_results.size() == 4); + + Ref match = all_results[0]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 1); + CHECK(match->get_end(0) == 2); + + match = all_results[1]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 3); + CHECK(match->get_end(0) == 4); + + match = all_results[2]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 7); + CHECK(match->get_end(0) == 8); + + match = all_results[3]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 9); + CHECK(match->get_end(0) == 10); +} + +TEST_CASE("[RegEx] Lookbehind groups empty matches") { + const String s = "abaaabab"; + + RegEx re("(?<=(b))"); + REQUIRE(re.is_valid()); + Ref match; + + const Array all_results = re.search_all(s); + CHECK(all_results.size() == 3); + + match = all_results[0]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 2); + CHECK(match->get_end(0) == 2); + CHECK(match->get_start(1) == 1); + CHECK(match->get_end(1) == 2); + CHECK(match->get_string(0) == String("")); + CHECK(match->get_string(1) == String("b")); + + match = all_results[1]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 6); + CHECK(match->get_end(0) == 6); + CHECK(match->get_start(1) == 5); + CHECK(match->get_end(1) == 6); + CHECK(match->get_string(0) == String("")); + CHECK(match->get_string(1) == String("b")); + + match = all_results[2]; + REQUIRE(match != nullptr); + CHECK(match->get_start(0) == 8); + CHECK(match->get_end(0) == 8); + CHECK(match->get_start(1) == 7); + CHECK(match->get_end(1) == 8); + CHECK(match->get_string(0) == String("")); + CHECK(match->get_string(1) == String("b")); +} + } // namespace TestRegEx #endif // TEST_REGEX_H From 663ba67016a013ab7d3d0441366d927fd3df6557 Mon Sep 17 00:00:00 2001 From: kleonc <9283098+kleonc@users.noreply.github.com> Date: Mon, 15 Jan 2024 17:32:26 +0100 Subject: [PATCH 56/95] Fix 2D normals for transposed texture (cherry picked from commit 0fe7eead024ef0b4ae2750aa09594beb8f4bb11c) --- drivers/gles3/shaders/canvas.glsl | 3 +++ servers/rendering/renderer_rd/shaders/canvas.glsl | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index ce8fe25625bf..c517fcb8ae73 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -587,6 +587,9 @@ void main() { if (normal_used || (using_light && bool(read_draw_data_flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) { normal.xy = texture(normal_texture, uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); + if (bool(read_draw_data_flags & FLAGS_TRANSPOSE_RECT)) { + normal.xy = normal.yx; + } if (bool(read_draw_data_flags & FLAGS_FLIP_H)) { normal.x = -normal.x; } diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 7a13ac720796..a234798e77bd 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -516,6 +516,9 @@ void main() { if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) { normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0); + if (bool(draw_data.flags & FLAGS_TRANSPOSE_RECT)) { + normal.xy = normal.yx; + } if (bool(draw_data.flags & FLAGS_FLIP_H)) { normal.x = -normal.x; } From dd665988d71004c2f40c9b5abf52fcbd5c9dff7b Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Wed, 20 Dec 2023 13:19:21 +0100 Subject: [PATCH 57/95] Correctly enforce minimum window size in editor Also set the maximum size for the language picked in the project manager. (cherry picked from commit 416e594eb32efb91cd1de8f8b409f0383e70f807) --- editor/editor_node.cpp | 4 ++- editor/project_manager.cpp | 55 ++++++++++++++++++++++---------------- editor/project_manager.h | 2 ++ 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 98b170c9a163..aa816bcf9aa1 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6861,7 +6861,9 @@ EditorNode::EditorNode() { // Define a minimum window size to prevent UI elements from overlapping or being cut off. Window *w = Object::cast_to(SceneTree::get_singleton()->get_root()); if (w) { - w->set_min_size(Size2(1024, 600) * EDSCALE); + const Size2 minimum_size = Size2(1024, 600) * EDSCALE; + w->set_min_size(minimum_size); // Calling it this early doesn't sync the property with DS. + DisplayServer::get_singleton()->window_set_min_size(minimum_size); } EditorFileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files")); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 291484600cf3..533bc473330c 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -2062,6 +2062,36 @@ void ProjectManager::_build_icon_type_cache(Ref p_theme) { } } +void ProjectManager::_update_size_limits() { + const Size2 minimum_size = Size2(680, 450) * EDSCALE; + const Size2 default_size = Size2(1024, 600) * EDSCALE; + + // Define a minimum window size to prevent UI elements from overlapping or being cut off. + Window *w = Object::cast_to(SceneTree::get_singleton()->get_root()); + if (w) { + // Calling Window methods this early doesn't sync properties with DS. + w->set_min_size(minimum_size); + DisplayServer::get_singleton()->window_set_min_size(minimum_size); + w->set_size(default_size); + DisplayServer::get_singleton()->window_set_size(default_size); + } + + Rect2i screen_rect = DisplayServer::get_singleton()->screen_get_usable_rect(DisplayServer::get_singleton()->window_get_current_screen()); + if (screen_rect.size != Vector2i()) { + // Center the window on the screen. + Vector2i window_position; + window_position.x = screen_rect.position.x + (screen_rect.size.x - default_size.x) / 2; + window_position.y = screen_rect.position.y + (screen_rect.size.y - default_size.y) / 2; + DisplayServer::get_singleton()->window_set_position(window_position); + + // Limit popup menus to prevent unusably long lists. + // We try to set it to half the screen resolution, but no smaller than the minimum window size. + Size2 half_screen_rect = (screen_rect.size * EDSCALE) / 2; + Size2 maximum_popup_size = MAX(half_screen_rect, minimum_size); + language_btn->get_popup()->set_max_size(maximum_popup_size); + } +} + void ProjectManager::_dim_window() { // This method must be called before calling `get_tree()->quit()`. // Otherwise, its effect won't be visible @@ -3268,30 +3298,9 @@ ProjectManager::ProjectManager() { SceneTree::get_singleton()->get_root()->connect("files_dropped", callable_mp(this, &ProjectManager::_files_dropped)); - // Define a minimum window size to prevent UI elements from overlapping or being cut off. - Window *w = Object::cast_to(SceneTree::get_singleton()->get_root()); - if (w) { - w->set_min_size(Size2(520, 350) * EDSCALE); - } - - // Resize the bootsplash window based on Editor display scale EDSCALE. - float scale_factor = MAX(1, EDSCALE); - if (scale_factor > 1.0) { - Vector2i window_size = DisplayServer::get_singleton()->window_get_size(); - Rect2i screen_rect = DisplayServer::get_singleton()->screen_get_usable_rect(DisplayServer::get_singleton()->window_get_current_screen()); - - window_size *= scale_factor; - - DisplayServer::get_singleton()->window_set_size(window_size); - if (screen_rect.size != Vector2i()) { - Vector2i window_position; - window_position.x = screen_rect.position.x + (screen_rect.size.x - window_size.x) / 2; - window_position.y = screen_rect.position.y + (screen_rect.size.y - window_size.y) / 2; - DisplayServer::get_singleton()->window_set_position(window_position); - } - } - OS::get_singleton()->set_low_processor_usage_mode(true); + + _update_size_limits(); } ProjectManager::~ProjectManager() { diff --git a/editor/project_manager.h b/editor/project_manager.h index 418567905710..d41207d7a292 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -330,6 +330,8 @@ class ProjectManager : public Control { static ProjectManager *singleton; + void _update_size_limits(); + Panel *background_panel = nullptr; TabContainer *tabs = nullptr; ProjectList *_project_list = nullptr; From 6f6a1dc5e9577830e55a1136e8919b85395edad6 Mon Sep 17 00:00:00 2001 From: Markus Sauermann <6299227+Sauermann@users.noreply.github.com> Date: Mon, 25 Dec 2023 23:32:29 +0100 Subject: [PATCH 58/95] Fix D&D viewport position calculation It is necessary to transform screen position to viewport position. (cherry picked from commit 4b6516c843ad6df039b7e5f78ead6b8e3416f243) --- scene/main/viewport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 3330eded6785..dadfd129149d 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2081,7 +2081,7 @@ void Viewport::_gui_input_event(Ref p_event) { Window *w = Object::cast_to(ObjectDB::get_instance(object_under)); if (w) { viewport_under = w; - viewport_pos = screen_mouse_pos - w->get_position(); + viewport_pos = w->get_final_transform().affine_inverse().xform(screen_mouse_pos - w->get_position()); } } } From 94949f0ee1bbdb7180ec8876f121461908d7f7ea Mon Sep 17 00:00:00 2001 From: mequam Date: Sat, 4 Mar 2023 11:52:15 -0500 Subject: [PATCH 59/95] [X11] Fix Godot stealing focus on alternative Window Managers (cherry picked from commit 40d69c25d5b4238b6372d4c0f5fd10a8f0a64e9e) --- platform/linuxbsd/x11/display_server_x11.cpp | 24 ++++++++++++++++---- platform/linuxbsd/x11/display_server_x11.h | 1 + 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index e1d842422c5d..2cacf6091f46 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -2010,7 +2010,7 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent // RevertToPointerRoot is used to make sure we don't lose all focus in case // a subwindow and its parent are both destroyed. if (!wd_window.no_focus && !wd_window.is_popup && wd_window.focused) { - if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup) { + if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup && _window_focus_check()) { XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime); } } @@ -2945,7 +2945,7 @@ void DisplayServerX11::window_set_ime_active(const bool p_active, WindowID p_win XWindowAttributes xwa; XSync(x11_display, False); XGetWindowAttributes(x11_display, wd.x11_xim_window, &xwa); - if (xwa.map_state == IsViewable) { + if (xwa.map_state == IsViewable && _window_focus_check()) { XSetInputFocus(x11_display, wd.x11_xim_window, RevertToParent, CurrentTime); } XSetICFocus(wd.xic); @@ -4228,6 +4228,22 @@ bool DisplayServerX11::mouse_process_popups() { return closed; } +bool DisplayServerX11::_window_focus_check() { + Window focused_window; + int focus_ret_state; + XGetInputFocus(x11_display, &focused_window, &focus_ret_state); + + bool has_focus = false; + for (const KeyValue &wid : windows) { + if (wid.value.x11_window == focused_window) { + has_focus = true; + break; + } + } + + return has_focus; +} + void DisplayServerX11::process_events() { _THREAD_SAFE_METHOD_ @@ -4499,7 +4515,7 @@ void DisplayServerX11::process_events() { // Set focus when menu window is started. // RevertToPointerRoot is used to make sure we don't lose all focus in case // a subwindow and its parent are both destroyed. - if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) { + if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup && _window_focus_check()) { XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); } @@ -4675,7 +4691,7 @@ void DisplayServerX11::process_events() { // Set focus when menu window is re-used. // RevertToPointerRoot is used to make sure we don't lose all focus in case // a subwindow and its parent are both destroyed. - if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) { + if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup && _window_focus_check()) { XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); } diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index a8d134a6c704..e1993bf29ac6 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -352,6 +352,7 @@ class DisplayServerX11 : public DisplayServer { Context context = CONTEXT_ENGINE; WindowID _get_focused_window_or_popup() const; + bool _window_focus_check(); void _send_window_event(const WindowData &wd, WindowEvent p_event); static void _dispatch_input_events(const Ref &p_event); From 89f22518dc3aa35ef3957779e59d49a0bf2b56db Mon Sep 17 00:00:00 2001 From: zinefer Date: Fri, 24 Nov 2023 21:00:35 -0700 Subject: [PATCH 60/95] Bugfix: Replace // with \\ before sending path to Blender On Windows, Blender treats //fileshare/assets/model.blend as a relative path which will not be found. Instead, replace the first two chars with `\\` which when escaped becomes `\\\\`. (cherry picked from commit 72d18d50a47ecb07f372fec80bf166a6abd0a756) --- .../gltf/editor/editor_scene_importer_blend.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 9587604e5666..24dab16b90a2 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -134,7 +134,19 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ // Get global paths for source and sink. // Escape paths to be valid Python strings to embed in the script. - const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape(); + String source_global = ProjectSettings::get_singleton()->globalize_path(p_path); + +#ifdef WINDOWS_ENABLED + // On Windows, when using a network share path, the above will return a path starting with "//" + // which once handed to Blender will be treated like a relative path. So we need to replace the + // first two characters with "\\" to make it absolute again. + if (source_global.is_network_share_path()) { + source_global = "\\\\" + source_global.substr(2); + } +#endif + + source_global = source_global.c_escape(); + const String blend_basename = p_path.get_file().get_basename(); const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join( vformat("%s-%s.gltf", blend_basename, p_path.md5_text())); From 3a8c04ea3c148715cc31fffe0f2b59865e2f1179 Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Mon, 18 Dec 2023 11:37:43 -0600 Subject: [PATCH 61/95] Add PackedRealArray as an alias for Vector (cherry picked from commit 3f469ee4858e559e007a9f812e4d73cea888a23e) --- core/variant/variant.h | 1 + 1 file changed, 1 insertion(+) diff --git a/core/variant/variant.h b/core/variant/variant.h index 17e701cf663e..480f21df987b 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -70,6 +70,7 @@ typedef Vector PackedInt32Array; typedef Vector PackedInt64Array; typedef Vector PackedFloat32Array; typedef Vector PackedFloat64Array; +typedef Vector PackedRealArray; typedef Vector PackedStringArray; typedef Vector PackedVector2Array; typedef Vector PackedVector3Array; From 2fe886f3a5257b625d2d7798ed2cd242eeb7f154 Mon Sep 17 00:00:00 2001 From: BlueCube3310 <53150244+BlueCube3310@users.noreply.github.com> Date: Wed, 6 Dec 2023 19:56:55 +0100 Subject: [PATCH 62/95] Fix squish RGTC_R decompression corruption (cherry picked from commit 433a2a6ea2bbaa06943db00de390c9aee14870c4) --- thirdparty/squish/colourblock.cpp | 17 +++- thirdparty/squish/colourblock.h | 1 + thirdparty/squish/godot-changes.patch | 109 ++++++++++++++++++++++++++ thirdparty/squish/squish.cpp | 4 +- 4 files changed, 127 insertions(+), 4 deletions(-) diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp index 3d87adaa7792..f14c9362bd5a 100644 --- a/thirdparty/squish/colourblock.cpp +++ b/thirdparty/squish/colourblock.cpp @@ -24,9 +24,9 @@ -------------------------------------------------------------------------- */ #include "colourblock.h" -// -- Godot start -- +// -- GODOT start -- #include "alpha.h" -// -- Godot end -- +// -- GODOT end -- namespace squish { @@ -214,7 +214,18 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 ) } } -// -- Godot start -- +// -- GODOT start -- +void DecompressColourBc4( u8* rgba, void const* block) +{ + DecompressAlphaDxt5(rgba,block); + for ( int i = 0; i < 16; ++i ) { + rgba[i*4] = rgba[i*4 + 3]; + rgba[i*4 + 1] = 0; + rgba[i*4 + 2] = 0; + rgba[i*4 + 3] = 255; + } +} + void DecompressColourBc5( u8* rgba, void const* block) { void const* rblock = block; diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h index 3cb9b7e3b936..e1eb9e4917a4 100644 --- a/thirdparty/squish/colourblock.h +++ b/thirdparty/squish/colourblock.h @@ -36,6 +36,7 @@ void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* void DecompressColour( u8* rgba, void const* block, bool isDxt1 ); // -- GODOT start -- +void DecompressColourBc4( u8* rgba, void const* block ); void DecompressColourBc5( u8* rgba, void const* block ); // -- GODOT end -- diff --git a/thirdparty/squish/godot-changes.patch b/thirdparty/squish/godot-changes.patch index ef7bafb4b4e7..555fbc51d0ed 100644 --- a/thirdparty/squish/godot-changes.patch +++ b/thirdparty/squish/godot-changes.patch @@ -100,3 +100,112 @@ index 1d22a64ad..fd11a147d 100644 // decompress alpha separately if necessary if( ( flags & kDxt3 ) != 0 ) + +diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp +index 49401358bc..f14c9362bd 100644 +--- a/thirdparty/squish/colourblock.cpp ++++ b/thirdparty/squish/colourblock.cpp +@@ -24,9 +24,9 @@ + -------------------------------------------------------------------------- */ + + #include "colourblock.h" +-// -- Godot start -- ++// -- GODOT start -- + #include "alpha.h" +-// -- Godot end -- ++// -- GODOT end -- + + namespace squish { + +diff --git a/thirdparty/squish/godot-changes.patch b/thirdparty/squish/godot-changes.patch +index ef7bafb4b4..655a8cffc2 100644 +--- a/thirdparty/squish/godot-changes.patch ++++ b/thirdparty/squish/godot-changes.patch +@@ -1,22 +1,33 @@ + diff --git a/thirdparty/squish/colourblock.cpp b/thirdparty/squish/colourblock.cpp +-index af8b98036..3d87adaa7 100644 ++index af8b980365..f14c9362bd 100644 + --- a/thirdparty/squish/colourblock.cpp + +++ b/thirdparty/squish/colourblock.cpp + @@ -24,6 +24,9 @@ + -------------------------------------------------------------------------- */ + + #include "colourblock.h" +-+// -- Godot start -- +++// -- GODOT start -- + +#include "alpha.h" +-+// -- Godot end -- +++// -- GODOT end -- + + namespace squish { + +-@@ -211,4 +214,23 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 ) ++@@ -211,4 +214,34 @@ void DecompressColour( u8* rgba, void const* block, bool isDxt1 ) + } + } + +-+// -- Godot start -- +++// -- GODOT start -- +++void DecompressColourBc4( u8* rgba, void const* block) +++{ +++ DecompressAlphaDxt5(rgba,block); +++ for ( int i = 0; i < 16; ++i ) { +++ rgba[i*4] = rgba[i*4 + 3]; +++ rgba[i*4 + 1] = 0; +++ rgba[i*4 + 2] = 0; +++ rgba[i*4 + 3] = 255; +++ } +++} +++ + +void DecompressColourBc5( u8* rgba, void const* block) + +{ + + void const* rblock = block; +@@ -37,21 +48,22 @@ index af8b98036..3d87adaa7 100644 + + + } // namespace squish + diff --git a/thirdparty/squish/colourblock.h b/thirdparty/squish/colourblock.h +-index fee2cd7c5..3cb9b7e3b 100644 ++index fee2cd7c5d..e1eb9e4917 100644 + --- a/thirdparty/squish/colourblock.h + +++ b/thirdparty/squish/colourblock.h +-@@ -35,6 +35,9 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* ++@@ -35,6 +35,10 @@ void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* + void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ); + + void DecompressColour( u8* rgba, void const* block, bool isDxt1 ); + +// -- GODOT start -- +++void DecompressColourBc4( u8* rgba, void const* block ); + +void DecompressColourBc5( u8* rgba, void const* block ); + +// -- GODOT end -- + + } // namespace squish + + diff --git a/thirdparty/squish/config.h b/thirdparty/squish/config.h +-index 92edefe96..05f8d7259 100644 ++index 92edefe966..05f8d72598 100644 + --- a/thirdparty/squish/config.h + +++ b/thirdparty/squish/config.h + @@ -32,6 +32,26 @@ +@@ -82,17 +94,19 @@ index 92edefe96..05f8d7259 100644 + #define SQUISH_USE_SSE 0 + #endif + diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp +-index 1d22a64ad..fd11a147d 100644 ++index 1d22a64ad6..086ba11cd0 100644 + --- a/thirdparty/squish/squish.cpp + +++ b/thirdparty/squish/squish.cpp +-@@ -135,7 +135,13 @@ void Decompress( u8* rgba, void const* block, int flags ) ++@@ -135,7 +135,15 @@ void Decompress( u8* rgba, void const* block, int flags ) + colourBlock = reinterpret_cast< u8 const* >( block ) + 8; + + // decompress colour + - DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); + + // -- GODOT start -- + + //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); +-+ if(( flags & ( kBc5 ) ) != 0) +++ if(( flags & ( kBc4 ) ) != 0) +++ DecompressColourBc4( rgba, colourBlock); +++ else if(( flags & ( kBc5 ) ) != 0) + + DecompressColourBc5( rgba, colourBlock); + + else + + DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); \ No newline at end of file diff --git a/thirdparty/squish/squish.cpp b/thirdparty/squish/squish.cpp index fd11a147de6a..1de1da3e5291 100644 --- a/thirdparty/squish/squish.cpp +++ b/thirdparty/squish/squish.cpp @@ -137,7 +137,9 @@ void Decompress( u8* rgba, void const* block, int flags ) // decompress colour // -- GODOT start -- //DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); - if(( flags & ( kBc5 ) ) != 0) + if(( flags & ( kBc4 ) ) != 0) + DecompressColourBc4( rgba, colourBlock); + else if(( flags & ( kBc5 ) ) != 0) DecompressColourBc5( rgba, colourBlock); else DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); From 5f3bd68cfecb1ff698d6e609804829e4fc807b76 Mon Sep 17 00:00:00 2001 From: BlueCube3310 <53150244+BlueCube3310@users.noreply.github.com> Date: Sat, 9 Dec 2023 18:07:25 +0100 Subject: [PATCH 63/95] Fix squish DXT5 RA-As-RG channel swapping (cherry picked from commit 1224129c50e64aafb86fd4c2241759c100a0d594) --- modules/squish/image_decompress_squish.cpp | 46 +++++++++++++++------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/modules/squish/image_decompress_squish.cpp b/modules/squish/image_decompress_squish.cpp index 5b35a2643aa1..fba76621d6a9 100644 --- a/modules/squish/image_decompress_squish.cpp +++ b/modules/squish/image_decompress_squish.cpp @@ -36,7 +36,9 @@ void image_decompress_squish(Image *p_image) { int w = p_image->get_width(); int h = p_image->get_height(); + Image::Format source_format = p_image->get_format(); Image::Format target_format = Image::FORMAT_RGBA8; + Vector data; int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps()); int mm_count = p_image->get_mipmap_count(); @@ -45,33 +47,49 @@ void image_decompress_squish(Image *p_image) { const uint8_t *rb = p_image->get_data().ptr(); uint8_t *wb = data.ptrw(); - int squish_flags = Image::FORMAT_MAX; - if (p_image->get_format() == Image::FORMAT_DXT1) { - squish_flags = squish::kDxt1; - } else if (p_image->get_format() == Image::FORMAT_DXT3) { - squish_flags = squish::kDxt3; - } else if (p_image->get_format() == Image::FORMAT_DXT5 || p_image->get_format() == Image::FORMAT_DXT5_RA_AS_RG) { - squish_flags = squish::kDxt5; - } else if (p_image->get_format() == Image::FORMAT_RGTC_R) { - squish_flags = squish::kBc4; - } else if (p_image->get_format() == Image::FORMAT_RGTC_RG) { - squish_flags = squish::kBc5; - } else { - ERR_FAIL_MSG("Squish: Can't decompress unknown format: " + itos(p_image->get_format()) + "."); + int squish_flags = 0; + + switch (source_format) { + case Image::FORMAT_DXT1: + squish_flags = squish::kDxt1; + break; + + case Image::FORMAT_DXT3: + squish_flags = squish::kDxt3; + break; + + case Image::FORMAT_DXT5: + case Image::FORMAT_DXT5_RA_AS_RG: + squish_flags = squish::kDxt5; + break; + + case Image::FORMAT_RGTC_R: + squish_flags = squish::kBc4; + break; + + case Image::FORMAT_RGTC_RG: + squish_flags = squish::kBc5; + break; + + default: + ERR_FAIL_MSG("Squish: Can't decompress unknown format: " + itos(p_image->get_format()) + "."); + break; } for (int i = 0; i <= mm_count; i++) { int src_ofs = 0, mipmap_size = 0, mipmap_w = 0, mipmap_h = 0; p_image->get_mipmap_offset_size_and_dimensions(i, src_ofs, mipmap_size, mipmap_w, mipmap_h); + int dst_ofs = Image::get_image_mipmap_offset(p_image->get_width(), p_image->get_height(), target_format, i); squish::DecompressImage(&wb[dst_ofs], w, h, &rb[src_ofs], squish_flags); + w >>= 1; h >>= 1; } p_image->set_data(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data); - if (p_image->get_format() == Image::FORMAT_DXT5_RA_AS_RG) { + if (source_format == Image::FORMAT_DXT5_RA_AS_RG) { p_image->convert_ra_rgba8_to_rg(); } } From 9f10aedb17763397f759f6231bc66c47f6ff87cc Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Fri, 15 Dec 2023 18:58:30 +0100 Subject: [PATCH 64/95] Correctly register editor-only module classes with the API (cherry picked from commit 0f8c955c1ad19bef9d4d615681c647cbc5a495e1) --- modules/minimp3/register_types.cpp | 5 +++++ modules/vorbis/register_types.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp index 627d093bc18e..c85f0b3389a6 100644 --- a/modules/minimp3/register_types.cpp +++ b/modules/minimp3/register_types.cpp @@ -52,8 +52,13 @@ void initialize_minimp3_module(ModuleInitializationLevel p_level) { ResourceFormatImporter::get_singleton()->add_importer(mp3_import); } + ClassDB::APIType prev_api = ClassDB::get_current_api(); + ClassDB::set_current_api(ClassDB::API_EDITOR); + // Required to document import options in the class reference. GDREGISTER_CLASS(ResourceImporterMP3); + + ClassDB::set_current_api(prev_api); #endif GDREGISTER_CLASS(AudioStreamMP3); diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp index 26af912999f1..def34220ea0d 100644 --- a/modules/vorbis/register_types.cpp +++ b/modules/vorbis/register_types.cpp @@ -48,8 +48,13 @@ void initialize_vorbis_module(ModuleInitializationLevel p_level) { ResourceFormatImporter::get_singleton()->add_importer(ogg_vorbis_importer); } + ClassDB::APIType prev_api = ClassDB::get_current_api(); + ClassDB::set_current_api(ClassDB::API_EDITOR); + // Required to document import options in the class reference. GDREGISTER_CLASS(ResourceImporterOggVorbis); + + ClassDB::set_current_api(prev_api); #endif GDREGISTER_CLASS(AudioStreamOggVorbis); From 43d24379a5b882801f49fa4215380990ab2c6e02 Mon Sep 17 00:00:00 2001 From: Aitor Guevara <428243+aitorciki@users.noreply.github.com> Date: Fri, 25 Aug 2023 13:58:32 +0200 Subject: [PATCH 65/95] Trigger zoom from pan gestures when pressing ctrl Enables zooming using pan + ctrl on macOS trackpads / Magic Mouse. Windows and Linux don't emit pan gesture events, so shouldn't be affected. Not tested on Android. (cherry picked from commit 6b45694836707cedb2dbdf342f27015c4e9df215) --- scene/gui/view_panner.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scene/gui/view_panner.cpp b/scene/gui/view_panner.cpp index fc03f2d887cf..c61fa1d9b800 100644 --- a/scene/gui/view_panner.cpp +++ b/scene/gui/view_panner.cpp @@ -125,6 +125,17 @@ bool ViewPanner::gui_input(const Ref &p_event, Rect2 p_canvas_rect) Ref pan_gesture = p_event; if (pan_gesture.is_valid()) { + if (pan_gesture->is_ctrl_pressed()) { + // Zoom gesture. + float pan_zoom_factor = 1.02f; + float zoom_direction = pan_gesture->get_delta().x - pan_gesture->get_delta().y; + if (zoom_direction == 0.f) { + return true; + } + float zoom = zoom_direction < 0 ? 1.0 / pan_zoom_factor : pan_zoom_factor; + zoom_callback.call(zoom, pan_gesture->get_position(), p_event); + return true; + } pan_callback.call(-pan_gesture->get_delta() * scroll_speed, p_event); } From 93fd5da49c499db6e37ce64e2b5513f62af672fa Mon Sep 17 00:00:00 2001 From: Dominic Date: Fri, 1 Dec 2023 13:26:03 -0500 Subject: [PATCH 66/95] Add wireframe for compatibility mode (cherry picked from commit bae6f86257ffb9bed915bcd0d6fa41e1da39894a) --- drivers/gles3/rasterizer_scene_gles3.cpp | 34 +++++++++--- drivers/gles3/storage/config.h | 3 +- drivers/gles3/storage/mesh_storage.cpp | 69 ++++++++++++++++++++++++ drivers/gles3/storage/mesh_storage.h | 18 +++++++ drivers/gles3/storage/utilities.cpp | 2 + 5 files changed, 118 insertions(+), 8 deletions(-) diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 04602fe07bb8..e4246ea67537 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2766,6 +2766,15 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, prev_index_array_gl = 0; } + bool use_wireframe = false; + if (p_params->force_wireframe) { + GLuint wireframe_index_array_gl = mesh_storage->mesh_surface_get_index_buffer_wireframe(mesh_surface); + if (wireframe_index_array_gl) { + index_array_gl = wireframe_index_array_gl; + use_wireframe = true; + } + } + bool use_index_buffer = index_array_gl != 0; if (prev_index_array_gl != index_array_gl) { if (index_array_gl != 0) { @@ -2956,6 +2965,11 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, count = mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface); } + if (use_wireframe) { + // In this case we are using index count, and we need double the indices for the wireframe mesh. + count = count * 2; + } + if constexpr (p_pass_mode != PASS_MODE_DEPTH) { // Don't count draw calls during depth pre-pass to match the RD renderers. if (p_render_data->render_info) { @@ -3010,17 +3024,25 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, glVertexAttribI4ui(15, default_color, default_color, default_custom, default_custom); } - if (use_index_buffer) { - glDrawElementsInstanced(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count); + if (use_wireframe) { + glDrawElementsInstanced(GL_LINES, count, GL_UNSIGNED_INT, 0, inst->instance_count); } else { - glDrawArraysInstanced(primitive_gl, 0, count, inst->instance_count); + if (use_index_buffer) { + glDrawElementsInstanced(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count); + } else { + glDrawArraysInstanced(primitive_gl, 0, count, inst->instance_count); + } } } else { // Using regular Mesh. - if (use_index_buffer) { - glDrawElements(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0); + if (use_wireframe) { + glDrawElements(GL_LINES, count, GL_UNSIGNED_INT, 0); } else { - glDrawArrays(primitive_gl, 0, count); + if (use_index_buffer) { + glDrawElements(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0); + } else { + glDrawArrays(primitive_gl, 0, count); + } } } diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h index b2dd98f02584..3b097f8e6623 100644 --- a/drivers/gles3/storage/config.h +++ b/drivers/gles3/storage/config.h @@ -63,8 +63,7 @@ class Config { int64_t max_renderable_lights = 0; int64_t max_lights_per_object = 0; - // TODO implement wireframe in OpenGL - // bool generate_wireframes; + bool generate_wireframes = false; HashSet extensions; diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index 9d8b56f4ec67..e5080b39a397 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -31,6 +31,7 @@ #ifdef GLES3_ENABLED #include "mesh_storage.h" +#include "config.h" #include "material_storage.h" #include "utilities.h" @@ -285,6 +286,69 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) ERR_FAIL_COND_MSG(!new_surface.index_count && !new_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both"); + if (GLES3::Config::get_singleton()->generate_wireframes && s->primitive == RS::PRIMITIVE_TRIANGLES) { + // Generate wireframes. This is mostly used by the editor. + s->wireframe = memnew(Mesh::Surface::Wireframe); + Vector wf_indices; + uint32_t &wf_index_count = s->wireframe->index_count; + uint32_t *wr = nullptr; + + if (new_surface.format & RS::ARRAY_FORMAT_INDEX) { + wf_index_count = s->index_count * 2; + wf_indices.resize(wf_index_count); + + Vector ir = new_surface.index_data; + wr = wf_indices.ptrw(); + + if (new_surface.vertex_count < (1 << 16)) { + // Read 16 bit indices. + const uint16_t *src_idx = (const uint16_t *)ir.ptr(); + for (uint32_t i = 0; i + 5 < wf_index_count; i += 6) { + // We use GL_LINES instead of GL_TRIANGLES for drawing these primitives later, + // so we need double the indices for each triangle. + wr[i + 0] = src_idx[i / 2]; + wr[i + 1] = src_idx[i / 2 + 1]; + wr[i + 2] = src_idx[i / 2 + 1]; + wr[i + 3] = src_idx[i / 2 + 2]; + wr[i + 4] = src_idx[i / 2 + 2]; + wr[i + 5] = src_idx[i / 2]; + } + + } else { + // Read 32 bit indices. + const uint32_t *src_idx = (const uint32_t *)ir.ptr(); + for (uint32_t i = 0; i + 5 < wf_index_count; i += 6) { + wr[i + 0] = src_idx[i / 2]; + wr[i + 1] = src_idx[i / 2 + 1]; + wr[i + 2] = src_idx[i / 2 + 1]; + wr[i + 3] = src_idx[i / 2 + 2]; + wr[i + 4] = src_idx[i / 2 + 2]; + wr[i + 5] = src_idx[i / 2]; + } + } + } else { + // Not using indices. + wf_index_count = s->vertex_count * 2; + wf_indices.resize(wf_index_count); + wr = wf_indices.ptrw(); + + for (uint32_t i = 0; i + 5 < wf_index_count; i += 6) { + wr[i + 0] = i / 2; + wr[i + 1] = i / 2 + 1; + wr[i + 2] = i / 2 + 1; + wr[i + 3] = i / 2 + 2; + wr[i + 4] = i / 2 + 2; + wr[i + 5] = i / 2; + } + } + + s->wireframe->index_buffer_size = wf_index_count * sizeof(uint32_t); + glGenBuffers(1, &s->wireframe->index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->wireframe->index_buffer); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->wireframe->index_buffer, s->wireframe->index_buffer_size, wr, GL_STATIC_DRAW, "Mesh wireframe index buffer"); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // unbind + } + s->aabb = new_surface.aabb; s->bone_aabbs = new_surface.bone_aabbs; //only really useful for returning them. s->mesh_to_skeleton_xform = p_surface.mesh_to_skeleton_xform; @@ -725,6 +789,11 @@ void MeshStorage::mesh_clear(RID p_mesh) { memfree(s.versions); //reallocs, so free with memfree. } + if (s.wireframe) { + GLES3::Utilities::get_singleton()->buffer_free_data(s.wireframe->index_buffer); + memdelete(s.wireframe); + } + if (s.lod_count) { for (uint32_t j = 0; j < s.lod_count; j++) { if (s.lods[j].index_buffer != 0) { diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h index d277477ff2aa..217c4dabf057 100644 --- a/drivers/gles3/storage/mesh_storage.h +++ b/drivers/gles3/storage/mesh_storage.h @@ -84,6 +84,14 @@ struct Mesh { uint32_t index_count = 0; uint32_t index_buffer_size = 0; + struct Wireframe { + GLuint index_buffer = 0; + uint32_t index_count = 0; + uint32_t index_buffer_size = 0; + }; + + Wireframe *wireframe = nullptr; + struct LOD { float edge_length = 0.0; uint32_t index_count = 0; @@ -380,6 +388,16 @@ class MeshStorage : public RendererMeshStorage { } } + _FORCE_INLINE_ GLuint mesh_surface_get_index_buffer_wireframe(void *p_surface) const { + Mesh::Surface *s = reinterpret_cast(p_surface); + + if (s->wireframe) { + return s->wireframe->index_buffer; + } + + return 0; + } + _FORCE_INLINE_ GLenum mesh_surface_get_index_type(void *p_surface) const { Mesh::Surface *s = reinterpret_cast(p_surface); diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp index 72bcbe879c7a..29b265e32711 100644 --- a/drivers/gles3/storage/utilities.cpp +++ b/drivers/gles3/storage/utilities.cpp @@ -327,6 +327,8 @@ void Utilities::update_dirty_resources() { } void Utilities::set_debug_generate_wireframes(bool p_generate) { + Config *config = Config::get_singleton(); + config->generate_wireframes = p_generate; } bool Utilities::has_os_feature(const String &p_feature) const { From 9609df181d6c5f67553773406822d4c5a3c1c847 Mon Sep 17 00:00:00 2001 From: Zach Coleman Date: Fri, 17 Nov 2023 08:32:54 -0500 Subject: [PATCH 67/95] Make screen_get_refresh_rate() respect iOS Low Power Mode (cherry picked from commit 6a8f6bae4c3af2727b2ab111fc8921c1875d867f) --- platform/ios/display_server_ios.mm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index 2561c1c09574..60da16ae8c65 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -443,7 +443,11 @@ } float DisplayServerIOS::screen_get_refresh_rate(int p_screen) const { - return [UIScreen mainScreen].maximumFramesPerSecond; + float fps = [UIScreen mainScreen].maximumFramesPerSecond; + if ([NSProcessInfo processInfo].lowPowerModeEnabled) { + fps = 60; + } + return fps; } float DisplayServerIOS::screen_get_scale(int p_screen) const { From 8e3740d425a704eec2e8e487e1dd078136afbfa5 Mon Sep 17 00:00:00 2001 From: Lasuch Date: Tue, 14 Nov 2023 21:53:02 +0100 Subject: [PATCH 68/95] Expose copy_effects copy compute shader in Mobile backend (cherry picked from commit 608d41a969c4f11e8a8522c9764ee9ea938a95c0) --- .../rendering/renderer_rd/effects/copy_effects.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index 87033cb559fc..c9f0008998c9 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -71,7 +71,9 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) { for (int i = 0; i < BLUR_MODE_MAX; i++) { blur_raster.pipelines[i].clear(); } + } + { Vector copy_modes; copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); copy_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n#define DST_IMAGE_8BIT\n"); @@ -310,12 +312,12 @@ CopyEffects::~CopyEffects() { filter.raster_shader.version_free(filter.shader_version); roughness.raster_shader.version_free(roughness.shader_version); } else { - copy.shader.version_free(copy.shader_version); cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version); filter.compute_shader.version_free(filter.shader_version); roughness.compute_shader.version_free(roughness.shader_version); } + copy.shader.version_free(copy.shader_version); specular_merge.shader.version_free(specular_merge.shader_version); RD::get_singleton()->free(filter.coefficient_buffer); @@ -335,8 +337,6 @@ CopyEffects::~CopyEffects() { } void CopyEffects::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_all_source, bool p_8_bit_dst, bool p_alpha_to_one) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the copy_to_rect shader with the mobile renderer."); - UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -386,8 +386,6 @@ void CopyEffects::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, cons } void CopyEffects::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the copy_cubemap_to_panorama shader with the mobile renderer."); - UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -423,8 +421,6 @@ void CopyEffects::copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panoram } void CopyEffects::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the copy_depth_to_rect shader with the mobile renderer."); - UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -462,8 +458,6 @@ void CopyEffects::copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_texture } void CopyEffects::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the copy_depth_to_rect_and_linearize shader with the mobile renderer."); - UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); From 6777e1b4bfdc02b26ea07b8e3f20b6b3257aae43 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 16 Nov 2023 18:47:46 +1100 Subject: [PATCH 69/95] Replace memory allocation point of ValueTrack correctly in AnimationMixer When a animation track doesn't have an keys, it's possible that we leak memory due the ERR_CONTINUE_MSG macro usage. By checking the error condition first, we avoid a allocation and thus the leak. (cherry picked from commit ea84effb845f7959b2eed362855e5c0e8ab68f20) --- scene/animation/animation_mixer.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index c6d69cf622d3..da00d1dd7b0a 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -638,6 +638,10 @@ bool AnimationMixer::_update_caches() { switch (track_type) { case Animation::TYPE_VALUE: { + // If a value track without a key is cached first, the initial value cannot be determined. + // It is a corner case, but which may cause problems with blending. + ERR_CONTINUE_MSG(anim->track_get_key_count(i) == 0, "AnimationMixer: '" + String(E) + "', Value Track: '" + String(path) + "' must have at least one key to cache for blending."); + TrackCacheValue *track_value = memnew(TrackCacheValue); if (resource.is_valid()) { @@ -654,9 +658,6 @@ bool AnimationMixer::_update_caches() { track = track_value; - // If a value track without a key is cached first, the initial value cannot be determined. - // It is a corner case, but which may cause problems with blending. - ERR_CONTINUE_MSG(anim->track_get_key_count(i) == 0, "AnimationMixer: '" + String(E) + "', Value Track: '" + String(path) + "' must have at least one key to cache for blending."); track_value->init_value = anim->track_get_key_value(i, 0); track_value->init_value.zero(); From 6e6d49c68ae7057e2e7279550f36ca548e3468b8 Mon Sep 17 00:00:00 2001 From: kleonc <9283098+kleonc@users.noreply.github.com> Date: Mon, 11 Dec 2023 16:17:45 +0100 Subject: [PATCH 70/95] Fix ColorPicker's alpha slider arrow offset (cherry picked from commit d76d8c5f294475f7d34337e9127e7877870214cf) --- scene/gui/color_picker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index bd0b58c9efae..cfcde28e86c2 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -74,7 +74,7 @@ void ColorPicker::_notification(int p_what) { sliders[i]->add_theme_constant_override(SNAME("center_grabber"), theme_cache.center_slider_grabbers); } alpha_label->set_custom_minimum_size(Size2(theme_cache.label_width, 0)); - alpha_label->add_theme_constant_override(SNAME("center_grabber"), theme_cache.center_slider_grabbers); + alpha_slider->add_theme_constant_override(SNAME("center_grabber"), theme_cache.center_slider_grabbers); for (int i = 0; i < MODE_BUTTON_COUNT; i++) { mode_btns[i]->begin_bulk_theme_override(); From 8633f7bcdb52e8b59b46ae891c5a936e1393fda3 Mon Sep 17 00:00:00 2001 From: kevmorg Date: Sat, 2 Dec 2023 15:55:46 -0500 Subject: [PATCH 71/95] Hide Node dock successfully on undo/redo and deletion Fixes #84530. (cherry picked from commit da84489b27dedbe480a2ffcf9dbb60a68775cf66) --- editor/node_dock.cpp | 13 +++++++++++-- editor/node_dock.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp index 65217304734e..372e696ed898 100644 --- a/editor/node_dock.cpp +++ b/editor/node_dock.cpp @@ -67,14 +67,23 @@ void NodeDock::update_lists() { connections->update_tree(); } +void NodeDock::_on_node_tree_exited() { + set_node(nullptr); +} + void NodeDock::set_node(Node *p_node) { + if (last_valid_node) { + last_valid_node->disconnect("tree_exited", callable_mp(this, &NodeDock::_on_node_tree_exited)); + last_valid_node = nullptr; + } + connections->set_node(p_node); groups->set_current(p_node); + if (p_node) { last_valid_node = p_node; - } + last_valid_node->connect("tree_exited", callable_mp(this, &NodeDock::_on_node_tree_exited)); - if (p_node) { if (connections_button->is_pressed()) { connections->show(); } else { diff --git a/editor/node_dock.h b/editor/node_dock.h index cc221714530f..41495ffeadd9 100644 --- a/editor/node_dock.h +++ b/editor/node_dock.h @@ -58,6 +58,7 @@ class NodeDock : public VBoxContainer { protected: static void _bind_methods(); void _notification(int p_what); + void _on_node_tree_exited(); public: void set_node(Node *p_node); From 5573f37ff353b7cb6f0b0593c9dda05a854290b9 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 11 Dec 2023 16:52:03 -0800 Subject: [PATCH 72/95] Change suffix from m to px (cherry picked from commit b7d5f3e9847254145e2647a76e3f96caa36d39a1) --- scene/resources/skeleton_modification_2d_twoboneik.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scene/resources/skeleton_modification_2d_twoboneik.cpp b/scene/resources/skeleton_modification_2d_twoboneik.cpp index d0b56252987c..4458cdc0e340 100644 --- a/scene/resources/skeleton_modification_2d_twoboneik.cpp +++ b/scene/resources/skeleton_modification_2d_twoboneik.cpp @@ -468,8 +468,8 @@ void SkeletonModification2DTwoBoneIK::_bind_methods() { ClassDB::bind_method(D_METHOD("get_joint_two_bone_idx"), &SkeletonModification2DTwoBoneIK::get_joint_two_bone_idx); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_minimum_distance", PROPERTY_HINT_RANGE, "0,100000000,0.01,suffix:m"), "set_target_minimum_distance", "get_target_minimum_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_maximum_distance", PROPERTY_HINT_NONE, "0,100000000,0.01,suffix:m"), "set_target_maximum_distance", "get_target_maximum_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_minimum_distance", PROPERTY_HINT_RANGE, "0,100000000,0.01,suffix:px"), "set_target_minimum_distance", "get_target_minimum_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_maximum_distance", PROPERTY_HINT_NONE, "0,100000000,0.01,suffix:px"), "set_target_maximum_distance", "get_target_maximum_distance"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_bend_direction", PROPERTY_HINT_NONE, ""), "set_flip_bend_direction", "get_flip_bend_direction"); ADD_GROUP("", ""); } From 5dbe105f221ff20a940021411b5f8f54445699c9 Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Mon, 11 Dec 2023 14:34:05 +0100 Subject: [PATCH 73/95] Fix theme access in the Groups editor (cherry picked from commit 0244f8318fb99d2df13b4bea17ef8ed77825685b) --- editor/groups_editor.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 09e5fe790d20..d083bc294a2c 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -117,7 +117,7 @@ void GroupDialog::_load_nodes(Node *p_current) { if (!can_edit(p_current, selected_group)) { node->set_selectable(0, false); - node->set_custom_color(0, groups->get_theme_color(SNAME("disabled_font_color"), EditorStringName(Editor))); + node->set_custom_color(0, get_theme_color(SNAME("disabled_font_color"), EditorStringName(Editor))); } } @@ -211,8 +211,8 @@ void GroupDialog::_add_group(String p_name) { TreeItem *new_group = groups->create_item(groups_root); new_group->set_text(0, name); - new_group->add_button(0, groups->get_editor_theme_icon(SNAME("Remove")), DELETE_GROUP); - new_group->add_button(0, groups->get_editor_theme_icon(SNAME("ActionCopy")), COPY_GROUP); + new_group->add_button(0, get_editor_theme_icon(SNAME("Remove")), DELETE_GROUP); + new_group->add_button(0, get_editor_theme_icon(SNAME("ActionCopy")), COPY_GROUP); new_group->set_editable(0, true); new_group->select(0); groups->ensure_cursor_is_visible(); @@ -391,20 +391,17 @@ void GroupDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_TRANSLATION_CHANGED: case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED: - case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { if (is_layout_rtl()) { - add_button->set_icon(groups->get_editor_theme_icon(SNAME("Back"))); - remove_button->set_icon(groups->get_editor_theme_icon(SNAME("Forward"))); + add_button->set_icon(get_editor_theme_icon(SNAME("Back"))); + remove_button->set_icon(get_editor_theme_icon(SNAME("Forward"))); } else { - add_button->set_icon(groups->get_editor_theme_icon(SNAME("Forward"))); - remove_button->set_icon(groups->get_editor_theme_icon(SNAME("Back"))); + add_button->set_icon(get_editor_theme_icon(SNAME("Forward"))); + remove_button->set_icon(get_editor_theme_icon(SNAME("Back"))); } - add_filter->set_right_icon(groups->get_editor_theme_icon(SNAME("Search"))); - add_filter->set_clear_button_enabled(true); - remove_filter->set_right_icon(groups->get_editor_theme_icon(SNAME("Search"))); - remove_filter->set_clear_button_enabled(true); + add_filter->set_right_icon(get_editor_theme_icon(SNAME("Search"))); + remove_filter->set_right_icon(get_editor_theme_icon(SNAME("Search"))); } break; } } @@ -512,6 +509,7 @@ GroupDialog::GroupDialog() { add_filter = memnew(LineEdit); add_filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); add_filter->set_placeholder(TTR("Filter Nodes")); + add_filter->set_clear_button_enabled(true); add_filter_hbc->add_child(add_filter); add_filter->connect("text_changed", callable_mp(this, &GroupDialog::_add_filter_changed)); @@ -562,6 +560,7 @@ GroupDialog::GroupDialog() { remove_filter = memnew(LineEdit); remove_filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); remove_filter->set_placeholder(TTR("Filter Nodes")); + remove_filter->set_clear_button_enabled(true); remove_filter_hbc->add_child(remove_filter); remove_filter->connect("text_changed", callable_mp(this, &GroupDialog::_remove_filter_changed)); From 4bc567d27abcc602308f8f8ce26f03c40cc90196 Mon Sep 17 00:00:00 2001 From: detomon Date: Mon, 4 Sep 2023 20:38:31 +0200 Subject: [PATCH 74/95] Fix creating and updating plugin with dot in folder name (cherry picked from commit 46253bd9e9a0ed9b8506a51bcda0472a09aa9bd5) --- editor/plugin_config_dialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp index 196a2186a72f..98b7ab6cc164 100644 --- a/editor/plugin_config_dialog.cpp +++ b/editor/plugin_config_dialog.cpp @@ -62,7 +62,7 @@ void PluginConfigDialog::_on_confirmed() { int lang_idx = script_option_edit->get_selected(); String ext = ScriptServer::get_language(lang_idx)->get_extension(); String script_name = script_edit->get_text().is_empty() ? _get_subfolder() : script_edit->get_text(); - if (script_name.get_extension().is_empty()) { + if (script_name.get_extension() != ext) { script_name += "." + ext; } String script_path = path.path_join(script_name); @@ -152,7 +152,7 @@ void PluginConfigDialog::config(const String &p_config_path) { ERR_FAIL_COND_MSG(err != OK, "Cannot load config file from path '" + p_config_path + "'."); name_edit->set_text(cf->get_value("plugin", "name", "")); - subfolder_edit->set_text(p_config_path.get_base_dir().get_basename().get_file()); + subfolder_edit->set_text(p_config_path.get_base_dir().get_file()); desc_edit->set_text(cf->get_value("plugin", "description", "")); author_edit->set_text(cf->get_value("plugin", "author", "")); version_edit->set_text(cf->get_value("plugin", "version", "")); From 6a2a0487531fde97be483164a12d0b71512cf34f Mon Sep 17 00:00:00 2001 From: wilto938 Date: Tue, 12 Dec 2023 12:27:26 +0100 Subject: [PATCH 75/95] Reset TileMap editor `drag_type` by using the _stop_dragging() function when the toolbar mode is not selected (cherry picked from commit 5a3de5bc308ab80bd538731dd03943b176af1612) --- editor/plugins/tiles/tile_map_editor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index a6de74a1d29e..7b3847e5489f 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -524,6 +524,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref &p } if (CanvasItemEditor::get_singleton()->get_current_tool() != CanvasItemEditor::TOOL_SELECT) { + _stop_dragging(); return false; } From 88526a23a5887627cb844d11d45a76300a045bb8 Mon Sep 17 00:00:00 2001 From: Nancy Zhang Date: Wed, 6 Dec 2023 23:32:40 -0500 Subject: [PATCH 76/95] Fix unable to deselect audio effects (cherry picked from commit cf39cc985bf79bbbfc04b72e85dbbfe42f88c64d) --- editor/editor_audio_buses.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index f244bc0da86b..e173d15747f2 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -912,6 +912,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { vb->add_child(effects); effects->connect("item_edited", callable_mp(this, &EditorAudioBus::_effect_edited)); effects->connect("cell_selected", callable_mp(this, &EditorAudioBus::_effect_selected)); + effects->connect("focus_exited", callable_mp(effects, &Tree::deselect_all)); effects->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true); SET_DRAG_FORWARDING_GCD(effects, EditorAudioBus); effects->connect("item_mouse_selected", callable_mp(this, &EditorAudioBus::_effect_rmb)); From 1f677eb2797b5abdf69c318eef566d9c64a15268 Mon Sep 17 00:00:00 2001 From: kobewi Date: Thu, 14 Dec 2023 18:18:44 +0100 Subject: [PATCH 77/95] Properly select the newly duplicated file (cherry picked from commit 0ae1241304660559f42aee1293c0e18286f46b1d) --- editor/filesystem_dock.cpp | 10 ++++++++-- editor/filesystem_dock.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 31f9b3e56f22..5a5f3c82833f 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1297,6 +1297,13 @@ void FileSystemDock::_fs_changed() { _update_file_list(true); } + if (!select_after_scan.is_empty()) { + _navigate_to_path(select_after_scan); + select_after_scan.clear(); + import_dock_needs_update = true; + _update_import_dock(); + } + set_process(false); } @@ -1476,8 +1483,6 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin EditorNode::get_singleton()->add_io_error(TTR("Cannot move a folder into itself.") + "\n" + old_path + "\n"); return; } - const_cast(this)->current_path = new_path; - Ref da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (p_item.is_file) { @@ -1917,6 +1922,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop for (int i = 0; i < to_move.size(); i++) { if (to_move[i].path != new_paths[i]) { _try_duplicate_item(to_move[i], new_paths[i]); + select_after_scan = new_paths[i]; is_copied = true; } } diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 1cde735cb8bd..cc6c0ebf5cb5 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -225,6 +225,7 @@ class FileSystemDock : public VBoxContainer { int history_max_size; String current_path; + String select_after_scan; bool initialized = false; From 49031b24e550309b1dd717eb5130240176c140c7 Mon Sep 17 00:00:00 2001 From: Saracen Date: Wed, 18 Oct 2023 02:29:02 +0100 Subject: [PATCH 78/95] Fix setting bezier track handle mode from inspector. (cherry picked from commit 09a4aa3ce80343587080e057677e31359039b7f8) --- editor/animation_track_editor.cpp | 26 ++++++++++++++++++-------- editor/animation_track_editor.h | 2 ++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index faffbb631fc9..8268cf10aece 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -306,10 +306,14 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu setting = true; undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); - int prev = animation->bezier_track_get_key_handle_mode(track, key); - undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); - undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev); + int prev_mode = animation->bezier_track_get_key_handle_mode(track, key); + Vector2 prev_in_handle = animation->bezier_track_get_key_in_handle(track, key); + Vector2 prev_out_handle = animation->bezier_track_get_key_out_handle(track, key); + undo_redo->add_do_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); undo_redo->add_do_method(this, "_update_obj", animation); + undo_redo->add_undo_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev_mode); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev_in_handle); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev_out_handle); undo_redo->add_undo_method(this, "_update_obj", animation); undo_redo->commit_action(); @@ -857,8 +861,8 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } Vector2 prev = animation->bezier_track_get_key_in_handle(track, key); - undo_redo->add_do_method(this, "_bezier_track_set_key_in_handle", track, key, value); - undo_redo->add_undo_method(this, "_bezier_track_set_key_in_handle", track, key, prev); + undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, value); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev); update_obj = true; } else if (name == "out_handle") { const Variant &value = p_value; @@ -878,9 +882,13 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p setting = true; undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } - int prev = animation->bezier_track_get_key_handle_mode(track, key); - undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); - undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev); + int prev_mode = animation->bezier_track_get_key_handle_mode(track, key); + Vector2 prev_in_handle = animation->bezier_track_get_key_in_handle(track, key); + Vector2 prev_out_handle = animation->bezier_track_get_key_out_handle(track, key); + undo_redo->add_do_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); + undo_redo->add_undo_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev_mode); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev_in_handle); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev_out_handle); update_obj = true; } } break; @@ -5175,6 +5183,7 @@ void AnimationTrackEditor::_update_key_edit() { key_edit->animation_read_only = read_only; key_edit->track = selection.front()->key().track; key_edit->use_fps = timeline->is_using_fps(); + key_edit->editor = this; int key_id = selection.front()->key().key; if (key_id >= animation->track_get_key_count(key_edit->track)) { @@ -5194,6 +5203,7 @@ void AnimationTrackEditor::_update_key_edit() { multi_key_edit = memnew(AnimationMultiTrackKeyEdit); multi_key_edit->animation = animation; multi_key_edit->animation_read_only = read_only; + multi_key_edit->editor = this; RBMap> key_ofs_map; RBMap base_map; diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index eb2cb2a4e44f..4b9849b26c8b 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -68,6 +68,7 @@ class AnimationTrackKeyEdit : public Object { PropertyInfo hint; NodePath base; bool use_fps = false; + AnimationTrackEditor *editor = nullptr; bool _hide_script_from_inspector() { return true; } bool _hide_metadata_from_inspector() { return true; } @@ -105,6 +106,7 @@ class AnimationMultiTrackKeyEdit : public Object { Node *root_path = nullptr; bool use_fps = false; + AnimationTrackEditor *editor = nullptr; bool _hide_script_from_inspector() { return true; } bool _hide_metadata_from_inspector() { return true; } From b34af3aa5a386a7d4681051805c9b65752845966 Mon Sep 17 00:00:00 2001 From: eldidou Date: Fri, 1 Dec 2023 12:32:25 +0100 Subject: [PATCH 79/95] Speed up GDScript::get_must_clear_dependencies() get_must_clear_dependencies() has a N^3*log(N) time complexity, and this can very quickly slow down the quitting process as more gdscripts are added in a project. This change improves it to N^2*log(N). Instead of using all the inverted dependencies, we do the same with all (non-inverted) dependencies, which is N times faster. Fixes #85435 (cherry picked from commit 0d77c3e09228b847658de3453b36fa78e073222c) --- modules/gdscript/gdscript.cpp | 41 ++++++++++++++--------------------- modules/gdscript/gdscript.h | 2 +- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 2de24b5413aa..76dcb02af880 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1156,8 +1156,8 @@ RBSet GDScript::get_dependencies() { return dependencies; } -RBSet GDScript::get_inverted_dependencies() { - RBSet inverted_dependencies; +HashMap> GDScript::get_all_dependencies() { + HashMap> all_dependencies; List scripts; { @@ -1171,51 +1171,42 @@ RBSet GDScript::get_inverted_dependencies() { } for (GDScript *scr : scripts) { - if (scr == nullptr || scr == this || scr->destructing) { + if (scr == nullptr || scr->destructing) { continue; } - - RBSet scr_dependencies = scr->get_dependencies(); - if (scr_dependencies.has(this)) { - inverted_dependencies.insert(scr); - } + all_dependencies.insert(scr, scr->get_dependencies()); } - return inverted_dependencies; + return all_dependencies; } RBSet GDScript::get_must_clear_dependencies() { RBSet dependencies = get_dependencies(); RBSet must_clear_dependencies; - HashMap> inverted_dependencies; - - for (GDScript *E : dependencies) { - inverted_dependencies.insert(E, E->get_inverted_dependencies()); - } + HashMap> all_dependencies = get_all_dependencies(); RBSet cant_clear; - for (KeyValue> &E : inverted_dependencies) { + for (KeyValue> &E : all_dependencies) { + if (dependencies.has(E.key)) { + continue; + } for (GDScript *F : E.value) { - if (!dependencies.has(F)) { - cant_clear.insert(E.key); - for (GDScript *G : E.key->get_dependencies()) { - cant_clear.insert(G); - } - break; + if (dependencies.has(F)) { + cant_clear.insert(F); } } } - for (KeyValue> &E : inverted_dependencies) { - if (cant_clear.has(E.key) || ScriptServer::is_global_class(E.key->get_fully_qualified_name())) { + for (GDScript *E : dependencies) { + if (cant_clear.has(E) || ScriptServer::is_global_class(E->get_fully_qualified_name())) { continue; } - must_clear_dependencies.insert(E.key); + must_clear_dependencies.insert(E); } cant_clear.clear(); dependencies.clear(); - inverted_dependencies.clear(); + all_dependencies.clear(); return must_clear_dependencies; } diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 682fe9b04cf0..2a71c2742925 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -253,7 +253,7 @@ class GDScript : public Script { const Ref &get_native() const { return native; } RBSet get_dependencies(); - RBSet get_inverted_dependencies(); + HashMap> get_all_dependencies(); RBSet get_must_clear_dependencies(); virtual bool has_script_signal(const StringName &p_signal) const override; From a47a07d13bc6e3fa031b22a0f4815f54a99c0820 Mon Sep 17 00:00:00 2001 From: jsjtxietian Date: Sun, 10 Dec 2023 16:21:16 +0800 Subject: [PATCH 80/95] Fix FileAccessPack::get_buffer will update pos past the length of file (cherry picked from commit 68a6fe81abadfac596d95234ecb34dfb01076f52) --- core/io/file_access_pack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 74c5c1c19109..265d9ef56cc4 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -327,7 +327,7 @@ uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const { to_read = (int64_t)pf.size - (int64_t)pos; } - pos += p_length; + pos += to_read; if (to_read <= 0) { return 0; From 06a94ecc14f0565190061fc2cd55405e5c4acc30 Mon Sep 17 00:00:00 2001 From: kobewi Date: Sat, 22 Jul 2023 13:36:51 +0200 Subject: [PATCH 81/95] Load project metadata file only when needed (cherry picked from commit 3dc47b0b847e4c42aeb0fd5e2f569c543b4f97ab) --- editor/editor_settings.cpp | 39 ++++++++++++++++++++++++-------------- editor/editor_settings.h | 2 ++ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 1eaeee97a578..6f52793e32e0 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -884,6 +884,10 @@ bool EditorSettings::_is_default_text_editor_theme(String p_theme_name) { return p_theme_name == "default" || p_theme_name == "godot 2" || p_theme_name == "custom"; } +const String EditorSettings::_get_project_metadata_path() const { + return EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg"); +} + // PUBLIC METHODS EditorSettings *EditorSettings::get_singleton() { @@ -1171,24 +1175,31 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) { // Metadata void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) { - Ref cf = memnew(ConfigFile); - String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg"); - Error err; - err = cf->load(path); - ERR_FAIL_COND_MSG(err != OK && err != ERR_FILE_NOT_FOUND, "Cannot load editor settings from file '" + path + "'."); - cf->set_value(p_section, p_key, p_data); - err = cf->save(path); - ERR_FAIL_COND_MSG(err != OK, "Cannot save editor settings to file '" + path + "'."); + const String path = _get_project_metadata_path(); + + if (project_metadata.is_null()) { + project_metadata.instantiate(); + + Error err = project_metadata->load(path); + if (err != OK && err != ERR_FILE_NOT_FOUND) { + ERR_PRINT("Cannot load project metadata from file '" + path + "'."); + } + } + project_metadata->set_value(p_section, p_key, p_data); + + Error err = project_metadata->save(path); + ERR_FAIL_COND_MSG(err != OK, "Cannot save project metadata to file '" + path + "'."); } Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) const { - Ref cf = memnew(ConfigFile); - String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg"); - Error err = cf->load(path); - if (err != OK) { - return p_default; + if (project_metadata.is_null()) { + project_metadata.instantiate(); + + const String path = _get_project_metadata_path(); + Error err = project_metadata->load(path); + ERR_FAIL_COND_V_MSG(err != OK && err != ERR_FILE_NOT_FOUND, p_default, "Cannot load project metadata from file '" + path + "'."); } - return cf->get_value(p_section, p_key, p_default); + return project_metadata->get_value(p_section, p_key, p_default); } void EditorSettings::set_favorites(const Vector &p_favorites) { diff --git a/editor/editor_settings.h b/editor/editor_settings.h index 660a9501a277..c3ce790e0e7b 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -79,6 +79,7 @@ class EditorSettings : public Resource { HashSet changed_settings; + mutable Ref project_metadata; HashMap hints; HashMap props; int last_order; @@ -106,6 +107,7 @@ class EditorSettings : public Resource { void _load_godot2_text_editor_theme(); bool _save_text_editor_theme(String p_file); bool _is_default_text_editor_theme(String p_theme_name); + const String _get_project_metadata_path() const; protected: static void _bind_methods(); From bce0ada5f4dbe6a749ced9abf99e128135770b1f Mon Sep 17 00:00:00 2001 From: jsjtxietian Date: Fri, 6 Oct 2023 15:02:03 +0800 Subject: [PATCH 82/95] Prompt require editor restart to user when gizmo color changed (cherry picked from commit b0ccd5c84f460d875d127455741d817ece6d3bed) --- editor/editor_settings.cpp | 8 ++++---- .../gizmos/audio_stream_player_3d_gizmo_plugin.cpp | 2 +- editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp | 2 +- editor/plugins/gizmos/decal_gizmo_plugin.cpp | 2 +- editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp | 2 +- editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp | 2 +- .../gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp | 4 ++-- editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp | 4 ++-- editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp | 2 +- editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp | 2 +- .../plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp | 2 +- editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp | 2 +- .../gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp | 2 +- editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp | 2 +- editor/plugins/skeleton_3d_editor_plugin.cpp | 4 ++-- modules/csg/editor/csg_gizmos.cpp | 2 +- 16 files changed, 22 insertions(+), 22 deletions(-) diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 6f52793e32e0..ea17ad17704f 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -632,9 +632,9 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { // Use a similar color to the 2D editor selection. EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/selection_box_color", Color(1.0, 0.5, 0), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) - _initial_set("editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6)); - _initial_set("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)); - _initial_set("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) + EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) + EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED) // If a line is a multiple of this, it uses the primary grid color. // Use a power of 2 value by default as it's more common to use powers of 2 in level design. @@ -1130,8 +1130,8 @@ Variant _EDITOR_DEF(const String &p_setting, const Variant &p_default, bool p_re ret = EDITOR_GET(p_setting); } else { EditorSettings::get_singleton()->set_manually(p_setting, p_default); - EditorSettings::get_singleton()->set_restart_if_changed(p_setting, p_restart_if_changed); } + EditorSettings::get_singleton()->set_restart_if_changed(p_setting, p_restart_if_changed); if (!EditorSettings::get_singleton()->has_default_value(p_setting)) { EditorSettings::get_singleton()->set_initial_value(p_setting, p_default); diff --git a/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp index cda00b954395..9d4b5e9d70e1 100644 --- a/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp @@ -38,7 +38,7 @@ #include "scene/3d/audio_stream_player_3d.h" AudioStreamPlayer3DGizmoPlugin::AudioStreamPlayer3DGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1)); create_icon_material("stream_player_3d_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Gizmo3DSamplePlayer"), EditorStringName(EditorIcons))); create_material("stream_player_3d_material_primary", gizmo_color); diff --git a/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp index af7874e4da99..19dd45a3ea58 100644 --- a/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp @@ -39,7 +39,7 @@ #include "scene/3d/camera_3d.h" Camera3DGizmoPlugin::Camera3DGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8)); create_material("camera_material", gizmo_color); create_icon_material("camera_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoCamera3D"), EditorStringName(EditorIcons))); diff --git a/editor/plugins/gizmos/decal_gizmo_plugin.cpp b/editor/plugins/gizmos/decal_gizmo_plugin.cpp index 7572e1dcd523..f2b44790eedd 100644 --- a/editor/plugins/gizmos/decal_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/decal_gizmo_plugin.cpp @@ -40,7 +40,7 @@ DecalGizmoPlugin::DecalGizmoPlugin() { helper.instantiate(); - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/decal", Color(0.6, 0.5, 1.0)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/decal", Color(0.6, 0.5, 1.0)); create_icon_material("decal_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoDecal"), EditorStringName(EditorIcons))); diff --git a/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp b/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp index 931a738aa293..b7bba8f8d733 100644 --- a/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp @@ -38,7 +38,7 @@ #include "scene/3d/fog_volume.h" FogVolumeGizmoPlugin::FogVolumeGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/fog_volume", Color(0.5, 0.7, 1)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/fog_volume", Color(0.5, 0.7, 1)); create_material("shape_material", gizmo_color); gizmo_color.a = 0.15; create_material("shape_material_internal", gizmo_color); diff --git a/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp index 2b673207ab91..bef6971eba18 100644 --- a/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp @@ -38,7 +38,7 @@ #include "scene/3d/gpu_particles_3d.h" GPUParticles3DGizmoPlugin::GPUParticles3DGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4)); create_material("particles_material", gizmo_color); gizmo_color.a = MAX((gizmo_color.a - 0.2) * 0.02, 0.0); create_material("particles_solid_material", gizmo_color); diff --git a/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp index 2cbfccc05e07..6f20a5345913 100644 --- a/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp @@ -39,12 +39,12 @@ GPUParticlesCollision3DGizmoPlugin::GPUParticlesCollision3DGizmoPlugin() { helper.instantiate(); - Color gizmo_color_attractor = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particle_attractor", Color(1, 0.7, 0.5)); + Color gizmo_color_attractor = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/particle_attractor", Color(1, 0.7, 0.5)); create_material("shape_material_attractor", gizmo_color_attractor); gizmo_color_attractor.a = 0.15; create_material("shape_material_attractor_internal", gizmo_color_attractor); - Color gizmo_color_collision = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particle_collision", Color(0.5, 0.7, 1)); + Color gizmo_color_collision = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/particle_collision", Color(0.5, 0.7, 1)); create_material("shape_material_collision", gizmo_color_collision); gizmo_color_collision.a = 0.15; create_material("shape_material_collision_internal", gizmo_color_collision); diff --git a/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp index c4cb44c8fad6..1fce7f5efb05 100644 --- a/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/joint_3d_gizmo_plugin.cpp @@ -276,8 +276,8 @@ void JointGizmosDrawer::draw_cone(const Transform3D &p_offset, const Basis &p_ba Joint3DGizmoPlugin::Joint3DGizmoPlugin() { create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); - create_material("joint_body_a_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1))); - create_material("joint_body_b_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1))); + create_material("joint_body_a_material", EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1))); + create_material("joint_body_b_material", EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1))); update_timer = memnew(Timer); update_timer->set_name("JointGizmoUpdateTimer"); diff --git a/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp b/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp index 74e6e818c610..64913dc77935 100644 --- a/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp @@ -37,7 +37,7 @@ #include "scene/3d/lightmap_gi.h" LightmapGIGizmoPlugin::LightmapGIGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/lightmap_lines", Color(0.5, 0.6, 1)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/lightmap_lines", Color(0.5, 0.6, 1)); gizmo_color.a = 0.1; create_material("lightmap_lines", gizmo_color); diff --git a/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp b/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp index 420829515f8f..5fd8ad22356b 100644 --- a/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp @@ -39,7 +39,7 @@ LightmapProbeGizmoPlugin::LightmapProbeGizmoPlugin() { create_icon_material("lightmap_probe_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoLightmapProbe"), EditorStringName(EditorIcons))); - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/lightprobe_lines", Color(0.5, 0.6, 1)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/lightprobe_lines", Color(0.5, 0.6, 1)); gizmo_color.a = 0.3; create_material("lightprobe_lines", gizmo_color); diff --git a/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp index f9a210b0e7c6..37c3a05b5086 100644 --- a/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/occluder_instance_3d_gizmo_plugin.cpp @@ -36,7 +36,7 @@ #include "scene/3d/occluder_instance_3d.h" OccluderInstance3DGizmoPlugin::OccluderInstance3DGizmoPlugin() { - create_material("line_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/occluder", Color(0.8, 0.5, 1))); + create_material("line_material", EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/occluder", Color(0.8, 0.5, 1))); create_handle_material("handles"); } diff --git a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp index d25311f1bed0..eb7e668f41c6 100644 --- a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp @@ -40,7 +40,7 @@ ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() { helper.instantiate(); - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5)); create_material("reflection_probe_material", gizmo_color); diff --git a/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp index 315f8aed53a2..d3ae823fdc5a 100644 --- a/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/visible_on_screen_notifier_3d_gizmo_plugin.cpp @@ -36,7 +36,7 @@ #include "scene/3d/visible_on_screen_notifier_3d.h" VisibleOnScreenNotifier3DGizmoPlugin::VisibleOnScreenNotifier3DGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7)); create_material("visibility_notifier_material", gizmo_color); gizmo_color.a = 0.1; create_material("visibility_notifier_solid_material", gizmo_color); diff --git a/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp index b916e99ab658..8d09400f7877 100644 --- a/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp +++ b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp @@ -41,7 +41,7 @@ VoxelGIGizmoPlugin::VoxelGIGizmoPlugin() { helper.instantiate(); - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/voxel_gi", Color(0.5, 1, 0.6)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/voxel_gi", Color(0.5, 1, 0.6)); create_material("voxel_gi_material", gizmo_color); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index eeefd1c90da1..9a709e8ddadd 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -1219,8 +1219,8 @@ void fragment() { selected_mat->set_shader(selected_sh); // Register properties in editor settings. - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/selected_bone", Color(0.8, 0.3, 0.0)); + EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4)); + EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/selected_bone", Color(0.8, 0.3, 0.0)); EDITOR_DEF("editors/3d_gizmos/gizmo_settings/bone_axis_length", (float)0.1); EDITOR_DEF("editors/3d_gizmos/gizmo_settings/bone_shape", 1); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d_gizmos/gizmo_settings/bone_shape", PROPERTY_HINT_ENUM, "Wire,Octahedron")); diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp index ebf0f5a91fa0..ea7b6d225e8e 100644 --- a/modules/csg/editor/csg_gizmos.cpp +++ b/modules/csg/editor/csg_gizmos.cpp @@ -44,7 +44,7 @@ CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() { helper.instantiate(); - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.0, 0.4, 1, 0.15)); + Color gizmo_color = EDITOR_DEF_RST("editors/3d_gizmos/gizmo_colors/csg", Color(0.0, 0.4, 1, 0.15)); create_material("shape_union_material", gizmo_color); create_material("shape_union_solid_material", gizmo_color); gizmo_color.invert(); From ee1034d3551fff083141204c9e5979bdff94d27e Mon Sep 17 00:00:00 2001 From: Danil Alexeev Date: Wed, 13 Dec 2023 00:19:04 +0300 Subject: [PATCH 83/95] GDScript: Fix POT generator skips some nodes (cherry picked from commit 1aa242f7c4f5cdc8712e783817fabc60224f21cb) --- .../gdscript_translation_parser_plugin.cpp | 124 +++++++++++------- .../gdscript_translation_parser_plugin.h | 1 - 2 files changed, 73 insertions(+), 52 deletions(-) diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp index 9128f104b8a1..f55b00ebe1e4 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp @@ -80,7 +80,7 @@ bool GDScriptEditorTranslationParserPlugin::_is_constant_string(const GDScriptPa void GDScriptEditorTranslationParserPlugin::_traverse_class(const GDScriptParser::ClassNode *p_class) { for (int i = 0; i < p_class->members.size(); i++) { const GDScriptParser::ClassNode::Member &m = p_class->members[i]; - // There are 7 types of Member, but only class, function and variable can contain translatable strings. + // Other member types can't contain translatable strings. switch (m.type) { case GDScriptParser::ClassNode::Member::CLASS: _traverse_class(m.m_class); @@ -89,7 +89,11 @@ void GDScriptEditorTranslationParserPlugin::_traverse_class(const GDScriptParser _traverse_function(m.function); break; case GDScriptParser::ClassNode::Member::VARIABLE: - _read_variable(m.variable); + _assess_expression(m.variable->initializer); + if (m.variable->property == GDScriptParser::VariableNode::PROP_INLINE) { + _traverse_function(m.variable->setter); + _traverse_function(m.variable->getter); + } break; default: break; @@ -98,11 +102,14 @@ void GDScriptEditorTranslationParserPlugin::_traverse_class(const GDScriptParser } void GDScriptEditorTranslationParserPlugin::_traverse_function(const GDScriptParser::FunctionNode *p_func) { - _traverse_block(p_func->body); -} + if (!p_func) { + return; + } -void GDScriptEditorTranslationParserPlugin::_read_variable(const GDScriptParser::VariableNode *p_var) { - _assess_expression(p_var->initializer); + for (int i = 0; i < p_func->parameters.size(); i++) { + _assess_expression(p_func->parameters[i]->initializer); + } + _traverse_block(p_func->body); } void GDScriptEditorTranslationParserPlugin::_traverse_block(const GDScriptParser::SuiteNode *p_suite) { @@ -114,53 +121,51 @@ void GDScriptEditorTranslationParserPlugin::_traverse_block(const GDScriptParser for (int i = 0; i < statements.size(); i++) { const GDScriptParser::Node *statement = statements[i]; - // Statements with Node type constant, break, continue, pass, breakpoint are skipped because they can't contain translatable strings. + // BREAK, BREAKPOINT, CONSTANT, CONTINUE, and PASS are skipped because they can't contain translatable strings. switch (statement->type) { - case GDScriptParser::Node::VARIABLE: - _assess_expression(static_cast(statement)->initializer); - break; + case GDScriptParser::Node::ASSERT: { + const GDScriptParser::AssertNode *assert_node = static_cast(statement); + _assess_expression(assert_node->condition); + _assess_expression(assert_node->message); + } break; + case GDScriptParser::Node::ASSIGNMENT: { + _assess_assignment(static_cast(statement)); + } break; + case GDScriptParser::Node::FOR: { + const GDScriptParser::ForNode *for_node = static_cast(statement); + _assess_expression(for_node->list); + _traverse_block(for_node->loop); + } break; case GDScriptParser::Node::IF: { const GDScriptParser::IfNode *if_node = static_cast(statement); _assess_expression(if_node->condition); - //FIXME : if the elif logic is changed in GDScriptParser, then this probably will have to change as well. See GDScriptParser::TreePrinter::print_if(). _traverse_block(if_node->true_block); _traverse_block(if_node->false_block); - break; - } - case GDScriptParser::Node::FOR: { - const GDScriptParser::ForNode *for_node = static_cast(statement); - _assess_expression(for_node->list); - _traverse_block(for_node->loop); - break; - } - case GDScriptParser::Node::WHILE: { - const GDScriptParser::WhileNode *while_node = static_cast(statement); - _assess_expression(while_node->condition); - _traverse_block(while_node->loop); - break; - } + } break; case GDScriptParser::Node::MATCH: { const GDScriptParser::MatchNode *match_node = static_cast(statement); _assess_expression(match_node->test); for (int j = 0; j < match_node->branches.size(); j++) { + _traverse_block(match_node->branches[j]->guard_body); _traverse_block(match_node->branches[j]->block); } - break; - } - case GDScriptParser::Node::RETURN: + } break; + case GDScriptParser::Node::RETURN: { _assess_expression(static_cast(statement)->return_value); - break; - case GDScriptParser::Node::ASSERT: - _assess_expression((static_cast(statement))->condition); - break; - case GDScriptParser::Node::ASSIGNMENT: - _assess_assignment(static_cast(statement)); - break; - default: + } break; + case GDScriptParser::Node::VARIABLE: { + _assess_expression(static_cast(statement)->initializer); + } break; + case GDScriptParser::Node::WHILE: { + const GDScriptParser::WhileNode *while_node = static_cast(statement); + _assess_expression(while_node->condition); + _traverse_block(while_node->loop); + } break; + default: { if (statement->is_expression()) { _assess_expression(static_cast(statement)); } - break; + } break; } } } @@ -172,25 +177,25 @@ void GDScriptEditorTranslationParserPlugin::_assess_expression(const GDScriptPar return; } - // ExpressionNode of type await, cast, get_node, identifier, literal, preload, self, subscript, unary are ignored as they can't be CallNode - // containing translation strings. + // GET_NODE, IDENTIFIER, LITERAL, PRELOAD, SELF, and TYPE are skipped because they can't contain translatable strings. switch (p_expression->type) { case GDScriptParser::Node::ARRAY: { const GDScriptParser::ArrayNode *array_node = static_cast(p_expression); for (int i = 0; i < array_node->elements.size(); i++) { _assess_expression(array_node->elements[i]); } - break; - } - case GDScriptParser::Node::ASSIGNMENT: + } break; + case GDScriptParser::Node::ASSIGNMENT: { _assess_assignment(static_cast(p_expression)); - break; + } break; + case GDScriptParser::Node::AWAIT: { + _assess_expression(static_cast(p_expression)->to_await); + } break; case GDScriptParser::Node::BINARY_OPERATOR: { const GDScriptParser::BinaryOpNode *binary_op_node = static_cast(p_expression); _assess_expression(binary_op_node->left_operand); _assess_expression(binary_op_node->right_operand); - break; - } + } break; case GDScriptParser::Node::CALL: { const GDScriptParser::CallNode *call_node = static_cast(p_expression); _extract_from_call(call_node); @@ -198,23 +203,40 @@ void GDScriptEditorTranslationParserPlugin::_assess_expression(const GDScriptPar _assess_expression(call_node->arguments[i]); } } break; + case GDScriptParser::Node::CAST: { + _assess_expression(static_cast(p_expression)->operand); + } break; case GDScriptParser::Node::DICTIONARY: { const GDScriptParser::DictionaryNode *dict_node = static_cast(p_expression); for (int i = 0; i < dict_node->elements.size(); i++) { _assess_expression(dict_node->elements[i].key); _assess_expression(dict_node->elements[i].value); } - break; - } + } break; + case GDScriptParser::Node::LAMBDA: { + _traverse_function(static_cast(p_expression)->function); + } break; + case GDScriptParser::Node::SUBSCRIPT: { + const GDScriptParser::SubscriptNode *subscript_node = static_cast(p_expression); + _assess_expression(subscript_node->base); + if (!subscript_node->is_attribute) { + _assess_expression(subscript_node->index); + } + } break; case GDScriptParser::Node::TERNARY_OPERATOR: { const GDScriptParser::TernaryOpNode *ternary_op_node = static_cast(p_expression); _assess_expression(ternary_op_node->condition); _assess_expression(ternary_op_node->true_expr); _assess_expression(ternary_op_node->false_expr); - break; - } - default: - break; + } break; + case GDScriptParser::Node::TYPE_TEST: { + _assess_expression(static_cast(p_expression)->operand); + } break; + case GDScriptParser::Node::UNARY_OPERATOR: { + _assess_expression(static_cast(p_expression)->operand); + } break; + default: { + } break; } } diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h index 580c2a80cd14..fab79a925fee 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h @@ -59,7 +59,6 @@ class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlug void _traverse_function(const GDScriptParser::FunctionNode *p_func); void _traverse_block(const GDScriptParser::SuiteNode *p_suite); - void _read_variable(const GDScriptParser::VariableNode *p_var); void _assess_expression(const GDScriptParser::ExpressionNode *p_expression); void _assess_assignment(const GDScriptParser::AssignmentNode *p_assignment); void _extract_from_call(const GDScriptParser::CallNode *p_call); From eb25ef6062e158b9f1a64a44c023e1a864c15495 Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Wed, 20 Dec 2023 13:09:36 +0100 Subject: [PATCH 84/95] Optimize scanning routines in the project manager (cherry picked from commit 3d4b33df3307ff72db9700deb6695569a5d71ea9) --- editor/project_manager.cpp | 193 +++++++++++++++++-------------------- editor/project_manager.h | 15 ++- 2 files changed, 96 insertions(+), 112 deletions(-) diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 533bc473330c..0b61410778e4 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1249,6 +1249,7 @@ struct ProjectListComparator { } }; +const char *ProjectList::SIGNAL_LIST_CHANGED = "list_changed"; const char *ProjectList::SIGNAL_SELECTION_CHANGED = "selection_changed"; const char *ProjectList::SIGNAL_PROJECT_ASK_OPEN = "project_ask_open"; @@ -1356,7 +1357,7 @@ ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_fa return Item(project_name, description, tags, p_path, icon, main_scene, unsupported_features, last_edited, p_favorite, grayed, missing, config_version); } -void ProjectList::migrate_config() { +void ProjectList::_migrate_config() { // Proposal #1637 moved the project list from editor settings to a separate config file // If the new config file doesn't exist, populate it from EditorSettings if (FileAccess::exists(_config_path)) { @@ -1388,9 +1389,10 @@ void ProjectList::migrate_config() { save_config(); } -void ProjectList::load_projects() { +void ProjectList::update_project_list() { // This is a full, hard reload of the list. Don't call this unless really required, it's expensive. // If you have 150 projects, it may read through 150 files on your disk at once + load 150 icons. + // FIXME: Does it really have to be a full, hard reload? Runtime updates should be made much cheaper. // Clear whole list for (int i = 0; i < _projects.size(); ++i) { @@ -1421,6 +1423,7 @@ void ProjectList::load_projects() { update_dock_menu(); set_v_scroll(0); + emit_signal(SNAME(SIGNAL_LIST_CHANGED)); } void ProjectList::update_dock_menu() { @@ -1678,6 +1681,48 @@ void ProjectList::erase_missing_projects() { save_config(); } +void ProjectList::_scan_folder_recursive(const String &p_path, List *r_projects) { + Ref da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Error error = da->change_dir(p_path); + ERR_FAIL_COND_MSG(error != OK, vformat("Failed to open the path \"%s\" for scanning (code %d).", p_path, error)); + + da->list_dir_begin(); + String n = da->get_next(); + while (!n.is_empty()) { + if (da->current_is_dir() && n[0] != '.') { + _scan_folder_recursive(da->get_current_dir().path_join(n), r_projects); + } else if (n == "project.godot") { + r_projects->push_back(da->get_current_dir()); + } + n = da->get_next(); + } + da->list_dir_end(); +} + +void ProjectList::find_projects(const String &p_path) { + PackedStringArray paths = { p_path }; + find_projects_multiple(paths); +} + +void ProjectList::find_projects_multiple(const PackedStringArray &p_paths) { + List projects; + + for (int i = 0; i < p_paths.size(); i++) { + const String &base_path = p_paths.get(i); + print_verbose(vformat("Scanning for projects in \"%s\".", base_path)); + + _scan_folder_recursive(base_path, &projects); + print_verbose(vformat("Found %d project(s).", projects.size())); + } + + for (const String &E : projects) { + add_project(E, false); + } + + save_config(); + update_project_list(); +} + int ProjectList::refresh_project(const String &dir_path) { // Reloads information about a specific project. // If it wasn't loaded and should be in the list, it is added (i.e new project). @@ -1916,6 +1961,7 @@ void ProjectList::_show_project(const String &p_path) { } void ProjectList::_bind_methods() { + ADD_SIGNAL(MethodInfo(SIGNAL_LIST_CHANGED)); ADD_SIGNAL(MethodInfo(SIGNAL_SELECTION_CHANGED)); ADD_SIGNAL(MethodInfo(SIGNAL_PROJECT_ASK_OPEN)); } @@ -1926,6 +1972,7 @@ ProjectList::ProjectList() { add_child(_scroll_children); _config_path = EditorPaths::get_singleton()->get_data_dir().path_join("projects.cfg"); + _migrate_config(); } /// Project Manager. @@ -2213,15 +2260,6 @@ void ProjectManager::shortcut_input(const Ref &p_ev) { } } -void ProjectManager::_load_recent_projects() { - _project_list->set_search_term(search_box->get_text().strip_edges()); - _project_list->load_projects(); - - _update_project_buttons(); - - tabs->set_current_tab(0); -} - void ProjectManager::_on_projects_updated() { Vector selected_projects = _project_list->get_selected_projects(); int index = 0; @@ -2459,30 +2497,6 @@ void ProjectManager::_run_project() { } } -void ProjectManager::_scan_dir(const String &path) { - Ref da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - Error error = da->change_dir(path); - ERR_FAIL_COND_MSG(error != OK, "Could not scan directory at: " + path); - da->list_dir_begin(); - String n = da->get_next(); - while (!n.is_empty()) { - if (da->current_is_dir() && !n.begins_with(".")) { - _scan_dir(da->get_current_dir().path_join(n)); - } else if (n == "project.godot") { - _project_list->add_project(da->get_current_dir(), false); - } - n = da->get_next(); - } - da->list_dir_end(); -} - -void ProjectManager::_scan_begin(const String &p_base) { - print_line("Scanning projects at: " + p_base); - _scan_dir(p_base); - _project_list->save_config(); - _load_recent_projects(); -} - void ProjectManager::_scan_projects() { scan_dir->popup_file_dialog(); } @@ -2682,54 +2696,26 @@ void ProjectManager::_install_project(const String &p_zip_path, const String &p_ } void ProjectManager::_files_dropped(PackedStringArray p_files) { + // TODO: Support installing multiple ZIPs at the same time? if (p_files.size() == 1 && p_files[0].ends_with(".zip")) { - const String file = p_files[0].get_file(); - _install_project(p_files[0], file.substr(0, file.length() - 4).capitalize()); + const String &file = p_files[0]; + _install_project(file, file.get_file().get_basename().capitalize()); return; } + HashSet folders_set; Ref da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < p_files.size(); i++) { - String file = p_files[i]; + const String &file = p_files[i]; folders_set.insert(da->dir_exists(file) ? file : file.get_base_dir()); } - if (folders_set.size() > 0) { - PackedStringArray folders; - for (const String &E : folders_set) { - folders.push_back(E); - } - - bool confirm = true; - if (folders.size() == 1) { - Ref dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (dir->change_dir(folders[0]) == OK) { - dir->list_dir_begin(); - String file = dir->get_next(); - while (confirm && !file.is_empty()) { - if (!dir->current_is_dir() && file.ends_with("project.godot")) { - confirm = false; - } - file = dir->get_next(); - } - dir->list_dir_end(); - } - } - if (confirm) { - multi_scan_ask->get_ok_button()->disconnect("pressed", callable_mp(this, &ProjectManager::_scan_multiple_folders)); - multi_scan_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_scan_multiple_folders).bind(folders)); - multi_scan_ask->set_text( - vformat(TTR("Are you sure to scan %s folders for existing Godot projects?\nThis could take a while."), folders.size())); - multi_scan_ask->popup_centered(); - } else { - _scan_multiple_folders(folders); - } - } -} + ERR_FAIL_COND(folders_set.size() == 0); // This can't really happen, we consume every dropped file path above. -void ProjectManager::_scan_multiple_folders(PackedStringArray p_files) { - for (int i = 0; i < p_files.size(); i++) { - _scan_begin(p_files.get(i)); + PackedStringArray folders; + for (const String &E : folders_set) { + folders.push_back(E); } + _project_list->find_projects_multiple(folders); } void ProjectManager::_on_order_option_changed(int p_idx) { @@ -2770,11 +2756,6 @@ void ProjectManager::_on_search_term_submitted(const String &p_text) { _open_selected_projects_ask(); } -void ProjectManager::_bind_methods() { - ClassDB::bind_method("_update_project_buttons", &ProjectManager::_update_project_buttons); - ClassDB::bind_method("_version_button_pressed", &ProjectManager::_version_button_pressed); -} - void ProjectManager::_open_asset_library() { asset_library->disable_community_support(); tabs->set_current_tab(1); @@ -2896,8 +2877,8 @@ ProjectManager::ProjectManager() { vb->add_child(center_box); tabs = memnew(TabContainer); - center_box->add_child(tabs); tabs->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); + center_box->add_child(tabs); tabs->connect("tab_changed", callable_mp(this, &ProjectManager::_on_tab_changed)); local_projects_vb = memnew(VBoxContainer); @@ -2976,10 +2957,11 @@ ProjectManager::ProjectManager() { search_tree_hb->add_child(search_panel); _project_list = memnew(ProjectList); - _project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons)); - _project_list->connect(ProjectList::SIGNAL_PROJECT_ASK_OPEN, callable_mp(this, &ProjectManager::_open_selected_projects_ask)); _project_list->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); search_panel->add_child(_project_list); + _project_list->connect(ProjectList::SIGNAL_LIST_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons)); + _project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons)); + _project_list->connect(ProjectList::SIGNAL_PROJECT_ASK_OPEN, callable_mp(this, &ProjectManager::_open_selected_projects_ask)); // The side bar with the edit, run, rename, etc. buttons. VBoxContainer *tree_vb = memnew(VBoxContainer); @@ -3125,7 +3107,7 @@ ProjectManager::ProjectManager() { scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden scan_dir->set_current_dir(EDITOR_GET("filesystem/directories/default_project_path")); add_child(scan_dir); - scan_dir->connect("dir_selected", callable_mp(this, &ProjectManager::_scan_begin)); + scan_dir->connect("dir_selected", callable_mp(_project_list, &ProjectList::find_projects)); erase_missing_ask = memnew(ConfirmationDialog); erase_missing_ask->set_ok_button_text(TTR("Remove All")); @@ -3159,10 +3141,6 @@ ProjectManager::ProjectManager() { multi_run_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_run_project_confirm)); add_child(multi_run_ask); - multi_scan_ask = memnew(ConfirmationDialog); - multi_scan_ask->set_ok_button_text(TTR("Scan")); - add_child(multi_scan_ask); - ask_update_settings = memnew(ConfirmationDialog); ask_update_settings->set_autowrap(true); ask_update_settings->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_confirm_update_settings)); @@ -3271,29 +3249,36 @@ ProjectManager::ProjectManager() { create_tag_btn->connect("pressed", callable_mp((Window *)create_tag_dialog, &Window::popup_centered).bind(Vector2i(500, 0) * EDSCALE)); } - _project_list->migrate_config(); - _load_recent_projects(); - - Ref dir_access = DirAccess::create(DirAccess::AccessType::ACCESS_FILESYSTEM); + // Initialize project list. + { + Ref dir_access = DirAccess::create(DirAccess::AccessType::ACCESS_FILESYSTEM); - String default_project_path = EDITOR_GET("filesystem/directories/default_project_path"); - if (!dir_access->dir_exists(default_project_path)) { - Error error = dir_access->make_dir_recursive(default_project_path); - if (error != OK) { - ERR_PRINT("Could not create default project directory at: " + default_project_path); + String default_project_path = EDITOR_GET("filesystem/directories/default_project_path"); + if (!default_project_path.is_empty() && !dir_access->dir_exists(default_project_path)) { + Error error = dir_access->make_dir_recursive(default_project_path); + if (error != OK) { + ERR_PRINT("Could not create default project directory at: " + default_project_path); + } } - } - String autoscan_path = EDITOR_GET("filesystem/directories/autoscan_project_path"); - if (!autoscan_path.is_empty()) { - if (dir_access->dir_exists(autoscan_path)) { - _scan_begin(autoscan_path); - } else { - Error error = dir_access->make_dir_recursive(autoscan_path); - if (error != OK) { - ERR_PRINT("Could not create project autoscan directory at: " + autoscan_path); + bool scanned_for_projects = false; // Scanning will update the list automatically. + + String autoscan_path = EDITOR_GET("filesystem/directories/autoscan_project_path"); + if (!autoscan_path.is_empty()) { + if (dir_access->dir_exists(autoscan_path)) { + _project_list->find_projects(autoscan_path); + scanned_for_projects = true; + } else { + Error error = dir_access->make_dir_recursive(autoscan_path); + if (error != OK) { + ERR_PRINT("Could not create project autoscan directory at: " + autoscan_path); + } } } + + if (!scanned_for_projects) { + _project_list->update_project_list(); + } } SceneTree::get_singleton()->get_root()->connect("files_dropped", callable_mp(this, &ProjectManager::_files_dropped)); diff --git a/editor/project_manager.h b/editor/project_manager.h index d41207d7a292..8a8b2ff99d40 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -267,6 +267,9 @@ class ProjectList : public ScrollContainer { void _favorite_pressed(Node *p_hb); void _show_project(const String &p_path); + void _migrate_config(); + void _scan_folder_recursive(const String &p_path, List *r_projects); + void _clear_project_selection(); void _toggle_project(int p_index); void _select_project_nocheck(int p_index); @@ -288,12 +291,15 @@ class ProjectList : public ScrollContainer { static void _bind_methods(); public: + static const char *SIGNAL_LIST_CHANGED; static const char *SIGNAL_SELECTION_CHANGED; static const char *SIGNAL_PROJECT_ASK_OPEN; - void load_projects(); + void update_project_list(); int get_project_count() const; + void find_projects(const String &p_path); + void find_projects_multiple(const PackedStringArray &p_paths); void sort_projects(); void add_project(const String &dir_path, bool favorite); @@ -316,7 +322,6 @@ class ProjectList : public ScrollContainer { void set_order_option(int p_option); void update_dock_menu(); - void migrate_config(); void save_config(); ProjectList(); @@ -369,7 +374,6 @@ class ProjectManager : public Control { ConfirmationDialog *erase_missing_ask = nullptr; ConfirmationDialog *multi_open_ask = nullptr; ConfirmationDialog *multi_run_ask = nullptr; - ConfirmationDialog *multi_scan_ask = nullptr; ConfirmationDialog *ask_full_convert_dialog = nullptr; ConfirmationDialog *ask_update_settings = nullptr; ConfirmationDialog *open_templates = nullptr; @@ -425,12 +429,8 @@ class ProjectManager : public Control { void _set_new_tag_name(const String p_name); void _create_new_tag(); - void _load_recent_projects(); void _on_project_created(const String &dir); void _on_projects_updated(); - void _scan_multiple_folders(PackedStringArray p_files); - void _scan_begin(const String &p_base); - void _scan_dir(const String &path); void _install_project(const String &p_zip_path, const String &p_title); @@ -449,7 +449,6 @@ class ProjectManager : public Control { protected: void _notification(int p_what); - static void _bind_methods(); public: static ProjectManager *get_singleton() { return singleton; } From c2d38b4388a8754fdb7a542d255ac8b747ad3941 Mon Sep 17 00:00:00 2001 From: Mika Viskari Date: Fri, 24 Nov 2023 18:47:55 +0200 Subject: [PATCH 85/95] Fix invalid frame index when Sprite2D's hframes or vframes has been changed (cherry picked from commit 484c5b5aff6e513a92baf5d3ddcae8bc8941ee26) --- doc/classes/Sprite2D.xml | 6 +++--- doc/classes/Sprite3D.xml | 6 +++--- scene/2d/sprite_2d.cpp | 17 +++++++++++++++++ scene/3d/sprite_3d.cpp | 21 +++++++++++++++++++-- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml index 8eb9e26a8382..f8622d8f3863 100644 --- a/doc/classes/Sprite2D.xml +++ b/doc/classes/Sprite2D.xml @@ -60,13 +60,13 @@ If [code]true[/code], texture is flipped vertically. - Current frame to display from sprite sheet. [member hframes] or [member vframes] must be greater than 1. + Current frame to display from sprite sheet. [member hframes] or [member vframes] must be greater than 1. This property is automatically adjusted when [member hframes] or [member vframes] are changed to keep pointing to the same visual frame (same column and row). If that's impossible, this value is reset to [code]0[/code]. Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member hframes] or [member vframes] must be greater than 1. - The number of columns in the sprite sheet. + The number of columns in the sprite sheet. When this property is changed, [member frame] is adjusted so that the same visual frame is maintained (same row and column). If that's impossible, [member frame] is reset to [code]0[/code]. The texture's drawing offset. @@ -84,7 +84,7 @@ [Texture2D] object to draw. - The number of rows in the sprite sheet. + The number of rows in the sprite sheet. When this property is changed, [member frame] is adjusted so that the same visual frame is maintained (same row and column). If that's impossible, [member frame] is reset to [code]0[/code]. diff --git a/doc/classes/Sprite3D.xml b/doc/classes/Sprite3D.xml index 9733c5f48a2a..4b4421aeba79 100644 --- a/doc/classes/Sprite3D.xml +++ b/doc/classes/Sprite3D.xml @@ -10,13 +10,13 @@ - Current frame to display from sprite sheet. [member hframes] or [member vframes] must be greater than 1. + Current frame to display from sprite sheet. [member hframes] or [member vframes] must be greater than 1. This property is automatically adjusted when [member hframes] or [member vframes] are changed to keep pointing to the same visual frame (same column and row). If that's impossible, this value is reset to [code]0[/code]. Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member hframes] or [member vframes] must be greater than 1. - The number of columns in the sprite sheet. + The number of columns in the sprite sheet. When this property is changed, [member frame] is adjusted so that the same visual frame is maintained (same row and column). If that's impossible, [member frame] is reset to [code]0[/code]. If [code]true[/code], the sprite will use [member region_rect] and display only the specified part of its texture. @@ -28,7 +28,7 @@ [Texture2D] object to draw. If [member GeometryInstance3D.material_override] is used, this will be overridden. The size information is still used. - The number of rows in the sprite sheet. + The number of rows in the sprite sheet. When this property is changed, [member frame] is adjusted so that the same visual frame is maintained (same row and column). If that's impossible, [member frame] is reset to [code]0[/code]. diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index 7e6b43559ca2..6d0a2968d795 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -261,6 +261,9 @@ Vector2i Sprite2D::get_frame_coords() const { void Sprite2D::set_vframes(int p_amount) { ERR_FAIL_COND_MSG(p_amount < 1, "Amount of vframes cannot be smaller than 1."); vframes = p_amount; + if (frame >= vframes * hframes) { + frame = 0; + } queue_redraw(); item_rect_changed(); notify_property_list_changed(); @@ -272,7 +275,21 @@ int Sprite2D::get_vframes() const { void Sprite2D::set_hframes(int p_amount) { ERR_FAIL_COND_MSG(p_amount < 1, "Amount of hframes cannot be smaller than 1."); + if (vframes > 1) { + // Adjust the frame to fit new sheet dimensions. + int original_column = frame % hframes; + if (original_column >= p_amount) { + // Frame's column was dropped, reset. + frame = 0; + } else { + int original_row = frame / hframes; + frame = original_row * p_amount + original_column; + } + } hframes = p_amount; + if (frame >= vframes * hframes) { + frame = 0; + } queue_redraw(); item_rect_changed(); notify_property_list_changed(); diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 920cf22b8372..ffd328c37e8e 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -804,8 +804,11 @@ Vector2i Sprite3D::get_frame_coords() const { } void Sprite3D::set_vframes(int p_amount) { - ERR_FAIL_COND(p_amount < 1); + ERR_FAIL_COND_MSG(p_amount < 1, "Amount of vframes cannot be smaller than 1."); vframes = p_amount; + if (frame >= vframes * hframes) { + frame = 0; + } _queue_redraw(); notify_property_list_changed(); } @@ -815,8 +818,22 @@ int Sprite3D::get_vframes() const { } void Sprite3D::set_hframes(int p_amount) { - ERR_FAIL_COND(p_amount < 1); + ERR_FAIL_COND_MSG(p_amount < 1, "Amount of hframes cannot be smaller than 1."); + if (vframes > 1) { + // Adjust the frame to fit new sheet dimensions. + int original_column = frame % hframes; + if (original_column >= p_amount) { + // Frame's column was dropped, reset. + frame = 0; + } else { + int original_row = frame / hframes; + frame = original_row * p_amount + original_column; + } + } hframes = p_amount; + if (frame >= vframes * hframes) { + frame = 0; + } _queue_redraw(); notify_property_list_changed(); } From beadc92e4f3b50c04c38dfc3c5b9b413b68a9a70 Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Thu, 21 Dec 2023 18:14:10 +0800 Subject: [PATCH 86/95] Clear sub-resources list when no sub-resource exists (cherry picked from commit 6e49ff91c0b88792a76c6514f0af25b937e7a9e4) --- editor/inspector_dock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 717aaf396fca..1ee273f64b30 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -139,8 +139,8 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) { } } + unique_resources_list_tree->clear(); if (resource_propnames.size()) { - unique_resources_list_tree->clear(); TreeItem *root = unique_resources_list_tree->create_item(); for (int i = 0; i < resource_propnames.size(); i++) { From c35e05e7b15b65badc334871e3fa58644a463dce Mon Sep 17 00:00:00 2001 From: Danil Alexeev Date: Tue, 12 Dec 2023 22:15:16 +0300 Subject: [PATCH 87/95] GDScript: Fix accessing static function as `Callable` in static context (cherry picked from commit 10dcb21d8b4f36de45b623ac0c9f14f3a7f9a96c) --- modules/gdscript/gdscript_compiler.cpp | 8 ++++++-- .../scripts/runtime/features/static_method_as_callable.gd | 8 +++++++- .../runtime/features/static_method_as_callable.out | 2 ++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 5cf6c9ba408b..a84a387271b7 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -322,9 +322,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) { // Get like it was a property. GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here. - GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF); - gen->write_get_named(temp, identifier, self); + GDScriptCodeGenerator::Address base(GDScriptCodeGenerator::Address::SELF); + if (member.type == GDScriptParser::ClassNode::Member::FUNCTION && member.function->is_static) { + base = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS); + } + + gen->write_get_named(temp, identifier, base); return temp; } } diff --git a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd index f6aa58737feb..97e9da3b2670 100644 --- a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd +++ b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.gd @@ -1,12 +1,18 @@ -# GH-79521 +# GH-79521, GH-86032 class_name TestStaticMethodAsCallable static func static_func() -> String: return "Test" +static func another_static_func(): + prints("another_static_func:", static_func.call(), static_func.is_valid()) + func test(): var a: Callable = TestStaticMethodAsCallable.static_func var b: Callable = static_func prints(a.call(), a.is_valid()) prints(b.call(), b.is_valid()) + @warning_ignore("static_called_on_instance") + another_static_func() + TestStaticMethodAsCallable.another_static_func() diff --git a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out index e6d461b8f95a..2b773ce8eeba 100644 --- a/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out +++ b/modules/gdscript/tests/scripts/runtime/features/static_method_as_callable.out @@ -1,3 +1,5 @@ GDTEST_OK Test true Test true +another_static_func: Test true +another_static_func: Test true From 873a77d8e9af1a0bb8b460ac599239e389f5978d Mon Sep 17 00:00:00 2001 From: Micky Date: Wed, 3 Jan 2024 01:33:08 +0100 Subject: [PATCH 88/95] Add autocompletion options for AnimatedSprite's other play methods (cherry picked from commit d5a7c7818c2424c9dc919d9e6d163a39bf13f081) --- scene/2d/animated_sprite_2d.cpp | 12 +++++++----- scene/3d/sprite_3d.cpp | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index bf3783966b16..d9754260949f 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -561,11 +561,13 @@ PackedStringArray AnimatedSprite2D::get_configuration_warnings() const { } void AnimatedSprite2D::get_argument_options(const StringName &p_function, int p_idx, List *r_options) const { - if (p_idx == 0 && p_function == "play" && frames.is_valid()) { - List al; - frames->get_animation_list(&al); - for (const StringName &name : al) { - r_options->push_back(String(name).quote()); + if (p_idx == 0 && frames.is_valid()) { + if (p_function == "play" || p_function == "play_backwards" || p_function == "set_animation" || p_function == "set_autoplay") { + List al; + frames->get_animation_list(&al); + for (const StringName &name : al) { + r_options->push_back(String(name).quote()); + } } } Node::get_argument_options(p_function, p_idx, r_options); diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index ffd328c37e8e..248af2f4caec 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -1365,11 +1365,13 @@ PackedStringArray AnimatedSprite3D::get_configuration_warnings() const { } void AnimatedSprite3D::get_argument_options(const StringName &p_function, int p_idx, List *r_options) const { - if (p_idx == 0 && p_function == "play" && frames.is_valid()) { - List al; - frames->get_animation_list(&al); - for (const StringName &name : al) { - r_options->push_back(String(name).quote()); + if (p_idx == 0 && frames.is_valid()) { + if (p_function == "play" || p_function == "play_backwards" || p_function == "set_animation" || p_function == "set_autoplay") { + List al; + frames->get_animation_list(&al); + for (const StringName &name : al) { + r_options->push_back(String(name).quote()); + } } } Node::get_argument_options(p_function, p_idx, r_options); From a92a2015f0f7031d7c5cce00994f66697e27c4bd Mon Sep 17 00:00:00 2001 From: Micky Date: Wed, 3 Jan 2024 00:13:04 +0100 Subject: [PATCH 89/95] Fix missing autocompletion for inheriting classes (cherry picked from commit ca2f3403840cae9748a38c98b7af1e9e60c63475) --- core/input/input.cpp | 1 + scene/2d/animated_sprite_2d.cpp | 2 +- scene/3d/sprite_3d.cpp | 2 +- scene/animation/animation_player.cpp | 2 +- scene/gui/control.cpp | 2 +- scene/main/scene_tree.cpp | 1 + scene/resources/material.cpp | 2 +- 7 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/input/input.cpp b/core/input/input.cpp index 257452b3d894..55953c5ac74e 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -192,6 +192,7 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, Listpush_back(name.quote()); } } + Object::get_argument_options(p_function, p_idx, r_options); } void Input::VelocityTrack::update(const Vector2 &p_delta_p) { diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index d9754260949f..b6c24864e6d0 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -570,7 +570,7 @@ void AnimatedSprite2D::get_argument_options(const StringName &p_function, int p_ } } } - Node::get_argument_options(p_function, p_idx, r_options); + Node2D::get_argument_options(p_function, p_idx, r_options); } #ifndef DISABLE_DEPRECATED diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 248af2f4caec..5dc2f49a49e2 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -1374,7 +1374,7 @@ void AnimatedSprite3D::get_argument_options(const StringName &p_function, int p_ } } } - Node::get_argument_options(p_function, p_idx, r_options); + SpriteBase3D::get_argument_options(p_function, p_idx, r_options); } #ifndef DISABLE_DEPRECATED diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index ad6caca32b53..deced61ddc9d 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -670,7 +670,7 @@ void AnimationPlayer::get_argument_options(const StringName &p_function, int p_i r_options->push_back(String(name).quote()); } } - Node::get_argument_options(p_function, p_idx, r_options); + AnimationMixer::get_argument_options(p_function, p_idx, r_options); } void AnimationPlayer::_animation_removed(const StringName &p_name, const StringName &p_library) { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index ed54bd000cb2..efc93a344daf 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -199,7 +199,7 @@ void Control::reparent(Node *p_parent, bool p_keep_global_transform) { void Control::get_argument_options(const StringName &p_function, int p_idx, List *r_options) const { ERR_READ_THREAD_GUARD; - Node::get_argument_options(p_function, p_idx, r_options); + CanvasItem::get_argument_options(p_function, p_idx, r_options); if (p_idx == 0) { List sn; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index cf80bd6c6fc8..a28c2053beb9 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1704,6 +1704,7 @@ void SceneTree::get_argument_options(const StringName &p_function, int p_idx, Li } } } + MainLoop::get_argument_options(p_function, p_idx, r_options); } void SceneTree::set_disable_node_threading(bool p_disable) { diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 1b74063ff452..dba4e4eb3470 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -468,7 +468,7 @@ void ShaderMaterial::get_argument_options(const StringName &p_function, int p_id } } } - Resource::get_argument_options(p_function, p_idx, r_options); + Material::get_argument_options(p_function, p_idx, r_options); } bool ShaderMaterial::_can_do_next_pass() const { From ce42f8b4ec5cdaa93a464e8fcff5d7b4a5c819fe Mon Sep 17 00:00:00 2001 From: Gregory De Bonis Date: Thu, 14 Dec 2023 10:39:15 -0300 Subject: [PATCH 90/95] Wrong key mapping for XK_KP_Delete key Fixes #86156 (cherry picked from commit 95bcf93849620f105b34a0e7adc51faca9bec8bf) --- platform/linuxbsd/x11/key_mapping_x11.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/linuxbsd/x11/key_mapping_x11.cpp b/platform/linuxbsd/x11/key_mapping_x11.cpp index 0f709872cb82..c0e6b91d57ab 100644 --- a/platform/linuxbsd/x11/key_mapping_x11.cpp +++ b/platform/linuxbsd/x11/key_mapping_x11.cpp @@ -88,7 +88,6 @@ void KeyMappingX11::initialize() { xkeysym_map[XK_KP_Equal] = Key::EQUAL; xkeysym_map[XK_KP_Separator] = Key::COMMA; xkeysym_map[XK_KP_Decimal] = Key::KP_PERIOD; - xkeysym_map[XK_KP_Delete] = Key::KP_PERIOD; xkeysym_map[XK_KP_Multiply] = Key::KP_MULTIPLY; xkeysym_map[XK_KP_Divide] = Key::KP_DIVIDE; xkeysym_map[XK_KP_Subtract] = Key::KP_SUBTRACT; @@ -105,6 +104,7 @@ void KeyMappingX11::initialize() { xkeysym_map[XK_KP_9] = Key::KP_9; // Same keys but with numlock off. xkeysym_map[XK_KP_Insert] = Key::INSERT; + xkeysym_map[XK_KP_Delete] = Key::KEY_DELETE; xkeysym_map[XK_KP_End] = Key::END; xkeysym_map[XK_KP_Down] = Key::DOWN; xkeysym_map[XK_KP_Page_Down] = Key::PAGEDOWN; From 6c8375b73d7da41ab03e45b4c757157e604a72b4 Mon Sep 17 00:00:00 2001 From: Samuel Venable Date: Sat, 4 Nov 2023 23:29:50 -0400 Subject: [PATCH 91/95] Fix NetBSD Executable Path (cherry picked from commit 52da1e9b6b96057efd8ab8039978828114d92564) --- drivers/unix/os_unix.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 9a77930d75b2..27172a1e3fa8 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -751,11 +751,26 @@ String OS_Unix::get_executable_path() const { return OS::get_executable_path(); } return b; -#elif defined(__OpenBSD__) || defined(__NetBSD__) +#elif defined(__OpenBSD__) char resolved_path[MAXPATHLEN]; realpath(OS::get_executable_path().utf8().get_data(), resolved_path); + return String(resolved_path); +#elif defined(__NetBSD__) + int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME }; + char buf[MAXPATHLEN]; + size_t len = sizeof(buf); + if (sysctl(mib, 4, buf, &len, nullptr, 0) != 0) { + WARN_PRINT("Couldn't get executable path from sysctl"); + return OS::get_executable_path(); + } + + // NetBSD does not always return a normalized path. For example if argv[0] is "./a.out" then executable path is "/home/netbsd/./a.out". Normalize with realpath: + char resolved_path[MAXPATHLEN]; + + realpath(buf, resolved_path); + return String(resolved_path); #elif defined(__FreeBSD__) int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; From 822b2b43a6bd7e15f24c8cadf37fc03a235f8db7 Mon Sep 17 00:00:00 2001 From: Alexander Hartmann Date: Wed, 3 Jan 2024 20:53:37 +0100 Subject: [PATCH 92/95] Fix 'get_window_safe_area' on Android (cherry picked from commit d7c6ad20204be927c54060ed1a1dc186c461799c) --- .../java/lib/src/org/godotengine/godot/GodotIO.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java index edcd9c4d1f18..4b51bd778d49 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -178,12 +178,10 @@ public double getScreenRefreshRate(double fallback) { } public int[] getDisplaySafeArea() { - DisplayMetrics metrics = activity.getResources().getDisplayMetrics(); - Display display = activity.getWindowManager().getDefaultDisplay(); - Point size = new Point(); - display.getRealSize(size); + Rect rect = new Rect(); + activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect); - int[] result = { 0, 0, size.x, size.y }; + int[] result = { rect.left, rect.top, rect.right, rect.bottom }; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets(); DisplayCutout cutout = insets.getDisplayCutout(); From 881d2538976049d7a8355730d2989c737940141c Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Sat, 6 Jan 2024 14:06:10 +0100 Subject: [PATCH 93/95] Fix some build errors with `disable_3d=Yes` * Some tests were incorrectly included * SCU builds with animation * Animation `switch` (cherry picked from commit c6a1ae78750919dfa30e8af6adf856565593cc18) --- scene/animation/animation_mixer.cpp | 15 ++++----------- scene/animation/root_motion_view.cpp | 4 ++++ scene/register_scene_types.cpp | 2 +- tests/test_main.cpp | 13 ++++++++----- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index da00d1dd7b0a..2ebd84849d1f 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -953,19 +953,12 @@ Variant AnimationMixer::post_process_key_value(const Ref &p_anim, int } Variant AnimationMixer::_post_process_key_value(const Ref &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) { - switch (p_anim->track_get_type(p_track)) { #ifndef _3D_DISABLED - case Animation::TYPE_POSITION_3D: { - if (p_object_idx >= 0) { - const Skeleton3D *skel = Object::cast_to(p_object); - return Vector3(p_value) * skel->get_motion_scale(); - } - return p_value; - } break; -#endif // _3D_DISABLED - default: { - } break; + if (p_object_idx >= 0 && p_anim->track_get_type(p_track) == Animation::TYPE_POSITION_3D) { + const Skeleton3D *skel = Object::cast_to(p_object); + return Vector3(p_value) * skel->get_motion_scale(); } +#endif // _3D_DISABLED return p_value; } diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp index 645850015b2e..fd520dadd66a 100644 --- a/scene/animation/root_motion_view.cpp +++ b/scene/animation/root_motion_view.cpp @@ -28,6 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ +#ifndef _3D_DISABLED + #include "root_motion_view.h" #include "scene/animation/animation_tree.h" @@ -203,3 +205,5 @@ RootMotionView::RootMotionView() { RootMotionView::~RootMotionView() { set_base(RID()); } + +#endif // _3D_DISABLED diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 3727c788fde9..f684969dd98c 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -78,7 +78,6 @@ #include "scene/animation/animation_node_state_machine.h" #include "scene/animation/animation_player.h" #include "scene/animation/animation_tree.h" -#include "scene/animation/root_motion_view.h" #include "scene/animation/tween.h" #include "scene/audio/audio_stream_player.h" #include "scene/debugger/scene_debugger.h" @@ -273,6 +272,7 @@ #include "scene/3d/voxel_gi.h" #include "scene/3d/world_environment.h" #include "scene/3d/xr_nodes.h" +#include "scene/animation/root_motion_view.h" #include "scene/resources/environment.h" #include "scene/resources/fog_material.h" #include "scene/resources/importer_mesh.h" diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 8c120f6d3af8..c945198b1bde 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -102,16 +102,12 @@ #include "tests/scene/test_curve_3d.h" #include "tests/scene/test_gradient.h" #include "tests/scene/test_navigation_agent_2d.h" -#include "tests/scene/test_navigation_agent_3d.h" #include "tests/scene/test_navigation_obstacle_2d.h" -#include "tests/scene/test_navigation_obstacle_3d.h" #include "tests/scene/test_navigation_region_2d.h" -#include "tests/scene/test_navigation_region_3d.h" #include "tests/scene/test_node.h" #include "tests/scene/test_node_2d.h" #include "tests/scene/test_packed_scene.h" #include "tests/scene/test_path_2d.h" -#include "tests/scene/test_path_3d.h" #include "tests/scene/test_primitives.h" #include "tests/scene/test_sprite_frames.h" #include "tests/scene/test_text_edit.h" @@ -121,10 +117,17 @@ #include "tests/scene/test_window.h" #include "tests/servers/rendering/test_shader_preprocessor.h" #include "tests/servers/test_navigation_server_2d.h" -#include "tests/servers/test_navigation_server_3d.h" #include "tests/servers/test_text_server.h" #include "tests/test_validate_testing.h" +#ifndef _3D_DISABLED +#include "tests/scene/test_navigation_agent_3d.h" +#include "tests/scene/test_navigation_obstacle_3d.h" +#include "tests/scene/test_navigation_region_3d.h" +#include "tests/scene/test_path_3d.h" +#include "tests/servers/test_navigation_server_3d.h" +#endif // _3D_DISABLED + #include "modules/modules_tests.gen.h" #include "tests/display_server_mock.h" From ad57a98eb0a3ab177fef95de46e13afc1434f84d Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Fri, 12 Jan 2024 17:58:42 +0100 Subject: [PATCH 94/95] [Core] Fix `AABB.encloses` failing on shared upper bound This differs from `Rect2(i)` and was fixed for those classes in the past (cherry picked from commit b4191bf8f64f984f469dc4fcef0c0f23cf6cf226) --- core/math/aabb.h | 6 +++--- tests/core/math/test_aabb.h | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/core/math/aabb.h b/core/math/aabb.h index 859810df372a..cea845bf7c2d 100644 --- a/core/math/aabb.h +++ b/core/math/aabb.h @@ -200,11 +200,11 @@ inline bool AABB::encloses(const AABB &p_aabb) const { return ( (src_min.x <= dst_min.x) && - (src_max.x > dst_max.x) && + (src_max.x >= dst_max.x) && (src_min.y <= dst_min.y) && - (src_max.y > dst_max.y) && + (src_max.y >= dst_max.y) && (src_min.z <= dst_min.z) && - (src_max.z > dst_max.z)); + (src_max.z >= dst_max.z)); } Vector3 AABB::get_support(const Vector3 &p_normal) const { diff --git a/tests/core/math/test_aabb.h b/tests/core/math/test_aabb.h index d3560ff6b6cd..b9f84cca245a 100644 --- a/tests/core/math/test_aabb.h +++ b/tests/core/math/test_aabb.h @@ -228,11 +228,20 @@ TEST_CASE("[AABB] Merging") { TEST_CASE("[AABB] Encloses") { const AABB aabb_big = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6)); + CHECK_MESSAGE( + aabb_big.encloses(aabb_big), + "encloses() with itself should return the expected result."); + AABB aabb_small = AABB(Vector3(-1.5, 2, -2.5), Vector3(1, 1, 1)); CHECK_MESSAGE( aabb_big.encloses(aabb_small), "encloses() with fully contained AABB (touching the edge) should return the expected result."); + aabb_small = AABB(Vector3(1.5, 6, 2.5), Vector3(1, 1, 1)); + CHECK_MESSAGE( + aabb_big.encloses(aabb_small), + "encloses() with fully contained AABB (touching the edge) should return the expected result."); + aabb_small = AABB(Vector3(0.5, 1.5, -2), Vector3(1, 1, 1)); CHECK_MESSAGE( !aabb_big.encloses(aabb_small), From e070bbc77e260a5456dd2d4c0869715f2b1297f8 Mon Sep 17 00:00:00 2001 From: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com> Date: Tue, 16 Jan 2024 19:27:03 +0100 Subject: [PATCH 95/95] [C#] Fix `Encloses` failing on shared upper bound for `AABB` and `Rect2(I)` (cherry picked from commit 227a165ce4ecf2c040263075ed4b23862519af6f) --- modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs | 6 +++--- modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs | 4 ++-- modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs index cc99225a3356..b4f9b3c16b9a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs @@ -95,11 +95,11 @@ public readonly bool Encloses(Aabb with) Vector3 dstMax = with._position + with._size; return srcMin.X <= dstMin.X && - srcMax.X > dstMax.X && + srcMax.X >= dstMax.X && srcMin.Y <= dstMin.Y && - srcMax.Y > dstMax.Y && + srcMax.Y >= dstMax.Y && srcMin.Z <= dstMin.Z && - srcMax.Z > dstMax.Z; + srcMax.Z >= dstMax.Z; } /// diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index babb26960b80..41ade74db7e2 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs @@ -120,8 +120,8 @@ public bool IsFinite() public readonly bool Encloses(Rect2 b) { return b._position.X >= _position.X && b._position.Y >= _position.Y && - b._position.X + b._size.X < _position.X + _size.X && - b._position.Y + b._size.Y < _position.Y + _size.Y; + b._position.X + b._size.X <= _position.X + _size.X && + b._position.Y + b._size.Y <= _position.Y + _size.Y; } /// diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs index 49fba02b54fd..f9e88f094a68 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs @@ -110,8 +110,8 @@ public readonly Rect2I Intersection(Rect2I b) public readonly bool Encloses(Rect2I b) { return b._position.X >= _position.X && b._position.Y >= _position.Y && - b._position.X + b._size.X < _position.X + _size.X && - b._position.Y + b._size.Y < _position.Y + _size.Y; + b._position.X + b._size.X <= _position.X + _size.X && + b._position.Y + b._size.Y <= _position.Y + _size.Y; } ///