diff options
Diffstat (limited to 'scene')
33 files changed, 333 insertions, 304 deletions
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index 1fe6a4a4b8..67e35cc7a3 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -100,6 +100,10 @@ void ParallaxLayer::_notification(int p_what) { _update_mirroring(); } break; case NOTIFICATION_EXIT_TREE: { + if (Engine::get_singleton()->is_editor_hint()) { + break; + } + set_position(orig_offset); set_scale(orig_scale); } break; diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 30f012c7aa..1b6dec1119 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1306,11 +1306,7 @@ void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResu void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_result) { platform_rid = p_result.collider; platform_velocity = p_result.collider_velocity; - platform_layer = 0; - CollisionObject2D *collision_object = Object::cast_to<CollisionObject2D>(ObjectDB::get_instance(p_result.collider_id)); - if (collision_object) { - platform_layer = collision_object->get_collision_layer(); - } + platform_layer = PhysicsServer2D::get_singleton()->body_get_collision_layer(platform_rid); } const Vector2 &CharacterBody2D::get_linear_velocity() const { diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 0eb424b32c..a139a92ab4 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -261,6 +261,7 @@ void TileMap::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { pending_update = true; + _clear_internals(); _recreate_internals(); } break; case NOTIFICATION_EXIT_TREE: { @@ -298,6 +299,7 @@ void TileMap::set_tileset(const Ref<TileSet> &p_tileset) { if (tile_set.is_valid()) { tile_set->connect("changed", callable_mp(this, &TileMap::_tile_set_changed)); + _clear_internals(); _recreate_internals(); } @@ -308,6 +310,7 @@ void TileMap::set_quadrant_size(int p_size) { ERR_FAIL_COND_MSG(p_size < 1, "TileMapQuadrant size cannot be smaller than 1."); quadrant_size = p_size; + _clear_internals(); _recreate_internals(); emit_signal(SNAME("changed")); } @@ -327,6 +330,9 @@ void TileMap::add_layer(int p_to_pos) { ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1); + // Must clear before adding the layer. + _clear_internals(); + layers.insert(p_to_pos, TileMapLayer()); _recreate_internals(); notify_property_list_changed(); @@ -340,6 +346,9 @@ void TileMap::move_layer(int p_layer, int p_to_pos) { ERR_FAIL_INDEX(p_layer, (int)layers.size()); ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1); + // Clear before shuffling layers. + _clear_internals(); + TileMapLayer tl = layers[p_layer]; layers.insert(p_to_pos, tl); layers.remove(p_to_pos < p_layer ? p_layer + 1 : p_layer); @@ -358,6 +367,9 @@ void TileMap::move_layer(int p_layer, int p_to_pos) { void TileMap::remove_layer(int p_layer) { ERR_FAIL_INDEX(p_layer, (int)layers.size()); + // Clear before removing the layer. + _clear_internals(); + layers.remove(p_layer); _recreate_internals(); notify_property_list_changed(); @@ -385,6 +397,7 @@ String TileMap::get_layer_name(int p_layer) const { void TileMap::set_layer_enabled(int p_layer, bool p_enabled) { ERR_FAIL_INDEX(p_layer, (int)layers.size()); layers[p_layer].enabled = p_enabled; + _clear_internals(); _recreate_internals(); emit_signal(SNAME("changed")); @@ -399,6 +412,7 @@ bool TileMap::is_layer_enabled(int p_layer) const { void TileMap::set_layer_y_sort_enabled(int p_layer, bool p_y_sort_enabled) { ERR_FAIL_INDEX(p_layer, (int)layers.size()); layers[p_layer].y_sort_enabled = p_y_sort_enabled; + _clear_internals(); _recreate_internals(); emit_signal(SNAME("changed")); @@ -413,6 +427,7 @@ bool TileMap::is_layer_y_sort_enabled(int p_layer) const { void TileMap::set_layer_y_sort_origin(int p_layer, int p_y_sort_origin) { ERR_FAIL_INDEX(p_layer, (int)layers.size()); layers[p_layer].y_sort_origin = p_y_sort_origin; + _clear_internals(); _recreate_internals(); emit_signal(SNAME("changed")); } @@ -425,6 +440,7 @@ int TileMap::get_layer_y_sort_origin(int p_layer) const { void TileMap::set_layer_z_index(int p_layer, int p_z_index) { ERR_FAIL_INDEX(p_layer, (int)layers.size()); layers[p_layer].z_index = p_z_index; + _clear_internals(); _recreate_internals(); emit_signal(SNAME("changed")); @@ -438,6 +454,7 @@ int TileMap::get_layer_z_index(int p_layer) const { void TileMap::set_collision_visibility_mode(TileMap::VisibilityMode p_show_collision) { collision_visibility_mode = p_show_collision; + _clear_internals(); _recreate_internals(); emit_signal(SNAME("changed")); } @@ -448,6 +465,7 @@ TileMap::VisibilityMode TileMap::get_collision_visibility_mode() { void TileMap::set_navigation_visibility_mode(TileMap::VisibilityMode p_show_navigation) { navigation_visibility_mode = p_show_navigation; + _clear_internals(); _recreate_internals(); emit_signal(SNAME("changed")); } @@ -458,6 +476,7 @@ TileMap::VisibilityMode TileMap::get_navigation_visibility_mode() { void TileMap::set_y_sort_enabled(bool p_enable) { Node2D::set_y_sort_enabled(p_enable); + _clear_internals(); _recreate_internals(); emit_signal(SNAME("changed")); } @@ -578,10 +597,10 @@ void TileMap::_update_dirty_quadrants() { } void TileMap::_recreate_internals() { - // Clear all internals. - _clear_internals(); - for (unsigned int layer = 0; layer < layers.size(); layer++) { + // Make sure that _clear_internals() was called prior. + ERR_FAIL_COND_MSG(layers[layer].quadrant_map.size() > 0, "TileMap layer " + itos(layer) + " had a non-empty quadrant map."); + if (!layers[layer].enabled) { continue; } @@ -2857,50 +2876,57 @@ void TileMap::draw_cells_outline(Control *p_control, Set<Vector2i> p_cells, Colo // Create a set. Vector2i tile_size = tile_set->get_tile_size(); - Vector<Vector2> uvs; + Vector<Vector2> polygon = tile_set->get_tile_shape_polygon(); + TileSet::TileShape shape = tile_set->get_tile_shape(); - if (tile_set->get_tile_shape() == TileSet::TILE_SHAPE_SQUARE) { - uvs.append(Vector2(1.0, 0.0)); - uvs.append(Vector2(1.0, 1.0)); - uvs.append(Vector2(0.0, 1.0)); - uvs.append(Vector2(0.0, 0.0)); - } else { - float overlap = 0.0; - switch (tile_set->get_tile_shape()) { - case TileSet::TILE_SHAPE_ISOMETRIC: - overlap = 0.5; - break; - case TileSet::TILE_SHAPE_HEXAGON: - overlap = 0.25; - break; - case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE: - overlap = 0.0; - break; - default: - break; - } - uvs.append(Vector2(1.0, overlap)); - uvs.append(Vector2(1.0, 1.0 - overlap)); - uvs.append(Vector2(0.5, 1.0)); - uvs.append(Vector2(0.0, 1.0 - overlap)); - uvs.append(Vector2(0.0, overlap)); - uvs.append(Vector2(0.5, 0.0)); - if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) { - for (int i = 0; i < uvs.size(); i++) { - uvs.write[i] = Vector2(uvs[i].y, uvs[i].x); - } - } + for (Set<Vector2i>::Element *E = p_cells.front(); E; E = E->next()) { + Vector2 center = map_to_world(E->get()); + +#define DRAW_SIDE_IF_NEEDED(side, polygon_index_from, polygon_index_to) \ + if (!p_cells.has(get_neighbor_cell(E->get(), side))) { \ + Vector2 from = p_transform.xform(center + polygon[polygon_index_from] * tile_size); \ + Vector2 to = p_transform.xform(center + polygon[polygon_index_to] * tile_size); \ + p_control->draw_line(from, to, p_color); \ } - for (Set<Vector2i>::Element *E = p_cells.front(); E; E = E->next()) { - Vector2 top_left = map_to_world(E->get()) - tile_size / 2; - TypedArray<Vector2i> surrounding_tiles = get_surrounding_tiles(E->get()); - for (int i = 0; i < surrounding_tiles.size(); i++) { - if (!p_cells.has(surrounding_tiles[i])) { - p_control->draw_line(p_transform.xform(top_left + uvs[i] * tile_size), p_transform.xform(top_left + uvs[(i + 1) % uvs.size()] * tile_size), p_color); + if (shape == TileSet::TILE_SHAPE_SQUARE) { + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 1, 2); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 2, 3); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 3, 0); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 0, 1); + } else { + if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0); + } else { + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 1, 2); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 4, 5); + } + } else { + if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3); + } else { + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 4, 5); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 1, 2); + DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3); + } } } } +#undef DRAW_SIDE_IF_NEEDED } TypedArray<String> TileMap::get_configuration_warnings() const { @@ -2993,6 +3019,7 @@ void TileMap::_bind_methods() { void TileMap::_tile_set_changed() { emit_signal(SNAME("changed")); + _clear_internals(); _recreate_internals(); } diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 3ada9072c2..9aad338d15 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -254,10 +254,6 @@ bool Camera3D::is_current() const { } } -bool Camera3D::_can_gizmo_scale() const { - return false; -} - Vector3 Camera3D::project_ray_normal(const Point2 &p_pos) const { Vector3 ray = project_local_ray_normal(p_pos); return get_camera_transform().basis.xform(ray).normalized(); diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index 3b704944b0..c1af7fa4f7 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -79,8 +79,6 @@ private: Ref<Environment> environment; Ref<CameraEffects> effects; - virtual bool _can_gizmo_scale() const; - // void _camera_make_current(Node *p_camera); friend class Viewport; void _update_audio_listener_state(); diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index ab417fafdd..c787ba5087 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -30,10 +30,6 @@ #include "light_3d.h" -bool Light3D::_can_gizmo_scale() const { - return false; -} - void Light3D::set_param(Param p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); param[p_param] = p_value; diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index ecea60339f..f788c323f7 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -86,8 +86,6 @@ private: protected: RID light; - virtual bool _can_gizmo_scale() const; - static void _bind_methods(); void _notification(int p_what); virtual void _validate_property(PropertyInfo &property) const override; diff --git a/scene/3d/listener_3d.cpp b/scene/3d/listener_3d.cpp index 1c52933ee5..8ae1f1940f 100644 --- a/scene/3d/listener_3d.cpp +++ b/scene/3d/listener_3d.cpp @@ -141,16 +141,6 @@ bool Listener3D::is_current() const { return false; } -bool Listener3D::_can_gizmo_scale() const { - return false; -} - -RES Listener3D::_get_gizmo_geometry() const { - Ref<ArrayMesh> mesh = memnew(ArrayMesh); - - return mesh; -} - void Listener3D::_bind_methods() { ClassDB::bind_method(D_METHOD("make_current"), &Listener3D::make_current); ClassDB::bind_method(D_METHOD("clear_current"), &Listener3D::clear_current); @@ -160,7 +150,6 @@ void Listener3D::_bind_methods() { Listener3D::Listener3D() { set_notify_transform(true); - //active=false; } Listener3D::~Listener3D() { diff --git a/scene/3d/listener_3d.h b/scene/3d/listener_3d.h index 25eacf5135..08c08aa0cb 100644 --- a/scene/3d/listener_3d.h +++ b/scene/3d/listener_3d.h @@ -42,9 +42,6 @@ private: RID scenario_id; - virtual bool _can_gizmo_scale() const; - virtual RES _get_gizmo_geometry() const; - friend class Viewport; void _update_audio_listener_state(); diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index de6925244a..7e7db57af3 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -274,7 +274,8 @@ Node *MeshInstance3D::create_multiple_convex_collisions_node() { return nullptr; } - Vector<Ref<Shape3D>> shapes = mesh->convex_decompose(); + Mesh::ConvexDecompositionSettings settings; + Vector<Ref<Shape3D>> shapes = mesh->convex_decompose(settings); if (!shapes.size()) { return nullptr; } diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp index a891566633..466f67afb8 100644 --- a/scene/3d/skeleton_ik_3d.cpp +++ b/scene/3d/skeleton_ik_3d.cpp @@ -542,7 +542,7 @@ Transform3D SkeletonIK3D::_get_target_transform() { target_node_override = Object::cast_to<Node3D>(get_node(target_node_path_override)); } - if (target_node_override) { + if (target_node_override && target_node_override->is_inside_tree()) { return target_node_override->get_global_transform(); } else { return target; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index f6091f224c..5825a35030 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -737,7 +737,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double if (anim->has_loop()) { at_anim_pos = Math::fposmod(p_time - pos, (double)anim->get_length()); //seek to loop } else { - at_anim_pos = MAX((double)anim->get_length(), p_time - pos); //seek to end + at_anim_pos = MIN((double)anim->get_length(), p_time - pos); //seek to end } if (player->is_playing() || p_seeked) { @@ -765,6 +765,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } } else { player->play(anim_name); + player->seek(0.0, true); nc->animation_playing = true; playing_caches.insert(nc); } diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 542011618d..2847031375 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -36,6 +36,10 @@ void Tweener::set_tween(Ref<Tween> p_tween) { tween = p_tween; } +void Tweener::clear_tween() { + tween.unref(); +} + void Tweener::_bind_methods() { ADD_SIGNAL(MethodInfo("finished")); } @@ -53,16 +57,21 @@ void Tween::start_tweeners() { Ref<PropertyTweener> Tween::tween_property(Object *p_target, NodePath p_property, Variant p_to, float p_duration) { ERR_FAIL_NULL_V(p_target, nullptr); - ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners."); + ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree."); ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); +#ifdef DEBUG_ENABLED + Variant::Type property_type = p_target->get_indexed(p_property.get_as_property_path().get_subnames()).get_type(); + ERR_FAIL_COND_V_MSG(property_type != p_to.get_type(), Ref<PropertyTweener>(), "Type mismatch between property and final value: " + Variant::get_type_name(property_type) + " and " + Variant::get_type_name(p_to.get_type())); +#endif + Ref<PropertyTweener> tweener = memnew(PropertyTweener(p_target, p_property, p_to, p_duration)); append(tweener); return tweener; } Ref<IntervalTweener> Tween::tween_interval(float p_time) { - ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners."); + ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree."); ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); Ref<IntervalTweener> tweener = memnew(IntervalTweener(p_time)); @@ -71,7 +80,7 @@ Ref<IntervalTweener> Tween::tween_interval(float p_time) { } Ref<CallbackTweener> Tween::tween_callback(Callable p_callback) { - ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners."); + ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree."); ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); Ref<CallbackTweener> tweener = memnew(CallbackTweener(p_callback)); @@ -79,8 +88,8 @@ Ref<CallbackTweener> Tween::tween_callback(Callable p_callback) { return tweener; } -Ref<MethodTweener> Tween::tween_method(Callable p_callback, float p_from, float p_to, float p_duration) { - ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners."); +Ref<MethodTweener> Tween::tween_method(Callable p_callback, Variant p_from, Variant p_to, float p_duration) { + ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree."); ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); Ref<MethodTweener> tweener = memnew(MethodTweener(p_callback, p_from, p_to, p_duration)); @@ -88,9 +97,7 @@ Ref<MethodTweener> Tween::tween_method(Callable p_callback, float p_from, float return tweener; } -Ref<Tween> Tween::append(Ref<Tweener> p_tweener) { - ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners."); - ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); +void Tween::append(Ref<Tweener> p_tweener) { p_tweener->set_tween(this); if (parallel_enabled) { @@ -102,8 +109,6 @@ Ref<Tween> Tween::append(Ref<Tweener> p_tweener) { tweeners.resize(current_step + 1); tweeners.write[current_step].push_back(p_tweener); - - return this; } void Tween::stop() { @@ -117,7 +122,7 @@ void Tween::pause() { } void Tween::play() { - ERR_FAIL_COND_MSG(invalid, "Tween invalid, can't play."); + ERR_FAIL_COND_MSG(!valid, "Tween invalid. Either finished or created outside scene tree."); ERR_FAIL_COND_MSG(dead, "Can't play finished Tween, use stop() first to reset its state."); running = true; } @@ -132,11 +137,22 @@ bool Tween::is_running() { } void Tween::set_valid(bool p_valid) { - invalid = !p_valid; + valid = p_valid; } bool Tween::is_valid() { - return invalid; + return valid; +} + +void Tween::clear() { + valid = false; + + for (List<Ref<Tweener>> &step : tweeners) { + for (Ref<Tweener> &tweener : step) { + tweener->clear_tween(); + } + } + tweeners.clear(); } Ref<Tween> Tween::bind_node(Node *p_node) { @@ -485,6 +501,8 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, f } Variant Tween::calculate_delta_value(Variant p_intial_val, Variant p_final_val) { + ERR_FAIL_COND_V_MSG(p_intial_val.get_type() != p_final_val.get_type(), p_intial_val, "Type mismatch between initial and final value: " + Variant::get_type_name(p_intial_val.get_type()) + " and " + Variant::get_type_name(p_final_val.get_type())); + switch (p_intial_val.get_type()) { case Variant::BOOL: { return (int)p_final_val - (int)p_intial_val; @@ -877,7 +895,7 @@ void MethodTweener::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ease", "ease"), &MethodTweener::set_ease); } -MethodTweener::MethodTweener(Callable p_callback, float p_from, float p_to, float p_duration) { +MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration) { callback = p_callback; initial_val = p_from; delta_val = tween->calculate_delta_value(p_from, p_to); diff --git a/scene/animation/tween.h b/scene/animation/tween.h index 947cdb7c2d..6a48d332b8 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -43,6 +43,7 @@ public: virtual void set_tween(Ref<Tween> p_tween); virtual void start() = 0; virtual bool step(float &r_delta) = 0; + void clear_tween(); protected: static void _bind_methods(); @@ -111,7 +112,7 @@ private: bool started = false; bool running = true; bool dead = false; - bool invalid = true; + bool valid = false; bool default_parallel = false; bool parallel_enabled = false; @@ -127,8 +128,8 @@ public: Ref<PropertyTweener> tween_property(Object *p_target, NodePath p_property, Variant p_to, float p_duration); Ref<IntervalTweener> tween_interval(float p_time); Ref<CallbackTweener> tween_callback(Callable p_callback); - Ref<MethodTweener> tween_method(Callable p_callback, float p_from, float p_to, float p_duration); - Ref<Tween> append(Ref<Tweener> p_tweener); + Ref<MethodTweener> tween_method(Callable p_callback, Variant p_from, Variant p_to, float p_duration); + void append(Ref<Tweener> p_tweener); bool custom_step(float p_delta); void stop(); @@ -139,6 +140,7 @@ public: bool is_running(); void set_valid(bool p_valid); bool is_valid(); + void clear(); Ref<Tween> bind_node(Node *p_node); Ref<Tween> set_process_mode(TweenProcessMode p_mode); @@ -256,7 +258,7 @@ public: void start() override; bool step(float &r_delta) override; - MethodTweener(Callable p_callback, float p_from, float p_to, float p_duration); + MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration); MethodTweener(); protected: diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 3beff57027..e7769f9372 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -2034,7 +2034,9 @@ String CodeEdit::get_text_for_symbol_lookup() { void CodeEdit::set_symbol_lookup_word_as_valid(bool p_valid) { symbol_lookup_word = p_valid ? symbol_lookup_new_word : ""; symbol_lookup_new_word = ""; - _set_symbol_lookup_word(symbol_lookup_word); + if (lookup_symbol_word != symbol_lookup_word) { + _set_symbol_lookup_word(symbol_lookup_word); + } } void CodeEdit::_bind_methods() { diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index cabae9feb2..b9b02b1427 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -356,16 +356,6 @@ void GraphEdit::_graph_node_raised(Node *p_gn) { } else { gn->raise(); } - int first_not_comment = 0; - for (int i = 0; i < get_child_count(); i++) { - GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i)); - if (gn2 && !gn2->is_comment()) { - first_not_comment = i; - break; - } - } - - move_child(connections_layer, first_not_comment); emit_signal(SNAME("node_selected"), p_gn); } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index aeadfd78ee..562bac60c2 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -366,7 +366,7 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> } if (p_line > 0) { - l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y; + l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y + get_theme_constant(SNAME("line_separation")); } else { l.offset.y = 0; } @@ -614,7 +614,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> *r_char_offset = l.char_offset + l.char_count; if (p_line > 0) { - l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y; + l.offset.y = p_frame->lines[p_line - 1].offset.y + p_frame->lines[p_line - 1].text_buf->get_size().y + get_theme_constant(SNAME("line_separation")); } else { l.offset.y = 0; } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 6bcbedfceb..06dfc31621 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2731,6 +2731,8 @@ void TextEdit::insert_line_at(int p_at, const String &p_text) { } void TextEdit::insert_text_at_caret(const String &p_text) { + begin_complex_operation(); + delete_selection(); int new_column, new_line; @@ -2740,6 +2742,8 @@ void TextEdit::insert_text_at_caret(const String &p_text) { set_caret_line(new_line, false); set_caret_column(new_column); update(); + + end_complex_operation(); } void TextEdit::remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) { @@ -3024,13 +3028,20 @@ void TextEdit::menu_option(int p_option) { /* Versioning */ void TextEdit::begin_complex_operation() { _push_current_op(); - next_operation_is_complex = true; + if (complex_operation_count == 0) { + next_operation_is_complex = true; + } + complex_operation_count++; } void TextEdit::end_complex_operation() { _push_current_op(); ERR_FAIL_COND(undo_stack.size() == 0); + complex_operation_count = MAX(complex_operation_count - 1, 0); + if (complex_operation_count > 0) { + return; + } if (undo_stack.back()->get().chain_forward) { undo_stack.back()->get().chain_forward = false; return; diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 525464c302..b1226f2aff 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -304,6 +304,7 @@ private: bool undo_enabled = true; int undo_stack_max_size = 50; + int complex_operation_count = 0; bool next_operation_is_complex = false; TextOperation current_op; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index c4dfbc0d4e..f62c09925d 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -156,6 +156,7 @@ void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) { c.dirty = true; c.icon_max_w = 0; _changed_notify(p_column); + cached_minimum_size_dirty = true; } TreeItem::TreeCellMode TreeItem::get_cell_mode(int p_column) const { @@ -169,6 +170,7 @@ void TreeItem::set_checked(int p_column, bool p_checked) { cells.write[p_column].checked = p_checked; cells.write[p_column].indeterminate = false; _changed_notify(p_column); + cached_minimum_size_dirty = true; } void TreeItem::set_indeterminate(int p_column, bool p_indeterminate) { @@ -180,6 +182,7 @@ void TreeItem::set_indeterminate(int p_column, bool p_indeterminate) { cells.write[p_column].indeterminate = p_indeterminate; cells.write[p_column].checked = false; _changed_notify(p_column); + cached_minimum_size_dirty = true; } bool TreeItem::is_checked(int p_column) const { @@ -212,6 +215,7 @@ void TreeItem::set_text(int p_column, String p_text) { cells.write[p_column].step = 0; } _changed_notify(p_column); + cached_minimum_size_dirty = true; } String TreeItem::get_text(int p_column) const { @@ -227,6 +231,7 @@ void TreeItem::set_text_direction(int p_column, Control::TextDirection p_text_di cells.write[p_column].dirty = true; _changed_notify(p_column); } + cached_minimum_size_dirty = true; } Control::TextDirection TreeItem::get_text_direction(int p_column) const { @@ -239,6 +244,7 @@ void TreeItem::clear_opentype_features(int p_column) { cells.write[p_column].opentype_features.clear(); cells.write[p_column].dirty = true; _changed_notify(p_column); + cached_minimum_size_dirty = true; } void TreeItem::set_opentype_feature(int p_column, const String &p_name, int p_value) { @@ -248,6 +254,7 @@ void TreeItem::set_opentype_feature(int p_column, const String &p_name, int p_va cells.write[p_column].opentype_features[tag] = p_value; cells.write[p_column].dirty = true; _changed_notify(p_column); + cached_minimum_size_dirty = true; } } @@ -266,6 +273,7 @@ void TreeItem::set_structured_text_bidi_override(int p_column, Control::Structur cells.write[p_column].st_parser = p_parser; cells.write[p_column].dirty = true; _changed_notify(p_column); + cached_minimum_size_dirty = true; } } @@ -279,6 +287,7 @@ void TreeItem::set_structured_text_bidi_override_options(int p_column, Array p_a cells.write[p_column].st_args = p_args; cells.write[p_column].dirty = true; _changed_notify(p_column); + cached_minimum_size_dirty = true; } Array TreeItem::get_structured_text_bidi_override_options(int p_column) const { @@ -292,6 +301,7 @@ void TreeItem::set_language(int p_column, const String &p_language) { cells.write[p_column].language = p_language; cells.write[p_column].dirty = true; _changed_notify(p_column); + cached_minimum_size_dirty = true; } } @@ -305,6 +315,7 @@ void TreeItem::set_suffix(int p_column, String p_suffix) { cells.write[p_column].suffix = p_suffix; _changed_notify(p_column); + cached_minimum_size_dirty = true; } String TreeItem::get_suffix(int p_column) const { @@ -316,6 +327,7 @@ void TreeItem::set_icon(int p_column, const Ref<Texture2D> &p_icon) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].icon = p_icon; _changed_notify(p_column); + cached_minimum_size_dirty = true; } Ref<Texture2D> TreeItem::get_icon(int p_column) const { @@ -327,6 +339,7 @@ void TreeItem::set_icon_region(int p_column, const Rect2 &p_icon_region) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].icon_region = p_icon_region; _changed_notify(p_column); + cached_minimum_size_dirty = true; } Rect2 TreeItem::get_icon_region(int p_column) const { @@ -349,6 +362,7 @@ void TreeItem::set_icon_max_width(int p_column, int p_max) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].icon_max_w = p_max; _changed_notify(p_column); + cached_minimum_size_dirty = true; } int TreeItem::get_icon_max_width(int p_column) const { @@ -461,6 +475,7 @@ void TreeItem::uncollapse_tree() { void TreeItem::set_custom_minimum_height(int p_height) { custom_min_height = p_height; _changed_notify(); + cached_minimum_size_dirty = true; } int TreeItem::get_custom_minimum_height() const { @@ -785,6 +800,7 @@ void TreeItem::add_button(int p_column, const Ref<Texture2D> &p_button, int p_id button.tooltip = p_tooltip; cells.write[p_column].buttons.push_back(button); _changed_notify(p_column); + cached_minimum_size_dirty = true; } int TreeItem::get_button_count(int p_column) const { @@ -828,6 +844,7 @@ void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture2D> &p_butto ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size()); cells.write[p_column].buttons.write[p_idx].texture = p_button; _changed_notify(p_column); + cached_minimum_size_dirty = true; } void TreeItem::set_button_color(int p_column, int p_idx, const Color &p_color) { @@ -843,6 +860,7 @@ void TreeItem::set_button_disabled(int p_column, int p_idx, bool p_disabled) { cells.write[p_column].buttons.write[p_idx].disabled = p_disabled; _changed_notify(p_column); + cached_minimum_size_dirty = true; } bool TreeItem::is_button_disabled(int p_column, int p_idx) const { @@ -856,6 +874,7 @@ void TreeItem::set_editable(int p_column, bool p_editable) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].editable = p_editable; _changed_notify(p_column); + cached_minimum_size_dirty = true; } bool TreeItem::is_editable(int p_column) { @@ -888,6 +907,7 @@ void TreeItem::clear_custom_color(int p_column) { void TreeItem::set_custom_font(int p_column, const Ref<Font> &p_font) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].custom_font = p_font; + cached_minimum_size_dirty = true; } Ref<Font> TreeItem::get_custom_font(int p_column) const { @@ -898,6 +918,7 @@ Ref<Font> TreeItem::get_custom_font(int p_column) const { void TreeItem::set_custom_font_size(int p_column, int p_font_size) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].custom_font_size = p_font_size; + cached_minimum_size_dirty = true; } int TreeItem::get_custom_font_size(int p_column) const { @@ -941,6 +962,7 @@ Color TreeItem::get_custom_bg_color(int p_column) const { void TreeItem::set_custom_as_button(int p_column, bool p_button) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].custom_button = p_button; + cached_minimum_size_dirty = true; } bool TreeItem::is_custom_set_as_button(int p_column) const { @@ -952,6 +974,7 @@ void TreeItem::set_text_align(int p_column, TextAlign p_align) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].text_align = p_align; _changed_notify(p_column); + cached_minimum_size_dirty = true; } TreeItem::TextAlign TreeItem::get_text_align(int p_column) const { @@ -963,6 +986,7 @@ void TreeItem::set_expand_right(int p_column, bool p_enable) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].expand_right = p_enable; _changed_notify(p_column); + cached_minimum_size_dirty = true; } bool TreeItem::get_expand_right(int p_column) const { @@ -973,6 +997,7 @@ bool TreeItem::get_expand_right(int p_column) const { void TreeItem::set_disable_folding(bool p_disable) { disable_folding = p_disable; _changed_notify(0); + cached_minimum_size_dirty = true; } bool TreeItem::is_folding_disabled() const { @@ -984,49 +1009,54 @@ Size2 TreeItem::get_minimum_size(int p_column) { Tree *tree = get_tree(); ERR_FAIL_COND_V(!tree, Size2()); - Size2 size; + if (cached_minimum_size_dirty) { + Size2 size; - // Default offset? - //size.width += (disable_folding || tree->hide_folding) ? tree->cache.hseparation : tree->cache.item_margin; + // Default offset? + //size.width += (disable_folding || tree->hide_folding) ? tree->cache.hseparation : tree->cache.item_margin; - // Text. - const TreeItem::Cell &cell = cells[p_column]; - if (!cell.text.is_empty()) { - if (cell.dirty) { - tree->update_item_cell(this, p_column); + // Text. + const TreeItem::Cell &cell = cells[p_column]; + if (!cell.text.is_empty()) { + if (cell.dirty) { + tree->update_item_cell(this, p_column); + } + Size2 text_size = cell.text_buf->get_size(); + size.width += text_size.width; + size.height = MAX(size.height, text_size.height); } - Size2 text_size = cell.text_buf->get_size(); - size.width += text_size.width; - size.height = MAX(size.height, text_size.height); - } - // Icon. - if (cell.mode == CELL_MODE_CHECK) { - size.width += tree->cache.checked->get_width() + tree->cache.hseparation; - } - if (cell.icon.is_valid()) { - Size2i icon_size = cell.get_icon_size(); - if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) { - icon_size.width = cell.icon_max_w; + // Icon. + if (cell.mode == CELL_MODE_CHECK) { + size.width += tree->cache.checked->get_width() + tree->cache.hseparation; + } + if (cell.icon.is_valid()) { + Size2i icon_size = cell.get_icon_size(); + if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) { + icon_size.width = cell.icon_max_w; + } + size.width += icon_size.width + tree->cache.hseparation; + size.height = MAX(size.height, icon_size.height); } - size.width += icon_size.width + tree->cache.hseparation; - size.height = MAX(size.height, icon_size.height); - } - // Buttons. - for (int i = 0; i < cell.buttons.size(); i++) { - Ref<Texture2D> texture = cell.buttons[i].texture; - if (texture.is_valid()) { - Size2 button_size = texture->get_size() + tree->cache.button_pressed->get_minimum_size(); - size.width += button_size.width; - size.height = MAX(size.height, button_size.height); + // Buttons. + for (int i = 0; i < cell.buttons.size(); i++) { + Ref<Texture2D> texture = cell.buttons[i].texture; + if (texture.is_valid()) { + Size2 button_size = texture->get_size() + tree->cache.button_pressed->get_minimum_size(); + size.width += button_size.width; + size.height = MAX(size.height, button_size.height); + } } - } - if (cell.buttons.size() >= 2) { - size.width += (cell.buttons.size() - 1) * tree->cache.button_margin; + if (cell.buttons.size() >= 2) { + size.width += (cell.buttons.size() - 1) * tree->cache.button_margin; + } + + cached_minimum_size = size; + cached_minimum_size_dirty = false; } - return size; + return cached_minimum_size; } Variant TreeItem::_call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { @@ -1307,6 +1337,10 @@ void Tree::update_cache() { cache.title_button_color = get_theme_color(SNAME("title_button_color")); v_scroll->set_custom_step(cache.font->get_height(cache.font_size)); + + for (TreeItem *item = get_root(); item; item = item->get_next()) { + item->cached_minimum_size_dirty = true; + } } int Tree::compute_item_height(TreeItem *p_item) const { diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 8b7ddc3faf..85fed941dc 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -130,6 +130,9 @@ private: bool disable_folding = false; int custom_min_height = 0; + Size2i cached_minimum_size; + bool cached_minimum_size_dirty = true; + TreeItem *parent = nullptr; // parent item TreeItem *prev = nullptr; // previous in list TreeItem *next = nullptr; // next in list diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 8452f1cb1a..e1b1b356a9 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -544,7 +544,7 @@ void SceneTree::process_tweens(float p_delta, bool p_physics) { } if (!E->get()->step(p_delta)) { - E->get()->set_valid(false); + E->get()->clear(); tweens.erase(E); } if (E == L) { diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 015a4d5dba..69f20ac990 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -197,8 +197,8 @@ #include "scene/resources/visual_shader_sdf_nodes.h" #include "scene/resources/world_2d.h" #include "scene/resources/world_3d.h" -#include "scene/resources/world_margin_shape_2d.h" -#include "scene/resources/world_margin_shape_3d.h" +#include "scene/resources/world_boundary_shape_2d.h" +#include "scene/resources/world_boundary_shape_3d.h" #include "scene/scene_string_names.h" #include "scene/main/shader_globals_override.h" @@ -750,7 +750,7 @@ void register_scene_types() { GDREGISTER_CLASS(CapsuleShape3D); GDREGISTER_CLASS(CylinderShape3D); GDREGISTER_CLASS(HeightMapShape3D); - GDREGISTER_CLASS(WorldMarginShape3D); + GDREGISTER_CLASS(WorldBoundaryShape3D); GDREGISTER_CLASS(ConvexPolygonShape3D); GDREGISTER_CLASS(ConcavePolygonShape3D); @@ -831,7 +831,7 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init GDREGISTER_VIRTUAL_CLASS(Shape2D); - GDREGISTER_CLASS(WorldMarginShape2D); + GDREGISTER_CLASS(WorldBoundaryShape2D); GDREGISTER_CLASS(SegmentShape2D); GDREGISTER_CLASS(SeparationRayShape2D); GDREGISTER_CLASS(CircleShape2D); @@ -919,7 +919,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("KinematicBody2D", "CharacterBody2D"); ClassDB::add_compatibility_class("KinematicCollision", "KinematicCollision3D"); ClassDB::add_compatibility_class("Light", "Light3D"); - ClassDB::add_compatibility_class("LineShape2D", "WorldMarginShape2D"); + ClassDB::add_compatibility_class("LineShape2D", "WorldBoundaryShape2D"); ClassDB::add_compatibility_class("Listener", "Listener3D"); ClassDB::add_compatibility_class("MeshInstance", "MeshInstance3D"); ClassDB::add_compatibility_class("MultiMeshInstance", "MultiMeshInstance3D"); @@ -950,7 +950,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("PhysicsServer", "PhysicsServer3D"); ClassDB::add_compatibility_class("PhysicsShapeQueryParameters", "PhysicsShapeQueryParameters3D"); ClassDB::add_compatibility_class("PinJoint", "PinJoint3D"); - ClassDB::add_compatibility_class("PlaneShape", "WorldMarginShape3D"); + ClassDB::add_compatibility_class("PlaneShape", "WorldBoundaryShape3D"); ClassDB::add_compatibility_class("ProceduralSky", "Sky"); ClassDB::add_compatibility_class("ProximityGroup", "ProximityGroup3D"); ClassDB::add_compatibility_class("RayCast", "RayCast3D"); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 71d0c69d55..8f3f25f104 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -38,7 +38,7 @@ #include <stdlib.h> -Mesh::ConvexDecompositionFunc Mesh::convex_composition_function = nullptr; +Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr; Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { if (triangle_mesh.is_valid()) { @@ -167,64 +167,13 @@ Vector<Face3> Mesh::get_faces() const { return tm->get_faces(); } return Vector<Face3>(); - /* - for (int i=0;i<surfaces.size();i++) { - if (RenderingServer::get_singleton()->mesh_surface_get_primitive_type( mesh, i ) != RenderingServer::PRIMITIVE_TRIANGLES ) - continue; - - Vector<int> indices; - Vector<Vector3> vertices; - - vertices=RenderingServer::get_singleton()->mesh_surface_get_array(mesh, i,RenderingServer::ARRAY_VERTEX); - - int len=RenderingServer::get_singleton()->mesh_surface_get_array_index_len(mesh, i); - bool has_indices; - - if (len>0) { - indices=RenderingServer::get_singleton()->mesh_surface_get_array(mesh, i,RenderingServer::ARRAY_INDEX); - has_indices=true; - - } else { - len=vertices.size(); - has_indices=false; - } - - if (len<=0) - continue; - - const int* indicesr = indices.ptr(); - const int *indicesptr = indicesr.ptr(); - - const Vector3* verticesr = vertices.ptr(); - const Vector3 *verticesptr = verticesr.ptr(); - - int old_faces=faces.size(); - int new_faces=old_faces+(len/3); - - faces.resize(new_faces); - - Face3* facesw = faces.ptrw(); - Face3 *facesptr=facesw.ptr(); - - - for (int i=0;i<len/3;i++) { - Face3 face; - - for (int j=0;j<3;j++) { - int idx=i*3+j; - face.vertex[j] = has_indices ? verticesptr[ indicesptr[ idx ] ] : verticesptr[idx]; - } - - facesptr[i+old_faces]=face; - } - - } -*/ } Ref<Shape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const { if (p_simplify) { - Vector<Ref<Shape3D>> decomposed = convex_decompose(1); + ConvexDecompositionSettings settings; + settings.max_convex_hulls = 1; + Vector<Ref<Shape3D>> decomposed = convex_decompose(settings); if (decomposed.size() == 1) { return decomposed[0]; } else { @@ -565,36 +514,37 @@ void Mesh::clear_cache() const { debug_lines.clear(); } -Vector<Ref<Shape3D>> Mesh::convex_decompose(int p_max_convex_hulls) const { - ERR_FAIL_COND_V(!convex_composition_function, Vector<Ref<Shape3D>>()); - - const Vector<Face3> faces = get_faces(); +Vector<Ref<Shape3D>> Mesh::convex_decompose(const ConvexDecompositionSettings &p_settings) const { + ERR_FAIL_COND_V(!convex_decomposition_function, Vector<Ref<Shape3D>>()); - Vector<Vector<Face3>> decomposed = convex_composition_function(faces, p_max_convex_hulls); - - Vector<Ref<Shape3D>> ret; + Ref<TriangleMesh> tm = generate_triangle_mesh(); + ERR_FAIL_COND_V(!tm.is_valid(), Vector<Ref<Shape3D>>()); - for (int i = 0; i < decomposed.size(); i++) { - Set<Vector3> points; - for (int j = 0; j < decomposed[i].size(); j++) { - points.insert(decomposed[i][j].vertex[0]); - points.insert(decomposed[i][j].vertex[1]); - points.insert(decomposed[i][j].vertex[2]); - } + const Vector<TriangleMesh::Triangle> &triangles = tm->get_triangles(); + int triangle_count = triangles.size(); - Vector<Vector3> convex_points; - convex_points.resize(points.size()); - { - Vector3 *w = convex_points.ptrw(); - int idx = 0; - for (Set<Vector3>::Element *E = points.front(); E; E = E->next()) { - w[idx++] = E->get(); + Vector<uint32_t> indices; + { + indices.resize(triangle_count * 3); + uint32_t *w = indices.ptrw(); + for (int i = 0; i < triangle_count; i++) { + for (int j = 0; j < 3; j++) { + w[i * 3 + j] = triangles[i].indices[j]; } } + } + + const Vector<Vector3> &vertices = tm->get_vertices(); + int vertex_count = vertices.size(); + Vector<Vector<Vector3>> decomposed = convex_decomposition_function((real_t *)vertices.ptr(), vertex_count, indices.ptr(), triangle_count, p_settings, nullptr); + + Vector<Ref<Shape3D>> ret; + + for (int i = 0; i < decomposed.size(); i++) { Ref<ConvexPolygonShape3D> shape; shape.instantiate(); - shape->set_points(convex_points); + shape->set_points(decomposed[i]); ret.push_back(shape); } diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index aa4ed1cb13..0776585a11 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -160,11 +160,42 @@ public: Size2i get_lightmap_size_hint() const; void clear_cache() const; - typedef Vector<Vector<Face3>> (*ConvexDecompositionFunc)(const Vector<Face3> &p_faces, int p_max_convex_hulls); + struct ConvexDecompositionSettings { + enum Mode : int { + CONVEX_DECOMPOSITION_MODE_VOXEL = 0, + CONVEX_DECOMPOSITION_MODE_TETRAHEDRON + }; + + /// Maximum concavity. [Range: 0.0 -> 1.0] + real_t max_concavity = 1.0; + /// Controls the bias toward clipping along symmetry planes. [Range: 0.0 -> 1.0] + real_t symmetry_planes_clipping_bias = 0.05; + /// Controls the bias toward clipping along revolution axes. [Range: 0.0 -> 1.0] + real_t revolution_axes_clipping_bias = 0.05; + real_t min_volume_per_convex_hull = 0.0001; + /// Maximum number of voxels generated during the voxelization stage. + uint32_t resolution = 10'000; + uint32_t max_num_vertices_per_convex_hull = 32; + /// Controls the granularity of the search for the "best" clipping plane. + /// [Range: 1 -> 16] + uint32_t plane_downsampling = 4; + /// Controls the precision of the convex-hull generation process during the + /// clipping plane selection stage. + /// [Range: 1 -> 16] + uint32_t convexhull_downsampling = 4; + /// enable/disable normalizing the mesh before applying the convex decomposition. + bool normalize_mesh = false; + Mode mode = CONVEX_DECOMPOSITION_MODE_VOXEL; + bool convexhull_approximation = true; + /// This is the maximum number of convex hulls to produce from the merge operation. + uint32_t max_convex_hulls = 1; + bool project_hull_vertices = true; + }; + typedef Vector<Vector<Vector3>> (*ConvexDecompositionFunc)(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const ConvexDecompositionSettings &p_settings, Vector<Vector<uint32_t>> *r_convex_indices); - static ConvexDecompositionFunc convex_composition_function; + static ConvexDecompositionFunc convex_decomposition_function; - Vector<Ref<Shape3D>> convex_decompose(int p_max_convex_hulls = -1) const; + Vector<Ref<Shape3D>> convex_decompose(const ConvexDecompositionSettings &p_settings) const; virtual int get_builtin_bind_pose_count() const; virtual Transform3D get_builtin_bind_pose(int p_index) const; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index e288e18f33..918fc3fe9c 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -982,10 +982,10 @@ void TileSet::clear_tile_proxies() { Vector<Vector2> TileSet::get_tile_shape_polygon() { Vector<Vector2> points; if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { - points.append(Vector2(0.0, 0.0)); - points.append(Vector2(1.0, 0.0)); - points.append(Vector2(1.0, 1.0)); - points.append(Vector2(0.0, 1.0)); + points.append(Vector2(-0.5, -0.5)); + points.append(Vector2(0.5, -0.5)); + points.append(Vector2(0.5, 0.5)); + points.append(Vector2(-0.5, 0.5)); } else { float overlap = 0.0; switch (tile_shape) { @@ -1002,31 +1002,24 @@ Vector<Vector2> TileSet::get_tile_shape_polygon() { break; } - points.append(Vector2(0.5, 0.0)); - points.append(Vector2(0.0, overlap)); - points.append(Vector2(0.0, 1.0 - overlap)); - points.append(Vector2(0.5, 1.0)); - points.append(Vector2(1.0, 1.0 - overlap)); - points.append(Vector2(1.0, overlap)); - points.append(Vector2(0.5, 0.0)); + points.append(Vector2(0.0, -0.5)); + points.append(Vector2(-0.5, overlap - 0.5)); + points.append(Vector2(-0.5, 0.5 - overlap)); + points.append(Vector2(0.0, 0.5)); + points.append(Vector2(0.5, 0.5 - overlap)); + points.append(Vector2(0.5, overlap - 0.5)); if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) { for (int i = 0; i < points.size(); i++) { points.write[i] = Vector2(points[i].y, points[i].x); } } } - for (int i = 0; i < points.size(); i++) { - points.write[i] = points[i] * tile_size - tile_size / 2; - } return points; } -void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled, Ref<Texture2D> p_texture) { +void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled, Ref<Texture2D> p_texture) { if (tile_meshes_dirty) { Vector<Vector2> uvs = get_tile_shape_polygon(); - for (int i = 0; i < uvs.size(); i++) { - uvs.write[i] = (uvs[i] + tile_size / 2) / tile_size; - } Vector<Color> colors; colors.resize(uvs.size()); @@ -1056,13 +1049,10 @@ void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p tile_meshes_dirty = false; } - Transform2D xform; - xform.scale(p_region.size); - xform.set_origin(p_region.get_position()); if (p_filled) { - p_canvas_item->draw_mesh(tile_filled_mesh, p_texture, xform, p_color); + p_canvas_item->draw_mesh(tile_filled_mesh, p_texture, p_transform, p_color); } else { - p_canvas_item->draw_mesh(tile_lines_mesh, Ref<Texture2D>(), xform, p_color); + p_canvas_item->draw_mesh(tile_lines_mesh, Ref<Texture2D>(), p_transform, p_color); } } diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 3baf022dc0..ba7207241a 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -385,7 +385,7 @@ public: // Helpers Vector<Vector2> get_tile_shape_polygon(); - void draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>()); + void draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>()); Vector<Point2> get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit); void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data); diff --git a/scene/resources/world_margin_shape_2d.cpp b/scene/resources/world_boundary_shape_2d.cpp index 3b43681528..39af92793f 100644 --- a/scene/resources/world_margin_shape_2d.cpp +++ b/scene/resources/world_boundary_shape_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* world_margin_shape_2d.cpp */ +/* world_boundary_shape_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "world_margin_shape_2d.h" +#include "world_boundary_shape_2d.h" #include "core/math/geometry_2d.h" #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" -bool WorldMarginShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { +bool WorldBoundaryShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { Vector2 point = get_distance() * get_normal(); Vector2 l[2][2] = { { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }, { point, point + get_normal() * 30 } }; @@ -48,7 +48,7 @@ bool WorldMarginShape2D::_edit_is_selected_on_click(const Point2 &p_point, doubl return false; } -void WorldMarginShape2D::_update_shape() { +void WorldBoundaryShape2D::_update_shape() { Array arr; arr.push_back(normal); arr.push_back(distance); @@ -56,25 +56,25 @@ void WorldMarginShape2D::_update_shape() { emit_changed(); } -void WorldMarginShape2D::set_normal(const Vector2 &p_normal) { +void WorldBoundaryShape2D::set_normal(const Vector2 &p_normal) { normal = p_normal; _update_shape(); } -void WorldMarginShape2D::set_distance(real_t p_distance) { +void WorldBoundaryShape2D::set_distance(real_t p_distance) { distance = p_distance; _update_shape(); } -Vector2 WorldMarginShape2D::get_normal() const { +Vector2 WorldBoundaryShape2D::get_normal() const { return normal; } -real_t WorldMarginShape2D::get_distance() const { +real_t WorldBoundaryShape2D::get_distance() const { return distance; } -void WorldMarginShape2D::draw(const RID &p_to_rid, const Color &p_color) { +void WorldBoundaryShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector2 point = get_distance() * get_normal(); Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }; @@ -83,7 +83,7 @@ void WorldMarginShape2D::draw(const RID &p_to_rid, const Color &p_color) { RS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, 3); } -Rect2 WorldMarginShape2D::get_rect() const { +Rect2 WorldBoundaryShape2D::get_rect() const { Vector2 point = get_distance() * get_normal(); Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }; @@ -96,22 +96,22 @@ Rect2 WorldMarginShape2D::get_rect() const { return rect; } -real_t WorldMarginShape2D::get_enclosing_radius() const { +real_t WorldBoundaryShape2D::get_enclosing_radius() const { return distance; } -void WorldMarginShape2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_normal", "normal"), &WorldMarginShape2D::set_normal); - ClassDB::bind_method(D_METHOD("get_normal"), &WorldMarginShape2D::get_normal); +void WorldBoundaryShape2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_normal", "normal"), &WorldBoundaryShape2D::set_normal); + ClassDB::bind_method(D_METHOD("get_normal"), &WorldBoundaryShape2D::get_normal); - ClassDB::bind_method(D_METHOD("set_distance", "distance"), &WorldMarginShape2D::set_distance); - ClassDB::bind_method(D_METHOD("get_distance"), &WorldMarginShape2D::get_distance); + ClassDB::bind_method(D_METHOD("set_distance", "distance"), &WorldBoundaryShape2D::set_distance); + ClassDB::bind_method(D_METHOD("get_distance"), &WorldBoundaryShape2D::get_distance); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "normal"), "set_normal", "get_normal"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance"), "set_distance", "get_distance"); } -WorldMarginShape2D::WorldMarginShape2D() : - Shape2D(PhysicsServer2D::get_singleton()->world_margin_shape_create()) { +WorldBoundaryShape2D::WorldBoundaryShape2D() : + Shape2D(PhysicsServer2D::get_singleton()->world_boundary_shape_create()) { _update_shape(); } diff --git a/scene/resources/world_margin_shape_2d.h b/scene/resources/world_boundary_shape_2d.h index 3c1d593ffe..4cc60f5985 100644 --- a/scene/resources/world_margin_shape_2d.h +++ b/scene/resources/world_boundary_shape_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* world_margin_shape_2d.h */ +/* world_boundary_shape_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef WORLD_MARGIN_SHAPE_2D_H -#define WORLD_MARGIN_SHAPE_2D_H +#ifndef WORLD_BOUNDARY_SHAPE_2D_H +#define WORLD_BOUNDARY_SHAPE_2D_H #include "scene/resources/shape_2d.h" -class WorldMarginShape2D : public Shape2D { - GDCLASS(WorldMarginShape2D, Shape2D); +class WorldBoundaryShape2D : public Shape2D { + GDCLASS(WorldBoundaryShape2D, Shape2D); - // WorldMarginShape2D is often used for one-way platforms, where the normal pointing up makes sense. + // WorldBoundaryShape2D is often used for one-way platforms, where the normal pointing up makes sense. Vector2 normal = Vector2(0, -1); real_t distance = 0.0; @@ -58,7 +58,7 @@ public: virtual Rect2 get_rect() const override; virtual real_t get_enclosing_radius() const override; - WorldMarginShape2D(); + WorldBoundaryShape2D(); }; -#endif // WORLD_MARGIN_SHAPE_2D_H +#endif // WORLD_BOUNDARY_SHAPE_2D_H diff --git a/scene/resources/world_margin_shape_3d.cpp b/scene/resources/world_boundary_shape_3d.cpp index 28d50e1921..8cde537164 100644 --- a/scene/resources/world_margin_shape_3d.cpp +++ b/scene/resources/world_boundary_shape_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* world_margin_shape_3d.cpp */ +/* world_boundary_shape_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "world_margin_shape_3d.h" +#include "world_boundary_shape_3d.h" #include "servers/physics_server_3d.h" -Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() const { +Vector<Vector3> WorldBoundaryShape3D::get_debug_mesh_lines() const { Plane p = get_plane(); Vector<Vector3> points; @@ -60,29 +60,29 @@ Vector<Vector3> WorldMarginShape3D::get_debug_mesh_lines() const { return points; } -void WorldMarginShape3D::_update_shape() { +void WorldBoundaryShape3D::_update_shape() { PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), plane); Shape3D::_update_shape(); } -void WorldMarginShape3D::set_plane(Plane p_plane) { +void WorldBoundaryShape3D::set_plane(const Plane &p_plane) { plane = p_plane; _update_shape(); notify_change_to_owners(); } -Plane WorldMarginShape3D::get_plane() const { +const Plane &WorldBoundaryShape3D::get_plane() const { return plane; } -void WorldMarginShape3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldMarginShape3D::set_plane); - ClassDB::bind_method(D_METHOD("get_plane"), &WorldMarginShape3D::get_plane); +void WorldBoundaryShape3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_plane", "plane"), &WorldBoundaryShape3D::set_plane); + ClassDB::bind_method(D_METHOD("get_plane"), &WorldBoundaryShape3D::get_plane); ADD_PROPERTY(PropertyInfo(Variant::PLANE, "plane"), "set_plane", "get_plane"); } -WorldMarginShape3D::WorldMarginShape3D() : - Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_PLANE)) { +WorldBoundaryShape3D::WorldBoundaryShape3D() : + Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_WORLD_BOUNDARY)) { set_plane(Plane(0, 1, 0, 0)); } diff --git a/scene/resources/world_margin_shape_3d.h b/scene/resources/world_boundary_shape_3d.h index 00417c4408..853f555ebc 100644 --- a/scene/resources/world_margin_shape_3d.h +++ b/scene/resources/world_boundary_shape_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* world_margin_shape_3d.h */ +/* world_boundary_shape_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef WORLD_MARGIN_SHAPE_3D_H -#define WORLD_MARGIN_SHAPE_3D_H +#ifndef WORLD_BOUNDARY_SHAPE_3D_H +#define WORLD_BOUNDARY_SHAPE_3D_H #include "scene/resources/shape_3d.h" -class WorldMarginShape3D : public Shape3D { - GDCLASS(WorldMarginShape3D, Shape3D); +class WorldBoundaryShape3D : public Shape3D { + GDCLASS(WorldBoundaryShape3D, Shape3D); Plane plane; protected: @@ -42,8 +42,8 @@ protected: virtual void _update_shape() override; public: - void set_plane(Plane p_plane); - Plane get_plane() const; + void set_plane(const Plane &p_plane); + const Plane &get_plane() const; virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override { @@ -51,6 +51,6 @@ public: return 0; } - WorldMarginShape3D(); + WorldBoundaryShape3D(); }; -#endif // WORLD_MARGIN_SHAPE_H +#endif // WORLD_BOUNDARY_SHAPE_H diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index 5d89d295c2..b283749ffa 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -91,9 +91,6 @@ SceneStringNames::SceneStringNames() { update = StaticCString::create("update"); updated = StaticCString::create("updated"); - _get_gizmo_geometry = StaticCString::create("_get_gizmo_geometry"); - _can_gizmo_scale = StaticCString::create("_can_gizmo_scale"); - _physics_process = StaticCString::create("_physics_process"); _process = StaticCString::create("_process"); diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 01f427ecd1..2923351eab 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -111,9 +111,6 @@ public: StringName _body_inout; StringName _area_inout; - StringName _get_gizmo_geometry; - StringName _can_gizmo_scale; - StringName _physics_process; StringName _process; StringName _enter_world; |