summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/animated_sprite_2d.cpp26
-rw-r--r--scene/2d/animated_sprite_2d.h2
-rw-r--r--scene/2d/area_2d.cpp26
-rw-r--r--scene/2d/area_2d.h2
-rw-r--r--scene/2d/audio_stream_player_2d.cpp6
-rw-r--r--scene/2d/audio_stream_player_2d.h2
-rw-r--r--scene/2d/camera_2d.cpp6
-rw-r--r--scene/2d/camera_2d.h2
-rw-r--r--scene/2d/collision_object_2d.cpp14
-rw-r--r--scene/2d/collision_object_2d.h4
-rw-r--r--scene/2d/cpu_particles_2d.cpp30
-rw-r--r--scene/2d/cpu_particles_2d.h2
-rw-r--r--scene/2d/gpu_particles_2d.cpp2
-rw-r--r--scene/2d/gpu_particles_2d.h2
-rw-r--r--scene/2d/light_2d.cpp6
-rw-r--r--scene/2d/light_2d.h2
-rw-r--r--scene/2d/line_2d.cpp8
-rw-r--r--scene/2d/navigation_obstacle_2d.h2
-rw-r--r--scene/2d/path_2d.cpp6
-rw-r--r--scene/2d/path_2d.h2
-rw-r--r--scene/2d/physical_bone_2d.cpp2
-rw-r--r--scene/2d/physics_body_2d.cpp21
-rw-r--r--scene/2d/physics_body_2d.h5
-rw-r--r--scene/2d/polygon_2d.cpp6
-rw-r--r--scene/2d/polygon_2d.h2
-rw-r--r--scene/2d/ray_cast_2d.cpp7
-rw-r--r--scene/2d/ray_cast_2d.h2
-rw-r--r--scene/2d/sprite_2d.cpp18
-rw-r--r--scene/2d/sprite_2d.h2
-rw-r--r--scene/2d/tile_map.cpp19
-rw-r--r--scene/2d/tile_map.h2
-rw-r--r--scene/3d/area_3d.cpp28
-rw-r--r--scene/3d/area_3d.h2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp8
-rw-r--r--scene/3d/audio_stream_player_3d.h2
-rw-r--r--scene/3d/bone_attachment_3d.cpp14
-rw-r--r--scene/3d/bone_attachment_3d.h2
-rw-r--r--scene/3d/camera_3d.cpp2
-rw-r--r--scene/3d/camera_3d.h2
-rw-r--r--scene/3d/collision_object_3d.cpp14
-rw-r--r--scene/3d/collision_object_3d.h4
-rw-r--r--scene/3d/cpu_particles_3d.cpp32
-rw-r--r--scene/3d/cpu_particles_3d.h2
-rw-r--r--scene/3d/decal.cpp7
-rw-r--r--scene/3d/decal.h2
-rw-r--r--scene/3d/fog_volume.cpp7
-rw-r--r--scene/3d/fog_volume.h2
-rw-r--r--scene/3d/gpu_particles_3d.cpp10
-rw-r--r--scene/3d/gpu_particles_3d.h2
-rw-r--r--scene/3d/label_3d.cpp22
-rw-r--r--scene/3d/label_3d.h8
-rw-r--r--scene/3d/light_3d.cpp36
-rw-r--r--scene/3d/light_3d.h4
-rw-r--r--scene/3d/lightmap_gi.cpp15
-rw-r--r--scene/3d/lightmap_gi.h2
-rw-r--r--scene/3d/navigation_obstacle_3d.h2
-rw-r--r--scene/3d/navigation_region_3d.cpp6
-rw-r--r--scene/3d/node_3d.cpp54
-rw-r--r--scene/3d/node_3d.h6
-rw-r--r--scene/3d/path_3d.cpp7
-rw-r--r--scene/3d/path_3d.h2
-rw-r--r--scene/3d/physics_body_3d.cpp22
-rw-r--r--scene/3d/physics_body_3d.h5
-rw-r--r--scene/3d/ray_cast_3d.cpp7
-rw-r--r--scene/3d/ray_cast_3d.h2
-rw-r--r--scene/3d/reflection_probe.cpp7
-rw-r--r--scene/3d/reflection_probe.h2
-rw-r--r--scene/3d/skeleton_3d.cpp39
-rw-r--r--scene/3d/skeleton_3d.h5
-rw-r--r--scene/3d/skeleton_ik_3d.cpp14
-rw-r--r--scene/3d/skeleton_ik_3d.h2
-rw-r--r--scene/3d/soft_dynamic_body_3d.cpp6
-rw-r--r--scene/3d/sprite_3d.cpp75
-rw-r--r--scene/3d/sprite_3d.h4
-rw-r--r--scene/3d/velocity_tracker_3d.h2
-rw-r--r--scene/3d/voxelizer.cpp10
-rw-r--r--scene/3d/xr_nodes.cpp12
-rw-r--r--scene/3d/xr_nodes.h2
-rw-r--r--scene/animation/animation_blend_space_1d.cpp9
-rw-r--r--scene/animation/animation_blend_space_1d.h2
-rw-r--r--scene/animation/animation_blend_space_2d.cpp13
-rw-r--r--scene/animation/animation_blend_space_2d.h2
-rw-r--r--scene/animation/animation_blend_tree.cpp53
-rw-r--r--scene/animation/animation_blend_tree.h14
-rw-r--r--scene/animation/animation_node_state_machine.cpp21
-rw-r--r--scene/animation/animation_node_state_machine.h7
-rw-r--r--scene/animation/animation_player.cpp19
-rw-r--r--scene/animation/animation_player.h2
-rw-r--r--scene/animation/animation_tree.cpp6
-rw-r--r--scene/animation/animation_tree.h2
-rw-r--r--scene/audio/audio_stream_player.cpp8
-rw-r--r--scene/audio/audio_stream_player.h2
-rw-r--r--scene/gui/button.cpp10
-rw-r--r--scene/gui/check_box.cpp2
-rw-r--r--scene/gui/check_button.cpp2
-rw-r--r--scene/gui/control.cpp212
-rw-r--r--scene/gui/control.h17
-rw-r--r--scene/gui/graph_edit.cpp2
-rw-r--r--scene/gui/graph_node.cpp7
-rw-r--r--scene/gui/graph_node.h2
-rw-r--r--scene/gui/item_list.cpp8
-rw-r--r--scene/gui/label.cpp8
-rw-r--r--scene/gui/line_edit.cpp6
-rw-r--r--scene/gui/line_edit.h4
-rw-r--r--scene/gui/menu_bar.cpp868
-rw-r--r--scene/gui/menu_bar.h156
-rw-r--r--scene/gui/menu_button.cpp6
-rw-r--r--scene/gui/option_button.cpp11
-rw-r--r--scene/gui/option_button.h2
-rw-r--r--scene/gui/popup_menu.cpp123
-rw-r--r--scene/gui/popup_menu.h11
-rw-r--r--scene/gui/rich_text_label.cpp10
-rw-r--r--scene/gui/tree.cpp34
-rw-r--r--scene/gui/tree.h7
-rw-r--r--scene/gui/video_stream_player.h2
-rw-r--r--scene/main/canvas_layer.cpp6
-rw-r--r--scene/main/canvas_layer.h2
-rw-r--r--scene/main/viewport.cpp6
-rw-r--r--scene/main/viewport.h2
-rw-r--r--scene/main/window.cpp6
-rw-r--r--scene/main/window.h2
-rw-r--r--scene/register_scene_types.cpp24
-rw-r--r--scene/resources/animation.cpp543
-rw-r--r--scene/resources/animation.h25
-rw-r--r--scene/resources/bone_map.cpp2
-rw-r--r--scene/resources/bone_map.h2
-rw-r--r--scene/resources/camera_effects.cpp10
-rw-r--r--scene/resources/camera_effects.h2
-rw-r--r--scene/resources/canvas_item_material.cpp6
-rw-r--r--scene/resources/canvas_item_material.h2
-rw-r--r--scene/resources/curve.cpp4
-rw-r--r--scene/resources/default_theme/default_theme.cpp29
-rw-r--r--scene/resources/environment.cpp42
-rw-r--r--scene/resources/environment.h2
-rw-r--r--scene/resources/font.cpp22
-rw-r--r--scene/resources/font.h4
-rw-r--r--scene/resources/material.cpp186
-rw-r--r--scene/resources/material.h8
-rw-r--r--scene/resources/mesh.cpp159
-rw-r--r--scene/resources/mesh.h6
-rw-r--r--scene/resources/mesh_library.h2
-rw-r--r--scene/resources/navigation_mesh.cpp12
-rw-r--r--scene/resources/navigation_mesh.h4
-rw-r--r--scene/resources/particles_material.cpp58
-rw-r--r--scene/resources/particles_material.h2
-rw-r--r--scene/resources/shader.cpp2
-rw-r--r--scene/resources/shader_include.cpp2
-rw-r--r--scene/resources/skeleton_profile.cpp14
-rw-r--r--scene/resources/skeleton_profile.h2
-rw-r--r--scene/resources/style_box.cpp6
-rw-r--r--scene/resources/style_box.h2
-rw-r--r--scene/resources/texture.cpp21
-rw-r--r--scene/resources/texture.h10
-rw-r--r--scene/resources/tile_set.cpp10
-rw-r--r--scene/resources/tile_set.h2
-rw-r--r--scene/resources/visual_shader.cpp12
-rw-r--r--scene/resources/visual_shader.h2
-rw-r--r--scene/resources/visual_shader_nodes.cpp16
158 files changed, 2552 insertions, 1159 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index d56c7b8811..177f587f4f 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -104,12 +104,12 @@ Rect2 AnimatedSprite2D::_get_rect() const {
return Rect2(ofs, s);
}
-void AnimatedSprite2D::_validate_property(PropertyInfo &property) const {
+void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const {
if (!frames.is_valid()) {
return;
}
- if (property.name == "animation") {
- property.hint = PROPERTY_HINT_ENUM;
+ if (p_property.name == "animation") {
+ p_property.hint = PROPERTY_HINT_ENUM;
List<StringName> names;
frames->get_animation_list(&names);
names.sort_custom<StringName::AlphCompare>();
@@ -118,33 +118,33 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &property) const {
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
if (E->prev()) {
- property.hint_string += ",";
+ p_property.hint_string += ",";
}
- property.hint_string += String(E->get());
+ p_property.hint_string += String(E->get());
if (animation == E->get()) {
current_found = true;
}
}
if (!current_found) {
- if (property.hint_string.is_empty()) {
- property.hint_string = String(animation);
+ if (p_property.hint_string.is_empty()) {
+ p_property.hint_string = String(animation);
} else {
- property.hint_string = String(animation) + "," + property.hint_string;
+ p_property.hint_string = String(animation) + "," + p_property.hint_string;
}
}
}
- if (property.name == "frame") {
- property.hint = PROPERTY_HINT_RANGE;
+ if (p_property.name == "frame") {
+ p_property.hint = PROPERTY_HINT_RANGE;
if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) {
- property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
+ p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
} else {
// Avoid an error, `hint_string` is required for `PROPERTY_HINT_RANGE`.
- property.hint_string = "0,0,1";
+ p_property.hint_string = "0,0,1";
}
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
}
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index ec38795a1a..0a19e250d8 100644
--- a/scene/2d/animated_sprite_2d.h
+++ b/scene/2d/animated_sprite_2d.h
@@ -62,7 +62,7 @@ class AnimatedSprite2D : public Node2D {
protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
#ifdef TOOLS_ENABLED
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 7890348314..75f1497edc 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -498,8 +498,8 @@ StringName Area2D::get_audio_bus_name() const {
return "Master";
}
-void Area2D::_validate_property(PropertyInfo &property) const {
- if (property.name == "audio_bus_name") {
+void Area2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "audio_bus_name") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0) {
@@ -509,28 +509,28 @@ void Area2D::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
- } else if (property.name.begins_with("gravity") && property.name != "gravity_space_override") {
+ p_property.hint_string = options;
+ } else if (p_property.name.begins_with("gravity") && p_property.name != "gravity_space_override") {
if (gravity_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
} else {
if (gravity_is_point) {
- if (property.name == "gravity_direction") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "gravity_direction") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
} else {
- if (property.name.begins_with("gravity_point_")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with("gravity_point_")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
- } else if (property.name.begins_with("linear_damp") && property.name != "linear_damp_space_override") {
+ } else if (p_property.name.begins_with("linear_damp") && p_property.name != "linear_damp_space_override") {
if (linear_damp_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- } else if (property.name.begins_with("angular_damp") && property.name != "angular_damp_space_override") {
+ } else if (p_property.name.begins_with("angular_damp") && p_property.name != "angular_damp_space_override") {
if (angular_damp_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index a584420ced..3d8d77eabb 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -135,7 +135,7 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_gravity_space_override_mode(SpaceOverride p_mode);
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 94d22111ea..fa49552085 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -323,8 +323,8 @@ bool AudioStreamPlayer2D::_is_active() const {
return active.is_set();
}
-void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const {
- if (property.name == "bus") {
+void AudioStreamPlayer2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "bus") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0) {
@@ -334,7 +334,7 @@ void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
+ p_property.hint_string = options;
}
}
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index d1c4dc4fdf..616d7fdb60 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -85,7 +85,7 @@ private:
float cached_global_panning_strength = 1.0f;
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index c43a796170..88f9c2a4a6 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -655,9 +655,9 @@ bool Camera2D::is_margin_drawing_enabled() const {
return margin_drawing_enabled;
}
-void Camera2D::_validate_property(PropertyInfo &property) const {
- if (!smoothing_enabled && property.name == "smoothing_speed") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Camera2D::_validate_property(PropertyInfo &p_property) const {
+ if (!smoothing_enabled && p_property.name == "smoothing_speed") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 294a6fcb80..78654ee606 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -100,7 +100,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_offset(const Vector2 &p_offset);
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index a8c12f4893..7f991df36c 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -186,6 +186,17 @@ bool CollisionObject2D::get_collision_mask_value(int p_layer_number) const {
return get_collision_mask() & (1 << (p_layer_number - 1));
}
+void CollisionObject2D::set_collision_priority(real_t p_priority) {
+ collision_priority = p_priority;
+ if (!area) {
+ PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), p_priority);
+ }
+}
+
+real_t CollisionObject2D::get_collision_priority() const {
+ return collision_priority;
+}
+
void CollisionObject2D::set_disable_mode(DisableMode p_mode) {
if (disable_mode == p_mode) {
return;
@@ -574,6 +585,8 @@ void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CollisionObject2D::get_collision_layer_value);
ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CollisionObject2D::set_collision_mask_value);
ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CollisionObject2D::get_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &CollisionObject2D::set_collision_priority);
+ ClassDB::bind_method(D_METHOD("get_collision_priority"), &CollisionObject2D::get_collision_priority);
ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject2D::set_disable_mode);
ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject2D::get_disable_mode);
ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable);
@@ -611,6 +624,7 @@ void CollisionObject2D::_bind_methods() {
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority");
ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_pickable"), "set_pickable", "is_pickable");
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index 997afee6c4..f03c6fc72e 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -49,6 +49,7 @@ public:
private:
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
+ real_t collision_priority = 1.0;
bool area = false;
RID rid;
@@ -115,6 +116,9 @@ public:
void set_collision_mask_value(int p_layer_number, bool p_value);
bool get_collision_mask_value(int p_layer_number) const;
+ void set_collision_priority(real_t p_priority);
+ real_t get_collision_priority() const;
+
void set_disable_mode(DisableMode p_mode);
DisableMode get_disable_mode() const;
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 26204a3b1a..40f74d3f50 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -503,32 +503,32 @@ bool CPUParticles2D::get_split_scale() {
return split_scale;
}
-void CPUParticles2D::_validate_property(PropertyInfo &property) const {
- if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
- property.usage = PROPERTY_USAGE_NONE;
+void CPUParticles2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_rect_extents" && emission_shape != EMISSION_SHAPE_RECTANGLE) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_rect_extents" && emission_shape != EMISSION_SHAPE_RECTANGLE) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
- property.usage = PROPERTY_USAGE_NONE;
+ if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_points" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_points" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("scale_curve_") && !split_scale) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("scale_curve_") && !split_scale) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 51d58723b4..8f1671d280 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -193,7 +193,7 @@ private:
protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_emitting(bool p_emitting);
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index 075421a26d..e4354a69e2 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -340,7 +340,7 @@ Ref<Texture2D> GPUParticles2D::get_texture() const {
return texture;
}
-void GPUParticles2D::_validate_property(PropertyInfo &property) const {
+void GPUParticles2D::_validate_property(PropertyInfo &p_property) const {
}
void GPUParticles2D::emit_particle(const Transform2D &p_transform2d, const Vector2 &p_velocity2d, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index a4231cc45d..7eece32898 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -84,7 +84,7 @@ private:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
void _update_collision_size();
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 0481a58431..7eb6b43af7 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -227,9 +227,9 @@ real_t Light2D::get_shadow_smooth() const {
return shadow_smooth;
}
-void Light2D::_validate_property(PropertyInfo &property) const {
- if (!shadow && (property.name == "shadow_color" || property.name == "shadow_filter" || property.name == "shadow_filter_smooth" || property.name == "shadow_item_cull_mask")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Light2D::_validate_property(PropertyInfo &p_property) const {
+ if (!shadow && (p_property.name == "shadow_color" || p_property.name == "shadow_filter" || p_property.name == "shadow_filter_smooth" || p_property.name == "shadow_item_cull_mask")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h
index a84b6516c0..373cfe59fd 100644
--- a/scene/2d/light_2d.h
+++ b/scene/2d/light_2d.h
@@ -79,7 +79,7 @@ protected:
_FORCE_INLINE_ RID _get_light() const { return canvas_light; }
void _notification(int p_what);
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_enabled(bool p_enabled);
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 06e5cbc97e..837f3061f1 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -346,13 +346,13 @@ void Line2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_points", "points"), &Line2D::set_points);
ClassDB::bind_method(D_METHOD("get_points"), &Line2D::get_points);
- ClassDB::bind_method(D_METHOD("set_point_position", "i", "position"), &Line2D::set_point_position);
- ClassDB::bind_method(D_METHOD("get_point_position", "i"), &Line2D::get_point_position);
+ ClassDB::bind_method(D_METHOD("set_point_position", "index", "position"), &Line2D::set_point_position);
+ ClassDB::bind_method(D_METHOD("get_point_position", "index"), &Line2D::get_point_position);
ClassDB::bind_method(D_METHOD("get_point_count"), &Line2D::get_point_count);
- ClassDB::bind_method(D_METHOD("add_point", "position", "at_position"), &Line2D::add_point, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("remove_point", "i"), &Line2D::remove_point);
+ ClassDB::bind_method(D_METHOD("add_point", "position", "index"), &Line2D::add_point, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("remove_point", "index"), &Line2D::remove_point);
ClassDB::bind_method(D_METHOD("clear_points"), &Line2D::clear_points);
diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h
index afda05956a..5795c6c94f 100644
--- a/scene/2d/navigation_obstacle_2d.h
+++ b/scene/2d/navigation_obstacle_2d.h
@@ -46,7 +46,7 @@ class NavigationObstacle2D : public Node {
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &p_property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
public:
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 9862c4bfb1..3c393f9752 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -245,14 +245,14 @@ bool PathFollow2D::get_cubic_interpolation() const {
return cubic;
}
-void PathFollow2D::_validate_property(PropertyInfo &property) const {
- if (property.name == "offset") {
+void PathFollow2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "offset") {
real_t max = 10000.0;
if (path && path->get_curve().is_valid()) {
max = path->get_curve()->get_baked_length();
}
- property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
+ p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
}
}
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index bc55f84831..1f3ee08a2b 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -76,7 +76,7 @@ private:
void _update_transform();
protected:
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp
index 2999736d64..62f4d855ef 100644
--- a/scene/2d/physical_bone_2d.cpp
+++ b/scene/2d/physical_bone_2d.cpp
@@ -158,6 +158,7 @@ void PhysicalBone2D::_start_physics_simulation() {
// Apply the layers and masks.
PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
+ PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority());
// Apply the correct mode.
_apply_body_mode();
@@ -176,6 +177,7 @@ void PhysicalBone2D::_stop_physics_simulation() {
set_physics_process_internal(false);
PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0);
PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0);
+ PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), 1.0);
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC);
}
}
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index ce22f32b01..797f08058f 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -1062,10 +1062,10 @@ void RigidDynamicBody2D::_bind_methods() {
BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE);
}
-void RigidDynamicBody2D::_validate_property(PropertyInfo &property) const {
+void RigidDynamicBody2D::_validate_property(PropertyInfo &p_property) const {
if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) {
- if (property.name == "center_of_mass") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "center_of_mass") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
@@ -1776,14 +1776,14 @@ void CharacterBody2D::_bind_methods() {
BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER);
}
-void CharacterBody2D::_validate_property(PropertyInfo &property) const {
+void CharacterBody2D::_validate_property(PropertyInfo &p_property) const {
if (motion_mode == MOTION_MODE_FLOATING) {
- if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with("floor_") || p_property.name == "up_direction" || p_property.name == "slide_on_ceiling") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
} else {
- if (property.name == "wall_min_slide_angle") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "wall_min_slide_angle") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
@@ -1823,6 +1823,10 @@ real_t KinematicCollision2D::get_angle(const Vector2 &p_up_direction) const {
return result.get_angle(p_up_direction);
}
+real_t KinematicCollision2D::get_depth() const {
+ return result.collision_depth;
+}
+
Object *KinematicCollision2D::get_local_shape() const {
if (!owner) {
return nullptr;
@@ -1874,6 +1878,7 @@ void KinematicCollision2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision2D::get_travel);
ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision2D::get_remainder);
ClassDB::bind_method(D_METHOD("get_angle", "up_direction"), &KinematicCollision2D::get_angle, DEFVAL(Vector2(0.0, -1.0)));
+ ClassDB::bind_method(D_METHOD("get_depth"), &KinematicCollision2D::get_depth);
ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision2D::get_local_shape);
ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision2D::get_collider);
ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision2D::get_collider_id);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 7401fc7578..75ea535424 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -216,7 +216,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *)
@@ -450,7 +450,7 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
};
VARIANT_ENUM_CAST(CharacterBody2D::MotionMode);
@@ -473,6 +473,7 @@ public:
Vector2 get_travel() const;
Vector2 get_remainder() const;
real_t get_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const;
+ real_t get_depth() const;
Object *get_local_shape() const;
Object *get_collider() const;
ObjectID get_collider_id() const;
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index ba62941d3a..cb918ecb8b 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -90,9 +90,9 @@ bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toler
}
#endif
-void Polygon2D::_validate_property(PropertyInfo &property) const {
- if (!invert && property.name == "invert_border") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Polygon2D::_validate_property(PropertyInfo &p_property) const {
+ if (!invert && p_property.name == "invert_border") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h
index d6a1be0f6d..d333152f62 100644
--- a/scene/2d/polygon_2d.h
+++ b/scene/2d/polygon_2d.h
@@ -77,7 +77,7 @@ class Polygon2D : public Node2D {
protected:
void _notification(int p_what);
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
#ifdef TOOLS_ENABLED
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 68e5ffdcf9..c4036faa79 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -82,6 +82,10 @@ Object *RayCast2D::get_collider() const {
return ObjectDB::get_instance(against);
}
+RID RayCast2D::get_collider_rid() const {
+ return against_rid;
+}
+
int RayCast2D::get_collider_shape() const {
return against_shape;
}
@@ -203,12 +207,14 @@ void RayCast2D::_update_raycast_state() {
if (dss->intersect_ray(ray_params, rr)) {
collided = true;
against = rr.collider_id;
+ against_rid = rr.rid;
collision_point = rr.position;
collision_normal = rr.normal;
against_shape = rr.shape;
} else {
collided = false;
against = ObjectID();
+ against_rid = RID();
against_shape = 0;
}
@@ -321,6 +327,7 @@ void RayCast2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast2D::force_raycast_update);
ClassDB::bind_method(D_METHOD("get_collider"), &RayCast2D::get_collider);
+ ClassDB::bind_method(D_METHOD("get_collider_rid"), &RayCast2D::get_collider_rid);
ClassDB::bind_method(D_METHOD("get_collider_shape"), &RayCast2D::get_collider_shape);
ClassDB::bind_method(D_METHOD("get_collision_point"), &RayCast2D::get_collision_point);
ClassDB::bind_method(D_METHOD("get_collision_normal"), &RayCast2D::get_collision_normal);
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h
index 1fb97d89fe..57f993fe8d 100644
--- a/scene/2d/ray_cast_2d.h
+++ b/scene/2d/ray_cast_2d.h
@@ -41,6 +41,7 @@ class RayCast2D : public Node2D {
bool enabled = true;
bool collided = false;
ObjectID against;
+ RID against_rid;
int against_shape = 0;
Vector2 collision_point;
Vector2 collision_normal;
@@ -91,6 +92,7 @@ public:
bool is_colliding() const;
Object *get_collider() const;
+ RID get_collider_rid() const;
int get_collider_shape() const;
Vector2 get_collision_point() const;
Vector2 get_collision_normal() const;
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index b3062ca02a..e1983f9cb9 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -368,19 +368,19 @@ Rect2 Sprite2D::get_rect() const {
return Rect2(ofs, s);
}
-void Sprite2D::_validate_property(PropertyInfo &property) const {
- if (property.name == "frame") {
- property.hint = PROPERTY_HINT_RANGE;
- property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+void Sprite2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "frame") {
+ p_property.hint = PROPERTY_HINT_RANGE;
+ p_property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
- if (property.name == "frame_coords") {
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ if (p_property.name == "frame_coords") {
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
- if (!region_enabled && (property.name == "region_rect" || property.name == "region_filter_clip")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (!region_enabled && (p_property.name == "region_rect" || p_property.name == "region_filter_clip")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h
index 5b33bb6802..60f5940cfe 100644
--- a/scene/2d/sprite_2d.h
+++ b/scene/2d/sprite_2d.h
@@ -64,7 +64,7 @@ protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
#ifdef TOOLS_ENABLED
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 5ba8c95a06..13bdd2bd5f 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -2063,6 +2063,18 @@ int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bo
return E->value.alternative_tile;
}
+TileData *TileMap::get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
+ int source_id = get_cell_source_id(p_layer, p_coords, p_use_proxies);
+ ERR_FAIL_COND_V_MSG(source_id == TileSet::INVALID_SOURCE, nullptr, vformat("Invalid TileSetSource at cell %s. Make sure a tile exists at this cell.", p_coords));
+
+ Ref<TileSetAtlasSource> source = tile_set->get_source(source_id);
+ if (source.is_valid()) {
+ return source->get_tile_data(get_cell_atlas_coords(p_layer, p_coords, p_use_proxies), get_cell_alternative_tile(p_layer, p_coords, p_use_proxies));
+ }
+
+ return nullptr;
+}
+
Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) {
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr);
ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr);
@@ -3846,9 +3858,10 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cell", "layer", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0));
ClassDB::bind_method(D_METHOD("erase_cell", "layer", "coords"), &TileMap::erase_cell);
- ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id);
- ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "layer", "coords", "use_proxies"), &TileMap::get_cell_atlas_coords);
- ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "layer", "coords", "use_proxies"), &TileMap::get_cell_alternative_tile);
+ ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "layer", "coords", "use_proxies"), &TileMap::get_cell_atlas_coords, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "layer", "coords", "use_proxies"), &TileMap::get_cell_alternative_tile, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_cell_tile_data", "layer", "coords", "use_proxies"), &TileMap::get_cell_tile_data, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_coords_for_body_rid", "body"), &TileMap::get_coords_for_body_rid);
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 012bf01df9..ecc6ee1d59 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -343,6 +343,8 @@ public:
int get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
int get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
+ // Helper method to make accessing the data easier.
+ TileData *get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
// Patterns.
Ref<TileMapPattern> get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array);
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index e9e19488e9..db7c3233f6 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -598,8 +598,8 @@ float Area3D::get_reverb_uniformity() const {
return reverb_uniformity;
}
-void Area3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "audio_bus_name" || property.name == "reverb_bus_name") {
+void Area3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "audio_bus_name" || p_property.name == "reverb_bus_name") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0) {
@@ -609,32 +609,30 @@ void Area3D::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
- } else if (property.name.begins_with("gravity") && property.name != "gravity_space_override") {
+ p_property.hint_string = options;
+ } else if (p_property.name.begins_with("gravity") && p_property.name != "gravity_space_override") {
if (gravity_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
} else {
if (gravity_is_point) {
- if (property.name == "gravity_direction") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "gravity_direction") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
} else {
- if (property.name.begins_with("gravity_point_")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with("gravity_point_")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
- } else if (property.name.begins_with("linear_damp") && property.name != "linear_damp_space_override") {
+ } else if (p_property.name.begins_with("linear_damp") && p_property.name != "linear_damp_space_override") {
if (linear_damp_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- } else if (property.name.begins_with("angular_damp") && property.name != "angular_damp_space_override") {
+ } else if (p_property.name.begins_with("angular_damp") && p_property.name != "angular_damp_space_override") {
if (angular_damp_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
-
- CollisionObject3D::_validate_property(property);
}
void Area3D::_bind_methods() {
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 3b892baf57..48364739b7 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -141,7 +141,7 @@ private:
float reverb_amount = 0.0;
float reverb_uniformity = 0.0;
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _initialize_wind();
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 65b00742ee..93e91f9b5b 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -648,8 +648,8 @@ bool AudioStreamPlayer3D::_is_active() const {
return active.is_set();
}
-void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "bus") {
+void AudioStreamPlayer3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "bus") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0) {
@@ -659,10 +659,8 @@ void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
+ p_property.hint_string = options;
}
-
- Node3D::_validate_property(property);
}
void AudioStreamPlayer3D::_bus_layout_changed() {
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 647b18a4a7..ef48269544 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -120,7 +120,7 @@ private:
float cached_global_panning_strength = 1.0f;
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index fbd5b5b65b..b3ff6497a7 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -30,8 +30,8 @@
#include "bone_attachment_3d.h"
-void BoneAttachment3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "bone_name") {
+void BoneAttachment3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "bone_name") {
// Because it is a constant function, we cannot use the _get_skeleton_3d function.
const Skeleton3D *parent = nullptr;
if (use_external_skeleton) {
@@ -51,15 +51,13 @@ void BoneAttachment3D::_validate_property(PropertyInfo &property) const {
names += parent->get_bone_name(i);
}
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = names;
+ p_property.hint = PROPERTY_HINT_ENUM;
+ p_property.hint_string = names;
} else {
- property.hint = PROPERTY_HINT_NONE;
- property.hint_string = "";
+ p_property.hint = PROPERTY_HINT_NONE;
+ p_property.hint_string = "";
}
}
-
- Node3D::_validate_property(property);
}
bool BoneAttachment3D::_set(const StringName &p_path, const Variant &p_value) {
diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h
index 3224361a25..f85053e614 100644
--- a/scene/3d/bone_attachment_3d.h
+++ b/scene/3d/bone_attachment_3d.h
@@ -64,7 +64,7 @@ class BoneAttachment3D : public Node3D {
Skeleton3D *_get_skeleton3d();
protected:
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
void _get_property_list(List<PropertyInfo> *p_list) const;
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index f654373ee5..e07f89fc65 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -71,8 +71,6 @@ void Camera3D::_validate_property(PropertyInfo &p_property) const {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
-
- Node3D::_validate_property(p_property);
}
void Camera3D::_update_camera() {
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index cedd976890..1a00017b0b 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -99,7 +99,7 @@ protected:
void _update_camera_mode();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &p_property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 9a5d4f5480..22de9a47a2 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -183,6 +183,17 @@ bool CollisionObject3D::get_collision_mask_value(int p_layer_number) const {
return get_collision_mask() & (1 << (p_layer_number - 1));
}
+void CollisionObject3D::set_collision_priority(real_t p_priority) {
+ collision_priority = p_priority;
+ if (!area) {
+ PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), p_priority);
+ }
+}
+
+real_t CollisionObject3D::get_collision_priority() const {
+ return collision_priority;
+}
+
void CollisionObject3D::set_disable_mode(DisableMode p_mode) {
if (disable_mode == p_mode) {
return;
@@ -432,6 +443,8 @@ void CollisionObject3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CollisionObject3D::get_collision_layer_value);
ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CollisionObject3D::set_collision_mask_value);
ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CollisionObject3D::get_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &CollisionObject3D::set_collision_priority);
+ ClassDB::bind_method(D_METHOD("get_collision_priority"), &CollisionObject3D::get_collision_priority);
ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject3D::set_disable_mode);
ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject3D::get_disable_mode);
ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &CollisionObject3D::set_ray_pickable);
@@ -466,6 +479,7 @@ void CollisionObject3D::_bind_methods() {
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority");
ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_ray_pickable"), "set_ray_pickable", "is_ray_pickable");
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index 3ec3aa0fc1..3f0d070db4 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -47,6 +47,7 @@ public:
private:
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
+ real_t collision_priority = 1.0;
bool area = false;
@@ -125,6 +126,9 @@ public:
void set_collision_mask_value(int p_layer_number, bool p_value);
bool get_collision_mask_value(int p_layer_number) const;
+ void set_collision_priority(real_t p_priority);
+ real_t get_collision_priority() const;
+
void set_disable_mode(DisableMode p_mode);
DisableMode get_disable_mode() const;
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 4df0c37ad6..a79fd15b1a 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -516,36 +516,34 @@ bool CPUParticles3D::get_split_scale() {
return split_scale;
}
-void CPUParticles3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
- property.usage = PROPERTY_USAGE_NONE;
+void CPUParticles3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if ((property.name == "emission_point_texture" || property.name == "emission_color_texture" || property.name == "emission_points") && (emission_shape != EMISSION_SHAPE_POINTS && (emission_shape != EMISSION_SHAPE_DIRECTED_POINTS))) {
- property.usage = PROPERTY_USAGE_NONE;
+ if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture" || p_property.name == "emission_points") && (emission_shape != EMISSION_SHAPE_POINTS && (emission_shape != EMISSION_SHAPE_DIRECTED_POINTS))) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("scale_curve_") && !split_scale) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("scale_curve_") && !split_scale) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
-
- Node3D::_validate_property(property);
}
static uint32_t idhash(uint32_t x) {
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index e26c301038..d84b0aedd2 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -198,7 +198,7 @@ private:
protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
AABB get_aabb() const override;
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index 0112f24e0c..460402ad1d 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -152,11 +152,10 @@ AABB Decal::get_aabb() const {
return aabb;
}
-void Decal::_validate_property(PropertyInfo &property) const {
- if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_length")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Decal::_validate_property(PropertyInfo &p_property) const {
+ if (!distance_fade_enabled && (p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_length")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- VisualInstance3D::_validate_property(property);
}
TypedArray<String> Decal::get_configuration_warnings() const {
diff --git a/scene/3d/decal.h b/scene/3d/decal.h
index 38da4c14e3..1a7d55b108 100644
--- a/scene/3d/decal.h
+++ b/scene/3d/decal.h
@@ -62,7 +62,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
virtual TypedArray<String> get_configuration_warnings() const override;
diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp
index 1b329143b6..319129603e 100644
--- a/scene/3d/fog_volume.cpp
+++ b/scene/3d/fog_volume.cpp
@@ -45,12 +45,11 @@ void FogVolume::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "FogMaterial,ShaderMaterial"), "set_material", "get_material");
}
-void FogVolume::_validate_property(PropertyInfo &property) const {
- if (property.name == "extents" && shape == RS::FOG_VOLUME_SHAPE_WORLD) {
- property.usage = PROPERTY_USAGE_NONE;
+void FogVolume::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "extents" && shape == RS::FOG_VOLUME_SHAPE_WORLD) {
+ p_property.usage = PROPERTY_USAGE_NONE;
return;
}
- VisualInstance3D::_validate_property(property);
}
void FogVolume::set_extents(const Vector3 &p_extents) {
diff --git a/scene/3d/fog_volume.h b/scene/3d/fog_volume.h
index 556a92ad3f..fcdc1e2807 100644
--- a/scene/3d/fog_volume.h
+++ b/scene/3d/fog_volume.h
@@ -49,7 +49,7 @@ class FogVolume : public VisualInstance3D {
protected:
_FORCE_INLINE_ RID _get_volume() { return volume; }
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_extents(const Vector3 &p_extents);
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index 2ee126e161..b46e6a8b71 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -376,16 +376,14 @@ AABB GPUParticles3D::capture_aabb() const {
return RS::get_singleton()->particles_get_current_aabb(particles);
}
-void GPUParticles3D::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("draw_pass_")) {
- int index = property.name.get_slicec('_', 2).to_int() - 1;
+void GPUParticles3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("draw_pass_")) {
+ int index = p_property.name.get_slicec('_', 2).to_int() - 1;
if (index >= draw_passes.size()) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
return;
}
}
-
- GeometryInstance3D::_validate_property(property);
}
void GPUParticles3D::emit_particle(const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index 0c745dd734..2ad9672474 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -94,7 +94,7 @@ private:
protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
AABB get_aabb() const override;
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index 712a37e745..f2d3dda792 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -162,9 +162,19 @@ void Label3D::_bind_methods() {
BIND_ENUM_CONSTANT(ALPHA_CUT_OPAQUE_PREPASS);
}
-void Label3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "material_override" || property.name == "material_overlay") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Label3D::_validate_property(PropertyInfo &p_property) const {
+ if (
+ p_property.name == "material_override" ||
+ p_property.name == "material_overlay" ||
+ p_property.name == "lod_bias" ||
+ p_property.name == "gi_mode" ||
+ p_property.name == "gi_lightmap_scale") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
+ if (p_property.name == "cast_shadow" && alpha_cut == ALPHA_CUT_DISABLED) {
+ // Alpha-blended materials can't cast shadows.
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -889,6 +899,7 @@ void Label3D::set_alpha_cut_mode(AlphaCutMode p_mode) {
if (alpha_cut != p_mode) {
alpha_cut = p_mode;
_queue_update();
+ notify_property_list_changed();
}
}
@@ -927,7 +938,12 @@ Label3D::Label3D() {
mesh = RenderingServer::get_singleton()->mesh_create();
+ // Disable shadow casting by default to improve performance and avoid unintended visual artifacts.
set_cast_shadows_setting(SHADOW_CASTING_SETTING_OFF);
+
+ // Label3D can't contribute to GI in any way, so disable it to improve performance.
+ set_gi_mode(GI_MODE_DISABLED);
+
set_base(mesh);
}
diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h
index 4498e89517..3c9a758e6e 100644
--- a/scene/3d/label_3d.h
+++ b/scene/3d/label_3d.h
@@ -55,7 +55,7 @@ public:
};
private:
- real_t pixel_size = 0.01;
+ real_t pixel_size = 0.005;
bool flags[FLAG_MAX] = {};
AlphaCutMode alpha_cut = ALPHA_CUT_DISABLED;
float alpha_scissor_threshold = 0.5;
@@ -109,7 +109,7 @@ private:
TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_OFF;
float width = 500.0;
- int font_size = 16;
+ int font_size = 32;
Ref<Font> font_override;
mutable Ref<Font> theme_font;
Color modulate = Color(1, 1, 1, 1);
@@ -117,7 +117,7 @@ private:
int outline_render_priority = -1;
int render_priority = 0;
- int outline_size = 0;
+ int outline_size = 12;
Color outline_modulate = Color(0, 0, 0, 1);
float line_spacing = 0.f;
@@ -149,7 +149,7 @@ protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _im_update();
void _font_changed();
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index 53c072c318..0581544e07 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -223,21 +223,19 @@ bool Light3D::is_editor_only() const {
return editor_only;
}
-void Light3D::_validate_property(PropertyInfo &property) const {
- if (!shadow && (property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_opacity" || property.name == "shadow_blur" || property.name == "distance_fade_shadow")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Light3D::_validate_property(PropertyInfo &p_property) const {
+ if (!shadow && (p_property.name == "shadow_bias" || p_property.name == "shadow_normal_bias" || p_property.name == "shadow_reverse_cull_face" || p_property.name == "shadow_transmittance_bias" || p_property.name == "shadow_fog_fade" || p_property.name == "shadow_opacity" || p_property.name == "shadow_blur" || p_property.name == "distance_fade_shadow")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (get_light_type() != RS::LIGHT_DIRECTIONAL && property.name == "light_angular_distance") {
+ if (get_light_type() != RS::LIGHT_DIRECTIONAL && p_property.name == "light_angular_distance") {
// Angular distance is only used in DirectionalLight3D.
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (!distance_fade_enabled && (p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_shadow" || p_property.name == "distance_fade_length")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
-
- VisualInstance3D::_validate_property(property);
}
void Light3D::_bind_methods() {
@@ -429,29 +427,27 @@ DirectionalLight3D::SkyMode DirectionalLight3D::get_sky_mode() const {
return sky_mode;
}
-void DirectionalLight3D::_validate_property(PropertyInfo &property) const {
- if (shadow_mode == SHADOW_ORTHOGONAL && (property.name == "directional_shadow_split_1" || property.name == "directional_shadow_blend_splits")) {
+void DirectionalLight3D::_validate_property(PropertyInfo &p_property) const {
+ if (shadow_mode == SHADOW_ORTHOGONAL && (p_property.name == "directional_shadow_split_1" || p_property.name == "directional_shadow_blend_splits")) {
// Split 2 and split blending are only used with the PSSM 2 Splits and PSSM 4 Splits shadow modes.
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if ((shadow_mode == SHADOW_ORTHOGONAL || shadow_mode == SHADOW_PARALLEL_2_SPLITS) && (property.name == "directional_shadow_split_2" || property.name == "directional_shadow_split_3")) {
+ if ((shadow_mode == SHADOW_ORTHOGONAL || shadow_mode == SHADOW_PARALLEL_2_SPLITS) && (p_property.name == "directional_shadow_split_2" || p_property.name == "directional_shadow_split_3")) {
// Splits 3 and 4 are only used with the PSSM 4 Splits shadow mode.
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "light_size" || property.name == "light_projector" || property.name == "light_specular") {
+ if (p_property.name == "light_size" || p_property.name == "light_projector" || p_property.name == "light_specular") {
// Not implemented in DirectionalLight3D (`light_size` is replaced by `light_angular_distance`).
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "distance_fade_enabled" || property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length") {
+ if (p_property.name == "distance_fade_enabled" || p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_shadow" || p_property.name == "distance_fade_length") {
// Not relevant for DirectionalLight3D, as the light LOD system only pertains to point lights.
// For DirectionalLight3D, `directional_shadow_max_distance` can be used instead.
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
-
- Light3D::_validate_property(property);
}
void DirectionalLight3D::_bind_methods() {
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index ef003e133d..035ba50e42 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -93,7 +93,7 @@ protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
Light3D(RenderingServer::LightType p_type);
@@ -171,7 +171,7 @@ private:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_shadow_mode(ShadowMode p_mode);
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 6b6a2eff9e..7efda6db32 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1410,17 +1410,16 @@ LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const {
return gen_probes;
}
-void LightmapGI::_validate_property(PropertyInfo &property) const {
- if (property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
- property.usage = PROPERTY_USAGE_NONE;
+void LightmapGI::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "environment_custom_color" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "environment_custom_color" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "environment_custom_energy" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "environment_custom_energy" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- VisualInstance3D::_validate_property(property);
}
void LightmapGI::_bind_methods() {
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index 85150b833f..87add9facc 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -216,7 +216,7 @@ private:
void _gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool> &positions_used, const AABB &p_bounds);
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
void _notification(int p_what);
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
index 0316fc37a8..7f6af668b6 100644
--- a/scene/3d/navigation_obstacle_3d.h
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -45,7 +45,7 @@ class NavigationObstacle3D : public Node {
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &p_property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
public:
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 1edeff034d..29ad1ba93d 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -363,6 +363,12 @@ NavigationRegion3D::~NavigationRegion3D() {
#ifdef DEBUG_ENABLED
void NavigationRegion3D::_update_debug_mesh() {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // don't update inside Editor as node 3d gizmo takes care of this
+ // as collisions and selections for Editor Viewport need to be updated
+ return;
+ }
+
if (!NavigationServer3D::get_singleton()->get_debug_enabled()) {
if (debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_instance, false);
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 1de85d57a3..ec60c8fdc2 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -879,25 +879,25 @@ NodePath Node3D::get_visibility_parent() const {
return visibility_parent_path;
}
-void Node3D::_validate_property(PropertyInfo &property) const {
- if (data.rotation_edit_mode != ROTATION_EDIT_MODE_BASIS && property.name == "basis") {
- property.usage = 0;
+void Node3D::_validate_property(PropertyInfo &p_property) const {
+ if (data.rotation_edit_mode != ROTATION_EDIT_MODE_BASIS && p_property.name == "basis") {
+ p_property.usage = 0;
}
- if (data.rotation_edit_mode == ROTATION_EDIT_MODE_BASIS && property.name == "scale") {
- property.usage = 0;
+ if (data.rotation_edit_mode == ROTATION_EDIT_MODE_BASIS && p_property.name == "scale") {
+ p_property.usage = 0;
}
- if (data.rotation_edit_mode != ROTATION_EDIT_MODE_QUATERNION && property.name == "quaternion") {
- property.usage = 0;
+ if (data.rotation_edit_mode != ROTATION_EDIT_MODE_QUATERNION && p_property.name == "quaternion") {
+ p_property.usage = 0;
}
- if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && property.name == "rotation") {
- property.usage = 0;
+ if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && p_property.name == "rotation") {
+ p_property.usage = 0;
}
- if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && property.name == "rotation_order") {
- property.usage = 0;
+ if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && p_property.name == "rotation_order") {
+ p_property.usage = 0;
}
}
-bool Node3D::property_can_revert(const String &p_name) {
+bool Node3D::_property_can_revert(const StringName &p_name) const {
if (p_name == "basis") {
return true;
} else if (p_name == "scale") {
@@ -912,47 +912,48 @@ bool Node3D::property_can_revert(const String &p_name) {
return false;
}
-Variant Node3D::property_get_revert(const String &p_name) {
- Variant r_ret;
+bool Node3D::_property_get_revert(const StringName &p_name, Variant &r_property) const {
bool valid = false;
if (p_name == "basis") {
Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid);
if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) {
- r_ret = Transform3D(variant).get_basis();
+ r_property = Transform3D(variant).get_basis();
} else {
- r_ret = Basis();
+ r_property = Basis();
}
} else if (p_name == "scale") {
Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid);
if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) {
- r_ret = Transform3D(variant).get_basis().get_scale();
+ r_property = Transform3D(variant).get_basis().get_scale();
} else {
- return Vector3(1.0, 1.0, 1.0);
+ r_property = Vector3(1.0, 1.0, 1.0);
}
} else if (p_name == "quaternion") {
Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid);
if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) {
- r_ret = Quaternion(Transform3D(variant).get_basis().get_rotation_quaternion());
+ r_property = Quaternion(Transform3D(variant).get_basis().get_rotation_quaternion());
} else {
- return Quaternion();
+ r_property = Quaternion();
}
} else if (p_name == "rotation") {
Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid);
if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) {
- r_ret = Transform3D(variant).get_basis().get_euler_normalized(data.euler_rotation_order);
+ r_property = Transform3D(variant).get_basis().get_euler_normalized(data.euler_rotation_order);
} else {
- return Vector3();
+ r_property = Vector3();
}
} else if (p_name == "position") {
Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid);
if (valid) {
- r_ret = Transform3D(variant).get_origin();
+ r_property = Transform3D(variant).get_origin();
} else {
- return Vector3();
+ r_property = Vector3();
}
+ } else {
+ return false;
}
- return r_ret;
+ return true;
}
void Node3D::_bind_methods() {
@@ -1032,9 +1033,6 @@ void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node3D::to_local);
ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node3D::to_global);
- ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &Node3D::property_can_revert);
- ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &Node3D::property_get_revert);
-
BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
BIND_CONSTANT(NOTIFICATION_ENTER_WORLD);
BIND_CONSTANT(NOTIFICATION_EXIT_WORLD);
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index b1e129798d..2757f9e9ed 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -155,10 +155,10 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
- bool property_can_revert(const String &p_name);
- Variant property_get_revert(const String &p_name);
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
public:
enum {
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 25226ad384..8c4e5c5275 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -330,16 +330,15 @@ bool PathFollow3D::get_cubic_interpolation() const {
return cubic;
}
-void PathFollow3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "offset") {
+void PathFollow3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "offset") {
real_t max = 10000;
if (path && path->get_curve().is_valid()) {
max = path->get_curve()->get_baked_length();
}
- property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
+ p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
}
- Node3D::_validate_property(property);
}
TypedArray<String> PathFollow3D::get_configuration_warnings() const {
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
index b4cc6db7e3..bc4db61a01 100644
--- a/scene/3d/path_3d.h
+++ b/scene/3d/path_3d.h
@@ -85,7 +85,7 @@ private:
void _update_transform(bool p_update_xyz_rot = true);
protected:
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 993608c306..515665bde6 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -1124,13 +1124,12 @@ void RigidDynamicBody3D::_bind_methods() {
BIND_ENUM_CONSTANT(DAMP_MODE_REPLACE);
}
-void RigidDynamicBody3D::_validate_property(PropertyInfo &property) const {
+void RigidDynamicBody3D::_validate_property(PropertyInfo &p_property) const {
if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) {
- if (property.name == "center_of_mass") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "center_of_mass") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- PhysicsBody3D::_validate_property(property);
}
RigidDynamicBody3D::RigidDynamicBody3D() :
@@ -2022,13 +2021,12 @@ void CharacterBody3D::_bind_methods() {
BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER);
}
-void CharacterBody3D::_validate_property(PropertyInfo &property) const {
+void CharacterBody3D::_validate_property(PropertyInfo &p_property) const {
if (motion_mode == MOTION_MODE_FLOATING) {
- if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with("floor_") || p_property.name == "up_direction" || p_property.name == "slide_on_ceiling") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- PhysicsBody3D::_validate_property(property);
}
CharacterBody3D::CharacterBody3D() :
@@ -2057,6 +2055,10 @@ int KinematicCollision3D::get_collision_count() const {
return result.collision_count;
}
+real_t KinematicCollision3D::get_depth() const {
+ return result.collision_depth;
+}
+
Vector3 KinematicCollision3D::get_position(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3());
return result.collisions[p_collision_index].position;
@@ -2127,6 +2129,7 @@ Vector3 KinematicCollision3D::get_collider_velocity(int p_collision_index) const
void KinematicCollision3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision3D::get_travel);
ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision3D::get_remainder);
+ ClassDB::bind_method(D_METHOD("get_depth"), &KinematicCollision3D::get_depth);
ClassDB::bind_method(D_METHOD("get_collision_count"), &KinematicCollision3D::get_collision_count);
ClassDB::bind_method(D_METHOD("get_position", "collision_index"), &KinematicCollision3D::get_position, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_normal", "collision_index"), &KinematicCollision3D::get_normal, DEFVAL(0));
@@ -3412,6 +3415,7 @@ void PhysicalBone3D::_start_physics_simulation() {
set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
+ PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority());
PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
set_as_top_level(true);
_internal_simulate_physics = true;
@@ -3425,10 +3429,12 @@ void PhysicalBone3D::_stop_physics_simulation() {
set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
+ PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority());
} else {
set_body_mode(PhysicsServer3D::BODY_MODE_STATIC);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), 0);
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0);
+ PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), 1.0);
}
if (_internal_simulate_physics) {
PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr);
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index e4a41be6c0..5d466f7e3c 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -226,7 +226,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *)
@@ -483,7 +483,7 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
};
VARIANT_ENUM_CAST(CharacterBody3D::MotionMode);
@@ -504,6 +504,7 @@ public:
Vector3 get_travel() const;
Vector3 get_remainder() const;
int get_collision_count() const;
+ real_t get_depth() const;
Vector3 get_position(int p_collision_index = 0) const;
Vector3 get_normal(int p_collision_index = 0) const;
real_t get_angle(int p_collision_index = 0, const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index 2db5ab2d4e..a45ef52452 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -88,6 +88,10 @@ Object *RayCast3D::get_collider() const {
return ObjectDB::get_instance(against);
}
+RID RayCast3D::get_collider_rid() const {
+ return against_rid;
+}
+
int RayCast3D::get_collider_shape() const {
return against_shape;
}
@@ -224,12 +228,14 @@ void RayCast3D::_update_raycast_state() {
if (dss->intersect_ray(ray_params, rr)) {
collided = true;
against = rr.collider_id;
+ against_rid = rr.rid;
collision_point = rr.position;
collision_normal = rr.normal;
against_shape = rr.shape;
} else {
collided = false;
against = ObjectID();
+ against_rid = RID();
against_shape = 0;
}
}
@@ -302,6 +308,7 @@ void RayCast3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast3D::force_raycast_update);
ClassDB::bind_method(D_METHOD("get_collider"), &RayCast3D::get_collider);
+ ClassDB::bind_method(D_METHOD("get_collider_rid"), &RayCast3D::get_collider_rid);
ClassDB::bind_method(D_METHOD("get_collider_shape"), &RayCast3D::get_collider_shape);
ClassDB::bind_method(D_METHOD("get_collision_point"), &RayCast3D::get_collision_point);
ClassDB::bind_method(D_METHOD("get_collision_normal"), &RayCast3D::get_collision_normal);
diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h
index aa62f6927e..eb5c3ee90a 100644
--- a/scene/3d/ray_cast_3d.h
+++ b/scene/3d/ray_cast_3d.h
@@ -41,6 +41,7 @@ class RayCast3D : public Node3D {
bool enabled = true;
bool collided = false;
ObjectID against;
+ RID against_rid;
int against_shape = 0;
Vector3 collision_point;
Vector3 collision_normal;
@@ -113,6 +114,7 @@ public:
void force_raycast_update();
bool is_colliding() const;
Object *get_collider() const;
+ RID get_collider_rid() const;
int get_collider_shape() const;
Vector3 get_collision_point() const;
Vector3 get_collision_normal() const;
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index 0a9d6cbbeb..bc3cc31963 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -178,13 +178,12 @@ AABB ReflectionProbe::get_aabb() const {
return aabb;
}
-void ReflectionProbe::_validate_property(PropertyInfo &property) const {
- if (property.name == "interior/ambient_color" || property.name == "interior/ambient_color_energy") {
+void ReflectionProbe::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "ambient_color" || p_property.name == "ambient_color_energy") {
if (ambient_mode != AMBIENT_COLOR) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- VisualInstance3D::_validate_property(property);
}
void ReflectionProbe::_bind_methods() {
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index a161717ece..5a5a3fe0bb 100644
--- a/scene/3d/reflection_probe.h
+++ b/scene/3d/reflection_probe.h
@@ -67,7 +67,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_intensity(float p_intensity);
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 4c38fccc8b..0cd7188c23 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -176,39 +176,37 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-void Skeleton3D::_validate_property(PropertyInfo &property) const {
- PackedStringArray split = property.name.split("/");
+void Skeleton3D::_validate_property(PropertyInfo &p_property) const {
+ PackedStringArray split = p_property.name.split("/");
if (split.size() == 3 && split[0] == "bones") {
if (split[2] == "rest") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (is_show_rest_only()) {
if (split[2] == "enabled") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "position") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "rotation") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "scale") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
} else if (!is_bone_enabled(split[1].to_int())) {
if (split[2] == "position") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "rotation") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "scale") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
}
-
- Node3D::_validate_property(property);
}
void Skeleton3D::_update_process_order() {
@@ -762,6 +760,20 @@ Vector3 Skeleton3D::get_bone_pose_scale(int p_bone) const {
return bones[p_bone].pose_scale;
}
+void Skeleton3D::reset_bone_pose(int p_bone) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
+ set_bone_pose_position(p_bone, bones[p_bone].rest.origin);
+ set_bone_pose_rotation(p_bone, bones[p_bone].rest.basis.get_rotation_quaternion());
+ set_bone_pose_scale(p_bone, bones[p_bone].rest.basis.get_scale());
+}
+
+void Skeleton3D::reset_bone_poses() {
+ for (int i = 0; i < bones.size(); i++) {
+ reset_bone_pose(i);
+ }
+}
+
Transform3D Skeleton3D::get_bone_pose(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
@@ -1252,6 +1264,9 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_pose_rotation", "bone_idx"), &Skeleton3D::get_bone_pose_rotation);
ClassDB::bind_method(D_METHOD("get_bone_pose_scale", "bone_idx"), &Skeleton3D::get_bone_pose_scale);
+ ClassDB::bind_method(D_METHOD("reset_bone_pose", "bone_idx"), &Skeleton3D::reset_bone_pose);
+ ClassDB::bind_method(D_METHOD("reset_bone_poses"), &Skeleton3D::reset_bone_poses);
+
ClassDB::bind_method(D_METHOD("is_bone_enabled", "bone_idx"), &Skeleton3D::is_bone_enabled);
ClassDB::bind_method(D_METHOD("set_bone_enabled", "bone_idx", "enabled"), &Skeleton3D::set_bone_enabled, DEFVAL(true));
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 8b69410a39..79feadf44f 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -156,7 +156,7 @@ protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
void _get_property_list(List<PropertyInfo> *p_list) const;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
@@ -227,6 +227,9 @@ public:
Quaternion get_bone_pose_rotation(int p_bone) const;
Vector3 get_bone_pose_scale(int p_bone) const;
+ void reset_bone_pose(int p_bone);
+ void reset_bone_poses();
+
void clear_bones_global_pose_override();
Transform3D get_bone_global_pose_override(int p_bone) const;
void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false);
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index 2182c5ba11..f0534c8099 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -329,8 +329,8 @@ void FabrikInverseKinematic::_update_chain(const Skeleton3D *p_sk, ChainItem *p_
}
}
-void SkeletonIK3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "root_bone" || property.name == "tip_bone") {
+void SkeletonIK3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "root_bone" || p_property.name == "tip_bone") {
if (skeleton) {
String names("--,");
for (int i = 0; i < skeleton->get_bone_count(); i++) {
@@ -340,15 +340,13 @@ void SkeletonIK3D::_validate_property(PropertyInfo &property) const {
names += skeleton->get_bone_name(i);
}
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = names;
+ p_property.hint = PROPERTY_HINT_ENUM;
+ p_property.hint_string = names;
} else {
- property.hint = PROPERTY_HINT_NONE;
- property.hint_string = "";
+ p_property.hint = PROPERTY_HINT_NONE;
+ p_property.hint_string = "";
}
}
-
- Node::_validate_property(property);
}
void SkeletonIK3D::_bind_methods() {
diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h
index 6ae86a2bf6..097df2c400 100644
--- a/scene/3d/skeleton_ik_3d.h
+++ b/scene/3d/skeleton_ik_3d.h
@@ -137,7 +137,7 @@ class SkeletonIK3D : public Node {
FabrikInverseKinematic::Task *task = nullptr;
protected:
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
virtual void _notification(int p_what);
diff --git a/scene/3d/soft_dynamic_body_3d.cpp b/scene/3d/soft_dynamic_body_3d.cpp
index 15f050defb..c9eafc77e0 100644
--- a/scene/3d/soft_dynamic_body_3d.cpp
+++ b/scene/3d/soft_dynamic_body_3d.cpp
@@ -88,10 +88,10 @@ void SoftDynamicBodyRenderingServerHandler::set_normal(int p_vertex_id, const vo
memcpy(&n, p_vector3, sizeof(Vector3));
n *= Vector3(0.5, 0.5, 0.5);
n += Vector3(0.5, 0.5, 0.5);
+ Vector2 res = n.octahedron_encode();
uint32_t value = 0;
- value |= CLAMP(int(n.x * 1023.0), 0, 1023);
- value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
memcpy(&write_buffer[p_vertex_id * stride + offset_normal], &value, sizeof(uint32_t));
}
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index ef2b9e1ce5..212d220ace 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -562,23 +562,21 @@ void Sprite3D::_draw() {
{
Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
+ Vector2 res = n.octahedron_encode();
uint32_t value = 0;
- value |= CLAMP(int(n.x * 1023.0), 0, 1023);
- value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
v_normal = value;
}
uint32_t v_tangent;
{
Plane t = tangent;
+ Vector2 res = t.normal.octahedron_tangent_encode(t.d);
uint32_t value = 0;
- value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023);
- value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
- if (t.d > 0) {
- value |= 3UL << 30;
- }
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
+
v_tangent = value;
}
@@ -751,18 +749,16 @@ Rect2 Sprite3D::get_item_rect() const {
return Rect2(ofs, s);
}
-void Sprite3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "frame") {
- property.hint = PROPERTY_HINT_RANGE;
- property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+void Sprite3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "frame") {
+ p_property.hint = PROPERTY_HINT_RANGE;
+ p_property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
- if (property.name == "frame_coords") {
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ if (p_property.name == "frame_coords") {
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
-
- SpriteBase3D::_validate_property(property);
}
void Sprite3D::_bind_methods() {
@@ -929,23 +925,20 @@ void AnimatedSprite3D::_draw() {
{
Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
+ Vector2 res = n.octahedron_encode();
uint32_t value = 0;
- value |= CLAMP(int(n.x * 1023.0), 0, 1023);
- value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
v_normal = value;
}
uint32_t v_tangent;
{
Plane t = tangent;
+ Vector2 res = t.normal.octahedron_tangent_encode(t.d);
uint32_t value = 0;
- value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023);
- value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
- if (t.d > 0) {
- value |= 3UL << 30;
- }
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
v_tangent = value;
}
@@ -1000,12 +993,12 @@ void AnimatedSprite3D::_draw() {
}
}
-void AnimatedSprite3D::_validate_property(PropertyInfo &property) const {
+void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const {
if (!frames.is_valid()) {
return;
}
- if (property.name == "animation") {
- property.hint = PROPERTY_HINT_ENUM;
+ if (p_property.name == "animation") {
+ p_property.hint = PROPERTY_HINT_ENUM;
List<StringName> names;
frames->get_animation_list(&names);
names.sort_custom<StringName::AlphCompare>();
@@ -1014,36 +1007,34 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &property) const {
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
if (E->prev()) {
- property.hint_string += ",";
+ p_property.hint_string += ",";
}
- property.hint_string += String(E->get());
+ p_property.hint_string += String(E->get());
if (animation == E->get()) {
current_found = true;
}
}
if (!current_found) {
- if (property.hint_string.is_empty()) {
- property.hint_string = String(animation);
+ if (p_property.hint_string.is_empty()) {
+ p_property.hint_string = String(animation);
} else {
- property.hint_string = String(animation) + "," + property.hint_string;
+ p_property.hint_string = String(animation) + "," + p_property.hint_string;
}
}
}
- if (property.name == "frame") {
- property.hint = PROPERTY_HINT_RANGE;
+ if (p_property.name == "frame") {
+ p_property.hint = PROPERTY_HINT_RANGE;
if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) {
- property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
+ p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
} else {
// Avoid an error, `hint_string` is required for `PROPERTY_HINT_RANGE`.
- property.hint_string = "0,0,1";
+ p_property.hint_string = "0,0,1";
}
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
-
- SpriteBase3D::_validate_property(property);
}
void AnimatedSprite3D::_notification(int p_what) {
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 6ac85a7bbc..03688cf787 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -174,7 +174,7 @@ protected:
virtual void _draw() override;
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_texture(const Ref<Texture2D> &p_texture);
@@ -229,7 +229,7 @@ protected:
virtual void _draw() override;
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
diff --git a/scene/3d/velocity_tracker_3d.h b/scene/3d/velocity_tracker_3d.h
index 6b27cdffc2..d3b92ab766 100644
--- a/scene/3d/velocity_tracker_3d.h
+++ b/scene/3d/velocity_tracker_3d.h
@@ -34,8 +34,6 @@
#include "scene/3d/node_3d.h"
class VelocityTracker3D : public RefCounted {
- GDCLASS(VelocityTracker3D, RefCounted);
-
struct PositionHistory {
uint64_t frame = 0;
Vector3 position;
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index 42a2a68e2d..9380d1cf32 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -323,8 +323,8 @@ Vector<Color> Voxelizer::_get_bake_texture(Ref<Image> p_image, const Color &p_co
}
Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material) {
- //this way of obtaining materials is inaccurate and also does not support some compressed formats very well
- Ref<StandardMaterial3D> mat = p_material;
+ // This way of obtaining materials is inaccurate and also does not support some compressed formats very well.
+ Ref<BaseMaterial3D> mat = p_material;
Ref<Material> material = mat; //hack for now
@@ -335,7 +335,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
MaterialCache mc;
if (mat.is_valid()) {
- Ref<Texture2D> albedo_tex = mat->get_texture(StandardMaterial3D::TEXTURE_ALBEDO);
+ Ref<Texture2D> albedo_tex = mat->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
Ref<Image> img_albedo;
if (albedo_tex.is_valid()) {
@@ -345,7 +345,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive
}
- Ref<Texture2D> emission_tex = mat->get_texture(StandardMaterial3D::TEXTURE_EMISSION);
+ Ref<Texture2D> emission_tex = mat->get_texture(BaseMaterial3D::TEXTURE_EMISSION);
Color emission_col = mat->get_emission();
float emission_energy = mat->get_emission_energy();
@@ -356,7 +356,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
img_emission = emission_tex->get_image();
}
- if (mat->get_emission_operator() == StandardMaterial3D::EMISSION_OP_ADD) {
+ if (mat->get_emission_operator() == BaseMaterial3D::EMISSION_OP_ADD) {
mc.emission = _get_bake_texture(img_emission, Color(1, 1, 1) * emission_energy, emission_col * emission_energy);
} else {
mc.emission = _get_bake_texture(img_emission, emission_col * emission_energy, Color(0, 0, 0));
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index 40a43043c6..de765d7ccb 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -244,27 +244,25 @@ void XRNode3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("trigger_haptic_pulse", "action_name", "frequency", "amplitude", "duration_sec", "delay_sec"), &XRNode3D::trigger_haptic_pulse);
};
-void XRNode3D::_validate_property(PropertyInfo &property) const {
+void XRNode3D::_validate_property(PropertyInfo &p_property) const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
- if (property.name == "tracker") {
+ if (p_property.name == "tracker") {
PackedStringArray names = xr_server->get_suggested_tracker_names();
String hint_string;
for (const String &name : names) {
hint_string += name + ",";
}
- property.hint_string = hint_string;
- } else if (property.name == "pose") {
+ p_property.hint_string = hint_string;
+ } else if (p_property.name == "pose") {
PackedStringArray names = xr_server->get_suggested_pose_names(tracker_name);
String hint_string;
for (const String &name : names) {
hint_string += name + ",";
}
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
-
- Node3D::_validate_property(property);
}
void XRNode3D::set_tracker(const StringName p_tracker_name) {
diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h
index 3079e20dc7..312bef7856 100644
--- a/scene/3d/xr_nodes.h
+++ b/scene/3d/xr_nodes.h
@@ -93,7 +93,7 @@ protected:
void _pose_changed(const Ref<XRPose> &p_pose);
public:
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void set_tracker(const StringName p_tracker_name);
StringName get_tracker() const;
diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp
index b42e426f51..f30aea3bdd 100644
--- a/scene/animation/animation_blend_space_1d.cpp
+++ b/scene/animation/animation_blend_space_1d.cpp
@@ -42,15 +42,14 @@ Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName
return get_blend_point_node(p_name.operator String().to_int());
}
-void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("blend_point_")) {
- String left = property.name.get_slicec('/', 0);
+void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("blend_point_")) {
+ String left = p_property.name.get_slicec('/', 0);
int idx = left.get_slicec('_', 2).to_int();
if (idx >= blend_points_used) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
- AnimationRootNode::_validate_property(property);
}
void AnimationNodeBlendSpace1D::_tree_changed() {
diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h
index 346e8a3a2f..1876ccebc7 100644
--- a/scene/animation/animation_blend_space_1d.h
+++ b/scene/animation/animation_blend_space_1d.h
@@ -65,7 +65,7 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
protected:
bool sync = false;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp
index 6b5851a977..2dc61efb94 100644
--- a/scene/animation/animation_blend_space_2d.cpp
+++ b/scene/animation/animation_blend_space_2d.cpp
@@ -566,18 +566,17 @@ String AnimationNodeBlendSpace2D::get_caption() const {
return "BlendSpace2D";
}
-void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &property) const {
- if (auto_triangles && property.name == "triangles") {
- property.usage = PROPERTY_USAGE_NONE;
+void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &p_property) const {
+ if (auto_triangles && p_property.name == "triangles") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("blend_point_")) {
- String left = property.name.get_slicec('/', 0);
+ if (p_property.name.begins_with("blend_point_")) {
+ String left = p_property.name.get_slicec('/', 0);
int idx = left.get_slicec('_', 2).to_int();
if (idx >= blend_points_used) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
- AnimationRootNode::_validate_property(property);
}
void AnimationNodeBlendSpace2D::set_auto_triangles(bool p_enable) {
diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h
index 689b96e356..250189f202 100644
--- a/scene/animation/animation_blend_space_2d.h
+++ b/scene/animation/animation_blend_space_2d.h
@@ -90,7 +90,7 @@ protected:
protected:
bool sync = false;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index fe2fb1b7a1..61f068408c 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -47,8 +47,8 @@ void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) cons
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
}
-void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const {
- if (property.name == "animation" && get_editable_animation_list) {
+void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "animation" && get_editable_animation_list) {
Vector<String> names = get_editable_animation_list();
String anims;
for (int i = 0; i < names.size(); i++) {
@@ -58,8 +58,8 @@ void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const {
anims += String(names[i]);
}
if (!anims.is_empty()) {
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = anims;
+ p_property.hint = PROPERTY_HINT_ENUM;
+ p_property.hint_string = anims;
}
}
}
@@ -676,12 +676,20 @@ String AnimationNodeTransition::get_input_caption(int p_input) const {
return inputs[p_input].name;
}
-void AnimationNodeTransition::set_cross_fade_time(float p_fade) {
- xfade = p_fade;
+void AnimationNodeTransition::set_xfade_time(float p_fade) {
+ xfade_time = p_fade;
}
-float AnimationNodeTransition::get_cross_fade_time() const {
- return xfade;
+float AnimationNodeTransition::get_xfade_time() const {
+ return xfade_time;
+}
+
+void AnimationNodeTransition::set_xfade_curve(const Ref<Curve> &p_curve) {
+ xfade_curve = p_curve;
+}
+
+Ref<Curve> AnimationNodeTransition::get_xfade_curve() const {
+ return xfade_curve;
}
void AnimationNodeTransition::set_from_start(bool p_from_start) {
@@ -707,7 +715,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
set_parameter(this->prev, prev_current);
prev = prev_current;
- prev_xfading = xfade;
+ prev_xfading = xfade_time;
time = 0;
switched = true;
}
@@ -734,13 +742,16 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
time += p_time;
}
- if (inputs[current].auto_advance && rem <= xfade) {
+ if (inputs[current].auto_advance && rem <= xfade_time) {
set_parameter(this->current, (current + 1) % enabled_inputs);
}
} else { // cross-fading from prev to current
- float blend = xfade == 0 ? 0 : (prev_xfading / xfade);
+ float blend = xfade_time == 0 ? 0 : (prev_xfading / xfade_time);
+ if (xfade_curve.is_valid()) {
+ blend = xfade_curve->interpolate(blend);
+ }
if (from_start && !p_seek && switched) { //just switched, seek to start of current
@@ -768,18 +779,16 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
return rem;
}
-void AnimationNodeTransition::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("input_")) {
- String n = property.name.get_slicec('/', 0).get_slicec('_', 1);
+void AnimationNodeTransition::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("input_")) {
+ String n = p_property.name.get_slicec('/', 0).get_slicec('_', 1);
if (n != "count") {
int idx = n.to_int();
if (idx >= enabled_inputs) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
-
- AnimationNode::_validate_property(property);
}
void AnimationNodeTransition::_bind_methods() {
@@ -792,14 +801,18 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
- ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time);
- ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time);
+ ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time);
+ ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time);
+
+ ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeTransition::set_xfade_curve);
+ ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeTransition::get_xfade_curve);
ClassDB::bind_method(D_METHOD("set_from_start", "from_start"), &AnimationNodeTransition::set_from_start);
ClassDB::bind_method(D_METHOD("is_from_start"), &AnimationNodeTransition::is_from_start);
ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_cross_fade_time", "get_cross_fade_time");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "from_start"), "set_from_start", "is_from_start");
for (int i = 0; i < MAX_INPUTS; i++) {
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index d35ff04f30..59c074cc80 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -67,7 +67,7 @@ public:
AnimationNodeAnimation();
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
private:
@@ -297,14 +297,15 @@ class AnimationNodeTransition : public AnimationNodeSync {
StringName current = PNAME("current");
StringName prev_current = "prev_current";
- float xfade = 0.0;
+ float xfade_time = 0.0;
+ Ref<Curve> xfade_curve;
bool from_start = true;
void _update_inputs();
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
@@ -321,8 +322,11 @@ public:
void set_input_caption(int p_input, const String &p_name);
String get_input_caption(int p_input) const;
- void set_cross_fade_time(float p_fade);
- float get_cross_fade_time() const;
+ void set_xfade_time(float p_fade);
+ float get_xfade_time() const;
+
+ void set_xfade_curve(const Ref<Curve> &p_curve);
+ Ref<Curve> get_xfade_curve() const;
void set_from_start(bool p_from_start);
bool is_from_start() const;
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 793967d9ad..4b3d7fd0a6 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -98,12 +98,20 @@ NodePath AnimationNodeStateMachineTransition::get_advance_expression_base_node()
void AnimationNodeStateMachineTransition::set_xfade_time(float p_xfade) {
ERR_FAIL_COND(p_xfade < 0);
- xfade = p_xfade;
+ xfade_time = p_xfade;
emit_changed();
}
float AnimationNodeStateMachineTransition::get_xfade_time() const {
- return xfade;
+ return xfade_time;
+}
+
+void AnimationNodeStateMachineTransition::set_xfade_curve(const Ref<Curve> &p_curve) {
+ xfade_curve = p_curve;
+}
+
+Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const {
+ return xfade_curve;
}
void AnimationNodeStateMachineTransition::set_disabled(bool p_disabled) {
@@ -137,6 +145,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_xfade_time", "secs"), &AnimationNodeStateMachineTransition::set_xfade_time);
ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeStateMachineTransition::get_xfade_time);
+ ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeStateMachineTransition::set_xfade_curve);
+ ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeStateMachineTransition::get_xfade_curve);
+
ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &AnimationNodeStateMachineTransition::set_disabled);
ClassDB::bind_method(D_METHOD("is_disabled"), &AnimationNodeStateMachineTransition::is_disabled);
@@ -150,6 +161,7 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_advance_expression_base_node"), &AnimationNodeStateMachineTransition::get_advance_expression_base_node);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority");
ADD_GROUP("Switch", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,At End"), "set_switch_mode", "get_switch_mode");
@@ -420,6 +432,9 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
}
+ if (current_curve.is_valid()) {
+ fade_blend = current_curve->interpolate(fade_blend);
+ }
float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_seek_root, fade_blend, AnimationNode::FILTER_IGNORE, true);
if (fading_from != StringName()) {
@@ -450,6 +465,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
if (p_state_machine->transitions[i].local_from == current && p_state_machine->transitions[i].local_to == path[0]) {
next_xfade = p_state_machine->transitions[i].transition->get_xfade_time();
+ current_curve = p_state_machine->transitions[i].transition->get_xfade_curve();
switch_mode = p_state_machine->transitions[i].transition->get_switch_mode();
next = path[0];
}
@@ -504,6 +520,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
tr.to = String(p_state_machine->transitions[auto_advance_to].to).replace_first("../", "");
tr.next = p_state_machine->transitions[auto_advance_to].to;
current_transition = tr;
+ current_curve = p_state_machine->transitions[auto_advance_to].transition->get_xfade_curve();
next_xfade = p_state_machine->transitions[auto_advance_to].transition->get_xfade_time();
switch_mode = p_state_machine->transitions[auto_advance_to].transition->get_switch_mode();
}
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index ead914db7a..ab78b1afe8 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -49,7 +49,8 @@ private:
bool auto_advance = false;
StringName advance_condition;
StringName advance_condition_name;
- float xfade = 0.0;
+ float xfade_time = 0.0;
+ Ref<Curve> xfade_curve;
bool disabled = false;
int priority = 1;
String advance_expression;
@@ -82,6 +83,9 @@ public:
void set_xfade_time(float p_xfade);
float get_xfade_time() const;
+ void set_xfade_curve(const Ref<Curve> &p_curve);
+ Ref<Curve> get_xfade_curve() const;
+
void set_disabled(bool p_disabled);
bool is_disabled() const;
@@ -117,6 +121,7 @@ class AnimationNodeStateMachinePlayback : public Resource {
StringName current;
Transition current_transition;
+ Ref<Curve> current_curve;
bool force_auto_advance = false;
StringName fading_from;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 09ec086564..48626ccc1b 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -37,6 +37,7 @@
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/2d/skeleton_2d.h"
void AnimatedValuesBackup::update_skeletons() {
@@ -174,8 +175,8 @@ bool AnimationPlayer::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
-void AnimationPlayer::_validate_property(PropertyInfo &property) const {
- if (property.name == "current_animation") {
+void AnimationPlayer::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "current_animation") {
List<String> names;
for (const KeyValue<StringName, AnimationData> &E : animation_set) {
@@ -191,10 +192,8 @@ void AnimationPlayer::_validate_property(PropertyInfo &property) const {
hint += E->get();
}
- property.hint_string = hint;
+ p_property.hint_string = hint;
}
-
- Node::_validate_property(property);
}
void AnimationPlayer::_get_property_list(List<PropertyInfo> *p_list) const {
@@ -323,10 +322,8 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
#endif // _3D_DISABLED
- {
- if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) {
- child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONESHOT);
- }
+ if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) {
+ child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONESHOT);
}
TrackNodeCacheKey key;
@@ -375,7 +372,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
node_cache->init_rot = rest.basis.get_rotation_quaternion();
node_cache->init_scale = rest.basis.get_scale();
} else {
- // no property, just use spatialnode
+ // Not a skeleton, the node can be accessed with the node_3d member.
node_cache->skeleton = nullptr;
}
}
@@ -2048,7 +2045,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) {
Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values();
old_values->restore();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Anim Apply Reset"));
ur->add_do_method(new_values.ptr(), "restore");
ur->add_undo_method(old_values.ptr(), "restore");
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index b6d8dab1ed..caf1387ff0 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -311,7 +311,7 @@ private:
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
void _notification(int p_what);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 14cf64afad..7dbe892299 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -399,9 +399,9 @@ void AnimationNode::_set_filters(const Array &p_filters) {
}
}
-void AnimationNode::_validate_property(PropertyInfo &property) const {
- if (!has_filter() && (property.name == "filter_enabled" || property.name == "filters")) {
- property.usage = PROPERTY_USAGE_NONE;
+void AnimationNode::_validate_property(PropertyInfo &p_property) const {
+ if (!has_filter() && (p_property.name == "filter_enabled" || p_property.name == "filters")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 99851d140e..ee51a54557 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -111,7 +111,7 @@ protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
GDVIRTUAL0RC(Dictionary, _get_child_nodes)
GDVIRTUAL0RC(Array, _get_parameter_list)
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 04debcab05..7c85b650bf 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -283,8 +283,8 @@ Vector<AudioFrame> AudioStreamPlayer::_get_volume_vector() {
return volume_vector;
}
-void AudioStreamPlayer::_validate_property(PropertyInfo &property) const {
- if (property.name == "bus") {
+void AudioStreamPlayer::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "bus") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0) {
@@ -294,10 +294,8 @@ void AudioStreamPlayer::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
+ p_property.hint_string = options;
}
-
- Node::_validate_property(property);
}
void AudioStreamPlayer::_bus_layout_changed() {
diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h
index 67e616312a..45a6d7663e 100644
--- a/scene/audio/audio_stream_player.h
+++ b/scene/audio/audio_stream_player.h
@@ -72,7 +72,7 @@ private:
Vector<AudioFrame> _get_volume_vector();
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 0a163b65ff..e163f4355c 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -34,11 +34,9 @@
#include "servers/rendering_server.h"
Size2 Button::get_minimum_size() const {
- Ref<Texture2D> _icon;
- if (icon.is_null() && has_theme_icon(SNAME("icon"))) {
+ Ref<Texture2D> _icon = icon;
+ if (_icon.is_null() && has_theme_icon(SNAME("icon"))) {
_icon = Control::get_theme_icon(SNAME("icon"));
- } else {
- _icon = icon;
}
return get_minimum_size_for_text_and_icon("", _icon);
@@ -342,13 +340,13 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu
minsize.width = 0;
}
- if (!expand_icon && !p_icon.is_null()) {
+ if (!expand_icon && p_icon.is_valid()) {
minsize.height = MAX(minsize.height, p_icon->get_height());
if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) {
minsize.width += p_icon->get_width();
if (!xl_text.is_empty() || !p_text.is_empty()) {
- minsize.width += get_theme_constant(SNAME("hseparation"));
+ minsize.width += MAX(0, get_theme_constant(SNAME("h_separation")));
}
} else {
minsize.width = MAX(minsize.width, p_icon->get_width());
diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp
index cb80f5b5ef..26edc1f1b0 100644
--- a/scene/gui/check_box.cpp
+++ b/scene/gui/check_box.cpp
@@ -75,7 +75,7 @@ Size2 CheckBox::get_minimum_size() const {
Size2 tex_size = get_icon_size();
minsize.width += tex_size.width;
if (get_text().length() > 0) {
- minsize.width += get_theme_constant(SNAME("h_separation"));
+ minsize.width += MAX(0, get_theme_constant(SNAME("h_separation")));
}
Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal"));
minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM));
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index a09873ea4f..b9674ca41e 100644
--- a/scene/gui/check_button.cpp
+++ b/scene/gui/check_button.cpp
@@ -52,7 +52,7 @@ Size2 CheckButton::get_minimum_size() const {
Size2 tex_size = get_icon_size();
minsize.width += tex_size.width;
if (get_text().length() > 0) {
- minsize.width += get_theme_constant(SNAME("h_separation"));
+ minsize.width += MAX(0, get_theme_constant(SNAME("h_separation")));
}
Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal"));
minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM));
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 06aa913eb1..545c39a605 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -422,9 +422,9 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-void Control::_validate_property(PropertyInfo &property) const {
+void Control::_validate_property(PropertyInfo &p_property) const {
// Update theme type variation options.
- if (property.name == "theme_type_variation") {
+ if (p_property.name == "theme_type_variation") {
List<StringName> names;
// Only the default theme and the project theme are used for the list of options.
@@ -447,18 +447,18 @@ void Control::_validate_property(PropertyInfo &property) const {
unique_names.append(E);
}
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
- if (property.name == "mouse_force_pass_scroll_events") {
+ if (p_property.name == "mouse_force_pass_scroll_events") {
// Disable force pass if the control is not stopping the event.
if (data.mouse_filter != MOUSE_FILTER_STOP) {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
- if (property.name == "scale") {
- property.hint = PROPERTY_HINT_LINK;
+ if (p_property.name == "scale") {
+ p_property.hint = PROPERTY_HINT_LINK;
}
// Validate which positioning properties should be displayed depending on the parent and the layout mode.
@@ -467,33 +467,33 @@ void Control::_validate_property(PropertyInfo &property) const {
// If there is no parent, display both anchor and container options.
// Set the layout mode to be disabled with the proper value.
- if (property.name == "layout_mode") {
- property.hint_string = "Position,Anchors,Container,Uncontrolled";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ if (p_property.name == "layout_mode") {
+ p_property.hint_string = "Position,Anchors,Container,Uncontrolled";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
// Use the layout mode to display or hide advanced anchoring properties.
bool use_custom_anchors = _get_anchors_layout_preset() == -1; // Custom "preset".
- if (!use_custom_anchors && (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_"))) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_custom_anchors && (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_"))) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
} else if (Object::cast_to<Container>(parent_node)) {
// If the parent is a container, display only container-related properties.
- if (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_") || property.name == "anchors_preset" ||
- property.name == "position" || property.name == "rotation" || property.name == "scale" || property.name == "size" || property.name == "pivot_offset") {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_") || p_property.name == "anchors_preset" ||
+ p_property.name == "position" || p_property.name == "rotation" || p_property.name == "scale" || p_property.name == "size" || p_property.name == "pivot_offset") {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
- } else if (property.name == "layout_mode") {
+ } else if (p_property.name == "layout_mode") {
// Set the layout mode to be disabled with the proper value.
- property.hint_string = "Position,Anchors,Container,Uncontrolled";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
- } else if (property.name == "size_flags_horizontal" || property.name == "size_flags_vertical") {
+ p_property.hint_string = "Position,Anchors,Container,Uncontrolled";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
+ } else if (p_property.name == "size_flags_horizontal" || p_property.name == "size_flags_vertical") {
// Filter allowed size flags based on the parent container configuration.
Container *parent_container = Object::cast_to<Container>(parent_node);
Vector<int> size_flags;
- if (property.name == "size_flags_horizontal") {
+ if (p_property.name == "size_flags_horizontal") {
size_flags = parent_container->get_allowed_size_flags_horizontal();
- } else if (property.name == "size_flags_vertical") {
+ } else if (p_property.name == "size_flags_vertical") {
size_flags = parent_container->get_allowed_size_flags_vertical();
}
@@ -522,30 +522,30 @@ void Control::_validate_property(PropertyInfo &property) const {
}
if (hint_string.is_empty()) {
- property.hint_string = "";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.hint_string = "";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
} else {
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
}
} else {
// If the parent is NOT a container or not a control at all, display only anchoring-related properties.
- if (property.name.begins_with("size_flags_")) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (p_property.name.begins_with("size_flags_")) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
- } else if (property.name == "layout_mode") {
+ } else if (p_property.name == "layout_mode") {
// Set the layout mode to be enabled with proper options.
- property.hint_string = "Position,Anchors";
+ p_property.hint_string = "Position,Anchors";
}
// Use the layout mode to display or hide advanced anchoring properties.
bool use_anchors = _get_layout_mode() == LayoutMode::LAYOUT_MODE_ANCHORS;
- if (!use_anchors && property.name == "anchors_preset") {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_anchors && p_property.name == "anchors_preset") {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
bool use_custom_anchors = use_anchors && _get_anchors_layout_preset() == -1; // Custom "preset".
- if (!use_custom_anchors && (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_"))) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_custom_anchors && (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_"))) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
}
@@ -555,16 +555,36 @@ void Control::_validate_property(PropertyInfo &property) const {
}
bool property_is_managed_by_container = false;
for (unsigned i = 0; i < properties_managed_by_container_count; i++) {
- property_is_managed_by_container = properties_managed_by_container[i] == property.name;
+ property_is_managed_by_container = properties_managed_by_container[i] == p_property.name;
if (property_is_managed_by_container) {
break;
}
}
if (property_is_managed_by_container) {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
+bool Control::_property_can_revert(const StringName &p_name) const {
+ if (p_name == "layout_mode" || p_name == "anchors_preset") {
+ return true;
+ }
+
+ return false;
+}
+
+bool Control::_property_get_revert(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "layout_mode") {
+ r_property = _get_default_layout_mode();
+ return true;
+ } else if (p_name == "anchors_preset") {
+ r_property = LayoutPreset::PRESET_TOP_LEFT;
+ return true;
+ }
+
+ return false;
+}
+
// Global relations.
bool Control::is_top_level_control() const {
@@ -794,24 +814,15 @@ void Control::_compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (
void Control::_set_layout_mode(LayoutMode p_mode) {
bool list_changed = false;
- if (p_mode == LayoutMode::LAYOUT_MODE_POSITION || p_mode == LayoutMode::LAYOUT_MODE_ANCHORS) {
- if ((int)get_meta("_edit_layout_mode", p_mode) != (int)p_mode) {
- list_changed = true;
- }
-
- set_meta("_edit_layout_mode", (int)p_mode);
+ if (data.stored_layout_mode != p_mode) {
+ list_changed = true;
+ data.stored_layout_mode = p_mode;
+ }
- if (p_mode == LayoutMode::LAYOUT_MODE_POSITION) {
- remove_meta("_edit_layout_mode");
- remove_meta("_edit_use_custom_anchors");
- set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT, LayoutPresetMode::PRESET_MODE_KEEP_SIZE);
- set_grow_direction_preset(LayoutPreset::PRESET_TOP_LEFT);
- }
- } else {
- if (has_meta("_edit_layout_mode")) {
- remove_meta("_edit_layout_mode");
- list_changed = true;
- }
+ if (data.stored_layout_mode == LayoutMode::LAYOUT_MODE_POSITION) {
+ data.stored_use_custom_anchors = false;
+ set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT, LayoutPresetMode::PRESET_MODE_KEEP_SIZE);
+ set_grow_direction_preset(LayoutPreset::PRESET_TOP_LEFT);
}
if (list_changed) {
@@ -832,33 +843,43 @@ Control::LayoutMode Control::_get_layout_mode() const {
if (_get_anchors_layout_preset() != (int)LayoutPreset::PRESET_TOP_LEFT) {
return LayoutMode::LAYOUT_MODE_ANCHORS;
}
- // Otherwise check what was saved.
- if (has_meta("_edit_layout_mode")) {
- return (LayoutMode)(int)get_meta("_edit_layout_mode");
+
+ // Otherwise fallback on what's stored.
+ return data.stored_layout_mode;
+}
+
+Control::LayoutMode Control::_get_default_layout_mode() const {
+ Node *parent_node = get_parent_control();
+ // In these modes the property is read-only.
+ if (!parent_node) {
+ return LayoutMode::LAYOUT_MODE_UNCONTROLLED;
+ } else if (Object::cast_to<Container>(parent_node)) {
+ return LayoutMode::LAYOUT_MODE_CONTAINER;
}
- // Or fallback on default.
+
+ // Otherwise fallback on the position mode.
return LayoutMode::LAYOUT_MODE_POSITION;
}
void Control::_set_anchors_layout_preset(int p_preset) {
bool list_changed = false;
- if (get_meta("_edit_layout_mode", LayoutMode::LAYOUT_MODE_ANCHORS).operator int() != LayoutMode::LAYOUT_MODE_ANCHORS) {
+ if (data.stored_layout_mode != LayoutMode::LAYOUT_MODE_ANCHORS) {
list_changed = true;
- set_meta("_edit_layout_mode", LayoutMode::LAYOUT_MODE_ANCHORS);
+ data.stored_layout_mode = LayoutMode::LAYOUT_MODE_ANCHORS;
}
if (p_preset == -1) {
- if (!get_meta("_edit_use_custom_anchors", false)) {
- set_meta("_edit_use_custom_anchors", true);
+ if (!data.stored_use_custom_anchors) {
+ data.stored_use_custom_anchors = true;
notify_property_list_changed();
}
return; // Keep settings as is.
}
- if (get_meta("_edit_use_custom_anchors", true)) {
+ if (data.stored_use_custom_anchors) {
list_changed = true;
- remove_meta("_edit_use_custom_anchors");
+ data.stored_use_custom_anchors = false;
}
LayoutPreset preset = (LayoutPreset)p_preset;
@@ -899,7 +920,7 @@ void Control::_set_anchors_layout_preset(int p_preset) {
int Control::_get_anchors_layout_preset() const {
// If the custom preset was selected by user, use it.
- if ((bool)get_meta("_edit_use_custom_anchors", false)) {
+ if (data.stored_use_custom_anchors) {
return -1;
}
@@ -2262,6 +2283,15 @@ void Control::_notify_theme_changed() {
}
}
+void Control::_invalidate_theme_cache() {
+ data.theme_icon_cache.clear();
+ data.theme_style_cache.clear();
+ data.theme_font_cache.clear();
+ data.theme_font_size_cache.clear();
+ data.theme_color_cache.clear();
+ data.theme_constant_cache.clear();
+}
+
void Control::set_theme(const Ref<Theme> &p_theme) {
if (data.theme == p_theme) {
return;
@@ -2443,9 +2473,15 @@ Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringNam
}
}
+ if (data.theme_icon_cache.has(p_theme_type) && data.theme_icon_cache[p_theme_type].has(p_name)) {
+ return data.theme_icon_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<Texture2D>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ Ref<Texture2D> icon = get_theme_item_in_types<Ref<Texture2D>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_icon_cache[p_theme_type][p_name] = icon;
+ return icon;
}
Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2456,9 +2492,15 @@ Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const String
}
}
+ if (data.theme_style_cache.has(p_theme_type) && data.theme_style_cache[p_theme_type].has(p_name)) {
+ return data.theme_style_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<StyleBox>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ Ref<StyleBox> style = get_theme_item_in_types<Ref<StyleBox>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_style_cache[p_theme_type][p_name] = style;
+ return style;
}
Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2469,9 +2511,15 @@ Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_
}
}
+ if (data.theme_font_cache.has(p_theme_type) && data.theme_font_cache[p_theme_type].has(p_name)) {
+ return data.theme_font_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<Font>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ Ref<Font> font = get_theme_item_in_types<Ref<Font>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_font_cache[p_theme_type][p_name] = font;
+ return font;
}
int Control::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2482,9 +2530,15 @@ int Control::get_theme_font_size(const StringName &p_name, const StringName &p_t
}
}
+ if (data.theme_font_size_cache.has(p_theme_type) && data.theme_font_size_cache[p_theme_type].has(p_name)) {
+ return data.theme_font_size_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ int font_size = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_font_size_cache[p_theme_type][p_name] = font_size;
+ return font_size;
}
Color Control::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2495,9 +2549,15 @@ Color Control::get_theme_color(const StringName &p_name, const StringName &p_the
}
}
+ if (data.theme_color_cache.has(p_theme_type) && data.theme_color_cache[p_theme_type].has(p_name)) {
+ return data.theme_color_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Color>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ Color color = get_theme_item_in_types<Color>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_color_cache[p_theme_type][p_name] = color;
+ return color;
}
int Control::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2508,9 +2568,15 @@ int Control::get_theme_constant(const StringName &p_name, const StringName &p_th
}
}
+ if (data.theme_constant_cache.has(p_theme_type) && data.theme_constant_cache[p_theme_type].has(p_name)) {
+ return data.theme_constant_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ int constant = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_constant_cache[p_theme_type][p_name] = constant;
+ return constant;
}
bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
@@ -3007,6 +3073,10 @@ void Control::remove_child_notify(Node *p_child) {
void Control::_notification(int p_notification) {
switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE: {
+ _invalidate_theme_cache();
+ } break;
+
case NOTIFICATION_POST_ENTER_TREE: {
data.minimum_size_valid = false;
data.is_rtl_dirty = true;
@@ -3144,6 +3214,7 @@ void Control::_notification(int p_notification) {
} break;
case NOTIFICATION_THEME_CHANGED: {
+ _invalidate_theme_cache();
update_minimum_size();
update();
} break;
@@ -3164,6 +3235,7 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
if (is_inside_tree()) {
data.is_rtl_dirty = true;
+ _invalidate_theme_cache();
_size_changed();
}
} break;
@@ -3340,7 +3412,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION);
const String anchors_presets_options = "Custom:-1,PresetFullRect:15,"
@@ -3348,7 +3420,7 @@ void Control::_bind_methods() {
"PresetCenterLeft:4,PresetCenterTop:5,PresetCenterRight:6,PresetCenterBottom:7,PresetCenter:8,"
"PresetLeftWide:9,PresetTopWide:10,PresetRightWide:11,PresetBottomWide:12,PresetVCenterWide:13,PresetHCenterWide:14";
- ADD_PROPERTY(PropertyInfo(Variant::INT, "anchors_preset", PROPERTY_HINT_ENUM, anchors_presets_options, PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_anchors_layout_preset", "_get_anchors_layout_preset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "anchors_preset", PROPERTY_HINT_ENUM, anchors_presets_options, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_anchors_layout_preset", "_get_anchors_layout_preset");
ADD_PROPERTY_DEFAULT("anchors_preset", -1);
ADD_SUBGROUP_INDENT("Anchor Points", "anchor_", 1);
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 9f17eccc3b..a50c66b634 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -170,6 +170,9 @@ private:
// Positioning and sizing.
+ LayoutMode stored_layout_mode = LayoutMode::LAYOUT_MODE_POSITION;
+ bool stored_use_custom_anchors = false;
+
real_t offset[4] = { 0.0, 0.0, 0.0, 0.0 };
real_t anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN };
FocusMode focus_mode = FOCUS_NONE;
@@ -229,6 +232,13 @@ private:
Theme::ThemeColorMap color_override;
Theme::ThemeConstantMap constant_override;
+ mutable HashMap<StringName, Theme::ThemeIconMap> theme_icon_cache;
+ mutable HashMap<StringName, Theme::ThemeStyleMap> theme_style_cache;
+ mutable HashMap<StringName, Theme::ThemeFontMap> theme_font_cache;
+ mutable HashMap<StringName, Theme::ThemeFontSizeMap> theme_font_size_cache;
+ mutable HashMap<StringName, Theme::ThemeColorMap> theme_color_cache;
+ mutable HashMap<StringName, Theme::ThemeConstantMap> theme_constant_cache;
+
// Internationalization.
LayoutDirection layout_dir = LAYOUT_DIRECTION_INHERITED;
@@ -268,6 +278,7 @@ private:
void _set_layout_mode(LayoutMode p_mode);
LayoutMode _get_layout_mode() const;
+ LayoutMode _get_default_layout_mode() const;
void _set_anchors_layout_preset(int p_preset);
int _get_anchors_layout_preset() const;
@@ -291,6 +302,7 @@ private:
void _theme_changed();
void _theme_property_override_changed();
void _notify_theme_changed();
+ void _invalidate_theme_cache();
static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign = true);
@@ -309,7 +321,10 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
+
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
// Internationalization.
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 09efee71a3..8d3a61b52e 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -2381,7 +2381,7 @@ void GraphEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("begin_node_move"));
ADD_SIGNAL(MethodInfo("end_node_move"));
ADD_SIGNAL(MethodInfo("scroll_offset_changed", PropertyInfo(Variant::VECTOR2, "offset")));
- ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::STRING, "slot"), PropertyInfo(Variant::BOOL, "is_output")));
+ ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::INT, "slot"), PropertyInfo(Variant::BOOL, "is_output")));
ADD_SIGNAL(MethodInfo("connection_drag_ended"));
BIND_ENUM_CONSTANT(SCROLL_ZOOMS);
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 112b8c74af..582519e70f 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -446,12 +446,11 @@ void GraphNode::_edit_set_position(const Point2 &p_position) {
set_position(p_position);
}
-void GraphNode::_validate_property(PropertyInfo &property) const {
- Control::_validate_property(property);
+void GraphNode::_validate_property(PropertyInfo &p_property) const {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph) {
- if (property.name == "position") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ if (p_property.name == "position") {
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
}
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 0651eb5cc9..6d5bb4361e 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -101,7 +101,7 @@ private:
#ifdef TOOLS_ENABLED
void _edit_set_position(const Point2 &p_position) override;
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
#endif
protected:
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index d0a25972f8..e3e9499705 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -932,11 +932,7 @@ void ItemList::_notification(int p_what) {
scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -bg->get_margin(SIDE_BOTTOM));
Size2 size = get_size();
-
int width = size.width - bg->get_minimum_size().width;
- if (scroll_bar->is_visible()) {
- width -= mw;
- }
draw_style_box(bg, Rect2(Point2(), size));
@@ -1095,6 +1091,10 @@ void ItemList::_notification(int p_what) {
shape_changed = false;
}
+ if (scroll_bar->is_visible()) {
+ width -= mw;
+ }
+
//ensure_selected_visible needs to be checked before we draw the list.
if (ensure_selected_visible && current >= 0 && current < items.size()) {
Rect2 r = items[current].rect_cache;
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index e7f48beb00..4ef1e48a32 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -764,13 +764,17 @@ int Label::get_visible_characters() const {
void Label::set_percent_visible(float p_percent) {
if (percent_visible != p_percent) {
- if (p_percent < 0 || p_percent >= 1) {
+ if (percent_visible >= 1.0) {
visible_chars = -1;
- percent_visible = 1;
+ percent_visible = 1.0;
+ } else if (percent_visible < 0.0) {
+ visible_chars = 0;
+ percent_visible = 0.0;
} else {
visible_chars = get_total_character_count() * p_percent;
percent_visible = p_percent;
}
+
if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
dirty = true;
}
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index f315b2bbf1..b523c2bb8b 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -2224,9 +2224,9 @@ Key LineEdit::_get_menu_action_accelerator(const String &p_action) {
}
}
-void LineEdit::_validate_property(PropertyInfo &property) const {
- if (!caret_blink_enabled && property.name == "caret_blink_speed") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void LineEdit::_validate_property(PropertyInfo &p_property) const {
+ if (!caret_blink_enabled && p_property.name == "caret_blink_speed") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index a828479b0c..254f842b66 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -95,7 +95,7 @@ private:
String text;
String placeholder;
String placeholder_translated;
- String secret_character = "*";
+ String secret_character = U"•";
String ime_text;
Point2 ime_selection;
@@ -221,7 +221,7 @@ protected:
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void gui_input(const Ref<InputEvent> &p_event) override;
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_horizontal_alignment(HorizontalAlignment p_alignment);
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
new file mode 100644
index 0000000000..f450222130
--- /dev/null
+++ b/scene/gui/menu_bar.cpp
@@ -0,0 +1,868 @@
+/*************************************************************************/
+/* menu_bar.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "menu_bar.h"
+
+#include "core/os/keyboard.h"
+#include "scene/main/window.h"
+
+void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+ if (is_native_menu()) {
+ // Handled by OS.
+ return;
+ }
+
+ MutexLock lock(mutex);
+ if (p_event->is_action("ui_left") && p_event->is_pressed()) {
+ int new_sel = selected_menu;
+ int old_sel = (selected_menu < 0) ? 0 : selected_menu;
+ do {
+ new_sel--;
+ if (new_sel < 0) {
+ new_sel = menu_cache.size() - 1;
+ }
+ if (old_sel == new_sel) {
+ return;
+ }
+ } while (menu_cache[new_sel].hidden || menu_cache[new_sel].disabled);
+
+ if (selected_menu != new_sel) {
+ selected_menu = new_sel;
+ focused_menu = selected_menu;
+ if (active_menu >= 0) {
+ get_menu_popup(active_menu)->hide();
+ }
+ _open_popup(selected_menu);
+ }
+ return;
+ } else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
+ int new_sel = selected_menu;
+ int old_sel = (selected_menu < 0) ? menu_cache.size() - 1 : selected_menu;
+ do {
+ new_sel++;
+ if (new_sel >= menu_cache.size()) {
+ new_sel = 0;
+ }
+ if (old_sel == new_sel) {
+ return;
+ }
+ } while (menu_cache[new_sel].hidden || menu_cache[new_sel].disabled);
+
+ if (selected_menu != new_sel) {
+ selected_menu = new_sel;
+ focused_menu = selected_menu;
+ if (active_menu >= 0) {
+ get_menu_popup(active_menu)->hide();
+ }
+ _open_popup(selected_menu);
+ }
+ return;
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ int old_sel = selected_menu;
+ focused_menu = _get_index_at_point(mm->get_position());
+ if (focused_menu >= 0) {
+ selected_menu = focused_menu;
+ }
+ if (selected_menu != old_sel) {
+ update();
+ }
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ if (mb->is_pressed() && (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT)) {
+ int index = _get_index_at_point(mb->get_position());
+ if (index >= 0) {
+ _open_popup(index);
+ }
+ }
+ }
+}
+
+void MenuBar::_open_popup(int p_index) {
+ ERR_FAIL_INDEX(p_index, menu_cache.size());
+
+ PopupMenu *pm = get_menu_popup(p_index);
+ if (pm->is_visible()) {
+ pm->hide();
+ return;
+ }
+
+ Rect2 item_rect = _get_menu_item_rect(p_index);
+ Point2 screen_pos = get_screen_position() + item_rect.position * get_viewport()->get_canvas_transform().get_scale();
+ Size2 screen_size = item_rect.size * get_viewport()->get_canvas_transform().get_scale();
+
+ active_menu = p_index;
+
+ pm->set_size(Size2(screen_size.x, 0));
+ screen_pos.y += screen_size.y;
+ if (is_layout_rtl()) {
+ screen_pos.x += screen_size.x - pm->get_size().width;
+ }
+ pm->set_position(screen_pos);
+ pm->set_parent_rect(Rect2(Point2(screen_pos - pm->get_position()), Size2(screen_size.x, screen_pos.y)));
+ pm->popup();
+
+ update();
+}
+
+void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
+ if (is_native_menu()) {
+ return;
+ }
+
+ if (!_is_focus_owner_in_shortcut_context()) {
+ return;
+ }
+
+ if (disable_shortcuts) {
+ return;
+ }
+
+ if (p_event->is_pressed() && !p_event->is_echo() && (Object::cast_to<InputEventKey>(p_event.ptr()) || Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventAction>(*p_event) || Object::cast_to<InputEventShortcut>(*p_event))) {
+ if (!get_parent() || !is_visible_in_tree()) {
+ return;
+ }
+
+ Vector<PopupMenu *> popups = _get_popups();
+ for (int i = 0; i < popups.size(); i++) {
+ if (menu_cache[i].hidden || menu_cache[i].disabled) {
+ continue;
+ }
+ if (popups[i]->activate_item_by_event(p_event, false)) {
+ accept_event();
+ return;
+ }
+ }
+ }
+}
+
+void MenuBar::set_shortcut_context(Node *p_node) {
+ if (p_node != nullptr) {
+ shortcut_context = p_node->get_instance_id();
+ } else {
+ shortcut_context = ObjectID();
+ }
+}
+
+Node *MenuBar::get_shortcut_context() const {
+ Object *ctx_obj = ObjectDB::get_instance(shortcut_context);
+ Node *ctx_node = Object::cast_to<Node>(ctx_obj);
+
+ return ctx_node;
+}
+
+bool MenuBar::_is_focus_owner_in_shortcut_context() const {
+ if (shortcut_context == ObjectID()) {
+ // No context, therefore global - always "in" context.
+ return true;
+ }
+
+ Node *ctx_node = get_shortcut_context();
+ Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr;
+
+ // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it.
+ return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus));
+}
+
+void MenuBar::_popup_visibility_changed(bool p_visible) {
+ if (!p_visible) {
+ active_menu = -1;
+ focused_menu = -1;
+ set_process_internal(false);
+ update();
+ return;
+ }
+
+ if (switch_on_hover) {
+ Window *window = Object::cast_to<Window>(get_viewport());
+ if (window) {
+ mouse_pos_adjusted = window->get_position();
+
+ if (window->is_embedded()) {
+ Window *window_parent = Object::cast_to<Window>(window->get_parent()->get_viewport());
+ while (window_parent) {
+ if (!window_parent->is_embedded()) {
+ mouse_pos_adjusted += window_parent->get_position();
+ break;
+ }
+
+ window_parent = Object::cast_to<Window>(window_parent->get_parent()->get_viewport());
+ }
+ }
+
+ set_process_internal(true);
+ }
+ }
+}
+
+void MenuBar::_update_submenu(const String &p_menu_name, PopupMenu *p_child) {
+ int count = p_child->get_item_count();
+ global_menus.insert(p_menu_name);
+ for (int i = 0; i < count; i++) {
+ if (p_child->is_item_separator(i)) {
+ DisplayServer::get_singleton()->global_menu_add_separator(p_menu_name);
+ } else if (!p_child->get_item_submenu(i).is_empty()) {
+ Node *n = p_child->get_node(p_child->get_item_submenu(i));
+ ERR_FAIL_COND_MSG(!n, "Item subnode does not exist: " + p_child->get_item_submenu(i) + ".");
+ PopupMenu *pm = Object::cast_to<PopupMenu>(n);
+ ERR_FAIL_COND_MSG(!pm, "Item subnode is not a PopupMenu: " + p_child->get_item_submenu(i) + ".");
+
+ DisplayServer::get_singleton()->global_menu_add_submenu_item(p_menu_name, p_child->get_item_text(i), p_menu_name + "/" + itos(i));
+ _update_submenu(p_menu_name + "/" + itos(i), pm);
+ } else {
+ int index = DisplayServer::get_singleton()->global_menu_add_item(p_menu_name, p_child->get_item_text(i), callable_mp(p_child, &PopupMenu::activate_item), i);
+
+ if (p_child->is_item_checkable(i)) {
+ DisplayServer::get_singleton()->global_menu_set_item_checkable(p_menu_name, index, true);
+ }
+ if (p_child->is_item_radio_checkable(i)) {
+ DisplayServer::get_singleton()->global_menu_set_item_radio_checkable(p_menu_name, index, true);
+ }
+ DisplayServer::get_singleton()->global_menu_set_item_checked(p_menu_name, index, p_child->is_item_checked(i));
+ DisplayServer::get_singleton()->global_menu_set_item_disabled(p_menu_name, index, p_child->is_item_disabled(i));
+ DisplayServer::get_singleton()->global_menu_set_item_max_states(p_menu_name, index, p_child->get_item_max_states(i));
+ DisplayServer::get_singleton()->global_menu_set_item_icon(p_menu_name, index, p_child->get_item_icon(i));
+ DisplayServer::get_singleton()->global_menu_set_item_state(p_menu_name, index, p_child->get_item_state(i));
+ DisplayServer::get_singleton()->global_menu_set_item_indentation_level(p_menu_name, index, p_child->get_item_indent(i));
+ DisplayServer::get_singleton()->global_menu_set_item_tooltip(p_menu_name, index, p_child->get_item_tooltip(i));
+ if (!p_child->is_item_shortcut_disabled(i) && p_child->get_item_shortcut(i).is_valid() && p_child->get_item_shortcut(i)->has_valid_event()) {
+ Array events = p_child->get_item_shortcut(i)->get_events();
+ for (int j = 0; j < events.size(); j++) {
+ Ref<InputEventKey> ie = events[j];
+ if (ie.is_valid()) {
+ DisplayServer::get_singleton()->global_menu_set_item_accelerator(p_menu_name, index, ie->get_keycode_with_modifiers());
+ break;
+ }
+ }
+ } else if (p_child->get_item_accelerator(i) != Key::NONE) {
+ DisplayServer::get_singleton()->global_menu_set_item_accelerator(p_menu_name, i, p_child->get_item_accelerator(i));
+ }
+ }
+ }
+}
+
+bool MenuBar::is_native_menu() const {
+ if (!is_visible_in_tree()) {
+ return false;
+ }
+ if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this)) {
+ return false;
+ }
+
+ return (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU) && is_native);
+}
+
+void MenuBar::_clear_menu() {
+ if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
+ return;
+ }
+
+ // Remove root menu items.
+ int count = DisplayServer::get_singleton()->global_menu_get_item_count("_main");
+ for (int i = count - 1; i >= 0; i--) {
+ if (global_menus.has(DisplayServer::get_singleton()->global_menu_get_item_submenu("_main", i))) {
+ DisplayServer::get_singleton()->global_menu_remove_item("_main", i);
+ }
+ }
+ // Erase submenu contents.
+ for (const String &E : global_menus) {
+ DisplayServer::get_singleton()->global_menu_clear(E);
+ }
+ global_menus.clear();
+}
+
+void MenuBar::_update_menu() {
+ _clear_menu();
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ int index = start_index;
+ if (is_native_menu()) {
+ Vector<PopupMenu *> popups = _get_popups();
+ String root_name = "MenuBar<" + String::num_int64((uint64_t)this, 16) + ">";
+ for (int i = 0; i < popups.size(); i++) {
+ if (menu_cache[i].hidden) {
+ continue;
+ }
+ String menu_name = String(popups[i]->get_meta("_menu_name", popups[i]->get_name()));
+
+ index = DisplayServer::get_singleton()->global_menu_add_submenu_item("_main", menu_name, root_name + "/" + itos(i), index);
+ if (menu_cache[i].disabled) {
+ DisplayServer::get_singleton()->global_menu_set_item_disabled("_main", index, true);
+ }
+ _update_submenu(root_name + "/" + itos(i), popups[i]);
+ index++;
+ }
+ }
+ update_minimum_size();
+ update();
+}
+
+void MenuBar::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (get_menu_count() > 0) {
+ _refresh_menu_names();
+ }
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ _clear_menu();
+ } break;
+ case NOTIFICATION_MOUSE_EXIT: {
+ focused_menu = -1;
+ update();
+ } break;
+ case NOTIFICATION_TRANSLATION_CHANGED:
+ case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
+ case NOTIFICATION_THEME_CHANGED: {
+ for (int i = 0; i < menu_cache.size(); i++) {
+ shape(menu_cache.write[i]);
+ }
+ _update_menu();
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ _update_menu();
+ } break;
+ case NOTIFICATION_DRAW: {
+ if (is_native_menu()) {
+ return;
+ }
+ for (int i = 0; i < menu_cache.size(); i++) {
+ _draw_menu_item(i);
+ }
+ } break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ MutexLock lock(mutex);
+
+ Vector2 pos = DisplayServer::get_singleton()->mouse_get_position() - mouse_pos_adjusted - get_global_position();
+ int index = _get_index_at_point(pos);
+ if (index >= 0 && index != active_menu) {
+ selected_menu = index;
+ focused_menu = selected_menu;
+ get_menu_popup(active_menu)->hide();
+ _open_popup(index);
+ }
+ } break;
+ }
+}
+
+int MenuBar::_get_index_at_point(const Point2 &p_point) const {
+ Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ int hsep = get_theme_constant(SNAME("h_separation"));
+ int offset = 0;
+ for (int i = 0; i < menu_cache.size(); i++) {
+ if (menu_cache[i].hidden) {
+ continue;
+ }
+ Size2 size = menu_cache[i].text_buf->get_size() + style->get_minimum_size();
+ if (p_point.x > offset && p_point.x < offset + size.x) {
+ if (p_point.y > 0 && p_point.y < size.y) {
+ return i;
+ }
+ }
+ offset += size.x + hsep;
+ }
+ return -1;
+}
+
+Rect2 MenuBar::_get_menu_item_rect(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, menu_cache.size(), Rect2());
+
+ Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ int hsep = get_theme_constant(SNAME("h_separation"));
+
+ int offset = 0;
+ for (int i = 0; i < p_index; i++) {
+ if (menu_cache[i].hidden) {
+ continue;
+ }
+ Size2 size = menu_cache[i].text_buf->get_size() + style->get_minimum_size();
+ offset += size.x + hsep;
+ }
+
+ return Rect2(Point2(offset, 0), menu_cache[p_index].text_buf->get_size() + style->get_minimum_size());
+}
+
+void MenuBar::_draw_menu_item(int p_index) {
+ ERR_FAIL_INDEX(p_index, menu_cache.size());
+
+ RID ci = get_canvas_item();
+ bool hovered = (focused_menu == p_index);
+ bool pressed = (active_menu == p_index);
+ bool rtl = is_layout_rtl();
+
+ if (menu_cache[p_index].hidden) {
+ return;
+ }
+
+ Color color;
+ Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Rect2 item_rect = _get_menu_item_rect(p_index);
+
+ if (menu_cache[p_index].disabled) {
+ if (rtl && has_theme_stylebox(SNAME("disabled_mirrored"))) {
+ style = get_theme_stylebox(SNAME("disabled_mirrored"));
+ } else {
+ style = get_theme_stylebox(SNAME("disabled"));
+ }
+ if (!flat) {
+ style->draw(ci, item_rect);
+ }
+ color = get_theme_color(SNAME("font_disabled_color"));
+ } else if (hovered && pressed && has_theme_stylebox("hover_pressed")) {
+ if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored"))) {
+ style = get_theme_stylebox(SNAME("hover_pressed_mirrored"));
+ } else {
+ style = get_theme_stylebox(SNAME("hover_pressed"));
+ }
+ if (!flat) {
+ style->draw(ci, item_rect);
+ }
+ if (has_theme_color(SNAME("font_hover_pressed_color"))) {
+ color = get_theme_color(SNAME("font_hover_pressed_color"));
+ }
+ } else if (pressed) {
+ if (rtl && has_theme_stylebox(SNAME("pressed_mirrored"))) {
+ style = get_theme_stylebox(SNAME("pressed_mirrored"));
+ } else {
+ style = get_theme_stylebox(SNAME("pressed"));
+ }
+ if (!flat) {
+ style->draw(ci, item_rect);
+ }
+ if (has_theme_color(SNAME("font_pressed_color"))) {
+ color = get_theme_color(SNAME("font_pressed_color"));
+ } else {
+ color = get_theme_color(SNAME("font_color"));
+ }
+ } else if (hovered) {
+ if (rtl && has_theme_stylebox(SNAME("hover_mirrored"))) {
+ style = get_theme_stylebox(SNAME("hover_mirrored"));
+ } else {
+ style = get_theme_stylebox(SNAME("hover"));
+ }
+ if (!flat) {
+ style->draw(ci, item_rect);
+ }
+ color = get_theme_color(SNAME("font_hover_color"));
+ } else {
+ if (rtl && has_theme_stylebox(SNAME("normal_mirrored"))) {
+ style = get_theme_stylebox(SNAME("normal_mirrored"));
+ } else {
+ style = get_theme_stylebox(SNAME("normal"));
+ }
+ if (!flat) {
+ style->draw(ci, item_rect);
+ }
+ // Focus colors only take precedence over normal state.
+ if (has_focus()) {
+ color = get_theme_color(SNAME("font_focus_color"));
+ } else {
+ color = get_theme_color(SNAME("font_color"));
+ }
+ }
+
+ Point2 text_ofs = item_rect.position + Point2(style->get_margin(SIDE_LEFT), style->get_margin(SIDE_TOP));
+
+ Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
+ int outline_size = get_theme_constant(SNAME("outline_size"));
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ menu_cache[p_index].text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color);
+ }
+ menu_cache[p_index].text_buf->draw(ci, text_ofs, color);
+}
+
+void MenuBar::shape(Menu &p_menu) {
+ Ref<Font> font = get_theme_font(SNAME("font"));
+ int font_size = get_theme_font_size(SNAME("font_size"));
+
+ p_menu.text_buf->clear();
+ if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
+ p_menu.text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
+ } else {
+ p_menu.text_buf->set_direction((TextServer::Direction)text_direction);
+ }
+ p_menu.text_buf->add_string(p_menu.name, font, font_size, language);
+}
+
+void MenuBar::_refresh_menu_names() {
+ Vector<PopupMenu *> popups = _get_popups();
+ for (int i = 0; i < popups.size(); i++) {
+ if (!popups[i]->has_meta("_menu_name") && String(popups[i]->get_name()) != get_menu_title(i)) {
+ menu_cache.write[i].name = popups[i]->get_name();
+ shape(menu_cache.write[i]);
+ }
+ }
+ _update_menu();
+}
+
+Vector<PopupMenu *> MenuBar::_get_popups() const {
+ Vector<PopupMenu *> popups;
+ for (int i = 0; i < get_child_count(); i++) {
+ PopupMenu *pm = Object::cast_to<PopupMenu>(get_child(i));
+ if (!pm) {
+ continue;
+ }
+ popups.push_back(pm);
+ }
+ return popups;
+}
+
+int MenuBar::get_menu_idx_from_control(PopupMenu *p_child) const {
+ ERR_FAIL_NULL_V(p_child, -1);
+ ERR_FAIL_COND_V(p_child->get_parent() != this, -1);
+
+ Vector<PopupMenu *> popups = _get_popups();
+ for (int i = 0; i < popups.size(); i++) {
+ if (popups[i] == p_child) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void MenuBar::add_child_notify(Node *p_child) {
+ Control::add_child_notify(p_child);
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(p_child);
+ if (!pm) {
+ return;
+ }
+ Menu menu = Menu(p_child->get_name());
+ shape(menu);
+
+ menu_cache.push_back(menu);
+ p_child->connect("renamed", callable_mp(this, &MenuBar::_refresh_menu_names));
+ p_child->connect("menu_changed", callable_mp(this, &MenuBar::_update_menu));
+ p_child->connect("about_to_popup", callable_mp(this, &MenuBar::_popup_visibility_changed).bind(true));
+ p_child->connect("popup_hide", callable_mp(this, &MenuBar::_popup_visibility_changed).bind(false));
+
+ _update_menu();
+}
+
+void MenuBar::move_child_notify(Node *p_child) {
+ Control::move_child_notify(p_child);
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(p_child);
+ if (!pm) {
+ return;
+ }
+
+ int old_idx = -1;
+ String menu_name = String(pm->get_meta("_menu_name", pm->get_name()));
+ // Find the previous menu index of the control.
+ for (int i = 0; i < get_menu_count(); i++) {
+ if (get_menu_title(i) == menu_name) {
+ old_idx = i;
+ break;
+ }
+ }
+ Menu menu = menu_cache[old_idx];
+ menu_cache.remove_at(old_idx);
+ menu_cache.insert(get_menu_idx_from_control(pm), menu);
+
+ _update_menu();
+}
+
+void MenuBar::remove_child_notify(Node *p_child) {
+ Control::remove_child_notify(p_child);
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(p_child);
+ if (!pm) {
+ return;
+ }
+
+ int idx = get_menu_idx_from_control(pm);
+
+ menu_cache.remove_at(idx);
+
+ p_child->remove_meta("_menu_name");
+ p_child->remove_meta("_menu_tooltip");
+
+ p_child->disconnect("renamed", callable_mp(this, &MenuBar::_refresh_menu_names));
+ p_child->disconnect("menu_changed", callable_mp(this, &MenuBar::_update_menu));
+ p_child->disconnect("about_to_popup", callable_mp(this, &MenuBar::_popup_visibility_changed));
+ p_child->disconnect("popup_hide", callable_mp(this, &MenuBar::_popup_visibility_changed));
+
+ _update_menu();
+}
+
+void MenuBar::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_switch_on_hover", "enable"), &MenuBar::set_switch_on_hover);
+ ClassDB::bind_method(D_METHOD("is_switch_on_hover"), &MenuBar::is_switch_on_hover);
+ ClassDB::bind_method(D_METHOD("set_disable_shortcuts", "disabled"), &MenuBar::set_disable_shortcuts);
+
+ ClassDB::bind_method(D_METHOD("set_prefer_global_menu", "enabled"), &MenuBar::set_prefer_global_menu);
+ ClassDB::bind_method(D_METHOD("is_prefer_global_menu"), &MenuBar::is_prefer_global_menu);
+ ClassDB::bind_method(D_METHOD("is_native_menu"), &MenuBar::is_native_menu);
+
+ ClassDB::bind_method(D_METHOD("get_menu_count"), &MenuBar::get_menu_count);
+
+ ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &MenuBar::set_text_direction);
+ ClassDB::bind_method(D_METHOD("get_text_direction"), &MenuBar::get_text_direction);
+ ClassDB::bind_method(D_METHOD("set_language", "language"), &MenuBar::set_language);
+ ClassDB::bind_method(D_METHOD("get_language"), &MenuBar::get_language);
+ ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &MenuBar::set_flat);
+ ClassDB::bind_method(D_METHOD("is_flat"), &MenuBar::is_flat);
+ ClassDB::bind_method(D_METHOD("set_start_index", "enabled"), &MenuBar::set_start_index);
+ ClassDB::bind_method(D_METHOD("get_start_index"), &MenuBar::get_start_index);
+
+ ClassDB::bind_method(D_METHOD("set_menu_title", "menu", "title"), &MenuBar::set_menu_title);
+ ClassDB::bind_method(D_METHOD("get_menu_title", "menu"), &MenuBar::get_menu_title);
+
+ ClassDB::bind_method(D_METHOD("set_menu_tooltip", "menu", "tooltip"), &MenuBar::set_menu_tooltip);
+ ClassDB::bind_method(D_METHOD("get_menu_tooltip", "menu"), &MenuBar::get_menu_tooltip);
+
+ ClassDB::bind_method(D_METHOD("set_menu_disabled", "menu", "disabled"), &MenuBar::set_menu_disabled);
+ ClassDB::bind_method(D_METHOD("is_menu_disabled", "menu"), &MenuBar::is_menu_disabled);
+
+ ClassDB::bind_method(D_METHOD("set_menu_hidden", "menu", "hidden"), &MenuBar::set_menu_hidden);
+ ClassDB::bind_method(D_METHOD("is_menu_hidden", "menu"), &MenuBar::is_menu_hidden);
+
+ ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &MenuBar::set_shortcut_context);
+ ClassDB::bind_method(D_METHOD("get_shortcut_context"), &MenuBar::get_shortcut_context);
+
+ ClassDB::bind_method(D_METHOD("get_menu_popup", "menu"), &MenuBar::get_menu_popup);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "start_index"), "set_start_index", "get_start_index");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefer_global_menu"), "set_prefer_global_menu", "is_prefer_global_menu");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_RESOURCE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
+
+ ADD_GROUP("BiDi", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
+}
+
+void MenuBar::set_switch_on_hover(bool p_enabled) {
+ switch_on_hover = p_enabled;
+}
+
+bool MenuBar::is_switch_on_hover() {
+ return switch_on_hover;
+}
+
+void MenuBar::set_disable_shortcuts(bool p_disabled) {
+ disable_shortcuts = p_disabled;
+}
+
+void MenuBar::set_text_direction(Control::TextDirection p_text_direction) {
+ ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
+ if (text_direction != p_text_direction) {
+ text_direction = p_text_direction;
+ _update_menu();
+ }
+}
+
+Control::TextDirection MenuBar::get_text_direction() const {
+ return text_direction;
+}
+
+void MenuBar::set_language(const String &p_language) {
+ if (language != p_language) {
+ language = p_language;
+ _update_menu();
+ }
+}
+
+String MenuBar::get_language() const {
+ return language;
+}
+
+void MenuBar::set_flat(bool p_enabled) {
+ if (flat != p_enabled) {
+ flat = p_enabled;
+ update();
+ }
+}
+
+bool MenuBar::is_flat() const {
+ return flat;
+}
+
+void MenuBar::set_start_index(int p_index) {
+ if (start_index != p_index) {
+ start_index = p_index;
+ _update_menu();
+ }
+}
+
+int MenuBar::get_start_index() const {
+ return start_index;
+}
+
+void MenuBar::set_prefer_global_menu(bool p_enabled) {
+ if (is_native != p_enabled) {
+ if (is_native) {
+ _clear_menu();
+ }
+ is_native = p_enabled;
+ _update_menu();
+ }
+}
+
+bool MenuBar::is_prefer_global_menu() const {
+ return is_native;
+}
+
+Size2 MenuBar::get_minimum_size() const {
+ if (is_native_menu()) {
+ return Size2();
+ }
+
+ Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+
+ Vector2 size;
+ for (int i = 0; i < menu_cache.size(); i++) {
+ if (menu_cache[i].hidden) {
+ continue;
+ }
+ Size2 sz = menu_cache[i].text_buf->get_size() + style->get_minimum_size();
+ size.y = MAX(size.y, sz.y);
+ size.x += sz.x;
+ }
+ if (menu_cache.size() > 1) {
+ size.x += get_theme_constant(SNAME("h_separation")) * (menu_cache.size() - 1);
+ }
+ return size;
+}
+
+int MenuBar::get_menu_count() const {
+ return menu_cache.size();
+}
+
+void MenuBar::set_menu_title(int p_menu, const String &p_title) {
+ ERR_FAIL_INDEX(p_menu, menu_cache.size());
+ PopupMenu *pm = get_menu_popup(p_menu);
+ if (p_title == pm->get_name()) {
+ pm->remove_meta("_menu_name");
+ } else {
+ pm->set_meta("_menu_name", p_title);
+ }
+ menu_cache.write[p_menu].name = p_title;
+ shape(menu_cache.write[p_menu]);
+ _update_menu();
+}
+
+String MenuBar::get_menu_title(int p_menu) const {
+ ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), String());
+ return menu_cache[p_menu].name;
+}
+
+void MenuBar::set_menu_tooltip(int p_menu, const String &p_tooltip) {
+ ERR_FAIL_INDEX(p_menu, menu_cache.size());
+ PopupMenu *pm = get_menu_popup(p_menu);
+ pm->set_meta("_menu_tooltip", p_tooltip);
+ menu_cache.write[p_menu].name = p_tooltip;
+}
+
+String MenuBar::get_menu_tooltip(int p_menu) const {
+ ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), String());
+ return menu_cache[p_menu].tooltip;
+}
+
+void MenuBar::set_menu_disabled(int p_menu, bool p_disabled) {
+ ERR_FAIL_INDEX(p_menu, menu_cache.size());
+ menu_cache.write[p_menu].disabled = p_disabled;
+ _update_menu();
+}
+
+bool MenuBar::is_menu_disabled(int p_menu) const {
+ ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), false);
+ return menu_cache[p_menu].disabled;
+}
+
+void MenuBar::set_menu_hidden(int p_menu, bool p_hidden) {
+ ERR_FAIL_INDEX(p_menu, menu_cache.size());
+ menu_cache.write[p_menu].hidden = p_hidden;
+ _update_menu();
+}
+
+bool MenuBar::is_menu_hidden(int p_menu) const {
+ ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), false);
+ return menu_cache[p_menu].hidden;
+}
+
+PopupMenu *MenuBar::get_menu_popup(int p_idx) const {
+ Vector<PopupMenu *> controls = _get_popups();
+ if (p_idx >= 0 && p_idx < controls.size()) {
+ return controls[p_idx];
+ } else {
+ return nullptr;
+ }
+}
+
+String MenuBar::get_tooltip(const Point2 &p_pos) const {
+ int index = _get_index_at_point(p_pos);
+ if (index >= 0 && index < menu_cache.size()) {
+ return menu_cache[index].tooltip;
+ } else {
+ return String();
+ }
+}
+
+void MenuBar::get_translatable_strings(List<String> *p_strings) const {
+ Vector<PopupMenu *> popups = _get_popups();
+ for (int i = 0; i < popups.size(); i++) {
+ PopupMenu *pm = popups[i];
+
+ if (!pm->has_meta("_menu_name") && !pm->has_meta("_menu_tooltip")) {
+ continue;
+ }
+
+ String name = pm->get_meta("_menu_name");
+ if (!name.is_empty()) {
+ p_strings->push_back(name);
+ }
+
+ String tooltip = pm->get_meta("_menu_tooltip");
+ if (!tooltip.is_empty()) {
+ p_strings->push_back(tooltip);
+ }
+ }
+}
+
+MenuBar::MenuBar() {
+ set_process_shortcut_input(true);
+}
+
+MenuBar::~MenuBar() {
+}
diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h
new file mode 100644
index 0000000000..3c4a25fd06
--- /dev/null
+++ b/scene/gui/menu_bar.h
@@ -0,0 +1,156 @@
+/*************************************************************************/
+/* menu_bar.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 MENU_BAR_H
+#define MENU_BAR_H
+
+#include "scene/gui/button.h"
+#include "scene/gui/popup_menu.h"
+
+class MenuBar : public Control {
+ GDCLASS(MenuBar, Control);
+
+ Mutex mutex;
+
+ bool switch_on_hover = true;
+ bool disable_shortcuts = false;
+ bool is_native = true;
+ bool flat = false;
+ int start_index = -1;
+
+ String language;
+ TextDirection text_direction = TEXT_DIRECTION_AUTO;
+
+ struct Menu {
+ String name;
+ String tooltip;
+
+ Ref<TextLine> text_buf;
+ bool hidden = false;
+ bool disabled = false;
+
+ Menu(const String &p_name) {
+ name = p_name;
+ text_buf.instantiate();
+ }
+
+ Menu() {
+ text_buf.instantiate();
+ }
+ };
+ Vector<Menu> menu_cache;
+ HashSet<String> global_menus;
+
+ int focused_menu = -1;
+ int selected_menu = -1;
+ int active_menu = -1;
+
+ Vector2i mouse_pos_adjusted;
+ ObjectID shortcut_context;
+
+ int _get_index_at_point(const Point2 &p_point) const;
+ Rect2 _get_menu_item_rect(int p_index) const;
+ void _draw_menu_item(int p_index);
+
+ void shape(Menu &p_menu);
+ void _refresh_menu_names();
+ Vector<PopupMenu *> _get_popups() const;
+ int get_menu_idx_from_control(PopupMenu *p_child) const;
+
+ void _open_popup(int p_index);
+ void _popup_visibility_changed(bool p_visible);
+ void _update_submenu(const String &p_menu_name, PopupMenu *p_child);
+ void _clear_menu();
+ void _update_menu();
+
+ bool _is_focus_owner_in_shortcut_context() const;
+
+protected:
+ virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
+
+ void _notification(int p_what);
+ virtual void add_child_notify(Node *p_child) override;
+ virtual void move_child_notify(Node *p_child) override;
+ virtual void remove_child_notify(Node *p_child) override;
+ static void _bind_methods();
+
+public:
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
+
+ void set_switch_on_hover(bool p_enabled);
+ bool is_switch_on_hover();
+ void set_disable_shortcuts(bool p_disabled);
+
+ void set_prefer_global_menu(bool p_enabled);
+ bool is_prefer_global_menu() const;
+
+ bool is_native_menu() const;
+
+ virtual Size2 get_minimum_size() const override;
+
+ int get_menu_count() const;
+
+ void set_text_direction(TextDirection p_text_direction);
+ TextDirection get_text_direction() const;
+
+ void set_language(const String &p_language);
+ String get_language() const;
+
+ void set_start_index(int p_index);
+ int get_start_index() const;
+
+ void set_flat(bool p_enabled);
+ bool is_flat() const;
+
+ void set_menu_title(int p_menu, const String &p_title);
+ String get_menu_title(int p_menu) const;
+
+ void set_menu_tooltip(int p_menu, const String &p_tooltip);
+ String get_menu_tooltip(int p_menu) const;
+
+ void set_menu_disabled(int p_menu, bool p_disabled);
+ bool is_menu_disabled(int p_menu) const;
+
+ void set_menu_hidden(int p_menu, bool p_hidden);
+ bool is_menu_hidden(int p_menu) const;
+
+ void set_shortcut_context(Node *p_node);
+ Node *get_shortcut_context() const;
+
+ PopupMenu *get_menu_popup(int p_menu) const;
+
+ virtual void get_translatable_strings(List<String> *p_strings) const override;
+ virtual String get_tooltip(const Point2 &p_pos) const override;
+
+ MenuBar();
+ ~MenuBar();
+};
+
+#endif // MENU_BAR_H
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 069a31d9d2..0252f25888 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -105,7 +105,11 @@ void MenuButton::pressed() {
popup->set_current_index(0);
}
- popup->popup();
+ if (popup->is_visible()) {
+ popup->hide();
+ } else {
+ popup->popup();
+ }
}
void MenuButton::gui_input(const Ref<InputEvent> &p_event) {
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index c6d011d4ef..a5a6240e27 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -47,7 +47,7 @@ Size2 OptionButton::get_minimum_size() const {
const Size2 arrow_size = Control::get_theme_icon(SNAME("arrow"))->get_size();
Size2 content_size = minsize - padding;
- content_size.width += arrow_size.width + get_theme_constant(SNAME("h_separation"));
+ content_size.width += arrow_size.width + MAX(0, get_theme_constant(SNAME("h_separation")));
content_size.height = MAX(content_size.height, arrow_size.height);
minsize = content_size + padding;
@@ -74,6 +74,9 @@ void OptionButton::_notification(int p_what) {
case DRAW_HOVER:
clr = get_theme_color(SNAME("font_hover_color"));
break;
+ case DRAW_HOVER_PRESSED:
+ clr = get_theme_color(SNAME("font_hover_pressed_color"));
+ break;
case DRAW_DISABLED:
clr = get_theme_color(SNAME("font_disabled_color"));
break;
@@ -468,9 +471,9 @@ void OptionButton::get_translatable_strings(List<String> *p_strings) const {
popup->get_translatable_strings(p_strings);
}
-void OptionButton::_validate_property(PropertyInfo &property) const {
- if (property.name == "text" || property.name == "icon") {
- property.usage = PROPERTY_USAGE_NONE;
+void OptionButton::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "text" || p_property.name == "icon") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index 49b5eee910..cd709b8f5f 100644
--- a/scene/gui/option_button.h
+++ b/scene/gui/option_button.h
@@ -58,7 +58,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 928bab8842..6ef8158302 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -36,6 +36,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
+#include "scene/gui/menu_bar.h"
String PopupMenu::_get_accel_text(const Item &p_item) const {
if (p_item.shortcut.is_valid()) {
@@ -66,7 +67,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
size.height = _get_item_height(i);
icon_w = MAX(icon_size.width, icon_w);
- size.width += items[i].h_ofs;
+ size.width += items[i].indent * get_theme_constant(SNAME("indent"));
if (items[i].checkable_type && !items[i].separator) {
has_check = true;
@@ -343,14 +344,27 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
}
} else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
Node *n = get_parent();
- if (n && Object::cast_to<PopupMenu>(n)) {
- hide();
- set_input_as_handled();
+ if (n) {
+ if (Object::cast_to<PopupMenu>(n)) {
+ hide();
+ set_input_as_handled();
+ } else if (Object::cast_to<MenuBar>(n)) {
+ Object::cast_to<MenuBar>(n)->gui_input(p_event);
+ set_input_as_handled();
+ return;
+ }
}
} else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && !items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
_activate_submenu(mouse_over, true);
set_input_as_handled();
+ } else {
+ Node *n = get_parent();
+ if (n && Object::cast_to<MenuBar>(n)) {
+ Object::cast_to<MenuBar>(n)->gui_input(p_event);
+ set_input_as_handled();
+ return;
+ }
}
} else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
@@ -513,9 +527,9 @@ void PopupMenu::_draw_items() {
bool rtl = control->is_layout_rtl();
Ref<StyleBox> style = get_theme_stylebox(SNAME("panel"));
Ref<StyleBox> hover = get_theme_stylebox(SNAME("hover"));
- // In Item::checkable_type enum order (less the non-checkable member).
- Ref<Texture2D> check[] = { get_theme_icon(SNAME("checked")), get_theme_icon(SNAME("radio_checked")) };
- Ref<Texture2D> uncheck[] = { get_theme_icon(SNAME("unchecked")), get_theme_icon(SNAME("radio_unchecked")) };
+ // In Item::checkable_type enum order (less the non-checkable member), with disabled repeated at the end.
+ Ref<Texture2D> check[] = { get_theme_icon(SNAME("checked")), get_theme_icon(SNAME("radio_checked")), get_theme_icon(SNAME("checked_disabled")), get_theme_icon(SNAME("radio_checked_disabled")) };
+ Ref<Texture2D> uncheck[] = { get_theme_icon(SNAME("unchecked")), get_theme_icon(SNAME("radio_unchecked")), get_theme_icon(SNAME("unchecked_disabled")), get_theme_icon(SNAME("radio_unchecked_disabled")) };
Ref<Texture2D> submenu;
if (rtl) {
submenu = get_theme_icon(SNAME("submenu_mirrored"));
@@ -558,7 +572,11 @@ void PopupMenu::_draw_items() {
float check_ofs = 0.0;
if (has_check) {
- check_ofs = MAX(get_theme_icon(SNAME("checked"))->get_width(), get_theme_icon(SNAME("radio_checked"))->get_width()) + hseparation;
+ for (int i = 0; i < 4; i++) {
+ check_ofs = MAX(check_ofs, check[i]->get_width());
+ check_ofs = MAX(check_ofs, uncheck[i]->get_width());
+ }
+ check_ofs += hseparation;
}
Point2 ofs = Point2();
@@ -585,7 +603,7 @@ void PopupMenu::_draw_items() {
String text = items[i].xl_text;
// Separator
- item_ofs.x += items[i].h_ofs;
+ item_ofs.x += items[i].indent * get_theme_constant(SNAME("indent"));
if (items[i].separator) {
if (!text.is_empty() || !items[i].icon.is_null()) {
int content_size = items[i].text_buf->get_size().width + hseparation * 2;
@@ -620,7 +638,8 @@ void PopupMenu::_draw_items() {
// Checkboxes
if (items[i].checkable_type && !items[i].separator) {
- Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr();
+ int disabled = int(items[i].disabled) * 2;
+ Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1 + disabled] : uncheck[items[i].checkable_type - 1 + disabled]).ptr();
if (rtl) {
icon->draw(ci, Size2(control->get_size().width - item_ofs.x - icon->get_width(), item_ofs.y) + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color);
} else {
@@ -769,6 +788,32 @@ void PopupMenu::_shape_item(int p_item) {
}
}
+void PopupMenu::_menu_changed() {
+ emit_signal(SNAME("menu_changed"));
+}
+
+void PopupMenu::add_child_notify(Node *p_child) {
+ Window::add_child_notify(p_child);
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(p_child);
+ if (!pm) {
+ return;
+ }
+ p_child->connect("menu_changed", callable_mp(this, &PopupMenu::_menu_changed));
+ _menu_changed();
+}
+
+void PopupMenu::remove_child_notify(Node *p_child) {
+ Window::remove_child_notify(p_child);
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(p_child);
+ if (!pm) {
+ return;
+ }
+ p_child->disconnect("menu_changed", callable_mp(this, &PopupMenu::_menu_changed));
+ _menu_changed();
+}
+
void PopupMenu::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -790,6 +835,7 @@ void PopupMenu::_notification(int p_what) {
}
child_controls_changed();
+ _menu_changed();
control->update();
} break;
@@ -884,6 +930,7 @@ void PopupMenu::add_item(const String &p_label, int p_id, Key p_accel) {
control->update();
child_controls_changed();
notify_property_list_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, Key p_accel) {
@@ -895,6 +942,7 @@ void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_labe
control->update();
child_controls_changed();
notify_property_list_changed();
+ _menu_changed();
}
void PopupMenu::add_check_item(const String &p_label, int p_id, Key p_accel) {
@@ -905,6 +953,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, Key p_accel) {
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, Key p_accel) {
@@ -926,6 +975,7 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_id, Key p_acce
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, Key p_accel) {
@@ -937,6 +987,7 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const St
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id, Key p_accel) {
@@ -948,6 +999,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
#define ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global) \
@@ -966,6 +1018,7 @@ void PopupMenu::add_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_g
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
@@ -976,6 +1029,7 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortc
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
@@ -986,6 +1040,7 @@ void PopupMenu::add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bo
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
@@ -997,6 +1052,7 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
@@ -1007,6 +1063,7 @@ void PopupMenu::add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
@@ -1018,6 +1075,7 @@ void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, cons
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_id) {
@@ -1030,6 +1088,7 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu,
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
#undef ITEM_SETUP_WITH_ACCEL
@@ -1052,6 +1111,7 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) {
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_text_direction(int p_item, Control::TextDirection p_text_direction) {
@@ -1088,6 +1148,7 @@ void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
@@ -1100,6 +1161,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_id(int p_idx, int p_id) {
@@ -1111,6 +1173,7 @@ void PopupMenu::set_item_id(int p_idx, int p_id) {
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) {
@@ -1123,6 +1186,7 @@ void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) {
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
@@ -1133,6 +1197,7 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
items.write[p_idx].metadata = p_meta;
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
@@ -1143,6 +1208,7 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
items.write[p_idx].disabled = p_disabled;
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
@@ -1153,6 +1219,7 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
items.write[p_idx].submenu = p_submenu;
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::toggle_item_checked(int p_idx) {
@@ -1160,6 +1227,7 @@ void PopupMenu::toggle_item_checked(int p_idx) {
items.write[p_idx].checked = !items[p_idx].checked;
control->update();
child_controls_changed();
+ _menu_changed();
}
String PopupMenu::get_item_text(int p_idx) const {
@@ -1242,9 +1310,14 @@ Ref<Shortcut> PopupMenu::get_item_shortcut(int p_idx) const {
return items[p_idx].shortcut;
}
-int PopupMenu::get_item_horizontal_offset(int p_idx) const {
+int PopupMenu::get_item_indent(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, items.size(), 0);
- return items[p_idx].h_ofs;
+ return items[p_idx].indent;
+}
+
+int PopupMenu::get_item_max_states(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, items.size(), -1);
+ return items[p_idx].max_states;
}
int PopupMenu::get_item_state(int p_idx) const {
@@ -1273,6 +1346,7 @@ void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE;
control->update();
+ _menu_changed();
}
void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) {
@@ -1282,6 +1356,7 @@ void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE;
control->update();
+ _menu_changed();
}
void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) {
@@ -1291,6 +1366,7 @@ void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].tooltip = p_tooltip;
control->update();
+ _menu_changed();
}
void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global) {
@@ -1310,16 +1386,18 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bo
}
control->update();
+ _menu_changed();
}
-void PopupMenu::set_item_horizontal_offset(int p_idx, int p_offset) {
+void PopupMenu::set_item_indent(int p_idx, int p_indent) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
- items.write[p_idx].h_ofs = p_offset;
+ items.write[p_idx].indent = p_indent;
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_multistate(int p_idx, int p_state) {
@@ -1329,6 +1407,7 @@ void PopupMenu::set_item_multistate(int p_idx, int p_state) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].state = p_state;
control->update();
+ _menu_changed();
}
void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) {
@@ -1338,6 +1417,7 @@ void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, items.size());
items.write[p_idx].shortcut_is_disabled = p_disabled;
control->update();
+ _menu_changed();
}
void PopupMenu::toggle_item_multistate(int p_idx) {
@@ -1352,6 +1432,7 @@ void PopupMenu::toggle_item_multistate(int p_idx) {
}
control->update();
+ _menu_changed();
}
bool PopupMenu::is_item_checkable(int p_idx) const {
@@ -1364,6 +1445,11 @@ bool PopupMenu::is_item_radio_checkable(int p_idx) const {
return items[p_idx].checkable_type == Item::CHECKABLE_TYPE_RADIO_BUTTON;
}
+bool PopupMenu::is_item_shortcut_global(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, items.size(), false);
+ return items[p_idx].shortcut_is_global;
+}
+
bool PopupMenu::is_item_shortcut_disabled(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, items.size(), false);
return items[p_idx].shortcut_is_disabled;
@@ -1394,6 +1480,7 @@ void PopupMenu::set_item_count(int p_count) {
control->update();
child_controls_changed();
notify_property_list_changed();
+ _menu_changed();
}
int PopupMenu::get_item_count() const {
@@ -1535,6 +1622,7 @@ void PopupMenu::remove_item(int p_idx) {
items.remove_at(p_idx);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_separator(const String &p_text, int p_id) {
@@ -1547,6 +1635,7 @@ void PopupMenu::add_separator(const String &p_text, int p_id) {
}
items.push_back(sep);
control->update();
+ _menu_changed();
}
void PopupMenu::clear() {
@@ -1560,6 +1649,7 @@ void PopupMenu::clear() {
control->update();
child_controls_changed();
notify_property_list_changed();
+ _menu_changed();
}
void PopupMenu::_ref_shortcut(Ref<Shortcut> p_sc) {
@@ -1834,7 +1924,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_as_radio_checkable", "index", "enable"), &PopupMenu::set_item_as_radio_checkable);
ClassDB::bind_method(D_METHOD("set_item_tooltip", "index", "tooltip"), &PopupMenu::set_item_tooltip);
ClassDB::bind_method(D_METHOD("set_item_shortcut", "index", "shortcut", "global"), &PopupMenu::set_item_shortcut, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("set_item_horizontal_offset", "index", "offset"), &PopupMenu::set_item_horizontal_offset);
+ ClassDB::bind_method(D_METHOD("set_item_indent", "index", "indent"), &PopupMenu::set_item_indent);
ClassDB::bind_method(D_METHOD("set_item_multistate", "index", "state"), &PopupMenu::set_item_multistate);
ClassDB::bind_method(D_METHOD("set_item_shortcut_disabled", "index", "disabled"), &PopupMenu::set_item_shortcut_disabled);
@@ -1858,7 +1948,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_item_shortcut_disabled", "index"), &PopupMenu::is_item_shortcut_disabled);
ClassDB::bind_method(D_METHOD("get_item_tooltip", "index"), &PopupMenu::get_item_tooltip);
ClassDB::bind_method(D_METHOD("get_item_shortcut", "index"), &PopupMenu::get_item_shortcut);
- ClassDB::bind_method(D_METHOD("get_item_horizontal_offset", "index"), &PopupMenu::get_item_horizontal_offset);
+ ClassDB::bind_method(D_METHOD("get_item_indent", "index"), &PopupMenu::get_item_indent);
ClassDB::bind_method(D_METHOD("set_current_index", "index"), &PopupMenu::set_current_index);
ClassDB::bind_method(D_METHOD("get_current_index"), &PopupMenu::get_current_index);
@@ -1898,6 +1988,7 @@ void PopupMenu::_bind_methods() {
ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("index_pressed", PropertyInfo(Variant::INT, "index")));
+ ADD_SIGNAL(MethodInfo("menu_changed"));
}
void PopupMenu::popup(const Rect2 &p_bounds) {
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index e203793c2e..d3ad0762e4 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -68,7 +68,7 @@ class PopupMenu : public Popup {
Key accel = Key::NONE;
int _ofs_cache = 0;
int _height_cache = 0;
- int h_ofs = 0;
+ int indent = 0;
Ref<Shortcut> shortcut;
bool shortcut_is_global = false;
bool shortcut_is_disabled = false;
@@ -134,8 +134,11 @@ class PopupMenu : public Popup {
void _minimum_lifetime_timeout();
void _close_pressed();
+ void _menu_changed();
protected:
+ virtual void add_child_notify(Node *p_child) override;
+ virtual void remove_child_notify(Node *p_child) override;
void _notification(int p_what);
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -183,7 +186,7 @@ public:
void set_item_as_radio_checkable(int p_idx, bool p_radio_checkable);
void set_item_tooltip(int p_idx, const String &p_tooltip);
void set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global = false);
- void set_item_horizontal_offset(int p_idx, int p_offset);
+ void set_item_indent(int p_idx, int p_indent);
void set_item_multistate(int p_idx, int p_state);
void toggle_item_multistate(int p_idx);
void set_item_shortcut_disabled(int p_idx, bool p_disabled);
@@ -206,9 +209,11 @@ public:
bool is_item_checkable(int p_idx) const;
bool is_item_radio_checkable(int p_idx) const;
bool is_item_shortcut_disabled(int p_idx) const;
+ bool is_item_shortcut_global(int p_idx) const;
String get_item_tooltip(int p_idx) const;
Ref<Shortcut> get_item_shortcut(int p_idx) const;
- int get_item_horizontal_offset(int p_idx) const;
+ int get_item_indent(int p_idx) const;
+ int get_item_max_states(int p_idx) const;
int get_item_state(int p_idx) const;
void set_current_index(int p_idx);
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 984f20ee58..ab466089a7 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -4912,15 +4912,19 @@ void RichTextLabel::set_percent_visible(float p_percent) {
if (percent_visible != p_percent) {
_stop_thread();
- if (p_percent < 0 || p_percent >= 1) {
+ if (percent_visible >= 1.0) {
visible_characters = -1;
- percent_visible = 1;
+ percent_visible = 1.0;
+ } else if (percent_visible < 0.0) {
+ visible_characters = 0;
+ percent_visible = 0.0;
} else {
visible_characters = get_total_character_count() * p_percent;
percent_visible = p_percent;
}
+
if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
- main->first_invalid_line.store(0); //invalidate ALL
+ main->first_invalid_line.store(0); // Invalidate ALL.
_validate_line_caches();
}
update();
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 1eb6c5a554..ede7bfb0bf 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -749,6 +749,7 @@ int TreeItem::get_child_count() {
}
Array TreeItem::get_children() {
+ // Don't need to explicitly create children cache, because get_child_count creates it.
int size = get_child_count();
Array arr;
arr.resize(size);
@@ -770,6 +771,22 @@ int TreeItem::get_index() {
return idx - 1;
}
+#ifdef DEV_ENABLED
+void TreeItem::validate_cache() const {
+ if (!parent || parent->children_cache.is_empty()) {
+ return;
+ }
+ TreeItem *scan = parent->first_child;
+ int index = 0;
+ while (scan) {
+ DEV_ASSERT(parent->children_cache[index] == scan);
+ ++index;
+ scan = scan->get_next();
+ }
+ DEV_ASSERT(index == parent->children_cache.size());
+}
+#endif
+
void TreeItem::move_before(TreeItem *p_item) {
ERR_FAIL_NULL(p_item);
ERR_FAIL_COND(is_root);
@@ -797,7 +814,11 @@ void TreeItem::move_before(TreeItem *p_item) {
parent->children_cache.clear();
} else {
parent->first_child = this;
- parent->children_cache.insert(0, this);
+ // If the cache is empty, it has not been built but there
+ // are items in the tree (note p_item != nullptr,) so we cannot update it.
+ if (!parent->children_cache.is_empty()) {
+ parent->children_cache.insert(0, this);
+ }
}
prev = item_prev;
@@ -807,6 +828,8 @@ void TreeItem::move_before(TreeItem *p_item) {
if (tree && old_tree == tree) {
tree->update();
}
+
+ validate_cache();
}
void TreeItem::move_after(TreeItem *p_item) {
@@ -839,12 +862,17 @@ void TreeItem::move_after(TreeItem *p_item) {
if (next) {
parent->children_cache.clear();
} else {
- parent->children_cache.append(this);
+ // If the cache is empty, it has not been built but there
+ // are items in the tree (note p_item != nullptr,) so we cannot update it.
+ if (!parent->children_cache.is_empty()) {
+ parent->children_cache.append(this);
+ }
}
if (tree && old_tree == tree) {
tree->update();
}
+ validate_cache();
}
void TreeItem::remove_child(TreeItem *p_item) {
@@ -859,6 +887,7 @@ void TreeItem::remove_child(TreeItem *p_item) {
if (tree) {
tree->update();
}
+ validate_cache();
}
void TreeItem::set_selectable(int p_column, bool p_selectable) {
@@ -1396,6 +1425,7 @@ TreeItem::TreeItem(Tree *p_tree) {
TreeItem::~TreeItem() {
_unlink_from_tree();
+ validate_cache();
prev = nullptr;
clear_children();
_change_tree(nullptr);
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index f0819e2980..bcc2419b80 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -342,6 +342,13 @@ public:
Array get_children();
int get_index();
+#ifdef DEV_ENABLED
+ // This debugging code can be removed once the current refactoring of this class is complete.
+ void validate_cache() const;
+#else
+ void validate_cache() const {}
+#endif
+
void move_before(TreeItem *p_item);
void move_after(TreeItem *p_item);
diff --git a/scene/gui/video_stream_player.h b/scene/gui/video_stream_player.h
index 913e7905b6..9974eb8488 100644
--- a/scene/gui/video_stream_player.h
+++ b/scene/gui/video_stream_player.h
@@ -79,7 +79,7 @@ class VideoStreamPlayer : public Control {
protected:
static void _bind_methods();
void _notification(int p_notification);
- void _validate_property(PropertyInfo &p_property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
Size2 get_minimum_size() const override;
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 3a071ef542..8f40f257f9 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -286,9 +286,9 @@ void CanvasLayer::_update_follow_viewport(bool p_force_exit) {
}
}
-void CanvasLayer::_validate_property(PropertyInfo &property) const {
- if (!follow_viewport && property.name == "follow_viewport_scale") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void CanvasLayer::_validate_property(PropertyInfo &p_property) const {
+ if (!follow_viewport && p_property.name == "follow_viewport_scale") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h
index 2493675b31..74b5ebd453 100644
--- a/scene/main/canvas_layer.h
+++ b/scene/main/canvas_layer.h
@@ -64,7 +64,7 @@ class CanvasLayer : public Node {
protected:
void _notification(int p_what);
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_layer(int p_xform);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 584fad9648..cc356e513c 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -3953,9 +3953,9 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(VRS_MAX);
}
-void Viewport::_validate_property(PropertyInfo &property) const {
- if (vrs_mode != VRS_TEXTURE && (property.name == "vrs_texture")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Viewport::_validate_property(PropertyInfo &p_property) const {
+ if (vrs_mode != VRS_TEXTURE && (p_property.name == "vrs_texture")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 4221baff06..a0ec2d54dd 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -709,7 +709,7 @@ public:
bool is_using_xr();
#endif // _3D_DISABLED
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
Viewport();
~Viewport();
};
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index d40b82f5eb..63cc535e26 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -1510,8 +1510,8 @@ bool Window::is_auto_translating() const {
return auto_translate;
}
-void Window::_validate_property(PropertyInfo &property) const {
- if (property.name == "theme_type_variation") {
+void Window::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "theme_type_variation") {
List<StringName> names;
// Only the default theme and the project theme are used for the list of options.
@@ -1534,7 +1534,7 @@ void Window::_validate_property(PropertyInfo &property) const {
unique_names.append(E);
}
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
}
diff --git a/scene/main/window.h b/scene/main/window.h
index c060f1d79d..aa32edbb04 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -158,7 +158,7 @@ protected:
virtual Size2 _get_contents_minimum_size() const;
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
virtual void add_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index a5842106fb..762d9f2a28 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -100,6 +100,7 @@
#include "scene/gui/line_edit.h"
#include "scene/gui/link_button.h"
#include "scene/gui/margin_container.h"
+#include "scene/gui/menu_bar.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/nine_patch_rect.h"
#include "scene/gui/option_button.h"
@@ -157,8 +158,8 @@
#include "scene/resources/immediate_mesh.h"
#include "scene/resources/label_settings.h"
#include "scene/resources/material.h"
-#include "scene/resources/mesh.h"
#include "scene/resources/mesh_data_tool.h"
+#include "scene/resources/multimesh.h"
#include "scene/resources/navigation_mesh.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/particles_material.h"
@@ -259,7 +260,7 @@
#include "scene/resources/fog_material.h"
#include "scene/resources/importer_mesh.h"
#include "scene/resources/mesh_library.h"
-#endif
+#endif // _3D_DISABLED
static Ref<ResourceFormatSaverText> resource_saver_text;
static Ref<ResourceFormatLoaderText> resource_loader_text;
@@ -351,6 +352,7 @@ void register_scene_types() {
GDREGISTER_CLASS(VSlider);
GDREGISTER_CLASS(Popup);
GDREGISTER_CLASS(PopupPanel);
+ GDREGISTER_CLASS(MenuBar);
GDREGISTER_CLASS(MenuButton);
GDREGISTER_CLASS(CheckBox);
GDREGISTER_CLASS(CheckButton);
@@ -573,7 +575,7 @@ void register_scene_types() {
GDREGISTER_CLASS(NavigationObstacle3D);
OS::get_singleton()->yield(); // may take time to init
-#endif
+#endif // _3D_DISABLED
/* REGISTER SHADER */
@@ -763,10 +765,6 @@ void register_scene_types() {
SceneTree::add_idle_callback(ParticlesMaterial::flush_changes);
ParticlesMaterial::init_shaders();
- GDREGISTER_CLASS(ProceduralSkyMaterial);
- GDREGISTER_CLASS(PanoramaSkyMaterial);
- GDREGISTER_CLASS(PhysicalSkyMaterial);
-
GDREGISTER_VIRTUAL_CLASS(Mesh);
GDREGISTER_CLASS(ArrayMesh);
GDREGISTER_CLASS(PlaceholderMesh);
@@ -794,6 +792,9 @@ void register_scene_types() {
GDREGISTER_CLASS(StandardMaterial3D);
GDREGISTER_CLASS(ORMMaterial3D);
GDREGISTER_CLASS(PlaceholderMaterial);
+ GDREGISTER_CLASS(ProceduralSkyMaterial);
+ GDREGISTER_CLASS(PanoramaSkyMaterial);
+ GDREGISTER_CLASS(PhysicalSkyMaterial);
SceneTree::add_idle_callback(BaseMaterial3D::flush_changes);
BaseMaterial3D::init_shaders();
@@ -822,9 +823,7 @@ void register_scene_types() {
ClassDB::register_class<SkeletonModification3DStackHolder>();
OS::get_singleton()->yield(); // may take time to init
-
- GDREGISTER_CLASS(VelocityTracker3D);
-#endif
+#endif // _3D_DISABLED
GDREGISTER_CLASS(PhysicsMaterial);
GDREGISTER_CLASS(World3D);
@@ -843,7 +842,6 @@ void register_scene_types() {
GDREGISTER_CLASS(CurveXYZTexture);
GDREGISTER_CLASS(GradientTexture1D);
GDREGISTER_CLASS(GradientTexture2D);
- GDREGISTER_CLASS(ProxyTexture);
GDREGISTER_CLASS(AnimatedTexture);
GDREGISTER_CLASS(CameraTexture);
GDREGISTER_VIRTUAL_CLASS(TextureLayered);
@@ -1052,7 +1050,6 @@ void register_scene_types() {
ClassDB::add_compatibility_class("Spatial", "Node3D");
ClassDB::add_compatibility_class("SpatialGizmo", "Node3DGizmo");
ClassDB::add_compatibility_class("SpatialMaterial", "StandardMaterial3D");
- ClassDB::add_compatibility_class("SpatialVelocityTracker", "VelocityTracker3D");
ClassDB::add_compatibility_class("SphereShape", "SphereShape3D");
ClassDB::add_compatibility_class("SpotLight", "SpotLight3D");
ClassDB::add_compatibility_class("SpringArm", "SpringArm3D");
@@ -1205,11 +1202,10 @@ void unregister_scene_types() {
// StandardMaterial3D is not initialised when 3D is disabled, so it shouldn't be cleaned up either
#ifndef _3D_DISABLED
BaseMaterial3D::finish_shaders();
-#endif // _3D_DISABLED
-
PhysicalSkyMaterial::cleanup_shader();
PanoramaSkyMaterial::cleanup_shader();
ProceduralSkyMaterial::cleanup_shader();
+#endif // _3D_DISABLED
ParticlesMaterial::finish_shaders();
CanvasItemMaterial::finish_shaders();
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 69b30b72b0..0782f779b5 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -967,7 +967,6 @@ int Animation::find_track(const NodePath &p_path, const TrackType p_type) const
void Animation::track_set_interpolation_type(int p_track, InterpolationType p_interp) {
ERR_FAIL_INDEX(p_track, tracks.size());
- ERR_FAIL_INDEX(p_interp, 3);
tracks[p_track]->interpolation = p_interp;
emit_changed();
}
@@ -2283,6 +2282,8 @@ int Animation::_find(const Vector<K> &p_keys, double p_time, bool p_backward) co
return middle;
}
+// Linear interpolation for anytype.
+
Vector3 Animation::_interpolate(const Vector3 &p_a, const Vector3 &p_b, real_t p_c) const {
return p_a.lerp(p_b, p_c);
}
@@ -2301,6 +2302,8 @@ real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c)
return p_a * (1.0 - p_c) + p_b * p_c;
}
+// Cubic interpolation for anytype.
+
Vector3 Animation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const {
return p_a.cubic_interpolate(p_b, p_pre_a, p_post_b, p_c);
}
@@ -2389,6 +2392,96 @@ real_t Animation::_cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, c
return _interpolate(p_a, p_b, p_c);
}
+// Cubic interpolation in time for anytype.
+
+Vector3 Animation::_cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ return p_a.cubic_interpolate_in_time(p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t);
+}
+
+Quaternion Animation::_cubic_interpolate_in_time(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ return p_a.spherical_cubic_interpolate_in_time(p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t);
+}
+
+Variant Animation::_cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ Variant::Type type_a = p_a.get_type();
+ Variant::Type type_b = p_b.get_type();
+ Variant::Type type_pa = p_pre_a.get_type();
+ Variant::Type type_pb = p_post_b.get_type();
+
+ //make int and real play along
+
+ uint32_t vformat = 1 << type_a;
+ vformat |= 1 << type_b;
+ vformat |= 1 << type_pa;
+ vformat |= 1 << type_pb;
+
+ if (vformat == ((1 << Variant::INT) | (1 << Variant::FLOAT)) || vformat == (1 << Variant::FLOAT)) {
+ //mix of real and int
+ real_t a = p_a;
+ real_t b = p_b;
+ real_t pa = p_pre_a;
+ real_t pb = p_post_b;
+
+ return Math::cubic_interpolate_in_time(a, b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
+ } else if ((vformat & (vformat - 1))) {
+ return p_a; //can't interpolate, mix of types
+ }
+
+ switch (type_a) {
+ case Variant::VECTOR2: {
+ Vector2 a = p_a;
+ Vector2 b = p_b;
+ Vector2 pa = p_pre_a;
+ Vector2 pb = p_post_b;
+
+ return a.cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
+ }
+ case Variant::RECT2: {
+ Rect2 a = p_a;
+ Rect2 b = p_b;
+ Rect2 pa = p_pre_a;
+ Rect2 pb = p_post_b;
+
+ return Rect2(
+ a.position.cubic_interpolate_in_time(b.position, pa.position, pb.position, p_c, p_b_t, p_pre_a_t, p_post_b_t),
+ a.size.cubic_interpolate_in_time(b.size, pa.size, pb.size, p_c, p_b_t, p_pre_a_t, p_post_b_t));
+ }
+ case Variant::VECTOR3: {
+ Vector3 a = p_a;
+ Vector3 b = p_b;
+ Vector3 pa = p_pre_a;
+ Vector3 pb = p_post_b;
+
+ return a.cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
+ }
+ case Variant::QUATERNION: {
+ Quaternion a = p_a;
+ Quaternion b = p_b;
+ Quaternion pa = p_pre_a;
+ Quaternion pb = p_post_b;
+
+ return a.spherical_cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
+ }
+ case Variant::AABB: {
+ AABB a = p_a;
+ AABB b = p_b;
+ AABB pa = p_pre_a;
+ AABB pb = p_post_b;
+
+ return AABB(
+ a.position.cubic_interpolate_in_time(b.position, pa.position, pb.position, p_c, p_b_t, p_pre_a_t, p_post_b_t),
+ a.size.cubic_interpolate_in_time(b.size, pa.size, pb.size, p_c, p_b_t, p_pre_a_t, p_post_b_t));
+ }
+ default: {
+ return _interpolate(p_a, p_b, p_c);
+ }
+ }
+}
+
+real_t Animation::_cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ return _interpolate(p_a, p_b, p_c);
+}
+
template <class T>
T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward) const {
int len = _find(p_keys, length) + 1; // try to find last key (there may be more past the end)
@@ -2568,26 +2661,65 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol
case INTERPOLATION_LINEAR: {
return _interpolate(p_keys[idx].value, p_keys[next].value, c);
} break;
- case INTERPOLATION_CUBIC: {
- int pre = idx - 1;
- if (pre < 0) {
- if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
- pre = len - 1;
- } else {
- pre = 0;
+ case INTERPOLATION_CUBIC:
+ case INTERPOLATION_CUBIC_IN_TIME: {
+ int pre = 0;
+ int post = 0;
+ if (!p_backward) {
+ pre = idx - 1;
+ if (pre < 0) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ pre = len - 1;
+ } else {
+ pre = 0;
+ }
}
- }
- int post = next + 1;
- if (post >= len) {
- if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
- post = 0;
- } else {
- post = next;
+ post = next + 1;
+ if (post >= len) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ post = 0;
+ } else {
+ post = next;
+ }
+ }
+ } else {
+ pre = idx + 1;
+ if (pre >= len) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ pre = 0;
+ } else {
+ pre = idx;
+ }
+ }
+ post = next - 1;
+ if (post < 0) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ post = len - 1;
+ } else {
+ post = 0;
+ }
}
}
- return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c);
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ if (p_interp == INTERPOLATION_CUBIC) {
+ return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c);
+ }
+ return _cubic_interpolate_in_time(
+ p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c,
+ pre > idx ? -length + p_keys[pre].time - p_keys[idx].time : p_keys[pre].time - p_keys[idx].time,
+ next < idx ? length + p_keys[next].time - p_keys[idx].time : p_keys[next].time - p_keys[idx].time,
+ next < idx || post <= idx ? length + p_keys[post].time - p_keys[idx].time : p_keys[post].time - p_keys[idx].time);
+ }
+ if (p_interp == INTERPOLATION_CUBIC) {
+ return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c);
+ }
+ return _cubic_interpolate_in_time(
+ p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c,
+ p_keys[pre].time - p_keys[idx].time,
+ p_keys[next].time - p_keys[idx].time,
+ p_keys[post].time - p_keys[idx].time);
} break;
default:
return p_keys[idx].value;
@@ -3839,6 +3971,7 @@ void Animation::_bind_methods() {
BIND_ENUM_CONSTANT(INTERPOLATION_NEAREST);
BIND_ENUM_CONSTANT(INTERPOLATION_LINEAR);
BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC);
+ BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC_IN_TIME);
BIND_ENUM_CONSTANT(UPDATE_CONTINUOUS);
BIND_ENUM_CONSTANT(UPDATE_DISCRETE);
@@ -3868,316 +4001,208 @@ void Animation::clear() {
emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
-bool Animation::_position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm) {
- const Vector3 &v0 = t0.value;
- const Vector3 &v1 = t1.value;
- const Vector3 &v2 = t2.value;
-
- if (v0.is_equal_approx(v2)) {
- //0 and 2 are close, let's see if 1 is close
- if (!v0.is_equal_approx(v1)) {
- //not close, not optimizable
- return false;
- }
-
- } else {
- Vector3 pd = (v2 - v0);
- real_t d0 = pd.dot(v0);
- real_t d1 = pd.dot(v1);
- real_t d2 = pd.dot(v2);
- if (d1 < d0 || d1 > d2) {
- return false;
- }
-
- Vector3 s[2] = { v0, v2 };
- real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
-
- if (d > pd.length() * p_allowed_linear_err) {
- return false; //beyond allowed error for collinearity
- }
-
- if (p_norm != Vector3() && Math::acos(pd.normalized().dot(p_norm)) > p_allowed_angular_error) {
- return false;
- }
+bool Animation::_vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<Vector3> t1, const TKey<Vector3> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) {
+ // Remove overlapping keys.
+ if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) {
+ return true;
}
-
- return true;
-}
-
-bool Animation::_rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle) {
- const Quaternion &q0 = t0.value;
- const Quaternion &q1 = t1.value;
- const Quaternion &q2 = t2.value;
-
- //localize both to rotation from q0
-
- if (q0.is_equal_approx(q2)) {
- if (!q0.is_equal_approx(q1)) {
- return false;
- }
-
- } else {
- Quaternion r02 = (q0.inverse() * q2).normalized();
- Quaternion r01 = (q0.inverse() * q1).normalized();
-
- Vector3 v02, v01;
- real_t a02, a01;
-
- r02.get_axis_angle(v02, a02);
- r01.get_axis_angle(v01, a01);
-
- if (Math::abs(a02) > p_max_optimizable_angle) {
- return false;
- }
-
- if (v01.dot(v02) < 0) {
- //make sure both rotations go the same way to compare
- v02 = -v02;
- a02 = -a02;
- }
-
- real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized())) / Math_PI;
- if (err_01 > p_allowed_angular_error) {
- //not rotating in the same axis
- return false;
- }
-
- if (a01 * a02 < 0) {
- //not rotating in the same direction
- return false;
- }
-
- real_t tr = a01 / a02;
- if (tr < 0 || tr > 1) {
- return false; //rotating too much or too less
+ if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) {
+ return true;
+ }
+ // Calc velocities.
+ Vector3 vc0 = (t1.value - t0.value) / (t1.time - t0.time);
+ Vector3 vc1 = (t2.value - t1.value) / (t2.time - t1.time);
+ real_t v0 = vc0.length();
+ real_t v1 = vc1.length();
+ // Avoid zero div but check equality.
+ if (abs(v0 - v1) < p_allowed_precision_error) {
+ return true;
+ } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
+ return false;
+ }
+ // Check axis.
+ if (vc0.normalized().dot(vc1.normalized()) >= 1.0 - p_allowed_angular_error * 2.0) {
+ real_t ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ if (ratio >= 1.0 - p_allowed_velocity_err) {
+ return true;
}
}
-
- return true;
+ return false;
}
-bool Animation::_scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error) {
- const Vector3 &v0 = t0.value;
- const Vector3 &v1 = t1.value;
- const Vector3 &v2 = t2.value;
-
- if (v0.is_equal_approx(v2)) {
- //0 and 2 are close, let's see if 1 is close
- if (!v0.is_equal_approx(v1)) {
- //not close, not optimizable
+bool Animation::_quaternion_track_optimize_key(const TKey<Quaternion> t0, const TKey<Quaternion> t1, const TKey<Quaternion> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) {
+ // Remove overlapping keys.
+ if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) {
+ return true;
+ }
+ if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) {
+ return true;
+ }
+ // Check axis.
+ Quaternion q0 = t0.value * t1.value * t0.value.inverse();
+ Quaternion q1 = t1.value * t2.value * t1.value.inverse();
+ if (q0.get_axis().dot(q1.get_axis()) >= 1.0 - p_allowed_angular_error * 2.0) {
+ // Calc velocities.
+ real_t v0 = Math::acos(t0.value.dot(t1.value)) / (t1.time - t0.time);
+ real_t v1 = Math::acos(t1.value.dot(t2.value)) / (t2.time - t1.time);
+ // Avoid zero div but check equality.
+ if (abs(v0 - v1) < p_allowed_precision_error) {
+ return true;
+ } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
return false;
}
-
- } else {
- Vector3 pd = (v2 - v0);
- real_t d0 = pd.dot(v0);
- real_t d1 = pd.dot(v1);
- real_t d2 = pd.dot(v2);
- if (d1 < d0 || d1 > d2) {
- return false; //beyond segment range
- }
-
- Vector3 s[2] = { v0, v2 };
- real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
-
- if (d > pd.length() * p_allowed_linear_error) {
- return false; //beyond allowed error for colinearity
+ real_t ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ if (ratio >= 1.0 - p_allowed_velocity_err) {
+ return true;
}
}
-
- return true;
+ return false;
}
-bool Animation::_blend_shape_track_optimize_key(const TKey<float> &t0, const TKey<float> &t1, const TKey<float> &t2, real_t p_allowed_unit_error) {
- float v0 = t0.value;
- float v1 = t1.value;
- float v2 = t2.value;
-
- if (Math::is_equal_approx(v1, v2, (float)p_allowed_unit_error)) {
- //0 and 2 are close, let's see if 1 is close
- if (!Math::is_equal_approx(v0, v1, (float)p_allowed_unit_error)) {
- //not close, not optimizable
- return false;
- }
- } else {
- /*
- TODO eventually discuss a way to optimize these better.
- float pd = (v2 - v0);
- real_t d0 = pd.dot(v0);
- real_t d1 = pd.dot(v1);
- real_t d2 = pd.dot(v2);
- if (d1 < d0 || d1 > d2) {
- return false; //beyond segment range
- }
-
- float s[2] = { v0, v2 };
- real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
-
- if (d > pd.length() * p_allowed_linear_error) {
- return false; //beyond allowed error for colinearity
+bool Animation::_float_track_optimize_key(const TKey<float> t0, const TKey<float> t1, const TKey<float> t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) {
+ // Remove overlapping keys.
+ if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) {
+ return true;
+ }
+ if (abs(t0.value - t1.value) < p_allowed_precision_error && abs(t1.value - t2.value) < p_allowed_precision_error) {
+ return true;
+ }
+ // Calc velocities.
+ real_t v0 = (t1.value - t0.value) / (t1.time - t0.time);
+ real_t v1 = (t2.value - t1.value) / (t2.time - t1.time);
+ // Avoid zero div but check equality.
+ if (abs(v0 - v1) < p_allowed_precision_error) {
+ return true;
+ } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
+ return false;
+ }
+ if (!signbit(v0 * v1)) {
+ real_t ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ if (ratio >= 1.0 - p_allowed_velocity_err) {
+ return true;
}
-*/
}
-
- return true;
+ return false;
}
-void Animation::_position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err) {
+void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D);
PositionTrack *tt = static_cast<PositionTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<Vector3> first_erased;
-
- Vector3 norm;
- for (int i = 1; i < tt->positions.size() - 1; i++) {
- TKey<Vector3> &t0 = tt->positions.write[i - 1];
- TKey<Vector3> &t1 = tt->positions.write[i];
- TKey<Vector3> &t2 = tt->positions.write[i + 1];
-
- bool erase = _position_track_optimize_key(t0, t1, t2, p_allowed_linear_err, p_allowed_angular_err, norm);
- if (erase && !prev_erased) {
- norm = (t2.value - t1.value).normalized();
- }
-
- if (prev_erased && !_position_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err, p_allowed_angular_err, norm)) {
- //avoid error to go beyond first erased key
- erase = false;
- }
+ int i = 0;
+ while (i < tt->positions.size() - 2) {
+ TKey<Vector3> t0 = tt->positions[i];
+ TKey<Vector3> t1 = tt->positions[i + 1];
+ TKey<Vector3> t2 = tt->positions[i + 2];
+ bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
-
- tt->positions.remove_at(i);
- i--;
-
+ tt->positions.remove_at(i + 1);
} else {
- prev_erased = false;
- norm = Vector3();
+ i++;
+ }
+ }
+
+ if (tt->positions.size() == 2) {
+ if ((tt->positions[0].value - tt->positions[1].value).length() < p_allowed_precision_error) {
+ tt->positions.remove_at(1);
}
}
}
-void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) {
+void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_ROTATION_3D);
RotationTrack *tt = static_cast<RotationTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<Quaternion> first_erased;
-
- for (int i = 1; i < tt->rotations.size() - 1; i++) {
- TKey<Quaternion> &t0 = tt->rotations.write[i - 1];
- TKey<Quaternion> &t1 = tt->rotations.write[i];
- TKey<Quaternion> &t2 = tt->rotations.write[i + 1];
- bool erase = _rotation_track_optimize_key(t0, t1, t2, p_allowed_angular_err, p_max_optimizable_angle);
-
- if (prev_erased && !_rotation_track_optimize_key(t0, first_erased, t2, p_allowed_angular_err, p_max_optimizable_angle)) {
- //avoid error to go beyond first erased key
- erase = false;
- }
+ int i = 0;
+ while (i < tt->rotations.size() - 2) {
+ TKey<Quaternion> t0 = tt->rotations[i];
+ TKey<Quaternion> t1 = tt->rotations[i + 1];
+ TKey<Quaternion> t2 = tt->rotations[i + 2];
+ bool erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
-
- tt->rotations.remove_at(i);
- i--;
-
+ tt->rotations.remove_at(i + 1);
} else {
- prev_erased = false;
+ i++;
+ }
+ }
+
+ if (tt->rotations.size() == 2) {
+ if ((tt->rotations[0].value - tt->rotations[1].value).length() < p_allowed_precision_error) {
+ tt->rotations.remove_at(1);
}
}
}
-void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_linear_err) {
+void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_SCALE_3D);
ScaleTrack *tt = static_cast<ScaleTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<Vector3> first_erased;
-
- for (int i = 1; i < tt->scales.size() - 1; i++) {
- TKey<Vector3> &t0 = tt->scales.write[i - 1];
- TKey<Vector3> &t1 = tt->scales.write[i];
- TKey<Vector3> &t2 = tt->scales.write[i + 1];
-
- bool erase = _scale_track_optimize_key(t0, t1, t2, p_allowed_linear_err);
- if (prev_erased && !_scale_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err)) {
- //avoid error to go beyond first erased key
- erase = false;
- }
+ int i = 0;
+ while (i < tt->scales.size() - 2) {
+ TKey<Vector3> t0 = tt->scales[i];
+ TKey<Vector3> t1 = tt->scales[i + 1];
+ TKey<Vector3> t2 = tt->scales[i + 2];
+ bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
-
- tt->scales.remove_at(i);
- i--;
-
+ tt->scales.remove_at(i + 1);
} else {
- prev_erased = false;
+ i++;
+ }
+ }
+
+ if (tt->scales.size() == 2) {
+ if ((tt->scales[0].value - tt->scales[1].value).length() < p_allowed_precision_error) {
+ tt->scales.remove_at(1);
}
}
}
-void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_linear_err) {
+void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_BLEND_SHAPE);
BlendShapeTrack *tt = static_cast<BlendShapeTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<float> first_erased;
- first_erased.value = 0.0;
- for (int i = 1; i < tt->blend_shapes.size() - 1; i++) {
- TKey<float> &t0 = tt->blend_shapes.write[i - 1];
- TKey<float> &t1 = tt->blend_shapes.write[i];
- TKey<float> &t2 = tt->blend_shapes.write[i + 1];
-
- bool erase = _blend_shape_track_optimize_key(t0, t1, t2, p_allowed_linear_err);
-
- if (prev_erased && !_blend_shape_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err)) {
- //avoid error to go beyond first erased key
- erase = false;
- }
+ int i = 0;
+ while (i < tt->blend_shapes.size() - 2) {
+ TKey<float> t0 = tt->blend_shapes[i];
+ TKey<float> t1 = tt->blend_shapes[i + 1];
+ TKey<float> t2 = tt->blend_shapes[i + 2];
+ bool erase = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error);
if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
-
- tt->blend_shapes.remove_at(i);
- i--;
-
+ tt->blend_shapes.remove_at(i + 1);
} else {
- prev_erased = false;
+ i++;
+ }
+ }
+
+ if (tt->blend_shapes.size() == 2) {
+ if (abs(tt->blend_shapes[0].value - tt->blend_shapes[1].value) < p_allowed_precision_error) {
+ tt->blend_shapes.remove_at(1);
}
}
}
-void Animation::optimize(real_t p_allowed_linear_err, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) {
+void Animation::optimize(real_t p_allowed_velocity_err, real_t p_allowed_angular_err, int p_precision) {
+ real_t precision = Math::pow(0.1, p_precision);
for (int i = 0; i < tracks.size(); i++) {
if (track_is_compressed(i)) {
continue; //not possible to optimize compressed track
}
if (tracks[i]->type == TYPE_POSITION_3D) {
- _position_track_optimize(i, p_allowed_linear_err, p_allowed_angular_err);
+ _position_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision);
} else if (tracks[i]->type == TYPE_ROTATION_3D) {
- _rotation_track_optimize(i, p_allowed_angular_err, p_max_optimizable_angle);
+ _rotation_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision);
} else if (tracks[i]->type == TYPE_SCALE_3D) {
- _scale_track_optimize(i, p_allowed_linear_err);
+ _scale_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision);
} else if (tracks[i]->type == TYPE_BLEND_SHAPE) {
- _blend_shape_track_optimize(i, p_allowed_linear_err);
+ _blend_shape_track_optimize(i, p_allowed_velocity_err, precision);
}
}
}
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index bf9f786a0d..367134b94c 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -56,7 +56,8 @@ public:
enum InterpolationType {
INTERPOLATION_NEAREST,
INTERPOLATION_LINEAR,
- INTERPOLATION_CUBIC
+ INTERPOLATION_CUBIC,
+ INTERPOLATION_CUBIC_IN_TIME,
};
enum UpdateMode {
@@ -231,6 +232,11 @@ private:
_FORCE_INLINE_ Variant _cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c) const;
_FORCE_INLINE_ real_t _cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c) const;
+ _FORCE_INLINE_ Vector3 _cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+ _FORCE_INLINE_ Quaternion _cubic_interpolate_in_time(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+ _FORCE_INLINE_ Variant _cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+ _FORCE_INLINE_ real_t _cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+
template <class T>
_FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward = false) const;
@@ -351,15 +357,14 @@ private:
return idxr;
}
- bool _position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_alowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm);
- bool _rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle);
- bool _scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error);
- bool _blend_shape_track_optimize_key(const TKey<float> &t0, const TKey<float> &t1, const TKey<float> &t2, real_t p_allowed_unit_error);
+ bool _vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<Vector3> t1, const TKey<Vector3> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
+ bool _quaternion_track_optimize_key(const TKey<Quaternion> t0, const TKey<Quaternion> t1, const TKey<Quaternion> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
+ bool _float_track_optimize_key(const TKey<float> t0, const TKey<float> t1, const TKey<float> t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error);
- void _position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err);
- void _rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle);
- void _scale_track_optimize(int p_idx, real_t p_allowed_linear_err);
- void _blend_shape_track_optimize(int p_idx, real_t p_allowed_unit_error);
+ void _position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error);
+ void _rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
+ void _scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error);
+ void _blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_precision_error);
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@@ -475,7 +480,7 @@ public:
void clear();
- void optimize(real_t p_allowed_linear_err = 0.05, real_t p_allowed_angular_err = 0.01, real_t p_max_optimizable_angle = Math_PI * 0.125);
+ void optimize(real_t p_allowed_velocity_err = 0.01, real_t p_allowed_angular_err = 0.01, int p_precision = 3);
void compress(uint32_t p_page_size = 8192, uint32_t p_fps = 120, float p_split_tolerance = 4.0); // 4.0 seems to be the split tolerance sweet spot from many tests
Animation();
diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp
index aff917b2d4..f4697a09b8 100644
--- a/scene/resources/bone_map.cpp
+++ b/scene/resources/bone_map.cpp
@@ -167,7 +167,7 @@ void BoneMap::_bind_methods() {
ADD_SIGNAL(MethodInfo("profile_updated"));
}
-void BoneMap::_validate_property(PropertyInfo &property) const {
+void BoneMap::_validate_property(PropertyInfo &p_property) const {
//
}
diff --git a/scene/resources/bone_map.h b/scene/resources/bone_map.h
index 17452dfc73..e1bb571df9 100644
--- a/scene/resources/bone_map.h
+++ b/scene/resources/bone_map.h
@@ -45,7 +45,7 @@ class BoneMap : public Resource {
protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp
index 97617adbae..0b11366591 100644
--- a/scene/resources/camera_effects.cpp
+++ b/scene/resources/camera_effects.cpp
@@ -145,11 +145,11 @@ void CameraEffects::_update_override_exposure() {
// Private methods, constructor and destructor
-void CameraEffects::_validate_property(PropertyInfo &property) const {
- if ((!dof_blur_far_enabled && (property.name == "dof_blur_far_distance" || property.name == "dof_blur_far_transition")) ||
- (!dof_blur_near_enabled && (property.name == "dof_blur_near_distance" || property.name == "dof_blur_near_transition")) ||
- (!override_exposure_enabled && property.name == "override_exposure")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void CameraEffects::_validate_property(PropertyInfo &p_property) const {
+ if ((!dof_blur_far_enabled && (p_property.name == "dof_blur_far_distance" || p_property.name == "dof_blur_far_transition")) ||
+ (!dof_blur_near_enabled && (p_property.name == "dof_blur_near_distance" || p_property.name == "dof_blur_near_transition")) ||
+ (!override_exposure_enabled && p_property.name == "override_exposure")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/resources/camera_effects.h b/scene/resources/camera_effects.h
index 85ae64cdf5..7353931d16 100644
--- a/scene/resources/camera_effects.h
+++ b/scene/resources/camera_effects.h
@@ -59,7 +59,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
virtual RID get_rid() const override;
diff --git a/scene/resources/canvas_item_material.cpp b/scene/resources/canvas_item_material.cpp
index aa6cc4aded..b16059c218 100644
--- a/scene/resources/canvas_item_material.cpp
+++ b/scene/resources/canvas_item_material.cpp
@@ -227,9 +227,9 @@ bool CanvasItemMaterial::get_particles_anim_loop() const {
return particles_anim_loop;
}
-void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("particles_anim_") && !particles_animation) {
- property.usage = PROPERTY_USAGE_NONE;
+void CanvasItemMaterial::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("particles_anim_") && !particles_animation) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
diff --git a/scene/resources/canvas_item_material.h b/scene/resources/canvas_item_material.h
index 160c67d6b1..7eaf5051d4 100644
--- a/scene/resources/canvas_item_material.h
+++ b/scene/resources/canvas_item_material.h
@@ -117,7 +117,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_blend_mode(BlendMode p_blend_mode);
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 5de92acb75..1835604285 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -1167,7 +1167,7 @@ void Curve2D::_get_property_list(List<PropertyInfo> *p_list) const {
void Curve2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve2D::get_point_count);
ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve2D::set_point_count);
- ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve2D::add_point, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "index"), &Curve2D::add_point, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve2D::set_point_position);
ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve2D::get_point_position);
ClassDB::bind_method(D_METHOD("set_point_in", "idx", "position"), &Curve2D::set_point_in);
@@ -1972,7 +1972,7 @@ void Curve3D::_get_property_list(List<PropertyInfo> *p_list) const {
void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve3D::get_point_count);
ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve3D::set_point_count);
- ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve3D::add_point, DEFVAL(Vector3()), DEFVAL(Vector3()), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "index"), &Curve3D::add_point, DEFVAL(Vector3()), DEFVAL(Vector3()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve3D::set_point_position);
ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve3D::get_point_position);
ClassDB::bind_method(D_METHOD("set_point_tilt", "idx", "tilt"), &Curve3D::set_point_tilt);
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index fa375795c1..b96ee5c6c4 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -177,6 +177,27 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("h_separation", "Button", 2 * scale);
+ // MenuBar
+ theme->set_stylebox("normal", "MenuBar", button_normal);
+ theme->set_stylebox("hover", "MenuBar", button_hover);
+ theme->set_stylebox("pressed", "MenuBar", button_pressed);
+ theme->set_stylebox("disabled", "MenuBar", button_disabled);
+ theme->set_stylebox("focus", "MenuBar", focus);
+
+ theme->set_font("font", "MenuBar", Ref<Font>());
+ theme->set_font_size("font_size", "MenuBar", -1);
+ theme->set_constant("outline_size", "MenuBar", 0 * scale);
+
+ theme->set_color("font_color", "MenuBar", control_font_color);
+ theme->set_color("font_pressed_color", "MenuBar", control_font_pressed_color);
+ theme->set_color("font_hover_color", "MenuBar", control_font_hover_color);
+ theme->set_color("font_focus_color", "MenuBar", control_font_focus_color);
+ theme->set_color("font_hover_pressed_color", "MenuBar", control_font_pressed_color);
+ theme->set_color("font_disabled_color", "MenuBar", control_font_disabled_color);
+ theme->set_color("font_outline_color", "MenuBar", Color(1, 1, 1));
+
+ theme->set_constant("h_separation", "MenuBar", 4 * scale);
+
// LinkButton
theme->set_stylebox("focus", "LinkButton", focus);
@@ -224,6 +245,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "OptionButton", control_font_color);
theme->set_color("font_pressed_color", "OptionButton", control_font_pressed_color);
theme->set_color("font_hover_color", "OptionButton", control_font_hover_color);
+ theme->set_color("font_hover_pressed_color", "OptionButton", control_font_pressed_color);
theme->set_color("font_focus_color", "OptionButton", control_font_focus_color);
theme->set_color("font_disabled_color", "OptionButton", control_font_disabled_color);
theme->set_color("font_outline_color", "OptionButton", Color(1, 1, 1));
@@ -231,6 +253,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("h_separation", "OptionButton", 2 * scale);
theme->set_constant("arrow_margin", "OptionButton", 4 * scale);
theme->set_constant("outline_size", "OptionButton", 0);
+ theme->set_constant("modulate_arrow", "OptionButton", false);
// MenuButton
@@ -644,9 +667,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("labeled_separator_right", "PopupMenu", separator_horizontal);
theme->set_icon("checked", "PopupMenu", icons["checked"]);
+ theme->set_icon("checked_disabled", "PopupMenu", icons["checked"]);
theme->set_icon("unchecked", "PopupMenu", icons["unchecked"]);
+ theme->set_icon("unchecked_disabled", "PopupMenu", icons["unchecked"]);
theme->set_icon("radio_checked", "PopupMenu", icons["radio_checked"]);
+ theme->set_icon("radio_checked_disabled", "PopupMenu", icons["radio_checked"]);
theme->set_icon("radio_unchecked", "PopupMenu", icons["radio_unchecked"]);
+ theme->set_icon("radio_unchecked_disabled", "PopupMenu", icons["radio_unchecked"]);
theme->set_icon("submenu", "PopupMenu", icons["popup_menu_arrow_right"]);
theme->set_icon("submenu_mirrored", "PopupMenu", icons["popup_menu_arrow_left"]);
@@ -663,6 +690,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "PopupMenu", Color(1, 1, 1));
theme->set_color("font_separator_outline_color", "PopupMenu", Color(1, 1, 1));
+ theme->set_constant("indent", "PopupMenu", 10 * scale);
theme->set_constant("h_separation", "PopupMenu", 4 * scale);
theme->set_constant("v_separation", "PopupMenu", 4 * scale);
theme->set_constant("outline_size", "PopupMenu", 0);
@@ -703,6 +731,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("resizer_color", "GraphNode", control_font_color);
theme->set_constant("separation", "GraphNode", 2 * scale);
theme->set_constant("title_offset", "GraphNode", 26 * scale);
+ theme->set_constant("title_h_offset", "GraphNode", 0);
theme->set_constant("close_offset", "GraphNode", 22 * scale);
theme->set_constant("close_h_offset", "GraphNode", 22 * scale);
theme->set_constant("port_offset", "GraphNode", 0);
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index d361b34da8..f7a7818b3b 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1037,46 +1037,46 @@ void Environment::_update_adjustment() {
// Private methods, constructor and destructor
-void Environment::_validate_property(PropertyInfo &property) const {
- if (property.name == "sky" || property.name == "sky_custom_fov" || property.name == "sky_rotation" || property.name == "ambient_light/sky_contribution") {
+void Environment::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "sky" || p_property.name == "sky_custom_fov" || p_property.name == "sky_rotation" || p_property.name == "ambient_light_sky_contribution") {
if (bg_mode != BG_SKY && ambient_source != AMBIENT_SOURCE_SKY && reflection_source != REFLECTION_SOURCE_SKY) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "fog_aerial_perspective") {
+ if (p_property.name == "fog_aerial_perspective") {
if (bg_mode != BG_SKY) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "tonemap_white" && tone_mapper == TONE_MAPPER_LINEAR) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "tonemap_white" && tone_mapper == TONE_MAPPER_LINEAR) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "background_color") {
+ if (p_property.name == "background_color") {
if (bg_mode != BG_COLOR && ambient_source != AMBIENT_SOURCE_COLOR) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "background_canvas_max_layer") {
+ if (p_property.name == "background_canvas_max_layer") {
if (bg_mode != BG_CANVAS) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "background_camera_feed_id") {
+ if (p_property.name == "background_camera_feed_id") {
if (bg_mode != BG_CAMERA_FEED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -1107,8 +1107,8 @@ void Environment::_validate_property(PropertyInfo &property) const {
String prefix = String(*prefixes);
String enabled = prefix + "enabled";
- if (property.name.begins_with(prefix) && property.name != enabled && !bool(get(enabled))) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with(prefix) && p_property.name != enabled && !bool(get(enabled))) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
@@ -1120,8 +1120,8 @@ void Environment::_validate_property(PropertyInfo &property) const {
while (*prefixes) {
String prefix = String(*prefixes);
- if (property.name.begins_with(prefix)) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with(prefix)) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index 385d815230..d39cb1acd8 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -211,7 +211,7 @@ private:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
#ifndef DISABLE_DEPRECATED
// Kept for compatibility from 3.x to 4.0.
bool _set(const StringName &p_name, const Variant &p_value);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 619036d296..e7d5d40777 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -2714,6 +2714,9 @@ void SystemFont::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &SystemFont::set_subpixel_positioning);
ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &SystemFont::get_subpixel_positioning);
+ ClassDB::bind_method(D_METHOD("set_multichannel_signed_distance_field", "msdf"), &SystemFont::set_multichannel_signed_distance_field);
+ ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &SystemFont::is_multichannel_signed_distance_field);
+
ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &SystemFont::set_oversampling);
ClassDB::bind_method(D_METHOD("get_oversampling"), &SystemFont::get_oversampling);
@@ -2729,6 +2732,7 @@ void SystemFont::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter"), "set_force_autohinter", "is_force_autohinter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel"), "set_subpixel_positioning", "get_subpixel_positioning");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field"), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), "set_oversampling", "get_oversampling");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), "set_fallbacks", "get_fallbacks");
}
@@ -2805,9 +2809,12 @@ void SystemFont::_update_base_font() {
file->set_force_autohinter(force_autohinter);
file->set_hinting(hinting);
file->set_subpixel_positioning(subpixel_positioning);
+ file->set_multichannel_signed_distance_field(msdf);
file->set_oversampling(oversampling);
base_font = file;
+
+ break;
}
if (base_font.is_valid()) {
@@ -2840,6 +2847,7 @@ void SystemFont::reset_state() {
hinting = TextServer::HINTING_LIGHT;
subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
oversampling = 0.f;
+ msdf = false;
Font::reset_state();
}
@@ -2969,6 +2977,20 @@ TextServer::SubpixelPositioning SystemFont::get_subpixel_positioning() const {
return subpixel_positioning;
}
+void SystemFont::set_multichannel_signed_distance_field(bool p_msdf) {
+ if (msdf != p_msdf) {
+ msdf = p_msdf;
+ if (base_font.is_valid()) {
+ base_font->set_multichannel_signed_distance_field(msdf);
+ }
+ emit_changed();
+ }
+}
+
+bool SystemFont::is_multichannel_signed_distance_field() const {
+ return msdf;
+}
+
void SystemFont::set_oversampling(real_t p_oversampling) {
if (oversampling != p_oversampling) {
oversampling = p_oversampling;
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 260b4e521f..696152a23b 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -404,6 +404,7 @@ class SystemFont : public Font {
TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
real_t oversampling = 0.f;
+ bool msdf = false;
protected:
static void _bind_methods();
@@ -434,6 +435,9 @@ public:
virtual void set_oversampling(real_t p_oversampling);
virtual real_t get_oversampling() const;
+ virtual void set_multichannel_signed_distance_field(bool p_msdf);
+ virtual bool is_multichannel_signed_distance_field() const;
+
virtual void set_font_names(const PackedStringArray &p_names);
virtual PackedStringArray get_font_names() const;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 88bc01fb25..bd0e470112 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -71,12 +71,12 @@ RID Material::get_rid() const {
return material;
}
-void Material::_validate_property(PropertyInfo &property) const {
- if (!_can_do_next_pass() && property.name == "next_pass") {
- property.usage = PROPERTY_USAGE_NONE;
+void Material::_validate_property(PropertyInfo &p_property) const {
+ if (!_can_do_next_pass() && p_property.name == "next_pass") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (!_can_use_render_priority() && property.name == "render_priority") {
- property.usage = PROPERTY_USAGE_NONE;
+ if (!_can_use_render_priority() && p_property.name == "render_priority") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
@@ -297,7 +297,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-bool ShaderMaterial::property_can_revert(const String &p_name) {
+bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
if (shader.is_valid()) {
StringName pr = shader->remap_uniform(p_name);
if (pr) {
@@ -310,15 +310,15 @@ bool ShaderMaterial::property_can_revert(const String &p_name) {
return false;
}
-Variant ShaderMaterial::property_get_revert(const String &p_name) {
- Variant r_ret;
+bool ShaderMaterial::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (shader.is_valid()) {
StringName pr = shader->remap_uniform(p_name);
if (pr) {
- r_ret = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
+ r_property = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
+ return true;
}
}
- return r_ret;
+ return false;
}
void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) {
@@ -386,8 +386,6 @@ void ShaderMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shader"), &ShaderMaterial::get_shader);
ClassDB::bind_method(D_METHOD("set_shader_uniform", "param", "value"), &ShaderMaterial::set_shader_uniform);
ClassDB::bind_method(D_METHOD("get_shader_uniform", "param"), &ShaderMaterial::get_shader_uniform);
- ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &ShaderMaterial::property_can_revert);
- ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &ShaderMaterial::property_get_revert);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shader", PROPERTY_HINT_RESOURCE_TYPE, "Shader"), "set_shader", "get_shader");
}
@@ -1869,61 +1867,61 @@ void BaseMaterial3D::_validate_high_end(const String &text, PropertyInfo &proper
}
}
-void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
- _validate_feature("normal", FEATURE_NORMAL_MAPPING, property);
- _validate_feature("emission", FEATURE_EMISSION, property);
- _validate_feature("rim", FEATURE_RIM, property);
- _validate_feature("clearcoat", FEATURE_CLEARCOAT, property);
- _validate_feature("anisotropy", FEATURE_ANISOTROPY, property);
- _validate_feature("ao", FEATURE_AMBIENT_OCCLUSION, property);
- _validate_feature("heightmap", FEATURE_HEIGHT_MAPPING, property);
- _validate_feature("subsurf_scatter", FEATURE_SUBSURFACE_SCATTERING, property);
- _validate_feature("backlight", FEATURE_BACKLIGHT, property);
- _validate_feature("refraction", FEATURE_REFRACTION, property);
- _validate_feature("detail", FEATURE_DETAIL, property);
+void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const {
+ _validate_feature("normal", FEATURE_NORMAL_MAPPING, p_property);
+ _validate_feature("emission", FEATURE_EMISSION, p_property);
+ _validate_feature("rim", FEATURE_RIM, p_property);
+ _validate_feature("clearcoat", FEATURE_CLEARCOAT, p_property);
+ _validate_feature("anisotropy", FEATURE_ANISOTROPY, p_property);
+ _validate_feature("ao", FEATURE_AMBIENT_OCCLUSION, p_property);
+ _validate_feature("heightmap", FEATURE_HEIGHT_MAPPING, p_property);
+ _validate_feature("subsurf_scatter", FEATURE_SUBSURFACE_SCATTERING, p_property);
+ _validate_feature("backlight", FEATURE_BACKLIGHT, p_property);
+ _validate_feature("refraction", FEATURE_REFRACTION, p_property);
+ _validate_feature("detail", FEATURE_DETAIL, p_property);
- _validate_high_end("refraction", property);
- _validate_high_end("subsurf_scatter", property);
- _validate_high_end("heightmap", property);
+ _validate_high_end("refraction", p_property);
+ _validate_high_end("subsurf_scatter", p_property);
+ _validate_high_end("heightmap", p_property);
- if (property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "grow_amount" && !grow_enabled) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "grow_amount" && !grow_enabled) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "point_size" && !flags[FLAG_USE_POINT_SIZE]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "point_size" && !flags[FLAG_USE_POINT_SIZE]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "proximity_fade_distance" && !proximity_fade_enabled) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "proximity_fade_distance" && !proximity_fade_enabled) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "msdf_pixel_range" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "msdf_pixel_range" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "msdf_outline_size" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "msdf_outline_size" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if ((p_property.name == "distance_fade_max_distance" || p_property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if ((property.name == "uv1_triplanar_sharpness" || property.name == "uv1_world_triplanar") && !flags[FLAG_UV1_USE_TRIPLANAR]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if ((p_property.name == "uv1_triplanar_sharpness" || p_property.name == "uv1_world_triplanar") && !flags[FLAG_UV1_USE_TRIPLANAR]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if ((property.name == "uv2_triplanar_sharpness" || property.name == "uv2_world_triplanar") && !flags[FLAG_UV2_USE_TRIPLANAR]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if ((p_property.name == "uv2_triplanar_sharpness" || p_property.name == "uv2_world_triplanar") && !flags[FLAG_UV2_USE_TRIPLANAR]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
// you can only enable anti-aliasing (in materials) on alpha scissor and alpha hash
@@ -1932,96 +1930,96 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
const bool alpha_aa_enabled = (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) && can_select_aa;
// alpha scissor slider isn't needed when alpha antialiasing is enabled
- if (property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
// alpha hash scale slider is only needed if transparency is alpha hash
- if (property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "alpha_antialiasing_mode" && !can_select_aa) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_antialiasing_mode" && !can_select_aa) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
// we can't choose an antialiasing mode if alpha isn't possible
- if (property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "blend_mode" && alpha_aa_enabled) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "blend_mode" && alpha_aa_enabled) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if ((property.name == "heightmap_min_layers" || property.name == "heightmap_max_layers") && !deep_parallax) {
- property.usage = PROPERTY_USAGE_NONE;
+ if ((p_property.name == "heightmap_min_layers" || p_property.name == "heightmap_max_layers") && !deep_parallax) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (property.name == "subsurf_scatter_transmittance_color" || property.name == "subsurf_scatter_transmittance_texture")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (p_property.name == "subsurf_scatter_transmittance_color" || p_property.name == "subsurf_scatter_transmittance_texture")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
if (orm) {
- if (property.name == "shading_mode") {
+ if (p_property.name == "shading_mode") {
// Vertex not supported in ORM mode, since no individual roughness.
- property.hint_string = "Unshaded,Per-Pixel";
+ p_property.hint_string = "Unshaded,Per-Pixel";
}
- if (property.name.begins_with("roughness") || property.name.begins_with("metallic") || property.name.begins_with("ao_texture")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("roughness") || p_property.name.begins_with("metallic") || p_property.name.begins_with("ao_texture")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
} else {
- if (property.name == "orm_texture") {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "orm_texture") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
if (shading_mode != SHADING_MODE_PER_PIXEL) {
if (shading_mode != SHADING_MODE_PER_VERTEX) {
//these may still work per vertex
- if (property.name.begins_with("ao")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("ao")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("emission")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("emission")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("metallic")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("metallic")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("rim")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("rim")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("roughness")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("roughness")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("subsurf_scatter")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("subsurf_scatter")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
//these definitely only need per pixel
- if (property.name.begins_with("anisotropy")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("anisotropy")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("clearcoat")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("clearcoat")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("normal")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("normal")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("backlight")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("backlight")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("transmittance")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("transmittance")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
@@ -2054,8 +2052,9 @@ Vector3 BaseMaterial3D::get_uv1_offset() const {
}
void BaseMaterial3D::set_uv1_triplanar_blend_sharpness(float p_sharpness) {
- uv1_triplanar_sharpness = p_sharpness;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, p_sharpness);
+ // Negative values or values higher than 150 can result in NaNs, leading to broken rendering.
+ uv1_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, uv1_triplanar_sharpness);
}
float BaseMaterial3D::get_uv1_triplanar_blend_sharpness() const {
@@ -2081,8 +2080,9 @@ Vector3 BaseMaterial3D::get_uv2_offset() const {
}
void BaseMaterial3D::set_uv2_triplanar_blend_sharpness(float p_sharpness) {
- uv2_triplanar_sharpness = p_sharpness;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, p_sharpness);
+ // Negative values or values higher than 150 can result in NaNs, leading to broken rendering.
+ uv2_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, uv2_triplanar_sharpness);
}
float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const {
diff --git a/scene/resources/material.h b/scene/resources/material.h
index ca5b17dd07..c6be1b8766 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -54,7 +54,7 @@ protected:
virtual bool _can_do_next_pass() const;
virtual bool _can_use_render_priority() const;
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
GDVIRTUAL0RC(RID, _get_shader_rid)
GDVIRTUAL0RC(Shader::Mode, _get_shader_mode)
@@ -99,8 +99,8 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- bool property_can_revert(const String &p_name);
- Variant property_get_revert(const String &p_name);
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
static void _bind_methods();
@@ -553,7 +553,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
virtual bool _can_do_next_pass() const override { return true; }
virtual bool _can_use_render_priority() const override { return true; }
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index ec9db89794..1f75d4a323 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -32,11 +32,10 @@
#include "core/math/convex_hull.h"
#include "core/templates/pair.h"
+#include "scene/resources/surface_tool.h"
+
#include "scene/resources/concave_polygon_shape_3d.h"
#include "scene/resources/convex_polygon_shape_3d.h"
-#include "surface_tool.h"
-
-#include <stdlib.h>
Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr;
@@ -201,7 +200,9 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
continue;
}
int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i);
- if ((primitive == PRIMITIVE_TRIANGLES && (len == 0 || (len % 3) != 0)) || (primitive == PRIMITIVE_TRIANGLE_STRIP && len < 3)) {
+ if ((primitive == PRIMITIVE_TRIANGLES && (len == 0 || (len % 3) != 0)) ||
+ (primitive == PRIMITIVE_TRIANGLE_STRIP && len < 3) ||
+ (surface_get_format(i) & ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY)) {
// Error was already shown, just skip (including zero).
continue;
}
@@ -211,6 +212,7 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
int vc = surface_get_array_len(i);
Vector<Vector3> vertices = a[ARRAY_VERTEX];
+ ERR_FAIL_COND_V(vertices.is_empty(), Ref<TriangleMesh>());
const Vector3 *vr = vertices.ptr();
int32_t from_index = widx / 3;
@@ -863,27 +865,6 @@ static Mesh::PrimitiveType _old_primitives[7] = {
};
#endif // DISABLE_DEPRECATED
-// Convert Octahedron-mapped normalized vector back to Cartesian
-// Assumes normalized format (elements of v within range [-1, 1])
-Vector3 _oct_to_norm(const Vector2 v) {
- Vector3 res(v.x, v.y, 1 - (Math::absf(v.x) + Math::absf(v.y)));
- float t = MAX(-res.z, 0.0f);
- res.x += t * -SIGN(res.x);
- res.y += t * -SIGN(res.y);
- return res.normalized();
-}
-
-// Convert Octahedron-mapped normalized tangent vector back to Cartesian
-// out_sign provides the direction for the original cartesian tangent
-// Assumes normalized format (elements of v within range [-1, 1])
-Vector3 _oct_to_tangent(const Vector2 v, float *out_sign) {
- Vector2 v_decompressed = v;
- v_decompressed.y = Math::absf(v_decompressed.y) * 2 - 1;
- Vector3 res = _oct_to_norm(v_decompressed);
- *out_sign = SIGN(v[1]);
- return res;
-}
-
void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_format, uint32_t p_new_format, uint32_t p_elements, Vector<uint8_t> &vertex_data, Vector<uint8_t> &attribute_data, Vector<uint8_t> &skin_data) {
uint32_t dst_vertex_stride;
uint32_t dst_attribute_stride;
@@ -954,127 +935,93 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
if ((p_old_format & OLD_ARRAY_COMPRESS_NORMAL) && (p_old_format & OLD_ARRAY_FORMAT_TANGENT) && (p_old_format & OLD_ARRAY_COMPRESS_TANGENT)) {
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
- const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f);
-
- const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0f), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20;
+ int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+
+ dst[0] = (int16_t)CLAMP(src[0] / 127.0f * 32767, -32768, 32767);
+ dst[1] = (int16_t)CLAMP(src[1] / 127.0f * 32767, -32768, 32767);
}
- src_offset += sizeof(int8_t) * 2;
+ src_offset += sizeof(int16_t) * 2;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
- const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f);
-
- const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0f), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20;
+ int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+
+ dst[0] = src[0];
+ dst[1] = src[1];
}
src_offset += sizeof(int16_t) * 2;
}
} else { // No Octahedral compression
if (p_old_format & OLD_ARRAY_COMPRESS_NORMAL) {
- const float multiplier = 1.f / 127.f * 1023.0f;
-
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ const Vector3 original_normal(src[0], src[1], src[2]);
+ Vector2 res = original_normal.octahedron_encode();
- *dst = 0;
- *dst |= CLAMP(int(src[0] * multiplier), 0, 1023);
- *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20;
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint32_t);
+ src_offset += sizeof(uint16_t) * 2;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ const Vector3 original_normal(src[0], src[1], src[2]);
+ Vector2 res = original_normal.octahedron_encode();
- *dst = 0;
- *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023);
- *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20;
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(float) * 3;
+ src_offset += sizeof(uint16_t) * 2;
}
}
} break;
case OLD_ARRAY_TANGENT: {
if (p_old_format & OLD_ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
- if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8
+ if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8 SNORM -> uint16 UNORM
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
- const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f);
- float out_sign;
- const Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20;
- if (out_sign > 0) {
- *dst |= 3 << 30;
- }
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
+
+ dst[0] = (uint16_t)CLAMP((src[0] / 127.0f * .5f + .5f) * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP((src[1] / 127.0f * .5f + .5f) * 65535, 0, 65535);
}
- src_offset += sizeof(int8_t) * 2;
- } else { // int16
+ src_offset += sizeof(uint16_t) * 2;
+ } else { // int16 SNORM -> uint16 UNORM
for (uint32_t i = 0; i < p_elements; i++) {
const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
- const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f);
- float out_sign;
- Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20;
- if (out_sign > 0) {
- *dst |= 3 << 30;
- }
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
+
+ dst[0] = (uint16_t)CLAMP((src[0] / 32767.0f * .5f + .5f) * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP((src[1] / 32767.0f * .5f + .5f) * 65535, 0, 65535);
}
- src_offset += sizeof(int16_t) * 2;
+ src_offset += sizeof(uint16_t) * 2;
}
} else { // No Octahedral compression
if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) {
- const float multiplier = 1.f / 127.f * 1023.0f;
-
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
-
- *dst = 0;
- *dst |= CLAMP(int(src[0] * multiplier), 0, 1023);
- *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20;
- if (src[3] > 0) {
- *dst |= 3 << 30;
- }
+ const Vector3 original_tangent(src[0], src[1], src[2]);
+ Vector2 res = original_tangent.octahedron_tangent_encode(src[3]);
+
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint32_t);
+ src_offset += sizeof(uint16_t) * 2;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
-
- *dst = 0;
- *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023);
- *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20;
- if (src[3] > 0) {
- *dst |= 3 << 30;
- }
+ const Vector3 original_tangent(src[0], src[1], src[2]);
+ Vector2 res = original_tangent.octahedron_tangent_encode(src[3]);
+
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(float) * 4;
+ src_offset += sizeof(uint16_t) * 2;
}
}
} break;
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 142373ce7f..491a383416 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -144,6 +144,7 @@ public:
ARRAY_FLAG_USE_DYNAMIC_UPDATE = RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE,
ARRAY_FLAG_USE_8_BONE_WEIGHTS = RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS,
+ ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY = RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY,
};
virtual int get_surface_count() const;
@@ -168,9 +169,6 @@ public:
void generate_debug_mesh_lines(Vector<Vector3> &r_lines);
void generate_debug_mesh_indices(Vector<Vector3> &r_points);
- Ref<Shape3D> create_trimesh_shape() const;
- Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
-
Ref<Mesh> create_outline(float p_margin) const;
void set_lightmap_size_hint(const Size2i &p_size);
@@ -213,6 +211,8 @@ public:
static ConvexDecompositionFunc convex_decomposition_function;
Vector<Ref<Shape3D>> convex_decompose(const ConvexDecompositionSettings &p_settings) const;
+ Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
+ Ref<Shape3D> create_trimesh_shape() const;
virtual int get_builtin_bind_pose_count() const;
virtual Transform3D get_builtin_bind_pose(int p_index) const;
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index 4105bd6960..79acb41c4e 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -33,8 +33,8 @@
#include "core/io/resource.h"
#include "core/templates/rb_map.h"
-#include "mesh.h"
#include "scene/3d/navigation_region_3d.h"
+#include "scene/resources/mesh.h"
#include "shape_3d.h"
class MeshLibrary : public Resource {
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index ac5493efdc..6c9c8ffdba 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -614,8 +614,10 @@ void NavigationMesh::_bind_methods() {
ADD_GROUP("Geometry", "geometry_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY_DEFAULT("geometry_collision_mask", 0xFFFFFFFF);
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "NavMesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry_source_group_name"), "set_source_group_name", "get_source_group_name");
+ ADD_PROPERTY_DEFAULT("geometry_source_group_name", StringName("navmesh"));
ADD_GROUP("Cells", "cell_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_height", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_height", "get_cell_height");
@@ -658,17 +660,17 @@ void NavigationMesh::_bind_methods() {
BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_MAX);
}
-void NavigationMesh::_validate_property(PropertyInfo &property) const {
- if (property.name == "geometry/collision_mask") {
+void NavigationMesh::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "geometry_collision_mask") {
if (parsed_geometry_type == PARSED_GEOMETRY_MESH_INSTANCES) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
return;
}
}
- if (property.name == "geometry/source_group_name") {
+ if (p_property.name == "geometry_source_group_name") {
if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
return;
}
}
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index 79d8962d24..c66025dc6d 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -33,8 +33,6 @@
#include "scene/resources/mesh.h"
-class Mesh;
-
class NavigationMesh : public Resource {
GDCLASS(NavigationMesh, Resource);
@@ -60,7 +58,7 @@ class NavigationMesh : public Resource {
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
#ifndef DISABLE_DEPRECATED
bool _set(const StringName &p_name, const Variant &p_value);
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index 4b2e029f47..0fe5c8f2db 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -1386,54 +1386,54 @@ RID ParticlesMaterial::get_shader_rid() const {
return shader_map[current_key].shader;
}
-void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
- if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
- property.usage = PROPERTY_USAGE_NONE;
+void ParticlesMaterial::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
- property.usage = PROPERTY_USAGE_NONE;
+ if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture") && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
if (!turbulence_enabled) {
- if (property.name == "turbulence_noise_strength" ||
- property.name == "turbulence_noise_scale" ||
- property.name == "turbulence_noise_speed" ||
- property.name == "turbulence_noise_speed_random" ||
- property.name == "turbulence_influence_over_life" ||
- property.name == "turbulence_influence_min" ||
- property.name == "turbulence_influence_max" ||
- property.name == "turbulence_initial_displacement_min" ||
- property.name == "turbulence_initial_displacement_max") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "turbulence_noise_strength" ||
+ p_property.name == "turbulence_noise_scale" ||
+ p_property.name == "turbulence_noise_speed" ||
+ p_property.name == "turbulence_noise_speed_random" ||
+ p_property.name == "turbulence_influence_over_life" ||
+ p_property.name == "turbulence_influence_min" ||
+ p_property.name == "turbulence_influence_max" ||
+ p_property.name == "turbulence_initial_displacement_min" ||
+ p_property.name == "turbulence_initial_displacement_max") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h
index 7fb46d6ac5..116d8b7d06 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particles_material.h
@@ -307,7 +307,7 @@ private:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_direction(Vector3 p_direction);
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index db7b03f2be..48d06934e3 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -82,7 +82,7 @@ void Shader::set_code(const String &p_code) {
// 1) Need to keep track of include dependencies at resource level
// 2) Server does not do interaction with Resource filetypes, this is a scene level feature.
ShaderPreprocessor preprocessor;
- preprocessor.preprocess(p_code, pp_code, nullptr, nullptr, &new_include_dependencies);
+ preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_include_dependencies);
}
// This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp
index 42435fe3c7..fe628dd323 100644
--- a/scene/resources/shader_include.cpp
+++ b/scene/resources/shader_include.cpp
@@ -47,7 +47,7 @@ void ShaderInclude::set_code(const String &p_code) {
{
String pp_code;
ShaderPreprocessor preprocessor;
- preprocessor.preprocess(p_code, pp_code, nullptr, nullptr, &new_dependencies);
+ preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_dependencies);
}
// This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp
index bfb4bb6e2b..875d2dcff7 100644
--- a/scene/resources/skeleton_profile.cpp
+++ b/scene/resources/skeleton_profile.cpp
@@ -121,26 +121,26 @@ bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const {
return true;
}
-void SkeletonProfile::_validate_property(PropertyInfo &property) const {
+void SkeletonProfile::_validate_property(PropertyInfo &p_property) const {
if (is_read_only) {
- if (property.name == ("group_size") || property.name == ("bone_size") || property.name == ("root_bone") || property.name == ("scale_base_bone")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == ("group_size") || p_property.name == ("bone_size") || p_property.name == ("root_bone") || p_property.name == ("scale_base_bone")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
}
- if (property.name == ("root_bone") || property.name == ("scale_base_bone")) {
+ if (p_property.name == ("root_bone") || p_property.name == ("scale_base_bone")) {
String hint = "";
for (int i = 0; i < bones.size(); i++) {
hint += i == 0 ? String(bones[i].bone_name) : "," + String(bones[i].bone_name);
}
- property.hint_string = hint;
+ p_property.hint_string = hint;
}
- PackedStringArray split = property.name.split("/");
+ PackedStringArray split = p_property.name.split("/");
if (split.size() == 3 && split[0] == "bones") {
if (split[2] == "bone_tail" && get_tail_direction(split[1].to_int()) != TAIL_DIRECTION_SPECIFIC_CHILD) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h
index 84dfca458e..66344d954d 100644
--- a/scene/resources/skeleton_profile.h
+++ b/scene/resources/skeleton_profile.h
@@ -72,7 +72,7 @@ protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index a53c299d00..ff5210f1b3 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -842,9 +842,9 @@ float StyleBoxFlat::get_style_margin(Side p_side) const {
return border_width[p_side];
}
-void StyleBoxFlat::_validate_property(PropertyInfo &property) const {
- if (!anti_aliased && property.name == "anti_aliasing_size") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void StyleBoxFlat::_validate_property(PropertyInfo &p_property) const {
+ if (!anti_aliased && p_property.name == "anti_aliasing_size") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 9f4f69d3ba..88db4f5fbd 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -166,7 +166,7 @@ class StyleBoxFlat : public StyleBox {
protected:
virtual float get_style_margin(Side p_side) const override;
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_bg_color(const Color &p_color);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 05ed9238b8..25f5006c4f 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -35,8 +35,8 @@
#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/os/os.h"
-#include "mesh.h"
#include "scene/resources/bit_map.h"
+#include "scene/resources/mesh.h"
#include "servers/camera/camera_feed.h"
int Texture2D::get_width() const {
int ret;
@@ -1038,7 +1038,7 @@ void CompressedTexture2D::reload_from_file() {
load(path);
}
-void CompressedTexture2D::_validate_property(PropertyInfo &property) const {
+void CompressedTexture2D::_validate_property(PropertyInfo &p_property) const {
}
void CompressedTexture2D::_bind_methods() {
@@ -1394,7 +1394,7 @@ void CompressedTexture3D::reload_from_file() {
load(path);
}
-void CompressedTexture3D::_validate_property(PropertyInfo &property) const {
+void CompressedTexture3D::_validate_property(PropertyInfo &p_property) const {
}
void CompressedTexture3D::_bind_methods() {
@@ -2537,13 +2537,6 @@ void GradientTexture2D::_bind_methods() {
//////////////////////////////////////
-void ProxyTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_base", "base"), &ProxyTexture::set_base);
- ClassDB::bind_method(D_METHOD("get_base"), &ProxyTexture::get_base);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_base", "get_base");
-}
-
void ProxyTexture::set_base(const Ref<Texture2D> &p_texture) {
ERR_FAIL_COND(p_texture == this);
@@ -2796,12 +2789,12 @@ bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const {
return true;
}
-void AnimatedTexture::_validate_property(PropertyInfo &property) const {
- String prop = property.name;
+void AnimatedTexture::_validate_property(PropertyInfo &p_property) const {
+ String prop = p_property.name;
if (prop.begins_with("frame_")) {
int frame = prop.get_slicec('/', 0).get_slicec('_', 1).to_int();
if (frame >= frame_count) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
@@ -3221,7 +3214,7 @@ void CompressedTextureLayered::reload_from_file() {
load(path);
}
-void CompressedTextureLayered::_validate_property(PropertyInfo &property) const {
+void CompressedTextureLayered::_validate_property(PropertyInfo &p_property) const {
}
void CompressedTextureLayered::_bind_methods() {
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 36b193c5d4..133b312d27 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -251,7 +251,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
static Ref<Image> load_image_from_file(Ref<FileAccess> p_file, int p_size_limit);
@@ -506,7 +506,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
Image::Format get_format() const override;
@@ -651,7 +651,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
Image::Format get_format() const override;
@@ -883,8 +883,6 @@ VARIANT_ENUM_CAST(GradientTexture2D::Fill);
VARIANT_ENUM_CAST(GradientTexture2D::Repeat);
class ProxyTexture : public Texture2D {
- GDCLASS(ProxyTexture, Texture2D);
-
private:
mutable RID proxy_ph;
mutable RID proxy;
@@ -942,7 +940,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_frames(int p_frames);
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index b0b9f1228f..552d856034 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -3302,11 +3302,11 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-void TileSet::_validate_property(PropertyInfo &property) const {
- if (property.name == "tile_layout" && tile_shape == TILE_SHAPE_SQUARE) {
- property.usage ^= PROPERTY_USAGE_READ_ONLY;
- } else if (property.name == "tile_offset_axis" && tile_shape == TILE_SHAPE_SQUARE) {
- property.usage ^= PROPERTY_USAGE_READ_ONLY;
+void TileSet::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "tile_layout" && tile_shape == TILE_SHAPE_SQUARE) {
+ p_property.usage ^= PROPERTY_USAGE_READ_ONLY;
+ } else if (p_property.name == "tile_offset_axis" && tile_shape == TILE_SHAPE_SQUARE) {
+ p_property.usage ^= PROPERTY_USAGE_READ_ONLY;
}
}
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 6ea3889fce..4c0823cdf2 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -295,7 +295,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
private:
// --- TileSet data ---
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index a67716d52b..0180b2ffcf 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -1698,13 +1698,13 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
inputs[i] = "(" + src_var + " ? 1.0 : 0.0)";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
- inputs[i] = "dot(" + src_var + ", vec2(0.5, 0.5))";
+ inputs[i] = src_var + ".x";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
- inputs[i] = "dot(" + src_var + ", vec3(0.333333, 0.333333, 0.333333))";
+ inputs[i] = src_var + ".x";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
- inputs[i] = "dot(" + src_var + ", vec4(0.25, 0.25, 0.25, 0.25))";
+ inputs[i] = src_var + ".x";
} break;
default:
break;
@@ -3153,8 +3153,8 @@ String VisualShaderNodeInput::get_input_index_name(int p_index) const {
return "";
}
-void VisualShaderNodeInput::_validate_property(PropertyInfo &property) const {
- if (property.name == "input_name") {
+void VisualShaderNodeInput::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "input_name") {
String port_list;
int idx = 0;
@@ -3172,7 +3172,7 @@ void VisualShaderNodeInput::_validate_property(PropertyInfo &property) const {
if (port_list.is_empty()) {
port_list = RTR("None");
}
- property.hint_string = port_list;
+ p_property.hint_string = port_list;
}
}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 7ca4e5fc4a..527588b6e6 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -428,7 +428,7 @@ public:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
virtual int get_input_port_count() const override;
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index b422d298b2..2911d726b4 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1015,7 +1015,7 @@ Vector<StringName> VisualShaderNodeCurveTexture::get_editable_properties() const
}
String VisualShaderNodeCurveTexture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve") + ";\n";
+ return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve") + " : repeat_disable;\n";
}
String VisualShaderNodeCurveTexture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
@@ -6830,23 +6830,23 @@ void VisualShaderNodeMultiplyAdd::set_op_type(OpType p_op_type) {
switch (p_op_type) {
case OP_TYPE_SCALAR: {
set_input_port_default_value(0, 0.0, get_input_port_default_value(0));
- set_input_port_default_value(1, 0.0, get_input_port_default_value(1));
+ set_input_port_default_value(1, 1.0, get_input_port_default_value(1));
set_input_port_default_value(2, 0.0, get_input_port_default_value(2));
} break;
case OP_TYPE_VECTOR_2D: {
set_input_port_default_value(0, Vector2(), get_input_port_default_value(0));
- set_input_port_default_value(1, Vector2(), get_input_port_default_value(1));
+ set_input_port_default_value(1, Vector2(1.0, 1.0), get_input_port_default_value(1));
set_input_port_default_value(2, Vector2(), get_input_port_default_value(2));
} break;
case OP_TYPE_VECTOR_3D: {
set_input_port_default_value(0, Vector3(), get_input_port_default_value(0));
- set_input_port_default_value(1, Vector3(), get_input_port_default_value(1));
+ set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0), get_input_port_default_value(1));
set_input_port_default_value(2, Vector3(), get_input_port_default_value(2));
} break;
case OP_TYPE_VECTOR_4D: {
- set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
- set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
- set_input_port_default_value(2, Quaternion(), get_input_port_default_value(2));
+ set_input_port_default_value(0, Vector4(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Vector4(1.0, 1.0, 1.0, 1.0), get_input_port_default_value(1));
+ set_input_port_default_value(2, Vector4(), get_input_port_default_value(2));
} break;
default:
break;
@@ -6880,7 +6880,7 @@ void VisualShaderNodeMultiplyAdd::_bind_methods() {
VisualShaderNodeMultiplyAdd::VisualShaderNodeMultiplyAdd() {
set_input_port_default_value(0, 0.0);
- set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(1, 1.0);
set_input_port_default_value(2, 0.0);
}