diff options
Diffstat (limited to 'scene/animation')
-rw-r--r-- | scene/animation/SCsub | 2 | ||||
-rw-r--r-- | scene/animation/animation_blend_space_2d.cpp | 185 | ||||
-rw-r--r-- | scene/animation/animation_blend_space_2d.h | 15 | ||||
-rw-r--r-- | scene/animation/animation_blend_tree.cpp | 23 | ||||
-rw-r--r-- | scene/animation/animation_blend_tree.h | 7 | ||||
-rw-r--r-- | scene/animation/animation_node_state_machine.cpp | 1 | ||||
-rw-r--r-- | scene/animation/animation_player.cpp | 14 | ||||
-rw-r--r-- | scene/animation/animation_player.h | 1 | ||||
-rw-r--r-- | scene/animation/animation_tree.cpp | 34 | ||||
-rw-r--r-- | scene/animation/animation_tree_player.cpp | 1 | ||||
-rw-r--r-- | scene/animation/skeleton_ik.cpp | 26 | ||||
-rw-r--r-- | scene/animation/skeleton_ik.h | 6 | ||||
-rw-r--r-- | scene/animation/tween.cpp | 20 | ||||
-rw-r--r-- | scene/animation/tween_interpolaters.cpp | 338 |
14 files changed, 242 insertions, 431 deletions
diff --git a/scene/animation/SCsub b/scene/animation/SCsub index bf9125be7f..b01e2fd54d 100644 --- a/scene/animation/SCsub +++ b/scene/animation/SCsub @@ -3,5 +3,3 @@ Import('env') env.add_source_files(env.scene_sources, "*.cpp") - -Export('env') diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index f5f899a6cd..866b85c4c7 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -33,9 +33,17 @@ void AnimationNodeBlendSpace2D::get_parameter_list(List<PropertyInfo> *r_list) const { r_list->push_back(PropertyInfo(Variant::VECTOR2, blend_position)); + r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", 0)); + r_list->push_back(PropertyInfo(Variant::REAL, length_internal, PROPERTY_HINT_NONE, "", 0)); } Variant AnimationNodeBlendSpace2D::get_parameter_default_value(const StringName &p_parameter) const { - return Vector2(); + if (p_parameter == closest) { + return -1; + } else if (p_parameter == length_internal) { + return 0; + } else { + return Vector2(); + } } void AnimationNodeBlendSpace2D::get_child_nodes(List<ChildNode> *r_child_nodes) { @@ -412,84 +420,124 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { _update_triangles(); Vector2 blend_pos = get_parameter(blend_position); + int closest = get_parameter(this->closest); + float length_internal = get_parameter(this->length_internal); + float mind = 0; //time of min distance point - if (triangles.size() == 0) - return 0; + if (blend_mode == BLEND_MODE_INTERPOLATED) { - Vector2 best_point; - bool first = true; - int blend_triangle = -1; - float blend_weights[3] = { 0, 0, 0 }; + if (triangles.size() == 0) + return 0; - for (int i = 0; i < triangles.size(); i++) { - Vector2 points[3]; - for (int j = 0; j < 3; j++) { - points[j] = get_blend_point_position(get_triangle_point(i, j)); - } + Vector2 best_point; + bool first = true; + int blend_triangle = -1; + float blend_weights[3] = { 0, 0, 0 }; - if (Geometry::is_point_in_triangle(blend_pos, points[0], points[1], points[2])) { + for (int i = 0; i < triangles.size(); i++) { + Vector2 points[3]; + for (int j = 0; j < 3; j++) { + points[j] = get_blend_point_position(get_triangle_point(i, j)); + } - blend_triangle = i; - _blend_triangle(blend_pos, points, blend_weights); - break; - } + if (Geometry::is_point_in_triangle(blend_pos, points[0], points[1], points[2])) { - for (int j = 0; j < 3; j++) { - Vector2 s[2] = { - points[j], - points[(j + 1) % 3] - }; - Vector2 closest = Geometry::get_closest_point_to_segment_2d(blend_pos, s); - if (first || closest.distance_to(blend_pos) < best_point.distance_to(blend_pos)) { - best_point = closest; blend_triangle = i; - first = false; - float d = s[0].distance_to(s[1]); - if (d == 0.0) { - blend_weights[j] = 1.0; - blend_weights[(j + 1) % 3] = 0.0; - blend_weights[(j + 2) % 3] = 0.0; - } else { - float c = s[0].distance_to(closest) / d; - - blend_weights[j] = 1.0 - c; - blend_weights[(j + 1) % 3] = c; - blend_weights[(j + 2) % 3] = 0.0; + _blend_triangle(blend_pos, points, blend_weights); + break; + } + + for (int j = 0; j < 3; j++) { + Vector2 s[2] = { + points[j], + points[(j + 1) % 3] + }; + Vector2 closest = Geometry::get_closest_point_to_segment_2d(blend_pos, s); + if (first || closest.distance_to(blend_pos) < best_point.distance_to(blend_pos)) { + best_point = closest; + blend_triangle = i; + first = false; + float d = s[0].distance_to(s[1]); + if (d == 0.0) { + blend_weights[j] = 1.0; + blend_weights[(j + 1) % 3] = 0.0; + blend_weights[(j + 2) % 3] = 0.0; + } else { + float c = s[0].distance_to(closest) / d; + + blend_weights[j] = 1.0 - c; + blend_weights[(j + 1) % 3] = c; + blend_weights[(j + 2) % 3] = 0.0; + } } } } - } - ERR_FAIL_COND_V(blend_triangle == -1, 0); //should never reach here + ERR_FAIL_COND_V(blend_triangle == -1, 0); //should never reach here - int triangle_points[3]; - for (int j = 0; j < 3; j++) { - triangle_points[j] = get_triangle_point(blend_triangle, j); - } + int triangle_points[3]; + for (int j = 0; j < 3; j++) { + triangle_points[j] = get_triangle_point(blend_triangle, j); + } - first = true; - float mind; - for (int i = 0; i < blend_points_used; i++) { + first = true; - bool found = false; - for (int j = 0; j < 3; j++) { - if (i == triangle_points[j]) { - //blend with the given weight - float t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false); - if (first || t < mind) { - mind = t; - first = false; + for (int i = 0; i < blend_points_used; i++) { + + bool found = false; + for (int j = 0; j < 3; j++) { + if (i == triangle_points[j]) { + //blend with the given weight + float t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false); + if (first || t < mind) { + mind = t; + first = false; + } + found = true; + break; } - found = true; - break; + } + + if (!found) { + //ignore + blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false); + } + } + } else { + + int new_closest = -1; + float new_closest_dist = 1e20; + + for (int i = 0; i < blend_points_used; i++) { + + float d = blend_points[i].position.distance_squared_to(blend_pos); + if (d < new_closest_dist) { + + new_closest = i; + new_closest_dist = d; } } - if (!found) { - //ignore - blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false); + if (new_closest != closest) { + + float from = 0; + if (blend_mode == BLEND_MODE_DISCRETE_CARRY && closest != -1) { + //see how much animation remains + from = blend_node(blend_points[closest].name, blend_points[closest].node, p_time, true, 0.0, FILTER_IGNORE, false) - length_internal; + } + + mind = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, 1.0, FILTER_IGNORE, false) + from; + length_internal = from + mind; + + closest = new_closest; + + } else { + mind = blend_node(blend_points[closest].name, blend_points[closest].node, p_time, p_seek, 1.0, FILTER_IGNORE, false); } } + + set_parameter(this->closest, closest); + set_parameter(this->length_internal, length_internal); return mind; } @@ -527,6 +575,14 @@ void AnimationNodeBlendSpace2D::_tree_changed() { emit_signal("tree_changed"); } +void AnimationNodeBlendSpace2D::set_blend_mode(BlendMode p_blend_mode) { + blend_mode = p_blend_mode; +} + +AnimationNodeBlendSpace2D::BlendMode AnimationNodeBlendSpace2D::get_blend_mode() const { + return blend_mode; +} + void AnimationNodeBlendSpace2D::_bind_methods() { ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1)); @@ -565,6 +621,9 @@ void AnimationNodeBlendSpace2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_auto_triangles", "enable"), &AnimationNodeBlendSpace2D::set_auto_triangles); ClassDB::bind_method(D_METHOD("get_auto_triangles"), &AnimationNodeBlendSpace2D::get_auto_triangles); + ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &AnimationNodeBlendSpace2D::set_blend_mode); + ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace2D::get_blend_mode); + ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace2D::_tree_changed); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_auto_triangles", "get_auto_triangles"); @@ -581,6 +640,11 @@ void AnimationNodeBlendSpace2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "x_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_x_label", "get_x_label"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_y_label", "get_y_label"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NOEDITOR), "set_blend_mode", "get_blend_mode"); + + BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED); + BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE); + BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE_CARRY); } AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() { @@ -597,6 +661,9 @@ AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() { y_label = "y"; trianges_dirty = false; blend_position = "blend_position"; + closest = "closest"; + length_internal = "length_internal"; + blend_mode = BLEND_MODE_INTERPOLATED; } AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() { diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h index 2c684687de..60671f1816 100644 --- a/scene/animation/animation_blend_space_2d.h +++ b/scene/animation/animation_blend_space_2d.h @@ -35,7 +35,14 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode { GDCLASS(AnimationNodeBlendSpace2D, AnimationRootNode) +public: + enum BlendMode { + BLEND_MODE_INTERPOLATED, + BLEND_MODE_DISCRETE, + BLEND_MODE_DISCRETE_CARRY, + }; +protected: enum { MAX_BLEND_POINTS = 64 }; @@ -56,11 +63,14 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode { Vector<BlendTriangle> triangles; StringName blend_position; + StringName closest; + StringName length_internal; Vector2 max_space; Vector2 min_space; Vector2 snap; String x_label; String y_label; + BlendMode blend_mode; void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node); void _set_triangles(const Vector<int> &p_triangles); @@ -122,10 +132,15 @@ public: void set_auto_triangles(bool p_enable); bool get_auto_triangles() const; + void set_blend_mode(BlendMode p_blend_mode); + BlendMode get_blend_mode() const; + virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name); AnimationNodeBlendSpace2D(); ~AnimationNodeBlendSpace2D(); }; +VARIANT_ENUM_CAST(AnimationNodeBlendSpace2D::BlendMode) + #endif // ANIMATION_BLEND_SPACE_2D_H diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index b85d4e541e..5b413737a9 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -40,12 +40,11 @@ StringName AnimationNodeAnimation::get_animation() const { return animation; } -float AnimationNodeAnimation::get_playback_time() const { - return time; -} - Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = NULL; +void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) const { + r_list->push_back(PropertyInfo(Variant::REAL, time, PROPERTY_HINT_NONE, "", 0)); +} void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const { if (property.name == "animation" && get_editable_animation_list) { @@ -70,6 +69,8 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) { AnimationPlayer *ap = state->player; ERR_FAIL_COND_V(!ap, 0); + float time = get_parameter(this->time); + if (!ap->has_animation(animation)) { AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent); @@ -86,6 +87,8 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) { Ref<Animation> anim = ap->get_animation(animation); + float step; + if (p_seek) { time = p_time; step = 0; @@ -109,6 +112,8 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) { blend_animation(animation, time, step, p_seek, 1.0); + set_parameter(this->time, time); + return anim_size - time; } @@ -120,16 +125,13 @@ void AnimationNodeAnimation::_bind_methods() { ClassDB::bind_method(D_METHOD("set_animation", "name"), &AnimationNodeAnimation::set_animation); ClassDB::bind_method(D_METHOD("get_animation"), &AnimationNodeAnimation::get_animation); - ClassDB::bind_method(D_METHOD("get_playback_time"), &AnimationNodeAnimation::get_playback_time); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation"); } AnimationNodeAnimation::AnimationNodeAnimation() { last_version = 0; skip = false; - time = 0; - step = 0; + time = "time"; } //////////////////////////////////////////////////////// @@ -266,7 +268,6 @@ float AnimationNodeOneShot::process(float p_time, bool p_seek) { if (do_start) { remaining = os_rem; - do_start = false; } if (!p_seek) { @@ -699,7 +700,7 @@ String AnimationNodeTransition::get_input_caption(int p_input) const { if (tree.is_valid() && current >= 0) { prev = current; - prev_xfading = xfade; + prev_xfading = xfade; time = 0; current = p_current; switched = true; @@ -770,8 +771,6 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) { rem = blend_input(current, p_time, p_seek, 1.0 - blend, FILTER_IGNORE, false); } - switched = false; - if (p_seek) { // don't seek prev animation blend_input(prev, 0, false, blend, FILTER_IGNORE, false); time = p_time; diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index 4ca11e464b..5adb7fd71a 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -38,10 +38,9 @@ class AnimationNodeAnimation : public AnimationRootNode { GDCLASS(AnimationNodeAnimation, AnimationRootNode); StringName animation; + StringName time; uint64_t last_version; - float time; - float step; bool skip; protected: @@ -50,6 +49,8 @@ protected: static void _bind_methods(); public: + void get_parameter_list(List<PropertyInfo> *r_list) const; + static Vector<String> (*get_editable_animation_list)(); virtual String get_caption() const; @@ -58,8 +59,6 @@ public: void set_animation(const StringName &p_name); StringName get_animation() const; - float get_playback_time() const; - AnimationNodeAnimation(); }; diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 5923ad7657..a7af3f687b 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -345,7 +345,6 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *sm, len_current = sm->blend_node(current, sm->states[current].node, 0, true, 1.0, AnimationNode::FILTER_IGNORE, false); pos_current = 0; loops_current = 0; - play_start = false; } if (!sm->states.has(current)) { diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 7d91703cf8..7f9953ab43 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1120,6 +1120,15 @@ void AnimationPlayer::queue(const StringName &p_name) { queued.push_back(p_name); } +PoolVector<String> AnimationPlayer::get_queue() { + PoolVector<String> ret; + for (List<StringName>::Element *E = queued.front(); E; E = E->next()) { + ret.push_back(E->get()); + } + + return ret; +} + void AnimationPlayer::clear_queue() { queued.clear(); } @@ -1348,6 +1357,9 @@ void AnimationPlayer::_animation_changed() { clear_caches(); emit_signal("caches_cleared"); + if (is_playing()) { + playback.seeked = true; //need to restart stuff, like audio + } } void AnimationPlayer::_stop_playing_caches() { @@ -1451,6 +1463,7 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) { case ANIMATION_PROCESS_PHYSICS: set_physics_process_internal(p_process && active); break; case ANIMATION_PROCESS_IDLE: set_process_internal(p_process && active); break; + case ANIMATION_PROCESS_MANUAL: break; } processing = p_process; @@ -1599,6 +1612,7 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_assigned_animation", "anim"), &AnimationPlayer::set_assigned_animation); ClassDB::bind_method(D_METHOD("get_assigned_animation"), &AnimationPlayer::get_assigned_animation); ClassDB::bind_method(D_METHOD("queue", "name"), &AnimationPlayer::queue); + ClassDB::bind_method(D_METHOD("get_queue"), &AnimationPlayer::get_queue); ClassDB::bind_method(D_METHOD("clear_queue"), &AnimationPlayer::clear_queue); ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationPlayer::set_active); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index f50b2454ec..b3bf8b1e22 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -312,6 +312,7 @@ public: void play(const StringName &p_name = StringName(), float p_custom_blend = -1, float p_custom_scale = 1.0, bool p_from_end = false); void play_backwards(const StringName &p_name = StringName(), float p_custom_blend = -1); void queue(const StringName &p_name); + PoolVector<String> get_queue(); void clear_queue(); void stop(bool p_reset = true); bool is_playing() const; diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index eb00f91bb3..2c8cbbdbd1 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -37,9 +37,20 @@ #include "servers/audio/audio_stream.h" void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const { + if (get_script_instance()) { + Array parameters = get_script_instance()->call("get_parameter_list"); + for (int i = 0; i < parameters.size(); i++) { + Dictionary d = parameters[i]; + ERR_CONTINUE(d.empty()); + r_list->push_back(PropertyInfo::from_dict(d)); + } + } } Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const { + if (get_script_instance()) { + return get_script_instance()->call("get_parameter_default_value"); + } return Variant(); } @@ -62,6 +73,18 @@ Variant AnimationNode::get_parameter(const StringName &p_name) const { } void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) { + + if (get_script_instance()) { + Dictionary cn = get_script_instance()->call("get_child_nodes"); + List<Variant> keys; + cn.get_key_list(&keys); + for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { + ChildNode child; + child.name = E->get(); + child.node = cn[E->get()]; + r_child_nodes->push_back(child); + } + } } void AnimationNode::blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend) { @@ -373,6 +396,9 @@ void AnimationNode::_validate_property(PropertyInfo &property) const { } Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) { + if (get_script_instance()) { + return get_script_instance()->call("get_child_by_name"); + } return Ref<AnimationNode>(); } @@ -403,6 +429,14 @@ void AnimationNode::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_filter_enabled", "is_filter_enabled"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters"); + BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "get_child_nodes")); + BIND_VMETHOD(MethodInfo(Variant::ARRAY, "get_parameter_list")); + BIND_VMETHOD(MethodInfo(Variant::OBJECT, "get_child_by_name", PropertyInfo(Variant::STRING, "name"))); + { + MethodInfo mi = MethodInfo(Variant::NIL, "get_parameter_default_value", PropertyInfo(Variant::STRING, "name")); + mi.return_val.usage = PROPERTY_USAGE_NIL_IS_VARIANT; + BIND_VMETHOD(mi); + } BIND_VMETHOD(MethodInfo("process", PropertyInfo(Variant::REAL, "time"), PropertyInfo(Variant::BOOL, "seek"))); BIND_VMETHOD(MethodInfo(Variant::STRING, "get_caption")); BIND_VMETHOD(MethodInfo(Variant::STRING, "has_filter")); diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 179f5d9698..524784df53 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -877,6 +877,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) { tr.track->object->call(method, args[0], args[1], args[2], args[3], args[4]); } } break; + default: {} } } } diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp index 69975e6195..3119e29586 100644 --- a/scene/animation/skeleton_ik.cpp +++ b/scene/animation/skeleton_ik.cpp @@ -280,7 +280,7 @@ void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_ } } -void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool p_use_magnet, const Vector3 &p_magnet_position) { +void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position) { if (blending_delta <= 0.01f) { return; // Skip solving @@ -314,7 +314,10 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool p_u } } else { // Set target orientation to tip - new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis; + if (override_tip_basis) + new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis; + else + new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis; } p_task->skeleton->set_bone_global_pose(ci->bone, new_bone_pose); @@ -366,6 +369,9 @@ void SkeletonIK::_bind_methods() { ClassDB::bind_method(D_METHOD("set_target_node", "node"), &SkeletonIK::set_target_node); ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonIK::get_target_node); + ClassDB::bind_method(D_METHOD("set_override_tip_basis", "override"), &SkeletonIK::set_override_tip_basis); + ClassDB::bind_method(D_METHOD("is_override_tip_basis"), &SkeletonIK::is_override_tip_basis); + ClassDB::bind_method(D_METHOD("set_use_magnet", "use"), &SkeletonIK::set_use_magnet); ClassDB::bind_method(D_METHOD("is_using_magnet"), &SkeletonIK::is_using_magnet); @@ -388,6 +394,7 @@ void SkeletonIK::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "tip_bone"), "set_tip_bone", "get_tip_bone"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "interpolation", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_interpolation", "get_interpolation"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "target"), "set_target_transform", "get_target_transform"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_tip_basis"), "set_override_tip_basis", "is_override_tip_basis"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_magnet"), "set_use_magnet", "is_using_magnet"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "magnet"), "set_magnet_position", "get_magnet_position"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_node"), "set_target_node", "get_target_node"); @@ -418,11 +425,12 @@ void SkeletonIK::_notification(int p_what) { SkeletonIK::SkeletonIK() : Node(), interpolation(1), - skeleton(NULL), - target_node_override(NULL), + override_tip_basis(true), use_magnet(false), min_distance(0.01), max_iterations(10), + skeleton(NULL), + target_node_override(NULL), task(NULL) { set_process_priority(1); @@ -478,6 +486,14 @@ NodePath SkeletonIK::get_target_node() { return target_node_path_override; } +void SkeletonIK::set_override_tip_basis(bool p_override) { + override_tip_basis = p_override; +} + +bool SkeletonIK::is_override_tip_basis() const { + return override_tip_basis; +} + void SkeletonIK::set_use_magnet(bool p_use) { use_magnet = p_use; } @@ -555,7 +571,7 @@ void SkeletonIK::reload_goal() { void SkeletonIK::_solve_chain() { if (!task) return; - FabrikInverseKinematic::solve(task, interpolation, use_magnet, magnet_position); + FabrikInverseKinematic::solve(task, interpolation, override_tip_basis, use_magnet, magnet_position); } #endif // _3D_DISABLED diff --git a/scene/animation/skeleton_ik.h b/scene/animation/skeleton_ik.h index 202d6959bb..b9628c479c 100644 --- a/scene/animation/skeleton_ik.h +++ b/scene/animation/skeleton_ik.h @@ -138,7 +138,7 @@ public: // The goal of chain should be always in local space static void set_goal(Task *p_task, const Transform &p_goal); static void make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta); - static void solve(Task *p_task, real_t blending_delta, bool p_use_magnet, const Vector3 &p_magnet_position); + static void solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position); }; class SkeletonIK : public Node { @@ -149,6 +149,7 @@ class SkeletonIK : public Node { real_t interpolation; Transform target; NodePath target_node_path_override; + bool override_tip_basis; bool use_magnet; Vector3 magnet_position; @@ -185,6 +186,9 @@ public: void set_target_node(const NodePath &p_node); NodePath get_target_node(); + void set_override_tip_basis(bool p_override); + bool is_override_tip_basis() const; + void set_use_magnet(bool p_use); bool is_using_magnet() const; diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 82e2bb93e2..3521782417 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -277,7 +277,10 @@ Variant &Tween::_get_initial_val(InterpolateData &p_data) { ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, p_data.initial_val); } return initial_val; - } break; + } + + case INTER_CALLBACK: + break; } return p_data.delta_val; } @@ -313,7 +316,7 @@ Variant &Tween::_get_delta_val(InterpolateData &p_data) { if (final_val.get_type() == Variant::INT) final_val = final_val.operator real_t(); _calc_delta_val(p_data.initial_val, final_val, p_data.delta_val); return p_data.delta_val; - } break; + } case TARGETING_PROPERTY: case TARGETING_METHOD: { @@ -325,7 +328,10 @@ Variant &Tween::_get_delta_val(InterpolateData &p_data) { //_calc_delta_val(p_data.initial_val, p_data.final_val, p_data.delta_val); _calc_delta_val(initial_val, p_data.final_val, p_data.delta_val); return p_data.delta_val; - } break; + } + + case INTER_CALLBACK: + break; } return p_data.initial_val; } @@ -857,12 +863,8 @@ bool Tween::seek(real_t p_time) { data.finish = false; } - switch (data.type) { - case INTER_PROPERTY: - case INTER_METHOD: - break; - case INTER_CALLBACK: - continue; + if (data.type == INTER_CALLBACK) { + continue; } Variant result = _run_equation(data); diff --git a/scene/animation/tween_interpolaters.cpp b/scene/animation/tween_interpolaters.cpp deleted file mode 100644 index 52aa7403c0..0000000000 --- a/scene/animation/tween_interpolaters.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/*************************************************************************/ -/* tween_interpolaters.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 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. */ -/*************************************************************************/ - -/** - * Adapted from Penner Easing equations' C++ port. - * Source: https://github.com/jesusgollonet/ofpennereasing - * License: BSD-3-clause - */ - -#include "tween.h" - -const real_t pi = 3.1415926535898; - -/////////////////////////////////////////////////////////////////////////// -// linear -/////////////////////////////////////////////////////////////////////////// -namespace linear { -static real_t in(real_t t, real_t b, real_t c, real_t d) { - return c * t / d + b; -} - -static real_t out(real_t t, real_t b, real_t c, real_t d) { - return c * t / d + b; -} - -static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - return c * t / d + b; -} - -static real_t out_in(real_t t, real_t b, real_t c, real_t d) { - return c * t / d + b; -} -}; // namespace linear -/////////////////////////////////////////////////////////////////////////// -// sine -/////////////////////////////////////////////////////////////////////////// -namespace sine { -static real_t in(real_t t, real_t b, real_t c, real_t d) { - return -c * cos(t / d * (pi / 2)) + c + b; -} - -static real_t out(real_t t, real_t b, real_t c, real_t d) { - return c * sin(t / d * (pi / 2)) + b; -} - -static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - return -c / 2 * (cos(pi * t / d) - 1) + b; -} - -static real_t out_in(real_t t, real_t b, real_t c, real_t d) { - return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d); -} -}; // namespace sine -/////////////////////////////////////////////////////////////////////////// -// quint -/////////////////////////////////////////////////////////////////////////// -namespace quint { -static real_t in(real_t t, real_t b, real_t c, real_t d) { - return c * pow(t / d, 5) + b; -} - -static real_t out(real_t t, real_t b, real_t c, real_t d) { - return c * (pow(t / d - 1, 5) + 1) + b; -} - -static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - t = t / d * 2; - if (t < 1) return c / 2 * pow(t, 5) + b; - return c / 2 * (pow(t - 2, 5) + 2) + b; -} - -static real_t out_in(real_t t, real_t b, real_t c, real_t d) { - return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d); -} -}; // namespace quint -/////////////////////////////////////////////////////////////////////////// -// quart -/////////////////////////////////////////////////////////////////////////// -namespace quart { -static real_t in(real_t t, real_t b, real_t c, real_t d) { - return c * pow(t / d, 4) + b; -} - -static real_t out(real_t t, real_t b, real_t c, real_t d) { - return -c * (pow(t / d - 1, 4) - 1) + b; -} - -static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - t = t / d * 2; - if (t < 1) return c / 2 * pow(t, 4) + b; - return -c / 2 * (pow(t - 2, 4) - 2) + b; -} - -static real_t out_in(real_t t, real_t b, real_t c, real_t d) { - return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d); -} -}; // namespace quart -/////////////////////////////////////////////////////////////////////////// -// quad -/////////////////////////////////////////////////////////////////////////// -namespace quad { -static real_t in(real_t t, real_t b, real_t c, real_t d) { - return c * pow(t / d, 2) + b; -} - -static real_t out(real_t t, real_t b, real_t c, real_t d) { - t = t / d; - return -c * t * (t - 2) + b; -} - -static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - t = t / d * 2; - if (t < 1) return c / 2 * pow(t, 2) + b; - return -c / 2 * ((t - 1) * (t - 3) - 1) + b; -} - -static real_t out_in(real_t t, real_t b, real_t c, real_t d) { - return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d); -} -}; // namespace quad -/////////////////////////////////////////////////////////////////////////// -// expo -/////////////////////////////////////////////////////////////////////////// -namespace expo { -static real_t in(real_t t, real_t b, real_t c, real_t d) { - if (t == 0) return b; - return c * pow(2, 10 * (t / d - 1)) + b - c * 0.001; -} - -static real_t out(real_t t, real_t b, real_t c, real_t d) { - if (t == d) return b + c; - return c * 1.001 * (-pow(2, -10 * t / d) + 1) + b; -} - -static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - if (t == 0) return b; - if (t == d) return b + c; - t = t / d * 2; - if (t < 1) return c / 2 * pow(2, 10 * (t - 1)) + b - c * 0.0005; - return c / 2 * 1.0005 * (-pow(2, -10 * (t - 1)) + 2) + b; -} - -static real_t out_in(real_t t, real_t b, real_t c, real_t d) { - return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d); -} -}; // namespace expo -/////////////////////////////////////////////////////////////////////////// -// elastic -/////////////////////////////////////////////////////////////////////////// -namespace elastic { -static real_t in(real_t t, real_t b, real_t c, real_t d) { - if (t == 0) return b; - if ((t /= d) == 1) return b + c; - float p = d * 0.3f; - float a = c; - float s = p / 4; - float postFix = a * pow(2, 10 * (t -= 1)); // this is a fix, again, with post-increment operators - return -(postFix * sin((t * d - s) * (2 * pi) / p)) + b; -} - -static real_t out(real_t t, real_t b, real_t c, real_t d) { - if (t == 0) return b; - if ((t /= d) == 1) return b + c; - float p = d * 0.3f; - float a = c; - float s = p / 4; - return (a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p) + c + b); -} - -static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - if (t == 0) return b; - if ((t /= d / 2) == 2) return b + c; - float p = d * (0.3f * 1.5f); - float a = c; - float s = p / 4; - - if (t < 1) { - float postFix = a * pow(2, 10 * (t -= 1)); // postIncrement is evil - return -0.5f * (postFix * sin((t * d - s) * (2 * pi) / p)) + b; - } - float postFix = a * pow(2, -10 * (t -= 1)); // postIncrement is evil - return postFix * sin((t * d - s) * (2 * pi) / p) * 0.5f + c + b; -} - -static real_t out_in(real_t t, real_t b, real_t c, real_t d) { - return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d); -} -}; // namespace elastic -/////////////////////////////////////////////////////////////////////////// -// cubic -/////////////////////////////////////////////////////////////////////////// -namespace cubic { -static real_t in(real_t t, real_t b, real_t c, real_t d) { - return c * (t /= d) * t * t + b; -} - -static real_t out(real_t t, real_t b, real_t c, real_t d) { - t = t / d - 1; - return c * (t * t * t + 1) + b; -} - -static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - if ((t /= d / 2) < 1) return c / 2 * t * t * t + b; - return c / 2 * ((t -= 2) * t * t + 2) + b; -} - -static real_t out_in(real_t t, real_t b, real_t c, real_t d) { - return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d); -} -}; // namespace cubic -/////////////////////////////////////////////////////////////////////////// -// circ -/////////////////////////////////////////////////////////////////////////// -namespace circ { -static real_t in(real_t t, real_t b, real_t c, real_t d) { - return -c * (sqrt(1 - (t /= d) * t) - 1) + b; // TODO: ehrich: operation with t is undefined -} - -static real_t out(real_t t, real_t b, real_t c, real_t d) { - return c * sqrt(1 - (t = t / d - 1) * t) + b; // TODO: ehrich: operation with t is undefined -} - -static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - if ((t /= d / 2) < 1) return -c / 2 * (sqrt(1 - t * t) - 1) + b; - return c / 2 * (sqrt(1 - t * (t -= 2)) + 1) + b; // TODO: ehrich: operation with t is undefined -} - -static real_t out_in(real_t t, real_t b, real_t c, real_t d) { - return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d); -} -}; // namespace circ -/////////////////////////////////////////////////////////////////////////// -// bounce -/////////////////////////////////////////////////////////////////////////// -namespace bounce { -static real_t out(real_t t, real_t b, real_t c, real_t d); - -static real_t in(real_t t, real_t b, real_t c, real_t d) { - return c - out(d - t, 0, c, d) + b; -} - -static real_t out(real_t t, real_t b, real_t c, real_t d) { - if ((t /= d) < (1 / 2.75f)) { - return c * (7.5625f * t * t) + b; - } else if (t < (2 / 2.75f)) { - float postFix = t -= (1.5f / 2.75f); - return c * (7.5625f * (postFix)*t + .75f) + b; - } else if (t < (2.5 / 2.75)) { - float postFix = t -= (2.25f / 2.75f); - return c * (7.5625f * (postFix)*t + .9375f) + b; - } else { - float postFix = t -= (2.625f / 2.75f); - return c * (7.5625f * (postFix)*t + .984375f) + b; - } -} - -static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - return (t < d / 2) ? in(t * 2, b, c / 2, d) : out((t * 2) - d, b + c / 2, c / 2, d); -} - -static real_t out_in(real_t t, real_t b, real_t c, real_t d) { - return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d); -} -}; // namespace bounce -/////////////////////////////////////////////////////////////////////////// -// back -/////////////////////////////////////////////////////////////////////////// -namespace back { -static real_t in(real_t t, real_t b, real_t c, real_t d) { - float s = 1.70158f; - float postFix = t /= d; - return c * (postFix)*t * ((s + 1) * t - s) + b; -} - -static real_t out(real_t t, real_t b, real_t c, real_t d) { - float s = 1.70158f; - return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; // TODO: ehrich: operation with t is undefined -} - -static real_t in_out(real_t t, real_t b, real_t c, real_t d) { - float s = 1.70158f; - if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525f)) + 1) * t - s)) + b; // TODO: ehrich: operation with s is undefined - float postFix = t -= 2; - return c / 2 * ((postFix)*t * (((s *= (1.525f)) + 1) * t + s) + 2) + b; // TODO: ehrich: operation with s is undefined -} - -static real_t out_in(real_t t, real_t b, real_t c, real_t d) { - return (t < d / 2) ? out(t * 2, b, c / 2, d) : in((t * 2) - d, b + c / 2, c / 2, d); -} -}; // namespace back - -Tween::interpolater Tween::interpolaters[Tween::TRANS_COUNT][Tween::EASE_COUNT] = { - { &linear::in, &linear::out, &linear::in_out, &linear::out_in }, - { &sine::in, &sine::out, &sine::in_out, &sine::out_in }, - { &quint::in, &quint::out, &quint::in_out, &quint::out_in }, - { &quart::in, &quart::out, &quart::in_out, &quart::out_in }, - { &quad::in, &quad::out, &quad::in_out, &quad::out_in }, - { &expo::in, &expo::out, &expo::in_out, &expo::out_in }, - { &elastic::in, &elastic::out, &elastic::in_out, &elastic::out_in }, - { &cubic::in, &cubic::out, &cubic::in_out, &cubic::out_in }, - { &circ::in, &circ::out, &circ::in_out, &circ::out_in }, - { &bounce::in, &bounce::out, &bounce::in_out, &bounce::out_in }, - { &back::in, &back::out, &back::in_out, &back::out_in }, -}; - -real_t Tween::_run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d) { - - interpolater cb = interpolaters[p_trans_type][p_ease_type]; - ERR_FAIL_COND_V(cb == NULL, b); - return cb(t, b, c, d); -} |