diff options
Diffstat (limited to 'scene')
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); } |