summaryrefslogtreecommitdiffstats
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/camera_2d.cpp4
-rw-r--r--scene/2d/navigation_region_2d.cpp178
-rw-r--r--scene/2d/navigation_region_2d.h6
-rw-r--r--scene/animation/animation_mixer.cpp28
-rw-r--r--scene/animation/animation_mixer.h6
-rw-r--r--scene/animation/animation_player.cpp4
-rw-r--r--scene/gui/code_edit.cpp2
-rw-r--r--scene/gui/control.cpp12
-rw-r--r--scene/gui/dialogs.cpp18
-rw-r--r--scene/gui/dialogs.h2
-rw-r--r--scene/gui/graph_edit.cpp27
-rw-r--r--scene/gui/graph_edit.h2
-rw-r--r--scene/gui/rich_text_label.cpp28
-rw-r--r--scene/gui/subviewport_container.cpp2
-rw-r--r--scene/gui/text_edit.cpp34
-rw-r--r--scene/gui/texture_button.cpp31
-rw-r--r--scene/main/canvas_item.cpp27
-rw-r--r--scene/main/instance_placeholder.cpp131
-rw-r--r--scene/main/instance_placeholder.h4
-rw-r--r--scene/main/window.cpp35
-rw-r--r--scene/main/window.h2
-rw-r--r--scene/resources/2d/tile_set.cpp2
-rw-r--r--scene/resources/material.cpp23
-rw-r--r--scene/resources/packed_scene.cpp10
-rw-r--r--scene/resources/resource_format_text.cpp322
-rw-r--r--scene/resources/resource_format_text.h8
26 files changed, 501 insertions, 447 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 822f1b58fd..18ef2d8505 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -54,16 +54,18 @@ void Camera2D::_update_scroll() {
if (is_current()) {
ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id));
+ Size2 screen_size = _get_camera_screen_size();
+
Transform2D xform;
if (is_physics_interpolated_and_enabled()) {
xform = _interpolation_data.xform_prev.interpolate_with(_interpolation_data.xform_curr, Engine::get_singleton()->get_physics_interpolation_fraction());
+ camera_screen_center = xform.affine_inverse().xform(0.5 * screen_size);
} else {
xform = get_camera_transform();
}
viewport->set_canvas_transform(xform);
- Size2 screen_size = _get_camera_screen_size();
Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5) : Point2());
Point2 adj_screen_pos = camera_screen_center - (screen_size * 0.5);
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index ab44e57d05..bad9de5daa 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -162,8 +162,19 @@ void NavigationRegion2D::_notification(int p_what) {
set_physics_process_internal(true);
} break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+#ifdef DEBUG_ENABLED
+ if (debug_instance_rid.is_valid()) {
+ RS::get_singleton()->canvas_item_set_visible(debug_instance_rid, is_visible_in_tree());
+ }
+#endif // DEBUG_ENABLED
+ } break;
+
case NOTIFICATION_EXIT_TREE: {
_region_exit_navigation_map();
+#ifdef DEBUG_ENABLED
+ _free_debug();
+#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@@ -189,6 +200,9 @@ void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_
}
navigation_polygon = p_navigation_polygon;
+#ifdef DEBUG_ENABLED
+ debug_mesh_dirty = true;
+#endif // DEBUG_ENABLED
NavigationServer2D::get_singleton()->region_set_navigation_polygon(region, p_navigation_polygon);
if (navigation_polygon.is_valid()) {
@@ -420,12 +434,42 @@ void NavigationRegion2D::_region_update_transform() {
#ifdef DEBUG_ENABLED
void NavigationRegion2D::_update_debug_mesh() {
- Vector<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices();
- if (navigation_polygon_vertices.size() < 3) {
+ if (!is_inside_tree()) {
+ _free_debug();
return;
}
const NavigationServer2D *ns2d = NavigationServer2D::get_singleton();
+ RenderingServer *rs = RenderingServer::get_singleton();
+
+ if (!debug_instance_rid.is_valid()) {
+ debug_instance_rid = rs->canvas_item_create();
+ }
+ if (!debug_mesh_rid.is_valid()) {
+ debug_mesh_rid = rs->mesh_create();
+ }
+
+ const Transform2D region_gt = get_global_transform();
+
+ rs->canvas_item_set_parent(debug_instance_rid, get_world_2d()->get_canvas());
+ rs->canvas_item_set_transform(debug_instance_rid, region_gt);
+
+ if (!debug_mesh_dirty) {
+ return;
+ }
+
+ rs->mesh_clear(debug_mesh_rid);
+ debug_mesh_dirty = false;
+
+ const Vector<Vector2> &vertices = navigation_polygon->get_vertices();
+ if (vertices.size() < 3) {
+ return;
+ }
+
+ int polygon_count = navigation_polygon->get_polygon_count();
+ if (polygon_count == 0) {
+ return;
+ }
bool enabled_geometry_face_random_color = ns2d->get_debug_navigation_enable_geometry_face_random_color();
bool enabled_edge_lines = ns2d->get_debug_navigation_enable_edge_lines();
@@ -438,39 +482,109 @@ void NavigationRegion2D::_update_debug_mesh() {
debug_edge_color = ns2d->get_debug_navigation_geometry_edge_disabled_color();
}
+ int vertex_count = 0;
+ int line_count = 0;
+
+ for (int i = 0; i < polygon_count; i++) {
+ const Vector<int> &polygon = navigation_polygon->get_polygon(i);
+ int polygon_size = polygon.size();
+ if (polygon_size < 3) {
+ continue;
+ }
+ line_count += polygon_size * 2;
+ vertex_count += (polygon_size - 2) * 3;
+ }
+
+ Vector<Vector2> face_vertex_array;
+ face_vertex_array.resize(vertex_count);
+
+ Vector<Color> face_color_array;
+ if (enabled_geometry_face_random_color) {
+ face_color_array.resize(vertex_count);
+ }
+
+ Vector<Vector2> line_vertex_array;
+ if (enabled_edge_lines) {
+ line_vertex_array.resize(line_count);
+ }
+
RandomPCG rand;
+ Color polygon_color = debug_face_color;
- for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) {
- // An array of vertices for this polygon.
- Vector<int> polygon = navigation_polygon->get_polygon(i);
- Vector<Vector2> debug_polygon_vertices;
- debug_polygon_vertices.resize(polygon.size());
- for (int j = 0; j < polygon.size(); j++) {
- ERR_FAIL_INDEX(polygon[j], navigation_polygon_vertices.size());
- debug_polygon_vertices.write[j] = navigation_polygon_vertices[polygon[j]];
+ int face_vertex_index = 0;
+ int line_vertex_index = 0;
+
+ Vector2 *face_vertex_array_ptrw = face_vertex_array.ptrw();
+ Color *face_color_array_ptrw = face_color_array.ptrw();
+ Vector2 *line_vertex_array_ptrw = line_vertex_array.ptrw();
+
+ for (int polygon_index = 0; polygon_index < polygon_count; polygon_index++) {
+ const Vector<int> &polygon_indices = navigation_polygon->get_polygon(polygon_index);
+ int polygon_indices_size = polygon_indices.size();
+ if (polygon_indices_size < 3) {
+ continue;
}
- // Generate the polygon color, slightly randomly modified from the settings one.
- Color random_variation_color = debug_face_color;
if (enabled_geometry_face_random_color) {
- random_variation_color.set_hsv(
- debug_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1,
- debug_face_color.get_s(),
- debug_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2);
+ // Generate the polygon color, slightly randomly modified from the settings one.
+ polygon_color.set_hsv(debug_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, debug_face_color.get_s(), debug_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2);
+ polygon_color.a = debug_face_color.a;
}
- random_variation_color.a = debug_face_color.a;
- Vector<Color> debug_face_colors;
- debug_face_colors.push_back(random_variation_color);
- RS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), debug_polygon_vertices, debug_face_colors);
+ for (int polygon_indices_index = 0; polygon_indices_index < polygon_indices_size - 2; polygon_indices_index++) {
+ face_vertex_array_ptrw[face_vertex_index] = vertices[polygon_indices[0]];
+ face_vertex_array_ptrw[face_vertex_index + 1] = vertices[polygon_indices[polygon_indices_index + 1]];
+ face_vertex_array_ptrw[face_vertex_index + 2] = vertices[polygon_indices[polygon_indices_index + 2]];
+ if (enabled_geometry_face_random_color) {
+ face_color_array_ptrw[face_vertex_index] = polygon_color;
+ face_color_array_ptrw[face_vertex_index + 1] = polygon_color;
+ face_color_array_ptrw[face_vertex_index + 2] = polygon_color;
+ }
+ face_vertex_index += 3;
+ }
if (enabled_edge_lines) {
- Vector<Color> debug_edge_colors;
- debug_edge_colors.push_back(debug_edge_color);
- debug_polygon_vertices.push_back(debug_polygon_vertices[0]); // Add first again for closing polyline.
- RS::get_singleton()->canvas_item_add_polyline(get_canvas_item(), debug_polygon_vertices, debug_edge_colors);
+ for (int polygon_indices_index = 0; polygon_indices_index < polygon_indices_size; polygon_indices_index++) {
+ line_vertex_array_ptrw[line_vertex_index] = vertices[polygon_indices[polygon_indices_index]];
+ line_vertex_index += 1;
+ if (polygon_indices_index + 1 == polygon_indices_size) {
+ line_vertex_array_ptrw[line_vertex_index] = vertices[polygon_indices[0]];
+ line_vertex_index += 1;
+ } else {
+ line_vertex_array_ptrw[line_vertex_index] = vertices[polygon_indices[polygon_indices_index + 1]];
+ line_vertex_index += 1;
+ }
+ }
}
}
+
+ if (!enabled_geometry_face_random_color) {
+ face_color_array.resize(face_vertex_array.size());
+ face_color_array.fill(debug_face_color);
+ }
+
+ Array face_mesh_array;
+ face_mesh_array.resize(Mesh::ARRAY_MAX);
+ face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
+ face_mesh_array[Mesh::ARRAY_COLOR] = face_color_array;
+
+ rs->mesh_add_surface_from_arrays(debug_mesh_rid, RS::PRIMITIVE_TRIANGLES, face_mesh_array, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
+
+ if (enabled_edge_lines) {
+ Vector<Color> line_color_array;
+ line_color_array.resize(line_vertex_array.size());
+ line_color_array.fill(debug_edge_color);
+
+ Array line_mesh_array;
+ line_mesh_array.resize(Mesh::ARRAY_MAX);
+ line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array;
+ line_mesh_array[Mesh::ARRAY_COLOR] = line_color_array;
+
+ rs->mesh_add_surface_from_arrays(debug_mesh_rid, RS::PRIMITIVE_LINES, line_mesh_array, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES);
+ }
+
+ rs->canvas_item_add_mesh(debug_instance_rid, debug_mesh_rid, Transform2D());
+ rs->canvas_item_set_visible(debug_instance_rid, is_visible_in_tree());
}
#endif // DEBUG_ENABLED
@@ -512,3 +626,19 @@ void NavigationRegion2D::_update_debug_baking_rect() {
}
}
#endif // DEBUG_ENABLED
+
+#ifdef DEBUG_ENABLED
+void NavigationRegion2D::_free_debug() {
+ RenderingServer *rs = RenderingServer::get_singleton();
+ ERR_FAIL_NULL(rs);
+ if (debug_instance_rid.is_valid()) {
+ rs->canvas_item_clear(debug_instance_rid);
+ rs->free(debug_instance_rid);
+ debug_instance_rid = RID();
+ }
+ if (debug_mesh_rid.is_valid()) {
+ rs->free(debug_mesh_rid);
+ debug_mesh_rid = RID();
+ }
+}
+#endif // DEBUG_ENABLED
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 5a86dd607d..52101cb93e 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -52,6 +52,12 @@ class NavigationRegion2D : public Node2D {
#ifdef DEBUG_ENABLED
private:
+ RID debug_mesh_rid;
+ RID debug_instance_rid;
+
+ bool debug_mesh_dirty = true;
+
+ void _free_debug();
void _update_debug_mesh();
void _update_debug_edge_connections_mesh();
void _update_debug_baking_rect();
diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp
index d4c6ca3ea0..e600de6b8b 100644
--- a/scene/animation/animation_mixer.cpp
+++ b/scene/animation/animation_mixer.cpp
@@ -501,6 +501,7 @@ AnimationMixer::AnimationCallbackModeMethod AnimationMixer::get_callback_mode_me
void AnimationMixer::set_callback_mode_discrete(AnimationCallbackModeDiscrete p_mode) {
callback_mode_discrete = p_mode;
+ _clear_caches();
emit_signal(SNAME("mixer_updated"));
}
@@ -688,7 +689,7 @@ bool AnimationMixer::_update_caches() {
track_value->init_value = anim->track_get_key_value(i, 0);
track_value->init_value.zero();
- track_value->init_use_continuous = callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS;
+ track_value->is_init = false;
// Can't interpolate them, need to convert.
track_value->is_variant_interpolatable = Animation::is_variant_interpolatable(track_value->init_value);
@@ -698,7 +699,6 @@ bool AnimationMixer::_update_caches() {
int rt = reset_anim->find_track(path, track_src_type);
if (rt >= 0) {
if (track_src_type == Animation::TYPE_VALUE) {
- track_value->init_use_continuous = track_value->init_use_continuous || (reset_anim->value_track_get_update_mode(rt) != Animation::UPDATE_DISCRETE); // Take precedence Force Continuous.
if (reset_anim->track_get_key_count(rt) > 0) {
track_value->init_value = reset_anim->track_get_key_value(rt, 0);
}
@@ -1006,7 +1006,7 @@ void AnimationMixer::_blend_init() {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
t->value = Animation::cast_to_blendwise(t->init_value);
t->element_size = t->init_value.is_string() ? (real_t)(t->init_value.operator String()).length() : 0;
- t->use_continuous = t->init_use_continuous;
+ t->use_continuous = false;
t->use_discrete = false;
} break;
case Animation::TYPE_AUDIO: {
@@ -1462,12 +1462,12 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
t->value = Animation::blend_variant(t->value, value, blend);
}
} else {
- t->use_discrete = true;
if (seeked) {
int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT, true);
if (idx < 0) {
continue;
}
+ t->use_discrete = true;
Variant value = a->track_get_key_value(i, idx);
value = post_process_key_value(a, i, value, t->object_id);
Object *t_obj = ObjectDB::get_instance(t->object_id);
@@ -1478,6 +1478,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
List<int> indices;
a->track_get_key_indices_in_range(i, time, delta, &indices, looped_flag);
for (int &F : indices) {
+ t->use_discrete = true;
Variant value = a->track_get_key_value(i, F);
value = post_process_key_value(a, i, value, t->object_id);
Object *t_obj = ObjectDB::get_instance(t->object_id);
@@ -1682,7 +1683,8 @@ void AnimationMixer::_blend_apply() {
// Finally, set the tracks.
for (const KeyValue<Animation::TypeHash, TrackCache *> &K : track_cache) {
TrackCache *track = K.value;
- if (!deterministic && Math::is_zero_approx(track->total_weight)) {
+ bool is_zero_amount = Math::is_zero_approx(track->total_weight);
+ if (!deterministic && is_zero_amount) {
continue;
}
switch (track->type) {
@@ -1742,10 +1744,24 @@ void AnimationMixer::_blend_apply() {
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
- if (!t->is_variant_interpolatable || !t->use_continuous || (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT && t->use_discrete)) {
+ if (t->use_discrete && !t->use_continuous) {
+ t->is_init = true; // If only disctere value is applied, no more RESET.
+ }
+
+ if ((t->is_init && (is_zero_amount || !t->use_continuous)) ||
+ (callback_mode_discrete != ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS &&
+ !is_zero_amount &&
+ callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT &&
+ t->use_discrete)) {
break; // Don't overwrite the value set by UPDATE_DISCRETE.
}
+ if (callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {
+ t->is_init = false; // Always update in Force Continuous.
+ } else {
+ t->is_init = !t->use_continuous; // If there is no Continuous in non-Force Continuous type, it means RESET.
+ }
+
// Trim unused elements if init array/string is not blended.
if (t->value.is_array()) {
int actual_blended_size = (int)Math::round(Math::abs(t->element_size.operator real_t()));
diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h
index b7898cffc9..089a210193 100644
--- a/scene/animation/animation_mixer.h
+++ b/scene/animation/animation_mixer.h
@@ -126,7 +126,7 @@ protected:
/* ---- General settings for animation ---- */
AnimationCallbackModeProcess callback_mode_process = ANIMATION_CALLBACK_MODE_PROCESS_IDLE;
AnimationCallbackModeMethod callback_mode_method = ANIMATION_CALLBACK_MODE_METHOD_DEFERRED;
- AnimationCallbackModeDiscrete callback_mode_discrete = ANIMATION_CALLBACK_MODE_DISCRETE_DOMINANT;
+ AnimationCallbackModeDiscrete callback_mode_discrete = ANIMATION_CALLBACK_MODE_DISCRETE_RECESSIVE;
int audio_max_polyphony = 32;
NodePath root_node;
@@ -224,7 +224,7 @@ protected:
Vector<StringName> subpath;
// TODO: There are many boolean, can be packed into one integer.
- bool init_use_continuous = false;
+ bool is_init = false;
bool use_continuous = false;
bool use_discrete = false;
bool is_using_angle = false;
@@ -237,7 +237,7 @@ protected:
init_value(p_other.init_value),
value(p_other.value),
subpath(p_other.subpath),
- init_use_continuous(p_other.init_use_continuous),
+ is_init(p_other.is_init),
use_continuous(p_other.use_continuous),
use_discrete(p_other.use_discrete),
is_using_angle(p_other.is_using_angle),
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 435776843c..0c24d79ad7 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -447,10 +447,10 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo
} else {
if (p_from_end && c.current.pos == 0) {
// Animation reset but played backwards, set position to the end.
- c.current.pos = c.current.from->animation->get_length();
+ seek(c.current.from->animation->get_length(), true, true);
} else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) {
// Animation resumed but already ended, set position to the beginning.
- c.current.pos = 0;
+ seek(0, true, true);
} else if (playing) {
return;
}
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 8131fe7aaa..c843bb8c44 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -3050,7 +3050,7 @@ void CodeEdit::_update_delimiter_cache(int p_from_line, int p_to_line) {
}
int CodeEdit::_is_in_delimiter(int p_line, int p_column, DelimiterType p_type) const {
- if (delimiters.size() == 0) {
+ if (delimiters.size() == 0 || p_line >= delimiter_cache.size()) {
return -1;
}
ERR_FAIL_INDEX_V(p_line, get_line_count(), 0);
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 1c175f9f95..0d5c69b207 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -211,17 +211,17 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
const String pf = p_function;
Theme::DataType type = Theme::DATA_TYPE_MAX;
- if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color") {
+ if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color" || pf == "remove_theme_color_override") {
type = Theme::DATA_TYPE_COLOR;
- } else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant") {
+ } else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant" || pf == "remove_theme_constant_override") {
type = Theme::DATA_TYPE_CONSTANT;
- } else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font") {
+ } else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font" || pf == "remove_theme_font_override") {
type = Theme::DATA_TYPE_FONT;
- } else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size") {
+ } else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size" || pf == "remove_theme_font_size_override") {
type = Theme::DATA_TYPE_FONT_SIZE;
- } else if (pf == "add_theme_icon_override" || pf == "has_theme_icon" || pf == "has_theme_icon_override" || pf == "get_theme_icon") {
+ } else if (pf == "add_theme_icon_override" || pf == "has_theme_icon" || pf == "has_theme_icon_override" || pf == "get_theme_icon" || pf == "remove_theme_icon_override") {
type = Theme::DATA_TYPE_ICON;
- } else if (pf == "add_theme_style_override" || pf == "has_theme_style" || pf == "has_theme_style_override" || pf == "get_theme_style") {
+ } else if (pf == "add_theme_stylebox_override" || pf == "has_theme_stylebox" || pf == "has_theme_stylebox_override" || pf == "get_theme_stylebox" || pf == "remove_theme_stylebox_override") {
type = Theme::DATA_TYPE_STYLEBOX;
}
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 58961d370c..3d8be38fbd 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -47,7 +47,7 @@ void AcceptDialog::_input_from_window(const Ref<InputEvent> &p_event) {
}
void AcceptDialog::_parent_focused() {
- if (!is_exclusive() && get_flag(FLAG_POPUP)) {
+ if (popped_up && !is_exclusive() && get_flag(FLAG_POPUP)) {
_cancel_pressed();
}
}
@@ -71,6 +71,7 @@ void AcceptDialog::_notification(int p_what) {
parent_visible->connect(SceneStringName(focus_entered), callable_mp(this, &AcceptDialog::_parent_focused));
}
} else {
+ popped_up = false;
if (parent_visible) {
parent_visible->disconnect(SceneStringName(focus_entered), callable_mp(this, &AcceptDialog::_parent_focused));
parent_visible = nullptr;
@@ -78,6 +79,14 @@ void AcceptDialog::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
+ if (!is_in_edited_scene_root()) {
+ if (has_focus()) {
+ popped_up = true;
+ }
+ }
+ } break;
+
case NOTIFICATION_THEME_CHANGED: {
bg_panel->add_theme_style_override("panel", theme_cache.panel_style);
@@ -114,8 +123,14 @@ void AcceptDialog::_text_submitted(const String &p_text) {
_ok_pressed();
}
+void AcceptDialog::_post_popup() {
+ Window::_post_popup();
+ popped_up = true;
+}
+
void AcceptDialog::_ok_pressed() {
if (hide_on_ok) {
+ popped_up = false;
set_visible(false);
}
ok_pressed();
@@ -124,6 +139,7 @@ void AcceptDialog::_ok_pressed() {
}
void AcceptDialog::_cancel_pressed() {
+ popped_up = false;
Window *parent_window = parent_visible;
if (parent_visible) {
parent_visible->disconnect(SceneStringName(focus_entered), callable_mp(this, &AcceptDialog::_parent_focused));
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index 12b48c903a..404237bfd8 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -51,6 +51,7 @@ class AcceptDialog : public Window {
HBoxContainer *buttons_hbox = nullptr;
Button *ok_button = nullptr;
+ bool popped_up = false;
bool hide_on_ok = true;
bool close_on_escape = true;
@@ -72,6 +73,7 @@ class AcceptDialog : public Window {
protected:
virtual Size2 _get_contents_minimum_size() const override;
virtual void _input_from_window(const Ref<InputEvent> &p_event) override;
+ virtual void _post_popup() override;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index c9f3fc1dfe..6c2a61d255 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -1299,18 +1299,26 @@ List<Ref<GraphEdit::Connection>> GraphEdit::get_connections_intersecting_with_re
return intersecting_connections;
}
-void GraphEdit::_draw_minimap_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_from_color, const Color &p_to_color) {
- const Vector<Vector2> &points = get_connection_line(p_from, p_to);
+void GraphEdit::_draw_minimap_connection_line(const Vector2 &p_from_graph_position, const Vector2 &p_to_graph_position, const Color &p_from_color, const Color &p_to_color) {
+ Vector<Vector2> points = get_connection_line(p_from_graph_position, p_to_graph_position);
+ ERR_FAIL_COND_MSG(points.size() < 2, "\"_get_connection_line()\" returned an invalid line.");
+ // Convert to minimap points.
+ for (Vector2 &point : points) {
+ point = minimap->_convert_from_graph_position(point) + minimap->minimap_offset;
+ }
+
+ // Setup polyline colors.
LocalVector<Color> colors;
colors.reserve(points.size());
-
- float length_inv = 1.0 / (p_from).distance_to(p_to);
+ const Vector2 &from = points[0];
+ const Vector2 &to = points[points.size() - 1];
+ float length_inv = 1.0 / (from).distance_to(to);
for (const Vector2 &point : points) {
- float normalized_curve_position = (p_from).distance_to(point) * length_inv;
+ float normalized_curve_position = from.distance_to(point) * length_inv;
colors.push_back(p_from_color.lerp(p_to_color, normalized_curve_position));
}
- p_where->draw_polyline_colors(points, colors, 0.5, lines_antialiased);
+ minimap->draw_polyline_colors(points, colors, 0.5, lines_antialiased);
}
void GraphEdit::_update_connections() {
@@ -1565,8 +1573,8 @@ void GraphEdit::_minimap_draw() {
// Draw node connections.
for (const Ref<Connection> &c : connections) {
- Vector2 from_position = minimap->_convert_from_graph_position(c->_cache.from_pos * zoom - graph_offset) + minimap_offset;
- Vector2 to_position = minimap->_convert_from_graph_position(c->_cache.to_pos * zoom - graph_offset) + minimap_offset;
+ Vector2 from_graph_position = c->_cache.from_pos * zoom - graph_offset;
+ Vector2 to_graph_position = c->_cache.to_pos * zoom - graph_offset;
Color from_color = c->_cache.from_color;
Color to_color = c->_cache.to_color;
@@ -1574,7 +1582,8 @@ void GraphEdit::_minimap_draw() {
from_color = from_color.lerp(theme_cache.activity_color, c->activity);
to_color = to_color.lerp(theme_cache.activity_color, c->activity);
}
- _draw_minimap_connection_line(minimap, from_position, to_position, from_color, to_color);
+
+ _draw_minimap_connection_line(from_graph_position, to_graph_position, from_color, to_color);
}
// Draw the "camera" viewport.
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index eeda9ae200..20c98c462c 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -328,7 +328,7 @@ private:
void _top_connection_layer_input(const Ref<InputEvent> &p_ev);
float _get_shader_line_width();
- void _draw_minimap_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color);
+ void _draw_minimap_connection_line(const Vector2 &p_from_graph_position, const Vector2 &p_to_graph_position, const Color &p_from_color, const Color &p_to_color);
void _invalidate_connection_line_cache();
void _update_top_connection_layer();
void _update_connections();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 5122b0a155..f6942ca206 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1607,8 +1607,34 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
if (p_meta) {
int64_t glyph_idx = TS->shaped_text_hit_test_grapheme(rid, p_click.x - rect.position.x);
if (glyph_idx >= 0) {
+ float baseline_y = rect.position.y + TS->shaped_text_get_ascent(rid);
const Glyph *glyphs = TS->shaped_text_get_glyphs(rid);
- char_pos = glyphs[glyph_idx].start;
+ if (glyphs[glyph_idx].flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) {
+ // Emebedded object.
+ for (int i = 0; i < objects.size(); i++) {
+ if (TS->shaped_text_get_object_glyph(rid, objects[i]) == glyph_idx) {
+ Rect2 obj_rect = TS->shaped_text_get_object_rect(rid, objects[i]);
+ obj_rect.position.y += baseline_y;
+ if (p_click.y >= obj_rect.position.y && p_click.y <= obj_rect.position.y + obj_rect.size.y) {
+ char_pos = glyphs[glyph_idx].start;
+ }
+ break;
+ }
+ }
+ } else if (glyphs[glyph_idx].font_rid != RID()) {
+ // Normal glyph.
+ float fa = TS->font_get_ascent(glyphs[glyph_idx].font_rid, glyphs[glyph_idx].font_size);
+ float fd = TS->font_get_descent(glyphs[glyph_idx].font_rid, glyphs[glyph_idx].font_size);
+ if (p_click.y >= baseline_y - fa && p_click.y <= baseline_y + fd) {
+ char_pos = glyphs[glyph_idx].start;
+ }
+ } else if (!(glyphs[glyph_idx].flags & TextServer::GRAPHEME_IS_VIRTUAL)) {
+ // Hex code box.
+ Vector2 gl_size = TS->get_hex_code_box_size(glyphs[glyph_idx].font_size, glyphs[glyph_idx].index);
+ if (p_click.y >= baseline_y - gl_size.y * 0.9 && p_click.y <= baseline_y + gl_size.y * 0.2) {
+ char_pos = glyphs[glyph_idx].start;
+ }
+ }
}
} else {
char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x);
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index f6cfe6ab18..c715aceb0b 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -287,7 +287,7 @@ void SubViewportContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_stretch_shrink"), &SubViewportContainer::get_stretch_shrink);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch"), "set_stretch", "is_stretch_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink"), "set_stretch_shrink", "get_stretch_shrink");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink", PROPERTY_HINT_RANGE, "1,32,1,or_greater"), "set_stretch_shrink", "get_stretch_shrink");
GDVIRTUAL_BIND(_propagate_input_event, "event");
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 69b84da23d..1dd00fab4d 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1003,23 +1003,12 @@ void TextEdit::_notification(int p_what) {
}
}
- if (str.length() == 0) {
- // Draw line background if empty as we won't loop at all.
- if (caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index) && highlight_current_line) {
- if (rtl) {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), theme_cache.current_line_color);
- } else {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, row_height), theme_cache.current_line_color);
- }
- }
- } else {
- // If it has text, then draw current line marker in the margin, as line number etc will draw over it, draw the rest of line marker later.
- if (caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index) && highlight_current_line) {
- if (rtl) {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), theme_cache.current_line_color);
- } else {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, row_height), theme_cache.current_line_color);
- }
+ // Draw current line highlight.
+ if (highlight_current_line && caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index)) {
+ if (rtl) {
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), theme_cache.current_line_color);
+ } else {
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, row_height), theme_cache.current_line_color);
}
}
@@ -4248,8 +4237,11 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
}
Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_of_bounds) const {
- float rows = p_pos.y;
- rows -= theme_cache.style_normal->get_margin(SIDE_TOP);
+ float rows = p_pos.y - theme_cache.style_normal->get_margin(SIDE_TOP);
+ if (!editable) {
+ rows -= theme_cache.style_readonly->get_offset().y / 2;
+ rows += theme_cache.style_normal->get_offset().y / 2;
+ }
rows /= get_line_height();
rows += _get_v_scroll_offset();
int first_vis_line = get_first_visible_line();
@@ -4280,6 +4272,10 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_
int col = 0;
int colx = p_pos.x - (theme_cache.style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding);
colx += first_visible_col;
+ if (!editable) {
+ colx -= theme_cache.style_readonly->get_offset().x / 2;
+ colx += theme_cache.style_normal->get_offset().x / 2;
+ }
col = _get_char_pos_for_line(colx, row, wrap_index);
if (get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE && wrap_index < get_line_wrap_count(row)) {
// Move back one if we are at the end of the row.
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index df90257e03..c267ff93c6 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -178,13 +178,14 @@ void TextureButton::_notification(int p_what) {
texdraw = focused;
}
- if (texdraw.is_valid()) {
- size = texdraw->get_size();
- _texture_region = Rect2(Point2(), texdraw->get_size());
+ if (texdraw.is_valid() || click_mask.is_valid()) {
+ const Size2 texdraw_size = texdraw.is_valid() ? texdraw->get_size() : Size2(click_mask->get_size());
+
+ size = texdraw_size;
+ _texture_region = Rect2(Point2(), texdraw_size);
_tile = false;
switch (stretch_mode) {
case STRETCH_KEEP:
- size = texdraw->get_size();
break;
case STRETCH_SCALE:
size = get_size();
@@ -194,18 +195,17 @@ void TextureButton::_notification(int p_what) {
_tile = true;
break;
case STRETCH_KEEP_CENTERED:
- ofs = (get_size() - texdraw->get_size()) / 2;
- size = texdraw->get_size();
+ ofs = (get_size() - texdraw_size) / 2;
break;
case STRETCH_KEEP_ASPECT_CENTERED:
case STRETCH_KEEP_ASPECT: {
Size2 _size = get_size();
- float tex_width = texdraw->get_width() * _size.height / texdraw->get_height();
+ float tex_width = texdraw_size.width * _size.height / texdraw_size.height;
float tex_height = _size.height;
if (tex_width > _size.width) {
tex_width = _size.width;
- tex_height = texdraw->get_height() * tex_width / texdraw->get_width();
+ tex_height = texdraw_size.height * tex_width / texdraw_size.width;
}
if (stretch_mode == STRETCH_KEEP_ASPECT_CENTERED) {
@@ -217,10 +217,9 @@ void TextureButton::_notification(int p_what) {
} break;
case STRETCH_KEEP_ASPECT_COVERED: {
size = get_size();
- Size2 tex_size = texdraw->get_size();
- Size2 scale_size(size.width / tex_size.width, size.height / tex_size.height);
+ Size2 scale_size = size / texdraw_size;
float scale = scale_size.width > scale_size.height ? scale_size.width : scale_size.height;
- Size2 scaled_tex_size = tex_size * scale;
+ Size2 scaled_tex_size = texdraw_size * scale;
Point2 ofs2 = ((scaled_tex_size - size) / scale).abs() / 2.0f;
_texture_region = Rect2(ofs2, size / scale);
} break;
@@ -233,10 +232,12 @@ void TextureButton::_notification(int p_what) {
if (draw_focus_only) {
// Do nothing, we only needed to calculate the rectangle.
- } else if (_tile) {
- draw_texture_rect(texdraw, Rect2(ofs, size), _tile);
- } else {
- draw_texture_rect_region(texdraw, Rect2(ofs, size), _texture_region);
+ } else if (texdraw.is_valid()) {
+ if (_tile) {
+ draw_texture_rect(texdraw, Rect2(ofs, size), _tile);
+ } else {
+ draw_texture_rect_region(texdraw, Rect2(ofs, size), _texture_region);
+ }
}
} else {
_position_rect = Rect2();
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 7ed1f130c8..c0386b056f 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -34,6 +34,7 @@
#include "scene/2d/canvas_group.h"
#include "scene/main/canvas_layer.h"
#include "scene/main/window.h"
+#include "scene/resources/atlas_texture.h"
#include "scene/resources/canvas_item_material.h"
#include "scene/resources/font.h"
#include "scene/resources/multimesh.h"
@@ -850,18 +851,28 @@ void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color
ERR_THREAD_GUARD;
ERR_DRAW_GUARD;
- RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ const Ref<AtlasTexture> atlas = p_texture;
+ if (atlas.is_valid() && atlas->get_atlas().is_valid()) {
+ const Ref<Texture2D> &texture = atlas->get_atlas();
+ const Vector2 atlas_size = texture->get_size();
+
+ const Vector2 remap_min = atlas->get_region().position / atlas_size;
+ const Vector2 remap_max = atlas->get_region().get_end() / atlas_size;
- RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid);
+ PackedVector2Array uvs = p_uvs;
+ for (Vector2 &p : uvs) {
+ p.x = Math::remap(p.x, 0, 1, remap_min.x, remap_max.x);
+ p.y = Math::remap(p.y, 0, 1, remap_min.y, remap_max.y);
+ }
+ RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, uvs, texture->get_rid());
+ } else {
+ RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, texture_rid);
+ }
}
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_DRAW_GUARD;
-
- Vector<Color> colors = { p_color };
- RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
- RenderingServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid);
+ draw_polygon(p_points, { p_color }, p_uvs, p_texture);
}
void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform, const Color &p_modulate) {
diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp
index fe23ca1800..f36bbe9395 100644
--- a/scene/main/instance_placeholder.cpp
+++ b/scene/main/instance_placeholder.cpp
@@ -88,16 +88,16 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene
if (!ps.is_valid()) {
return nullptr;
}
- Node *scene = ps->instantiate();
- if (!scene) {
+ Node *instance = ps->instantiate();
+ if (!instance) {
return nullptr;
}
- scene->set_name(get_name());
- scene->set_multiplayer_authority(get_multiplayer_authority());
+ instance->set_name(get_name());
+ instance->set_multiplayer_authority(get_multiplayer_authority());
int pos = get_index();
for (const PropSet &E : stored_values) {
- scene->set(E.name, E.value);
+ set_value_on_instance(this, instance, E);
}
if (p_replace) {
@@ -105,10 +105,125 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene
base->remove_child(this);
}
- base->add_child(scene);
- base->move_child(scene, pos);
+ base->add_child(instance);
+ base->move_child(instance, pos);
- return scene;
+ return instance;
+}
+
+// This method will attempt to set the correct values on the placeholder instance
+// for regular types this is trivial and unnecessary.
+// For nodes however this becomes a bit tricky because they might now have existed until the instantiation,
+// so this method will try to find the correct nodes and resolve them.
+void InstancePlaceholder::set_value_on_instance(InstancePlaceholder *p_placeholder, Node *p_instance, const PropSet &p_set) {
+ bool is_valid;
+
+ // If we don't have any info, we can't do anything,
+ // so try setting the value directly.
+ Variant current = p_instance->get(p_set.name, &is_valid);
+ if (!is_valid) {
+ p_instance->set(p_set.name, p_set.value, &is_valid);
+ return;
+ }
+
+ Variant::Type current_type = current.get_type();
+ Variant::Type placeholder_type = p_set.value.get_type();
+
+ // Arrays are a special case, because their containing type might be different.
+ if (current_type != Variant::Type::ARRAY) {
+ // Check if the variant types match.
+ if (Variant::evaluate(Variant::OP_EQUAL, current_type, placeholder_type)) {
+ p_instance->set(p_set.name, p_set.value, &is_valid);
+ if (is_valid) {
+ return;
+ }
+ // Types match but setting failed? This is strange, so let's print a warning!
+ WARN_PRINT(vformat("Property '%s' with type '%s' could not be set when creating instance of '%s'.", p_set.name, Variant::get_type_name(current_type), p_placeholder->get_name()));
+ return;
+ }
+ } else {
+ // We are dealing with an Array.
+ // Let's check if the subtype of the array matches first.
+ // This is needed because the set method of ScriptInstance checks for type,
+ // but the ClassDB set method doesn't! So we cannot reliably know what actually happens.
+ Array current_array = current;
+ Array placeholder_array = p_set.value;
+ if (current_array.is_same_typed(placeholder_array)) {
+ p_instance->set(p_set.name, p_set.value, &is_valid);
+ if (is_valid) {
+ return;
+ }
+ // Internal array types match but setting failed? This is strange, so let's print a warning!
+ WARN_PRINT(vformat("Array Property '%s' with type '%s' could not be set when creating instance of '%s'.", p_set.name, Variant::get_type_name(Variant::Type(current_array.get_typed_builtin())), p_placeholder->get_name()));
+ }
+ // Arrays are not the same internal type. This should be happening because we have a NodePath Array,
+ // but the instance wants a Node Array.
+ }
+
+ switch (current_type) {
+ case Variant::Type::NIL:
+ if (placeholder_type != Variant::Type::NODE_PATH) {
+ break;
+ }
+ // If it's nil but we have a NodePath, we guess what works.
+
+ p_instance->set(p_set.name, p_set.value, &is_valid);
+ if (is_valid) {
+ break;
+ }
+
+ p_instance->set(p_set.name, try_get_node(p_placeholder, p_instance, p_set.value), &is_valid);
+ break;
+ case Variant::Type::OBJECT:
+ if (placeholder_type != Variant::Type::NODE_PATH) {
+ break;
+ }
+ // Easiest case, we want a node, but we have a deferred NodePath.
+ p_instance->set(p_set.name, try_get_node(p_placeholder, p_instance, p_set.value));
+ break;
+ case Variant::Type::ARRAY: {
+ // If we have reached here it means our array types don't match,
+ // so we will convert the placeholder array into the correct type
+ // and resolve nodes if necessary.
+ Array current_array = current;
+ Array converted_array;
+ Array placeholder_array = p_set.value;
+ converted_array = current_array.duplicate();
+ converted_array.resize(placeholder_array.size());
+
+ if (Variant::evaluate(Variant::OP_EQUAL, current_array.get_typed_builtin(), Variant::Type::NODE_PATH)) {
+ // We want a typed NodePath array.
+ for (int i = 0; i < placeholder_array.size(); i++) {
+ converted_array.set(i, placeholder_array[i]);
+ }
+ } else {
+ // We want Nodes, convert NodePaths.
+ for (int i = 0; i < placeholder_array.size(); i++) {
+ converted_array.set(i, try_get_node(p_placeholder, p_instance, placeholder_array[i]));
+ }
+ }
+
+ p_instance->set(p_set.name, converted_array, &is_valid);
+ if (!is_valid) {
+ WARN_PRINT(vformat("Property '%s' with type '%s' could not be set when creating instance of '%s'.", p_set.name, Variant::get_type_name(current_type), p_placeholder->get_name()));
+ }
+ break;
+ }
+ default:
+ WARN_PRINT(vformat("Property '%s' with type '%s' could not be set when creating instance of '%s'.", p_set.name, Variant::get_type_name(current_type), p_placeholder->get_name()));
+ break;
+ }
+}
+
+Node *InstancePlaceholder::try_get_node(InstancePlaceholder *p_placeholder, Node *p_instance, const NodePath &p_path) {
+ // First try to resolve internally,
+ // if that fails try resolving externally.
+ Node *node = p_instance->get_node_or_null(p_path);
+ if (node == nullptr) {
+ node = p_placeholder->get_node_or_null(p_path);
+ }
+
+ return node;
}
Dictionary InstancePlaceholder::get_stored_values(bool p_with_order) {
diff --git a/scene/main/instance_placeholder.h b/scene/main/instance_placeholder.h
index 480474d0bd..ccf1e63a16 100644
--- a/scene/main/instance_placeholder.h
+++ b/scene/main/instance_placeholder.h
@@ -46,6 +46,10 @@ class InstancePlaceholder : public Node {
List<PropSet> stored_values;
+private:
+ void set_value_on_instance(InstancePlaceholder *p_placeholder, Node *p_instance, const PropSet &p_set);
+ Node *try_get_node(InstancePlaceholder *p_placeholder, Node *p_instance, const NodePath &p_path);
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index e9a7123da0..addbd6078a 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -306,10 +306,21 @@ String Window::get_title() const {
return title;
}
+void Window::_settings_changed() {
+ if (visible && initial_position != WINDOW_INITIAL_POSITION_ABSOLUTE && is_in_edited_scene_root()) {
+ Size2 screen_size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
+ position = (screen_size - size) / 2;
+ if (embedder) {
+ embedder->_sub_window_update(this);
+ }
+ }
+}
+
void Window::set_initial_position(Window::WindowInitialPosition p_initial_position) {
ERR_MAIN_THREAD_GUARD;
initial_position = p_initial_position;
+ _settings_changed();
notify_property_list_changed();
}
@@ -829,7 +840,12 @@ void Window::set_visible(bool p_visible) {
if (visible) {
embedder = embedder_vp;
if (initial_position != WINDOW_INITIAL_POSITION_ABSOLUTE) {
- position = (embedder->get_visible_rect().size - size) / 2;
+ if (is_in_edited_scene_root()) {
+ Size2 screen_size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
+ position = (screen_size - size) / 2;
+ } else {
+ position = (embedder->get_visible_rect().size - size) / 2;
+ }
}
embedder->_sub_window_register(this);
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
@@ -1265,6 +1281,12 @@ void Window::_notification(int p_what) {
} break;
case NOTIFICATION_ENTER_TREE: {
+ if (is_in_edited_scene_root()) {
+ if (!ProjectSettings::get_singleton()->is_connected("settings_changed", callable_mp(this, &Window::_settings_changed))) {
+ ProjectSettings::get_singleton()->connect("settings_changed", callable_mp(this, &Window::_settings_changed));
+ }
+ }
+
bool embedded = false;
{
embedder = get_embedder();
@@ -1280,7 +1302,12 @@ void Window::_notification(int p_what) {
// Create as embedded.
if (embedder) {
if (initial_position != WINDOW_INITIAL_POSITION_ABSOLUTE) {
- position = (embedder->get_visible_rect().size - size) / 2;
+ if (is_in_edited_scene_root()) {
+ Size2 screen_size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
+ position = (screen_size - size) / 2;
+ } else {
+ position = (embedder->get_visible_rect().size - size) / 2;
+ }
}
embedder->_sub_window_register(this);
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE);
@@ -1377,6 +1404,10 @@ void Window::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_TREE: {
+ if (ProjectSettings::get_singleton()->is_connected("settings_changed", callable_mp(this, &Window::_settings_changed))) {
+ ProjectSettings::get_singleton()->disconnect("settings_changed", callable_mp(this, &Window::_settings_changed));
+ }
+
set_theme_context(nullptr, false);
if (transient) {
diff --git a/scene/main/window.h b/scene/main/window.h
index ffcf50ccdd..33d593711f 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -214,6 +214,8 @@ private:
int resize_margin = 0;
} theme_cache;
+ void _settings_changed();
+
Viewport *embedder = nullptr;
Transform2D window_transform;
diff --git a/scene/resources/2d/tile_set.cpp b/scene/resources/2d/tile_set.cpp
index 0f73577768..6c3356a205 100644
--- a/scene/resources/2d/tile_set.cpp
+++ b/scene/resources/2d/tile_set.cpp
@@ -6378,7 +6378,7 @@ Ref<ConvexPolygonShape2D> TileData::get_collision_polygon_shape(int p_layer_id,
for (int i = 0; i < size; i++) {
Ref<ConvexPolygonShape2D> transformed_polygon;
transformed_polygon.instantiate();
- transformed_polygon->set_points(get_transformed_vertices(shapes_data.shapes[shape_index]->get_points(), p_flip_h, p_flip_v, p_transpose));
+ transformed_polygon->set_points(get_transformed_vertices(shapes_data.shapes[i]->get_points(), p_flip_h, p_flip_v, p_transpose));
shapes_data.transformed_shapes[key][i] = transformed_polygon;
}
return shapes_data.transformed_shapes[key][shape_index];
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 27da825bfe..8e49a8b56f 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -822,7 +822,18 @@ uniform float distance_fade_max : hint_range(0.0, 4096.0, 0.01);
)";
}
- if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && flags[FLAG_UV1_USE_TRIPLANAR]) {
+ String msg = "MSDF is not supported on triplanar materials. Ignoring MSDF in favor of triplanar mapping.";
+ if (textures[TEXTURE_ALBEDO].is_valid()) {
+ WARN_PRINT(vformat("%s (albedo %s): " + msg, get_path(), textures[TEXTURE_ALBEDO]->get_path()));
+ } else if (!get_path().is_empty()) {
+ WARN_PRINT(vformat("%s: " + msg, get_path()));
+ } else {
+ WARN_PRINT(msg);
+ }
+ }
+
+ if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && !flags[FLAG_UV1_USE_TRIPLANAR]) {
code += R"(
uniform float msdf_pixel_range : hint_range(1.0, 100.0, 1.0);
uniform float msdf_outline_size : hint_range(0.0, 250.0, 1.0);
@@ -1271,7 +1282,7 @@ void vertex() {)";
code += "}\n";
- if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && !flags[FLAG_UV1_USE_TRIPLANAR]) {
code += R"(
float msdf_median(float r, float g, float b, float a) {
return min(max(min(r, g), min(max(r, g), b)), a);
@@ -1414,7 +1425,7 @@ void fragment() {)";
}
}
- if (flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ if (flags[FLAG_ALBEDO_TEXTURE_MSDF] && !flags[FLAG_UV1_USE_TRIPLANAR]) {
code += R"(
{
// Albedo Texture MSDF: Enabled
@@ -1427,11 +1438,7 @@ void fragment() {)";
if (flags[FLAG_USE_POINT_SIZE]) {
code += " vec2 dest_size = vec2(1.0) / fwidth(POINT_COORD);\n";
} else {
- if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += " vec2 dest_size = vec2(1.0) / fwidth(uv1_triplanar_pos);\n";
- } else {
- code += " vec2 dest_size = vec2(1.0) / fwidth(base_uv);\n";
- }
+ code += " vec2 dest_size = vec2(1.0) / fwidth(base_uv);\n";
}
code += R"(
float px_size = max(0.5 * dot(msdf_size, dest_size), 1.0);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 5e50b9a240..0c57c6b7ba 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -314,6 +314,16 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
ERR_FAIL_INDEX_V(nprops[j].value, prop_count, nullptr);
if (nprops[j].name & FLAG_PATH_PROPERTY_IS_NODE) {
+ if (!Engine::get_singleton()->is_editor_hint() && node->get_scene_instance_load_placeholder()) {
+ // We cannot know if the referenced nodes exist yet, so instead of deferring, we write the NodePaths directly.
+
+ uint32_t name_idx = nprops[j].name & (FLAG_PATH_PROPERTY_IS_NODE - 1);
+ ERR_FAIL_UNSIGNED_INDEX_V(name_idx, (uint32_t)sname_count, nullptr);
+
+ node->set(snames[name_idx], props[nprops[j].value], &valid);
+ continue;
+ }
+
uint32_t name_idx = nprops[j].name & (FLAG_PATH_PROPERTY_IS_NODE - 1);
ERR_FAIL_UNSIGNED_INDEX_V(name_idx, (uint32_t)sname_count, nullptr);
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 2e27ac9198..7c13e623c2 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -33,9 +33,7 @@
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/io/missing_resource.h"
-#include "core/io/resource_format_binary.h"
#include "core/object/script_language.h"
-#include "core/version.h"
// Version 2: Changed names for Basis, AABB, Vectors, etc.
// Version 3: New string ID for ext/subresources, breaks forward compat.
@@ -44,11 +42,6 @@
// For compat, save as version 3 if not using PackedVector4Array or no big PackedByteArray.
#define FORMAT_VERSION_COMPAT 3
-#define BINARY_FORMAT_VERSION 4
-
-#include "core/io/dir_access.h"
-#include "core/version.h"
-
#define _printerr() ERR_PRINT(String(res_path + ":" + itos(lines) + " - Parse Error: " + error_text).utf8().get_data());
///
@@ -1127,298 +1120,6 @@ void ResourceLoaderText::open(Ref<FileAccess> p_f, bool p_skip_first_tag) {
rp.userdata = this;
}
-static void bs_save_unicode_string(Ref<FileAccess> p_f, const String &p_string, bool p_bit_on_len = false) {
- CharString utf8 = p_string.utf8();
- if (p_bit_on_len) {
- p_f->store_32((utf8.length() + 1) | 0x80000000);
- } else {
- p_f->store_32(utf8.length() + 1);
- }
- p_f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1);
-}
-
-Error ResourceLoaderText::save_as_binary(const String &p_path) {
- if (error) {
- return error;
- }
-
- Ref<FileAccess> wf = FileAccess::open(p_path, FileAccess::WRITE);
- if (wf.is_null()) {
- return ERR_CANT_OPEN;
- }
-
- //save header compressed
- static const uint8_t header[4] = { 'R', 'S', 'R', 'C' };
- wf->store_buffer(header, 4);
-
- wf->store_32(0); //endianness, little endian
- wf->store_32(0); //64 bits file, false for now
- wf->store_32(VERSION_MAJOR);
- wf->store_32(VERSION_MINOR);
- static const int save_format_version = BINARY_FORMAT_VERSION;
- wf->store_32(save_format_version);
-
- bs_save_unicode_string(wf, is_scene ? "PackedScene" : resource_type);
- wf->store_64(0); //offset to import metadata, this is no longer used
-
- wf->store_32(ResourceFormatSaverBinaryInstance::FORMAT_FLAG_NAMED_SCENE_IDS | ResourceFormatSaverBinaryInstance::FORMAT_FLAG_UIDS);
-
- wf->store_64(res_uid);
-
- for (int i = 0; i < ResourceFormatSaverBinaryInstance::RESERVED_FIELDS; i++) {
- wf->store_32(0); // reserved
- }
-
- wf->store_32(0); //string table size, will not be in use
- uint64_t ext_res_count_pos = wf->get_position();
-
- wf->store_32(0); //zero ext resources, still parsing them
-
- //go with external resources
-
- DummyReadData dummy_read;
- VariantParser::ResourceParser rp_new;
- rp_new.ext_func = _parse_ext_resource_dummys;
- rp_new.sub_func = _parse_sub_resource_dummys;
- rp_new.userdata = &dummy_read;
-
- while (next_tag.name == "ext_resource") {
- if (!next_tag.fields.has("path")) {
- error = ERR_FILE_CORRUPT;
- error_text = "Missing 'path' in external resource tag";
- _printerr();
- return error;
- }
-
- if (!next_tag.fields.has("type")) {
- error = ERR_FILE_CORRUPT;
- error_text = "Missing 'type' in external resource tag";
- _printerr();
- return error;
- }
-
- if (!next_tag.fields.has("id")) {
- error = ERR_FILE_CORRUPT;
- error_text = "Missing 'id' in external resource tag";
- _printerr();
- return error;
- }
-
- String path = next_tag.fields["path"];
- String type = next_tag.fields["type"];
- String id = next_tag.fields["id"];
- ResourceUID::ID uid = ResourceUID::INVALID_ID;
- if (next_tag.fields.has("uid")) {
- String uidt = next_tag.fields["uid"];
- uid = ResourceUID::get_singleton()->text_to_id(uidt);
- }
-
- bs_save_unicode_string(wf, type);
- bs_save_unicode_string(wf, path);
- wf->store_64(uid);
-
- int lindex = dummy_read.external_resources.size();
- Ref<DummyResource> dr;
- dr.instantiate();
- dr->set_path("res://dummy" + itos(lindex)); //anything is good to detect it for saving as external
- dummy_read.external_resources[dr] = lindex;
- dummy_read.rev_external_resources[id] = dr;
-
- error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp_new);
-
- if (error) {
- _printerr();
- return error;
- }
- }
-
- // save external resource table
- wf->seek(ext_res_count_pos);
- wf->store_32(dummy_read.external_resources.size());
- wf->seek_end();
-
- //now, save resources to a separate file, for now
-
- uint64_t sub_res_count_pos = wf->get_position();
- wf->store_32(0); //zero sub resources, still parsing them
-
- String temp_file = p_path + ".temp";
- Vector<uint64_t> local_offsets;
- Vector<uint64_t> local_pointers_pos;
- {
- Ref<FileAccess> wf2 = FileAccess::open(temp_file, FileAccess::WRITE);
- if (wf2.is_null()) {
- return ERR_CANT_OPEN;
- }
-
- while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
- String type;
- String id;
- bool main_res;
-
- if (next_tag.name == "sub_resource") {
- if (!next_tag.fields.has("type")) {
- error = ERR_FILE_CORRUPT;
- error_text = "Missing 'type' in external resource tag";
- _printerr();
- return error;
- }
-
- if (!next_tag.fields.has("id")) {
- error = ERR_FILE_CORRUPT;
- error_text = "Missing 'id' in external resource tag";
- _printerr();
- return error;
- }
-
- type = next_tag.fields["type"];
- id = next_tag.fields["id"];
- main_res = false;
-
- if (!dummy_read.resource_map.has(id)) {
- Ref<DummyResource> dr;
- dr.instantiate();
- dr->set_scene_unique_id(id);
- dummy_read.resource_map[id] = dr;
- uint32_t im_size = dummy_read.resource_index_map.size();
- dummy_read.resource_index_map.insert(dr, im_size);
- }
-
- } else {
- type = res_type;
- String uid_text = ResourceUID::get_singleton()->id_to_text(res_uid);
- id = type + "_" + uid_text.replace("uid://", "").replace("<invalid>", "0");
- main_res = true;
- }
-
- local_offsets.push_back(wf2->get_position());
-
- bs_save_unicode_string(wf, "local://" + id);
- local_pointers_pos.push_back(wf->get_position());
- wf->store_64(0); //temp local offset
-
- bs_save_unicode_string(wf2, type);
- uint64_t propcount_ofs = wf2->get_position();
- wf2->store_32(0);
-
- int prop_count = 0;
-
- while (true) {
- String assign;
- Variant value;
-
- error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp_new);
-
- if (error) {
- if (main_res && error == ERR_FILE_EOF) {
- next_tag.name = ""; //exit
- break;
- }
-
- _printerr();
- return error;
- }
-
- if (!assign.is_empty()) {
- HashMap<StringName, int> empty_string_map; //unused
- bs_save_unicode_string(wf2, assign, true);
- ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
- prop_count++;
-
- } else if (!next_tag.name.is_empty()) {
- error = OK;
- break;
- } else {
- error = ERR_FILE_CORRUPT;
- error_text = "Premature end of file while parsing [sub_resource]";
- _printerr();
- return error;
- }
- }
-
- wf2->seek(propcount_ofs);
- wf2->store_32(prop_count);
- wf2->seek_end();
- }
-
- if (next_tag.name == "node") {
- // This is a node, must save one more!
-
- if (!is_scene) {
- error_text += "found the 'node' tag on a resource file!";
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
- }
-
- Ref<PackedScene> packed_scene = _parse_node_tag(rp_new);
-
- if (!packed_scene.is_valid()) {
- return error;
- }
-
- error = OK;
- //get it here
- List<PropertyInfo> props;
- packed_scene->get_property_list(&props);
-
- String id = "PackedScene_" + ResourceUID::get_singleton()->id_to_text(res_uid).replace("uid://", "").replace("<invalid>", "0");
- bs_save_unicode_string(wf, "local://" + id);
- local_pointers_pos.push_back(wf->get_position());
- wf->store_64(0); //temp local offset
-
- local_offsets.push_back(wf2->get_position());
- bs_save_unicode_string(wf2, "PackedScene");
- uint64_t propcount_ofs = wf2->get_position();
- wf2->store_32(0);
-
- int prop_count = 0;
-
- for (const PropertyInfo &E : props) {
- if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
- continue;
- }
-
- String name = E.name;
- Variant value = packed_scene->get(name);
-
- HashMap<StringName, int> empty_string_map; //unused
- bs_save_unicode_string(wf2, name, true);
- ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_index_map, dummy_read.external_resources, empty_string_map);
- prop_count++;
- }
-
- wf2->seek(propcount_ofs);
- wf2->store_32(prop_count);
- wf2->seek_end();
- }
- }
-
- uint64_t offset_from = wf->get_position();
- wf->seek(sub_res_count_pos); //plus one because the saved one
- wf->store_32(local_offsets.size());
-
- for (int i = 0; i < local_offsets.size(); i++) {
- wf->seek(local_pointers_pos[i]);
- wf->store_64(local_offsets[i] + offset_from);
- }
-
- wf->seek_end();
-
- Vector<uint8_t> data = FileAccess::get_file_as_bytes(temp_file);
- wf->store_buffer(data.ptr(), data.size());
- {
- Ref<DirAccess> dar = DirAccess::open(temp_file.get_base_dir());
- ERR_FAIL_COND_V(dar.is_null(), FAILED);
-
- dar->remove(temp_file);
- }
-
- wf->store_buffer((const uint8_t *)"RSRC", 4); //magic at end
-
- return OK;
-}
-
Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
if (error) {
return error;
@@ -1835,29 +1536,6 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const
ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = nullptr;
-Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) {
- Error err;
- Ref<FileAccess> f = FileAccess::open(p_src_path, FileAccess::READ, &err);
-
- ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_OPEN, "Cannot open file '" + p_src_path + "'.");
-
- ResourceLoaderText loader;
- const String &path = p_src_path;
- loader.local_path = ProjectSettings::get_singleton()->localize_path(path);
- loader.res_path = loader.local_path;
- loader.open(f);
- return loader.save_as_binary(p_dst_path);
-}
-
-/*****************************************************************************************************/
-/*****************************************************************************************************/
-/*****************************************************************************************************/
-/*****************************************************************************************************/
-/*****************************************************************************************************/
-/*****************************************************************************************************/
-/*****************************************************************************************************/
-/*****************************************************************************************************/
-/*****************************************************************************************************/
/*****************************************************************************************************/
String ResourceFormatSaverTextInstance::_write_resources(void *ud, const Ref<Resource> &p_resource) {
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index 41363fd975..b5542f77ba 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -87,11 +87,6 @@ class ResourceLoaderText {
Error _parse_sub_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str);
Error _parse_ext_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str);
- // for converter
- class DummyResource : public Resource {
- public:
- };
-
struct DummyReadData {
bool no_placeholders = false;
HashMap<Ref<Resource>, int> external_resources;
@@ -133,7 +128,6 @@ public:
Error rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const HashMap<String, String> &p_map);
Error get_classes_used(HashSet<StringName> *r_classes);
- Error save_as_binary(const String &p_path);
ResourceLoaderText();
};
@@ -152,8 +146,6 @@ public:
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override;
virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map) override;
- static Error convert_file_to_binary(const String &p_src_path, const String &p_dst_path);
-
ResourceFormatLoaderText() { singleton = this; }
};