diff options
Diffstat (limited to 'scene')
44 files changed, 799 insertions, 266 deletions
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index 00082b321e..80d60dca17 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -96,16 +96,30 @@ void NavigationAgent2D::_bind_methods() { void NavigationAgent2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { - agent_parent = Object::cast_to<Node2D>(get_parent()); - if (agent_parent != nullptr) { - // place agent on navigation map first or else the RVO agent callback creation fails silently later - NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map()); - set_avoidance_enabled(avoidance_enabled); - } + case NOTIFICATION_POST_ENTER_TREE: { + // need to use POST_ENTER_TREE cause with normal ENTER_TREE not all required Nodes are ready. + // cannot use READY as ready does not get called if Node is readded to SceneTree + set_agent_parent(get_parent()); set_physics_process_internal(true); } break; + case NOTIFICATION_PARENTED: { + if (is_inside_tree() && (get_parent() != agent_parent)) { + // only react to PARENTED notifications when already inside_tree and parent changed, e.g. users switch nodes around + // PARENTED notification fires also when Node is added in scripts to a parent + // this would spam transforms fails and world fails while Node is outside SceneTree + // when node gets reparented when joining the tree POST_ENTER_TREE takes care of this + set_agent_parent(get_parent()); + set_physics_process_internal(true); + } + } break; + + case NOTIFICATION_UNPARENTED: { + // if agent has no parent no point in processing it until reparented + set_agent_parent(nullptr); + set_physics_process_internal(false); + } break; + case NOTIFICATION_PAUSED: { if (agent_parent && !agent_parent->can_process()) { map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid()); @@ -133,7 +147,11 @@ void NavigationAgent2D::_notification(int p_what) { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (agent_parent) { - NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position()); + if (avoidance_enabled) { + // agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding + // no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used + NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position()); + } _check_distance_to_target(); } } break; @@ -167,6 +185,21 @@ bool NavigationAgent2D::get_avoidance_enabled() const { return avoidance_enabled; } +void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) { + // remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map + NavigationServer2D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done"); + if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) { + // place agent on navigation map first or else the RVO agent callback creation fails silently later + agent_parent = Object::cast_to<Node2D>(p_agent_parent); + NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map()); + // create new avoidance callback if enabled + set_avoidance_enabled(avoidance_enabled); + } else { + agent_parent = nullptr; + NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID()); + } +} + void NavigationAgent2D::set_navigable_layers(uint32_t p_layers) { bool layers_changed = navigable_layers != p_layers; navigable_layers = p_layers; diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 5ab4cdba5d..c9983119d0 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -82,6 +82,8 @@ public: void set_avoidance_enabled(bool p_enabled); bool get_avoidance_enabled() const; + void set_agent_parent(Node *p_agent_parent); + void set_navigable_layers(uint32_t p_layers); uint32_t get_navigable_layers() const; diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 260faf1d68..6f3222f27e 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -331,6 +331,7 @@ void NavigationPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("get_polygon_count"), &NavigationPolygon::get_polygon_count); ClassDB::bind_method(D_METHOD("get_polygon", "idx"), &NavigationPolygon::get_polygon); ClassDB::bind_method(D_METHOD("clear_polygons"), &NavigationPolygon::clear_polygons); + ClassDB::bind_method(D_METHOD("get_mesh"), &NavigationPolygon::get_mesh); ClassDB::bind_method(D_METHOD("add_outline", "outline"), &NavigationPolygon::add_outline); ClassDB::bind_method(D_METHOD("add_outline_at_index", "outline", "index"), &NavigationPolygon::add_outline_at_index); @@ -387,6 +388,26 @@ uint32_t NavigationRegion2D::get_layers() const { return NavigationServer2D::get_singleton()->region_get_layers(region); } +void NavigationRegion2D::set_enter_cost(real_t p_enter_cost) { + ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive."); + enter_cost = MAX(p_enter_cost, 0.0); + NavigationServer2D::get_singleton()->region_set_enter_cost(region, p_enter_cost); +} + +real_t NavigationRegion2D::get_enter_cost() const { + return enter_cost; +} + +void NavigationRegion2D::set_travel_cost(real_t p_travel_cost) { + ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive."); + travel_cost = MAX(p_travel_cost, 0.0); + NavigationServer2D::get_singleton()->region_set_enter_cost(region, travel_cost); +} + +real_t NavigationRegion2D::get_travel_cost() const { + return travel_cost; +} + RID NavigationRegion2D::get_region_rid() const { return region; } @@ -543,16 +564,26 @@ void NavigationRegion2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion2D::get_region_rid); + ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationRegion2D::set_enter_cost); + ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationRegion2D::get_enter_cost); + + ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationRegion2D::set_travel_cost); + ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion2D::get_travel_cost); + ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_layers", "get_layers"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost"); } NavigationRegion2D::NavigationRegion2D() { set_notify_transform(true); region = NavigationServer2D::get_singleton()->region_create(); + NavigationServer2D::get_singleton()->region_set_enter_cost(region, get_enter_cost()); + NavigationServer2D::get_singleton()->region_set_travel_cost(region, get_travel_cost()); } NavigationRegion2D::~NavigationRegion2D() { diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 3c4a4e81d9..31574749f7 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -98,6 +98,9 @@ class NavigationRegion2D : public Node2D { RID region; Ref<NavigationPolygon> navpoly; + real_t enter_cost = 0.0; + real_t travel_cost = 1.0; + void _navpoly_changed(); void _map_changed(RID p_RID); @@ -119,6 +122,12 @@ public: RID get_region_rid() const; + void set_enter_cost(real_t p_enter_cost); + real_t get_enter_cost() const; + + void set_travel_cost(real_t p_travel_cost); + real_t get_travel_cost() const; + void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly); Ref<NavigationPolygon> get_navigation_polygon() const; diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 2ed5ef905a..6fa18d393e 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -244,9 +244,9 @@ Point2 Node2D::get_global_position() const { } void Node2D::set_global_position(const Point2 &p_pos) { - CanvasItem *pi = get_parent_item(); - if (pi) { - Transform2D inv = pi->get_global_transform().affine_inverse(); + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D inv = parent->get_global_transform().affine_inverse(); set_position(inv.xform(p_pos)); } else { set_position(p_pos); @@ -257,25 +257,48 @@ real_t Node2D::get_global_rotation() const { return get_global_transform().get_rotation(); } -void Node2D::set_global_rotation(real_t p_radians) { - CanvasItem *pi = get_parent_item(); - if (pi) { - const real_t parent_global_rot = pi->get_global_transform().get_rotation(); - set_rotation(p_radians - parent_global_rot); +real_t Node2D::get_global_skew() const { + return get_global_transform().get_skew(); +} + +void Node2D::set_global_rotation(const real_t p_radians) { + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D parent_global_transform = parent->get_global_transform(); + Transform2D new_transform = parent_global_transform * get_transform(); + new_transform.set_rotation(p_radians); + new_transform = parent_global_transform.affine_inverse() * new_transform; + set_rotation(new_transform.get_rotation()); } else { set_rotation(p_radians); } } +void Node2D::set_global_skew(const real_t p_radians) { + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D parent_global_transform = parent->get_global_transform(); + Transform2D new_transform = parent_global_transform * get_transform(); + new_transform.set_skew(p_radians); + new_transform = parent_global_transform.affine_inverse() * new_transform; + set_skew(new_transform.get_skew()); + } else { + set_skew(p_radians); + } +} + Size2 Node2D::get_global_scale() const { return get_global_transform().get_scale(); } void Node2D::set_global_scale(const Size2 &p_scale) { - CanvasItem *pi = get_parent_item(); - if (pi) { - const Size2 parent_global_scale = pi->get_global_transform().get_scale(); - set_scale(p_scale / parent_global_scale); + CanvasItem *parent = get_parent_item(); + if (parent) { + Transform2D parent_global_transform = parent->get_global_transform(); + Transform2D new_transform = parent_global_transform * get_transform(); + new_transform.set_scale(p_scale); + new_transform = parent_global_transform.affine_inverse() * new_transform; + set_scale(new_transform.get_scale()); } else { set_scale(p_scale); } @@ -295,9 +318,9 @@ void Node2D::set_transform(const Transform2D &p_transform) { } void Node2D::set_global_transform(const Transform2D &p_transform) { - CanvasItem *pi = get_parent_item(); - if (pi) { - set_transform(pi->get_global_transform().affine_inverse() * p_transform); + CanvasItem *parent = get_parent_item(); + if (parent) { + set_transform(parent->get_global_transform().affine_inverse() * p_transform); } else { set_transform(p_transform); } @@ -388,6 +411,8 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_global_position"), &Node2D::get_global_position); ClassDB::bind_method(D_METHOD("set_global_rotation", "radians"), &Node2D::set_global_rotation); ClassDB::bind_method(D_METHOD("get_global_rotation"), &Node2D::get_global_rotation); + ClassDB::bind_method(D_METHOD("set_global_skew", "radians"), &Node2D::set_global_skew); + ClassDB::bind_method(D_METHOD("get_global_skew"), &Node2D::get_global_skew); ClassDB::bind_method(D_METHOD("set_global_scale", "scale"), &Node2D::set_global_scale); ClassDB::bind_method(D_METHOD("get_global_scale"), &Node2D::get_global_scale); @@ -421,6 +446,7 @@ void Node2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_global_position", "get_global_position"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rotation", PROPERTY_HINT_NONE, "radians", PROPERTY_USAGE_NONE), "set_global_rotation", "get_global_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_scale", "get_global_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_skew", PROPERTY_HINT_NONE, "radians", PROPERTY_USAGE_NONE), "set_global_skew", "get_global_skew"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); ADD_GROUP("Ordering", ""); diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 69d14f82ad..473c34768f 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -92,12 +92,14 @@ public: Point2 get_global_position() const; real_t get_global_rotation() const; + real_t get_global_skew() const; Size2 get_global_scale() const; void set_transform(const Transform2D &p_transform); void set_global_transform(const Transform2D &p_transform); void set_global_position(const Point2 &p_pos); - void set_global_rotation(real_t p_radians); + void set_global_rotation(const real_t p_radians); + void set_global_skew(const real_t p_radians); void set_global_scale(const Size2 &p_scale); void set_z_index(int p_z); diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp index 33dd737416..1971dc1240 100644 --- a/scene/2d/visible_on_screen_notifier_2d.cpp +++ b/scene/2d/visible_on_screen_notifier_2d.cpp @@ -66,6 +66,7 @@ void VisibleOnScreenNotifier2D::set_rect(const Rect2 &p_rect) { if (is_inside_tree()) { RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_exit)); } + update(); } Rect2 VisibleOnScreenNotifier2D::get_rect() const { diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 735ce0bb07..7c1fb3779f 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -273,7 +273,8 @@ void AudioStreamPlayer3D::_notification(int p_what) { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { // Update anything related to position first, if possible of course. Vector<AudioFrame> volume_vector; - if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) { + if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count()) || force_update_panning) { + force_update_panning = false; volume_vector = _update_panning(); } @@ -318,6 +319,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { } } +// Interacts with PhysicsServer3D, so can only be called during _physics_process Area3D *AudioStreamPlayer3D::_get_overriding_area() { //check if any area is diverting sound into a bus Ref<World3D> world_3d = get_world_3d(); @@ -356,6 +358,7 @@ Area3D *AudioStreamPlayer3D::_get_overriding_area() { return nullptr; } +// Interacts with PhysicsServer3D, so can only be called during _physics_process StringName AudioStreamPlayer3D::_get_actual_bus() { Area3D *overriding_area = _get_overriding_area(); if (overriding_area && overriding_area->is_overriding_audio_bus() && !overriding_area->is_using_reverb_bus()) { @@ -364,6 +367,7 @@ StringName AudioStreamPlayer3D::_get_actual_bus() { return bus; } +// Interacts with PhysicsServer3D, so can only be called during _physics_process Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() { Vector<AudioFrame> output_volume_vector; output_volume_vector.resize(4); @@ -537,6 +541,7 @@ float AudioStreamPlayer3D::get_unit_db() const { void AudioStreamPlayer3D::set_unit_size(float p_volume) { unit_size = p_volume; + update_gizmos(); } float AudioStreamPlayer3D::get_unit_size() const { @@ -665,6 +670,7 @@ void AudioStreamPlayer3D::_bus_layout_changed() { void AudioStreamPlayer3D::set_max_distance(float p_metres) { ERR_FAIL_COND(p_metres < 0.0); max_distance = p_metres; + update_gizmos(); } float AudioStreamPlayer3D::get_max_distance() const { @@ -725,6 +731,7 @@ float AudioStreamPlayer3D::get_attenuation_filter_db() const { void AudioStreamPlayer3D::set_attenuation_model(AttenuationModel p_model) { ERR_FAIL_INDEX((int)p_model, 4); attenuation_model = p_model; + update_gizmos(); } AudioStreamPlayer3D::AttenuationModel AudioStreamPlayer3D::get_attenuation_model() const { diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 53cdd2e630..bc47a8de93 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -82,12 +82,13 @@ private: int max_polyphony = 1; uint64_t last_mix_count = -1; + bool force_update_panning = false; static void _calc_output_vol(const Vector3 &source_dir, real_t tightness, Vector<AudioFrame> &output); void _calc_reverb_vol(Area3D *area, Vector3 listener_area_pos, Vector<AudioFrame> direct_path_vol, Vector<AudioFrame> &reverb_vol); - static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->_update_panning(); } + static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->force_update_panning = true; } void _set_playing(bool p_enable); bool _is_active() const; diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index 88f676d031..947d6012d5 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -102,18 +102,32 @@ void NavigationAgent3D::_bind_methods() { void NavigationAgent3D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { - agent_parent = Object::cast_to<Node3D>(get_parent()); - if (agent_parent != nullptr) { - // place agent on navigation map first or else the RVO agent callback creation fails silently later - NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map()); - set_avoidance_enabled(avoidance_enabled); - } + case NOTIFICATION_POST_ENTER_TREE: { + // need to use POST_ENTER_TREE cause with normal ENTER_TREE not all required Nodes are ready. + // cannot use READY as ready does not get called if Node is readded to SceneTree + set_agent_parent(get_parent()); set_physics_process_internal(true); } break; + case NOTIFICATION_PARENTED: { + if (is_inside_tree() && (get_parent() != agent_parent)) { + // only react to PARENTED notifications when already inside_tree and parent changed, e.g. users switch nodes around + // PARENTED notification fires also when Node is added in scripts to a parent + // this would spam transforms fails and world fails while Node is outside SceneTree + // when node gets reparented when joining the tree POST_ENTER_TREE takes care of this + set_agent_parent(get_parent()); + set_physics_process_internal(true); + } + } break; + + case NOTIFICATION_UNPARENTED: { + // if agent has no parent no point in processing it until reparented + set_agent_parent(nullptr); + set_physics_process_internal(false); + } break; + case NOTIFICATION_EXIT_TREE: { - agent_parent = nullptr; + set_agent_parent(nullptr); set_physics_process_internal(false); } break; @@ -139,7 +153,11 @@ void NavigationAgent3D::_notification(int p_what) { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (agent_parent) { - NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin); + if (avoidance_enabled) { + // agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding + // no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used + NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin); + } _check_distance_to_target(); } } break; @@ -174,6 +192,21 @@ bool NavigationAgent3D::get_avoidance_enabled() const { return avoidance_enabled; } +void NavigationAgent3D::set_agent_parent(Node *p_agent_parent) { + // remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map + NavigationServer3D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done"); + if (Object::cast_to<Node3D>(p_agent_parent) != nullptr) { + // place agent on navigation map first or else the RVO agent callback creation fails silently later + agent_parent = Object::cast_to<Node3D>(p_agent_parent); + NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map()); + // create new avoidance callback if enabled + set_avoidance_enabled(avoidance_enabled); + } else { + agent_parent = nullptr; + NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID()); + } +} + void NavigationAgent3D::set_navigable_layers(uint32_t p_layers) { bool layers_changed = navigable_layers != p_layers; navigable_layers = p_layers; diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h index 28bcffd5b4..633bf091d1 100644 --- a/scene/3d/navigation_agent_3d.h +++ b/scene/3d/navigation_agent_3d.h @@ -84,6 +84,8 @@ public: void set_avoidance_enabled(bool p_enabled); bool get_avoidance_enabled() const; + void set_agent_parent(Node *p_agent_parent); + void set_navigable_layers(uint32_t p_layers); uint32_t get_navigable_layers() const; diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 6404432631..dda1382814 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -73,6 +73,26 @@ uint32_t NavigationRegion3D::get_layers() const { return NavigationServer3D::get_singleton()->region_get_layers(region); } +void NavigationRegion3D::set_enter_cost(real_t p_enter_cost) { + ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive."); + enter_cost = MAX(p_enter_cost, 0.0); + NavigationServer3D::get_singleton()->region_set_enter_cost(region, p_enter_cost); +} + +real_t NavigationRegion3D::get_enter_cost() const { + return enter_cost; +} + +void NavigationRegion3D::set_travel_cost(real_t p_travel_cost) { + ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive."); + travel_cost = MAX(p_travel_cost, 0.0); + NavigationServer3D::get_singleton()->region_set_enter_cost(region, travel_cost); +} + +real_t NavigationRegion3D::get_travel_cost() const { + return travel_cost; +} + RID NavigationRegion3D::get_region_rid() const { return region; } @@ -131,6 +151,17 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes NavigationServer3D::get_singleton()->region_set_navmesh(region, p_navmesh); + if (debug_view == nullptr && is_inside_tree() && navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) { + MeshInstance3D *dm = memnew(MeshInstance3D); + dm->set_mesh(navmesh->get_debug_mesh()); + if (is_enabled()) { + dm->set_material_override(get_tree()->get_debug_navigation_material()); + } else { + dm->set_material_override(get_tree()->get_debug_navigation_disabled_material()); + } + add_child(dm); + debug_view = dm; + } if (debug_view && navmesh.is_valid()) { Object::cast_to<MeshInstance3D>(debug_view)->set_mesh(navmesh->get_debug_mesh()); } @@ -213,12 +244,20 @@ void NavigationRegion3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion3D::get_region_rid); + ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationRegion3D::set_enter_cost); + ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationRegion3D::get_enter_cost); + + ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationRegion3D::set_travel_cost); + ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion3D::get_travel_cost); + ClassDB::bind_method(D_METHOD("bake_navigation_mesh", "on_thread"), &NavigationRegion3D::bake_navigation_mesh, DEFVAL(true)); ClassDB::bind_method(D_METHOD("_bake_finished", "nav_mesh"), &NavigationRegion3D::_bake_finished); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_layers", "get_layers"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost"); ADD_SIGNAL(MethodInfo("navigation_mesh_changed")); ADD_SIGNAL(MethodInfo("bake_finished")); @@ -232,6 +271,8 @@ void NavigationRegion3D::_navigation_changed() { NavigationRegion3D::NavigationRegion3D() { set_notify_transform(true); region = NavigationServer3D::get_singleton()->region_create(); + NavigationServer3D::get_singleton()->region_set_enter_cost(region, get_enter_cost()); + NavigationServer3D::get_singleton()->region_set_travel_cost(region, get_travel_cost()); } NavigationRegion3D::~NavigationRegion3D() { diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index 140dfebf6a..042684c5b7 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -41,6 +41,9 @@ class NavigationRegion3D : public Node3D { RID region; Ref<NavigationMesh> navmesh; + real_t enter_cost = 0.0; + real_t travel_cost = 1.0; + Node *debug_view = nullptr; Thread bake_thread; @@ -59,6 +62,12 @@ public: RID get_region_rid() const; + void set_enter_cost(real_t p_enter_cost); + real_t get_enter_cost() const; + + void set_travel_cost(real_t p_travel_cost); + real_t get_travel_cost() const; + void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh); Ref<NavigationMesh> get_navigation_mesh() const; diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 273e01989a..e40c8bfa2b 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -496,3 +496,12 @@ void GeometryInstance3D::_bind_methods() { GeometryInstance3D::GeometryInstance3D() { //RS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0); } + +GeometryInstance3D::~GeometryInstance3D() { + if (material_overlay.is_valid()) { + set_material_overlay(Ref<Material>()); + } + if (material_override.is_valid()) { + set_material_override(Ref<Material>()); + } +} diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index f8fd4378fe..e5f98bd65e 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -188,6 +188,7 @@ public: TypedArray<String> get_configuration_warnings() const override; GeometryInstance3D(); + virtual ~GeometryInstance3D(); }; VARIANT_ENUM_CAST(GeometryInstance3D::ShadowCastingSetting); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 6f7ad94139..5fff1e1df3 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -31,6 +31,7 @@ #include "color_picker.h" #include "core/input/input.h" +#include "core/math/color.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "scene/main/window.h" @@ -39,6 +40,9 @@ #include "editor/editor_settings.h" #endif +#include "thirdparty/misc/ok_color.h" +#include "thirdparty/misc/ok_color_shader.h" + List<Color> ColorPicker::preset_cache; void ColorPicker::_notification(int p_what) { @@ -102,6 +106,7 @@ void ColorPicker::_notification(int p_what) { Ref<Shader> ColorPicker::wheel_shader; Ref<Shader> ColorPicker::circle_shader; +Ref<Shader> ColorPicker::circle_ok_color_shader; void ColorPicker::init_shaders() { wheel_shader.instantiate(); @@ -152,11 +157,36 @@ void fragment() { COLOR = vec4(mix(vec3(1.0), clamp(abs(fract(vec3((a - TAU) / TAU) + vec3(1.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - vec3(3.0)) - vec3(1.0), 0.0, 1.0), ((float(sqrt(x * x + y * y)) * 2.0)) / 1.0) * vec3(v), (b + b2 + b3 + b4) / 4.00); })"); + + circle_ok_color_shader.instantiate(); + circle_ok_color_shader->set_code(OK_COLOR_SHADER + R"( +// ColorPicker ok color hsv circle shader. + +uniform float v = 1.0; + +void fragment() { + float x = UV.x - 0.5; + float y = UV.y - 0.5; + x += 0.001; + y += 0.001; + float b = float(sqrt(x * x + y * y) < 0.5); + x -= 0.002; + float b2 = float(sqrt(x * x + y * y) < 0.5); + y -= 0.002; + float b3 = float(sqrt(x * x + y * y) < 0.5); + x += 0.002; + float b4 = float(sqrt(x * x + y * y) < 0.5); + float s = sqrt(x * x + y * y); + float h = atan(y, x) / (2.0*M_PI); + vec3 col = okhsl_to_srgb(vec3(h, s, v)); + COLOR = vec4(col, (b + b2 + b3 + b4) / 4.00); +})"); } void ColorPicker::finish_shaders() { wheel_shader.unref(); circle_shader.unref(); + circle_ok_color_shader.unref(); } void ColorPicker::set_focus_on_line_edit() { @@ -166,8 +196,12 @@ void ColorPicker::set_focus_on_line_edit() { void ColorPicker::_update_controls() { const char *rgb[3] = { "R", "G", "B" }; const char *hsv[3] = { "H", "S", "V" }; - - if (hsv_mode_enabled) { + const char *hsl[3] = { "H", "S", "L" }; + if (hsv_mode_enabled && picker_type == SHAPE_OKHSL_CIRCLE) { + for (int i = 0; i < 3; i++) { + labels[i]->set_text(hsl[i]); + } + } else if (hsv_mode_enabled && picker_type != SHAPE_OKHSL_CIRCLE) { for (int i = 0; i < 3; i++) { labels[i]->set_text(hsv[i]); } @@ -176,14 +210,23 @@ void ColorPicker::_update_controls() { labels[i]->set_text(rgb[i]); } } - + if (picker_type == SHAPE_OKHSL_CIRCLE) { + btn_hsv->set_text(RTR("OKHSL")); + } else { + btn_hsv->set_text(RTR("HSV")); + } if (hsv_mode_enabled) { set_raw_mode(false); + set_hsv_mode(true); btn_raw->set_disabled(true); } else if (raw_mode_enabled) { + set_raw_mode(true); set_hsv_mode(false); + btn_raw->set_disabled(false); btn_hsv->set_disabled(true); } else { + set_raw_mode(false); + set_hsv_mode(false); btn_raw->set_disabled(false); btn_hsv->set_disabled(false); } @@ -236,8 +279,15 @@ void ColorPicker::_update_controls() { wheel_edit->show(); w_edit->show(); uv_edit->hide(); - wheel->set_material(circle_mat); + circle_mat->set_shader(circle_shader); + break; + case SHAPE_OKHSL_CIRCLE: + wheel_edit->show(); + w_edit->show(); + uv_edit->hide(); + wheel->set_material(circle_mat); + circle_mat->set_shader(circle_ok_color_shader); break; default: { } @@ -246,11 +296,17 @@ void ColorPicker::_update_controls() { void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) { color = p_color; - if (color != last_hsv) { - h = color.get_h(); - s = color.get_s(); - v = color.get_v(); - last_hsv = color; + if (color != last_color) { + if (picker_type == SHAPE_OKHSL_CIRCLE) { + h = color.get_ok_hsl_h(); + s = color.get_ok_hsl_s(); + v = color.get_ok_hsl_l(); + } else { + h = color.get_h(); + s = color.get_s(); + v = color.get_v(); + } + last_color = color; } if (!is_inside_tree()) { @@ -301,10 +357,13 @@ void ColorPicker::_value_changed(double) { h = scroll[0]->get_value() / 360.0; s = scroll[1]->get_value() / 100.0; v = scroll[2]->get_value() / 100.0; - color.set_hsv(h, s, v, scroll[3]->get_value() / 255.0); - - last_hsv = color; + if (picker_type == SHAPE_OKHSL_CIRCLE) { + color.set_ok_hsl(h, s, v, Math::round(scroll[3]->get_value() / 255.0)); + } else { + color.set_hsv(h, s, v, Math::round(scroll[3]->get_value() / 255.0)); + } + last_color = color; } else { for (int i = 0; i < 4; i++) { color.components[i] = scroll[i]->get_value() / (raw_mode_enabled ? 1.0 : 255.0); @@ -342,7 +401,6 @@ void ColorPicker::_update_color(bool p_update_sliders) { for (int i = 0; i < 4; i++) { scroll[i]->set_step(1.0); } - scroll[0]->set_max(359); scroll[0]->set_value(h * 360.0); scroll[1]->set_max(100); @@ -350,7 +408,7 @@ void ColorPicker::_update_color(bool p_update_sliders) { scroll[2]->set_max(100); scroll[2]->set_value(v * 100.0); scroll[3]->set_max(255); - scroll[3]->set_value(color.components[3] * 255.0); + scroll[3]->set_value(Math::round(color.components[3] * 255.0)); } else { for (int i = 0; i < 4; i++) { if (raw_mode_enabled) { @@ -362,7 +420,7 @@ void ColorPicker::_update_color(bool p_update_sliders) { scroll[i]->set_value(color.components[i]); } else { scroll[i]->set_step(1); - const float byte_value = color.components[i] * 255.0; + const float byte_value = Math::round(color.components[i] * 255.0); scroll[i]->set_max(next_power_of_2(MAX(255, byte_value)) - 1); scroll[i]->set_value(byte_value); } @@ -426,7 +484,6 @@ Color ColorPicker::get_pick_color() const { void ColorPicker::set_picker_shape(PickerShapeType p_picker_type) { ERR_FAIL_INDEX(p_picker_type, SHAPE_MAX); picker_type = p_picker_type; - _update_controls(); _update_color(); } @@ -702,7 +759,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { Ref<Texture2D> cursor = get_theme_icon(SNAME("picker_cursor"), SNAME("ColorPicker")); int x; int y; - if (picker_type == SHAPE_VHS_CIRCLE) { + if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { x = center.x + (center.x * Math::cos(h * Math_TAU) * s) - (cursor->get_width() / 2); y = center.y + (center.y * Math::sin(h * Math_TAU) * s) - (cursor->get_height() / 2); } else { @@ -735,6 +792,25 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { Color col; col.set_hsv(h, 1, 1); c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); + } else if (picker_type == SHAPE_OKHSL_CIRCLE) { + Vector<Point2> points; + Vector<Color> colors; + Color col; + col.set_ok_hsl(h, s, 1); + points.resize(4); + colors.resize(4); + points.set(0, Vector2()); + points.set(1, Vector2(c->get_size().x, 0)); + points.set(2, c->get_size()); + points.set(3, Vector2(0, c->get_size().y)); + colors.set(0, col); + colors.set(1, col); + colors.set(2, Color(0, 0, 0)); + colors.set(3, Color(0, 0, 0)); + c->draw_polygon(points, colors); + int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1); + col.set_ok_hsl(h, 1, v); + c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted()); } else if (picker_type == SHAPE_VHS_CIRCLE) { Vector<Point2> points; Vector<Color> colors; @@ -757,7 +833,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { } } else if (p_which == 2) { c->draw_rect(Rect2(Point2(), c->get_size()), Color(1, 1, 1)); - if (picker_type == SHAPE_VHS_CIRCLE) { + if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { circle_mat->set_shader_param("v", v); } } @@ -793,10 +869,19 @@ void ColorPicker::_slider_draw(int p_which) { } Color s_col; Color v_col; - s_col.set_hsv(h, 0, v); + if (picker_type == SHAPE_OKHSL_CIRCLE) { + s_col.set_ok_hsl(h, 0, v); + } else { + s_col.set_hsv(h, 0, v); + } left_color = (p_which == 1) ? s_col : Color(0, 0, 0); - s_col.set_hsv(h, 1, v); - v_col.set_hsv(h, s, 1); + if (picker_type == SHAPE_OKHSL_CIRCLE) { + s_col.set_ok_hsl(h, 1, v); + v_col.set_ok_hsl(h, s, 1); + } else { + s_col.set_hsv(h, 1, v); + v_col.set_hsv(h, s, 1); + } right_color = (p_which == 1) ? s_col : v_col; } else { left_color = Color( @@ -828,9 +913,8 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { if (bev.is_valid()) { if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { Vector2 center = c->get_size() / 2.0; - if (picker_type == SHAPE_VHS_CIRCLE) { + if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { real_t dist = center.distance_to(bev->get_position()); - if (dist <= center.x) { real_t rad = center.angle_to_point(bev->get_position()); h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; @@ -867,8 +951,13 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { } } changing_color = true; - color.set_hsv(h, s, v, color.a); - last_hsv = color; + if (picker_type == SHAPE_OKHSL_CIRCLE) { + color.set_ok_hsl(h, s, v, color.a); + } else if (picker_type != SHAPE_OKHSL_CIRCLE) { + color.set_hsv(h, s, v, color.a); + } + last_color = color; + set_pick_color(color); _update_color(); if (!deferred_mode_enabled) { @@ -892,7 +981,7 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { } Vector2 center = c->get_size() / 2.0; - if (picker_type == SHAPE_VHS_CIRCLE) { + if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { real_t dist = center.distance_to(mev->get_position()); real_t rad = center.angle_to_point(mev->get_position()); h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; @@ -913,9 +1002,12 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { v = 1.0 - (y - corner_y) / real_size.y; } } - - color.set_hsv(h, s, v, color.a); - last_hsv = color; + if (picker_type != SHAPE_OKHSL_CIRCLE) { + color.set_hsv(h, s, v, color.a); + } else if (picker_type == SHAPE_OKHSL_CIRCLE) { + color.set_ok_hsl(h, s, v, color.a); + } + last_color = color; set_pick_color(color); _update_color(); if (!deferred_mode_enabled) { @@ -931,7 +1023,7 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) { changing_color = true; float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height); - if (picker_type == SHAPE_VHS_CIRCLE) { + if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { v = 1.0 - (y / w_edit->get_size().height); } else { h = y / w_edit->get_size().height; @@ -939,8 +1031,12 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { } else { changing_color = false; } - color.set_hsv(h, s, v, color.a); - last_hsv = color; + if (picker_type != SHAPE_OKHSL_CIRCLE) { + color.set_hsv(h, s, v, color.a); + } else if (picker_type == SHAPE_OKHSL_CIRCLE) { + color.set_ok_hsl(h, s, v, color.a); + } + last_color = color; set_pick_color(color); _update_color(); if (!deferred_mode_enabled) { @@ -957,13 +1053,17 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { return; } float y = CLAMP((float)mev->get_position().y, 0, w_edit->get_size().height); - if (picker_type == SHAPE_VHS_CIRCLE) { + if (picker_type == SHAPE_VHS_CIRCLE || picker_type == SHAPE_OKHSL_CIRCLE) { v = 1.0 - (y / w_edit->get_size().height); } else { h = y / w_edit->get_size().height; } - color.set_hsv(h, s, v, color.a); - last_hsv = color; + if (hsv_mode_enabled && picker_type != SHAPE_OKHSL_CIRCLE) { + color.set_hsv(h, s, v, color.a); + } else if (hsv_mode_enabled && picker_type == SHAPE_OKHSL_CIRCLE) { + color.set_ok_hsl(h, s, v, color.a); + } + last_color = color; set_pick_color(color); _update_color(); if (!deferred_mode_enabled) { @@ -1128,7 +1228,7 @@ void ColorPicker::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hsv_mode"), "set_hsv_mode", "is_hsv_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "raw_mode"), "set_raw_mode", "is_raw_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle"), "set_picker_shape", "get_picker_shape"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle"), "set_picker_shape", "get_picker_shape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_enabled"), "set_presets_enabled", "are_presets_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_visible"), "set_presets_visible", "are_presets_visible"); @@ -1139,6 +1239,7 @@ void ColorPicker::_bind_methods() { BIND_ENUM_CONSTANT(SHAPE_HSV_RECTANGLE); BIND_ENUM_CONSTANT(SHAPE_HSV_WHEEL); BIND_ENUM_CONSTANT(SHAPE_VHS_CIRCLE); + BIND_ENUM_CONSTANT(SHAPE_OKHSL_CIRCLE); } ColorPicker::ColorPicker() : diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 6f3e16009c..953be032ec 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -68,6 +68,7 @@ public: SHAPE_HSV_RECTANGLE, SHAPE_HSV_WHEEL, SHAPE_VHS_CIRCLE, + SHAPE_OKHSL_CIRCLE, SHAPE_MAX }; @@ -75,6 +76,7 @@ public: private: static Ref<Shader> wheel_shader; static Ref<Shader> circle_shader; + static Ref<Shader> circle_ok_color_shader; static List<Color> preset_cache; Control *screen = nullptr; @@ -124,7 +126,7 @@ private: float h = 0.0; float s = 0.0; float v = 0.0; - Color last_hsv; + Color last_color; void _html_submitted(const String &p_html); void _value_changed(double); @@ -161,6 +163,8 @@ public: void set_edit_alpha(bool p_show); bool is_editing_alpha() const; + int get_preset_size(); + void _set_pick_color(const Color &p_color, bool p_update_sliders); void set_pick_color(const Color &p_color); Color get_pick_color() const; diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index fdff6a88a9..8ad55fc6ef 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -426,8 +426,8 @@ void GraphEdit::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { - port_grab_distance_horizontal = get_theme_constant(SNAME("port_grab_distance_horizontal")); - port_grab_distance_vertical = get_theme_constant(SNAME("port_grab_distance_vertical")); + port_hotzone_inner_extent = get_theme_constant("port_hotzone_inner_extent"); + port_hotzone_outer_extent = get_theme_constant("port_hotzone_outer_extent"); zoom_minus->set_icon(get_theme_icon(SNAME("minus"))); zoom_reset->set_icon(get_theme_icon(SNAME("reset"))); @@ -508,8 +508,9 @@ void GraphEdit::_notification(int p_what) { void GraphEdit::_update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes) { Rect2 comment_node_rect = p_node->get_rect(); - Vector<GraphNode *> enclosed_nodes; + comment_node_rect.size *= zoom; + Vector<GraphNode *> enclosed_nodes; for (int i = 0; i < get_child_count(); i++) { GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); if (!gn || gn->is_selected()) { @@ -517,6 +518,8 @@ void GraphEdit::_update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<S } Rect2 node_rect = gn->get_rect(); + node_rect.size *= zoom; + bool included = comment_node_rect.encloses(node_rect); if (included) { enclosed_nodes.push_back(gn); @@ -544,8 +547,7 @@ void GraphEdit::_set_position_of_comment_enclosed_nodes(GraphNode *p_node, HashM } bool GraphEdit::_filter_input(const Point2 &p_point) { - Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode")); - Vector2i port_size = Vector2i(port->get_width(), port->get_height()); + Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode")); for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); @@ -553,14 +555,18 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { continue; } - for (int j = 0; j < gn->get_connection_output_count(); j++) { - if (is_in_output_hotzone(gn, j, p_point / zoom, port_size)) { + for (int j = 0; j < gn->get_connection_input_count(); j++) { + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_input_height(j)); + if (is_in_input_hotzone(gn, j, p_point / zoom, port_size)) { return true; } } - for (int j = 0; j < gn->get_connection_input_count(); j++) { - if (is_in_input_hotzone(gn, j, p_point / zoom, port_size)) { + for (int j = 0; j < gn->get_connection_output_count(); j++) { + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_output_height(j)); + if (is_in_output_hotzone(gn, j, p_point / zoom, port_size)) { return true; } } @@ -572,8 +578,7 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { Ref<InputEventMouseButton> mb = p_ev; if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) { - Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode")); - Vector2i port_size = Vector2i(port->get_width(), port->get_height()); + Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode")); connecting_valid = false; click_pos = mb->get_position() / zoom; @@ -585,6 +590,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_output_height(j)); + if (is_in_output_hotzone(gn, j, click_pos, port_size)) { if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) { //check disconnect @@ -629,6 +637,10 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); + + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_input_height(j)); + if (is_in_input_hotzone(gn, j, click_pos, port_size)) { if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) { //check disconnect @@ -682,11 +694,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0; if (connecting_valid) { - Ref<Texture2D> port = get_theme_icon(SNAME("port"), SNAME("GraphNode")); - Vector2i port_size = Vector2i(port->get_width(), port->get_height()); - Vector2 mpos = mm->get_position() / zoom; for (int i = get_child_count() - 1; i >= 0; i--) { + Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode")); GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); if (!gn) { continue; @@ -695,6 +705,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { if (!connecting_out) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_output_height(j)); + int type = gn->get_connection_output_type(j); if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_output_hotzone(gn, j, mpos, port_size)) { connecting_target = true; @@ -707,6 +720,9 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { } else { for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); + Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height()); + port_size.height = MAX(port_size.height, gn->get_connection_input_height(j)); + int type = gn->get_connection_input_type(j); if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_input_hotzone(gn, j, mpos, port_size)) { connecting_target = true; @@ -754,19 +770,24 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { } } -bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &pos) { - if (p_control->is_set_as_top_level() || !p_control->is_visible()) { +bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &mpos, const Vector2 &p_offset) { + if (p_control->is_set_as_top_level() || !p_control->is_visible() || !p_control->is_inside_tree()) { return false; } - if (!p_control->has_point(pos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) { - //test children + Rect2 control_rect = p_control->get_rect(); + control_rect.size *= zoom; + control_rect.position *= zoom; + control_rect.position += p_offset; + + if (!control_rect.has_point(mpos) || p_control->get_mouse_filter() == MOUSE_FILTER_IGNORE) { + // Test children. for (int i = 0; i < p_control->get_child_count(); i++) { - Control *subchild = Object::cast_to<Control>(p_control->get_child(i)); - if (!subchild) { + Control *child_rect = Object::cast_to<Control>(p_control->get_child(i)); + if (!child_rect) { continue; } - if (_check_clickable_control(subchild, pos - subchild->get_position())) { + if (_check_clickable_control(child_rect, mpos, control_rect.position)) { return true; } } @@ -798,7 +819,13 @@ bool GraphEdit::is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index, } bool GraphEdit::is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left) { - if (!Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2).has_point(p_mouse_pos)) { + Rect2 hotzone = Rect2( + pos.x - (p_left ? port_hotzone_outer_extent : port_hotzone_inner_extent), + pos.y - p_port_size.height / 2.0, + port_hotzone_inner_extent + port_hotzone_outer_extent, + p_port_size.height); + + if (!hotzone.has_point(p_mouse_pos)) { return false; } @@ -807,23 +834,17 @@ bool GraphEdit::is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_po if (!child) { continue; } - Rect2 rect = child->get_rect(); - - // To prevent intersections with other nodes. - rect.position *= zoom; - rect.size *= zoom; - - if (rect.has_point(p_mouse_pos)) { - //check sub-controls - Vector2 subpos = p_mouse_pos - rect.position; + Rect2 child_rect = child->get_rect(); + child_rect.size *= zoom; + if (child_rect.has_point(p_mouse_pos * zoom)) { for (int j = 0; j < child->get_child_count(); j++) { Control *subchild = Object::cast_to<Control>(child->get_child(j)); if (!subchild) { continue; } - if (_check_clickable_control(subchild, subpos - subchild->get_position())) { + if (_check_clickable_control(subchild, p_mouse_pos * zoom, child_rect.position)) { return false; } } @@ -839,13 +860,23 @@ PackedVector2Array GraphEdit::get_connection_line(const Vector2 &p_from, const V return ret; } + float x_diff = (p_to.x - p_from.x); + float cp_offset = x_diff * lines_curvature; + if (x_diff < 0) { + cp_offset *= -1; + } + Curve2D curve; - Vector<Color> colors; curve.add_point(p_from); - curve.set_point_out(0, Vector2(60, 0)); + curve.set_point_out(0, Vector2(cp_offset, 0)); curve.add_point(p_to); - curve.set_point_in(1, Vector2(-60, 0)); - return curve.tessellate(); + curve.set_point_in(1, Vector2(-cp_offset, 0)); + + if (lines_curvature > 0) { + return curve.tessellate(5, 2.0); + } else { + return curve.tessellate(1); + } } void GraphEdit::_draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom) { @@ -1666,6 +1697,15 @@ void GraphEdit::_minimap_toggled() { } } +void GraphEdit::set_connection_lines_curvature(float p_curvature) { + lines_curvature = p_curvature; + update(); +} + +float GraphEdit::get_connection_lines_curvature() const { + return lines_curvature; +} + void GraphEdit::set_connection_lines_thickness(float p_thickness) { lines_thickness = p_thickness; update(); @@ -2244,6 +2284,9 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_snap", "enable"), &GraphEdit::set_use_snap); ClassDB::bind_method(D_METHOD("is_using_snap"), &GraphEdit::is_using_snap); + ClassDB::bind_method(D_METHOD("set_connection_lines_curvature", "curvature"), &GraphEdit::set_connection_lines_curvature); + ClassDB::bind_method(D_METHOD("get_connection_lines_curvature"), &GraphEdit::get_connection_lines_curvature); + ClassDB::bind_method(D_METHOD("set_connection_lines_thickness", "pixels"), &GraphEdit::set_connection_lines_thickness); ClassDB::bind_method(D_METHOD("get_connection_lines_thickness"), &GraphEdit::get_connection_lines_thickness); @@ -2280,6 +2323,7 @@ void GraphEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "panning_scheme", PROPERTY_HINT_ENUM, "Scroll Zooms,Scroll Pans"), "set_panning_scheme", "get_panning_scheme"); ADD_GROUP("Connection Lines", "connection_lines"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "connection_lines_curvature"), "set_connection_lines_curvature", "get_connection_lines_curvature"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "connection_lines_thickness"), "set_connection_lines_thickness", "get_connection_lines_thickness"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "connection_lines_antialiased"), "set_connection_lines_antialiased", "is_connection_lines_antialiased"); diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index 5484a2317c..02e90e4717 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -124,8 +124,8 @@ private: HScrollBar *h_scroll = nullptr; VScrollBar *v_scroll = nullptr; - float port_grab_distance_horizontal = 0.0; - float port_grab_distance_vertical = 0.0; + float port_hotzone_inner_extent = 0.0; + float port_hotzone_outer_extent = 0.0; Ref<ViewPanner> panner; bool warped_panning = true; @@ -178,6 +178,7 @@ private: List<Connection> connections; float lines_thickness = 2.0f; + float lines_curvature = 0.5f; bool lines_antialiased = true; PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to); @@ -250,7 +251,7 @@ private: friend class GraphEditMinimap; void _minimap_toggled(); - bool _check_clickable_control(Control *p_control, const Vector2 &pos); + bool _check_clickable_control(Control *p_control, const Vector2 &r_mouse_pos, const Vector2 &p_offset); bool arranging_graph = false; @@ -344,6 +345,9 @@ public: int get_snap() const; void set_snap(int p_snap); + void set_connection_lines_curvature(float p_curvature); + float get_connection_lines_curvature() const; + void set_connection_lines_thickness(float p_thickness); float get_connection_lines_thickness() const; diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 45f036d8fc..5cb28a30e8 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -832,6 +832,7 @@ void GraphNode::_connpos_update() { cc.pos = Point2i(edgeofs, y + h / 2); cc.type = slot_info[idx].type_left; cc.color = slot_info[idx].color_left; + cc.height = size.height; conn_input_cache.push_back(cc); } if (slot_info[idx].enable_right) { @@ -839,6 +840,7 @@ void GraphNode::_connpos_update() { cc.pos = Point2i(get_size().width - edgeofs, y + h / 2); cc.type = slot_info[idx].type_right; cc.color = slot_info[idx].color_right; + cc.height = size.height; conn_output_cache.push_back(cc); } } @@ -859,12 +861,13 @@ int GraphNode::get_connection_input_count() { return conn_input_cache.size(); } -int GraphNode::get_connection_output_count() { +int GraphNode::get_connection_input_height(int p_idx) { if (connpos_dirty) { _connpos_update(); } - return conn_output_cache.size(); + ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), 0); + return conn_input_cache[p_idx].height; } Vector2 GraphNode::get_connection_input_position(int p_idx) { @@ -897,6 +900,23 @@ Color GraphNode::get_connection_input_color(int p_idx) { return conn_input_cache[p_idx].color; } +int GraphNode::get_connection_output_count() { + if (connpos_dirty) { + _connpos_update(); + } + + return conn_output_cache.size(); +} + +int GraphNode::get_connection_output_height(int p_idx) { + if (connpos_dirty) { + _connpos_update(); + } + + ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), 0); + return conn_output_cache[p_idx].height; +} + Vector2 GraphNode::get_connection_output_position(int p_idx) { if (connpos_dirty) { _connpos_update(); @@ -1066,15 +1086,17 @@ void GraphNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_selected", "selected"), &GraphNode::set_selected); ClassDB::bind_method(D_METHOD("is_selected"), &GraphNode::is_selected); - ClassDB::bind_method(D_METHOD("get_connection_output_count"), &GraphNode::get_connection_output_count); ClassDB::bind_method(D_METHOD("get_connection_input_count"), &GraphNode::get_connection_input_count); + ClassDB::bind_method(D_METHOD("get_connection_input_height", "idx"), &GraphNode::get_connection_input_height); + ClassDB::bind_method(D_METHOD("get_connection_input_position", "idx"), &GraphNode::get_connection_input_position); + ClassDB::bind_method(D_METHOD("get_connection_input_type", "idx"), &GraphNode::get_connection_input_type); + ClassDB::bind_method(D_METHOD("get_connection_input_color", "idx"), &GraphNode::get_connection_input_color); + ClassDB::bind_method(D_METHOD("get_connection_output_count"), &GraphNode::get_connection_output_count); + ClassDB::bind_method(D_METHOD("get_connection_output_height", "idx"), &GraphNode::get_connection_output_height); ClassDB::bind_method(D_METHOD("get_connection_output_position", "idx"), &GraphNode::get_connection_output_position); ClassDB::bind_method(D_METHOD("get_connection_output_type", "idx"), &GraphNode::get_connection_output_type); ClassDB::bind_method(D_METHOD("get_connection_output_color", "idx"), &GraphNode::get_connection_output_color); - ClassDB::bind_method(D_METHOD("get_connection_input_position", "idx"), &GraphNode::get_connection_input_position); - ClassDB::bind_method(D_METHOD("get_connection_input_type", "idx"), &GraphNode::get_connection_input_type); - ClassDB::bind_method(D_METHOD("get_connection_input_color", "idx"), &GraphNode::get_connection_input_color); ClassDB::bind_method(D_METHOD("set_show_close_button", "show"), &GraphNode::set_show_close_button); ClassDB::bind_method(D_METHOD("is_close_button_visible"), &GraphNode::is_close_button_visible); diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 9481a7452d..f6c943dc89 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -81,6 +81,7 @@ private: Vector2 pos; int type = 0; Color color; + int height; }; Vector<ConnCache> conn_input_cache; @@ -167,10 +168,13 @@ public: bool is_close_button_visible() const; int get_connection_input_count(); - int get_connection_output_count(); + int get_connection_input_height(int p_idx); Vector2 get_connection_input_position(int p_idx); int get_connection_input_type(int p_idx); Color get_connection_input_color(int p_idx); + + int get_connection_output_count(); + int get_connection_output_height(int p_idx); Vector2 get_connection_output_position(int p_idx); int get_connection_output_type(int p_idx); Color get_connection_output_color(int p_idx); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 73188d6602..540250c8e9 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -312,7 +312,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { selection.end = text.length(); selection.double_click = true; last_dblclk = 0; - caret_column = selection.begin; + set_caret_column(selection.begin); if (!pass && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) { DisplayServer::get_singleton()->clipboard_set_primary(text); } @@ -327,7 +327,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { selection.begin = words[i]; selection.end = words[i + 1]; selection.double_click = true; - caret_column = selection.end; + set_caret_column(selection.end); break; } } @@ -695,7 +695,7 @@ bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const { return false; } Ref<Texture2D> icon = Control::get_theme_icon(SNAME("clear")); - int x_ofs = get_theme_stylebox(SNAME("normal"))->get_offset().x; + int x_ofs = get_theme_stylebox(SNAME("normal"))->get_margin(SIDE_RIGHT); return p_pos.x > get_size().width - icon->get_width() - x_ofs; } @@ -1686,13 +1686,17 @@ Size2 LineEdit::get_minimum_size() const { min_size.height = MAX(TS->shaped_text_get_size(text_rid).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM), font->get_height(font_size)); // Take icons into account. - bool using_placeholder = text.is_empty() && ime_text.is_empty(); - bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; - if (right_icon.is_valid() || display_clear_icon) { - Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon; - min_size.width += r_icon->get_width(); - min_size.height = MAX(min_size.height, r_icon->get_height()); + int icon_max_width = 0; + if (right_icon.is_valid()) { + min_size.height = MAX(min_size.height, right_icon->get_height()); + icon_max_width = right_icon->get_width(); + } + if (clear_button_enabled) { + Ref<Texture2D> clear_icon = Control::get_theme_icon(SNAME("clear")); + min_size.height = MAX(min_size.height, clear_icon->get_height()); + icon_max_width = MAX(icon_max_width, clear_icon->get_width()); } + min_size.width += icon_max_width; return style->get_minimum_size() + min_size; } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 94c2a9e64b..cf7bf930a5 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -414,7 +414,7 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font } l.offset.y = p_h; - return l.offset.y + l.text_buf->get_size().y + l.text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); + return _calculate_line_vertical_offset(l); } float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, float p_h, int *r_char_offset) { @@ -683,7 +683,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> *r_char_offset = l.char_offset + l.char_count; l.offset.y = p_h; - return l.offset.y + l.text_buf->get_size().y + l.text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); + return _calculate_line_vertical_offset(l); } int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs) { @@ -1566,7 +1566,7 @@ int RichTextLabel::_find_first_line(int p_from, int p_to, int p_vofs) const { while (l < r) { int m = Math::floor(double(l + r) / 2.0); MutexLock lock(main->lines[m].text_buf->get_mutex()); - int ofs = main->lines[m].offset.y + main->lines[m].text_buf->get_size().y + main->lines[m].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); + int ofs = _calculate_line_vertical_offset(main->lines[m]); if (ofs < p_vofs) { l = m + 1; } else { @@ -1576,6 +1576,10 @@ int RichTextLabel::_find_first_line(int p_from, int p_to, int p_vofs) const { return l; } +_FORCE_INLINE_ float RichTextLabel::_calculate_line_vertical_offset(const RichTextLabel::Line &line) const { + return line.get_height(get_theme_constant(SNAME("line_separation"))); +} + void RichTextLabel::_notification(int p_what) { switch (p_what) { case NOTIFICATION_MOUSE_EXIT: { @@ -1609,6 +1613,7 @@ void RichTextLabel::_notification(int p_what) { update(); } break; + case NOTIFICATION_PREDELETE: case NOTIFICATION_EXIT_TREE: { _stop_thread(); } break; @@ -2489,7 +2494,7 @@ bool RichTextLabel::_validate_line_caches() { // Resize lines without reshaping. int fi = main->first_resized_line.load(); - float total_height = 0; + float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]); for (int i = fi; i < (int)main->lines.size(); i++) { total_height = _resize_line(main, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height); @@ -2551,6 +2556,10 @@ bool RichTextLabel::_validate_line_caches() { void RichTextLabel::_process_line_caches() { // Shape invalid lines. + if (!is_inside_tree()) { + return; + } + MutexLock data_lock(data_mutex); Rect2 text_rect = _get_text_rect(); @@ -2560,10 +2569,9 @@ void RichTextLabel::_process_line_caches() { int fi = main->first_invalid_line.load(); int total_chars = (fi == 0) ? 0 : (main->lines[fi].char_offset + main->lines[fi].char_count); - float total_height = 0; + float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]); for (int i = fi; i < (int)main->lines.size(); i++) { total_height = _shape_line(main, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height, &total_chars); - updating_scroll = true; bool exceeds = total_height > ctrl_height && scroll_active; if (exceeds != scroll_visible) { @@ -2577,11 +2585,11 @@ void RichTextLabel::_process_line_caches() { scroll_w = 0; vscroll->hide(); } - main->first_invalid_line.store(0); main->first_resized_line.store(0); main->first_invalid_font_line.store(0); + // since scroll was added or removed we need to resize all lines total_height = 0; for (int j = 0; j <= i; j++) { total_height = _resize_line(main, j, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height); @@ -3369,21 +3377,34 @@ void RichTextLabel::append_text(const String &p_bbcode) { bool in_bold = false; bool in_italics = false; + bool after_list_open_tag = false; + bool after_list_close_tag = false; set_process_internal(false); - while (pos < p_bbcode.length()) { + while (pos <= p_bbcode.length()) { int brk_pos = p_bbcode.find("[", pos); if (brk_pos < 0) { brk_pos = p_bbcode.length(); } - if (brk_pos > pos) { - add_text(p_bbcode.substr(pos, brk_pos - pos)); + String text = brk_pos > pos ? p_bbcode.substr(pos, brk_pos - pos) : ""; + + // Trim the first newline character, it may be added later as needed. + if (after_list_close_tag || after_list_open_tag) { + text = text.trim_prefix("\n"); } if (brk_pos == p_bbcode.length()) { + // For tags that are not properly closed. + if (text.is_empty() && after_list_open_tag) { + text = "\n"; + } + + if (!text.is_empty()) { + add_text(text); + } break; //nothing else to add } @@ -3391,7 +3412,8 @@ void RichTextLabel::append_text(const String &p_bbcode) { if (brk_end == -1) { //no close, add the rest - add_text(p_bbcode.substr(brk_pos, p_bbcode.length() - brk_pos)); + text += p_bbcode.substr(brk_pos, p_bbcode.length() - brk_pos); + add_text(text); break; } @@ -3437,18 +3459,60 @@ void RichTextLabel::append_text(const String &p_bbcode) { } if (!tag_ok) { - add_text("[" + tag); + text += "[" + tag; + add_text(text); + after_list_open_tag = false; + after_list_close_tag = false; pos = brk_end; continue; } + if (text.is_empty() && after_list_open_tag) { + text = "\n"; // Make empty list have at least one item. + } + after_list_open_tag = false; + + if (tag == "/ol" || tag == "/ul") { + if (!text.is_empty()) { + // Make sure text ends with a newline character, that is, the last item + // will wrap at the end of block. + if (!text.ends_with("\n")) { + text += "\n"; + } + } else if (!after_list_close_tag) { + text = "\n"; // Make the innermost list item wrap at the end of lists. + } + after_list_close_tag = true; + } else { + after_list_close_tag = false; + } + + if (!text.is_empty()) { + add_text(text); + } + tag_stack.pop_front(); pos = brk_end + 1; if (tag != "/img" && tag != "/dropcap") { pop(); } + continue; + } + + if (tag == "ol" || tag.begins_with("ol ") || tag == "ul" || tag.begins_with("ul ")) { + if (text.is_empty() && after_list_open_tag) { + text = "\n"; // Make each list have at least one item at the beginning. + } + after_list_open_tag = true; + } else { + after_list_open_tag = false; + } + if (!text.is_empty()) { + add_text(text); + } + after_list_close_tag = false; - } else if (tag == "b") { + if (tag == "b") { //use bold font in_bold = true; if (in_italics) { diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 7fbd5f1745..93e57058b0 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -117,6 +117,10 @@ private: int char_count = 0; Line() { text_buf.instantiate(); } + + _FORCE_INLINE_ float get_height(float line_separation) const { + return offset.y + text_buf->get_size().y + text_buf->get_line_count() * line_separation; + } }; struct Item { @@ -504,6 +508,8 @@ private: void _scroll_changed(double); int _find_first_line(int p_from, int p_to, int p_vofs) const; + _FORCE_INLINE_ float _calculate_line_vertical_offset(const Line &line) const; + virtual void gui_input(const Ref<InputEvent> &p_event) override; virtual String get_tooltip(const Point2 &p_pos) const override; Item *_get_next_item(Item *p_item, bool p_free = false) const; diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index b96ba0ebf9..fec8d11bef 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -862,6 +862,7 @@ void TabBar::_update_hover() { void TabBar::_update_cache() { if (tabs.is_empty()) { + buttons_visible = false; return; } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 0f74c9c357..8e948203f1 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -3080,7 +3080,7 @@ void TextEdit::set_line(int p_line, const String &p_new_text) { _remove_text(p_line, 0, p_line, text[p_line].length()); _insert_text(p_line, 0, p_new_text); if (caret.line == p_line && caret.column > p_new_text.length()) { - set_caret_column(MIN(caret.column, p_new_text.length()), false); + set_caret_column(p_new_text.length(), false); } if (has_selection() && p_line == selection.to_line && selection.to_column > text[p_line].length()) { selection.to_column = text[p_line].length(); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 4d18bc91c4..d3e7540790 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2164,12 +2164,12 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } // Draw relationship lines. - if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) { + if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root) && c->is_visible()) { int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); int parent_ofs = p_pos.x + cache.item_margin; Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs; - if (c->get_first_child() != nullptr) { + if (c->get_visible_child_count() > 0) { root_pos -= Point2i(cache.arrow->get_width(), 0); } @@ -3971,16 +3971,15 @@ TreeItem *Tree::get_last_item() const { return last; } -void Tree::item_edited(int p_column, TreeItem *p_item, MouseButton p_mouse_index) { +void Tree::item_edited(int p_column, TreeItem *p_item, MouseButton p_custom_mouse_index) { edited_item = p_item; edited_col = p_column; if (p_item != nullptr && p_column >= 0 && p_column < p_item->cells.size()) { edited_item->cells.write[p_column].dirty = true; } - if (p_mouse_index == MouseButton::NONE) { - emit_signal(SNAME("item_edited")); - } else { - emit_signal(SNAME("custom_item_clicked"), p_mouse_index); + emit_signal(SNAME("item_edited")); + if (p_custom_mouse_index != MouseButton::NONE) { + emit_signal(SNAME("custom_item_clicked"), p_custom_mouse_index); } } @@ -4524,6 +4523,7 @@ Point2 Tree::get_scroll() const { } void Tree::scroll_to_item(TreeItem *p_item, bool p_center_on_item) { + ERR_FAIL_NULL(p_item); if (!is_visible_in_tree() || !p_item->is_visible()) { return; // Hack to work around crash in get_item_rect() if Tree is not in tree. } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index a70f24cb62..0a8dd3204a 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -474,7 +474,7 @@ private: void _notification(int p_what); - void item_edited(int p_column, TreeItem *p_item, MouseButton p_mouse_index = MouseButton::NONE); + void item_edited(int p_column, TreeItem *p_item, MouseButton p_custom_mouse_index = MouseButton::NONE); void item_changed(int p_column, TreeItem *p_item); void item_selected(int p_column, TreeItem *p_item); void item_deselected(int p_column, TreeItem *p_item); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index b695dddf65..14daf2c108 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1381,6 +1381,9 @@ SceneTree::SceneTree() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/screen_space_aa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)")); root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode)); + const bool use_taa = GLOBAL_DEF("rendering/anti_aliasing/quality/use_taa", false); + root->set_use_taa(use_taa); + const bool use_debanding = GLOBAL_DEF("rendering/anti_aliasing/quality/use_debanding", false); root->set_use_debanding(use_debanding); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 590c73de0b..0e00e51181 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -161,29 +161,6 @@ ViewportTexture::~ViewportTexture() { } } -///////////////////////////////////// - -// Aliases used to provide custom styles to tooltips in the default -// theme and editor theme. -// TooltipPanel is also used for custom tooltips, while TooltipLabel -// is only relevant for default tooltips. - -class TooltipPanel : public PopupPanel { - GDCLASS(TooltipPanel, PopupPanel); - -public: - TooltipPanel() {} -}; - -class TooltipLabel : public Label { - GDCLASS(TooltipLabel, Label); - -public: - TooltipLabel() {} -}; - -///////////////////////////////////// - void Viewport::_sub_window_update_order() { for (int i = 0; i < gui.sub_windows.size(); i++) { RS::get_singleton()->canvas_item_set_draw_index(gui.sub_windows[i].canvas_item, i); @@ -1221,7 +1198,8 @@ void Viewport::_gui_show_tooltip() { } // Popup window which houses the tooltip content. - TooltipPanel *panel = memnew(TooltipPanel); + PopupPanel *panel = memnew(PopupPanel); + panel->set_theme_type_variation(SNAME("TooltipPanel")); // Controls can implement `make_custom_tooltip` to provide their own tooltip. // This should be a Control node which will be added as child to a TooltipPanel. @@ -1229,7 +1207,8 @@ void Viewport::_gui_show_tooltip() { // If no custom tooltip is given, use a default implementation. if (!base_tooltip) { - gui.tooltip_label = memnew(TooltipLabel); + gui.tooltip_label = memnew(Label); + gui.tooltip_label->set_theme_type_variation(SNAME("TooltipLabel")); gui.tooltip_label->set_auto_translate(gui.tooltip_control->is_auto_translating()); gui.tooltip_label->set_text(tooltip_text); base_tooltip = gui.tooltip_label; @@ -2897,6 +2876,18 @@ Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const { return screen_space_aa; } +void Viewport::set_use_taa(bool p_use_taa) { + if (use_taa == p_use_taa) { + return; + } + use_taa = p_use_taa; + RS::get_singleton()->viewport_set_use_taa(viewport, p_use_taa); +} + +bool Viewport::is_using_taa() const { + return use_taa; +} + void Viewport::set_use_debanding(bool p_use_debanding) { if (use_debanding == p_use_debanding) { return; @@ -3458,8 +3449,8 @@ void Viewport::_own_world_3d_changed() { _update_audio_listener_3d(); } -void Viewport::set_use_own_world_3d(bool p_world_3d) { - if (p_world_3d == own_world_3d.is_valid()) { +void Viewport::set_use_own_world_3d(bool p_use_own_world_3d) { + if (p_use_own_world_3d == own_world_3d.is_valid()) { return; } @@ -3467,18 +3458,18 @@ void Viewport::set_use_own_world_3d(bool p_world_3d) { _propagate_exit_world_3d(this); } - if (!p_world_3d) { - own_world_3d = Ref<World3D>(); - if (world_3d.is_valid()) { - world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed)); - } - } else { + if (p_use_own_world_3d) { if (world_3d.is_valid()) { own_world_3d = world_3d->duplicate(); world_3d->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed)); } else { own_world_3d = Ref<World3D>(memnew(World3D)); } + } else { + own_world_3d = Ref<World3D>(); + if (world_3d.is_valid()) { + world_3d->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Viewport::_own_world_3d_changed)); + } } if (is_inside_tree()) { @@ -3632,6 +3623,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &Viewport::set_screen_space_aa); ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &Viewport::get_screen_space_aa); + ClassDB::bind_method(D_METHOD("set_use_taa", "enable"), &Viewport::set_use_taa); + ClassDB::bind_method(D_METHOD("is_using_taa"), &Viewport::is_using_taa); + ClassDB::bind_method(D_METHOD("set_use_debanding", "enable"), &Viewport::set_use_debanding); ClassDB::bind_method(D_METHOD("is_using_debanding"), &Viewport::is_using_debanding); @@ -3760,6 +3754,7 @@ void Viewport::_bind_methods() { ADD_GROUP("Rendering", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa", "get_msaa"); ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), "set_screen_space_aa", "get_screen_space_aa"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_taa"), "set_use_taa", "is_using_taa"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mesh_lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_mesh_lod_threshold", "get_mesh_lod_threshold"); @@ -3858,6 +3853,7 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_DECALS); BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_REFLECTION_PROBES); BIND_ENUM_CONSTANT(DEBUG_DRAW_OCCLUDERS) + BIND_ENUM_CONSTANT(DEBUG_DRAW_MOTION_VECTORS) BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST); BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 5bca5a2dda..a22a2acf49 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -160,6 +160,7 @@ public: DEBUG_DRAW_CLUSTER_DECALS, DEBUG_DRAW_CLUSTER_REFLECTION_PROBES, DEBUG_DRAW_OCCLUDERS, + DEBUG_DRAW_MOTION_VECTORS, }; enum DefaultCanvasItemTextureFilter { @@ -291,6 +292,7 @@ private: MSAA msaa = MSAA_DISABLED; ScreenSpaceAA screen_space_aa = SCREEN_SPACE_AA_DISABLED; + bool use_taa = false; Scaling3DMode scaling_3d_mode = SCALING_3D_MODE_BILINEAR; float scaling_3d_scale = 1.0; @@ -515,6 +517,9 @@ public: void set_screen_space_aa(ScreenSpaceAA p_screen_space_aa); ScreenSpaceAA get_screen_space_aa() const; + void set_use_taa(bool p_use_taa); + bool is_using_taa() const; + void set_scaling_3d_mode(Scaling3DMode p_scaling_3d_mode); Scaling3DMode get_scaling_3d_mode() const; @@ -676,7 +681,7 @@ public: Ref<World3D> get_world_3d() const; Ref<World3D> find_world_3d() const; void _own_world_3d_changed(); - void set_use_own_world_3d(bool p_world_3d); + void set_use_own_world_3d(bool p_use_own_world_3d); bool is_using_own_world_3d() const; void _propagate_enter_world_3d(Node *p_node); void _propagate_exit_world_3d(Node *p_node); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 193f18c075..9b347ed7c8 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -681,7 +681,7 @@ void Window::_update_viewport_size() { } break; case CONTENT_SCALE_MODE_VIEWPORT: { - final_size = viewport_size; + final_size = (viewport_size / content_scale_factor).floor(); attach_to_screen_rect = Rect2(margin, screen_size); } break; diff --git a/scene/multiplayer/multiplayer_synchronizer.cpp b/scene/multiplayer/multiplayer_synchronizer.cpp index 34d5abf9f6..78cec9ee10 100644 --- a/scene/multiplayer/multiplayer_synchronizer.cpp +++ b/scene/multiplayer/multiplayer_synchronizer.cpp @@ -96,7 +96,7 @@ void MultiplayerSynchronizer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_replication_config", "config"), &MultiplayerSynchronizer::set_replication_config); ClassDB::bind_method(D_METHOD("get_replication_config"), &MultiplayerSynchronizer::get_replication_config); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "congiruation", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "replication_config", PROPERTY_HINT_RESOURCE_TYPE, "SceneReplicationConfig"), "set_replication_config", "get_replication_config"); } void MultiplayerSynchronizer::_notification(int p_what) { diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index ba22fdcad3..5fcaf8f2c4 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -1004,13 +1004,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("selection_fill", "GraphEdit", Color(1, 1, 1, 0.3)); theme->set_color("selection_stroke", "GraphEdit", Color(1, 1, 1, 0.8)); theme->set_color("activity", "GraphEdit", Color(1, 1, 1)); - theme->set_constant("bezier_len_pos", "GraphEdit", 80 * scale); - theme->set_constant("bezier_len_neg", "GraphEdit", 160 * scale); // Visual Node Ports - theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 24 * scale); - theme->set_constant("port_grab_distance_vertical", "GraphEdit", 26 * scale); + theme->set_constant("port_hotzone_inner_extent", "GraphEdit", 22 * scale); + theme->set_constant("port_hotzone_outer_extent", "GraphEdit", 26 * scale); theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0)); Ref<StyleBoxFlat> style_minimap_camera = make_flat_stylebox(Color(0.65, 0.65, 0.65, 0.2), 0, 0, 0, 0, 0); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 8d515eca09..f6ffc8db53 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -1179,7 +1179,7 @@ void Environment::_bind_methods() { ADD_GROUP("Sky", "sky_"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_sky", "get_sky"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_custom_fov", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), "set_sky_custom_fov", "get_sky_custom_fov"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation"), "set_sky_rotation", "get_sky_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_sky_rotation", "get_sky_rotation"); // Ambient light @@ -1466,7 +1466,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_ambient_inject", PROPERTY_HINT_RANGE, "0.0,16,0.01,exp"), "set_volumetric_fog_ambient_inject", "get_volumetric_fog_ambient_inject"); ADD_SUBGROUP("Temporal Reprojection", "volumetric_fog_temporal_reprojection_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_temporal_reprojection_enabled"), "set_volumetric_fog_temporal_reprojection_enabled", "is_volumetric_fog_temporal_reprojection_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_temporal_reprojection_amount", PROPERTY_HINT_RANGE, "0.0,0.999,0.001"), "set_volumetric_fog_temporal_reprojection_amount", "get_volumetric_fog_temporal_reprojection_amount"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_temporal_reprojection_amount", PROPERTY_HINT_RANGE, "0.5,0.99,0.001"), "set_volumetric_fog_temporal_reprojection_amount", "get_volumetric_fog_temporal_reprojection_amount"); // Adjustment diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index ab1873ffe9..5c34c7cafa 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -161,32 +161,45 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { return triangle_mesh; } - int facecount = 0; + int faces_size = 0; for (int i = 0; i < get_surface_count(); i++) { - if (surface_get_primitive_type(i) != PRIMITIVE_TRIANGLES) { - continue; - } - - if (surface_get_format(i) & ARRAY_FORMAT_INDEX) { - facecount += surface_get_array_index_len(i); - } else { - facecount += surface_get_array_len(i); + switch (surface_get_primitive_type(i)) { + case PRIMITIVE_TRIANGLES: { + int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i); + // Don't error if zero, it's valid (we'll just skip it later). + ERR_CONTINUE_MSG((len % 3) != 0, vformat("Ignoring surface %d, incorrect %s count: %d (for PRIMITIVE_TRIANGLES).", i, (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? "index" : "vertex", len)); + faces_size += len; + } break; + case PRIMITIVE_TRIANGLE_STRIP: { + int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i); + // Don't error if zero, it's valid (we'll just skip it later). + ERR_CONTINUE_MSG(len != 0 && len < 3, vformat("Ignoring surface %d, incorrect %s count: %d (for PRIMITIVE_TRIANGLE_STRIP).", i, (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? "index" : "vertex", len)); + faces_size += (len == 0) ? 0 : (len - 2) * 3; + } break; + default: { + } break; } } - if (facecount == 0 || (facecount % 3) != 0) { + if (faces_size == 0) { return triangle_mesh; } Vector<Vector3> faces; - faces.resize(facecount); + faces.resize(faces_size); Vector3 *facesw = faces.ptrw(); int widx = 0; for (int i = 0; i < get_surface_count(); i++) { - if (surface_get_primitive_type(i) != PRIMITIVE_TRIANGLES) { + Mesh::PrimitiveType primitive = surface_get_primitive_type(i); + if (primitive != PRIMITIVE_TRIANGLES && primitive != PRIMITIVE_TRIANGLE_STRIP) { + 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)) { + // Error was already shown, just skip (including zero). continue; } @@ -202,14 +215,30 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { Vector<int> indices = a[ARRAY_INDEX]; const int *ir = indices.ptr(); - for (int j = 0; j < ic; j++) { - int index = ir[j]; - facesw[widx++] = vr[index]; + if (primitive == PRIMITIVE_TRIANGLES) { + for (int j = 0; j < ic; j++) { + int index = ir[j]; + facesw[widx++] = vr[index]; + } + } else { // PRIMITIVE_TRIANGLE_STRIP + for (int j = 2; j < ic; j++) { + facesw[widx++] = vr[ir[j - 2]]; + facesw[widx++] = vr[ir[j - 1]]; + facesw[widx++] = vr[ir[j]]; + } } } else { - for (int j = 0; j < vc; j++) { - facesw[widx++] = vr[j]; + if (primitive == PRIMITIVE_TRIANGLES) { + for (int j = 0; j < vc; j++) { + facesw[widx++] = vr[j]; + } + } else { // PRIMITIVE_TRIANGLE_STRIP + for (int j = 2; j < vc; j++) { + facesw[widx++] = vr[j - 2]; + facesw[widx++] = vr[j - 1]; + facesw[widx++] = vr[j]; + } } } } diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index 8353973fb9..7f5ce1eb6b 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -486,29 +486,36 @@ void NavigationMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type"); - 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(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(PropertyInfo(Variant::FLOAT, "cell/size", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater"), "set_cell_size", "get_cell_size"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell/height", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater"), "set_cell_height", "get_cell_height"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/height", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater"), "set_agent_height", "get_agent_height"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/radius", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater"), "set_agent_radius", "get_agent_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/max_climb", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater"), "set_agent_max_climb", "get_agent_max_climb"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent/max_slope", PROPERTY_HINT_RANGE, "0.02,90.0,0.01"), "set_agent_max_slope", "get_agent_max_slope"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region/min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_min_size", "get_region_min_size"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region/merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_merge_size", "get_region_merge_size"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge/max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater"), "set_edge_max_length", "get_edge_max_length"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge/max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater"), "set_edge_max_error", "get_edge_max_error"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "polygon/verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail/sample_distance", PROPERTY_HINT_RANGE, "0.1,16.0,0.01,or_greater"), "set_detail_sample_distance", "get_detail_sample_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail/sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_max_error", "get_detail_sample_max_error"); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter/filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans"); + ADD_GROUP("Sampling", "sample_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type"); + 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(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_GROUP("Cells", "cell_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater"), "set_cell_size", "get_cell_size"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_height", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater"), "set_cell_height", "get_cell_height"); + ADD_GROUP("Agents", "agent_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater"), "set_agent_height", "get_agent_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_radius", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater"), "set_agent_radius", "get_agent_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_max_climb", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater"), "set_agent_max_climb", "get_agent_max_climb"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_max_slope", PROPERTY_HINT_RANGE, "0.02,90.0,0.01"), "set_agent_max_slope", "get_agent_max_slope"); + ADD_GROUP("Regions", "region_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region_min_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_min_size", "get_region_min_size"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "region_merge_size", PROPERTY_HINT_RANGE, "0.0,150.0,0.01,or_greater"), "set_region_merge_size", "get_region_merge_size"); + ADD_GROUP("Edges", "edge_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_max_length", PROPERTY_HINT_RANGE, "0.0,50.0,0.01,or_greater"), "set_edge_max_length", "get_edge_max_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_max_error", PROPERTY_HINT_RANGE, "0.1,3.0,0.01,or_greater"), "set_edge_max_error", "get_edge_max_error"); + ADD_GROUP("Polygons", "polygon_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "polygon_verts_per_poly", PROPERTY_HINT_RANGE, "3.0,12.0,1.0,or_greater"), "set_verts_per_poly", "get_verts_per_poly"); + ADD_GROUP("Details", "detail_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_sample_distance", PROPERTY_HINT_RANGE, "0.1,16.0,0.01,or_greater"), "set_detail_sample_distance", "get_detail_sample_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "detail_sample_max_error", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater"), "set_detail_sample_max_error", "get_detail_sample_max_error"); + ADD_GROUP("Filters", "filter_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans"); BIND_ENUM_CONSTANT(SAMPLE_PARTITION_WATERSHED); BIND_ENUM_CONSTANT(SAMPLE_PARTITION_MONOTONE); @@ -542,4 +549,41 @@ void NavigationMesh::_validate_property(PropertyInfo &property) const { } } +#ifndef DISABLE_DEPRECATED +bool NavigationMesh::_set(const StringName &p_name, const Variant &p_value) { + String name = p_name; + if (name.find("/") != -1) { + // Compatibility with pre-3.5 "category/path" property names. + name = name.replace("/", "_"); + if (name == "sample_partition_type_sample_partition_type") { + set("sample_partition_type", p_value); + } else if (name == "filter_filter_walkable_low_height_spans") { + set("filter_walkable_low_height_spans", p_value); + } else { + set(name, p_value); + } + + return true; + } + return false; +} + +bool NavigationMesh::_get(const StringName &p_name, Variant &r_ret) const { + String name = p_name; + if (name.find("/") != -1) { + // Compatibility with pre-3.5 "category/path" property names. + name = name.replace("/", "_"); + if (name == "sample_partition_type_sample_partition_type") { + r_ret = get("sample_partition_type"); + } else if (name == "filter_filter_walkable_low_height_spans") { + r_ret = get("filter_walkable_low_height_spans"); + } else { + r_ret = get(name); + } + return true; + } + return false; +} +#endif // DISABLE_DEPRECATED + NavigationMesh::NavigationMesh() {} diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h index 449e6f2dff..93c1c11876 100644 --- a/scene/resources/navigation_mesh.h +++ b/scene/resources/navigation_mesh.h @@ -62,6 +62,11 @@ protected: static void _bind_methods(); virtual void _validate_property(PropertyInfo &property) const override; +#ifndef DISABLE_DEPRECATED + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; +#endif // DISABLE_DEPRECATED + void _set_polygons(const Array &p_array); Array _get_polygons() const; diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index f3cb2b9ea7..b54bbc1478 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -122,7 +122,7 @@ void StyleBox::_bind_methods() { ClassDB::bind_method(D_METHOD("draw", "canvas_item", "rect"), &StyleBox::draw); - ADD_GROUP("Content Margin", "content_margin_"); + ADD_GROUP("Content Margins", "content_margin_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_LEFT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_TOP); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_RIGHT); @@ -315,15 +315,14 @@ void StyleBoxTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("get_v_axis_stretch_mode"), &StyleBoxTexture::get_v_axis_stretch_mode); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); - ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); - ADD_GROUP("Margin", "margin_"); + ADD_GROUP("Margins", "margin_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_LEFT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_TOP); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_RIGHT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_BOTTOM); - ADD_GROUP("Expand Margin", "expand_margin_"); + ADD_GROUP("Expand Margins", "expand_margin_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_LEFT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_TOP); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT); @@ -333,6 +332,9 @@ void StyleBoxTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode"); + ADD_GROUP("Sub-Region", "region_"); + ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); + ADD_GROUP("Modulate", "modulate_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate_color"), "set_modulate", "get_modulate"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled"); @@ -921,7 +923,7 @@ void StyleBoxFlat::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "corner_detail", PROPERTY_HINT_RANGE, "1,20,1"), "set_corner_detail", "get_corner_detail"); - ADD_GROUP("Expand Margin", "expand_margin_"); + ADD_GROUP("Expand Margins", "expand_margin_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_LEFT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_TOP); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 9442a58ac1..8994bb5983 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -150,33 +150,21 @@ void ImageTexture::reload_from_file() { bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) { if (p_name == "image") { create_from_image(p_value); - } else if (p_name == "size") { - Size2 s = p_value; - w = s.width; - h = s.height; - RenderingServer::get_singleton()->texture_set_size_override(texture, w, h); - } else { - return false; + return true; } - - return true; + return false; } bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const { if (p_name == "image") { r_ret = get_image(); - } else if (p_name == "size") { - r_ret = Size2(w, h); - } else { - return false; + return true; } - - return true; + return false; } void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("image"), PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT)); - p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("size"), PROPERTY_HINT_NONE, "")); + p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("image"), PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT)); } void ImageTexture::create_from_image(const Ref<Image> &p_image) { @@ -2161,7 +2149,7 @@ void GradientTexture1D::_bind_methods() { ClassDB::bind_method(D_METHOD("_update"), &GradientTexture1D::_update); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,16384"), "set_width", "get_width"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr"); } @@ -2249,7 +2237,7 @@ void GradientTexture1D::_update() { } void GradientTexture1D::set_width(int p_width) { - ERR_FAIL_COND(p_width <= 0); + ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range."); width = p_width; _queue_update(); } @@ -2413,6 +2401,7 @@ float GradientTexture2D::_get_gradient_offset_at(int x, int y) const { } void GradientTexture2D::set_width(int p_width) { + ERR_FAIL_COND_MSG(p_width <= 0 || p_width > 16384, "Texture dimensions have to be within 1 to 16384 range."); width = p_width; _queue_update(); } @@ -2422,6 +2411,7 @@ int GradientTexture2D::get_width() const { } void GradientTexture2D::set_height(int p_height) { + ERR_FAIL_COND_MSG(p_height <= 0 || p_height > 16384, "Texture dimensions have to be within 1 to 16384 range."); height = p_height; _queue_update(); } @@ -2515,8 +2505,8 @@ void GradientTexture2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_update"), &GradientTexture2D::_update); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_gradient", "get_gradient"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048"), "set_width", "get_width"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,or_greater"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,or_greater"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr"); ADD_GROUP("Fill", "fill_"); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 1b1107d79e..9d2d4cdb20 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -281,7 +281,7 @@ void TileSet::TerrainsPattern::set_terrains_from_array(Array p_terrains) { int in_array_index = 0; for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { if (is_valid_bit[i]) { - ERR_FAIL_COND(in_array_index >= p_terrains.size()); + ERR_FAIL_INDEX(in_array_index, p_terrains.size()); set_terrain(TileSet::CellNeighbor(i), p_terrains[in_array_index]); in_array_index++; } diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 5c0f36ca92..b8667f07fe 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -2462,7 +2462,7 @@ void VisualShaderNodeFloatFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeFloatFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeFloatFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Fract,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_SIN); BIND_ENUM_CONSTANT(FUNC_COS); @@ -2481,7 +2481,7 @@ void VisualShaderNodeFloatFunc::_bind_methods() { BIND_ENUM_CONSTANT(FUNC_FLOOR); BIND_ENUM_CONSTANT(FUNC_ROUND); BIND_ENUM_CONSTANT(FUNC_CEIL); - BIND_ENUM_CONSTANT(FUNC_FRAC); + BIND_ENUM_CONSTANT(FUNC_FRACT); BIND_ENUM_CONSTANT(FUNC_SATURATE); BIND_ENUM_CONSTANT(FUNC_NEGATE); BIND_ENUM_CONSTANT(FUNC_ACOSH); @@ -2713,7 +2713,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Fract,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_NORMALIZE); BIND_ENUM_CONSTANT(FUNC_SATURATE); @@ -2733,7 +2733,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() { BIND_ENUM_CONSTANT(FUNC_EXP); BIND_ENUM_CONSTANT(FUNC_EXP2); BIND_ENUM_CONSTANT(FUNC_FLOOR); - BIND_ENUM_CONSTANT(FUNC_FRAC); + BIND_ENUM_CONSTANT(FUNC_FRACT); BIND_ENUM_CONSTANT(FUNC_INVERSE_SQRT); BIND_ENUM_CONSTANT(FUNC_LOG); BIND_ENUM_CONSTANT(FUNC_LOG2); diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index b159d25eba..1eb7b7240f 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -934,7 +934,7 @@ public: FUNC_FLOOR, FUNC_ROUND, FUNC_CEIL, - FUNC_FRAC, + FUNC_FRACT, FUNC_SATURATE, FUNC_NEGATE, FUNC_ACOSH, @@ -1053,7 +1053,7 @@ public: FUNC_EXP, FUNC_EXP2, FUNC_FLOOR, - FUNC_FRAC, + FUNC_FRACT, FUNC_INVERSE_SQRT, FUNC_LOG, FUNC_LOG2, diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp index 0088236112..eb0af63975 100644 --- a/scene/resources/world_3d.cpp +++ b/scene/resources/world_3d.cpp @@ -150,8 +150,8 @@ World3D::World3D() { navigation_map = NavigationServer3D::get_singleton()->map_create(); NavigationServer3D::get_singleton()->map_set_active(navigation_map, true); - NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.3)); - NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.3)); + NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.25)); + NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.25)); } World3D::~World3D() { |