summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/classes/MultiplayerAPI.xml2
-rw-r--r--platform/ios/export/export_plugin.cpp4
-rw-r--r--scene/3d/label_3d.cpp11
-rw-r--r--scene/main/canvas_item.cpp59
-rw-r--r--scene/main/viewport.cpp298
-rw-r--r--scene/main/viewport.h81
-rw-r--r--scene/property_utils.cpp8
-rw-r--r--scene/resources/3d/primitive_meshes.cpp9
-rw-r--r--scene/resources/font.cpp7
-rw-r--r--scene/resources/packed_scene.cpp40
-rw-r--r--scene/resources/packed_scene.h2
-rw-r--r--thirdparty/README.md4
-rw-r--r--thirdparty/thorvg/inc/config.h2
-rw-r--r--thirdparty/thorvg/inc/thorvg.h16
-rw-r--r--thirdparty/thorvg/patches/Fix_compiler_shadowing_warning.patch23
-rw-r--r--thirdparty/thorvg/src/common/tvgArray.h10
-rw-r--r--thirdparty/thorvg/src/common/tvgBezier.cpp99
-rw-r--r--thirdparty/thorvg/src/common/tvgBezier.h2
-rw-r--r--thirdparty/thorvg/src/common/tvgLock.h1
-rw-r--r--thirdparty/thorvg/src/common/tvgMath.h1
-rw-r--r--thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp3
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp33
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp4
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp8
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp10
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp18
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp2
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp7
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp6
-rw-r--r--thirdparty/thorvg/src/renderer/tvgAnimation.cpp22
-rw-r--r--thirdparty/thorvg/src/renderer/tvgAnimation.h48
-rw-r--r--thirdparty/thorvg/src/renderer/tvgLoadModule.h15
-rw-r--r--thirdparty/thorvg/src/renderer/tvgLoader.cpp44
-rw-r--r--thirdparty/thorvg/src/renderer/tvgRender.h2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgSaver.cpp7
-rw-r--r--thirdparty/thorvg/src/renderer/tvgShape.cpp14
-rw-r--r--thirdparty/thorvg/src/renderer/tvgShape.h2
-rw-r--r--thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp6
-rwxr-xr-xthirdparty/thorvg/update-thorvg.sh2
39 files changed, 533 insertions, 399 deletions
diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml
index 009d7c03ea..d5016867a7 100644
--- a/doc/classes/MultiplayerAPI.xml
+++ b/doc/classes/MultiplayerAPI.xml
@@ -34,7 +34,7 @@
<return type="int" />
<description>
Returns the sender's peer ID for the RPC currently being executed.
- [b]Note:[/b] If not inside an RPC this method will return 0.
+ [b]Note:[/b] This method returns [code]0[/code] when called outside of an RPC. As such, the original peer ID may be lost when code execution is delayed (such as with GDScript's [code]await[/code] keyword).
</description>
</method>
<method name="get_unique_id">
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index 91d75b0629..00473165fd 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -416,6 +416,10 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
} else if (lines[i].find("$pbx_launch_screen_build_reference") != -1) {
String value = "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };";
strnew += lines[i].replace("$pbx_launch_screen_build_reference", value) + "\n";
+#ifndef DISABLE_DEPRECATED
+ } else if (lines[i].find("$pbx_launch_image_usage_setting") != -1) {
+ strnew += lines[i].replace("$pbx_launch_image_usage_setting", "") + "\n";
+#endif
} else if (lines[i].find("$launch_screen_image_mode") != -1) {
int image_scale_mode = p_preset->get("storyboard/image_scale_mode");
String value;
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index 02f40713bf..9f71c881a9 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -782,6 +782,8 @@ Ref<Font> Label3D::get_font() const {
}
Ref<Font> Label3D::_get_font_or_default() const {
+ // Similar code taken from `FontVariation::_get_base_font_or_default`.
+
if (theme_font.is_valid()) {
theme_font->disconnect_changed(callable_mp(const_cast<Label3D *>(this), &Label3D::_font_changed));
theme_font.unref();
@@ -791,12 +793,17 @@ Ref<Font> Label3D::_get_font_or_default() const {
return font_override;
}
- StringName theme_name = "font";
+ const StringName theme_name = "font";
List<StringName> theme_types;
ThemeDB::get_singleton()->get_native_type_dependencies(get_class_name(), &theme_types);
ThemeContext *global_context = ThemeDB::get_singleton()->get_default_theme_context();
- for (const Ref<Theme> &theme : global_context->get_themes()) {
+ List<Ref<Theme>> themes = global_context->get_themes();
+ if (Engine::get_singleton()->is_editor_hint()) {
+ themes.push_front(ThemeDB::get_singleton()->get_project_theme());
+ }
+
+ for (const Ref<Theme> &theme : themes) {
if (theme.is_null()) {
continue;
}
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 2f435cafee..2d0da075ba 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -40,6 +40,9 @@
#include "scene/resources/world_2d.h"
#include "scene/scene_string_names.h"
+#define ERR_DRAW_GUARD \
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside this node's `_draw()`, functions connected to its `draw` signal, or when it receives NOTIFICATION_DRAW.")
+
#ifdef TOOLS_ENABLED
bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
if (_edit_use_rect()) {
@@ -588,7 +591,7 @@ bool CanvasItem::is_y_sort_enabled() const {
void CanvasItem::draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, real_t p_dash, bool p_aligned) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_dash <= 0.0);
float length = (p_to - p_from).length();
@@ -624,14 +627,14 @@ void CanvasItem::draw_dashed_line(const Point2 &p_from, const Point2 &p_to, cons
void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width, bool p_antialiased) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width, p_antialiased);
}
void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width, bool p_antialiased) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
Vector<Color> colors = { p_color };
RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width, p_antialiased);
@@ -639,7 +642,7 @@ void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_co
void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width, bool p_antialiased) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased);
}
@@ -662,7 +665,7 @@ void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_sta
void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
Vector<Color> colors = { p_color };
RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, colors, p_width);
@@ -670,14 +673,14 @@ void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_c
void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width);
}
void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, real_t p_width) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
Rect2 rect = p_rect.abs();
@@ -706,14 +709,14 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
}
void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_texture.is_null());
@@ -722,7 +725,7 @@ void CanvasItem::draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_p
void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_texture.is_null());
p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose);
@@ -730,28 +733,28 @@ void CanvasItem::draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2
void CanvasItem::draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_texture.is_null());
p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv);
}
void CanvasItem::draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, double p_outline, double p_pixel_range, double p_scale) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_texture.is_null());
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range, p_scale);
}
void CanvasItem::draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_texture.is_null());
RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate);
}
void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_style_box.is_null());
@@ -760,7 +763,7 @@ void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p
void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid);
@@ -768,7 +771,7 @@ void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Col
void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const Size2 &p_scale) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
Transform2D xform(p_rot, p_offset);
xform.scale_basis(p_scale);
@@ -777,27 +780,27 @@ void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const
void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix);
}
void CanvasItem::draw_animation_slice(double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, p_animation_length, p_slice_begin, p_slice_end, p_offset);
}
void CanvasItem::draw_end_animation() {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, 1, 0, 2, 0);
}
void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
@@ -806,7 +809,7 @@ void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color
void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
Vector<Color> colors = { p_color };
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
@@ -830,7 +833,7 @@ void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Tex
void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_font.is_null());
p_font->draw_string(canvas_item, p_pos, p_text, p_alignment, p_width, p_font_size, p_modulate, p_jst_flags, p_direction, p_orientation);
@@ -838,7 +841,7 @@ void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const
void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_font.is_null());
p_font->draw_multiline_string(canvas_item, p_pos, p_text, p_alignment, p_width, p_font_size, p_max_lines, p_modulate, p_brk_flags, p_jst_flags, p_direction, p_orientation);
@@ -846,7 +849,7 @@ void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_
void CanvasItem::draw_string_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_size, const Color &p_modulate, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_font.is_null());
p_font->draw_string_outline(canvas_item, p_pos, p_text, p_alignment, p_width, p_font_size, p_size, p_modulate, p_jst_flags, p_direction, p_orientation);
@@ -854,7 +857,7 @@ void CanvasItem::draw_string_outline(const Ref<Font> &p_font, const Point2 &p_po
void CanvasItem::draw_multiline_string_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HorizontalAlignment p_alignment, float p_width, int p_font_size, int p_max_lines, int p_size, const Color &p_modulate, BitField<TextServer::LineBreakFlag> p_brk_flags, BitField<TextServer::JustificationFlag> p_jst_flags, TextServer::Direction p_direction, TextServer::Orientation p_orientation) const {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_font.is_null());
p_font->draw_multiline_string_outline(canvas_item, p_pos, p_text, p_alignment, p_width, p_font_size, p_max_lines, p_size, p_modulate, p_brk_flags, p_jst_flags, p_direction, p_orientation);
@@ -862,7 +865,7 @@ void CanvasItem::draw_multiline_string_outline(const Ref<Font> &p_font, const Po
void CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, int p_font_size, const Color &p_modulate) const {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_char.length() != 1);
ERR_FAIL_COND(p_font.is_null());
@@ -871,7 +874,7 @@ void CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const S
void CanvasItem::draw_char_outline(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, int p_font_size, int p_size, const Color &p_modulate) const {
ERR_THREAD_GUARD;
- ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_DRAW_GUARD;
ERR_FAIL_COND(p_char.length() != 1);
ERR_FAIL_COND(p_font.is_null());
@@ -1353,7 +1356,7 @@ void CanvasItem::set_visibility_layer_bit(uint32_t p_visibility_layer, bool p_en
}
bool CanvasItem::get_visibility_layer_bit(uint32_t p_visibility_layer) const {
- ERR_READ_THREAD_GUARD_V(0);
+ ERR_READ_THREAD_GUARD_V(false);
ERR_FAIL_UNSIGNED_INDEX_V(p_visibility_layer, 32, false);
return (visibility_layer & (1 << p_visibility_layer));
}
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 1ee6a8dca7..c8d2d71c2a 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1068,32 +1068,6 @@ void Viewport::canvas_parent_mark_dirty(Node *p_node) {
}
}
-void Viewport::_update_audio_listener_2d() {
- if (AudioServer::get_singleton()) {
- AudioServer::get_singleton()->notify_listener_changed();
- }
-}
-
-void Viewport::set_as_audio_listener_2d(bool p_enable) {
- ERR_MAIN_THREAD_GUARD;
- if (p_enable == is_audio_listener_2d_enabled) {
- return;
- }
-
- is_audio_listener_2d_enabled = p_enable;
- _update_audio_listener_2d();
-}
-
-bool Viewport::is_audio_listener_2d() const {
- ERR_READ_THREAD_GUARD_V(false);
- return is_audio_listener_2d_enabled;
-}
-
-AudioListener2D *Viewport::get_audio_listener_2d() const {
- ERR_READ_THREAD_GUARD_V(nullptr);
- return audio_listener_2d;
-}
-
void Viewport::enable_canvas_transform_override(bool p_enable) {
ERR_MAIN_THREAD_GUARD;
if (override_canvas_transform == p_enable) {
@@ -1162,25 +1136,6 @@ Transform2D Viewport::get_global_canvas_transform() const {
return global_canvas_transform;
}
-void Viewport::_camera_2d_set(Camera2D *p_camera_2d) {
- camera_2d = p_camera_2d;
-}
-
-void Viewport::_audio_listener_2d_set(AudioListener2D *p_listener) {
- if (audio_listener_2d == p_listener) {
- return;
- } else if (audio_listener_2d) {
- audio_listener_2d->clear_current();
- }
- audio_listener_2d = p_listener;
-}
-
-void Viewport::_audio_listener_2d_remove(AudioListener2D *p_listener) {
- if (audio_listener_2d == p_listener) {
- audio_listener_2d = nullptr;
- }
-}
-
void Viewport::_canvas_layer_add(CanvasLayer *p_canvas_layer) {
canvas_layers.insert(p_canvas_layer);
}
@@ -1272,40 +1227,11 @@ Ref<World2D> Viewport::get_world_2d() const {
return world_2d;
}
-Camera2D *Viewport::get_camera_2d() const {
- ERR_READ_THREAD_GUARD_V(nullptr);
- return camera_2d;
-}
-
Transform2D Viewport::get_final_transform() const {
ERR_READ_THREAD_GUARD_V(Transform2D());
return stretch_transform * global_canvas_transform;
}
-void Viewport::assign_next_enabled_camera_2d(const StringName &p_camera_group) {
- ERR_MAIN_THREAD_GUARD;
- List<Node *> camera_list;
- get_tree()->get_nodes_in_group(p_camera_group, &camera_list);
-
- Camera2D *new_camera = nullptr;
- for (Node *E : camera_list) {
- Camera2D *cam = Object::cast_to<Camera2D>(E);
- if (!cam) {
- continue; // Non-camera node (e.g. ParallaxBackground).
- }
-
- if (cam->is_enabled()) {
- new_camera = cam;
- break;
- }
- }
-
- _camera_2d_set(new_camera);
- if (!camera_2d) {
- set_canvas_transform(Transform2D());
- }
-}
-
void Viewport::_update_canvas_items(Node *p_node) {
if (p_node != this) {
Window *w = Object::cast_to<Window>(p_node);
@@ -2644,76 +2570,6 @@ void Viewport::_drop_physics_mouseover(bool p_paused_only) {
#endif // _3D_DISABLED
}
-void Viewport::_cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paused_only, uint64_t p_frame_reference) {
- List<ObjectID> to_erase;
- List<ObjectID> to_mouse_exit;
-
- for (const KeyValue<ObjectID, uint64_t> &E : physics_2d_mouseover) {
- if (!p_clean_all_frames && E.value == p_frame_reference) {
- continue;
- }
-
- Object *o = ObjectDB::get_instance(E.key);
- if (o) {
- CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
- if (co && co->is_inside_tree()) {
- if (p_clean_all_frames && p_paused_only && co->can_process()) {
- continue;
- }
- to_mouse_exit.push_back(E.key);
- }
- }
- to_erase.push_back(E.key);
- }
-
- while (to_erase.size()) {
- physics_2d_mouseover.erase(to_erase.front()->get());
- to_erase.pop_front();
- }
-
- // Per-shape.
- List<Pair<ObjectID, int>> shapes_to_erase;
- List<Pair<ObjectID, int>> shapes_to_mouse_exit;
-
- for (KeyValue<Pair<ObjectID, int>, uint64_t> &E : physics_2d_shape_mouseover) {
- if (!p_clean_all_frames && E.value == p_frame_reference) {
- continue;
- }
-
- Object *o = ObjectDB::get_instance(E.key.first);
- if (o) {
- CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
- if (co && co->is_inside_tree()) {
- if (p_clean_all_frames && p_paused_only && co->can_process()) {
- continue;
- }
- shapes_to_mouse_exit.push_back(E.key);
- }
- }
- shapes_to_erase.push_back(E.key);
- }
-
- while (shapes_to_erase.size()) {
- physics_2d_shape_mouseover.erase(shapes_to_erase.front()->get());
- shapes_to_erase.pop_front();
- }
-
- while (to_mouse_exit.size()) {
- Object *o = ObjectDB::get_instance(to_mouse_exit.front()->get());
- CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
- co->_mouse_exit();
- to_mouse_exit.pop_front();
- }
-
- while (shapes_to_mouse_exit.size()) {
- Pair<ObjectID, int> e = shapes_to_mouse_exit.front()->get();
- Object *o = ObjectDB::get_instance(e.first);
- CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
- co->_mouse_shape_exit(e.second);
- shapes_to_mouse_exit.pop_front();
- }
-}
-
void Viewport::_gui_grab_click_focus(Control *p_control) {
gui.mouse_click_grabber = p_control;
callable_mp(this, &Viewport::_post_gui_grab_click_focus).call_deferred();
@@ -4065,6 +3921,150 @@ bool Viewport::get_canvas_cull_mask_bit(uint32_t p_layer) const {
return (canvas_cull_mask & (1 << p_layer));
}
+void Viewport::_update_audio_listener_2d() {
+ if (AudioServer::get_singleton()) {
+ AudioServer::get_singleton()->notify_listener_changed();
+ }
+}
+
+void Viewport::_audio_listener_2d_set(AudioListener2D *p_audio_listener) {
+ if (audio_listener_2d == p_audio_listener) {
+ return;
+ } else if (audio_listener_2d) {
+ audio_listener_2d->clear_current();
+ }
+ audio_listener_2d = p_audio_listener;
+}
+
+void Viewport::_audio_listener_2d_remove(AudioListener2D *p_audio_listener) {
+ if (audio_listener_2d == p_audio_listener) {
+ audio_listener_2d = nullptr;
+ }
+}
+
+void Viewport::_camera_2d_set(Camera2D *p_camera_2d) {
+ camera_2d = p_camera_2d;
+}
+
+void Viewport::_cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paused_only, uint64_t p_frame_reference) {
+ List<ObjectID> to_erase;
+ List<ObjectID> to_mouse_exit;
+
+ for (const KeyValue<ObjectID, uint64_t> &E : physics_2d_mouseover) {
+ if (!p_clean_all_frames && E.value == p_frame_reference) {
+ continue;
+ }
+
+ Object *o = ObjectDB::get_instance(E.key);
+ if (o) {
+ CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
+ if (co && co->is_inside_tree()) {
+ if (p_clean_all_frames && p_paused_only && co->can_process()) {
+ continue;
+ }
+ to_mouse_exit.push_back(E.key);
+ }
+ }
+ to_erase.push_back(E.key);
+ }
+
+ while (to_erase.size()) {
+ physics_2d_mouseover.erase(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+
+ // Per-shape.
+ List<Pair<ObjectID, int>> shapes_to_erase;
+ List<Pair<ObjectID, int>> shapes_to_mouse_exit;
+
+ for (KeyValue<Pair<ObjectID, int>, uint64_t> &E : physics_2d_shape_mouseover) {
+ if (!p_clean_all_frames && E.value == p_frame_reference) {
+ continue;
+ }
+
+ Object *o = ObjectDB::get_instance(E.key.first);
+ if (o) {
+ CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
+ if (co && co->is_inside_tree()) {
+ if (p_clean_all_frames && p_paused_only && co->can_process()) {
+ continue;
+ }
+ shapes_to_mouse_exit.push_back(E.key);
+ }
+ }
+ shapes_to_erase.push_back(E.key);
+ }
+
+ while (shapes_to_erase.size()) {
+ physics_2d_shape_mouseover.erase(shapes_to_erase.front()->get());
+ shapes_to_erase.pop_front();
+ }
+
+ while (to_mouse_exit.size()) {
+ Object *o = ObjectDB::get_instance(to_mouse_exit.front()->get());
+ CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
+ co->_mouse_exit();
+ to_mouse_exit.pop_front();
+ }
+
+ while (shapes_to_mouse_exit.size()) {
+ Pair<ObjectID, int> e = shapes_to_mouse_exit.front()->get();
+ Object *o = ObjectDB::get_instance(e.first);
+ CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o);
+ co->_mouse_shape_exit(e.second);
+ shapes_to_mouse_exit.pop_front();
+ }
+}
+
+AudioListener2D *Viewport::get_audio_listener_2d() const {
+ ERR_READ_THREAD_GUARD_V(nullptr);
+ return audio_listener_2d;
+}
+
+void Viewport::set_as_audio_listener_2d(bool p_enable) {
+ ERR_MAIN_THREAD_GUARD;
+ if (p_enable == is_audio_listener_2d_enabled) {
+ return;
+ }
+
+ is_audio_listener_2d_enabled = p_enable;
+ _update_audio_listener_2d();
+}
+
+bool Viewport::is_audio_listener_2d() const {
+ ERR_READ_THREAD_GUARD_V(false);
+ return is_audio_listener_2d_enabled;
+}
+
+Camera2D *Viewport::get_camera_2d() const {
+ ERR_READ_THREAD_GUARD_V(nullptr);
+ return camera_2d;
+}
+
+void Viewport::assign_next_enabled_camera_2d(const StringName &p_camera_group) {
+ ERR_MAIN_THREAD_GUARD;
+ List<Node *> camera_list;
+ get_tree()->get_nodes_in_group(p_camera_group, &camera_list);
+
+ Camera2D *new_camera = nullptr;
+ for (Node *E : camera_list) {
+ Camera2D *cam = Object::cast_to<Camera2D>(E);
+ if (!cam) {
+ continue; // Non-camera node (e.g. ParallaxBackground).
+ }
+
+ if (cam->is_enabled()) {
+ new_camera = cam;
+ break;
+ }
+ }
+
+ _camera_2d_set(new_camera);
+ if (!camera_2d) {
+ set_canvas_transform(Transform2D());
+ }
+}
+
#ifndef _3D_DISABLED
AudioListener3D *Viewport::get_audio_listener_3d() const {
ERR_READ_THREAD_GUARD_V(nullptr);
@@ -4640,10 +4640,6 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("push_unhandled_input", "event", "in_local_coords"), &Viewport::push_unhandled_input, DEFVAL(false));
#endif // DISABLE_DEPRECATED
- ClassDB::bind_method(D_METHOD("get_camera_2d"), &Viewport::get_camera_2d);
- ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d);
- ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d);
-
ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position);
ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Viewport::warp_mouse);
ClassDB::bind_method(D_METHOD("update_mouse_cursor_state"), &Viewport::update_mouse_cursor_state);
@@ -4712,6 +4708,10 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("_process_picking"), &Viewport::_process_picking);
+ ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d);
+ ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d);
+ ClassDB::bind_method(D_METHOD("get_camera_2d"), &Viewport::get_camera_2d);
+
#ifndef _3D_DISABLED
ClassDB::bind_method(D_METHOD("set_world_3d", "world_3d"), &Viewport::set_world_3d);
ClassDB::bind_method(D_METHOD("get_world_3d"), &Viewport::get_world_3d);
@@ -4786,7 +4786,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_2d"), "set_as_audio_listener_2d", "is_audio_listener_2d");
#ifndef _3D_DISABLED
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_3d"), "set_as_audio_listener_3d", "is_audio_listener_3d");
-#endif
+#endif // _3D_DISABLED
ADD_GROUP("Physics", "physics_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking"), "set_physics_object_picking", "get_physics_object_picking");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking_sort"), "set_physics_object_picking_sort", "get_physics_object_picking_sort");
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 2904e3e156..29ccdc5426 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -218,17 +218,12 @@ private:
Viewport *parent = nullptr;
Viewport *gui_parent = nullptr; // Whose gui.tooltip_popup it is.
- AudioListener2D *audio_listener_2d = nullptr;
- Camera2D *camera_2d = nullptr;
HashSet<CanvasLayer *> canvas_layers;
RID viewport;
RID current_canvas;
RID subwindow_canvas;
- bool is_audio_listener_2d_enabled = false;
- RID internal_audio_listener_2d;
-
bool override_canvas_transform = false;
Transform2D canvas_transform_override;
@@ -267,13 +262,6 @@ private:
bool handle_input_locally = true;
bool local_input_handled = false;
- // Collider to frame
- HashMap<ObjectID, uint64_t> physics_2d_mouseover;
- // Collider & shape to frame
- HashMap<Pair<ObjectID, int>, uint64_t, PairHash<ObjectID, int>> physics_2d_shape_mouseover;
- // Cleans up colliders corresponding to old frames or all of them.
- void _cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paused_only, uint64_t p_frame_reference = 0);
-
Ref<World2D> world_2d;
StringName input_group;
@@ -447,13 +435,6 @@ private:
bool _gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check);
- friend class AudioListener2D;
- void _audio_listener_2d_set(AudioListener2D *p_listener);
- void _audio_listener_2d_remove(AudioListener2D *p_listener);
-
- friend class Camera2D;
- void _camera_2d_set(Camera2D *p_camera_2d);
-
friend class CanvasLayer;
void _canvas_layer_add(CanvasLayer *p_canvas_layer);
void _canvas_layer_remove(CanvasLayer *p_canvas_layer);
@@ -483,6 +464,7 @@ private:
uint64_t event_count = 0;
void _process_dirty_canvas_parent_orders();
+ void _propagate_world_2d_changed(Node *p_node);
protected:
void _set_size(const Size2i &p_size, const Size2i &p_size_2d_override, bool p_allocated);
@@ -494,6 +476,7 @@ protected:
void _notification(int p_what);
void _process_picking();
static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
public:
void canvas_parent_mark_dirty(Node *p_node);
@@ -501,11 +484,6 @@ public:
uint64_t get_processed_events_count() const { return event_count; }
- AudioListener2D *get_audio_listener_2d() const;
- Camera2D *get_camera_2d() const;
- void set_as_audio_listener_2d(bool p_enable);
- bool is_audio_listener_2d() const;
-
void update_canvas_items();
Rect2 get_visible_rect() const;
@@ -528,7 +506,6 @@ public:
Transform2D get_global_canvas_transform() const;
virtual Transform2D get_final_transform() const;
- void assign_next_enabled_camera_2d(const StringName &p_camera_group);
void gui_set_root_order_dirty();
@@ -689,16 +666,43 @@ public:
virtual bool is_attached_in_viewport() const { return false; };
virtual bool is_sub_viewport() const { return false; };
+private:
+ // 2D audio, camera, and physics. (don't put World2D here because World2D is needed for Control nodes).
+ friend class AudioListener2D; // Needs _audio_listener_2d_set and _audio_listener_2d_remove
+ AudioListener2D *audio_listener_2d = nullptr;
+ void _audio_listener_2d_set(AudioListener2D *p_audio_listener);
+ void _audio_listener_2d_remove(AudioListener2D *p_audio_listener);
+ bool is_audio_listener_2d_enabled = false;
+ RID internal_audio_listener_2d;
+
+ friend class Camera2D; // Needs _camera_2d_set
+ Camera2D *camera_2d = nullptr;
+ void _camera_2d_set(Camera2D *p_camera_2d);
+
+ // Collider to frame
+ HashMap<ObjectID, uint64_t> physics_2d_mouseover;
+ // Collider & shape to frame
+ HashMap<Pair<ObjectID, int>, uint64_t, PairHash<ObjectID, int>> physics_2d_shape_mouseover;
+ // Cleans up colliders corresponding to old frames or all of them.
+ void _cleanup_mouseover_colliders(bool p_clean_all_frames, bool p_paused_only, uint64_t p_frame_reference = 0);
+
+public:
+ AudioListener2D *get_audio_listener_2d() const;
+ void set_as_audio_listener_2d(bool p_enable);
+ bool is_audio_listener_2d() const;
+
+ Camera2D *get_camera_2d() const;
+ void assign_next_enabled_camera_2d(const StringName &p_camera_group);
+
#ifndef _3D_DISABLED
+private:
+ // 3D audio, camera, physics, and world.
bool use_xr = false;
friend class AudioListener3D;
AudioListener3D *audio_listener_3d = nullptr;
HashSet<AudioListener3D *> audio_listener_3d_set;
bool is_audio_listener_3d_enabled = false;
RID internal_audio_listener_3d;
- AudioListener3D *get_audio_listener_3d() const;
- void set_as_audio_listener_3d(bool p_enable);
- bool is_audio_listener_3d() const;
void _update_audio_listener_3d();
void _listener_transform_3d_changed_notify();
void _audio_listener_3d_set(AudioListener3D *p_listener);
@@ -729,13 +733,24 @@ public:
friend class Camera3D;
Camera3D *camera_3d = nullptr;
HashSet<Camera3D *> camera_3d_set;
- Camera3D *get_camera_3d() const;
void _camera_3d_transform_changed_notify();
void _camera_3d_set(Camera3D *p_camera);
bool _camera_3d_add(Camera3D *p_camera); //true if first
void _camera_3d_remove(Camera3D *p_camera);
void _camera_3d_make_next_current(Camera3D *p_exclude);
+ Ref<World3D> world_3d;
+ Ref<World3D> own_world_3d;
+ void _own_world_3d_changed();
+ void _propagate_enter_world_3d(Node *p_node);
+ void _propagate_exit_world_3d(Node *p_node);
+
+public:
+ AudioListener3D *get_audio_listener_3d() const;
+ void set_as_audio_listener_3d(bool p_enable);
+ bool is_audio_listener_3d() const;
+
+ Camera3D *get_camera_3d() const;
void enable_camera_3d_override(bool p_enable);
bool is_camera_3d_override_enabled() const;
@@ -748,24 +763,16 @@ public:
void set_disable_3d(bool p_disable);
bool is_3d_disabled() const;
- Ref<World3D> world_3d;
- Ref<World3D> own_world_3d;
void set_world_3d(const Ref<World3D> &p_world_3d);
Ref<World3D> get_world_3d() const;
Ref<World3D> find_world_3d() const;
- void _own_world_3d_changed();
void set_use_own_world_3d(bool p_use_own_world_3d);
bool is_using_own_world_3d() const;
- void _propagate_enter_world_3d(Node *p_node);
- void _propagate_exit_world_3d(Node *p_node);
void set_use_xr(bool p_use_xr);
bool is_using_xr();
#endif // _3D_DISABLED
- void _propagate_world_2d_changed(Node *p_node);
-
- void _validate_property(PropertyInfo &p_property) const;
Viewport();
~Viewport();
};
diff --git a/scene/property_utils.cpp b/scene/property_utils.cpp
index 090c81aefe..be58f1c1e1 100644
--- a/scene/property_utils.cpp
+++ b/scene/property_utils.cpp
@@ -73,15 +73,15 @@ Variant PropertyUtils::get_property_default_value(const Object *p_object, const
for (int i = 0; i < states_stack.size(); ++i) {
const SceneState::PackState &ia = states_stack[i];
bool found = false;
- Variant value_in_ancestor = ia.state->get_property_value(ia.node, p_property, found);
- const Vector<String> &deferred_properties = ia.state->get_node_deferred_nodepath_properties(ia.node);
+ bool node_deferred = false;
+ Variant value_in_ancestor = ia.state->get_property_value(ia.node, p_property, found, node_deferred);
if (found) {
if (r_is_valid) {
*r_is_valid = true;
}
// Replace properties stored as NodePaths with actual Nodes.
// Otherwise, the property value would be considered as overridden.
- if (deferred_properties.has(p_property)) {
+ if (node_deferred) {
if (value_in_ancestor.get_type() == Variant::ARRAY) {
Array paths = value_in_ancestor;
@@ -103,7 +103,7 @@ Variant PropertyUtils::get_property_default_value(const Object *p_object, const
}
// Save script for later
bool has_script = false;
- Variant script = ia.state->get_property_value(ia.node, SNAME("script"), has_script);
+ Variant script = ia.state->get_property_value(ia.node, SNAME("script"), has_script, node_deferred);
if (has_script) {
Ref<Script> scr = script;
if (scr.is_valid()) {
diff --git a/scene/resources/3d/primitive_meshes.cpp b/scene/resources/3d/primitive_meshes.cpp
index f99e4b15f6..c2b2a6d68b 100644
--- a/scene/resources/3d/primitive_meshes.cpp
+++ b/scene/resources/3d/primitive_meshes.cpp
@@ -3463,6 +3463,8 @@ Ref<Font> TextMesh::get_font() const {
}
Ref<Font> TextMesh::_get_font_or_default() const {
+ // Similar code taken from `FontVariation::_get_base_font_or_default`.
+
if (font_override.is_valid()) {
return font_override;
}
@@ -3472,7 +3474,12 @@ Ref<Font> TextMesh::_get_font_or_default() const {
ThemeDB::get_singleton()->get_native_type_dependencies(get_class_name(), &theme_types);
ThemeContext *global_context = ThemeDB::get_singleton()->get_default_theme_context();
- for (const Ref<Theme> &theme : global_context->get_themes()) {
+ List<Ref<Theme>> themes = global_context->get_themes();
+ if (Engine::get_singleton()->is_editor_hint()) {
+ themes.push_front(ThemeDB::get_singleton()->get_project_theme());
+ }
+
+ for (const Ref<Theme> &theme : themes) {
if (theme.is_null()) {
continue;
}
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 7bf2d857de..884fb7ba2b 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -2861,7 +2861,12 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
ThemeDB::get_singleton()->get_native_type_dependencies(get_class_name(), &theme_types);
ThemeContext *global_context = ThemeDB::get_singleton()->get_default_theme_context();
- for (const Ref<Theme> &theme : global_context->get_themes()) {
+ List<Ref<Theme>> themes = global_context->get_themes();
+ if (Engine::get_singleton()->is_editor_hint()) {
+ themes.push_front(ThemeDB::get_singleton()->get_project_theme());
+ }
+
+ for (const Ref<Theme> &theme : themes) {
if (theme.is_null()) {
continue;
}
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 2c92a3edb3..9fb91e9931 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -1310,29 +1310,31 @@ int SceneState::_find_base_scene_node_remap_key(int p_idx) const {
return -1;
}
-Variant SceneState::get_property_value(int p_node, const StringName &p_property, bool &found) const {
- found = false;
+Variant SceneState::get_property_value(int p_node, const StringName &p_property, bool &r_found, bool &r_node_deferred) const {
+ r_found = false;
+ r_node_deferred = false;
ERR_FAIL_COND_V(p_node < 0, Variant());
if (p_node < nodes.size()) {
- //find in built-in nodes
+ // Find in built-in nodes.
int pc = nodes[p_node].properties.size();
const StringName *namep = names.ptr();
const NodeData::Property *p = nodes[p_node].properties.ptr();
for (int i = 0; i < pc; i++) {
if (p_property == namep[p[i].name & FLAG_PROP_NAME_MASK]) {
- found = true;
+ r_found = true;
+ r_node_deferred = p[i].name & FLAG_PATH_PROPERTY_IS_NODE;
return variants[p[i].value];
}
}
}
- //property not found, try on instance
-
- if (base_scene_node_remap.has(p_node)) {
- return get_base_scene_state()->get_property_value(base_scene_node_remap[p_node], p_property, found);
+ // Property not found, try on instance.
+ HashMap<int, int>::ConstIterator I = base_scene_node_remap.find(p_node);
+ if (I) {
+ return get_base_scene_state()->get_property_value(I->value, p_property, r_found, r_node_deferred);
}
return Variant();
@@ -1722,13 +1724,25 @@ StringName SceneState::get_node_property_name(int p_idx, int p_prop) const {
Vector<String> SceneState::get_node_deferred_nodepath_properties(int p_idx) const {
Vector<String> ret;
- ERR_FAIL_INDEX_V(p_idx, nodes.size(), ret);
- for (int i = 0; i < nodes[p_idx].properties.size(); i++) {
- uint32_t idx = nodes[p_idx].properties[i].name;
- if (idx & FLAG_PATH_PROPERTY_IS_NODE) {
- ret.push_back(names[idx & FLAG_PROP_NAME_MASK]);
+ ERR_FAIL_COND_V(p_idx < 0, ret);
+
+ if (p_idx < nodes.size()) {
+ // Find in built-in nodes.
+ for (int i = 0; i < nodes[p_idx].properties.size(); i++) {
+ uint32_t idx = nodes[p_idx].properties[i].name;
+ if (idx & FLAG_PATH_PROPERTY_IS_NODE) {
+ ret.push_back(names[idx & FLAG_PROP_NAME_MASK]);
+ }
}
+ return ret;
}
+
+ // Property not found, try on instance.
+ HashMap<int, int>::ConstIterator I = base_scene_node_remap.find(p_idx);
+ if (I) {
+ return get_base_scene_state()->get_node_deferred_nodepath_properties(I->value);
+ }
+
return ret;
}
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 304e401602..c46a4dd5fe 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -139,7 +139,7 @@ public:
static Ref<Resource> get_remap_resource(const Ref<Resource> &p_resource, HashMap<Ref<Resource>, Ref<Resource>> &remap_cache, const Ref<Resource> &p_fallback, Node *p_for_scene);
int find_node_by_path(const NodePath &p_node) const;
- Variant get_property_value(int p_node, const StringName &p_property, bool &found) const;
+ Variant get_property_value(int p_node, const StringName &p_property, bool &r_found, bool &r_node_deferred) const;
bool is_node_in_group(int p_node, const StringName &p_group) const;
bool is_connection(int p_node, const StringName &p_signal, int p_to_node, const StringName &p_to_method) const;
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 59b9203960..145f0d427e 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -861,13 +861,13 @@ instead of `miniz.h` as an external dependency.
## thorvg
- Upstream: https://github.com/thorvg/thorvg
-- Version: 0.12.5 (9c8eeaab9629b5d241b1092a3398fe6351c259cd, 2024)
+- Version: 0.12.7 (cddae9966cbb48c431ea17c262d6f48393206fd7, 2024)
- License: MIT
Files extracted from upstream source:
See `thorvg/update-thorvg.sh` for extraction instructions. Set the version
-number and run the script and apply patches from the `patches` folder.
+number and run the script.
## ufbx
diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h
index c5745dab1b..1133b99e64 100644
--- a/thirdparty/thorvg/inc/config.h
+++ b/thirdparty/thorvg/inc/config.h
@@ -10,5 +10,5 @@
// For internal debugging:
//#define THORVG_LOG_ENABLED
-#define THORVG_VERSION_STRING "0.12.5"
+#define THORVG_VERSION_STRING "0.12.7"
#endif
diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h
index 6aee53f7e0..d4fa5c8712 100644
--- a/thirdparty/thorvg/inc/thorvg.h
+++ b/thirdparty/thorvg/inc/thorvg.h
@@ -1223,6 +1223,10 @@ public:
/**
* @brief Loads a picture data directly from a file.
*
+ * ThorVG efficiently caches the loaded data using the specified @p path as a key.
+ * This means that loading the same file again will not result in duplicate operations;
+ * instead, ThorVG will reuse the previously loaded picture data.
+ *
* @param[in] path A path to the picture file.
*
* @retval Result::Success When succeed.
@@ -1238,6 +1242,10 @@ public:
/**
* @brief Loads a picture data from a memory block of a given size.
*
+ * ThorVG efficiently caches the loaded data using the specified @p data address as a key
+ * when the @p copy has @c false. This means that loading the same data again will not result in duplicate operations
+ * for the sharable @p data. Instead, ThorVG will reuse the previously loaded picture data.
+ *
* @param[in] data A pointer to a memory location where the content of the picture file is stored.
* @param[in] size The size in bytes of the memory occupied by the @p data.
* @param[in] copy Decides whether the data should be copied into the engine local buffer.
@@ -1299,6 +1307,10 @@ public:
/**
* @brief Loads a raw data from a memory block with a given size.
*
+ * ThorVG efficiently caches the loaded data using the specified @p data address as a key
+ * when the @p copy has @c false. This means that loading the same data again will not result in duplicate operations
+ * for the sharable @p data. Instead, ThorVG will reuse the previously loaded picture data.
+ *
* @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.
@@ -1544,6 +1556,10 @@ public:
/**
* @brief Loads a scalable font data(ttf) from a file.
*
+ * ThorVG efficiently caches the loaded data using the specified @p path as a key.
+ * This means that loading the same file again will not result in duplicate operations;
+ * instead, ThorVG will reuse the previously loaded font data.
+ *
* @param[in] path The path to the font file.
*
* @retval Result::Success When succeed.
diff --git a/thirdparty/thorvg/patches/Fix_compiler_shadowing_warning.patch b/thirdparty/thorvg/patches/Fix_compiler_shadowing_warning.patch
deleted file mode 100644
index e0647628d3..0000000000
--- a/thirdparty/thorvg/patches/Fix_compiler_shadowing_warning.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-diff --git a/thirdparty/thorvg/src/common/tvgLock.h b/thirdparty/thorvg/src/common/tvgLock.h
-index e6d993a41e..5dd3d5a624 100644
---- a/thirdparty/thorvg/src/common/tvgLock.h
-+++ b/thirdparty/thorvg/src/common/tvgLock.h
-@@ -38,10 +38,10 @@ namespace tvg {
- {
- Key* key = nullptr;
-
-- ScopedLock(Key& key)
-+ ScopedLock(Key& k)
- {
-- key.mtx.lock();
-- this->key = &key;
-+ k.mtx.lock();
-+ key = &k;
- }
-
- ~ScopedLock()
-@@ -68,3 +68,4 @@ namespace tvg {
- #endif //THORVG_THREAD_SUPPORT
-
- #endif //_TVG_LOCK_H_
-+
diff --git a/thirdparty/thorvg/src/common/tvgArray.h b/thirdparty/thorvg/src/common/tvgArray.h
index acb3a41b97..d95df40460 100644
--- a/thirdparty/thorvg/src/common/tvgArray.h
+++ b/thirdparty/thorvg/src/common/tvgArray.h
@@ -90,6 +90,16 @@ struct Array
return data[idx];
}
+ const T* begin() const
+ {
+ return data;
+ }
+
+ T* begin()
+ {
+ return data;
+ }
+
T* end()
{
return data + count;
diff --git a/thirdparty/thorvg/src/common/tvgBezier.cpp b/thirdparty/thorvg/src/common/tvgBezier.cpp
index 5fb501721e..8c19afa32a 100644
--- a/thirdparty/thorvg/src/common/tvgBezier.cpp
+++ b/thirdparty/thorvg/src/common/tvgBezier.cpp
@@ -29,7 +29,7 @@
/* Internal Class Implementation */
/************************************************************************/
-static float _lineLength(const Point& pt1, const Point& pt2)
+static float _lineLengthApprox(const Point& pt1, const Point& pt2)
{
/* 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
@@ -41,6 +41,59 @@ static float _lineLength(const Point& pt1, const Point& pt2)
}
+static float _lineLength(const Point& pt1, const Point& pt2)
+{
+ Point diff = {pt2.x - pt1.x, pt2.y - pt1.y};
+ return sqrtf(diff.x * diff.x + diff.y * diff.y);
+}
+
+
+template<typename LengthFunc>
+float _bezLength(const Bezier& cur, LengthFunc lineLengthFunc)
+{
+ Bezier left, right;
+ auto len = lineLengthFunc(cur.start, cur.ctrl1) + lineLengthFunc(cur.ctrl1, cur.ctrl2) + lineLengthFunc(cur.ctrl2, cur.end);
+ auto chord = lineLengthFunc(cur.start, cur.end);
+
+ if (fabsf(len - chord) > BEZIER_EPSILON) {
+ tvg::bezSplit(cur, left, right);
+ return _bezLength(left, lineLengthFunc) + _bezLength(right, lineLengthFunc);
+ }
+ return len;
+}
+
+
+template<typename LengthFunc>
+float _bezAt(const Bezier& bz, float at, float length, LengthFunc lineLengthFunc)
+{
+ auto biggest = 1.0f;
+ auto smallest = 0.0f;
+ auto t = 0.5f;
+
+ //just in case to prevent an infinite loop
+ if (at <= 0) return 0.0f;
+ if (at >= length) return 1.0f;
+
+ while (true) {
+ auto right = bz;
+ Bezier left;
+ bezSplitLeft(right, t, left);
+ length = _bezLength(left, lineLengthFunc);
+ if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < BEZIER_EPSILON) {
+ break;
+ }
+ if (length < at) {
+ smallest = t;
+ t = (t + biggest) * 0.5f;
+ } else {
+ biggest = t;
+ t = (smallest + t) * 0.5f;
+ }
+ }
+ return t;
+}
+
+
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
@@ -48,7 +101,7 @@ static float _lineLength(const Point& pt1, const Point& pt2)
namespace tvg
{
-void bezSplit(const Bezier&cur, Bezier& left, Bezier& right)
+void bezSplit(const Bezier& cur, Bezier& left, Bezier& right)
{
auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f;
left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f;
@@ -72,15 +125,13 @@ void bezSplit(const Bezier&cur, Bezier& left, Bezier& right)
float bezLength(const Bezier& cur)
{
- Bezier left, right;
- auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end);
- auto chord = _lineLength(cur.start, cur.end);
+ return _bezLength(cur, _lineLength);
+}
- if (fabsf(len - chord) > BEZIER_EPSILON) {
- bezSplit(cur, left, right);
- return bezLength(left) + bezLength(right);
- }
- return len;
+
+float bezLengthApprox(const Bezier& cur)
+{
+ return _bezLength(cur, _lineLengthApprox);
}
@@ -110,31 +161,13 @@ void bezSplitLeft(Bezier& cur, float at, Bezier& left)
float bezAt(const Bezier& bz, float at, float length)
{
- auto biggest = 1.0f;
- auto smallest = 0.0f;
- auto t = 0.5f;
+ return _bezAt(bz, at, length, _lineLength);
+}
- //just in case to prevent an infinite loop
- if (at <= 0) return 0.0f;
- if (at >= length) return 1.0f;
- while (true) {
- auto right = bz;
- Bezier left;
- bezSplitLeft(right, t, left);
- length = bezLength(left);
- if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < BEZIER_EPSILON) {
- break;
- }
- if (length < at) {
- smallest = t;
- t = (t + biggest) * 0.5f;
- } else {
- biggest = t;
- t = (smallest + t) * 0.5f;
- }
- }
- return t;
+float bezAtApprox(const Bezier& bz, float at, float length)
+{
+ return _bezAt(bz, at, length, _lineLengthApprox);
}
diff --git a/thirdparty/thorvg/src/common/tvgBezier.h b/thirdparty/thorvg/src/common/tvgBezier.h
index cb2766c505..80a199258a 100644
--- a/thirdparty/thorvg/src/common/tvgBezier.h
+++ b/thirdparty/thorvg/src/common/tvgBezier.h
@@ -44,6 +44,8 @@ void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right);
Point bezPointAt(const Bezier& bz, float t);
float bezAngleAt(const Bezier& bz, float t);
+float bezLengthApprox(const Bezier& cur);
+float bezAtApprox(const Bezier& bz, float at, float length);
}
#endif //_TVG_BEZIER_H_
diff --git a/thirdparty/thorvg/src/common/tvgLock.h b/thirdparty/thorvg/src/common/tvgLock.h
index 8bf1534605..5dd3d5a624 100644
--- a/thirdparty/thorvg/src/common/tvgLock.h
+++ b/thirdparty/thorvg/src/common/tvgLock.h
@@ -68,3 +68,4 @@ namespace tvg {
#endif //THORVG_THREAD_SUPPORT
#endif //_TVG_LOCK_H_
+
diff --git a/thirdparty/thorvg/src/common/tvgMath.h b/thirdparty/thorvg/src/common/tvgMath.h
index 50c3458efc..7f6708262b 100644
--- a/thirdparty/thorvg/src/common/tvgMath.h
+++ b/thirdparty/thorvg/src/common/tvgMath.h
@@ -31,6 +31,7 @@
#define MATH_PI 3.14159265358979323846f
#define MATH_PI2 1.57079632679489661923f
+#define PATH_KAPPA 0.552284f
#define mathMin(x, y) (((x) < (y)) ? (x) : (y))
#define mathMax(x, y) (((x) > (y)) ? (x) : (y))
diff --git a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp
index 9c57c665ca..35351f7130 100644
--- a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp
@@ -47,9 +47,6 @@ void PngLoader::run(unsigned tid)
surface.h = height;
surface.cs = ColorSpace::ABGR8888;
surface.channelSize = sizeof(uint32_t);
-
- if (state.info_png.color.colortype == LCT_RGBA) surface.premultiplied = false;
- else surface.premultiplied = true;
}
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
index ab795fd908..7a4f544539 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp
@@ -89,6 +89,7 @@ static char* _skipSpace(const char* str, const char* end)
static char* _copyId(const char* str)
{
if (!str) return nullptr;
+ if (strlen(str) == 0) return nullptr;
return strdup(str);
}
@@ -377,19 +378,25 @@ static void _parseDashArray(SvgLoaderData* loader, const char *str, SvgDash* das
static char* _idFromUrl(const char* url)
{
- url = _skipSpace(url, nullptr);
- if ((*url) == '(') {
- ++url;
- url = _skipSpace(url, nullptr);
- }
+ auto open = strchr(url, '(');
+ auto close = strchr(url, ')');
+ if (!open || !close || open >= close) return nullptr;
+
+ open = strchr(url, '#');
+ if (!open || open >= close) return nullptr;
+
+ ++open;
+ --close;
- if ((*url) == '\'') ++url;
- if ((*url) == '#') ++url;
+ //trim the rest of the spaces if any
+ while (open < close && *close == ' ') --close;
+
+ //quick verification
+ for (auto id = open; id < close; id++) {
+ if (*id == ' ' || *id == '\'') return nullptr;
+ }
- int i = 0;
- while (url[i] > ' ' && url[i] != ')' && url[i] != '\'') ++i;
-
- return strDuplicate(url, i);
+ return strDuplicate(open, (close - open + 1));
}
@@ -3494,7 +3501,7 @@ void SvgLoader::clear(bool all)
free(loaderData.svgParse);
loaderData.svgParse = nullptr;
- for (auto gradient = loaderData.gradients.data; gradient < loaderData.gradients.end(); ++gradient) {
+ for (auto gradient = loaderData.gradients.begin(); gradient < loaderData.gradients.end(); ++gradient) {
(*gradient)->clear();
free(*gradient);
}
@@ -3506,7 +3513,7 @@ void SvgLoader::clear(bool all)
if (!all) return;
- for (auto p = loaderData.images.data; p < loaderData.images.end(); ++p) {
+ for (auto p = loaderData.images.begin(); p < loaderData.images.end(); ++p) {
free(*p);
}
loaderData.images.reset();
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
index 674c30f5bd..b9084cd050 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp
@@ -409,7 +409,7 @@ static bool _recognizeShape(SvgNode* node, Shape* shape)
}
case SvgNodeType::Polygon: {
if (node->node.polygon.pts.count < 2) break;
- auto pts = node->node.polygon.pts.data;
+ auto pts = node->node.polygon.pts.begin();
shape->moveTo(pts[0], pts[1]);
for (pts += 2; pts < node->node.polygon.pts.end(); pts += 2) {
shape->lineTo(pts[0], pts[1]);
@@ -419,7 +419,7 @@ static bool _recognizeShape(SvgNode* node, Shape* shape)
}
case SvgNodeType::Polyline: {
if (node->node.polyline.pts.count < 2) break;
- auto pts = node->node.polyline.pts.data;
+ auto pts = node->node.polyline.pts.begin();
shape->moveTo(pts[0], pts[1]);
for (pts += 2; pts < node->node.polyline.pts.end(); pts += 2) {
shape->lineTo(pts[0], pts[1]);
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp
index 8956cd9f24..60763068d4 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp
@@ -201,7 +201,13 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr
fill->radial.fy = cy + r * (fy - cy) / dist;
fill->radial.dx = cx - fill->radial.fx;
fill->radial.dy = cy - fill->radial.fy;
- fill->radial.a = fill->radial.dr * fill->radial.dr - fill->radial.dx * fill->radial.dx - fill->radial.dy * fill->radial.dy;
+ // Prevent loss of precision on Apple Silicon when dr=dy and dx=0 due to FMA
+ // https://github.com/thorvg/thorvg/issues/2014
+ auto dr2 = fill->radial.dr * fill->radial.dr;
+ auto dx2 = fill->radial.dx * fill->radial.dx;
+ auto dy2 = fill->radial.dy * fill->radial.dy;
+
+ fill->radial.a = dr2 - dx2 - dy2;
}
if (fill->radial.a > 0) fill->radial.invA = 1.0f / fill->radial.a;
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
index 42e405195e..ad5a2b7371 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
@@ -50,12 +50,6 @@ 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()) {
@@ -293,13 +287,13 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, S
{
if (!outline) return false;
- auto pt = outline->pts.data;
-
if (outline->pts.empty() || outline->cntrs.empty()) {
renderRegion.reset();
return false;
}
+ auto pt = outline->pts.begin();
+
auto xMin = pt->x;
auto xMax = pt->x;
auto yMin = pt->y;
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
index c187af38d5..3387905761 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp
@@ -182,7 +182,7 @@ struct SwShapeTask : SwTask
shapeDelOutline(&shape, mpool, tid);
//Clip Path
- for (auto clip = clips.data; clip < clips.end(); ++clip) {
+ for (auto clip = clips.begin(); clip < clips.end(); ++clip) {
auto clipper = static_cast<SwTask*>(*clip);
//Clip shape rle
if (shape.rle && !clipper->clip(shape.rle)) goto err;
@@ -242,7 +242,7 @@ struct SwSceneTask : SwTask
rleMerge(sceneRle, clipper1->rle(), clipper2->rle());
//Unify the remained clippers
- for (auto rd = scene.data + 2; rd < scene.end(); ++rd) {
+ for (auto rd = scene.begin() + 2; rd < scene.end(); ++rd) {
auto clipper = static_cast<SwTask*>(*rd);
rleMerge(sceneRle, sceneRle, clipper->rle());
}
@@ -301,7 +301,7 @@ struct SwImageTask : SwTask
if (image.rle) {
//Clear current task memorypool here if the clippers would use the same memory pool
imageDelOutline(&image, mpool, tid);
- for (auto clip = clips.data; clip < clips.end(); ++clip) {
+ for (auto clip = clips.begin(); clip < clips.end(); ++clip) {
auto clipper = static_cast<SwTask*>(*clip);
if (!clipper->clip(image.rle)) goto err;
}
@@ -377,7 +377,7 @@ SwRenderer::~SwRenderer()
bool SwRenderer::clear()
{
- for (auto task = tasks.data; task < tasks.end(); ++task) {
+ for (auto task = tasks.begin(); task < tasks.end(); ++task) {
if ((*task)->disposed) {
delete(*task);
} else {
@@ -451,7 +451,7 @@ bool SwRenderer::preRender()
void SwRenderer::clearCompositors()
{
//Free Composite Caches
- for (auto comp = compositors.data; comp < compositors.end(); ++comp) {
+ for (auto comp = compositors.begin(); comp < compositors.end(); ++comp) {
free((*comp)->compositor->image.data);
delete((*comp)->compositor);
delete(*comp);
@@ -467,7 +467,7 @@ bool SwRenderer::postRender()
rasterUnpremultiply(surface);
}
- for (auto task = tasks.data; task < tasks.end(); ++task) {
+ for (auto task = tasks.begin(); task < tasks.end(); ++task) {
if ((*task)->disposed) delete(*task);
else (*task)->pushed = false;
}
@@ -624,7 +624,7 @@ Compositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs)
auto reqChannelSize = CHANNEL_SIZE(cs);
//Use cached data
- for (auto p = compositors.data; p < compositors.end(); ++p) {
+ for (auto p = compositors.begin(); p < compositors.end(); ++p) {
if ((*p)->compositor->valid && (*p)->compositor->image.channelSize == reqChannelSize) {
cmp = *p;
break;
@@ -723,7 +723,7 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform,
//TODO: Failed threading them. It would be better if it's possible.
//See: https://github.com/thorvg/thorvg/issues/1409
//Guarantee composition targets get ready.
- for (auto clip = clips.data; clip < clips.end(); ++clip) {
+ for (auto clip = clips.begin(); clip < clips.end(); ++clip) {
static_cast<SwTask*>(*clip)->done();
}
@@ -784,7 +784,7 @@ RenderData SwRenderer::prepare(const Array<RenderData>& scene, RenderData data,
//TODO: Failed threading them. It would be better if it's possible.
//See: https://github.com/thorvg/thorvg/issues/1409
//Guarantee composition targets get ready.
- for (auto task = scene.data; task < scene.end(); ++task) {
+ for (auto task = scene.begin(); task < scene.end(); ++task) {
static_cast<SwTask*>(*task)->done();
}
return prepareCommon(task, transform, clips, opacity, flags);
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp
index 33c94e1063..386cc594b4 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp
@@ -713,7 +713,7 @@ static void _decomposeOutline(RleWorker& rw)
auto outline = rw.outline;
auto first = 0; //index of first point in contour
- for (auto cntr = outline->cntrs.data; cntr < outline->cntrs.end(); ++cntr) {
+ for (auto cntr = outline->cntrs.begin(); cntr < outline->cntrs.end(); ++cntr) {
auto last = *cntr;
auto limit = outline->pts.data + last;
auto start = UPSCALE(outline->pts[first]);
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp
index d3b715eab8..03261a4b7f 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp
@@ -37,13 +37,8 @@ struct Line
static float _lineLength(const Point& pt1, const Point& pt2)
{
- /* 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. */
Point diff = {pt2.x - pt1.x, pt2.y - pt1.y};
- if (diff.x < 0) diff.x = -diff.x;
- if (diff.y < 0) diff.y = -diff.y;
- return (diff.x > diff.y) ? (diff.x + diff.y * 0.375f) : (diff.y + diff.x * 0.375f);
+ return sqrtf(diff.x * diff.x + diff.y * diff.y);
}
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp
index 8f44cf3616..9ec4bd78a5 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp
@@ -377,9 +377,6 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to)
//a zero-length lineto is a no-op; avoid creating a spurious corner
if (delta.zero()) return;
- //compute length of line
- auto angle = mathAtan(delta);
-
/* The lineLength is used to determine the intersection of strokes outlines.
The scale needs to be reverted since the stroke width has not been scaled.
An alternative option is to scale the width of the stroke properly by
@@ -387,6 +384,7 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to)
delta.x = static_cast<SwCoord>(delta.x / stroke.sx);
delta.y = static_cast<SwCoord>(delta.y / stroke.sy);
auto lineLength = mathLength(delta);
+ auto angle = mathAtan(delta);
delta = {static_cast<SwCoord>(stroke.width), 0};
mathRotate(delta, angle + SW_ANGLE_PI2);
@@ -835,7 +833,7 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline)
uint32_t first = 0;
uint32_t i = 0;
- for (auto cntr = outline.cntrs.data; cntr < outline.cntrs.end(); ++cntr, ++i) {
+ for (auto cntr = outline.cntrs.begin(); cntr < outline.cntrs.end(); ++cntr, ++i) {
auto last = *cntr; //index of last point in contour
auto limit = outline.pts.data + last;
diff --git a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp
index 995eca7f41..809c4e98e4 100644
--- a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp
@@ -20,33 +20,13 @@
* SOFTWARE.
*/
-#include "tvgCommon.h"
#include "tvgFrameModule.h"
-#include "tvgPaint.h"
-#include "tvgPicture.h"
+#include "tvgAnimation.h"
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
-struct Animation::Impl
-{
- Picture* picture = nullptr;
-
- Impl()
- {
- picture = Picture::gen().release();
- PP(picture)->ref();
- }
-
- ~Impl()
- {
- if (PP(picture)->unref() == 0) {
- delete(picture);
- }
- }
-};
-
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
diff --git a/thirdparty/thorvg/src/renderer/tvgAnimation.h b/thirdparty/thorvg/src/renderer/tvgAnimation.h
new file mode 100644
index 0000000000..14212eb67a
--- /dev/null
+++ b/thirdparty/thorvg/src/renderer/tvgAnimation.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 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_ANIMATION_H_
+#define _TVG_ANIMATION_H_
+
+#include "tvgCommon.h"
+#include "tvgPaint.h"
+#include "tvgPicture.h"
+
+struct Animation::Impl
+{
+ Picture* picture = nullptr;
+
+ Impl()
+ {
+ picture = Picture::gen().release();
+ PP(picture)->ref();
+ }
+
+ ~Impl()
+ {
+ if (PP(picture)->unref() == 0) {
+ delete(picture);
+ }
+ }
+};
+
+#endif //_TVG_ANIMATION_H_
diff --git a/thirdparty/thorvg/src/renderer/tvgLoadModule.h b/thirdparty/thorvg/src/renderer/tvgLoadModule.h
index 0dc57253ed..c750683771 100644
--- a/thirdparty/thorvg/src/renderer/tvgLoadModule.h
+++ b/thirdparty/thorvg/src/renderer/tvgLoadModule.h
@@ -32,17 +32,20 @@ struct LoadModule
INLIST_ITEM(LoadModule);
//Use either hashkey(data) or hashpath(path)
- uint64_t hashkey;
- char* hashpath = nullptr;
+ union {
+ uintptr_t hashkey;
+ char* hashpath = nullptr;
+ };
FileType type; //current loader file type
uint16_t sharing = 0; //reference count
bool readied = false; //read done already.
+ bool pathcache = false; //cached by path
LoadModule(FileType type) : type(type) {}
virtual ~LoadModule()
{
- free(hashpath);
+ if (pathcache) free(hashpath);
}
virtual bool open(const string& path) { return false; }
@@ -57,6 +60,12 @@ struct LoadModule
return true;
}
+ bool cached()
+ {
+ if (hashkey) return true;
+ return false;
+ }
+
virtual bool close()
{
if (sharing == 0) return true;
diff --git a/thirdparty/thorvg/src/renderer/tvgLoader.cpp b/thirdparty/thorvg/src/renderer/tvgLoader.cpp
index fc93a0cbdc..2853b83895 100644
--- a/thirdparty/thorvg/src/renderer/tvgLoader.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgLoader.cpp
@@ -57,9 +57,9 @@
#include "tvgRawLoader.h"
-uint64_t HASH_KEY(const char* data, uint64_t size)
+uintptr_t HASH_KEY(const char* data)
{
- return (((uint64_t) data) << 32) | size;
+ return reinterpret_cast<uintptr_t>(data);
}
/************************************************************************/
@@ -219,7 +219,7 @@ static LoadModule* _findFromCache(const string& path)
auto loader = _activeLoaders.head;
while (loader) {
- if (loader->hashpath && !strcmp(loader->hashpath, path.c_str())) {
+ if (loader->pathcache && !strcmp(loader->hashpath, path.c_str())) {
++loader->sharing;
return loader;
}
@@ -237,7 +237,7 @@ static LoadModule* _findFromCache(const char* data, uint32_t size, const string&
ScopedLock lock(key);
auto loader = _activeLoaders.head;
- auto key = HASH_KEY(data, size);
+ auto key = HASH_KEY(data);
while (loader) {
if (loader->type == type && loader->hashkey == key) {
@@ -281,7 +281,7 @@ bool LoaderMgr::retrieve(LoadModule* loader)
{
if (!loader) return false;
if (loader->close()) {
- {
+ if (loader->cached()) {
ScopedLock lock(key);
_activeLoaders.remove(loader);
}
@@ -300,6 +300,7 @@ LoadModule* LoaderMgr::loader(const string& path, bool* invalid)
if (auto loader = _findByPath(path)) {
if (loader->open(path)) {
loader->hashpath = strdup(path.c_str());
+ loader->pathcache = true;
{
ScopedLock lock(key);
_activeLoaders.back(loader);
@@ -313,6 +314,7 @@ LoadModule* LoaderMgr::loader(const string& path, bool* invalid)
if (auto loader = _find(static_cast<FileType>(i))) {
if (loader->open(path)) {
loader->hashpath = strdup(path.c_str());
+ loader->pathcache = true;
{
ScopedLock lock(key);
_activeLoaders.back(loader);
@@ -338,7 +340,7 @@ LoadModule* LoaderMgr::loader(const char* key)
auto loader = _activeLoaders.head;
while (loader) {
- if (loader->hashpath && strstr(loader->hashpath, key)) {
+ if (loader->pathcache && strstr(loader->hashpath, key)) {
++loader->sharing;
return loader;
}
@@ -350,15 +352,21 @@ LoadModule* LoaderMgr::loader(const char* key)
LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy)
{
- if (auto loader = _findFromCache(data, size, mimeType)) return loader;
+ //Note that users could use the same data pointer with the different content.
+ //Thus caching is only valid for shareable.
+ if (!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)) {
- loader->hashkey = HASH_KEY(data, size);
- ScopedLock lock(key);
- _activeLoaders.back(loader);
+ if (!copy) {
+ loader->hashkey = HASH_KEY(data);
+ ScopedLock lock(key);
+ _activeLoaders.back(loader);
+ }
return loader;
} else {
TVGLOG("LOADER", "Given mimetype \"%s\" seems incorrect or not supported.", mimeType.c_str());
@@ -371,8 +379,8 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mim
auto loader = _find(static_cast<FileType>(i));
if (loader) {
if (loader->open(data, size, copy)) {
- loader->hashkey = HASH_KEY(data, size);
- {
+ if (!copy) {
+ loader->hashkey = HASH_KEY(data);
ScopedLock lock(key);
_activeLoaders.back(loader);
}
@@ -387,14 +395,18 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mim
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;
+ //Note that users could use the same data pointer with the different content.
+ //Thus caching is only valid for shareable.
+ if (!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)) {
- loader->hashkey = HASH_KEY((const char*)data, w * h);
- {
+ if (!copy) {
+ loader->hashkey = HASH_KEY((const char*)data);
ScopedLock lock(key);
_activeLoaders.back(loader);
}
diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h
index 210382efb4..a44d41ffdd 100644
--- a/thirdparty/thorvg/src/renderer/tvgRender.h
+++ b/thirdparty/thorvg/src/renderer/tvgRender.h
@@ -59,7 +59,7 @@ struct Surface
uint32_t w = 0, h = 0;
ColorSpace cs = ColorSpace::Unsupported;
uint8_t channelSize = 0;
- bool premultiplied = 0; //Alpha-premultiplied
+ bool premultiplied = false; //Alpha-premultiplied
Surface()
{
diff --git a/thirdparty/thorvg/src/renderer/tvgSaver.cpp b/thirdparty/thorvg/src/renderer/tvgSaver.cpp
index 11eb24d437..068b5ee6c3 100644
--- a/thirdparty/thorvg/src/renderer/tvgSaver.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgSaver.cpp
@@ -22,6 +22,7 @@
#include "tvgCommon.h"
#include "tvgSaveModule.h"
+#include "tvgPaint.h"
#ifdef THORVG_TVG_SAVER_SUPPORT
#include "tvgTvgSaver.h"
@@ -123,7 +124,7 @@ Result Saver::save(std::unique_ptr<Paint> paint, const string& path, bool compre
//Already on saving an other resource.
if (pImpl->saveModule) {
- delete(p);
+ if (P(p)->refCnt == 0) delete(p);
return Result::InsufficientCondition;
}
@@ -132,12 +133,12 @@ Result Saver::save(std::unique_ptr<Paint> paint, const string& path, bool compre
pImpl->saveModule = saveModule;
return Result::Success;
} else {
- delete(p);
+ if (P(p)->refCnt == 0) delete(p);
delete(saveModule);
return Result::Unknown;
}
}
- delete(p);
+ if (P(p)->refCnt == 0) delete(p);
return Result::NonSupport;
}
diff --git a/thirdparty/thorvg/src/renderer/tvgShape.cpp b/thirdparty/thorvg/src/renderer/tvgShape.cpp
index a3b92532a8..ab1f378b47 100644
--- a/thirdparty/thorvg/src/renderer/tvgShape.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgShape.cpp
@@ -26,7 +26,7 @@
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
-constexpr auto PATH_KAPPA = 0.552284f;
+
/************************************************************************/
/* External Class Implementation */
@@ -130,11 +130,11 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept
auto ryKappa = ry * PATH_KAPPA;
pImpl->grow(6, 13);
- pImpl->moveTo(cx, cy - ry);
- pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
+ pImpl->moveTo(cx + rx, cy);
pImpl->cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry);
pImpl->cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy);
pImpl->cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry);
+ pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy);
pImpl->close();
return Result::Success;
@@ -215,20 +215,20 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry)
pImpl->lineTo(x + w, y + h);
pImpl->lineTo(x, y + h);
pImpl->close();
- //circle
+ //rounded rectangle or circle
} else {
auto hrx = rx * PATH_KAPPA;
auto hry = ry * PATH_KAPPA;
pImpl->grow(10, 17);
- pImpl->moveTo(x + w, y + ry);
+ pImpl->moveTo(x + rx, y);
+ pImpl->lineTo(x + w - rx, y);
+ pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
pImpl->lineTo(x + w, y + h - ry);
pImpl->cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h);
pImpl->lineTo(x + rx, y + h);
pImpl->cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry);
pImpl->lineTo(x, y + ry);
pImpl->cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y);
- pImpl->lineTo(x + w - rx, y);
- pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry);
pImpl->close();
}
diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h
index 1a7a29a999..740da55847 100644
--- a/thirdparty/thorvg/src/renderer/tvgShape.h
+++ b/thirdparty/thorvg/src/renderer/tvgShape.h
@@ -106,7 +106,7 @@ struct Shape::Impl
{
//Path bounding size
if (rs.path.pts.count > 0 ) {
- auto pts = rs.path.pts.data;
+ auto pts = rs.path.pts.begin();
Point min = { pts->x, pts->y };
Point max = { pts->x, pts->y };
diff --git a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp
index 68a3dbe97a..fa7aadd7ac 100644
--- a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp
+++ b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp
@@ -123,14 +123,14 @@ struct TaskSchedulerImpl
~TaskSchedulerImpl()
{
- for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) {
+ for (auto tq = taskQueues.begin(); tq < taskQueues.end(); ++tq) {
(*tq)->complete();
}
- for (auto thread = threads.data; thread < threads.end(); ++thread) {
+ for (auto thread = threads.begin(); thread < threads.end(); ++thread) {
(*thread)->join();
delete(*thread);
}
- for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) {
+ for (auto tq = taskQueues.begin(); tq < taskQueues.end(); ++tq) {
delete(*tq);
}
}
diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh
index 2811a43339..3ef2c25878 100755
--- a/thirdparty/thorvg/update-thorvg.sh
+++ b/thirdparty/thorvg/update-thorvg.sh
@@ -1,6 +1,6 @@
#!/bin/bash -e
-VERSION=0.12.5
+VERSION=0.12.7
cd thirdparty/thorvg/ || true
rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/