summaryrefslogtreecommitdiff
path: root/scene/resources
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <remi@verschelde.fr>2021-10-11 22:55:01 +0200
committerGitHub <noreply@github.com>2021-10-11 22:55:01 +0200
commit9ed4f8367b29204b89f9feaf86727b24396fb180 (patch)
tree8c41815399d8eff5746ac17464ebb34d82b0a747 /scene/resources
parent5edfdc53ebb97616a6a72031b2e28ec7865d6ab8 (diff)
parent372ba7666304805abe8641487c97899f9bdd97af (diff)
Merge pull request #48332 from TokageItLab/implement-ping-pong
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/animation.cpp539
-rw-r--r--scene/resources/animation.h30
-rw-r--r--scene/resources/audio_stream_sample.cpp6
-rw-r--r--scene/resources/audio_stream_sample.h2
4 files changed, 380 insertions, 197 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index b4eec2530b..4382674470 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -309,8 +309,8 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
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/")) {
@@ -1413,7 +1413,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;
@@ -1443,8 +1443,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;
@@ -1585,7 +1591,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) {
@@ -1603,7 +1609,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());
@@ -1612,24 +1618,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;
@@ -1637,49 +1661,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;
}
}
}
@@ -1729,7 +1785,7 @@ 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 {
+Error Animation::transform_track_interpolate(int p_track, double p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale, bool p_backward) 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);
@@ -1738,7 +1794,7 @@ Error Animation::transform_track_interpolate(int p_track, double p_time, Vector3
bool ok = false;
- TransformKey tk = _interpolate(tt->transforms, p_time, tt->interpolation, tt->loop_wrap, &ok);
+ TransformKey tk = _interpolate(tt->transforms, p_time, tt->interpolation, tt->loop_wrap, &ok, p_backward);
if (!ok) {
return ERR_UNAVAILABLE;
@@ -1813,7 +1869,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);
@@ -1827,30 +1883,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);
@@ -1909,7 +1985,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];
@@ -1920,104 +1996,176 @@ 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);
- }
+ 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
-
- 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);
-
- } 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;
+ if (from_time > to_time) {
+ // 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);
+ } 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);
}
- 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;
- }
+ if ((int)Math::floor(abs(p_delta) / length) % 2 == 0) {
+ if (p_pingponged == -1) {
+ // 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, 0, from_time, p_indices);
+ _track_get_key_indices_in_range(tt->transforms, 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;
+ }
+ return;
+ }
+ if (p_pingponged == 1) {
+ // 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, 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;
+ }
+ return;
+ }
+ }
+ } break;
}
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);
-
} 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;
}
}
@@ -2055,7 +2203,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);
@@ -2069,35 +2217,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);
@@ -2483,13 +2654,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) {
@@ -2628,7 +2799,7 @@ 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("transform_track_interpolate", "track_idx", "time_sec", "is_backward"), &Animation::_transform_track_interpolate, DEFVAL(false));
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);
@@ -2666,8 +2837,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);
@@ -2676,7 +2847,7 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("copy_track", "track_idx", "to_animation"), &Animation::copy_track);
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"));
@@ -2696,6 +2867,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() {
@@ -2703,7 +2878,7 @@ void Animation::clear() {
memdelete(tracks[i]);
}
tracks.clear();
- loop = false;
+ loop_mode = LOOP_NONE;
length = 1;
emit_changed();
emit_signal(SceneStringNames::get_singleton()->tracks_changed);
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 9a410bd566..032b1a9277 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -60,7 +60,12 @@ public:
UPDATE_DISCRETE,
UPDATE_TRIGGER,
UPDATE_CAPTURE,
+ };
+ enum LoopMode {
+ LOOP_NONE,
+ LOOP_LINEAR,
+ LOOP_PINGPONG,
};
private:
@@ -184,7 +189,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_ Animation::TransformKey _interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, real_t p_c) const;
@@ -200,7 +206,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;
@@ -210,15 +216,16 @@ private:
double length = 1.0;
real_t step = 0.1;
- bool loop = false;
+ LoopMode loop_mode = LOOP_NONE;
+ int pingponged = 0;
// bind helpers
private:
- Array _transform_track_interpolate(int p_track, double p_time) const {
+ Array _transform_track_interpolate(int p_track, double p_time, bool p_backward = false) const {
Vector3 loc;
Quaternion rot;
Vector3 scale;
- transform_track_interpolate(p_track, p_time, &loc, &rot, &scale);
+ transform_track_interpolate(p_track, p_time, &loc, &rot, &scale, p_backward);
Array ret;
ret.push_back(loc);
ret.push_back(rot);
@@ -324,26 +331,26 @@ 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;
+ Error transform_track_interpolate(int p_track, double p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale, bool p_backward = false) 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;
@@ -359,5 +366,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
};