diff options
Diffstat (limited to 'scene')
42 files changed, 1454 insertions, 1114 deletions
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index 33b1c7bcce..fff9c47d4d 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -533,13 +533,13 @@ void Area2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_body_inout"), &Area2D::_body_inout); ClassDB::bind_method(D_METHOD("_area_inout"), &Area2D::_area_inout); - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"))); ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"))); - ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape"))); - ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); + ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"))); ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"))); diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index bddc342c1a..18a50ae098 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -68,7 +68,7 @@ void AudioStreamPlayer2D::_notification(int p_what) { active.set(); Ref<AudioStreamPlayback> new_playback = stream->instance_playback(); ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback."); - AudioServer::get_singleton()->start_playback_stream(new_playback, _get_actual_bus(), volume_vector, setplay.get()); + AudioServer::get_singleton()->start_playback_stream(new_playback, _get_actual_bus(), volume_vector, setplay.get(), pitch_scale); stream_playbacks.push_back(new_playback); setplay.set(-1); } diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index 5bce705dd5..3637594e1b 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -163,8 +163,8 @@ void GPUParticles2D::set_trail_sections(int p_sections) { } void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) { - ERR_FAIL_COND(trail_section_subdivisions < 1); - ERR_FAIL_COND(trail_section_subdivisions > 1024); + ERR_FAIL_COND(p_subdivisions < 1); + ERR_FAIL_COND(p_subdivisions > 1024); trail_section_subdivisions = p_subdivisions; update(); diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index 67e35cc7a3..797e2e59cb 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -123,12 +123,12 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_s Point2 new_ofs = (screen_offset + (p_offset - screen_offset) * motion_scale) + motion_offset * p_scale + orig_offset * p_scale; if (mirroring.x) { - double den = mirroring.x * p_scale; + real_t den = mirroring.x * p_scale; new_ofs.x -= den * ceil(new_ofs.x / den); } if (mirroring.y) { - double den = mirroring.y * p_scale; + real_t den = mirroring.y * p_scale; new_ofs.y -= den * ceil(new_ofs.y / den); } diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index f493d97ceb..41288d646f 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1000,8 +1000,8 @@ void RigidDynamicBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "applied_force"), "set_applied_force", "get_applied_force"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "applied_torque"), "set_applied_torque", "get_applied_torque"); - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("sleeping_state_changed")); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 222ec986b0..c2f150ce00 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -409,6 +409,19 @@ bool TileMap::is_layer_enabled(int p_layer) const { return layers[p_layer].enabled; } +void TileMap::set_layer_modulate(int p_layer, Color p_modulate) { + ERR_FAIL_INDEX(p_layer, (int)layers.size()); + layers[p_layer].modulate = p_modulate; + _clear_internals(); + _recreate_internals(); + emit_signal(SNAME("changed")); +} + +Color TileMap::get_layer_modulate(int p_layer) const { + ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), Color()); + return layers[p_layer].modulate; +} + 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; @@ -798,8 +811,9 @@ void TileMap::_rendering_cleanup_layer(int p_layer) { ERR_FAIL_INDEX(p_layer, (int)layers.size()); RenderingServer *rs = RenderingServer::get_singleton(); - if (!layers[p_layer].canvas_item.is_valid()) { + if (layers[p_layer].canvas_item.is_valid()) { rs->free(layers[p_layer].canvas_item); + layers[p_layer].canvas_item = RID(); } } @@ -832,6 +846,19 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List int prev_z_index = 0; RID prev_canvas_item; + Color modulate = get_self_modulate(); + modulate *= get_layer_modulate(q.layer); + if (selected_layer >= 0) { + int z1 = get_layer_z_index(q.layer); + int z2 = get_layer_z_index(selected_layer); + if (z1 < z2 || (z1 == z2 && q.layer < selected_layer)) { + modulate = modulate.darkened(0.5); + } else if (z1 > z2 || (z1 == z2 && q.layer > selected_layer)) { + modulate = modulate.darkened(0.5); + modulate.a *= 0.3; + } + } + // Iterate over the cells of the quadrant. for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) { TileMapCell c = get_cell(q.layer, E_cell.value, true); @@ -894,15 +921,6 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List } // Drawing the tile in the canvas item. - Color modulate = get_self_modulate(); - if (selected_layer >= 0) { - if (q.layer < selected_layer) { - modulate = modulate.darkened(0.5); - } else if (q.layer > selected_layer) { - modulate = modulate.darkened(0.5); - modulate.a *= 0.3; - } - } draw_tile(canvas_item, E_cell.key - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, modulate); // --- Occluders --- @@ -2083,6 +2101,9 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { } else if (components[1] == "enabled") { set_layer_enabled(index, p_value); return true; + } else if (components[1] == "modulate") { + set_layer_modulate(index, p_value); + return true; } else if (components[1] == "y_sort_enabled") { set_layer_y_sort_enabled(index, p_value); return true; @@ -2119,6 +2140,9 @@ bool TileMap::_get(const StringName &p_name, Variant &r_ret) const { } else if (components[1] == "enabled") { r_ret = is_layer_enabled(index); return true; + } else if (components[1] == "modulate") { + r_ret = get_layer_modulate(index); + return true; } else if (components[1] == "y_sort_enabled") { r_ret = is_layer_y_sort_enabled(index); return true; @@ -2144,6 +2168,7 @@ void TileMap::_get_property_list(List<PropertyInfo> *p_list) const { for (unsigned int i = 0; i < layers.size(); i++) { p_list->push_back(PropertyInfo(Variant::STRING, vformat("layer_%d/name", i), PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::BOOL, vformat("layer_%d/enabled", i), PROPERTY_HINT_NONE)); + p_list->push_back(PropertyInfo(Variant::COLOR, vformat("layer_%d/modulate", i), PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::BOOL, vformat("layer_%d/y_sort_enabled", i), PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::INT, vformat("layer_%d/y_sort_origin", i), PROPERTY_HINT_NONE)); p_list->push_back(PropertyInfo(Variant::INT, vformat("layer_%d/z_index", i), PROPERTY_HINT_NONE)); @@ -3027,6 +3052,8 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("get_layer_name", "layer"), &TileMap::get_layer_name); ClassDB::bind_method(D_METHOD("set_layer_enabled", "layer", "enabled"), &TileMap::set_layer_enabled); ClassDB::bind_method(D_METHOD("is_layer_enabled", "layer"), &TileMap::is_layer_enabled); + ClassDB::bind_method(D_METHOD("set_layer_modulate", "layer", "enabled"), &TileMap::set_layer_modulate); + ClassDB::bind_method(D_METHOD("get_layer_modulate", "layer"), &TileMap::get_layer_modulate); ClassDB::bind_method(D_METHOD("set_layer_y_sort_enabled", "layer", "y_sort_enabled"), &TileMap::set_layer_y_sort_enabled); ClassDB::bind_method(D_METHOD("is_layer_y_sort_enabled", "layer"), &TileMap::is_layer_y_sort_enabled); ClassDB::bind_method(D_METHOD("set_layer_y_sort_origin", "layer", "y_sort_origin"), &TileMap::set_layer_y_sort_origin); @@ -3068,6 +3095,8 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_tile_data", "layer"), &TileMap::_set_tile_data); ClassDB::bind_method(D_METHOD("_get_tile_data", "layer"), &TileMap::_get_tile_data); + ClassDB::bind_method(D_METHOD("_tile_set_changed_deferred_update"), &TileMap::_tile_set_changed_deferred_update); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_quadrant_size", "get_quadrant_size"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_animatable"), "set_collision_animatable", "is_collision_animatable"); @@ -3087,8 +3116,16 @@ void TileMap::_bind_methods() { void TileMap::_tile_set_changed() { emit_signal(SNAME("changed")); - _clear_internals(); - _recreate_internals(); + _tile_set_changed_deferred_update_needed = true; + call_deferred("_tile_set_changed_deferred_update"); +} + +void TileMap::_tile_set_changed_deferred_update() { + if (_tile_set_changed_deferred_update_needed) { + _clear_internals(); + _recreate_internals(); + _tile_set_changed_deferred_update_needed = false; + } } TileMap::TileMap() { diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 2faede2445..e5809deabb 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -219,6 +219,7 @@ private: struct TileMapLayer { String name; bool enabled = true; + Color modulate = Color(1, 1, 1, 1); bool y_sort_enabled = false; int y_sort_origin = 0; int z_index = 0; @@ -284,6 +285,8 @@ private: Vector<int> _get_tile_data(int p_layer) const; void _tile_set_changed(); + bool _tile_set_changed_deferred_update_needed = false; + void _tile_set_changed_deferred_update(); protected: bool _set(const StringName &p_name, const Variant &p_value); @@ -321,6 +324,8 @@ public: String get_layer_name(int p_layer) const; void set_layer_enabled(int p_layer, bool p_visible); bool is_layer_enabled(int p_layer) const; + void set_layer_modulate(int p_layer, Color p_modulate); + Color get_layer_modulate(int p_layer) const; void set_layer_y_sort_enabled(int p_layer, bool p_enabled); bool is_layer_y_sort_enabled(int p_layer) const; void set_layer_y_sort_origin(int p_layer, int p_y_sort_origin); diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index 7e4c40ca0e..d411525707 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -649,13 +649,13 @@ void Area3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_reverb_uniformity", "amount"), &Area3D::set_reverb_uniformity); ClassDB::bind_method(D_METHOD("get_reverb_uniformity"), &Area3D::get_reverb_uniformity); - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"))); ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"))); - ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape"))); - ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); + ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::RID, "area_rid"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"))); ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"))); diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index a54b10ba70..c422070480 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -282,7 +282,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback."); Map<StringName, Vector<AudioFrame>> bus_map; bus_map[_get_actual_bus()] = volume_vector; - AudioServer::get_singleton()->start_playback_stream(new_playback, bus_map, setplay.get(), linear_attenuation, attenuation_filter_cutoff_hz, actual_pitch_scale); + AudioServer::get_singleton()->start_playback_stream(new_playback, bus_map, setplay.get(), actual_pitch_scale, linear_attenuation, attenuation_filter_cutoff_hz); stream_playbacks.push_back(new_playback); setplay.set(-1); } diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index afd11482e3..8e89f4fc54 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -215,8 +215,6 @@ void BoneAttachment3D::_transform_changed() { sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true); } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) { sk->set_bone_local_pose_override(bone_idx, sk->global_pose_to_local_pose(bone_idx, our_trans), 1.0, true); - } else if (override_mode == OVERRIDE_MODES::MODE_CUSTOM_POSE) { - sk->set_bone_custom_pose(bone_idx, sk->global_pose_to_local_pose(bone_idx, our_trans)); } } } @@ -273,8 +271,6 @@ void BoneAttachment3D::set_override_pose(bool p_override) { sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false); } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) { sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false); - } else if (override_mode == OVERRIDE_MODES::MODE_CUSTOM_POSE) { - sk->set_bone_custom_pose(bone_idx, Transform3D()); } } _transform_changed(); @@ -294,8 +290,6 @@ void BoneAttachment3D::set_override_mode(int p_mode) { sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false); } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) { sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false); - } else if (override_mode == OVERRIDE_MODES::MODE_CUSTOM_POSE) { - sk->set_bone_custom_pose(bone_idx, Transform3D()); } } override_mode = p_mode; diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h index cf681cace8..57b9854e0e 100644 --- a/scene/3d/bone_attachment_3d.h +++ b/scene/3d/bone_attachment_3d.h @@ -47,7 +47,6 @@ class BoneAttachment3D : public Node3D { enum OVERRIDE_MODES { MODE_GLOBAL_POSE, MODE_LOCAL_POSE, - MODE_CUSTOM_POSE }; bool use_external_skeleton = false; diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 18b7bcc789..588d2b5018 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -656,6 +656,7 @@ Vector3 Camera3D::get_doppler_tracked_velocity() const { } RID Camera3D::get_pyramid_shape_rid() { + ERR_FAIL_COND_V_MSG(!is_inside_tree(), RID(), "Camera is not inside scene."); if (pyramid_shape == RID()) { pyramid_shape_points = get_near_plane_points(); pyramid_shape = PhysicsServer3D::get_singleton()->convex_polygon_shape_create(); diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index 4fa34615bf..9127168c58 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -475,7 +475,7 @@ Ref<Image> GPUParticlesCollisionSDF::bake() { _create_bvh(bvh, face_pos.ptr(), face_pos.size(), faces.ptr(), th); Vector<uint8_t> data; - data.resize(sdf_size.z * sdf_size.y * sdf_size.x * sizeof(float)); + data.resize(sdf_size.z * sdf_size.y * sdf_size.x * (int)sizeof(float)); if (bake_step_function) { bake_step_function(0, "Baking SDF"); diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index 67f4a88228..cfd90e5da0 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -146,11 +146,13 @@ void MeshInstance3D::_resolve_skeleton_path() { if (!skeleton_path.is_empty()) { Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(get_node(skeleton_path)); if (skeleton) { - new_skin_reference = skeleton->register_skin(skin_internal); if (skin_internal.is_null()) { + new_skin_reference = skeleton->register_skin(skeleton->create_skin_from_rest_transforms()); //a skin was created for us skin_internal = new_skin_reference->get_skin(); notify_property_list_changed(); + } else { + new_skin_reference = skeleton->register_skin(skin_internal); } } } diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 976bff4fbc..8cb348d6e3 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -1040,8 +1040,8 @@ void RigidDynamicBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("sleeping_state_changed")); diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 2b52f034b2..14506fd9bd 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -99,8 +99,12 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) { set_bone_rest(which, p_value); } else if (what == "enabled") { set_bone_enabled(which, p_value); - } else if (what == "pose") { - set_bone_pose(which, p_value); + } else if (what == "position") { + set_bone_pose_position(which, p_value); + } else if (what == "rotation") { + set_bone_pose_rotation(which, p_value); + } else if (what == "scale") { + set_bone_pose_scale(which, p_value); } else { return false; } @@ -135,8 +139,12 @@ bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const { r_ret = get_bone_rest(which); } else if (what == "enabled") { r_ret = is_bone_enabled(which); - } else if (what == "pose") { - r_ret = get_bone_pose(which); + } else if (what == "position") { + r_ret = get_bone_pose_position(which); + } else if (what == "rotation") { + r_ret = get_bone_pose_rotation(which); + } else if (what == "scale") { + r_ret = get_bone_pose_scale(which); } else { return false; } @@ -151,7 +159,9 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "rest", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + "position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::QUATERNION, prep + "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); } #ifndef _3D_DISABLED @@ -161,6 +171,45 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const { "SkeletonModificationStack3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); #endif //_3D_DISABLED + + for (PropertyInfo &E : *p_list) { + _validate_property(E); + } +} + +void Skeleton3D::_validate_property(PropertyInfo &property) const { + PackedStringArray spr = property.name.split("/"); + if (spr.size() == 3 && spr[0] == "bones") { + if (spr[2] == "rest") { + property.usage |= PROPERTY_USAGE_READ_ONLY; + } + if (is_show_rest_only()) { + if (spr[2] == "enabled") { + property.usage |= PROPERTY_USAGE_READ_ONLY; + } + if (spr[2] == "position") { + property.usage |= PROPERTY_USAGE_READ_ONLY; + } + if (spr[2] == "rotation") { + property.usage |= PROPERTY_USAGE_READ_ONLY; + } + if (spr[2] == "scale") { + property.usage |= PROPERTY_USAGE_READ_ONLY; + } + } else if (!is_bone_enabled(spr[1].to_int())) { + if (spr[2] == "position") { + property.usage |= PROPERTY_USAGE_READ_ONLY; + } + if (spr[2] == "rotation") { + property.usage |= PROPERTY_USAGE_READ_ONLY; + } + if (spr[2] == "scale") { + property.usage |= PROPERTY_USAGE_READ_ONLY; + } + } + } + + Node3D::_validate_property(property); } void Skeleton3D::_update_process_order() { @@ -547,18 +596,6 @@ void Skeleton3D::unparent_bone_and_rest(int p_bone) { _make_dirty(); } -void Skeleton3D::set_bone_disable_rest(int p_bone, bool p_disable) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - bones.write[p_bone].disable_rest = p_disable; -} - -bool Skeleton3D::is_bone_rest_disabled(int p_bone) const { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, false); - return bones[p_bone].disable_rest; -} - int Skeleton3D::get_bone_parent(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, -1); @@ -657,36 +694,60 @@ void Skeleton3D::clear_bones() { // Posing api -void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) { +void Skeleton3D::set_bone_pose_position(int p_bone, const Vector3 &p_position) { const int bone_size = bones.size(); ERR_FAIL_INDEX(p_bone, bone_size); - bones.write[p_bone].pose = p_pose; + bones.write[p_bone].pose_position = p_position; + bones.write[p_bone].pose_cache_dirty = true; if (is_inside_tree()) { _make_dirty(); } } -Transform3D Skeleton3D::get_bone_pose(int p_bone) const { +void Skeleton3D::set_bone_pose_rotation(int p_bone, const Quaternion &p_rotation) { const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - return bones[p_bone].pose; -} + ERR_FAIL_INDEX(p_bone, bone_size); -void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose) { + bones.write[p_bone].pose_rotation = p_rotation; + bones.write[p_bone].pose_cache_dirty = true; + if (is_inside_tree()) { + _make_dirty(); + } +} +void Skeleton3D::set_bone_pose_scale(int p_bone, const Vector3 &p_scale) { const int bone_size = bones.size(); ERR_FAIL_INDEX(p_bone, bone_size); - //ERR_FAIL_COND( !is_inside_scene() ); - bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform3D()); - bones.write[p_bone].custom_pose = p_custom_pose; + bones.write[p_bone].pose_scale = p_scale; + bones.write[p_bone].pose_cache_dirty = true; + if (is_inside_tree()) { + _make_dirty(); + } +} - _make_dirty(); +Vector3 Skeleton3D::get_bone_pose_position(int p_bone) const { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, Vector3()); + return bones[p_bone].pose_position; } -Transform3D Skeleton3D::get_bone_custom_pose(int p_bone) const { +Quaternion Skeleton3D::get_bone_pose_rotation(int p_bone) const { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, Quaternion()); + return bones[p_bone].pose_rotation; +} + +Vector3 Skeleton3D::get_bone_pose_scale(int p_bone) const { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, Vector3()); + return bones[p_bone].pose_scale; +} + +Transform3D Skeleton3D::get_bone_pose(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - return bones[p_bone].custom_pose; + ((Skeleton3D *)this)->bones.write[p_bone].update_pose_cache(); + return bones[p_bone].pose_cache; } void Skeleton3D::_make_dirty() { @@ -887,59 +948,57 @@ void Skeleton3D::_skin_changed() { _make_dirty(); } -Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) { - for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) { - if (E->get()->skin == p_skin) { - return Ref<SkinReference>(E->get()); +Ref<Skin> Skeleton3D::create_skin_from_rest_transforms() { + Ref<Skin> skin; + + skin.instantiate(); + skin->set_bind_count(bones.size()); + _update_process_order(); // Just in case. + + // Pose changed, rebuild cache of inverses. + const Bone *bonesptr = bones.ptr(); + int len = bones.size(); + + // Calculate global rests and invert them. + LocalVector<int> bones_to_process; + bones_to_process = get_parentless_bones(); + while (bones_to_process.size() > 0) { + int current_bone_idx = bones_to_process[0]; + const Bone &b = bonesptr[current_bone_idx]; + bones_to_process.erase(current_bone_idx); + LocalVector<int> child_bones_vector; + child_bones_vector = get_bone_children(current_bone_idx); + int child_bones_size = child_bones_vector.size(); + if (b.parent < 0) { + skin->set_bind_pose(current_bone_idx, b.rest); + } + for (int i = 0; i < child_bones_size; i++) { + int child_bone_idx = child_bones_vector[i]; + const Bone &cb = bonesptr[child_bone_idx]; + skin->set_bind_pose(child_bone_idx, skin->get_bind_pose(current_bone_idx) * cb.rest); + // Add the bone's children to the list of bones to be processed. + bones_to_process.push_back(child_bones_vector[i]); } } - Ref<Skin> skin = p_skin; - - if (skin.is_null()) { - // Need to create one from existing code, this is for compatibility only - // when skeletons did not support skins. It is also used by gizmo - // to display the skeleton. - - skin.instantiate(); - skin->set_bind_count(bones.size()); - _update_process_order(); // Just in case. - - // Pose changed, rebuild cache of inverses. - const Bone *bonesptr = bones.ptr(); - int len = bones.size(); - - // Calculate global rests and invert them. - LocalVector<int> bones_to_process; - bones_to_process = get_parentless_bones(); - while (bones_to_process.size() > 0) { - int current_bone_idx = bones_to_process[0]; - const Bone &b = bonesptr[current_bone_idx]; - bones_to_process.erase(current_bone_idx); - LocalVector<int> child_bones_vector; - child_bones_vector = get_bone_children(current_bone_idx); - int child_bones_size = child_bones_vector.size(); - if (b.parent < 0) { - skin->set_bind_pose(current_bone_idx, b.rest); - } - for (int i = 0; i < child_bones_size; i++) { - int child_bone_idx = child_bones_vector[i]; - const Bone &cb = bonesptr[child_bone_idx]; - skin->set_bind_pose(child_bone_idx, skin->get_bind_pose(current_bone_idx) * cb.rest); - // Add the bone's children to the list of bones to be processed. - bones_to_process.push_back(child_bones_vector[i]); - } - } + for (int i = 0; i < len; i++) { + // The inverse is what is actually required. + skin->set_bind_bone(i, i); + skin->set_bind_pose(i, skin->get_bind_pose(i).affine_inverse()); + } - for (int i = 0; i < len; i++) { - // The inverse is what is actually required. - skin->set_bind_bone(i, i); - skin->set_bind_pose(i, skin->get_bind_pose(i).affine_inverse()); + return skin; +} + +Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) { + ERR_FAIL_COND_V(p_skin.is_null(), Ref<SkinReference>()); + + for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) { + if (E->get()->skin == p_skin) { + return Ref<SkinReference>(E->get()); } } - ERR_FAIL_COND_V(skin.is_null(), Ref<SkinReference>()); - Ref<SkinReference> skin_ref; skin_ref.instantiate(); @@ -947,11 +1006,11 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) { skin_ref->bind_count = 0; skin_ref->skeleton = RenderingServer::get_singleton()->skeleton_create(); skin_ref->skeleton_node = this; - skin_ref->skin = skin; + skin_ref->skin = p_skin; skin_bindings.insert(skin_ref.operator->()); - skin->connect("changed", Callable(skin_ref.operator->(), "_skin_changed")); + skin_ref->skin->connect("changed", Callable(skin_ref.operator->(), "_skin_changed")); _make_dirty(); // Skin needs to be updated, so update skeleton. @@ -987,59 +1046,33 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) { Bone &b = bonesptr[current_bone_idx]; bool bone_enabled = b.enabled && !show_rest_only; - if (b.disable_rest) { - if (bone_enabled) { - Transform3D pose = b.pose; - if (b.custom_pose_enable) { - pose = b.custom_pose * pose; - } - if (b.parent >= 0) { - b.pose_global = bonesptr[b.parent].pose_global * pose; - b.pose_global_no_override = b.pose_global; - } else { - b.pose_global = pose; - b.pose_global_no_override = b.pose_global; - } + if (bone_enabled) { + b.update_pose_cache(); + Transform3D pose = b.pose_cache; + + if (b.parent >= 0) { + b.pose_global = bonesptr[b.parent].pose_global * pose; + b.pose_global_no_override = b.pose_global; } else { - if (b.parent >= 0) { - b.pose_global = bonesptr[b.parent].pose_global; - b.pose_global_no_override = b.pose_global; - } else { - b.pose_global = Transform3D(); - b.pose_global_no_override = b.pose_global; - } + b.pose_global = pose; + b.pose_global_no_override = b.pose_global; } - } else { - if (bone_enabled) { - Transform3D pose = b.pose; - if (b.custom_pose_enable) { - pose = b.custom_pose * pose; - } - if (b.parent >= 0) { - b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose); - b.pose_global_no_override = b.pose_global; - } else { - b.pose_global = b.rest * pose; - b.pose_global_no_override = b.pose_global; - } + if (b.parent >= 0) { + b.pose_global = bonesptr[b.parent].pose_global * b.rest; + b.pose_global_no_override = b.pose_global; } else { - if (b.parent >= 0) { - b.pose_global = bonesptr[b.parent].pose_global * b.rest; - b.pose_global_no_override = b.pose_global; - } else { - b.pose_global = b.rest; - b.pose_global_no_override = b.pose_global; - } + b.pose_global = b.rest; + b.pose_global_no_override = b.pose_global; } } if (b.local_pose_override_amount >= CMP_EPSILON) { Transform3D override_local_pose; if (b.parent >= 0) { - override_local_pose = bonesptr[b.parent].pose_global * (b.rest * b.local_pose_override); + override_local_pose = bonesptr[b.parent].pose_global * b.local_pose_override; } else { - override_local_pose = (b.rest * b.local_pose_override); + override_local_pose = b.local_pose_override; } b.pose_global = b.pose_global.interpolate_with(override_local_pose, b.local_pose_override_amount); } @@ -1080,8 +1113,8 @@ Transform3D Skeleton3D::global_pose_to_local_pose(int p_bone_idx, Transform3D p_ ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D()); if (bones[p_bone_idx].parent >= 0) { int parent_bone_idx = bones[p_bone_idx].parent; - Transform3D conversion_transform = (bones[parent_bone_idx].pose_global * bones[p_bone_idx].rest); - return conversion_transform.affine_inverse() * p_global_pose; + Transform3D conversion_transform = bones[parent_bone_idx].pose_global.affine_inverse(); + return conversion_transform * p_global_pose; } else { return p_global_pose; } @@ -1092,8 +1125,7 @@ Transform3D Skeleton3D::local_pose_to_global_pose(int p_bone_idx, Transform3D p_ ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D()); if (bones[p_bone_idx].parent >= 0) { int parent_bone_idx = bones[p_bone_idx].parent; - Transform3D conversion_transform = (bones[parent_bone_idx].pose_global * bones[p_bone_idx].rest); - return conversion_transform * p_local_pose; + return bones[parent_bone_idx].pose_global * p_local_pose; } else { return p_local_pose; } @@ -1183,17 +1215,21 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton3D::get_bone_rest); ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton3D::set_bone_rest); + ClassDB::bind_method(D_METHOD("create_skin_from_rest_transforms"), &Skeleton3D::create_skin_from_rest_transforms); ClassDB::bind_method(D_METHOD("register_skin", "skin"), &Skeleton3D::register_skin); ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton3D::localize_rests); - ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton3D::set_bone_disable_rest); - ClassDB::bind_method(D_METHOD("is_bone_rest_disabled", "bone_idx"), &Skeleton3D::is_bone_rest_disabled); - ClassDB::bind_method(D_METHOD("clear_bones"), &Skeleton3D::clear_bones); ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton3D::get_bone_pose); - ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton3D::set_bone_pose); + ClassDB::bind_method(D_METHOD("set_bone_pose_position", "bone_idx", "position"), &Skeleton3D::set_bone_pose_position); + ClassDB::bind_method(D_METHOD("set_bone_pose_rotation", "bone_idx", "rotation"), &Skeleton3D::set_bone_pose_rotation); + ClassDB::bind_method(D_METHOD("set_bone_pose_scale", "bone_idx", "scale"), &Skeleton3D::set_bone_pose_scale); + + ClassDB::bind_method(D_METHOD("get_bone_pose_position", "bone_idx"), &Skeleton3D::get_bone_pose_position); + ClassDB::bind_method(D_METHOD("get_bone_pose_rotation", "bone_idx"), &Skeleton3D::get_bone_pose_rotation); + ClassDB::bind_method(D_METHOD("get_bone_pose_scale", "bone_idx"), &Skeleton3D::get_bone_pose_scale); ClassDB::bind_method(D_METHOD("is_bone_enabled", "bone_idx"), &Skeleton3D::is_bone_enabled); ClassDB::bind_method(D_METHOD("set_bone_enabled", "bone_idx", "enabled"), &Skeleton3D::set_bone_enabled, DEFVAL(true)); @@ -1208,9 +1244,6 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bone_local_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_local_pose_override, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_bone_local_pose_override", "bone_idx"), &Skeleton3D::get_bone_local_pose_override); - ClassDB::bind_method(D_METHOD("get_bone_custom_pose", "bone_idx"), &Skeleton3D::get_bone_custom_pose); - ClassDB::bind_method(D_METHOD("set_bone_custom_pose", "bone_idx", "custom_pose"), &Skeleton3D::set_bone_custom_pose); - ClassDB::bind_method(D_METHOD("force_update_all_bone_transforms"), &Skeleton3D::force_update_all_bone_transforms); ClassDB::bind_method(D_METHOD("force_update_bone_child_transform", "bone_idx"), &Skeleton3D::force_update_bone_children_transforms); diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index 9aa4fc823f..f7bc3df94e 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -76,16 +76,24 @@ private: bool enabled; int parent; - bool disable_rest = false; Transform3D rest; - Transform3D pose; + _FORCE_INLINE_ void update_pose_cache() { + if (pose_cache_dirty) { + pose_cache.basis.set_quaternion_scale(pose_rotation, pose_scale); + pose_cache.origin = pose_position; + pose_cache_dirty = false; + } + } + bool pose_cache_dirty = true; + Transform3D pose_cache; + Vector3 pose_position; + Quaternion pose_rotation; + Vector3 pose_scale = Vector3(1, 1, 1); + Transform3D pose_global; Transform3D pose_global_no_override; - bool custom_pose_enable = false; - Transform3D custom_pose; - real_t global_pose_override_amount = 0.0; bool global_pose_override_reset = false; Transform3D global_pose_override; @@ -107,8 +115,6 @@ private: Bone() { parent = -1; enabled = true; - disable_rest = false; - custom_pose_enable = false; global_pose_override_amount = 0; global_pose_override_reset = false; #ifndef _3D_DISABLED @@ -147,6 +153,7 @@ protected: bool _get(const StringName &p_path, Variant &r_ret) const; bool _set(const StringName &p_path, const Variant &p_value); void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void _validate_property(PropertyInfo &property) const override; void _notification(int p_what); static void _bind_methods(); @@ -187,9 +194,6 @@ public: void remove_bone_child(int p_bone, int p_child); Vector<int> get_parentless_bones(); - void set_bone_disable_rest(int p_bone, bool p_disable); - bool is_bone_rest_disabled(int p_bone) const; - int get_bone_count() const; void set_bone_rest(int p_bone, const Transform3D &p_rest); @@ -206,11 +210,15 @@ public: // posing api - void set_bone_pose(int p_bone, const Transform3D &p_pose); + void set_bone_pose_position(int p_bone, const Vector3 &p_position); + void set_bone_pose_rotation(int p_bone, const Quaternion &p_rotation); + void set_bone_pose_scale(int p_bone, const Vector3 &p_scale); + Transform3D get_bone_pose(int p_bone) const; - void set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose); - Transform3D get_bone_custom_pose(int p_bone) const; + Vector3 get_bone_pose_position(int p_bone) const; + Quaternion get_bone_pose_rotation(int p_bone) const; + Vector3 get_bone_pose_scale(int p_bone) const; void clear_bones_global_pose_override(); Transform3D get_bone_global_pose_override(int p_bone) const; @@ -222,6 +230,8 @@ public: void localize_rests(); // used for loaders and tools + Ref<Skin> create_skin_from_rest_transforms(); + Ref<SkinReference> register_skin(const Ref<Skin> &p_skin); void force_update_all_dirty_bones(); diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp index 9a2aaa8be2..6761fdd944 100644 --- a/scene/3d/vehicle_body_3d.cpp +++ b/scene/3d/vehicle_body_3d.cpp @@ -275,7 +275,7 @@ void VehicleWheel3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_steering"), &VehicleWheel3D::get_steering); ADD_GROUP("Per-Wheel Motion", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, "-1024,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering"); ADD_GROUP("VehicleBody3D Motion", ""); @@ -914,7 +914,7 @@ void VehicleBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_steering"), &VehicleBody3D::get_steering); ADD_GROUP("Motion", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "engine_force", PROPERTY_HINT_RANGE, "-1024,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering"); } diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp deleted file mode 100644 index 56743007e4..0000000000 --- a/scene/animation/animation_cache.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/*************************************************************************/ -/* animation_cache.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "animation_cache.h" - -void AnimationCache::_node_exit_tree(Node *p_node) { - //it is one shot, so it disconnects upon arrival - - ERR_FAIL_COND(!connected_nodes.has(p_node)); - - connected_nodes.erase(p_node); - - for (int i = 0; i < path_cache.size(); i++) { - if (path_cache[i].node != p_node) { - continue; - } - - path_cache.write[i].valid = false; //invalidate path cache - } -} - -void AnimationCache::_animation_changed() { - _clear_cache(); -} - -void AnimationCache::_clear_cache() { - while (connected_nodes.size()) { - connected_nodes.front()->get()->disconnect("tree_exiting", callable_mp(this, &AnimationCache::_node_exit_tree)); - connected_nodes.erase(connected_nodes.front()); - } - path_cache.clear(); - cache_valid = false; - cache_dirty = true; -} - -void AnimationCache::_update_cache() { - cache_valid = false; - - ERR_FAIL_COND(!root); - ERR_FAIL_COND(!root->is_inside_tree()); - ERR_FAIL_COND(animation.is_null()); - - for (int i = 0; i < animation->get_track_count(); i++) { - NodePath np = animation->track_get_path(i); - - Node *node = root->get_node(np); - if (!node) { - path_cache.push_back(Path()); - ERR_CONTINUE_MSG(!node, "Invalid track path in animation '" + np + "'."); - } - - Path path; - - Ref<Resource> res; - - if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM3D) { -#ifndef _3D_DISABLED - if (np.get_subname_count() > 1) { - path_cache.push_back(Path()); - ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM3D, "Transform tracks can't have a subpath '" + np + "'."); - } - - Node3D *sp = Object::cast_to<Node3D>(node); - - if (!sp) { - path_cache.push_back(Path()); - ERR_CONTINUE_MSG(!sp, "Transform track not of type Node3D '" + np + "'."); - } - - if (np.get_subname_count() == 1) { - StringName property = np.get_subname(0); - String ps = property; - - Skeleton3D *sk = Object::cast_to<Skeleton3D>(node); - if (!sk) { - path_cache.push_back(Path()); - ERR_CONTINUE_MSG(!sk, "Property defined in Transform track, but not a Skeleton! '" + np + "'."); - } - - int idx = sk->find_bone(ps); - if (idx == -1) { - path_cache.push_back(Path()); - ERR_CONTINUE_MSG(idx == -1, "Property defined in Transform track, but not a Skeleton Bone! '" + np + "'."); - } - - path.bone_idx = idx; - path.skeleton = sk; - } - - path.node_3d = sp; -#endif // _3D_DISABLED - } else { - if (np.get_subname_count() > 0) { - RES res2; - Vector<StringName> leftover_subpath; - - // We don't want to cache the last resource unless it is a method call - bool is_method = animation->track_get_type(i) == Animation::TYPE_METHOD; - root->get_node_and_resource(np, res2, leftover_subpath, is_method); - - if (res2.is_valid()) { - path.resource = res2; - } else { - path.node = node; - } - path.object = res2.is_valid() ? res2.ptr() : (Object *)node; - path.subpath = leftover_subpath; - - } else { - path.node = node; - path.object = node; - path.subpath = np.get_subnames(); - } - } - - if (animation->track_get_type(i) == Animation::TYPE_VALUE) { - if (np.get_subname_count() == 0) { - path_cache.push_back(Path()); - ERR_CONTINUE_MSG(np.get_subname_count() == 0, "Value Track lacks property: " + np + "."); - } - - } else if (animation->track_get_type(i) == Animation::TYPE_METHOD) { - if (path.subpath.size() != 0) { // Trying to call a method of a non-resource - - path_cache.push_back(Path()); - ERR_CONTINUE_MSG(path.subpath.size() != 0, "Method Track has property: " + np + "."); - } - } - - path.valid = true; - - path_cache.push_back(path); - - if (!connected_nodes.has(path.node)) { - connected_nodes.insert(path.node); - path.node->connect("tree_exiting", callable_mp(this, &AnimationCache::_node_exit_tree), Node::make_binds(path.node), CONNECT_ONESHOT); - } - } - - cache_dirty = false; - cache_valid = true; -} - -void AnimationCache::set_track_transform(int p_idx, const Transform3D &p_transform) { - if (cache_dirty) { - _update_cache(); - } - - ERR_FAIL_COND(!cache_valid); - ERR_FAIL_INDEX(p_idx, path_cache.size()); - Path &p = path_cache.write[p_idx]; - if (!p.valid) { - return; - } - -#ifndef _3D_DISABLED - ERR_FAIL_COND(!p.node); - ERR_FAIL_COND(!p.node_3d); - - if (p.skeleton) { - p.skeleton->set_bone_pose(p.bone_idx, p_transform); - } else { - p.node_3d->set_transform(p_transform); - } -#endif // _3D_DISABLED -} - -void AnimationCache::set_track_value(int p_idx, const Variant &p_value) { - if (cache_dirty) { - _update_cache(); - } - - ERR_FAIL_COND(!cache_valid); - ERR_FAIL_INDEX(p_idx, path_cache.size()); - Path &p = path_cache.write[p_idx]; - if (!p.valid) { - return; - } - - ERR_FAIL_COND(!p.object); - p.object->set_indexed(p.subpath, p_value); -} - -void AnimationCache::call_track(int p_idx, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - if (cache_dirty) { - _update_cache(); - } - - ERR_FAIL_COND(!cache_valid); - ERR_FAIL_INDEX(p_idx, path_cache.size()); - Path &p = path_cache.write[p_idx]; - if (!p.valid) { - return; - } - - ERR_FAIL_COND(!p.object); - p.object->call(p_method, p_args, p_argcount, r_error); -} - -void AnimationCache::set_all(float p_time, float p_delta) { - if (cache_dirty) { - _update_cache(); - } - - ERR_FAIL_COND(!cache_valid); - - int tc = animation->get_track_count(); - for (int i = 0; i < tc; i++) { - switch (animation->track_get_type(i)) { - case Animation::TYPE_TRANSFORM3D: { - Vector3 loc, scale; - Quaternion rot; - animation->transform_track_interpolate(i, p_time, &loc, &rot, &scale); - Transform3D tr(Basis(rot), loc); - tr.basis.scale(scale); - - set_track_transform(i, tr); - - } break; - case Animation::TYPE_VALUE: { - if (animation->value_track_get_update_mode(i) == Animation::UPDATE_CONTINUOUS || (animation->value_track_get_update_mode(i) == Animation::UPDATE_DISCRETE && p_delta == 0)) { - Variant v = animation->value_track_interpolate(i, p_time); - set_track_value(i, v); - } else { - List<int> indices; - animation->value_track_get_key_indices(i, p_time, p_delta, &indices); - - for (int &E : indices) { - Variant v = animation->track_get_key_value(i, E); - set_track_value(i, v); - } - } - - } break; - case Animation::TYPE_METHOD: { - List<int> indices; - animation->method_track_get_key_indices(i, p_time, p_delta, &indices); - - for (int &E : indices) { - Vector<Variant> args = animation->method_track_get_params(i, E); - StringName name = animation->method_track_get_name(i, E); - Callable::CallError err; - - if (!args.size()) { - call_track(i, name, nullptr, 0, err); - } else { - Vector<const Variant *> argptrs; - argptrs.resize(args.size()); - for (int j = 0; j < args.size(); j++) { - argptrs.write[j] = &args.write[j]; - } - - call_track(i, name, (const Variant **)&argptrs[0], args.size(), err); - } - } - - } break; - default: { - } - } - } -} - -void AnimationCache::set_animation(const Ref<Animation> &p_animation) { - _clear_cache(); - - if (animation.is_valid()) { - animation->disconnect("changed", callable_mp(this, &AnimationCache::_animation_changed)); - } - - animation = p_animation; - - if (animation.is_valid()) { - animation->connect("changed", callable_mp(this, &AnimationCache::_animation_changed)); - } -} - -void AnimationCache::_bind_methods() { -} - -void AnimationCache::set_root(Node *p_root) { - _clear_cache(); - root = p_root; -} - -AnimationCache::AnimationCache() { -} diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h deleted file mode 100644 index c856e644f7..0000000000 --- a/scene/animation/animation_cache.h +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************/ -/* animation_cache.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef ANIMATION_CACHE_H -#define ANIMATION_CACHE_H - -#include "scene/3d/skeleton_3d.h" -#include "scene/resources/animation.h" - -class AnimationCache : public Object { - GDCLASS(AnimationCache, Object); - - struct Path { - RES resource; - Object *object = nullptr; -#ifndef _3D_DISABLED - Skeleton3D *skeleton = nullptr; - Node3D *node_3d = nullptr; -#endif // _3D_DISABLED - Node *node = nullptr; - - int bone_idx = -1; - Vector<StringName> subpath; - bool valid = false; - }; - - Set<Node *> connected_nodes; - Vector<Path> path_cache; - - Node *root = nullptr; - Ref<Animation> animation; - bool cache_dirty = true; - bool cache_valid = false; - - void _node_exit_tree(Node *p_node); - - void _clear_cache(); - void _update_cache(); - void _animation_changed(); - -protected: - static void _bind_methods(); - -public: - void set_track_transform(int p_idx, const Transform3D &p_transform); - void set_track_value(int p_idx, const Variant &p_value); - void call_track(int p_idx, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); - - void set_all(float p_time, float p_delta = 0); - - void set_animation(const Ref<Animation> &p_animation); - void set_root(Node *p_root); - - AnimationCache(); -}; - -#endif // ANIMATION_CACHE_H diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 2c8c4ee788..8407e0dd99 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -60,7 +60,12 @@ void AnimatedValuesBackup::restore() const { if (entry->bone_idx == -1) { entry->object->set_indexed(entry->subpath, entry->value); } else { - Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose(entry->bone_idx, entry->value); + Array arr = entry->value; + if (arr.size() == 3) { + Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_position(entry->bone_idx, arr[0]); + Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_rotation(entry->bone_idx, arr[1]); + Object::cast_to<Skeleton3D>(entry->object)->set_bone_pose_scale(entry->bone_idx, arr[0]); + } } } } @@ -242,6 +247,8 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov p_anim->node_cache.resize(a->get_track_count()); + setup_pass++; + for (int i = 0; i < a->get_track_count(); i++) { p_anim->node_cache.write[i] = nullptr; RES resource; @@ -275,46 +282,68 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov node_cache_map[key] = TrackNodeCache(); } - p_anim->node_cache.write[i] = &node_cache_map[key]; - p_anim->node_cache[i]->path = a->track_get_path(i); - p_anim->node_cache[i]->node = child; - p_anim->node_cache[i]->resource = resource; - p_anim->node_cache[i]->node_2d = Object::cast_to<Node2D>(child); + TrackNodeCache *node_cache = &node_cache_map[key]; + p_anim->node_cache.write[i] = node_cache; + + node_cache->path = a->track_get_path(i); + node_cache->node = child; + node_cache->resource = resource; + node_cache->node_2d = Object::cast_to<Node2D>(child); #ifndef _3D_DISABLED - if (a->track_get_type(i) == Animation::TYPE_TRANSFORM3D) { + if (a->track_get_type(i) == Animation::TYPE_POSITION_3D || a->track_get_type(i) == Animation::TYPE_ROTATION_3D || a->track_get_type(i) == Animation::TYPE_SCALE_3D) { // special cases and caches for transform tracks + if (node_cache->last_setup_pass != setup_pass) { + node_cache->loc_used = false; + node_cache->rot_used = false; + node_cache->scale_used = false; + } + // cache node_3d - p_anim->node_cache[i]->node_3d = Object::cast_to<Node3D>(child); + node_cache->node_3d = Object::cast_to<Node3D>(child); // cache skeleton - p_anim->node_cache[i]->skeleton = Object::cast_to<Skeleton3D>(child); - if (p_anim->node_cache[i]->skeleton) { + node_cache->skeleton = Object::cast_to<Skeleton3D>(child); + if (node_cache->skeleton) { if (a->track_get_path(i).get_subname_count() == 1) { StringName bone_name = a->track_get_path(i).get_subname(0); - p_anim->node_cache[i]->bone_idx = p_anim->node_cache[i]->skeleton->find_bone(bone_name); - if (p_anim->node_cache[i]->bone_idx < 0) { + node_cache->bone_idx = node_cache->skeleton->find_bone(bone_name); + if (node_cache->bone_idx < 0) { // broken track (nonexistent bone) - p_anim->node_cache[i]->skeleton = nullptr; - p_anim->node_cache[i]->node_3d = nullptr; - ERR_CONTINUE(p_anim->node_cache[i]->bone_idx < 0); + node_cache->skeleton = nullptr; + node_cache->node_3d = nullptr; + ERR_CONTINUE(node_cache->bone_idx < 0); } } else { // no property, just use spatialnode - p_anim->node_cache[i]->skeleton = nullptr; + node_cache->skeleton = nullptr; + } + } + + switch (a->track_get_type(i)) { + case Animation::TYPE_POSITION_3D: { + node_cache->loc_used = true; + } break; + case Animation::TYPE_ROTATION_3D: { + node_cache->rot_used = true; + } break; + case Animation::TYPE_SCALE_3D: { + node_cache->scale_used = true; + } break; + default: { } } } #endif // _3D_DISABLED if (a->track_get_type(i) == Animation::TYPE_VALUE) { - if (!p_anim->node_cache[i]->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) { + if (!node_cache->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) { TrackNodeCache::PropertyAnim pa; pa.subpath = leftover_path; pa.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child; pa.special = SP_NONE; pa.owner = p_anim->node_cache[i]; - if (false && p_anim->node_cache[i]->node_2d) { + if (false && node_cache->node_2d) { if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_pos) { pa.special = SP_NODE2D_POS; } else if (leftover_path.size() == 1 && leftover_path[0] == SceneStringNames::get_singleton()->transform_rot) { @@ -323,20 +352,22 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov pa.special = SP_NODE2D_SCALE; } } - p_anim->node_cache[i]->property_anim[a->track_get_path(i).get_concatenated_subnames()] = pa; + node_cache->property_anim[a->track_get_path(i).get_concatenated_subnames()] = pa; } } if (a->track_get_type(i) == Animation::TYPE_BEZIER && leftover_path.size()) { - if (!p_anim->node_cache[i]->bezier_anim.has(a->track_get_path(i).get_concatenated_subnames())) { + if (!node_cache->bezier_anim.has(a->track_get_path(i).get_concatenated_subnames())) { TrackNodeCache::BezierAnim ba; ba.bezier_property = leftover_path; ba.object = resource.is_valid() ? (Object *)resource.ptr() : (Object *)child; ba.owner = p_anim->node_cache[i]; - p_anim->node_cache[i]->bezier_anim[a->track_get_path(i).get_concatenated_subnames()] = ba; + node_cache->bezier_anim[a->track_get_path(i).get_concatenated_subnames()] = ba; } } + + node_cache->last_setup_pass = setup_pass; } } @@ -369,17 +400,15 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } switch (a->track_get_type(i)) { - case Animation::TYPE_TRANSFORM3D: { + case Animation::TYPE_POSITION_3D: { #ifndef _3D_DISABLED if (!nc->node_3d) { continue; } Vector3 loc; - Quaternion rot; - Vector3 scale; - Error err = a->transform_track_interpolate(i, p_time, &loc, &rot, &scale); + Error err = a->position_track_interpolate(i, p_time, &loc); //ERR_CONTINUE(err!=OK); //used for testing, should be removed if (err != OK) { @@ -391,12 +420,63 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double cache_update[cache_update_size++] = nc; nc->accum_pass = accum_pass; nc->loc_accum = loc; - nc->rot_accum = rot; - nc->scale_accum = scale; - + nc->rot_accum = Quaternion(); + nc->scale_accum = Vector3(); } else { nc->loc_accum = nc->loc_accum.lerp(loc, p_interp); + } +#endif // _3D_DISABLED + } break; + case Animation::TYPE_ROTATION_3D: { +#ifndef _3D_DISABLED + if (!nc->node_3d) { + continue; + } + + Quaternion rot; + + Error err = a->rotation_track_interpolate(i, p_time, &rot); + //ERR_CONTINUE(err!=OK); //used for testing, should be removed + + if (err != OK) { + continue; + } + + if (nc->accum_pass != accum_pass) { + ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX); + cache_update[cache_update_size++] = nc; + nc->accum_pass = accum_pass; + nc->loc_accum = Vector3(); + nc->rot_accum = rot; + nc->scale_accum = Vector3(); + } else { nc->rot_accum = nc->rot_accum.slerp(rot, p_interp); + } +#endif // _3D_DISABLED + } break; + case Animation::TYPE_SCALE_3D: { +#ifndef _3D_DISABLED + if (!nc->node_3d) { + continue; + } + + Vector3 scale; + + Error err = a->scale_track_interpolate(i, p_time, &scale); + //ERR_CONTINUE(err!=OK); //used for testing, should be removed + + if (err != OK) { + continue; + } + + if (nc->accum_pass != accum_pass) { + ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX); + cache_update[cache_update_size++] = nc; + nc->accum_pass = accum_pass; + nc->loc_accum = Vector3(); + nc->rot_accum = Quaternion(); + nc->scale_accum = scale; + } else { nc->scale_accum = nc->scale_accum.lerp(scale, p_interp); } #endif // _3D_DISABLED @@ -855,15 +935,30 @@ void AnimationPlayer::_animation_update_transforms() { TrackNodeCache *nc = cache_update[i]; ERR_CONTINUE(nc->accum_pass != accum_pass); - - t.origin = nc->loc_accum; - t.basis.set_quaternion_scale(nc->rot_accum, nc->scale_accum); #ifndef _3D_DISABLED if (nc->skeleton && nc->bone_idx >= 0) { - nc->skeleton->set_bone_pose(nc->bone_idx, t); + if (nc->loc_used) { + nc->skeleton->set_bone_pose_position(nc->bone_idx, nc->loc_accum); + } + if (nc->rot_used) { + nc->skeleton->set_bone_pose_rotation(nc->bone_idx, nc->rot_accum); + } + if (nc->scale_used) { + nc->skeleton->set_bone_pose_scale(nc->bone_idx, nc->scale_accum); + } + } else if (nc->node_3d) { - nc->node_3d->set_transform(t); + if (nc->loc_used) { + nc->node_3d->set_position(nc->loc_accum); + } + if (nc->rot_used) { + nc->node_3d->set_rotation(nc->rot_accum.get_euler()); + } + if (nc->scale_used) { + nc->node_3d->set_scale(nc->scale_accum); + } } + #endif // _3D_DISABLED } } @@ -1527,7 +1622,12 @@ Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values(Node *p_root_o AnimatedValuesBackup::Entry entry; entry.object = nc->skeleton; entry.bone_idx = nc->bone_idx; - entry.value = nc->skeleton->get_bone_pose(nc->bone_idx); + Array arr; + arr.resize(3); + arr[0] = nc->skeleton->get_bone_pose_position(nc->bone_idx); + arr[1] = nc->skeleton->get_bone_pose_rotation(nc->bone_idx); + arr[2] = nc->skeleton->get_bone_pose_scale(nc->bone_idx); + entry.value = nc; backup->entries.push_back(entry); } else { if (nc->node_3d) { diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index b693e29bdf..f8e72a67b6 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -88,6 +88,8 @@ private: SP_NODE2D_SCALE, }; + uint32_t setup_pass = 1; + struct TrackNodeCache { NodePath path; uint32_t id = 0; @@ -101,6 +103,10 @@ private: int bone_idx = -1; // accumulated transforms + bool loc_used = false; + bool rot_used = false; + bool scale_used = false; + Vector3 loc_accum; Quaternion rot_accum; Vector3 scale_accum; @@ -134,6 +140,7 @@ private: Map<StringName, BezierAnim> bezier_anim; + uint32_t last_setup_pass = 0; TrackNodeCache() {} }; diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 9ca8d478b1..dd5fe46223 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -544,13 +544,18 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { NodePath path = anim->track_get_path(i); Animation::TrackType track_type = anim->track_get_type(i); + Animation::TrackType track_cache_type = track_type; + if (track_cache_type == Animation::TYPE_POSITION_3D || track_cache_type == Animation::TYPE_ROTATION_3D || track_cache_type == Animation::TYPE_SCALE_3D) { + track_cache_type = Animation::TYPE_POSITION_3D; //reference them as position3D tracks, even if they modify rotation or scale + } + TrackCache *track = nullptr; if (track_cache.has(path)) { track = track_cache.get(path); } //if not valid, delete track - if (track && (track->type != track_type || ObjectDB::get_instance(track->object_id) == nullptr)) { + if (track && (track->type != track_cache_type || ObjectDB::get_instance(track->object_id) == nullptr)) { playing_caches.erase(track); memdelete(track); track_cache.erase(path); @@ -587,7 +592,9 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { track = track_value; } break; - case Animation::TYPE_TRANSFORM3D: { + case Animation::TYPE_POSITION_3D: + case Animation::TYPE_ROTATION_3D: + case Animation::TYPE_SCALE_3D: { #ifndef _3D_DISABLED Node3D *node_3d = Object::cast_to<Node3D>(child); @@ -597,6 +604,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { } TrackCacheTransform *track_xform = memnew(TrackCacheTransform); + track_xform->type = Animation::TYPE_POSITION_3D; track_xform->node_3d = node_3d; track_xform->skeleton = nullptr; @@ -615,6 +623,21 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { track_xform->object_id = track_xform->object->get_instance_id(); track = track_xform; + + switch (track_type) { + case Animation::TYPE_POSITION_3D: { + track_xform->loc_used = true; + } break; + case Animation::TYPE_ROTATION_3D: { + track_xform->rot_used = true; + } break; + case Animation::TYPE_SCALE_3D: { + track_xform->scale_used = true; + } break; + default: { + } + } + #endif // _3D_DISABLED } break; case Animation::TYPE_METHOD: { @@ -670,6 +693,26 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { } track_cache[path] = track; + } else if (track_cache_type == Animation::TYPE_POSITION_3D) { + TrackCacheTransform *track_xform = static_cast<TrackCacheTransform *>(track); + if (track->setup_pass != setup_pass) { + track_xform->loc_used = false; + track_xform->rot_used = false; + track_xform->scale_used = false; + } + switch (track_type) { + case Animation::TYPE_POSITION_3D: { + track_xform->loc_used = true; + } break; + case Animation::TYPE_ROTATION_3D: { + track_xform->rot_used = true; + } break; + case Animation::TYPE_SCALE_3D: { + track_xform->scale_used = true; + } break; + default: { + } + } } track->setup_pass = setup_pass; @@ -831,8 +874,11 @@ void AnimationTree::_process_graph(real_t p_delta) { ERR_CONTINUE(!track_cache.has(path)); TrackCache *track = track_cache[path]; - if (track->type != a->track_get_type(i)) { - continue; //may happen should not + + Animation::TrackType ttype = a->track_get_type(i); + if (ttype != Animation::TYPE_POSITION_3D && ttype != Animation::TYPE_ROTATION_3D && ttype != Animation::TYPE_SCALE_3D && track->type != ttype) { + //broken animation, but avoid error spamming + continue; } track->root_motion = root_motion_track == path; @@ -848,20 +894,81 @@ void AnimationTree::_process_graph(real_t p_delta) { continue; //nothing to blend } - switch (track->type) { - case Animation::TYPE_TRANSFORM3D: { + switch (ttype) { + case Animation::TYPE_POSITION_3D: { #ifndef _3D_DISABLED TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); + if (t->process_pass != process_pass) { + t->process_pass = process_pass; + t->loc = Vector3(); + t->rot = Quaternion(); + t->rot_blend_accum = 0; + t->scale = Vector3(1, 1, 1); + } + if (track->root_motion) { - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->loc = Vector3(); - t->rot = Quaternion(); - t->rot_blend_accum = 0; - t->scale = Vector3(1, 1, 1); + real_t prev_time = time - delta; + if (prev_time < 0) { + if (!a->has_loop()) { + prev_time = 0; + } else { + prev_time = a->get_length() + prev_time; + } } + Vector3 loc[2]; + + if (prev_time > time) { + Error err = a->position_track_interpolate(i, prev_time, &loc[0]); + if (err != OK) { + continue; + } + + a->position_track_interpolate(i, a->get_length(), &loc[1]); + + t->loc += (loc[1] - loc[0]) * blend; + prev_time = 0; + } + + Error err = a->position_track_interpolate(i, prev_time, &loc[0]); + if (err != OK) { + continue; + } + + a->position_track_interpolate(i, time, &loc[1]); + + t->loc += (loc[1] - loc[0]) * blend; + + prev_time = 0; + + } else { + Vector3 loc; + + Error err = a->position_track_interpolate(i, time, &loc); + //ERR_CONTINUE(err!=OK); //used for testing, should be removed + + if (err != OK) { + continue; + } + + t->loc = t->loc.lerp(loc, blend); + } +#endif // _3D_DISABLED + } break; + case Animation::TYPE_ROTATION_3D: { +#ifndef _3D_DISABLED + TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); + + if (t->process_pass != process_pass) { + t->process_pass = process_pass; + t->loc = Vector3(); + t->rot = Quaternion(); + t->rot_blend_accum = 0; + t->scale = Vector3(1, 1, 1); + } + + if (track->root_motion) { real_t prev_time = time - delta; if (prev_time < 0) { if (!a->has_loop()) { @@ -871,61 +978,44 @@ void AnimationTree::_process_graph(real_t p_delta) { } } - Vector3 loc[2]; Quaternion rot[2]; - Vector3 scale[2]; if (prev_time > time) { - Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]); + Error err = a->rotation_track_interpolate(i, prev_time, &rot[0]); if (err != OK) { continue; } - a->transform_track_interpolate(i, a->get_length(), &loc[1], &rot[1], &scale[1]); + a->rotation_track_interpolate(i, a->get_length(), &rot[1]); - t->loc += (loc[1] - loc[0]) * blend; - t->scale += (scale[1] - scale[0]) * blend; Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); t->rot = (t->rot * q).normalized(); prev_time = 0; } - Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]); + Error err = a->rotation_track_interpolate(i, prev_time, &rot[0]); if (err != OK) { continue; } - a->transform_track_interpolate(i, time, &loc[1], &rot[1], &scale[1]); + a->rotation_track_interpolate(i, time, &rot[1]); - t->loc += (loc[1] - loc[0]) * blend; - t->scale += (scale[1] - scale[0]) * blend; Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); t->rot = (t->rot * q).normalized(); prev_time = 0; } else { - Vector3 loc; Quaternion rot; - Vector3 scale; - Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale); + Error err = a->rotation_track_interpolate(i, time, &rot); //ERR_CONTINUE(err!=OK); //used for testing, should be removed - if (t->process_pass != process_pass) { - t->process_pass = process_pass; - t->loc = loc; - t->rot = rot; - t->rot_blend_accum = 0; - t->scale = scale; - } - if (err != OK) { continue; } - t->loc = t->loc.lerp(loc, blend); if (t->rot_blend_accum == 0) { t->rot = rot; t->rot_blend_accum = blend; @@ -934,6 +1024,67 @@ void AnimationTree::_process_graph(real_t p_delta) { t->rot = rot.slerp(t->rot, t->rot_blend_accum / rot_total).normalized(); t->rot_blend_accum = rot_total; } + } +#endif // _3D_DISABLED + } break; + case Animation::TYPE_SCALE_3D: { +#ifndef _3D_DISABLED + TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); + + if (t->process_pass != process_pass) { + t->process_pass = process_pass; + t->loc = Vector3(); + t->rot = Quaternion(); + t->rot_blend_accum = 0; + t->scale = Vector3(1, 1, 1); + } + + if (track->root_motion) { + real_t prev_time = time - delta; + if (prev_time < 0) { + if (!a->has_loop()) { + prev_time = 0; + } else { + prev_time = a->get_length() + prev_time; + } + } + + Vector3 scale[2]; + + if (prev_time > time) { + Error err = a->scale_track_interpolate(i, prev_time, &scale[0]); + if (err != OK) { + continue; + } + + a->scale_track_interpolate(i, a->get_length(), &scale[1]); + + t->scale += (scale[1] - scale[0]) * blend; + + prev_time = 0; + } + + Error err = a->scale_track_interpolate(i, prev_time, &scale[0]); + if (err != OK) { + continue; + } + + a->scale_track_interpolate(i, time, &scale[1]); + + t->scale += (scale[1] - scale[0]) * blend; + + prev_time = 0; + + } else { + Vector3 scale; + + Error err = a->scale_track_interpolate(i, time, &scale); + //ERR_CONTINUE(err!=OK); //used for testing, should be removed + + if (err != OK) { + continue; + } + t->scale = t->scale.lerp(scale, blend); } #endif // _3D_DISABLED @@ -1198,26 +1349,38 @@ void AnimationTree::_process_graph(real_t p_delta) { } switch (track->type) { - case Animation::TYPE_TRANSFORM3D: { + case Animation::TYPE_POSITION_3D: { #ifndef _3D_DISABLED TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); - Transform3D xform; - xform.origin = t->loc; - - xform.basis.set_quaternion_scale(t->rot, t->scale); - if (t->root_motion) { + Transform3D xform; + xform.origin = t->loc; + xform.basis.set_quaternion_scale(t->rot, t->scale); + root_motion_transform = xform; - if (t->skeleton && t->bone_idx >= 0) { - root_motion_transform = (t->skeleton->get_bone_rest(t->bone_idx) * root_motion_transform) * t->skeleton->get_bone_rest(t->bone_idx).affine_inverse(); - } } else if (t->skeleton && t->bone_idx >= 0) { - t->skeleton->set_bone_pose(t->bone_idx, xform); + if (t->loc_used) { + t->skeleton->set_bone_pose_position(t->bone_idx, t->loc); + } + if (t->rot_used) { + t->skeleton->set_bone_pose_rotation(t->bone_idx, t->rot); + } + if (t->scale_used) { + t->skeleton->set_bone_pose_scale(t->bone_idx, t->scale); + } } else if (!t->skeleton) { - t->node_3d->set_transform(xform); + if (t->loc_used) { + t->node_3d->set_position(t->loc); + } + if (t->rot_used) { + t->node_3d->set_rotation(t->rot.get_euler()); + } + if (t->scale_used) { + t->node_3d->set_scale(t->scale); + } } #endif // _3D_DISABLED } break; diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 1e0267682e..ed207dfe0c 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -197,13 +197,16 @@ private: Skeleton3D *skeleton = nullptr; #endif // _3D_DISABLED int bone_idx = -1; + bool loc_used = false; + bool rot_used = false; + bool scale_used = false; Vector3 loc; Quaternion rot; real_t rot_blend_accum = 0.0; Vector3 scale; TrackCacheTransform() { - type = Animation::TYPE_TRANSFORM3D; + type = Animation::TYPE_POSITION_3D; } }; diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 0334ba667b..d2fd65d3d9 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -135,7 +135,7 @@ void AudioStreamPlayer::play(float p_from_pos) { Ref<AudioStreamPlayback> stream_playback = stream->instance_playback(); ERR_FAIL_COND_MSG(stream_playback.is_null(), "Failed to instantiate playback."); - AudioServer::get_singleton()->start_playback_stream(stream_playback, bus, _get_volume_vector(), p_from_pos); + AudioServer::get_singleton()->start_playback_stream(stream_playback, bus, _get_volume_vector(), p_from_pos, pitch_scale); stream_playbacks.push_back(stream_playback); active.set(); set_process_internal(true); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 653885aa08..54e7d8f960 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -241,7 +241,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { _reset_caret_blink_timer(); if (b->is_pressed()) { - accept_event(); //don't pass event further when clicked on text field + accept_event(); // don't pass event further when clicked on text field if (!text.is_empty() && is_editable() && _is_over_clear_button(b->get_position())) { clear_button_status.press_attempt = true; clear_button_status.pressing_inside = true; @@ -1931,7 +1931,7 @@ void LineEdit::_shape() { TS->shaped_text_clear(text_rid); String t; - if (text.length() == 0) { + if (text.length() == 0 && ime_text.length() == 0) { t = placeholder_translated; } else if (pass) { t = secret_character.repeat(text.length() + ime_text.length()); diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp index 35a098c6fd..fe11de128a 100644 --- a/scene/gui/texture_progress_bar.cpp +++ b/scene/gui/texture_progress_bar.cpp @@ -341,7 +341,11 @@ void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_textu } break; case FILL_BILINEAR_LEFT_AND_RIGHT: { double center_mapped_from_real_width = (width_total * 0.5 - topleft.x) / max_middle_real_size * max_middle_texture_size + topleft.x; - double drift_from_unscaled_center = (src_rect.size.x * 0.5 - center_mapped_from_real_width) * (last_section_size - first_section_size) / (bottomright.x - topleft.x); + double drift_from_unscaled_center = 0; + if (bottomright.y != topleft.y) { // To avoid division by zero. + drift_from_unscaled_center = (src_rect.size.x * 0.5 - center_mapped_from_real_width) * (last_section_size - first_section_size) / (bottomright.x - topleft.x); + } + src_rect.position.x += center_mapped_from_real_width + drift_from_unscaled_center - width_texture * 0.5; src_rect.size.x = width_texture; dst_rect.position.x += (width_total - width_filled) * 0.5; @@ -351,7 +355,11 @@ void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_textu } break; case FILL_BILINEAR_TOP_AND_BOTTOM: { double center_mapped_from_real_width = (width_total * 0.5 - topleft.y) / max_middle_real_size * max_middle_texture_size + topleft.y; - double drift_from_unscaled_center = (src_rect.size.y * 0.5 - center_mapped_from_real_width) * (last_section_size - first_section_size) / (bottomright.y - topleft.y); + double drift_from_unscaled_center = 0; + if (bottomright.y != topleft.y) { // To avoid division by zero. + drift_from_unscaled_center = (src_rect.size.y * 0.5 - center_mapped_from_real_width) * (last_section_size - first_section_size) / (bottomright.y - topleft.y); + } + src_rect.position.y += center_mapped_from_real_width + drift_from_unscaled_center - width_texture * 0.5; src_rect.size.y = width_texture; dst_rect.position.y += (width_total - width_filled) * 0.5; diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp index 8734037a57..989aabc549 100644 --- a/scene/gui/video_player.cpp +++ b/scene/gui/video_player.cpp @@ -29,9 +29,9 @@ /*************************************************************************/ #include "video_player.h" -#include "scene/scene_string_names.h" #include "core/os/os.h" +#include "scene/scene_string_names.h" #include "servers/audio_server.h" int VideoPlayer::sp_get_channel_count() const { @@ -55,7 +55,7 @@ bool VideoPlayer::mix(AudioFrame *p_buffer, int p_frames) { return false; } -// Called from main thread (eg VideoStreamPlaybackWebm::update) +// Called from main thread (e.g. VideoStreamPlaybackTheora::update). int VideoPlayer::_audio_mix_callback(void *p_udata, const float *p_data, int p_frames) { ERR_FAIL_NULL_V(p_udata, 0); ERR_FAIL_NULL_V(p_data, 0); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 2982e33fcf..0e62e6e30a 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2881,9 +2881,8 @@ bool Viewport::gui_is_dragging() const { void Viewport::set_input_as_handled() { _drop_physics_mouseover(); - if (handle_input_locally) { - local_input_handled = true; - } else { + + if (!handle_input_locally) { ERR_FAIL_COND(!is_inside_tree()); Viewport *vp = this; while (true) { @@ -2895,16 +2894,19 @@ void Viewport::set_input_as_handled() { } vp = vp->get_parent()->get_viewport(); } - vp->set_input_as_handled(); + if (vp != this) { + vp->set_input_as_handled(); + return; + } } + + local_input_handled = true; } bool Viewport::is_input_handled() const { - if (handle_input_locally) { - return local_input_handled; - } else { - const Viewport *vp = this; + if (!handle_input_locally) { ERR_FAIL_COND_V(!is_inside_tree(), false); + const Viewport *vp = this; while (true) { if (Object::cast_to<Window>(vp)) { break; @@ -2914,8 +2916,11 @@ bool Viewport::is_input_handled() const { } vp = vp->get_parent()->get_viewport(); } - return vp->is_input_handled(); + if (vp != this) { + return vp->is_input_handled(); + } } + return local_input_handled; } void Viewport::set_handle_input_locally(bool p_enable) { diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index b4eec2530b..6612c5ff3c 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -43,8 +43,12 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { if (tracks.size() == track && what == "type") { String type = p_value; - if (type == "transform" || type == "transform3d") { - add_track(TYPE_TRANSFORM3D); + if (type == "position_3d") { + add_track(TYPE_POSITION_3D); + } else if (type == "rotation_3d") { + add_track(TYPE_ROTATION_3D); + } else if (type == "scale_3d") { + add_track(TYPE_SCALE_3D); } else if (type == "value") { add_track(TYPE_VALUE); } else if (type == "method") { @@ -75,35 +79,72 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { } else if (what == "enabled") { track_set_enabled(track, p_value); } else if (what == "keys" || what == "key_values") { - if (track_get_type(track) == TYPE_TRANSFORM3D) { - TransformTrack *tt = static_cast<TransformTrack *>(tracks[track]); + if (track_get_type(track) == TYPE_POSITION_3D) { + PositionTrack *tt = static_cast<PositionTrack *>(tracks[track]); Vector<real_t> values = p_value; int vcount = values.size(); - ERR_FAIL_COND_V(vcount % TRANSFORM_TRACK_SIZE, false); + ERR_FAIL_COND_V(vcount % POSITION_TRACK_SIZE, false); const real_t *r = values.ptr(); - int64_t count = vcount / TRANSFORM_TRACK_SIZE; - tt->transforms.resize(count); + int64_t count = vcount / POSITION_TRACK_SIZE; + tt->positions.resize(count); + TKey<Vector3> *tw = tt->positions.ptrw(); for (int i = 0; i < count; i++) { - TKey<TransformKey> &tk = tt->transforms.write[i]; - const real_t *ofs = &r[i * TRANSFORM_TRACK_SIZE]; + TKey<Vector3> &tk = tw[i]; + const real_t *ofs = &r[i * POSITION_TRACK_SIZE]; tk.time = ofs[0]; tk.transition = ofs[1]; - tk.value.loc.x = ofs[2]; - tk.value.loc.y = ofs[3]; - tk.value.loc.z = ofs[4]; + tk.value.x = ofs[2]; + tk.value.y = ofs[3]; + tk.value.z = ofs[4]; + } + } else if (track_get_type(track) == TYPE_ROTATION_3D) { + RotationTrack *rt = static_cast<RotationTrack *>(tracks[track]); + Vector<real_t> values = p_value; + int vcount = values.size(); + ERR_FAIL_COND_V(vcount % ROTATION_TRACK_SIZE, false); + + const real_t *r = values.ptr(); + + int64_t count = vcount / ROTATION_TRACK_SIZE; + rt->rotations.resize(count); + + TKey<Quaternion> *rw = rt->rotations.ptrw(); + for (int i = 0; i < count; i++) { + TKey<Quaternion> &rk = rw[i]; + const real_t *ofs = &r[i * ROTATION_TRACK_SIZE]; + rk.time = ofs[0]; + rk.transition = ofs[1]; + + rk.value.x = ofs[2]; + rk.value.y = ofs[3]; + rk.value.z = ofs[4]; + rk.value.w = ofs[5]; + } + } else if (track_get_type(track) == TYPE_SCALE_3D) { + ScaleTrack *st = static_cast<ScaleTrack *>(tracks[track]); + Vector<real_t> values = p_value; + int vcount = values.size(); + ERR_FAIL_COND_V(vcount % SCALE_TRACK_SIZE, false); - tk.value.rot.x = ofs[5]; - tk.value.rot.y = ofs[6]; - tk.value.rot.z = ofs[7]; - tk.value.rot.w = ofs[8]; + const real_t *r = values.ptr(); + + int64_t count = vcount / SCALE_TRACK_SIZE; + st->scales.resize(count); - tk.value.scale.x = ofs[9]; - tk.value.scale.y = ofs[10]; - tk.value.scale.z = ofs[11]; + TKey<Vector3> *sw = st->scales.ptrw(); + for (int i = 0; i < count; i++) { + TKey<Vector3> &sk = sw[i]; + const real_t *ofs = &r[i * SCALE_TRACK_SIZE]; + sk.time = ofs[0]; + sk.transition = ofs[1]; + + sk.value.x = ofs[2]; + sk.value.y = ofs[3]; + sk.value.z = ofs[4]; } } else if (track_get_type(track) == TYPE_VALUE) { @@ -319,8 +360,14 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { ERR_FAIL_INDEX_V(track, tracks.size(), false); if (what == "type") { switch (track_get_type(track)) { - case TYPE_TRANSFORM3D: - r_ret = "transform"; + case TYPE_POSITION_3D: + r_ret = "position_3d"; + break; + case TYPE_ROTATION_3D: + r_ret = "rotation_3d"; + break; + case TYPE_SCALE_3D: + r_ret = "scale_3d"; break; case TYPE_VALUE: r_ret = "value"; @@ -352,31 +399,64 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { } else if (what == "enabled") { r_ret = track_is_enabled(track); } else if (what == "keys") { - if (track_get_type(track) == TYPE_TRANSFORM3D) { + if (track_get_type(track) == TYPE_POSITION_3D) { Vector<real_t> keys; int kk = track_get_key_count(track); - keys.resize(kk * TRANSFORM_TRACK_SIZE); + keys.resize(kk * POSITION_TRACK_SIZE); real_t *w = keys.ptrw(); int idx = 0; for (int i = 0; i < track_get_key_count(track); i++) { Vector3 loc; - Quaternion rot; - Vector3 scale; - transform_track_get_key(track, i, &loc, &rot, &scale); + position_track_get_key(track, i, &loc); w[idx++] = track_get_key_time(track, i); w[idx++] = track_get_key_transition(track, i); w[idx++] = loc.x; w[idx++] = loc.y; w[idx++] = loc.z; + } + r_ret = keys; + return true; + } else if (track_get_type(track) == TYPE_ROTATION_3D) { + Vector<real_t> keys; + int kk = track_get_key_count(track); + keys.resize(kk * ROTATION_TRACK_SIZE); + + real_t *w = keys.ptrw(); + + int idx = 0; + for (int i = 0; i < track_get_key_count(track); i++) { + Quaternion rot; + rotation_track_get_key(track, i, &rot); + + w[idx++] = track_get_key_time(track, i); + w[idx++] = track_get_key_transition(track, i); w[idx++] = rot.x; w[idx++] = rot.y; w[idx++] = rot.z; w[idx++] = rot.w; + } + r_ret = keys; + return true; + + } else if (track_get_type(track) == TYPE_SCALE_3D) { + Vector<real_t> keys; + int kk = track_get_key_count(track); + keys.resize(kk * SCALE_TRACK_SIZE); + + real_t *w = keys.ptrw(); + + int idx = 0; + for (int i = 0; i < track_get_key_count(track); i++) { + Vector3 scale; + scale_track_get_key(track, i, &scale); + + w[idx++] = track_get_key_time(track, i); + w[idx++] = track_get_key_transition(track, i); w[idx++] = scale.x; w[idx++] = scale.y; w[idx++] = scale.z; @@ -384,7 +464,6 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { r_ret = keys; return true; - } else if (track_get_type(track) == TYPE_VALUE) { const ValueTrack *vt = static_cast<const ValueTrack *>(tracks[track]); @@ -591,10 +670,18 @@ int Animation::add_track(TrackType p_type, int p_at_pos) { } switch (p_type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = memnew(TransformTrack); + case TYPE_POSITION_3D: { + PositionTrack *tt = memnew(PositionTrack); tracks.insert(p_at_pos, tt); } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = memnew(RotationTrack); + tracks.insert(p_at_pos, rt); + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = memnew(ScaleTrack); + tracks.insert(p_at_pos, st); + } break; case TYPE_VALUE: { tracks.insert(p_at_pos, memnew(ValueTrack)); @@ -629,9 +716,19 @@ void Animation::remove_track(int p_track) { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - _clear(tt->transforms); + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + _clear(tt->positions); + + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + _clear(rt->rotations); + + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + _clear(st->scales); } break; case TYPE_VALUE: { @@ -672,7 +769,7 @@ int Animation::get_track_count() const { } Animation::TrackType Animation::track_get_type(int p_track) const { - ERR_FAIL_INDEX_V(p_track, tracks.size(), TYPE_TRANSFORM3D); + ERR_FAIL_INDEX_V(p_track, tracks.size(), TYPE_VALUE); return tracks[p_track]->type; } @@ -720,31 +817,6 @@ bool Animation::track_get_interpolation_loop_wrap(int p_track) const { return tracks[p_track]->loop_wrap; } -// transform -/* -template<class T> -int Animation::_insert_pos(double p_time, T& p_keys) { - // simple, linear time inset that should be fast enough in reality. - - int idx=p_keys.size(); - - while(true) { - - - if (idx==0 || p_keys[idx-1].time < p_time) { - //condition for insertion. - p_keys.insert(idx,T()); - return idx; - } else if (p_keys[idx-1].time == p_time) { - // condition for replacing. - return idx-1; - } - - idx--; - } -} - -*/ template <class T, class V> int Animation::_insert(double p_time, T &p_keys, const V &p_value) { int idx = p_keys.size(); @@ -774,45 +846,153 @@ void Animation::_clear(T &p_keys) { p_keys.clear(); } -Error Animation::transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const { +//// + +int Animation::position_track_insert_key(int p_track, double p_time, const Vector3 &p_position) { + ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_POSITION_3D, -1); + + PositionTrack *tt = static_cast<PositionTrack *>(t); + + TKey<Vector3> tkey; + tkey.time = p_time; + tkey.value = p_position; + + int ret = _insert(p_time, tt->positions, tkey); + emit_changed(); + return ret; +} + +Error Animation::position_track_get_key(int p_track, int p_key, Vector3 *r_position) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); Track *t = tracks[p_track]; - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, ERR_INVALID_PARAMETER); - ERR_FAIL_INDEX_V(p_key, tt->transforms.size(), ERR_INVALID_PARAMETER); + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_COND_V(t->type != TYPE_POSITION_3D, ERR_INVALID_PARAMETER); + ERR_FAIL_INDEX_V(p_key, tt->positions.size(), ERR_INVALID_PARAMETER); - if (r_loc) { - *r_loc = tt->transforms[p_key].value.loc; - } - if (r_rot) { - *r_rot = tt->transforms[p_key].value.rot; - } - if (r_scale) { - *r_scale = tt->transforms[p_key].value.scale; + *r_position = tt->positions[p_key].value; + + return OK; +} + +Error Animation::position_track_interpolate(int p_track, double p_time, Vector3 *r_interpolation) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_POSITION_3D, ERR_INVALID_PARAMETER); + + PositionTrack *tt = static_cast<PositionTrack *>(t); + + bool ok = false; + + Vector3 tk = _interpolate(tt->positions, p_time, tt->interpolation, tt->loop_wrap, &ok); + + if (!ok) { + return ERR_UNAVAILABLE; } + *r_interpolation = tk; + return OK; +} + +//// + +int Animation::rotation_track_insert_key(int p_track, double p_time, const Quaternion &p_rotation) { + ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_ROTATION_3D, -1); + + RotationTrack *rt = static_cast<RotationTrack *>(t); + + TKey<Quaternion> tkey; + tkey.time = p_time; + tkey.value = p_rotation; + + int ret = _insert(p_time, rt->rotations, tkey); + emit_changed(); + return ret; +} + +Error Animation::rotation_track_get_key(int p_track, int p_key, Quaternion *r_rotation) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_COND_V(t->type != TYPE_ROTATION_3D, ERR_INVALID_PARAMETER); + ERR_FAIL_INDEX_V(p_key, rt->rotations.size(), ERR_INVALID_PARAMETER); + + *r_rotation = rt->rotations[p_key].value; return OK; } -int Animation::transform_track_insert_key(int p_track, double p_time, const Vector3 &p_loc, const Quaternion &p_rot, const Vector3 &p_scale) { +Error Animation::rotation_track_interpolate(int p_track, double p_time, Quaternion *r_interpolation) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_ROTATION_3D, ERR_INVALID_PARAMETER); + + RotationTrack *rt = static_cast<RotationTrack *>(t); + + bool ok = false; + + Quaternion tk = _interpolate(rt->rotations, p_time, rt->interpolation, rt->loop_wrap, &ok); + + if (!ok) { + return ERR_UNAVAILABLE; + } + *r_interpolation = tk; + return OK; +} + +//// + +int Animation::scale_track_insert_key(int p_track, double p_time, const Vector3 &p_scale) { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; - ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, -1); + ERR_FAIL_COND_V(t->type != TYPE_SCALE_3D, -1); - TransformTrack *tt = static_cast<TransformTrack *>(t); + ScaleTrack *st = static_cast<ScaleTrack *>(t); - TKey<TransformKey> tkey; + TKey<Vector3> tkey; tkey.time = p_time; - tkey.value.loc = p_loc; - tkey.value.rot = p_rot; - tkey.value.scale = p_scale; + tkey.value = p_scale; - int ret = _insert(p_time, tt->transforms, tkey); + int ret = _insert(p_time, st->scales, tkey); emit_changed(); return ret; } +Error Animation::scale_track_get_key(int p_track, int p_key, Vector3 *r_scale) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_COND_V(t->type != TYPE_SCALE_3D, ERR_INVALID_PARAMETER); + ERR_FAIL_INDEX_V(p_key, st->scales.size(), ERR_INVALID_PARAMETER); + + *r_scale = st->scales[p_key].value; + + return OK; +} + +Error Animation::scale_track_interpolate(int p_track, double p_time, Vector3 *r_interpolation) const { + ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); + Track *t = tracks[p_track]; + ERR_FAIL_COND_V(t->type != TYPE_SCALE_3D, ERR_INVALID_PARAMETER); + + ScaleTrack *st = static_cast<ScaleTrack *>(t); + + bool ok = false; + + Vector3 tk = _interpolate(st->scales, p_time, st->interpolation, st->loop_wrap, &ok); + + if (!ok) { + return ERR_UNAVAILABLE; + } + *r_interpolation = tk; + return OK; +} + void Animation::track_remove_key_at_time(int p_track, double p_time) { int idx = track_find_key(p_track, p_time, true); ERR_FAIL_COND(idx < 0); @@ -824,10 +1004,22 @@ void Animation::track_remove_key(int p_track, int p_idx) { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX(p_idx, tt->transforms.size()); - tt->transforms.remove(p_idx); + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX(p_idx, tt->positions.size()); + tt->positions.remove(p_idx); + + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX(p_idx, rt->rotations.size()); + rt->rotations.remove(p_idx); + + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX(p_idx, st->scales.size()); + st->scales.remove(p_idx); } break; case TYPE_VALUE: { @@ -870,13 +1062,37 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - int k = _find(tt->transforms, p_time); - if (k < 0 || k >= tt->transforms.size()) { + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + int k = _find(tt->positions, p_time); + if (k < 0 || k >= tt->positions.size()) { return -1; } - if (tt->transforms[k].time != p_time && p_exact) { + if (tt->positions[k].time != p_time && p_exact) { + return -1; + } + return k; + + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + int k = _find(rt->rotations, p_time); + if (k < 0 || k >= rt->rotations.size()) { + return -1; + } + if (rt->rotations[k].time != p_time && p_exact) { + return -1; + } + return k; + + } break; + case TYPE_SCALE_3D: { + ScaleTrack *rt = static_cast<ScaleTrack *>(t); + int k = _find(rt->scales, p_time); + if (k < 0 || k >= rt->scales.size()) { + return -1; + } + if (rt->scales[k].time != p_time && p_exact) { return -1; } return k; @@ -952,24 +1168,21 @@ void Animation::track_insert_key(int p_track, double p_time, const Variant &p_ke Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - Dictionary d = p_key; - Vector3 loc; - if (d.has("location")) { - loc = d["location"]; - } - - Quaternion rot; - if (d.has("rotation")) { - rot = d["rotation"]; - } + case TYPE_POSITION_3D: { + ERR_FAIL_COND((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I)); + int idx = position_track_insert_key(p_track, p_time, p_key); + track_set_key_transition(p_track, idx, p_transition); - Vector3 scale; - if (d.has("scale")) { - scale = d["scale"]; - } + } break; + case TYPE_ROTATION_3D: { + ERR_FAIL_COND((p_key.get_type() != Variant::QUATERNION) && (p_key.get_type() != Variant::BASIS)); + int idx = rotation_track_insert_key(p_track, p_time, p_key); + track_set_key_transition(p_track, idx, p_transition); - int idx = transform_track_insert_key(p_track, p_time, loc, rot, scale); + } break; + case TYPE_SCALE_3D: { + ERR_FAIL_COND((p_key.get_type() != Variant::VECTOR3) && (p_key.get_type() != Variant::VECTOR3I)); + int idx = scale_track_insert_key(p_track, p_time, p_key); track_set_key_transition(p_track, idx, p_transition); } break; @@ -1054,9 +1267,17 @@ int Animation::track_get_key_count(int p_track) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - return tt->transforms.size(); + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + return tt->positions.size(); + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + return rt->rotations.size(); + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + return st->scales.size(); } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); @@ -1089,16 +1310,23 @@ Variant Animation::track_get_key_value(int p_track, int p_key_idx) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), Variant()); + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, tt->positions.size(), Variant()); - Dictionary d; - d["location"] = tt->transforms[p_key_idx].value.loc; - d["rotation"] = tt->transforms[p_key_idx].value.rot; - d["scale"] = tt->transforms[p_key_idx].value.scale; + return tt->positions[p_key_idx].value; + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, rt->rotations.size(), Variant()); - return d; + return rt->rotations[p_key_idx].value; + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, st->scales.size(), Variant()); + + return st->scales[p_key_idx].value; } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); @@ -1157,10 +1385,20 @@ double Animation::track_get_key_time(int p_track, int p_key_idx) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), -1); - return tt->transforms[p_key_idx].time; + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, tt->positions.size(), -1); + return tt->positions[p_key_idx].time; + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, rt->rotations.size(), -1); + return rt->rotations[p_key_idx].time; + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, st->scales.size(), -1); + return st->scales[p_key_idx].time; } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); @@ -1202,13 +1440,31 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); - TKey<TransformKey> key = tt->transforms[p_key_idx]; + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->positions.size()); + TKey<Vector3> key = tt->positions[p_key_idx]; key.time = p_time; - tt->transforms.remove(p_key_idx); - _insert(p_time, tt->transforms, key); + tt->positions.remove(p_key_idx); + _insert(p_time, tt->positions, key); + return; + } + case TYPE_ROTATION_3D: { + RotationTrack *tt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->rotations.size()); + TKey<Quaternion> key = tt->rotations[p_key_idx]; + key.time = p_time; + tt->rotations.remove(p_key_idx); + _insert(p_time, tt->rotations, key); + return; + } + case TYPE_SCALE_3D: { + ScaleTrack *tt = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->scales.size()); + TKey<Vector3> key = tt->scales[p_key_idx]; + key.time = p_time; + tt->scales.remove(p_key_idx); + _insert(p_time, tt->scales, key); return; } case TYPE_VALUE: { @@ -1266,10 +1522,20 @@ real_t Animation::track_get_key_transition(int p_track, int p_key_idx) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), -1); - return tt->transforms[p_key_idx].transition; + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, tt->positions.size(), -1); + return tt->positions[p_key_idx].transition; + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, rt->rotations.size(), -1); + return rt->rotations[p_key_idx].transition; + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX_V(p_key_idx, st->scales.size(), -1); + return st->scales[p_key_idx].transition; } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); @@ -1302,21 +1568,28 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); + case TYPE_POSITION_3D: { + ERR_FAIL_COND((p_value.get_type() != Variant::VECTOR3) && (p_value.get_type() != Variant::VECTOR3I)); + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->positions.size()); - Dictionary d = p_value; + tt->positions.write[p_key_idx].value = p_value; - if (d.has("location")) { - tt->transforms.write[p_key_idx].value.loc = d["location"]; - } - if (d.has("rotation")) { - tt->transforms.write[p_key_idx].value.rot = d["rotation"]; - } - if (d.has("scale")) { - tt->transforms.write[p_key_idx].value.scale = d["scale"]; - } + } break; + case TYPE_ROTATION_3D: { + ERR_FAIL_COND((p_value.get_type() != Variant::QUATERNION) && (p_value.get_type() != Variant::BASIS)); + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, rt->rotations.size()); + + rt->rotations.write[p_key_idx].value = p_value; + + } break; + case TYPE_SCALE_3D: { + ERR_FAIL_COND((p_value.get_type() != Variant::VECTOR3) && (p_value.get_type() != Variant::VECTOR3I)); + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, st->scales.size()); + + st->scales.write[p_key_idx].value = p_value; } break; case TYPE_VALUE: { @@ -1385,10 +1658,20 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, real_t p_tr Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM3D: { - TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); - tt->transforms.write[p_key_idx].transition = p_transition; + case TYPE_POSITION_3D: { + PositionTrack *tt = static_cast<PositionTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, tt->positions.size()); + tt->positions.write[p_key_idx].transition = p_transition; + } break; + case TYPE_ROTATION_3D: { + RotationTrack *rt = static_cast<RotationTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, rt->rotations.size()); + rt->rotations.write[p_key_idx].transition = p_transition; + } break; + case TYPE_SCALE_3D: { + ScaleTrack *st = static_cast<ScaleTrack *>(t); + ERR_FAIL_INDEX(p_key_idx, st->scales.size()); + st->scales.write[p_key_idx].transition = p_transition; } break; case TYPE_VALUE: { ValueTrack *vt = static_cast<ValueTrack *>(t); @@ -1450,15 +1733,6 @@ int Animation::_find(const Vector<K> &p_keys, double p_time) const { return middle; } -Animation::TransformKey Animation::_interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, real_t p_c) const { - TransformKey ret; - ret.loc = _interpolate(p_a.loc, p_b.loc, p_c); - ret.rot = _interpolate(p_a.rot, p_b.rot, p_c); - ret.scale = _interpolate(p_a.scale, p_b.scale, p_c); - - return ret; -} - Vector3 Animation::_interpolate(const Vector3 &p_a, const Vector3 &p_b, real_t p_c) const { return p_a.lerp(p_b, p_c); } @@ -1477,16 +1751,6 @@ real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) return p_a * (1.0 - p_c) + p_b * p_c; } -Animation::TransformKey Animation::_cubic_interpolate(const Animation::TransformKey &p_pre_a, const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, const Animation::TransformKey &p_post_b, real_t p_c) const { - Animation::TransformKey tk; - - tk.loc = p_a.loc.cubic_interpolate(p_b.loc, p_pre_a.loc, p_post_b.loc, p_c); - tk.scale = p_a.scale.cubic_interpolate(p_b.scale, p_pre_a.scale, p_post_b.scale, p_c); - tk.rot = p_a.rot.cubic_slerp(p_b.rot, p_pre_a.rot, p_post_b.rot, p_c); - - return tk; -} - Vector3 Animation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const { return p_a.cubic_interpolate(p_b, p_pre_a, p_post_b, p_c); } @@ -1729,36 +1993,6 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol // do a barrel roll } -Error Animation::transform_track_interpolate(int p_track, double p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const { - ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); - Track *t = tracks[p_track]; - ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, ERR_INVALID_PARAMETER); - - TransformTrack *tt = static_cast<TransformTrack *>(t); - - bool ok = false; - - TransformKey tk = _interpolate(tt->transforms, p_time, tt->interpolation, tt->loop_wrap, &ok); - - if (!ok) { - return ERR_UNAVAILABLE; - } - - if (r_loc) { - *r_loc = tk.loc; - } - - if (r_rot) { - *r_rot = tk.rot; - } - - if (r_scale) { - *r_scale = tk.scale; - } - - return OK; -} - Variant Animation::value_track_interpolate(int p_track, double p_time) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); Track *t = tracks[p_track]; @@ -1933,10 +2167,22 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl // handle loop by splitting switch (t->type) { - case TYPE_TRANSFORM3D: { - const TransformTrack *tt = static_cast<const TransformTrack *>(t); - _track_get_key_indices_in_range(tt->transforms, from_time, length, p_indices); - _track_get_key_indices_in_range(tt->transforms, 0, to_time, p_indices); + case TYPE_POSITION_3D: { + const PositionTrack *tt = static_cast<const PositionTrack *>(t); + _track_get_key_indices_in_range(tt->positions, from_time, length, p_indices); + _track_get_key_indices_in_range(tt->positions, 0, to_time, p_indices); + + } break; + case TYPE_ROTATION_3D: { + const RotationTrack *rt = static_cast<const RotationTrack *>(t); + _track_get_key_indices_in_range(rt->rotations, from_time, length, p_indices); + _track_get_key_indices_in_range(rt->rotations, 0, to_time, p_indices); + + } break; + case TYPE_SCALE_3D: { + const ScaleTrack *st = static_cast<const ScaleTrack *>(t); + _track_get_key_indices_in_range(st->scales, from_time, length, p_indices); + _track_get_key_indices_in_range(st->scales, 0, to_time, p_indices); } break; case TYPE_VALUE: { @@ -1989,9 +2235,19 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl } switch (t->type) { - case TYPE_TRANSFORM3D: { - const TransformTrack *tt = static_cast<const TransformTrack *>(t); - _track_get_key_indices_in_range(tt->transforms, from_time, to_time, p_indices); + case TYPE_POSITION_3D: { + const PositionTrack *tt = static_cast<const PositionTrack *>(t); + _track_get_key_indices_in_range(tt->positions, from_time, to_time, p_indices); + + } break; + case TYPE_ROTATION_3D: { + const RotationTrack *rt = static_cast<const RotationTrack *>(t); + _track_get_key_indices_in_range(rt->rotations, from_time, to_time, p_indices); + + } break; + case TYPE_SCALE_3D: { + const ScaleTrack *st = static_cast<const ScaleTrack *>(t); + _track_get_key_indices_in_range(st->scales, from_time, to_time, p_indices); } break; case TYPE_VALUE: { @@ -2608,7 +2864,10 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_set_enabled", "track_idx", "enabled"), &Animation::track_set_enabled); ClassDB::bind_method(D_METHOD("track_is_enabled", "track_idx"), &Animation::track_is_enabled); - ClassDB::bind_method(D_METHOD("transform_track_insert_key", "track_idx", "time", "location", "rotation", "scale"), &Animation::transform_track_insert_key); + ClassDB::bind_method(D_METHOD("position_track_insert_key", "track_idx", "time", "position"), &Animation::position_track_insert_key); + ClassDB::bind_method(D_METHOD("rotation_track_insert_key", "track_idx", "time", "rotation"), &Animation::rotation_track_insert_key); + ClassDB::bind_method(D_METHOD("scale_track_insert_key", "track_idx", "time", "scale"), &Animation::scale_track_insert_key); + ClassDB::bind_method(D_METHOD("track_insert_key", "track_idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1)); ClassDB::bind_method(D_METHOD("track_remove_key", "track_idx", "key_idx"), &Animation::track_remove_key); ClassDB::bind_method(D_METHOD("track_remove_key_at_time", "track_idx", "time"), &Animation::track_remove_key_at_time); @@ -2628,7 +2887,6 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("track_set_interpolation_loop_wrap", "track_idx", "interpolation"), &Animation::track_set_interpolation_loop_wrap); ClassDB::bind_method(D_METHOD("track_get_interpolation_loop_wrap", "track_idx"), &Animation::track_get_interpolation_loop_wrap); - ClassDB::bind_method(D_METHOD("transform_track_interpolate", "track_idx", "time_sec"), &Animation::_transform_track_interpolate); ClassDB::bind_method(D_METHOD("value_track_set_update_mode", "track_idx", "mode"), &Animation::value_track_set_update_mode); ClassDB::bind_method(D_METHOD("value_track_get_update_mode", "track_idx"), &Animation::value_track_get_update_mode); @@ -2682,7 +2940,9 @@ void Animation::_bind_methods() { ADD_SIGNAL(MethodInfo("tracks_changed")); BIND_ENUM_CONSTANT(TYPE_VALUE); - BIND_ENUM_CONSTANT(TYPE_TRANSFORM3D); + BIND_ENUM_CONSTANT(TYPE_POSITION_3D); + BIND_ENUM_CONSTANT(TYPE_ROTATION_3D); + BIND_ENUM_CONSTANT(TYPE_SCALE_3D); BIND_ENUM_CONSTANT(TYPE_METHOD); BIND_ENUM_CONSTANT(TYPE_BEZIER); BIND_ENUM_CONSTANT(TYPE_AUDIO); @@ -2709,193 +2969,215 @@ void Animation::clear() { emit_signal(SceneStringNames::get_singleton()->tracks_changed); } -bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, real_t p_alowed_linear_err, real_t p_alowed_angular_err, real_t p_max_optimizable_angle, const Vector3 &p_norm) { - real_t c = (t1.time - t0.time) / (t2.time - t0.time); - real_t t[3] = { -1, -1, -1 }; +bool Animation::_position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm) { + const Vector3 &v0 = t0.value; + const Vector3 &v1 = t1.value; + const Vector3 &v2 = t2.value; - { //translation + if (v0.is_equal_approx(v2)) { + //0 and 2 are close, let's see if 1 is close + if (!v0.is_equal_approx(v1)) { + //not close, not optimizable + return false; + } - const Vector3 &v0 = t0.value.loc; - const Vector3 &v1 = t1.value.loc; - const Vector3 &v2 = t2.value.loc; + } else { + Vector3 pd = (v2 - v0); + real_t d0 = pd.dot(v0); + real_t d1 = pd.dot(v1); + real_t d2 = pd.dot(v2); + if (d1 < d0 || d1 > d2) { + return false; + } - if (v0.is_equal_approx(v2)) { - //0 and 2 are close, let's see if 1 is close - if (!v0.is_equal_approx(v1)) { - //not close, not optimizable - return false; - } + Vector3 s[2] = { v0, v2 }; + real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); - } else { - Vector3 pd = (v2 - v0); - real_t d0 = pd.dot(v0); - real_t d1 = pd.dot(v1); - real_t d2 = pd.dot(v2); - if (d1 < d0 || d1 > d2) { - return false; - } + if (d > pd.length() * p_allowed_linear_err) { + return false; //beyond allowed error for collinearity + } - Vector3 s[2] = { v0, v2 }; - real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); + if (p_norm != Vector3() && Math::acos(pd.normalized().dot(p_norm)) > p_allowed_angular_error) { + return false; + } + } - if (d > pd.length() * p_alowed_linear_err) { - return false; //beyond allowed error for collinearity - } + return true; +} - if (p_norm != Vector3() && Math::acos(pd.normalized().dot(p_norm)) > p_alowed_angular_err) { - return false; - } +bool Animation::_rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle) { + const Quaternion &q0 = t0.value; + const Quaternion &q1 = t1.value; + const Quaternion &q2 = t2.value; + + //localize both to rotation from q0 - t[0] = (d1 - d0) / (d2 - d0); + if (q0.is_equal_approx(q2)) { + if (!q0.is_equal_approx(q1)) { + return false; } - } - { //rotation + } else { + Quaternion r02 = (q0.inverse() * q2).normalized(); + Quaternion r01 = (q0.inverse() * q1).normalized(); - const Quaternion &q0 = t0.value.rot; - const Quaternion &q1 = t1.value.rot; - const Quaternion &q2 = t2.value.rot; + Vector3 v02, v01; + real_t a02, a01; - //localize both to rotation from q0 + r02.get_axis_angle(v02, a02); + r01.get_axis_angle(v01, a01); - if (q0.is_equal_approx(q2)) { - if (!q0.is_equal_approx(q1)) { - return false; - } + if (Math::abs(a02) > p_max_optimizable_angle) { + return false; + } - } else { - Quaternion r02 = (q0.inverse() * q2).normalized(); - Quaternion r01 = (q0.inverse() * q1).normalized(); + if (v01.dot(v02) < 0) { + //make sure both rotations go the same way to compare + v02 = -v02; + a02 = -a02; + } - Vector3 v02, v01; - real_t a02, a01; + real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized())) / Math_PI; + if (err_01 > p_allowed_angular_error) { + //not rotating in the same axis + return false; + } - r02.get_axis_angle(v02, a02); - r01.get_axis_angle(v01, a01); + if (a01 * a02 < 0) { + //not rotating in the same direction + return false; + } - if (Math::abs(a02) > p_max_optimizable_angle) { - return false; - } + real_t tr = a01 / a02; + if (tr < 0 || tr > 1) { + return false; //rotating too much or too less + } + } - if (v01.dot(v02) < 0) { - //make sure both rotations go the same way to compare - v02 = -v02; - a02 = -a02; - } + return true; +} - real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized())) / Math_PI; - if (err_01 > p_alowed_angular_err) { - //not rotating in the same axis - return false; - } +bool Animation::_scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error) { + const Vector3 &v0 = t0.value; + const Vector3 &v1 = t1.value; + const Vector3 &v2 = t2.value; - if (a01 * a02 < 0) { - //not rotating in the same direction - return false; - } + if (v0.is_equal_approx(v2)) { + //0 and 2 are close, let's see if 1 is close + if (!v0.is_equal_approx(v1)) { + //not close, not optimizable + return false; + } - real_t tr = a01 / a02; - if (tr < 0 || tr > 1) { - return false; //rotating too much or too less - } + } else { + Vector3 pd = (v2 - v0); + real_t d0 = pd.dot(v0); + real_t d1 = pd.dot(v1); + real_t d2 = pd.dot(v2); + if (d1 < d0 || d1 > d2) { + return false; //beyond segment range + } - t[1] = tr; + Vector3 s[2] = { v0, v2 }; + real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); + + if (d > pd.length() * p_allowed_linear_error) { + return false; //beyond allowed error for colinearity } } - { //scale + return true; +} - const Vector3 &v0 = t0.value.scale; - const Vector3 &v1 = t1.value.scale; - const Vector3 &v2 = t2.value.scale; +void Animation::_position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err) { + ERR_FAIL_INDEX(p_idx, tracks.size()); + ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D); + PositionTrack *tt = static_cast<PositionTrack *>(tracks[p_idx]); + bool prev_erased = false; + TKey<Vector3> first_erased; - if (v0.is_equal_approx(v2)) { - //0 and 2 are close, let's see if 1 is close - if (!v0.is_equal_approx(v1)) { - //not close, not optimizable - return false; - } + Vector3 norm; - } else { - Vector3 pd = (v2 - v0); - real_t d0 = pd.dot(v0); - real_t d1 = pd.dot(v1); - real_t d2 = pd.dot(v2); - if (d1 < d0 || d1 > d2) { - return false; //beyond segment range - } + for (int i = 1; i < tt->positions.size() - 1; i++) { + TKey<Vector3> &t0 = tt->positions.write[i - 1]; + TKey<Vector3> &t1 = tt->positions.write[i]; + TKey<Vector3> &t2 = tt->positions.write[i + 1]; - Vector3 s[2] = { v0, v2 }; - real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); + bool erase = _position_track_optimize_key(t0, t1, t2, p_allowed_linear_err, p_allowed_angular_err, norm); + if (erase && !prev_erased) { + norm = (t2.value - t1.value).normalized(); + } + + if (prev_erased && !_position_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err, p_allowed_angular_err, norm)) { + //avoid error to go beyond first erased key + erase = false; + } - if (d > pd.length() * p_alowed_linear_err) { - return false; //beyond allowed error for collinearity + if (erase) { + if (!prev_erased) { + first_erased = t1; + prev_erased = true; } - t[2] = (d1 - d0) / (d2 - d0); + tt->positions.remove(i); + i--; + + } else { + prev_erased = false; + norm = Vector3(); } } +} - bool erase = false; - if (t[0] == -1 && t[1] == -1 && t[2] == -1) { - erase = true; - } else { - erase = true; - real_t lt = -1.0; - for (int j = 0; j < 3; j++) { - //search for t on first, one must be it - if (t[j] != -1) { - lt = t[j]; //official t - //validate rest - for (int k = j + 1; k < 3; k++) { - if (t[k] == -1) { - continue; - } +void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) { + ERR_FAIL_INDEX(p_idx, tracks.size()); + ERR_FAIL_COND(tracks[p_idx]->type != TYPE_ROTATION_3D); + RotationTrack *tt = static_cast<RotationTrack *>(tracks[p_idx]); + bool prev_erased = false; + TKey<Quaternion> first_erased; - if (Math::abs(lt - t[k]) > p_alowed_linear_err) { - erase = false; - break; - } - } - break; - } - } + for (int i = 1; i < tt->rotations.size() - 1; i++) { + TKey<Quaternion> &t0 = tt->rotations.write[i - 1]; + TKey<Quaternion> &t1 = tt->rotations.write[i]; + TKey<Quaternion> &t2 = tt->rotations.write[i + 1]; - ERR_FAIL_COND_V(lt == -1, false); + bool erase = _rotation_track_optimize_key(t0, t1, t2, p_allowed_angular_err, p_max_optimizable_angle); + + if (prev_erased && !_rotation_track_optimize_key(t0, first_erased, t2, p_allowed_angular_err, p_max_optimizable_angle)) { + //avoid error to go beyond first erased key + erase = false; + } if (erase) { - if (Math::abs(lt - c) > p_alowed_linear_err) { - //todo, evaluate changing the transition if this fails? - //this could be done as a second pass and would be - //able to optimize more - erase = false; + if (!prev_erased) { + first_erased = t1; + prev_erased = true; } + + tt->rotations.remove(i); + i--; + + } else { + prev_erased = false; } } - - return erase; } -void Animation::_transform_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) { +void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_linear_err) { ERR_FAIL_INDEX(p_idx, tracks.size()); - ERR_FAIL_COND(tracks[p_idx]->type != TYPE_TRANSFORM3D); - TransformTrack *tt = static_cast<TransformTrack *>(tracks[p_idx]); + ERR_FAIL_COND(tracks[p_idx]->type != TYPE_SCALE_3D); + ScaleTrack *tt = static_cast<ScaleTrack *>(tracks[p_idx]); bool prev_erased = false; - TKey<TransformKey> first_erased; + TKey<Vector3> first_erased; - Vector3 norm; + for (int i = 1; i < tt->scales.size() - 1; i++) { + TKey<Vector3> &t0 = tt->scales.write[i - 1]; + TKey<Vector3> &t1 = tt->scales.write[i]; + TKey<Vector3> &t2 = tt->scales.write[i + 1]; - for (int i = 1; i < tt->transforms.size() - 1; i++) { - TKey<TransformKey> &t0 = tt->transforms.write[i - 1]; - TKey<TransformKey> &t1 = tt->transforms.write[i]; - TKey<TransformKey> &t2 = tt->transforms.write[i + 1]; + bool erase = _scale_track_optimize_key(t0, t1, t2, p_allowed_linear_err); - bool erase = _transform_track_optimize_key(t0, t1, t2, p_allowed_linear_err, p_allowed_angular_err, p_max_optimizable_angle, norm); - if (erase && !prev_erased) { - norm = (t2.value.loc - t1.value.loc).normalized(); - } - - if (prev_erased && !_transform_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err, p_allowed_angular_err, p_max_optimizable_angle, norm)) { + if (prev_erased && !_scale_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err)) { //avoid error to go beyond first erased key erase = false; } @@ -2906,20 +3188,23 @@ void Animation::_transform_track_optimize(int p_idx, real_t p_allowed_linear_err prev_erased = true; } - tt->transforms.remove(i); + tt->scales.remove(i); i--; } else { prev_erased = false; - norm = Vector3(); } } } void Animation::optimize(real_t p_allowed_linear_err, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) { for (int i = 0; i < tracks.size(); i++) { - if (tracks[i]->type == TYPE_TRANSFORM3D) { - _transform_track_optimize(i, p_allowed_linear_err, p_allowed_angular_err, p_max_optimizable_angle); + if (tracks[i]->type == TYPE_POSITION_3D) { + _position_track_optimize(i, p_allowed_linear_err, p_allowed_angular_err); + } else if (tracks[i]->type == TYPE_ROTATION_3D) { + _rotation_track_optimize(i, p_allowed_angular_err, p_max_optimizable_angle); + } else if (tracks[i]->type == TYPE_SCALE_3D) { + _scale_track_optimize(i, p_allowed_linear_err); } } } diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 9a410bd566..614e12a560 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -42,7 +42,9 @@ class Animation : public Resource { public: enum TrackType { TYPE_VALUE, ///< Set a value in a property, can be interpolated. - TYPE_TRANSFORM3D, ///< Transform a node or a bone. + TYPE_POSITION_3D, ///< Position 3D track + TYPE_ROTATION_3D, ///< Rotation 3D track + TYPE_SCALE_3D, ///< Scale 3D track TYPE_METHOD, ///< Call any method on a specific node. TYPE_BEZIER, ///< Bezier curve TYPE_AUDIO, @@ -86,21 +88,31 @@ private: T value; }; - struct TransformKey { - Vector3 loc; - Quaternion rot; - Vector3 scale; + const int32_t POSITION_TRACK_SIZE = 5; + const int32_t ROTATION_TRACK_SIZE = 6; + const int32_t SCALE_TRACK_SIZE = 5; + + /* POSITION TRACK */ + + struct PositionTrack : public Track { + Vector<TKey<Vector3>> positions; + + PositionTrack() { type = TYPE_POSITION_3D; } }; - // Not necessarily the same size as Transform3D. The amount of numbers in Animation::Key and TransformKey. - const int32_t TRANSFORM_TRACK_SIZE = 12; + /* ROTATION TRACK */ - /* TRANSFORM TRACK */ + struct RotationTrack : public Track { + Vector<TKey<Quaternion>> rotations; - struct TransformTrack : public Track { - Vector<TKey<TransformKey>> transforms; + RotationTrack() { type = TYPE_ROTATION_3D; } + }; - TransformTrack() { type = TYPE_TRANSFORM3D; } + /* SCALE TRACK */ + + struct ScaleTrack : public Track { + Vector<TKey<Vector3>> scales; + ScaleTrack() { type = TYPE_SCALE_3D; } }; /* PROPERTY VALUE TRACK */ @@ -186,14 +198,11 @@ private: template <class K> inline int _find(const Vector<K> &p_keys, double p_time) const; - _FORCE_INLINE_ Animation::TransformKey _interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, real_t p_c) const; - _FORCE_INLINE_ Vector3 _interpolate(const Vector3 &p_a, const Vector3 &p_b, real_t p_c) const; _FORCE_INLINE_ Quaternion _interpolate(const Quaternion &p_a, const Quaternion &p_b, real_t p_c) const; _FORCE_INLINE_ Variant _interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const; _FORCE_INLINE_ real_t _interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const; - _FORCE_INLINE_ Animation::TransformKey _cubic_interpolate(const Animation::TransformKey &p_pre_a, const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, const Animation::TransformKey &p_post_b, real_t p_c) const; _FORCE_INLINE_ Vector3 _cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const; _FORCE_INLINE_ Quaternion _cubic_interpolate(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c) const; _FORCE_INLINE_ Variant _cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c) const; @@ -214,18 +223,6 @@ private: // bind helpers private: - Array _transform_track_interpolate(int p_track, double p_time) const { - Vector3 loc; - Quaternion rot; - Vector3 scale; - transform_track_interpolate(p_track, p_time, &loc, &rot, &scale); - Array ret; - ret.push_back(loc); - ret.push_back(rot); - ret.push_back(scale); - return ret; - } - Vector<int> _value_track_get_key_indices(int p_track, double p_time, double p_delta) const { List<int> idxs; value_track_get_key_indices(p_track, p_time, p_delta, &idxs); @@ -247,8 +244,13 @@ private: return idxr; } - bool _transform_track_optimize_key(const TKey<TransformKey> &t0, const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, real_t p_alowed_linear_err, real_t p_alowed_angular_err, real_t p_max_optimizable_angle, const Vector3 &p_norm); - void _transform_track_optimize(int p_idx, real_t p_allowed_linear_err = 0.05, real_t p_allowed_angular_err = 0.01, real_t p_max_optimizable_angle = Math_PI * 0.125); + bool _position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_alowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm); + bool _rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle); + bool _scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error); + + void _position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err); + void _rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle); + void _scale_track_optimize(int p_idx, real_t p_allowed_linear_err); protected: bool _set(const StringName &p_name, const Variant &p_value); @@ -294,8 +296,18 @@ public: double track_get_key_time(int p_track, int p_key_idx) const; real_t track_get_key_transition(int p_track, int p_key_idx) const; - int transform_track_insert_key(int p_track, double p_time, const Vector3 &p_loc, const Quaternion &p_rot = Quaternion(), const Vector3 &p_scale = Vector3()); - Error transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const; + int position_track_insert_key(int p_track, double p_time, const Vector3 &p_position); + Error position_track_get_key(int p_track, int p_key, Vector3 *r_position) const; + Error position_track_interpolate(int p_track, double p_time, Vector3 *r_interpolation) const; + + int rotation_track_insert_key(int p_track, double p_time, const Quaternion &p_rotation); + Error rotation_track_get_key(int p_track, int p_key, Quaternion *r_rotation) const; + Error rotation_track_interpolate(int p_track, double p_time, Quaternion *r_interpolation) const; + + int scale_track_insert_key(int p_track, double p_time, const Vector3 &p_scale); + Error scale_track_get_key(int p_track, int p_key, Vector3 *r_scale) const; + Error scale_track_interpolate(int p_track, double p_time, Vector3 *r_interpolation) const; + void track_set_interpolation_type(int p_track, InterpolationType p_interp); InterpolationType track_get_interpolation_type(int p_track) const; @@ -324,8 +336,6 @@ public: void track_set_interpolation_loop_wrap(int p_track, bool p_enable); bool track_get_interpolation_loop_wrap(int p_track) const; - Error transform_track_interpolate(int p_track, double p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const; - Variant value_track_interpolate(int p_track, double p_time) const; void value_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices) const; void value_track_set_update_mode(int p_track, UpdateMode p_mode); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 9a3f081a8b..be0d3a140e 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -1291,7 +1291,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_density", PROPERTY_HINT_RANGE, "0,16,0.0001"), "set_fog_density", "get_fog_density"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_aerial_perspective", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_aerial_perspective", "get_fog_aerial_perspective"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_lesser,or_greater"), "set_fog_height", "get_fog_height"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "0,128,0.001,or_greater"), "set_fog_height_density", "get_fog_height_density"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "-16,16,0.0001,or_lesser,or_greater"), "set_fog_height_density", "get_fog_height_density"); ClassDB::bind_method(D_METHOD("set_volumetric_fog_enabled", "enabled"), &Environment::set_volumetric_fog_enabled); ClassDB::bind_method(D_METHOD("is_volumetric_fog_enabled"), &Environment::is_volumetric_fog_enabled); diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index 2572c5de33..076b8312b6 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -997,7 +997,7 @@ Ref<NavigationMesh> ImporterMesh::create_navigation_mesh() { extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y); -struct EditorSceneImporterMeshLightmapSurface { +struct EditorSceneFormatImporterMeshLightmapSurface { Ref<Material> material; LocalVector<SurfaceTool::Vertex> vertices; Mesh::PrimitiveType primitive = Mesh::PrimitiveType::PRIMITIVE_MAX; @@ -1015,7 +1015,7 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, LocalVector<float> uv; LocalVector<Pair<int, int>> uv_indices; - Vector<EditorSceneImporterMeshLightmapSurface> lightmap_surfaces; + Vector<EditorSceneFormatImporterMeshLightmapSurface> lightmap_surfaces; // Keep only the scale Basis basis = p_base_transform.get_basis(); @@ -1027,7 +1027,7 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, Basis normal_basis = transform.basis.inverse().transposed(); for (int i = 0; i < get_surface_count(); i++) { - EditorSceneImporterMeshLightmapSurface s; + EditorSceneFormatImporterMeshLightmapSurface s; s.primitive = get_surface_primitive_type(i); ERR_FAIL_COND_V_MSG(s.primitive != Mesh::PRIMITIVE_TRIANGLES, ERR_UNAVAILABLE, "Only triangles are supported for lightmap unwrap."); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 18e6a51118..7ffe0b03e1 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1577,7 +1577,7 @@ void ArrayMesh::regen_normal_maps() { } //dirty hack -bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) = NULL; +bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) = nullptr; struct ArrayMeshLightmapSurface { Ref<Material> material; diff --git a/scene/resources/skeleton_modification_3d_fabrik.cpp b/scene/resources/skeleton_modification_3d_fabrik.cpp index e615615924..20ebbda256 100644 --- a/scene/resources/skeleton_modification_3d_fabrik.cpp +++ b/scene/resources/skeleton_modification_3d_fabrik.cpp @@ -168,7 +168,7 @@ void SkeletonModification3DFABRIK::_execute(real_t p_delta) { // Apply magnet positions: if (stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx) >= 0) { int parent_bone_idx = stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx); - Transform3D conversion_transform = (stack->skeleton->get_bone_global_pose(parent_bone_idx) * stack->skeleton->get_bone_rest(parent_bone_idx)); + Transform3D conversion_transform = (stack->skeleton->get_bone_global_pose(parent_bone_idx)); local_pose_override.origin += conversion_transform.basis.xform_inv(fabrik_data_chain[i].magnet_position); } else { local_pose_override.origin += fabrik_data_chain[i].magnet_position; diff --git a/scene/resources/skeleton_modification_3d_twoboneik.cpp b/scene/resources/skeleton_modification_3d_twoboneik.cpp index ae7a3bab7e..c1a71148a7 100644 --- a/scene/resources/skeleton_modification_3d_twoboneik.cpp +++ b/scene/resources/skeleton_modification_3d_twoboneik.cpp @@ -455,7 +455,7 @@ void SkeletonModification3DTwoBoneIK::calculate_joint_lengths() { joint_two_length = 0; for (int i = 0; i < bone_two_children.size(); i++) { joint_two_length += bone_two_rest_trans.origin.distance_to( - stack->skeleton->local_pose_to_global_pose(bone_two_children[i], stack->skeleton->get_bone_rest(bone_two_children[i])).origin); + stack->skeleton->get_bone_global_pose(bone_two_children[i]).origin); } joint_two_length = joint_two_length / bone_two_children.size(); } else { diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index e19ca38b82..b988b2ab3e 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -171,6 +171,8 @@ void TileSet::set_source_id(int p_source_id, int p_new_source_id) { source_ids.append(p_new_source_id); source_ids.sort(); + _compute_next_source_id(); + emit_changed(); } @@ -3064,6 +3066,7 @@ void TileSetAtlasSource::reset_state() { void TileSetAtlasSource::set_texture(Ref<Texture2D> p_texture) { texture = p_texture; + _clear_tiles_outside_texture(); emit_changed(); } @@ -3079,6 +3082,7 @@ void TileSetAtlasSource::set_margins(Vector2i p_margins) { margins = p_margins; } + _clear_tiles_outside_texture(); emit_changed(); } Vector2i TileSetAtlasSource::get_margins() const { @@ -3093,6 +3097,7 @@ void TileSetAtlasSource::set_separation(Vector2i p_separation) { separation = p_separation; } + _clear_tiles_outside_texture(); emit_changed(); } Vector2i TileSetAtlasSource::get_separation() const { @@ -3107,6 +3112,7 @@ void TileSetAtlasSource::set_texture_region_size(Vector2i p_tile_size) { texture_region_size = p_tile_size; } + _clear_tiles_outside_texture(); emit_changed(); } Vector2i TileSetAtlasSource::get_texture_region_size() const { @@ -3352,7 +3358,7 @@ void TileSetAtlasSource::create_tile(const Vector2i p_atlas_coords, const Vector ERR_FAIL_COND(p_size.x <= 0 || p_size.y <= 0); bool room_for_tile = has_room_for_tile(p_atlas_coords, p_size, 1, Vector2i(), 1); - ERR_FAIL_COND_MSG(!room_for_tile, "Cannot create tile, tiles are already present in the space the tile would cover."); + ERR_FAIL_COND_MSG(!room_for_tile, "Cannot create tile. The tile is outside the texture or tiles are already present in the space the tile would cover."); // Initialize the tile data. TileAlternativesData tad; @@ -3550,9 +3556,7 @@ bool TileSetAtlasSource::has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_s return false; } if (coords.x >= atlas_grid_size.x || coords.y >= atlas_grid_size.y) { - if (!(_coords_mapping_cache.has(coords) && _coords_mapping_cache[coords] == p_ignored_tile)) { - return false; // Only accept tiles outside the atlas if they are part of the ignored tile. - } + return false; } } } @@ -3560,6 +3564,37 @@ bool TileSetAtlasSource::has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_s return true; } +PackedVector2Array TileSetAtlasSource::get_tiles_to_be_removed_on_change(Ref<Texture2D> p_texture, Vector2i p_margins, Vector2i p_separation, Vector2i p_texture_region_size) { + ERR_FAIL_COND_V(p_margins.x < 0 || p_margins.y < 0, PackedVector2Array()); + ERR_FAIL_COND_V(p_separation.x < 0 || p_separation.y < 0, PackedVector2Array()); + ERR_FAIL_COND_V(p_texture_region_size.x <= 0 || p_texture_region_size.y <= 0, PackedVector2Array()); + + // Compute the new atlas grid size. + Size2 new_grid_size; + if (p_texture.is_valid()) { + Size2i valid_area = p_texture->get_size() - p_margins; + + // Compute the number of valid tiles in the tiles atlas + if (valid_area.x >= p_texture_region_size.x && valid_area.y >= p_texture_region_size.y) { + valid_area -= p_texture_region_size; + new_grid_size = Size2i(1, 1) + valid_area / (p_texture_region_size + p_separation); + } + } + + Vector<Vector2> output; + for (KeyValue<Vector2i, TileAlternativesData> &E : tiles) { + for (unsigned int frame = 0; frame < E.value.animation_frames_durations.size(); frame++) { + Vector2i frame_coords = E.key + (E.value.size_in_atlas + E.value.animation_separation) * ((E.value.animation_columns > 0) ? Vector2i(frame % E.value.animation_columns, frame / E.value.animation_columns) : Vector2i(frame, 0)); + frame_coords += E.value.size_in_atlas; + if (frame_coords.x > new_grid_size.x || frame_coords.y > new_grid_size.y) { + output.push_back(E.key); + break; + } + } + } + return output; +} + Rect2i TileSetAtlasSource::get_tile_texture_region(Vector2i p_atlas_coords, int p_frame) const { ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Rect2i(), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords))); ERR_FAIL_INDEX_V(p_frame, (int)tiles[p_atlas_coords].animation_frames_durations.size(), Rect2i()); @@ -3624,34 +3659,6 @@ void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_ emit_signal(SNAME("changed")); } -bool TileSetAtlasSource::has_tiles_outside_texture() { - Vector2i grid_size = get_atlas_grid_size(); - Vector<Vector2i> to_remove; - - for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) { - if (E.key.x >= grid_size.x || E.key.y >= grid_size.y) { - return true; - } - } - - return false; -} - -void TileSetAtlasSource::clear_tiles_outside_texture() { - Vector2i grid_size = get_atlas_grid_size(); - Vector<Vector2i> to_remove; - - for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) { - if (E.key.x >= grid_size.x || E.key.y >= grid_size.y) { - to_remove.append(E.key); - } - } - - for (int i = 0; i < to_remove.size(); i++) { - remove_tile(to_remove[i]); - } -} - int TileSetAtlasSource::create_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_id_override) { ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords))); ERR_FAIL_COND_V_MSG(p_alternative_id_override >= 0 && tiles[p_atlas_coords].alternatives.has(p_alternative_id_override), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("Cannot create alternative tile. Another alternative exists with id %d.", p_alternative_id_override)); @@ -3752,7 +3759,7 @@ void TileSetAtlasSource::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tile_size_in_atlas", "atlas_coords"), &TileSetAtlasSource::get_tile_size_in_atlas); ClassDB::bind_method(D_METHOD("has_room_for_tile", "atlas_coords", "size", "animation_columns", "animation_separation", "frames_count", "ignored_tile"), &TileSetAtlasSource::has_room_for_tile, DEFVAL(INVALID_ATLAS_COORDS)); - + ClassDB::bind_method(D_METHOD("get_tiles_to_be_removed_on_change", "texture", "margins", "separation", "texture_region_size"), &TileSetAtlasSource::get_tiles_to_be_removed_on_change); ClassDB::bind_method(D_METHOD("get_tile_at_coords", "atlas_coords"), &TileSetAtlasSource::get_tile_at_coords); ClassDB::bind_method(D_METHOD("set_tile_animation_columns", "atlas_coords", "frame_columns"), &TileSetAtlasSource::set_tile_animation_columns); @@ -3777,8 +3784,6 @@ void TileSetAtlasSource::_bind_methods() { // Helpers. ClassDB::bind_method(D_METHOD("get_atlas_grid_size"), &TileSetAtlasSource::get_atlas_grid_size); - ClassDB::bind_method(D_METHOD("has_tiles_outside_texture"), &TileSetAtlasSource::has_tiles_outside_texture); - ClassDB::bind_method(D_METHOD("clear_tiles_outside_texture"), &TileSetAtlasSource::clear_tiles_outside_texture); ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_tile_texture_region, DEFVAL(0)); } @@ -3852,6 +3857,20 @@ void TileSetAtlasSource::_create_coords_mapping_cache(Vector2i p_atlas_coords) { } } +void TileSetAtlasSource::_clear_tiles_outside_texture() { + LocalVector<Vector2i> to_remove; + + for (const KeyValue<Vector2i, TileSetAtlasSource::TileAlternativesData> &E : tiles) { + if (!has_room_for_tile(E.key, E.value.size_in_atlas, E.value.animation_columns, E.value.animation_separation, E.value.animation_frames_durations.size(), E.key)) { + to_remove.push_back(E.key); + } + } + + for (unsigned int i = 0; i < to_remove.size(); i++) { + remove_tile(to_remove[i]); + } +} + /////////////////////////////// TileSetScenesCollectionSource ////////////////////////////////////// void TileSetScenesCollectionSource::_compute_next_alternative_id() { diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 716b66405f..351bdff89d 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -479,8 +479,10 @@ private: void _compute_next_alternative_id(const Vector2i p_atlas_coords); - void _create_coords_mapping_cache(Vector2i p_atlas_coords); void _clear_coords_mapping_cache(Vector2i p_atlas_coords); + void _create_coords_mapping_cache(Vector2i p_atlas_coords); + + void _clear_tiles_outside_texture(); protected: bool _set(const StringName &p_name, const Variant &p_value); @@ -534,7 +536,7 @@ public: virtual Vector2i get_tile_id(int p_index) const override; bool has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_size, int p_animation_columns, Vector2i p_animation_separation, int p_frames_count, Vector2i p_ignored_tile = INVALID_ATLAS_COORDS) const; - + PackedVector2Array get_tiles_to_be_removed_on_change(Ref<Texture2D> p_texture, Vector2i p_margins, Vector2i p_separation, Vector2i p_texture_region_size); Vector2i get_tile_at_coords(Vector2i p_atlas_coords) const; // Animation. @@ -565,8 +567,6 @@ public: // Helpers. Vector2i get_atlas_grid_size() const; - bool has_tiles_outside_texture(); - void clear_tiles_outside_texture(); Rect2i get_tile_texture_region(Vector2i p_atlas_coords, int p_frame = 0) const; Vector2i get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const; diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 934d16bd7e..0dc83b4bb8 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -113,6 +113,10 @@ bool VisualShaderNode::is_output_port_expandable(int p_port) const { return false; } +bool VisualShaderNode::has_output_port_preview(int p_port) const { + return true; +} + void VisualShaderNode::_set_output_ports_expanded(const Array &p_values) { for (int i = 0; i < p_values.size(); i++) { expanded_output_ports[p_values[i]] = true; @@ -2307,7 +2311,21 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { }; const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { + // Spatial, Vertex + + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "vec3(0.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "vec3(1.0, 0.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(1.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Spatial, Fragment + + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "tangent", "vec3(0.0, 1.0, 0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "binormal", "vec3(1.0, 0.0, 0.0)" }, @@ -2315,44 +2333,59 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV, 0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "side", "1.0" }, - - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(1.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Spatial, Light - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv2", "vec3(UV, 0.0)" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(1.0, 1.0, 0.0)" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Canvas Item, Vertex + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Canvas Item, Fragment + + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Canvas Item, Light + + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "vec3(0.0, 0.0, 1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Sky + + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, + { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Particles + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr }, }; @@ -2413,13 +2446,10 @@ String VisualShaderNodeInput::generate_code(Shader::Mode p_mode, VisualShader::T case PORT_TYPE_VECTOR: { code = " " + p_output_vars[0] + " = vec3(0.0);\n"; } break; - case PORT_TYPE_TRANSFORM: { - code = " " + p_output_vars[0] + " = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; - } break; case PORT_TYPE_BOOLEAN: { code = " " + p_output_vars[0] + " = false;\n"; } break; - default: //default (none found) is scalar + default: break; } } diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index b3efac02aa..f910f28536 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -254,6 +254,8 @@ public: void set_input_port_connected(int p_port, bool p_connected); virtual bool is_generate_input_var(int p_port) const; + virtual bool has_output_port_preview(int p_port) const; + virtual bool is_output_port_expandable(int p_port) const; void _set_output_ports_expanded(const Array &p_data); Array _get_output_ports_expanded() const; diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp index 5fe801e037..18b933e5cf 100644 --- a/scene/resources/visual_shader_particle_nodes.cpp +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -47,6 +47,10 @@ String VisualShaderNodeParticleEmitter::get_output_port_name(int p_port) const { return String(); } +bool VisualShaderNodeParticleEmitter::has_output_port_preview(int p_port) const { + return false; +} + VisualShaderNodeParticleEmitter::VisualShaderNodeParticleEmitter() { } @@ -265,6 +269,10 @@ Vector<StringName> VisualShaderNodeParticleMultiplyByAxisAngle::get_editable_pro return props; } +bool VisualShaderNodeParticleMultiplyByAxisAngle::has_output_port_preview(int p_port) const { + return false; +} + VisualShaderNodeParticleMultiplyByAxisAngle::VisualShaderNodeParticleMultiplyByAxisAngle() { set_input_port_default_value(1, Vector3(1, 0, 0)); set_input_port_default_value(2, 0.0); @@ -313,6 +321,10 @@ String VisualShaderNodeParticleConeVelocity::get_output_port_name(int p_port) co return String(); } +bool VisualShaderNodeParticleConeVelocity::has_output_port_preview(int p_port) const { + return false; +} + String VisualShaderNodeParticleConeVelocity::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; code += " __radians = radians(" + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n"; @@ -421,6 +433,10 @@ VisualShaderNodeParticleRandomness::OpType VisualShaderNodeParticleRandomness::g return op_type; } +bool VisualShaderNodeParticleRandomness::has_output_port_preview(int p_port) const { + return false; +} + VisualShaderNodeParticleRandomness::VisualShaderNodeParticleRandomness() { set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 1.0); @@ -521,6 +537,10 @@ VisualShaderNodeParticleAccelerator::Mode VisualShaderNodeParticleAccelerator::g return mode; } +bool VisualShaderNodeParticleAccelerator::has_output_port_preview(int p_port) const { + return false; +} + VisualShaderNodeParticleAccelerator::VisualShaderNodeParticleAccelerator() { set_input_port_default_value(0, Vector3(1, 1, 1)); set_input_port_default_value(1, 0.0); diff --git a/scene/resources/visual_shader_particle_nodes.h b/scene/resources/visual_shader_particle_nodes.h index f5435c3511..b8bc7992cc 100644 --- a/scene/resources/visual_shader_particle_nodes.h +++ b/scene/resources/visual_shader_particle_nodes.h @@ -42,6 +42,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; VisualShaderNodeParticleEmitter(); }; @@ -112,6 +113,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; @@ -135,6 +137,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; @@ -168,6 +171,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; @@ -209,6 +213,7 @@ public: virtual int get_output_port_count() const override; virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; |