diff options
author | Silc 'Tokage' Renew <tokage.it.lab@gmail.com> | 2021-10-15 22:25:00 +0900 |
---|---|---|
committer | Silc 'Tokage' Renew <tokage.it.lab@gmail.com> | 2021-11-03 13:39:33 +0900 |
commit | 953a7bce7edf289dd8d2a1a6c8ecd8105380c8da (patch) | |
tree | a460d22509538abda5248c0b3ea7dc96d054b638 /scene/resources | |
parent | af80bc8abecc30c77901967281679e380fb9f952 (diff) |
reimplement ping-pong
Diffstat (limited to 'scene/resources')
-rw-r--r-- | scene/resources/animation.cpp | 679 | ||||
-rw-r--r-- | scene/resources/animation.h | 24 | ||||
-rw-r--r-- | scene/resources/audio_stream_sample.cpp | 6 | ||||
-rw-r--r-- | scene/resources/audio_stream_sample.h | 2 |
4 files changed, 477 insertions, 234 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 06ce993cc7..804f26a847 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -449,8 +449,8 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { return true; } else if (name == "length") { r_ret = length; - } else if (name == "loop") { - r_ret = loop; + } else if (name == "loop_mode") { + r_ret = loop_mode; } else if (name == "step") { r_ret = step; } else if (name.begins_with("tracks/")) { @@ -2231,7 +2231,7 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, real_t p_tr } template <class K> -int Animation::_find(const Vector<K> &p_keys, double p_time) const { +int Animation::_find(const Vector<K> &p_keys, double p_time, bool p_backward) const { int len = p_keys.size(); if (len == 0) { return -2; @@ -2261,8 +2261,14 @@ int Animation::_find(const Vector<K> &p_keys, double p_time) const { } } - if (keys[middle].time > p_time) { - middle--; + if (!p_backward) { + if (keys[middle].time > p_time) { + middle--; + } + } else { + if (keys[middle].time < p_time) { + middle++; + } } return middle; @@ -2385,7 +2391,7 @@ real_t Animation::_cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, c } template <class T> -T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const { +T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward) const { int len = _find(p_keys, length) + 1; // try to find last key (there may be more past the end) if (len <= 0) { @@ -2403,7 +2409,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol return p_keys[0].value; } - int idx = _find(p_keys, p_time); + int idx = _find(p_keys, p_time, p_backward); ERR_FAIL_COND_V(idx == -2, T()); @@ -2412,24 +2418,42 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol real_t c = 0.0; // prepare for all cases of interpolation - if (loop && p_loop_wrap) { + if ((loop_mode == LOOP_LINEAR || loop_mode == LOOP_PINGPONG) && p_loop_wrap) { // loop - if (idx >= 0) { - if ((idx + 1) < len) { - next = idx + 1; - real_t delta = p_keys[next].time - p_keys[idx].time; - real_t from = p_time - p_keys[idx].time; - - if (Math::is_zero_approx(delta)) { - c = 0; + if (!p_backward) { + // no backward + if (idx >= 0) { + if (idx < len - 1) { + next = idx + 1; + real_t delta = p_keys[next].time - p_keys[idx].time; + real_t from = p_time - p_keys[idx].time; + + if (Math::is_zero_approx(delta)) { + c = 0; + } else { + c = from / delta; + } } else { - c = from / delta; - } + next = 0; + real_t delta = (length - p_keys[idx].time) + p_keys[next].time; + real_t from = p_time - p_keys[idx].time; + if (Math::is_zero_approx(delta)) { + c = 0; + } else { + c = from / delta; + } + } } else { + // on loop, behind first key + idx = len - 1; next = 0; - real_t delta = (length - p_keys[idx].time) + p_keys[next].time; - real_t from = p_time - p_keys[idx].time; + real_t endtime = (length - p_keys[idx].time); + if (endtime < 0) { // may be keys past the end + endtime = 0; + } + real_t delta = endtime + p_keys[next].time; + real_t from = endtime + p_time; if (Math::is_zero_approx(delta)) { c = 0; @@ -2437,49 +2461,81 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol c = from / delta; } } - } else { - // on loop, behind first key - idx = len - 1; - next = 0; - real_t endtime = (length - p_keys[idx].time); - if (endtime < 0) { // may be keys past the end - endtime = 0; - } - real_t delta = endtime + p_keys[next].time; - real_t from = endtime + p_time; - - if (Math::is_zero_approx(delta)) { - c = 0; + // backward + if (idx <= len - 1) { + if (idx > 0) { + next = idx - 1; + real_t delta = (length - p_keys[next].time) - (length - p_keys[idx].time); + real_t from = (length - p_time) - (length - p_keys[idx].time); + + if (Math::is_zero_approx(delta)) + c = 0; + else + c = from / delta; + } else { + next = len - 1; + real_t delta = p_keys[idx].time + (length - p_keys[next].time); + real_t from = (length - p_time) - (length - p_keys[idx].time); + + if (Math::is_zero_approx(delta)) + c = 0; + else + c = from / delta; + } } else { - c = from / delta; + // on loop, in front of last key + idx = 0; + next = len - 1; + real_t endtime = p_keys[idx].time; + if (endtime > length) // may be keys past the end + endtime = length; + real_t delta = p_keys[next].time - endtime; + real_t from = p_time - endtime; + + if (Math::is_zero_approx(delta)) + c = 0; + else + c = from / delta; } } - } else { // no loop - - if (idx >= 0) { - if ((idx + 1) < len) { - next = idx + 1; - real_t delta = p_keys[next].time - p_keys[idx].time; - real_t from = p_time - p_keys[idx].time; - - if (Math::is_zero_approx(delta)) { - c = 0; + if (!p_backward) { + if (idx >= 0) { + if (idx < len - 1) { + next = idx + 1; + real_t delta = p_keys[next].time - p_keys[idx].time; + real_t from = p_time - p_keys[idx].time; + + if (Math::is_zero_approx(delta)) { + c = 0; + } else { + c = from / delta; + } } else { - c = from / delta; + next = idx; } - } else { - next = idx; + idx = next = 0; } - } else { - // only allow extending first key to anim start if looping - if (loop) { - idx = next = 0; + if (idx <= len - 1) { + if (idx > 0) { + next = idx - 1; + real_t delta = (length - p_keys[next].time) - (length - p_keys[idx].time); + real_t from = (length - p_time) - (length - p_keys[idx].time); + + if (Math::is_zero_approx(delta)) { + c = 0; + } else { + c = from / delta; + } + + } else { + next = idx; + } } else { - result = false; + idx = next = len - 1; } } } @@ -2583,7 +2639,7 @@ void Animation::_value_track_get_key_indices_in_range(const ValueTrack *vt, doub } } -void Animation::value_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices) const { +void Animation::value_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged) const { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; ERR_FAIL_COND(t->type != TYPE_VALUE); @@ -2597,30 +2653,50 @@ void Animation::value_track_get_key_indices(int p_track, double p_time, double p SWAP(from_time, to_time); } - if (loop) { - from_time = Math::fposmod(from_time, length); - to_time = Math::fposmod(to_time, length); + switch (loop_mode) { + case LOOP_NONE: { + if (from_time < 0) { + from_time = 0; + } + if (from_time > length) { + from_time = length; + } - if (from_time > to_time) { - // handle loop by splitting - _value_track_get_key_indices_in_range(vt, from_time, length, p_indices); - _value_track_get_key_indices_in_range(vt, 0, to_time, p_indices); - return; - } - } else { - if (from_time < 0) { - from_time = 0; - } - if (from_time > length) { - from_time = length; - } + if (to_time < 0) { + to_time = 0; + } + if (to_time > length) { + to_time = length; + } + } break; + case LOOP_LINEAR: { + from_time = Math::fposmod(from_time, length); + to_time = Math::fposmod(to_time, length); - if (to_time < 0) { - to_time = 0; - } - if (to_time > length) { - to_time = length; - } + if (from_time > to_time) { + // handle loop by splitting + _value_track_get_key_indices_in_range(vt, from_time, length, p_indices); + _value_track_get_key_indices_in_range(vt, 0, to_time, p_indices); + return; + } + } break; + case LOOP_PINGPONG: { + from_time = Math::pingpong(from_time, length); + to_time = Math::pingpong(to_time, length); + + if (p_pingponged == -1) { + // handle loop by splitting + _value_track_get_key_indices_in_range(vt, 0, from_time, p_indices); + _value_track_get_key_indices_in_range(vt, 0, to_time, p_indices); + return; + } + if (p_pingponged == 1) { + // handle loop by splitting + _value_track_get_key_indices_in_range(vt, from_time, length, p_indices); + _value_track_get_key_indices_in_range(vt, to_time, length, p_indices); + return; + } + } break; } _value_track_get_key_indices_in_range(vt, from_time, to_time, p_indices); @@ -2679,7 +2755,7 @@ void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, double } } -void Animation::track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices) const { +void Animation::track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged) const { ERR_FAIL_INDEX(p_track, tracks.size()); const Track *t = tracks[p_track]; @@ -2690,114 +2766,255 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl SWAP(from_time, to_time); } - if (loop) { - if (from_time > length || from_time < 0) { - from_time = Math::fposmod(from_time, length); - } - - if (to_time > length || to_time < 0) { - to_time = Math::fposmod(to_time, length); - } - - if (from_time > to_time) { - // handle loop by splitting - - switch (t->type) { - case TYPE_POSITION_3D: { - const PositionTrack *tt = static_cast<const PositionTrack *>(t); - if (tt->compressed_track >= 0) { - _get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, length, p_indices); - _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, to_time, p_indices); - - } else { - _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); - if (rt->compressed_track >= 0) { - _get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, length, p_indices); - _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, to_time, p_indices); + switch (loop_mode) { + case LOOP_NONE: { + if (from_time < 0) { + from_time = 0; + } + if (from_time > length) { + from_time = length; + } - } else { - _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); - } + if (to_time < 0) { + to_time = 0; + } + if (to_time > length) { + to_time = length; + } + } break; + case LOOP_LINEAR: { + if (from_time > length || from_time < 0) { + from_time = Math::fposmod(from_time, length); + } + if (to_time > length || to_time < 0) { + to_time = Math::fposmod(to_time, length); + } - } break; - case TYPE_SCALE_3D: { - const ScaleTrack *st = static_cast<const ScaleTrack *>(t); - if (st->compressed_track >= 0) { - _get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, length, p_indices); - _get_compressed_key_indices_in_range<3>(st->compressed_track, 0, to_time, p_indices); + if (from_time > to_time) { + // handle loop by splitting + switch (t->type) { + case TYPE_POSITION_3D: { + const PositionTrack *tt = static_cast<const PositionTrack *>(t); + if (tt->compressed_track >= 0) { + _get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, length, p_indices); + _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, to_time, p_indices); + } else { + _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); + if (rt->compressed_track >= 0) { + _get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, length, p_indices); + _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, to_time, p_indices); + } else { + _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); + if (st->compressed_track >= 0) { + _get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, length, p_indices); + _get_compressed_key_indices_in_range<3>(st->compressed_track, 0, to_time, p_indices); + } else { + _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_BLEND_SHAPE: { + const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t); + if (bst->compressed_track >= 0) { + _get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices); + _get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, to_time, p_indices); + } else { + _track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices); + _track_get_key_indices_in_range(bst->blend_shapes, 0, to_time, p_indices); + } + } break; + case TYPE_VALUE: { + const ValueTrack *vt = static_cast<const ValueTrack *>(t); + _track_get_key_indices_in_range(vt->values, from_time, length, p_indices); + _track_get_key_indices_in_range(vt->values, 0, to_time, p_indices); + } break; + case TYPE_METHOD: { + const MethodTrack *mt = static_cast<const MethodTrack *>(t); + _track_get_key_indices_in_range(mt->methods, from_time, length, p_indices); + _track_get_key_indices_in_range(mt->methods, 0, to_time, p_indices); + } break; + case TYPE_BEZIER: { + const BezierTrack *bz = static_cast<const BezierTrack *>(t); + _track_get_key_indices_in_range(bz->values, from_time, length, p_indices); + _track_get_key_indices_in_range(bz->values, 0, to_time, p_indices); + } break; + case TYPE_AUDIO: { + const AudioTrack *ad = static_cast<const AudioTrack *>(t); + _track_get_key_indices_in_range(ad->values, from_time, length, p_indices); + _track_get_key_indices_in_range(ad->values, 0, to_time, p_indices); + } break; + case TYPE_ANIMATION: { + const AnimationTrack *an = static_cast<const AnimationTrack *>(t); + _track_get_key_indices_in_range(an->values, from_time, length, p_indices); + _track_get_key_indices_in_range(an->values, 0, to_time, p_indices); + } break; + } + return; + } + } break; + case LOOP_PINGPONG: { + if (from_time > length || from_time < 0) { + from_time = Math::pingpong(from_time, length); + } + if (to_time > length || to_time < 0) { + to_time = Math::pingpong(to_time, length); + } - } else { - _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); + if ((int)Math::floor(abs(p_delta) / length) % 2 == 0) { + if (p_pingponged == -1) { + // handle loop by splitting + switch (t->type) { + case TYPE_POSITION_3D: { + const PositionTrack *tt = static_cast<const PositionTrack *>(t); + if (tt->compressed_track >= 0) { + _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, from_time, p_indices); + _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, to_time, p_indices); + } else { + _track_get_key_indices_in_range(tt->positions, 0, from_time, 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); + if (rt->compressed_track >= 0) { + _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, from_time, p_indices); + _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, to_time, p_indices); + } else { + _track_get_key_indices_in_range(rt->rotations, 0, from_time, 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); + if (st->compressed_track >= 0) { + _get_compressed_key_indices_in_range<3>(st->compressed_track, 0, from_time, p_indices); + _get_compressed_key_indices_in_range<3>(st->compressed_track, 0, to_time, p_indices); + } else { + _track_get_key_indices_in_range(st->scales, 0, from_time, p_indices); + _track_get_key_indices_in_range(st->scales, 0, to_time, p_indices); + } + } break; + case TYPE_BLEND_SHAPE: { + const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t); + if (bst->compressed_track >= 0) { + _get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, from_time, p_indices); + _get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, to_time, p_indices); + } else { + _track_get_key_indices_in_range(bst->blend_shapes, 0, from_time, p_indices); + _track_get_key_indices_in_range(bst->blend_shapes, 0, to_time, p_indices); + } + } break; + case TYPE_VALUE: { + const ValueTrack *vt = static_cast<const ValueTrack *>(t); + _track_get_key_indices_in_range(vt->values, 0, from_time, p_indices); + _track_get_key_indices_in_range(vt->values, 0, to_time, p_indices); + } break; + case TYPE_METHOD: { + const MethodTrack *mt = static_cast<const MethodTrack *>(t); + _track_get_key_indices_in_range(mt->methods, 0, from_time, p_indices); + _track_get_key_indices_in_range(mt->methods, 0, to_time, p_indices); + } break; + case TYPE_BEZIER: { + const BezierTrack *bz = static_cast<const BezierTrack *>(t); + _track_get_key_indices_in_range(bz->values, 0, from_time, p_indices); + _track_get_key_indices_in_range(bz->values, 0, to_time, p_indices); + } break; + case TYPE_AUDIO: { + const AudioTrack *ad = static_cast<const AudioTrack *>(t); + _track_get_key_indices_in_range(ad->values, 0, from_time, p_indices); + _track_get_key_indices_in_range(ad->values, 0, to_time, p_indices); + } break; + case TYPE_ANIMATION: { + const AnimationTrack *an = static_cast<const AnimationTrack *>(t); + _track_get_key_indices_in_range(an->values, 0, from_time, p_indices); + _track_get_key_indices_in_range(an->values, 0, to_time, p_indices); + } break; } - - } break; - case TYPE_BLEND_SHAPE: { - const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t); - if (bst->compressed_track >= 0) { - _get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices); - _get_compressed_key_indices_in_range<1>(bst->compressed_track, 0, to_time, p_indices); - - } else { - _track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices); - _track_get_key_indices_in_range(bst->blend_shapes, 0, to_time, p_indices); + return; + } + if (p_pingponged == 1) { + // handle loop by splitting + switch (t->type) { + case TYPE_POSITION_3D: { + const PositionTrack *tt = static_cast<const PositionTrack *>(t); + if (tt->compressed_track >= 0) { + _get_compressed_key_indices_in_range<3>(tt->compressed_track, from_time, length, p_indices); + _get_compressed_key_indices_in_range<3>(tt->compressed_track, to_time, length, p_indices); + } else { + _track_get_key_indices_in_range(tt->positions, from_time, length, p_indices); + _track_get_key_indices_in_range(tt->positions, to_time, length, p_indices); + } + } break; + case TYPE_ROTATION_3D: { + const RotationTrack *rt = static_cast<const RotationTrack *>(t); + if (rt->compressed_track >= 0) { + _get_compressed_key_indices_in_range<3>(rt->compressed_track, from_time, length, p_indices); + _get_compressed_key_indices_in_range<3>(rt->compressed_track, to_time, length, p_indices); + } else { + _track_get_key_indices_in_range(rt->rotations, from_time, length, p_indices); + _track_get_key_indices_in_range(rt->rotations, to_time, length, p_indices); + } + } break; + case TYPE_SCALE_3D: { + const ScaleTrack *st = static_cast<const ScaleTrack *>(t); + if (st->compressed_track >= 0) { + _get_compressed_key_indices_in_range<3>(st->compressed_track, from_time, length, p_indices); + _get_compressed_key_indices_in_range<3>(st->compressed_track, to_time, length, p_indices); + } else { + _track_get_key_indices_in_range(st->scales, from_time, length, p_indices); + _track_get_key_indices_in_range(st->scales, to_time, length, p_indices); + } + } break; + case TYPE_BLEND_SHAPE: { + const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t); + if (bst->compressed_track >= 0) { + _get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices); + _get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length, p_indices); + } else { + _track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices); + _track_get_key_indices_in_range(bst->blend_shapes, to_time, length, p_indices); + } + } break; + case TYPE_VALUE: { + const ValueTrack *vt = static_cast<const ValueTrack *>(t); + _track_get_key_indices_in_range(vt->values, from_time, length, p_indices); + _track_get_key_indices_in_range(vt->values, to_time, length, p_indices); + } break; + case TYPE_METHOD: { + const MethodTrack *mt = static_cast<const MethodTrack *>(t); + _track_get_key_indices_in_range(mt->methods, from_time, length, p_indices); + _track_get_key_indices_in_range(mt->methods, to_time, length, p_indices); + } break; + case TYPE_BEZIER: { + const BezierTrack *bz = static_cast<const BezierTrack *>(t); + _track_get_key_indices_in_range(bz->values, from_time, length, p_indices); + _track_get_key_indices_in_range(bz->values, to_time, length, p_indices); + } break; + case TYPE_AUDIO: { + const AudioTrack *ad = static_cast<const AudioTrack *>(t); + _track_get_key_indices_in_range(ad->values, from_time, length, p_indices); + _track_get_key_indices_in_range(ad->values, to_time, length, p_indices); + } break; + case TYPE_ANIMATION: { + const AnimationTrack *an = static_cast<const AnimationTrack *>(t); + _track_get_key_indices_in_range(an->values, from_time, length, p_indices); + _track_get_key_indices_in_range(an->values, to_time, length, p_indices); + } break; } - - } break; - case TYPE_VALUE: { - const ValueTrack *vt = static_cast<const ValueTrack *>(t); - _track_get_key_indices_in_range(vt->values, from_time, length, p_indices); - _track_get_key_indices_in_range(vt->values, 0, to_time, p_indices); - - } break; - case TYPE_METHOD: { - const MethodTrack *mt = static_cast<const MethodTrack *>(t); - _track_get_key_indices_in_range(mt->methods, from_time, length, p_indices); - _track_get_key_indices_in_range(mt->methods, 0, to_time, p_indices); - - } break; - case TYPE_BEZIER: { - const BezierTrack *bz = static_cast<const BezierTrack *>(t); - _track_get_key_indices_in_range(bz->values, from_time, length, p_indices); - _track_get_key_indices_in_range(bz->values, 0, to_time, p_indices); - - } break; - case TYPE_AUDIO: { - const AudioTrack *ad = static_cast<const AudioTrack *>(t); - _track_get_key_indices_in_range(ad->values, from_time, length, p_indices); - _track_get_key_indices_in_range(ad->values, 0, to_time, p_indices); - - } break; - case TYPE_ANIMATION: { - const AnimationTrack *an = static_cast<const AnimationTrack *>(t); - _track_get_key_indices_in_range(an->values, from_time, length, p_indices); - _track_get_key_indices_in_range(an->values, 0, to_time, p_indices); - - } break; + return; + } } - return; - } - } else { - if (from_time < 0) { - from_time = 0; - } - if (from_time > length) { - from_time = length; - } - - if (to_time < 0) { - to_time = 0; - } - if (to_time > length) { - to_time = length; - } + } break; } switch (t->type) { @@ -2808,7 +3025,6 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl } else { _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); @@ -2817,7 +3033,6 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl } else { _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); @@ -2826,7 +3041,6 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl } else { _track_get_key_indices_in_range(st->scales, from_time, to_time, p_indices); } - } break; case TYPE_BLEND_SHAPE: { const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t); @@ -2835,32 +3049,26 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl } else { _track_get_key_indices_in_range(bst->blend_shapes, from_time, to_time, p_indices); } - } break; case TYPE_VALUE: { const ValueTrack *vt = static_cast<const ValueTrack *>(t); _track_get_key_indices_in_range(vt->values, from_time, to_time, p_indices); - } break; case TYPE_METHOD: { const MethodTrack *mt = static_cast<const MethodTrack *>(t); _track_get_key_indices_in_range(mt->methods, from_time, to_time, p_indices); - } break; case TYPE_BEZIER: { const BezierTrack *bz = static_cast<const BezierTrack *>(t); _track_get_key_indices_in_range(bz->values, from_time, to_time, p_indices); - } break; case TYPE_AUDIO: { const AudioTrack *ad = static_cast<const AudioTrack *>(t); _track_get_key_indices_in_range(ad->values, from_time, to_time, p_indices); - } break; case TYPE_ANIMATION: { const AnimationTrack *an = static_cast<const AnimationTrack *>(t); _track_get_key_indices_in_range(an->values, from_time, to_time, p_indices); - } break; } } @@ -2898,7 +3106,7 @@ void Animation::_method_track_get_key_indices_in_range(const MethodTrack *mt, do } } -void Animation::method_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices) const { +void Animation::method_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged) const { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; ERR_FAIL_COND(t->type != TYPE_METHOD); @@ -2912,35 +3120,58 @@ void Animation::method_track_get_key_indices(int p_track, double p_time, double SWAP(from_time, to_time); } - if (loop) { - if (from_time > length || from_time < 0) { - from_time = Math::fposmod(from_time, length); - } + switch (loop_mode) { + case LOOP_NONE: { + if (from_time < 0) { + from_time = 0; + } + if (from_time > length) { + from_time = length; + } - if (to_time > length || to_time < 0) { - to_time = Math::fposmod(to_time, length); - } + if (to_time < 0) { + to_time = 0; + } + if (to_time > length) { + to_time = length; + } + } break; + case LOOP_LINEAR: { + if (from_time > length || from_time < 0) { + from_time = Math::fposmod(from_time, length); + } + if (to_time > length || to_time < 0) { + to_time = Math::fposmod(to_time, length); + } - if (from_time > to_time) { - // handle loop by splitting - _method_track_get_key_indices_in_range(mt, from_time, length, p_indices); - _method_track_get_key_indices_in_range(mt, 0, to_time, p_indices); - return; - } - } else { - if (from_time < 0) { - from_time = 0; - } - if (from_time > length) { - from_time = length; - } + if (from_time > to_time) { + // handle loop by splitting + _method_track_get_key_indices_in_range(mt, from_time, length, p_indices); + _method_track_get_key_indices_in_range(mt, 0, to_time, p_indices); + return; + } + } break; + case LOOP_PINGPONG: { + if (from_time > length || from_time < 0) { + from_time = Math::pingpong(from_time, length); + } + if (to_time > length || to_time < 0) { + to_time = Math::pingpong(to_time, length); + } - if (to_time < 0) { - to_time = 0; - } - if (to_time > length) { - to_time = length; - } + if (p_pingponged == -1) { + _method_track_get_key_indices_in_range(mt, 0, from_time, p_indices); + _method_track_get_key_indices_in_range(mt, 0, to_time, p_indices); + return; + } + if (p_pingponged == 1) { + _method_track_get_key_indices_in_range(mt, from_time, length, p_indices); + _method_track_get_key_indices_in_range(mt, to_time, length, p_indices); + return; + } + } break; + default: + break; } _method_track_get_key_indices_in_range(mt, from_time, to_time, p_indices); @@ -3326,13 +3557,13 @@ real_t Animation::get_length() const { return length; } -void Animation::set_loop(bool p_enabled) { - loop = p_enabled; +void Animation::set_loop_mode(Animation::LoopMode p_loop_mode) { + loop_mode = p_loop_mode; emit_changed(); } -bool Animation::has_loop() const { - return loop; +Animation::LoopMode Animation::get_loop_mode() const { + return loop_mode; } void Animation::track_set_imported(int p_track, bool p_imported) { @@ -3514,8 +3745,8 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("set_length", "time_sec"), &Animation::set_length); ClassDB::bind_method(D_METHOD("get_length"), &Animation::get_length); - ClassDB::bind_method(D_METHOD("set_loop", "enabled"), &Animation::set_loop); - ClassDB::bind_method(D_METHOD("has_loop"), &Animation::has_loop); + ClassDB::bind_method(D_METHOD("set_loop_mode", "loop_mode"), &Animation::set_loop_mode); + ClassDB::bind_method(D_METHOD("get_loop_mode"), &Animation::get_loop_mode); ClassDB::bind_method(D_METHOD("set_step", "size_sec"), &Animation::set_step); ClassDB::bind_method(D_METHOD("get_step"), &Animation::get_step); @@ -3526,7 +3757,7 @@ void Animation::_bind_methods() { ClassDB::bind_method(D_METHOD("compress", "page_size", "fps", "split_tolerance"), &Animation::compress, DEFVAL(8192), DEFVAL(120), DEFVAL(4.0)); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "0.001,99999,0.001"), "set_length", "get_length"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode"), "set_loop_mode", "get_loop_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step", PROPERTY_HINT_RANGE, "0,4096,0.001"), "set_step", "get_step"); ADD_SIGNAL(MethodInfo("tracks_changed")); @@ -3549,6 +3780,10 @@ void Animation::_bind_methods() { BIND_ENUM_CONSTANT(UPDATE_DISCRETE); BIND_ENUM_CONSTANT(UPDATE_TRIGGER); BIND_ENUM_CONSTANT(UPDATE_CAPTURE); + + BIND_ENUM_CONSTANT(LOOP_NONE); + BIND_ENUM_CONSTANT(LOOP_LINEAR); + BIND_ENUM_CONSTANT(LOOP_PINGPONG); } void Animation::clear() { @@ -3556,7 +3791,7 @@ void Animation::clear() { memdelete(tracks[i]); } tracks.clear(); - loop = false; + loop_mode = LOOP_NONE; length = 1; compression.enabled = false; compression.bounds.clear(); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index ee07fb19d3..510d6c8323 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -64,7 +64,12 @@ public: UPDATE_DISCRETE, UPDATE_TRIGGER, UPDATE_CAPTURE, + }; + enum LoopMode { + LOOP_NONE, + LOOP_LINEAR, + LOOP_PINGPONG, }; private: @@ -208,7 +213,8 @@ private: int _insert(double p_time, T &p_keys, const V &p_value); template <class K> - inline int _find(const Vector<K> &p_keys, double p_time) const; + + inline int _find(const Vector<K> &p_keys, double p_time, bool p_backward = false) 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; @@ -221,7 +227,7 @@ private: _FORCE_INLINE_ real_t _cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c) const; template <class T> - _FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const; + _FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward = false) const; template <class T> _FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices) const; @@ -231,7 +237,8 @@ private: double length = 1.0; real_t step = 0.1; - bool loop = false; + LoopMode loop_mode = LOOP_NONE; + int pingponged = 0; /* Animation compression page format (version 1): * @@ -438,23 +445,23 @@ public: bool track_get_interpolation_loop_wrap(int p_track) 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_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged = 0) const; void value_track_set_update_mode(int p_track, UpdateMode p_mode); UpdateMode value_track_get_update_mode(int p_track) const; - void method_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices) const; + void method_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged = 0) const; Vector<Variant> method_track_get_params(int p_track, int p_key_idx) const; StringName method_track_get_name(int p_track, int p_key_idx) const; void copy_track(int p_track, Ref<Animation> p_to_animation); - void track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices) const; + void track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices, int p_pingponged = 0) const; void set_length(real_t p_length); real_t get_length() const; - void set_loop(bool p_enabled); - bool has_loop() const; + void set_loop_mode(LoopMode p_loop_mode); + LoopMode get_loop_mode() const; void set_step(real_t p_step); real_t get_step() const; @@ -471,5 +478,6 @@ public: VARIANT_ENUM_CAST(Animation::TrackType); VARIANT_ENUM_CAST(Animation::InterpolationType); VARIANT_ENUM_CAST(Animation::UpdateMode); +VARIANT_ENUM_CAST(Animation::LoopMode); #endif diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp index d018103e64..c8a10e1c2a 100644 --- a/scene/resources/audio_stream_sample.cpp +++ b/scene/resources/audio_stream_sample.cpp @@ -299,7 +299,7 @@ int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int if (loop_format != AudioStreamSample::LOOP_DISABLED && offset < loop_begin_fp) { /* loopstart reached */ - if (loop_format == AudioStreamSample::LOOP_PING_PONG) { + if (loop_format == AudioStreamSample::LOOP_PINGPONG) { /* bounce ping pong */ offset = loop_begin_fp + (loop_begin_fp - offset); increment = -increment; @@ -320,7 +320,7 @@ int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int if (loop_format != AudioStreamSample::LOOP_DISABLED && offset >= loop_end_fp) { /* loopend reached */ - if (loop_format == AudioStreamSample::LOOP_PING_PONG) { + if (loop_format == AudioStreamSample::LOOP_PINGPONG) { /* bounce ping pong */ offset = loop_end_fp - (offset - loop_end_fp); increment = -increment; @@ -650,7 +650,7 @@ void AudioStreamSample::_bind_methods() { BIND_ENUM_CONSTANT(LOOP_DISABLED); BIND_ENUM_CONSTANT(LOOP_FORWARD); - BIND_ENUM_CONSTANT(LOOP_PING_PONG); + BIND_ENUM_CONSTANT(LOOP_PINGPONG); BIND_ENUM_CONSTANT(LOOP_BACKWARD); } diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h index 24198e3c98..0eb34be9bf 100644 --- a/scene/resources/audio_stream_sample.h +++ b/scene/resources/audio_stream_sample.h @@ -92,7 +92,7 @@ public: enum LoopMode { LOOP_DISABLED, LOOP_FORWARD, - LOOP_PING_PONG, + LOOP_PINGPONG, LOOP_BACKWARD }; |