Added the interpolation methods from Animation. Also added equivalent structs to store animation keyframe data.

This commit is contained in:
Relintai 2020-02-10 18:38:41 +01:00
parent 9c287b9e54
commit 00f6c128bd
2 changed files with 489 additions and 49 deletions

View File

@ -414,8 +414,12 @@ void ProceduralAnimation::set_keyframe_node_position(const int category_index, c
ae->keyframes[keyframe_index]->position = value; ae->keyframes[keyframe_index]->position = value;
} }
void ProceduralAnimation::initialize() {
}
ProceduralAnimation::ProceduralAnimation() { ProceduralAnimation::ProceduralAnimation() {
_initialized = false;
} }
ProceduralAnimation::~ProceduralAnimation() { ProceduralAnimation::~ProceduralAnimation() {
@ -428,6 +432,347 @@ ProceduralAnimation::~ProceduralAnimation() {
_animation.unref(); _animation.unref();
} }
ProceduralAnimation::TransformAnimationKey ProceduralAnimation::_interpolate(const ProceduralAnimation::TransformAnimationKey &p_a, const ProceduralAnimation::TransformAnimationKey &p_b, float p_c) const {
TransformAnimationKey ret;
ret.loc = _interpolate(p_a.loc, p_b.loc, p_c);
ret.rot = _interpolate(p_a.rot, p_b.rot, p_c);
ret.scale = _interpolate(p_a.scale, p_b.scale, p_c);
return ret;
}
Vector3 ProceduralAnimation::_interpolate(const Vector3 &p_a, const Vector3 &p_b, float p_c) const {
return p_a.linear_interpolate(p_b, p_c);
}
Quat ProceduralAnimation::_interpolate(const Quat &p_a, const Quat &p_b, float p_c) const {
return p_a.slerp(p_b, p_c);
}
Variant ProceduralAnimation::_interpolate(const Variant &p_a, const Variant &p_b, float p_c) const {
Variant dst;
Variant::interpolate(p_a, p_b, p_c, dst);
return dst;
}
float ProceduralAnimation::_interpolate(const float &p_a, const float &p_b, float p_c) const {
return p_a * (1.0 - p_c) + p_b * p_c;
}
ProceduralAnimation::TransformAnimationKey ProceduralAnimation::_cubic_interpolate(const ProceduralAnimation::TransformAnimationKey &p_pre_a, const ProceduralAnimation::TransformAnimationKey &p_a, const ProceduralAnimation::TransformAnimationKey &p_b, const ProceduralAnimation::TransformAnimationKey &p_post_b, float p_c) const {
TransformAnimationKey tk;
tk.loc = p_a.loc.cubic_interpolate(p_b.loc, p_pre_a.loc, p_post_b.loc, p_c);
tk.scale = p_a.scale.cubic_interpolate(p_b.scale, p_pre_a.scale, p_post_b.scale, p_c);
tk.rot = p_a.rot.cubic_slerp(p_b.rot, p_pre_a.rot, p_post_b.rot, p_c);
return tk;
}
Vector3 ProceduralAnimation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, float p_c) const {
return p_a.cubic_interpolate(p_b, p_pre_a, p_post_b, p_c);
}
Quat ProceduralAnimation::_cubic_interpolate(const Quat &p_pre_a, const Quat &p_a, const Quat &p_b, const Quat &p_post_b, float p_c) const {
return p_a.cubic_slerp(p_b, p_pre_a, p_post_b, p_c);
}
Variant ProceduralAnimation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, float p_c) const {
Variant::Type type_a = p_a.get_type();
Variant::Type type_b = p_b.get_type();
Variant::Type type_pa = p_pre_a.get_type();
Variant::Type type_pb = p_post_b.get_type();
//make int and real play along
uint32_t vformat = 1 << type_a;
vformat |= 1 << type_b;
vformat |= 1 << type_pa;
vformat |= 1 << type_pb;
if (vformat == ((1 << Variant::INT) | (1 << Variant::REAL)) || vformat == (1 << Variant::REAL)) {
//mix of real and int
real_t p0 = p_pre_a;
real_t p1 = p_a;
real_t p2 = p_b;
real_t p3 = p_post_b;
float t = p_c;
float t2 = t * t;
float t3 = t2 * t;
return 0.5f * ((p1 * 2.0f) +
(-p0 + p2) * t +
(2.0f * p0 - 5.0f * p1 + 4 * p2 - p3) * t2 +
(-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3);
} else if ((vformat & (vformat - 1))) {
return p_a; //can't interpolate, mix of types
}
switch (type_a) {
case Variant::VECTOR2: {
Vector2 a = p_a;
Vector2 b = p_b;
Vector2 pa = p_pre_a;
Vector2 pb = p_post_b;
return a.cubic_interpolate(b, pa, pb, p_c);
}
case Variant::RECT2: {
Rect2 a = p_a;
Rect2 b = p_b;
Rect2 pa = p_pre_a;
Rect2 pb = p_post_b;
return Rect2(
a.position.cubic_interpolate(b.position, pa.position, pb.position, p_c),
a.size.cubic_interpolate(b.size, pa.size, pb.size, p_c));
}
case Variant::VECTOR3: {
Vector3 a = p_a;
Vector3 b = p_b;
Vector3 pa = p_pre_a;
Vector3 pb = p_post_b;
return a.cubic_interpolate(b, pa, pb, p_c);
}
case Variant::QUAT: {
Quat a = p_a;
Quat b = p_b;
Quat pa = p_pre_a;
Quat pb = p_post_b;
return a.cubic_slerp(b, pa, pb, p_c);
}
case Variant::AABB: {
AABB a = p_a;
AABB b = p_b;
AABB pa = p_pre_a;
AABB pb = p_post_b;
return AABB(
a.position.cubic_interpolate(b.position, pa.position, pb.position, p_c),
a.size.cubic_interpolate(b.size, pa.size, pb.size, p_c));
}
default: {
return _interpolate(p_a, p_b, p_c);
}
}
}
float ProceduralAnimation::_cubic_interpolate(const float &p_pre_a, const float &p_a, const float &p_b, const float &p_post_b, float p_c) const {
return _interpolate(p_a, p_b, p_c);
}
template <class T>
T ProceduralAnimation::_interpolate(const Vector<ProceduralAnimation::AnimationKey > &p_keys, float p_time, ProceduralAnimation::KeyInterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const {
/*
int len = _find(p_keys, length) + 1; // try to find last key (there may be more past the end)
if (len <= 0) {
// (-1 or -2 returned originally) (plus one above)
// meaning no keys, or only key time is larger than length
if (p_ok)
*p_ok = false;
return T();
} else if (len == 1) { // one key found (0+1), return it
if (p_ok)
*p_ok = true;
return p_keys[0].value;
}
int idx = _find(p_keys, p_time);
ERR_FAIL_COND_V(idx == -2, T());
bool result = true;
int next = 0;
float c = 0;
// prepare for all cases of interpolation
if (loop && p_loop_wrap) {
// loop
if (idx >= 0) {
if ((idx + 1) < len) {
next = idx + 1;
float delta = p_keys[next].time - p_keys[idx].time;
float from = p_time - p_keys[idx].time;
if (Math::is_zero_approx(delta))
c = 0;
else
c = from / delta;
} else {
next = 0;
float delta = (length - p_keys[idx].time) + p_keys[next].time;
float 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;
float endtime = (length - p_keys[idx].time);
if (endtime < 0) // may be keys past the end
endtime = 0;
float delta = endtime + p_keys[next].time;
float from = endtime + p_time;
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;
float delta = p_keys[next].time - p_keys[idx].time;
float from = p_time - p_keys[idx].time;
if (Math::is_zero_approx(delta))
c = 0;
else
c = from / delta;
} else {
next = idx;
}
} else {
// only allow extending first key to anim start if looping
if (loop)
idx = next = 0;
else
result = false;
}
}
if (p_ok)
*p_ok = result;
if (!result)
return T();
float tr = p_keys[idx].transition;
if (tr == 0 || idx == next) {
// don't interpolate if not needed
return p_keys[idx].value;
}
if (tr != 1.0) {
c = Math::ease(c, tr);
}
switch (p_interp) {
case INTERPOLATION_NEAREST: {
return p_keys[idx].value;
} break;
case INTERPOLATION_LINEAR: {
return _interpolate(p_keys[idx].value, p_keys[next].value, c);
} break;
case INTERPOLATION_CUBIC: {
int pre = idx - 1;
if (pre < 0)
pre = 0;
int post = next + 1;
if (post >= len)
post = next;
return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c);
} break;
default: return p_keys[idx].value;
}
*/
// do a barrel roll
return T();
}
/*
Error ProceduralAnimation::transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER);
Track *t = tracks[p_track];
ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM, ERR_INVALID_PARAMETER);
TransformTrack *tt = static_cast<TransformTrack *>(t);
bool ok = false;
TransformKey tk = _interpolate(tt->transforms, p_time, tt->interpolation, tt->loop_wrap, &ok);
if (!ok)
return ERR_UNAVAILABLE;
if (r_loc)
*r_loc = tk.loc;
if (r_rot)
*r_rot = tk.rot;
if (r_scale)
*r_scale = tk.scale;
return OK;
}
Variant ProceduralAnimation::value_track_interpolate(int p_track, float p_time) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), 0);
Track *t = tracks[p_track];
ERR_FAIL_COND_V(t->type != TYPE_VALUE, Variant());
ValueTrack *vt = static_cast<ValueTrack *>(t);
bool ok = false;
Variant res = _interpolate(vt->values, p_time, (vt->update_mode == UPDATE_CONTINUOUS || vt->update_mode == UPDATE_CAPTURE) ? vt->interpolation : INTERPOLATION_NEAREST, vt->loop_wrap, &ok);
if (ok) {
return res;
}
return Variant();
}
*/
bool ProceduralAnimation::_set(const StringName &p_name, const Variant &p_value) { bool ProceduralAnimation::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name; String name = p_name;

View File

@ -37,6 +37,129 @@ SOFTWARE.
class ProceduralAnimation : public Resource { class ProceduralAnimation : public Resource {
GDCLASS(ProceduralAnimation, Resource); GDCLASS(ProceduralAnimation, Resource);
friend class Animation;
protected:
enum AnimationKeyTrackType {
TYPE_VALUE = Animation::TYPE_VALUE,
TYPE_TRANSFORM = Animation::TYPE_TRANSFORM,
TYPE_METHOD = Animation::TYPE_METHOD,
TYPE_BEZIER = Animation::TYPE_BEZIER,
TYPE_AUDIO = Animation::TYPE_AUDIO,
TYPE_ANIMATION = Animation::TYPE_ANIMATION,
TYPE_NONE,
};
enum KeyInterpolationType {
INTERPOLATION_NEAREST = Animation::INTERPOLATION_NEAREST,
INTERPOLATION_LINEAR = Animation::INTERPOLATION_LINEAR,
INTERPOLATION_CUBIC = Animation::INTERPOLATION_CUBIC,
INTERPOLATION_CURVE,
};
/* Key data */
struct AnimationKey {
AnimationKeyTrackType type;
NodePath path;
bool enabled;
AnimationKey() {
type = TYPE_NONE;
enabled = true;
}
};
struct VariantAnimationKey : public AnimationKey {
Variant value;
VariantAnimationKey() {
type = TYPE_VALUE;
}
};
struct TransformAnimationKey : public AnimationKey {
Vector3 loc;
Quat rot;
Vector3 scale;
TransformAnimationKey() : AnimationKey() {
type = TYPE_TRANSFORM;
}
};
struct MethodAnimationKey : public AnimationKey {
StringName method;
Vector<Variant> params;
MethodAnimationKey() : AnimationKey() {
type = TYPE_METHOD;
}
};
struct AudioAnimationKey : public AnimationKey {
RES stream;
float start_offset;
float end_offset;
AudioAnimationKey() : AnimationKey() {
type = TYPE_AUDIO;
start_offset = 0;
end_offset = 0;
}
};
/* Animation data */
struct AnimationKeyFrame {
String name;
int animation_keyframe_index;
int next_keyframe;
Ref<Curve> in_curve;
Vector2 position;
Vector<AnimationKey> keys;
AnimationKeyFrame() {
animation_keyframe_index = 0;
next_keyframe = -1;
in_curve.instance();
}
~AnimationKeyFrame() {
in_curve.unref();
keys.clear();
}
};
struct AnimationEntry {
String name;
Vector2 position;
int start_frame_index;
Map<int, AnimationKeyFrame *> keyframes;
AnimationEntry() {
start_frame_index = -1;
}
~AnimationEntry() {
for (Map<int, AnimationKeyFrame *>::Element *E = keyframes.front(); E; E = E->next())
memdelete(E->get());
keyframes.clear();
}
};
struct Category {
String name;
Map<int, AnimationEntry *> animations;
~Category() {
for (Map<int, AnimationEntry *>::Element *E = animations.front(); E; E = E->next())
memdelete(E->get());
animations.clear();
}
};
public: public:
Ref<Animation> get_animation() const; Ref<Animation> get_animation() const;
void set_animation(const Ref<Animation> &value); void set_animation(const Ref<Animation> &value);
@ -88,65 +211,37 @@ public:
Vector2 get_keyframe_node_position(const int category_index, int animation_index, const int keyframe_index) const; Vector2 get_keyframe_node_position(const int category_index, int animation_index, const int keyframe_index) const;
void set_keyframe_node_position(const int category_index, const int animation_index, const int keyframe_index, const Vector2 &value); void set_keyframe_node_position(const int category_index, const int animation_index, const int keyframe_index, const Vector2 &value);
void initialize();
ProceduralAnimation(); ProceduralAnimation();
~ProceduralAnimation(); ~ProceduralAnimation();
protected:
_FORCE_INLINE_ TransformAnimationKey _interpolate(const TransformAnimationKey &p_a, const TransformAnimationKey &p_b, float p_c) const;
_FORCE_INLINE_ Vector3 _interpolate(const Vector3 &p_a, const Vector3 &p_b, float p_c) const;
_FORCE_INLINE_ Quat _interpolate(const Quat &p_a, const Quat &p_b, float p_c) const;
_FORCE_INLINE_ Variant _interpolate(const Variant &p_a, const Variant &p_b, float p_c) const;
_FORCE_INLINE_ float _interpolate(const float &p_a, const float &p_b, float p_c) const;
_FORCE_INLINE_ TransformAnimationKey _cubic_interpolate(const TransformAnimationKey &p_pre_a, const TransformAnimationKey &p_a, const TransformAnimationKey &p_b, const TransformAnimationKey &p_post_b, float p_c) const;
_FORCE_INLINE_ Vector3 _cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, float p_c) const;
_FORCE_INLINE_ Quat _cubic_interpolate(const Quat &p_pre_a, const Quat &p_a, const Quat &p_b, const Quat &p_post_b, float p_c) const;
_FORCE_INLINE_ Variant _cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, float p_c) const;
_FORCE_INLINE_ float _cubic_interpolate(const float &p_pre_a, const float &p_a, const float &p_b, const float &p_post_b, float p_c) const;
template <class T>
_FORCE_INLINE_ T _interpolate(const Vector<AnimationKey > &p_keys, float p_time, KeyInterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const;
protected: protected:
bool _set(const StringName &p_name, const Variant &p_value); bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const; bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const; void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods(); static void _bind_methods();
protected:
struct AnimationKeyFrame {
String name;
int animation_keyframe_index;
int next_keyframe;
Ref<Curve> in_curve;
Vector2 position;
AnimationKeyFrame() {
animation_keyframe_index = 0;
next_keyframe = -1;
in_curve.instance();
}
~AnimationKeyFrame() {
in_curve.unref();
}
};
struct AnimationEntry {
String name;
Vector2 position;
int start_frame_index;
Map<int, AnimationKeyFrame *> keyframes;
AnimationEntry() {
start_frame_index = -1;
}
~AnimationEntry() {
for (Map<int, AnimationKeyFrame *>::Element *E = keyframes.front(); E; E = E->next())
memdelete(E->get());
keyframes.clear();
}
};
struct Category {
String name;
Map<int, AnimationEntry *> animations;
~Category() {
for (Map<int, AnimationEntry *>::Element *E = animations.front(); E; E = E->next())
memdelete(E->get());
animations.clear();
}
};
private: private:
bool _initialized;
String _editor_add_category_name; String _editor_add_category_name;
String _add_editor_category_animation_name; String _add_editor_category_animation_name;