Merge pull request #65325 from TokageItLab/refactor-variant-for-anim

Move some static methods to `Animation` from `Variant` for refactoring `Animation` and `Tween`
This commit is contained in:
Rémi Verschelde 2022-09-16 09:20:50 +02:00
commit a981a8061f
11 changed files with 495 additions and 870 deletions

View file

@ -251,27 +251,6 @@ static GDNativeBool gdnative_variant_booleanize(const GDNativeVariantPtr p_self)
return self->booleanize();
}
static void gdnative_variant_sub(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst) {
const Variant *a = (const Variant *)p_a;
const Variant *b = (const Variant *)p_b;
memnew_placement(r_dst, Variant);
Variant::sub(*a, *b, *(Variant *)r_dst);
}
static void gdnative_variant_blend(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) {
const Variant *a = (const Variant *)p_a;
const Variant *b = (const Variant *)p_b;
memnew_placement(r_dst, Variant);
Variant::blend(*a, *b, p_c, *(Variant *)r_dst);
}
static void gdnative_variant_interpolate(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) {
const Variant *a = (const Variant *)p_a;
const Variant *b = (const Variant *)p_b;
memnew_placement(r_dst, Variant);
Variant::interpolate(*a, *b, p_c, *(Variant *)r_dst);
}
static void gdnative_variant_duplicate(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep) {
const Variant *self = (const Variant *)p_self;
memnew_placement(r_ret, Variant(self->duplicate(p_deep)));
@ -970,9 +949,6 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.variant_recursive_hash = gdnative_variant_recursive_hash;
gdni.variant_hash_compare = gdnative_variant_hash_compare;
gdni.variant_booleanize = gdnative_variant_booleanize;
gdni.variant_sub = gdnative_variant_sub;
gdni.variant_blend = gdnative_variant_blend;
gdni.variant_interpolate = gdnative_variant_interpolate;
gdni.variant_duplicate = gdnative_variant_duplicate;
gdni.variant_stringify = gdnative_variant_stringify;

View file

@ -427,9 +427,6 @@ typedef struct {
GDNativeInt (*variant_recursive_hash)(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count);
GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other);
GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self);
void (*variant_sub)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst);
void (*variant_blend)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst);
void (*variant_interpolate)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst);
void (*variant_duplicate)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep);
void (*variant_stringify)(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret);

View file

@ -552,9 +552,6 @@ public:
void zero();
Variant duplicate(bool p_deep = false) const;
Variant recursive_duplicate(bool p_deep, int recursion_count) const;
static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);
static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst);
static void sub(const Variant &a, const Variant &b, Variant &r_dst);
/* Built-In Methods */

View file

@ -1911,572 +1911,6 @@ Variant Variant::recursive_duplicate(bool p_deep, int recursion_count) const {
}
}
void Variant::sub(const Variant &a, const Variant &b, Variant &r_dst) {
if (a.type != b.type) {
return;
}
switch (a.type) {
case NIL: {
r_dst = Variant();
}
return;
case INT: {
int64_t va = a._data._int;
int64_t vb = b._data._int;
r_dst = int(va - vb);
}
return;
case FLOAT: {
double ra = a._data._float;
double rb = b._data._float;
r_dst = ra - rb;
}
return;
case VECTOR2: {
r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) - *reinterpret_cast<const Vector2 *>(b._data._mem);
}
return;
case VECTOR2I: {
int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
r_dst = Vector2i(int32_t(vax - vbx), int32_t(vay - vby));
}
return;
case RECT2: {
const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem);
const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem);
r_dst = Rect2(ra->position - rb->position, ra->size - rb->size);
}
return;
case RECT2I: {
const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
int32_t vax = ra->position.x;
int32_t vay = ra->position.y;
int32_t vbx = ra->size.x;
int32_t vby = ra->size.y;
int32_t vcx = rb->position.x;
int32_t vcy = rb->position.y;
int32_t vdx = rb->size.x;
int32_t vdy = rb->size.y;
r_dst = Rect2i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vcx - vdx), int32_t(vcy - vdy));
}
return;
case VECTOR3: {
r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) - *reinterpret_cast<const Vector3 *>(b._data._mem);
}
return;
case VECTOR3I: {
int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
r_dst = Vector3i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vaz - vbz));
}
return;
case AABB: {
const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem);
const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem);
r_dst = ::AABB(ra->position - rb->position, ra->size - rb->size);
}
return;
case QUATERNION: {
Quaternion empty_rot;
const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem);
const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem);
r_dst = (*qb).inverse() * *qa;
}
return;
case COLOR: {
const Color *ca = reinterpret_cast<const Color *>(a._data._mem);
const Color *cb = reinterpret_cast<const Color *>(b._data._mem);
float new_r = ca->r - cb->r;
float new_g = ca->g - cb->g;
float new_b = ca->b - cb->b;
float new_a = ca->a - cb->a;
new_r = new_r > 1.0 ? 1.0 : new_r;
new_g = new_g > 1.0 ? 1.0 : new_g;
new_b = new_b > 1.0 ? 1.0 : new_b;
new_a = new_a > 1.0 ? 1.0 : new_a;
r_dst = Color(new_r, new_g, new_b, new_a);
}
return;
default: {
r_dst = a;
}
return;
}
}
void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) {
if (a.type != b.type) {
if (a.is_num() && b.is_num()) {
real_t va = a;
real_t vb = b;
r_dst = va + vb * c;
} else {
r_dst = a;
}
return;
}
switch (a.type) {
case NIL: {
r_dst = Variant();
}
return;
case INT: {
int64_t va = a._data._int;
int64_t vb = b._data._int;
r_dst = int(va + vb * c + 0.5);
}
return;
case FLOAT: {
double ra = a._data._float;
double rb = b._data._float;
r_dst = ra + rb * c;
}
return;
case VECTOR2: {
r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) + *reinterpret_cast<const Vector2 *>(b._data._mem) * c;
}
return;
case VECTOR2I: {
int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
}
return;
case RECT2: {
const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem);
const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem);
r_dst = Rect2(ra->position + rb->position * c, ra->size + rb->size * c);
}
return;
case RECT2I: {
const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
int32_t vax = ra->position.x;
int32_t vay = ra->position.y;
int32_t vbx = ra->size.x;
int32_t vby = ra->size.y;
int32_t vcx = rb->position.x;
int32_t vcy = rb->position.y;
int32_t vdx = rb->size.x;
int32_t vdy = rb->size.y;
r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
}
return;
case VECTOR3: {
r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) + *reinterpret_cast<const Vector3 *>(b._data._mem) * c;
}
return;
case VECTOR3I: {
int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
}
return;
case AABB: {
const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem);
const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem);
r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c);
}
return;
case QUATERNION: {
Quaternion empty_rot;
const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem);
const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem);
r_dst = *qa * empty_rot.slerp(*qb, c);
}
return;
case COLOR: {
const Color *ca = reinterpret_cast<const Color *>(a._data._mem);
const Color *cb = reinterpret_cast<const Color *>(b._data._mem);
float new_r = ca->r + cb->r * c;
float new_g = ca->g + cb->g * c;
float new_b = ca->b + cb->b * c;
float new_a = ca->a + cb->a * c;
new_r = new_r > 1.0 ? 1.0 : new_r;
new_g = new_g > 1.0 ? 1.0 : new_g;
new_b = new_b > 1.0 ? 1.0 : new_b;
new_a = new_a > 1.0 ? 1.0 : new_a;
r_dst = Color(new_r, new_g, new_b, new_a);
}
return;
default: {
r_dst = c < 0.5 ? a : b;
}
return;
}
}
void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst) {
if (a.type != b.type) {
if (a.is_num() && b.is_num()) {
//not as efficient but..
real_t va = a;
real_t vb = b;
r_dst = va + (vb - va) * c;
} else {
r_dst = a;
}
return;
}
switch (a.type) {
case NIL: {
r_dst = Variant();
}
return;
case BOOL: {
r_dst = a;
}
return;
case INT: {
int64_t va = a._data._int;
int64_t vb = b._data._int;
r_dst = int(va + (vb - va) * c);
}
return;
case FLOAT: {
real_t va = a._data._float;
real_t vb = b._data._float;
r_dst = va + (vb - va) * c;
}
return;
case STRING: {
//this is pretty funny and bizarre, but artists like to use it for typewriter effects
String sa = *reinterpret_cast<const String *>(a._data._mem);
String sb = *reinterpret_cast<const String *>(b._data._mem);
String dst;
int sa_len = sa.length();
int sb_len = sb.length();
int csize = sa_len + (sb_len - sa_len) * c;
if (csize == 0) {
r_dst = "";
return;
}
dst.resize(csize + 1);
dst[csize] = 0;
int split = csize / 2;
for (int i = 0; i < csize; i++) {
char32_t chr = ' ';
if (i < split) {
if (i < sa.length()) {
chr = sa[i];
} else if (i < sb.length()) {
chr = sb[i];
}
} else {
if (i < sb.length()) {
chr = sb[i];
} else if (i < sa.length()) {
chr = sa[i];
}
}
dst[i] = chr;
}
r_dst = dst;
}
return;
case VECTOR2: {
r_dst = reinterpret_cast<const Vector2 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector2 *>(b._data._mem), c);
}
return;
case VECTOR2I: {
int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
}
return;
case RECT2: {
r_dst = Rect2(reinterpret_cast<const Rect2 *>(a._data._mem)->position.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->position, c), reinterpret_cast<const Rect2 *>(a._data._mem)->size.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->size, c));
}
return;
case RECT2I: {
const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
int32_t vax = ra->position.x;
int32_t vay = ra->position.y;
int32_t vbx = ra->size.x;
int32_t vby = ra->size.y;
int32_t vcx = rb->position.x;
int32_t vcy = rb->position.y;
int32_t vdx = rb->size.x;
int32_t vdy = rb->size.y;
r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
}
return;
case VECTOR3: {
r_dst = reinterpret_cast<const Vector3 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector3 *>(b._data._mem), c);
}
return;
case VECTOR3I: {
int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
}
return;
case TRANSFORM2D: {
r_dst = a._data._transform2d->interpolate_with(*b._data._transform2d, c);
}
return;
case PLANE: {
r_dst = a;
}
return;
case QUATERNION: {
r_dst = reinterpret_cast<const Quaternion *>(a._data._mem)->slerp(*reinterpret_cast<const Quaternion *>(b._data._mem), c);
}
return;
case AABB: {
r_dst = ::AABB(a._data._aabb->position.lerp(b._data._aabb->position, c), a._data._aabb->size.lerp(b._data._aabb->size, c));
}
return;
case BASIS: {
r_dst = a._data._basis->lerp(*b._data._basis, c);
}
return;
case TRANSFORM3D: {
r_dst = a._data._transform3d->interpolate_with(*b._data._transform3d, c);
}
return;
case COLOR: {
r_dst = reinterpret_cast<const Color *>(a._data._mem)->lerp(*reinterpret_cast<const Color *>(b._data._mem), c);
}
return;
case STRING_NAME: {
r_dst = a;
}
return;
case NODE_PATH: {
r_dst = a;
}
return;
case RID: {
r_dst = a;
}
return;
case OBJECT: {
r_dst = a;
}
return;
case DICTIONARY: {
}
return;
case ARRAY: {
r_dst = a;
}
return;
case PACKED_BYTE_ARRAY: {
r_dst = a;
}
return;
case PACKED_INT32_ARRAY: {
const Vector<int32_t> *arr_a = &PackedArrayRef<int32_t>::get_array(a._data.packed_array);
const Vector<int32_t> *arr_b = &PackedArrayRef<int32_t>::get_array(b._data.packed_array);
int32_t sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
r_dst = a;
} else {
Vector<int32_t> v;
v.resize(sz);
{
int32_t *vw = v.ptrw();
const int32_t *ar = arr_a->ptr();
const int32_t *br = arr_b->ptr();
Variant va;
for (int32_t i = 0; i < sz; i++) {
Variant::interpolate(ar[i], br[i], c, va);
vw[i] = va;
}
}
r_dst = v;
}
}
return;
case PACKED_INT64_ARRAY: {
const Vector<int64_t> *arr_a = &PackedArrayRef<int64_t>::get_array(a._data.packed_array);
const Vector<int64_t> *arr_b = &PackedArrayRef<int64_t>::get_array(b._data.packed_array);
int64_t sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
r_dst = a;
} else {
Vector<int64_t> v;
v.resize(sz);
{
int64_t *vw = v.ptrw();
const int64_t *ar = arr_a->ptr();
const int64_t *br = arr_b->ptr();
Variant va;
for (int64_t i = 0; i < sz; i++) {
Variant::interpolate(ar[i], br[i], c, va);
vw[i] = va;
}
}
r_dst = v;
}
}
return;
case PACKED_FLOAT32_ARRAY: {
const Vector<float> *arr_a = &PackedArrayRef<float>::get_array(a._data.packed_array);
const Vector<float> *arr_b = &PackedArrayRef<float>::get_array(b._data.packed_array);
int sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
r_dst = a;
} else {
Vector<float> v;
v.resize(sz);
{
float *vw = v.ptrw();
const float *ar = arr_a->ptr();
const float *br = arr_b->ptr();
Variant va;
for (int i = 0; i < sz; i++) {
Variant::interpolate(ar[i], br[i], c, va);
vw[i] = va;
}
}
r_dst = v;
}
}
return;
case PACKED_FLOAT64_ARRAY: {
const Vector<double> *arr_a = &PackedArrayRef<double>::get_array(a._data.packed_array);
const Vector<double> *arr_b = &PackedArrayRef<double>::get_array(b._data.packed_array);
int sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
r_dst = a;
} else {
Vector<double> v;
v.resize(sz);
{
double *vw = v.ptrw();
const double *ar = arr_a->ptr();
const double *br = arr_b->ptr();
Variant va;
for (int i = 0; i < sz; i++) {
Variant::interpolate(ar[i], br[i], c, va);
vw[i] = va;
}
}
r_dst = v;
}
}
return;
case PACKED_STRING_ARRAY: {
r_dst = a;
}
return;
case PACKED_VECTOR2_ARRAY: {
const Vector<Vector2> *arr_a = &PackedArrayRef<Vector2>::get_array(a._data.packed_array);
const Vector<Vector2> *arr_b = &PackedArrayRef<Vector2>::get_array(b._data.packed_array);
int sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
r_dst = a;
} else {
Vector<Vector2> v;
v.resize(sz);
{
Vector2 *vw = v.ptrw();
const Vector2 *ar = arr_a->ptr();
const Vector2 *br = arr_b->ptr();
for (int i = 0; i < sz; i++) {
vw[i] = ar[i].lerp(br[i], c);
}
}
r_dst = v;
}
}
return;
case PACKED_VECTOR3_ARRAY: {
const Vector<Vector3> *arr_a = &PackedArrayRef<Vector3>::get_array(a._data.packed_array);
const Vector<Vector3> *arr_b = &PackedArrayRef<Vector3>::get_array(b._data.packed_array);
int sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
r_dst = a;
} else {
Vector<Vector3> v;
v.resize(sz);
{
Vector3 *vw = v.ptrw();
const Vector3 *ar = arr_a->ptr();
const Vector3 *br = arr_b->ptr();
for (int i = 0; i < sz; i++) {
vw[i] = ar[i].lerp(br[i], c);
}
}
r_dst = v;
}
}
return;
case PACKED_COLOR_ARRAY: {
const Vector<Color> *arr_a = &PackedArrayRef<Color>::get_array(a._data.packed_array);
const Vector<Color> *arr_b = &PackedArrayRef<Color>::get_array(b._data.packed_array);
int sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
r_dst = a;
} else {
Vector<Color> v;
v.resize(sz);
{
Color *vw = v.ptrw();
const Color *ar = arr_a->ptr();
const Color *br = arr_b->ptr();
for (int i = 0; i < sz; i++) {
vw[i] = ar[i].lerp(br[i], c);
}
}
r_dst = v;
}
}
return;
default: {
r_dst = a;
}
}
}
void Variant::_register_variant_setters_getters() {
register_named_setters_getters();
register_indexed_setters_getters();

View file

@ -6050,10 +6050,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
real_t to_diff = fmod(b - a, Math_TAU);
to_v = a + fmod(2.0 * to_diff, Math_TAU) - to_diff;
}
Variant delta_v;
Variant::sub(to_v, from_v, delta_v);
Variant delta_v = Animation::subtract_variant(to_v, from_v);
double duration = to_t - from_t;
double fixed_duration = duration - 0.01; // Prevent to overwrap keys...
double fixed_duration = duration - UNIT_EPSILON; // Prevent to overwrap keys...
for (double delta_t = dur_step; delta_t < fixed_duration; delta_t += dur_step) {
Pair<real_t, Variant> keydata;
keydata.first = from_t + delta_t;

View file

@ -650,15 +650,14 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
double c = Math::ease(p_time / first_key_time, transition);
Variant first_value = a->track_get_key_value(i, first_key);
first_value = _post_process_key_value(a, i, first_value, nc->node);
Variant interp_value;
Variant::interpolate(pa->capture, first_value, c, interp_value);
Variant interp_value = Animation::interpolate_variant(pa->capture, first_value, c);
if (pa->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_prop_size >= NODE_CACHE_UPDATE_MAX);
cache_update_prop[cache_update_prop_size++] = pa;
pa->value_accum = interp_value;
pa->accum_pass = accum_pass;
} else {
Variant::interpolate(pa->value_accum, interp_value, p_interp, pa->value_accum);
pa->value_accum = Animation::interpolate_variant(pa->value_accum, interp_value, p_interp);
}
continue; //handled
@ -679,7 +678,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
pa->value_accum = value;
pa->accum_pass = accum_pass;
} else {
Variant::interpolate(pa->value_accum, value, p_interp, pa->value_accum);
pa->value_accum = Animation::interpolate_variant(pa->value_accum, value, p_interp);
}
} else if (p_is_current && p_delta != 0) {

View file

@ -1383,8 +1383,13 @@ void AnimationTree::_process_graph(double p_delta) {
}
t->value = Math::fposmod(rot_a + (rot_b - rot_init) * (float)blend, (float)Math_TAU);
} else {
Variant::sub(value, t->init_value, value);
Variant::blend(t->value, value, blend, t->value);
if (t->init_value.get_type() == Variant::BOOL) {
value = Animation::subtract_variant(value.operator real_t(), t->init_value.operator real_t());
t->value = Animation::blend_variant(t->value.operator real_t(), value.operator real_t(), blend);
} else {
value = Animation::subtract_variant(value, t->init_value);
t->value = Animation::blend_variant(t->value, value, blend);
}
}
} else {
if (blend < CMP_EPSILON) {
@ -1703,7 +1708,11 @@ void AnimationTree::_process_graph(double p_delta) {
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
t->object->set_indexed(t->subpath, t->value);
if (t->init_value.get_type() == Variant::BOOL) {
t->object->set_indexed(t->subpath, t->value.operator real_t() >= 0.5);
} else {
t->object->set_indexed(t->subpath, t->value);
}
} break;
case Animation::TYPE_BEZIER: {

View file

@ -32,6 +32,7 @@
#include "scene/animation/easing_equations.h"
#include "scene/main/node.h"
#include "scene/resources/animation.h"
Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = {
{ &linear::in, &linear::in, &linear::in, &linear::in }, // Linear is the same for each easing.
@ -375,264 +376,14 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, f
ERR_FAIL_INDEX_V(p_trans, TransitionType::TRANS_MAX, Variant());
ERR_FAIL_INDEX_V(p_ease, EaseType::EASE_MAX, Variant());
// Helper macro to run equation on sub-elements of the value (e.g. x and y of Vector2).
#define APPLY_EQUATION(element) \
r.element = run_equation(p_trans, p_ease, p_time, i.element, d.element, p_duration);
// Special case for bool.
if (p_initial_val.get_type() == Variant::BOOL) {
return run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration) >= 0.5;
}
switch (p_initial_val.get_type()) {
case Variant::BOOL: {
return (run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration)) >= 0.5;
}
case Variant::INT: {
return (int)run_equation(p_trans, p_ease, p_time, (int)p_initial_val, (int)p_delta_val, p_duration);
}
case Variant::FLOAT: {
return run_equation(p_trans, p_ease, p_time, (real_t)p_initial_val, (real_t)p_delta_val, p_duration);
}
case Variant::VECTOR2: {
Vector2 i = p_initial_val;
Vector2 d = p_delta_val;
Vector2 r;
APPLY_EQUATION(x);
APPLY_EQUATION(y);
return r;
}
case Variant::VECTOR2I: {
Vector2i i = p_initial_val;
Vector2i d = p_delta_val;
Vector2i r;
APPLY_EQUATION(x);
APPLY_EQUATION(y);
return r;
}
case Variant::RECT2: {
Rect2 i = p_initial_val;
Rect2 d = p_delta_val;
Rect2 r;
APPLY_EQUATION(position.x);
APPLY_EQUATION(position.y);
APPLY_EQUATION(size.x);
APPLY_EQUATION(size.y);
return r;
}
case Variant::RECT2I: {
Rect2i i = p_initial_val;
Rect2i d = p_delta_val;
Rect2i r;
APPLY_EQUATION(position.x);
APPLY_EQUATION(position.y);
APPLY_EQUATION(size.x);
APPLY_EQUATION(size.y);
return r;
}
case Variant::VECTOR3: {
Vector3 i = p_initial_val;
Vector3 d = p_delta_val;
Vector3 r;
APPLY_EQUATION(x);
APPLY_EQUATION(y);
APPLY_EQUATION(z);
return r;
}
case Variant::VECTOR3I: {
Vector3i i = p_initial_val;
Vector3i d = p_delta_val;
Vector3i r;
APPLY_EQUATION(x);
APPLY_EQUATION(y);
APPLY_EQUATION(z);
return r;
}
case Variant::TRANSFORM2D: {
Transform2D i = p_initial_val;
Transform2D d = p_delta_val;
Transform2D r;
APPLY_EQUATION(columns[0][0]);
APPLY_EQUATION(columns[0][1]);
APPLY_EQUATION(columns[1][0]);
APPLY_EQUATION(columns[1][1]);
APPLY_EQUATION(columns[2][0]);
APPLY_EQUATION(columns[2][1]);
return r;
}
case Variant::VECTOR4: {
Vector4 i = p_initial_val;
Vector4 d = p_delta_val;
Vector4 r;
APPLY_EQUATION(x);
APPLY_EQUATION(y);
APPLY_EQUATION(z);
APPLY_EQUATION(w);
return r;
}
case Variant::QUATERNION: {
Quaternion i = p_initial_val;
Quaternion d = p_delta_val;
Quaternion r = i * d;
r = i.slerp(r, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration));
return r;
}
case Variant::AABB: {
AABB i = p_initial_val;
AABB d = p_delta_val;
AABB r;
APPLY_EQUATION(position.x);
APPLY_EQUATION(position.y);
APPLY_EQUATION(position.z);
APPLY_EQUATION(size.x);
APPLY_EQUATION(size.y);
APPLY_EQUATION(size.z);
return r;
}
case Variant::BASIS: {
Basis i = p_initial_val;
Basis d = p_delta_val;
Basis r;
APPLY_EQUATION(rows[0][0]);
APPLY_EQUATION(rows[0][1]);
APPLY_EQUATION(rows[0][2]);
APPLY_EQUATION(rows[1][0]);
APPLY_EQUATION(rows[1][1]);
APPLY_EQUATION(rows[1][2]);
APPLY_EQUATION(rows[2][0]);
APPLY_EQUATION(rows[2][1]);
APPLY_EQUATION(rows[2][2]);
return r;
}
case Variant::TRANSFORM3D: {
Transform3D i = p_initial_val;
Transform3D d = p_delta_val;
Transform3D r;
APPLY_EQUATION(basis.rows[0][0]);
APPLY_EQUATION(basis.rows[0][1]);
APPLY_EQUATION(basis.rows[0][2]);
APPLY_EQUATION(basis.rows[1][0]);
APPLY_EQUATION(basis.rows[1][1]);
APPLY_EQUATION(basis.rows[1][2]);
APPLY_EQUATION(basis.rows[2][0]);
APPLY_EQUATION(basis.rows[2][1]);
APPLY_EQUATION(basis.rows[2][2]);
APPLY_EQUATION(origin.x);
APPLY_EQUATION(origin.y);
APPLY_EQUATION(origin.z);
return r;
}
case Variant::COLOR: {
Color i = p_initial_val;
Color d = p_delta_val;
Color r;
APPLY_EQUATION(r);
APPLY_EQUATION(g);
APPLY_EQUATION(b);
APPLY_EQUATION(a);
return r;
}
default: {
return p_initial_val;
}
};
#undef APPLY_EQUATION
}
Variant Tween::calculate_delta_value(Variant p_intial_val, Variant p_final_val) {
ERR_FAIL_COND_V_MSG(p_intial_val.get_type() != p_final_val.get_type(), p_intial_val, "Type mismatch between initial and final value: " + Variant::get_type_name(p_intial_val.get_type()) + " and " + Variant::get_type_name(p_final_val.get_type()));
switch (p_intial_val.get_type()) {
case Variant::BOOL: {
return (int)p_final_val - (int)p_intial_val;
}
case Variant::RECT2: {
Rect2 i = p_intial_val;
Rect2 f = p_final_val;
return Rect2(f.position - i.position, f.size - i.size);
}
case Variant::RECT2I: {
Rect2i i = p_intial_val;
Rect2i f = p_final_val;
return Rect2i(f.position - i.position, f.size - i.size);
}
case Variant::TRANSFORM2D: {
Transform2D i = p_intial_val;
Transform2D f = p_final_val;
return Transform2D(f.columns[0][0] - i.columns[0][0],
f.columns[0][1] - i.columns[0][1],
f.columns[1][0] - i.columns[1][0],
f.columns[1][1] - i.columns[1][1],
f.columns[2][0] - i.columns[2][0],
f.columns[2][1] - i.columns[2][1]);
}
case Variant::AABB: {
AABB i = p_intial_val;
AABB f = p_final_val;
return AABB(f.position - i.position, f.size - i.size);
}
case Variant::BASIS: {
Basis i = p_intial_val;
Basis f = p_final_val;
return Basis(f.rows[0][0] - i.rows[0][0],
f.rows[0][1] - i.rows[0][1],
f.rows[0][2] - i.rows[0][2],
f.rows[1][0] - i.rows[1][0],
f.rows[1][1] - i.rows[1][1],
f.rows[1][2] - i.rows[1][2],
f.rows[2][0] - i.rows[2][0],
f.rows[2][1] - i.rows[2][1],
f.rows[2][2] - i.rows[2][2]);
}
case Variant::TRANSFORM3D: {
Transform3D i = p_intial_val;
Transform3D f = p_final_val;
return Transform3D(f.basis.rows[0][0] - i.basis.rows[0][0],
f.basis.rows[0][1] - i.basis.rows[0][1],
f.basis.rows[0][2] - i.basis.rows[0][2],
f.basis.rows[1][0] - i.basis.rows[1][0],
f.basis.rows[1][1] - i.basis.rows[1][1],
f.basis.rows[1][2] - i.basis.rows[1][2],
f.basis.rows[2][0] - i.basis.rows[2][0],
f.basis.rows[2][1] - i.basis.rows[2][1],
f.basis.rows[2][2] - i.basis.rows[2][2],
f.origin.x - i.origin.x,
f.origin.y - i.origin.y,
f.origin.z - i.origin.z);
}
default: {
return Variant::evaluate(Variant::OP_SUBTRACT, p_final_val, p_intial_val);
}
};
Variant ret = Animation::add_variant(p_initial_val, p_delta_val);
ret = Animation::interpolate_variant(p_initial_val, ret, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration));
return ret;
}
void Tween::_bind_methods() {
@ -748,10 +499,10 @@ void PropertyTweener::start() {
}
if (relative) {
final_val = Variant::evaluate(Variant::Operator::OP_ADD, initial_val, base_final_val);
final_val = Animation::add_variant(initial_val, base_final_val);
}
delta_val = tween->calculate_delta_value(initial_val, final_val);
delta_val = Animation::subtract_variant(final_val, initial_val);
}
bool PropertyTweener::step(float &r_delta) {
@ -973,7 +724,7 @@ void MethodTweener::_bind_methods() {
MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration) {
callback = p_callback;
initial_val = p_from;
delta_val = tween->calculate_delta_value(p_from, p_to);
delta_val = Animation::subtract_variant(p_to, p_from);
final_val = p_to;
duration = p_duration;
}

View file

@ -164,7 +164,6 @@ public:
static real_t run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d);
static Variant interpolate_variant(Variant p_initial_val, Variant p_delta_val, float p_time, float p_duration, Tween::TransitionType p_trans, Tween::EaseType p_ease);
Variant calculate_delta_value(Variant p_intial_val, Variant p_final_val);
bool step(float p_delta);
bool can_process(bool p_tree_paused) const;

View file

@ -2317,9 +2317,7 @@ Quaternion Animation::_interpolate(const Quaternion &p_a, const Quaternion &p_b,
}
Variant Animation::_interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const {
Variant dst;
Variant::interpolate(p_a, p_b, p_c, dst);
return dst;
return interpolate_variant(p_a, p_b, p_c);
}
real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const {
@ -5563,6 +5561,466 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in
return false;
}
// Helper math fuctions for Variant.
Variant Animation::add_variant(const Variant &a, const Variant &b) {
if (a.get_type() != b.get_type()) {
return a;
}
switch (a.get_type()) {
case Variant::NIL: {
return Variant();
}
case Variant::BOOL: {
return (a.operator real_t()) + (b.operator real_t()); // It is cast for interpolation.
}
case Variant::RECT2: {
const Rect2 ra = a.operator Rect2();
const Rect2 rb = b.operator Rect2();
return Rect2(ra.position + rb.position, ra.size + rb.size);
}
case Variant::RECT2I: {
const Rect2i ra = a.operator Rect2i();
const Rect2i rb = b.operator Rect2i();
return Rect2i(ra.position + rb.position, ra.size + rb.size);
}
case Variant::PLANE: {
const Plane pa = a.operator Plane();
const Plane pb = b.operator Plane();
return Plane(pa.normal + pb.normal, pa.d + pb.d);
}
case Variant::AABB: {
const ::AABB aa = a.operator ::AABB();
const ::AABB ab = b.operator ::AABB();
return ::AABB(aa.position + ab.position, aa.size + ab.size);
}
case Variant::QUATERNION: {
return (a.operator Quaternion()) * (b.operator Quaternion());
}
case Variant::TRANSFORM2D: {
return (a.operator Transform2D()) * (b.operator Transform2D());
}
case Variant::TRANSFORM3D: {
return (a.operator Transform3D()) * (b.operator Transform3D());
}
default: {
return Variant::evaluate(Variant::OP_ADD, a, b);
}
}
}
Variant Animation::subtract_variant(const Variant &a, const Variant &b) {
if (a.get_type() != b.get_type()) {
return a;
}
switch (a.get_type()) {
case Variant::NIL: {
return Variant();
}
case Variant::BOOL: {
return (a.operator real_t()) - (b.operator real_t()); // It is cast for interpolation.
}
case Variant::RECT2: {
const Rect2 ra = a.operator Rect2();
const Rect2 rb = b.operator Rect2();
return Rect2(ra.position - rb.position, ra.size - rb.size);
}
case Variant::RECT2I: {
const Rect2i ra = a.operator Rect2i();
const Rect2i rb = b.operator Rect2i();
return Rect2i(ra.position - rb.position, ra.size - rb.size);
}
case Variant::PLANE: {
const Plane pa = a.operator Plane();
const Plane pb = b.operator Plane();
return Plane(pa.normal - pb.normal, pa.d - pb.d);
}
case Variant::AABB: {
const ::AABB aa = a.operator ::AABB();
const ::AABB ab = b.operator ::AABB();
return ::AABB(aa.position - ab.position, aa.size - ab.size);
}
case Variant::QUATERNION: {
return (b.operator Quaternion()).inverse() * (a.operator Quaternion());
}
case Variant::TRANSFORM2D: {
return (b.operator Transform2D()).inverse() * (a.operator Transform2D());
}
case Variant::TRANSFORM3D: {
return (b.operator Transform3D()).inverse() * (a.operator Transform3D());
}
default: {
return Variant::evaluate(Variant::OP_SUBTRACT, a, b);
}
}
}
Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) {
if (a.get_type() != b.get_type()) {
if (a.is_num() && b.is_num()) {
real_t va = a;
real_t vb = b;
return va + vb * c;
}
return a;
}
switch (a.get_type()) {
case Variant::NIL: {
return Variant();
}
case Variant::INT: {
return int((a.operator int64_t()) + (b.operator int64_t()) * c + 0.5);
}
case Variant::FLOAT: {
return (a.operator double()) + (b.operator double()) * c;
}
case Variant::VECTOR2: {
return (a.operator Vector2()) + (b.operator Vector2()) * c;
}
case Variant::VECTOR2I: {
const Vector2i va = a.operator Vector2i();
const Vector2i vb = b.operator Vector2i();
return Vector2i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5));
}
case Variant::RECT2: {
const Rect2 ra = a.operator Rect2();
const Rect2 rb = b.operator Rect2();
return Rect2(ra.position + rb.position * c, ra.size + rb.size * c);
}
case Variant::RECT2I: {
const Rect2i ra = a.operator Rect2i();
const Rect2i rb = b.operator Rect2i();
return Rect2i(int32_t(ra.position.x + rb.position.x * c + 0.5), int32_t(ra.position.y + rb.position.y * c + 0.5), int32_t(ra.size.x + rb.size.x * c + 0.5), int32_t(ra.size.y + rb.size.y * c + 0.5));
}
case Variant::VECTOR3: {
return (a.operator Vector3()) + (b.operator Vector3()) * c;
}
case Variant::VECTOR3I: {
const Vector3i va = a.operator Vector3i();
const Vector3i vb = b.operator Vector3i();
return Vector3i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5));
}
case Variant::VECTOR4: {
return (a.operator Vector4()) + (b.operator Vector4()) * c;
}
case Variant::VECTOR4I: {
const Vector4i va = a.operator Vector4i();
const Vector4i vb = b.operator Vector4i();
return Vector4i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5), int32_t(va.w + vb.w * c + 0.5));
}
case Variant::PLANE: {
const Plane pa = a.operator Plane();
const Plane pb = b.operator Plane();
return Plane(pa.normal + pb.normal * c, pa.d + pb.d * c);
}
case Variant::COLOR: {
return (a.operator Color()) + (b.operator Color()) * c;
}
case Variant::AABB: {
const ::AABB aa = a.operator ::AABB();
const ::AABB ab = b.operator ::AABB();
return ::AABB(aa.position + ab.position * c, aa.size + ab.size * c);
}
case Variant::BASIS: {
return (a.operator Basis()) + (b.operator Basis()) * c;
}
case Variant::QUATERNION: {
return (a.operator Quaternion()) * Quaternion().slerp((b.operator Quaternion()), c);
}
case Variant::TRANSFORM2D: {
return (a.operator Transform2D()) * Transform2D().interpolate_with((b.operator Transform2D()), c);
}
case Variant::TRANSFORM3D: {
return (a.operator Transform3D()) * Transform3D().interpolate_with((b.operator Transform3D()), c);
}
default: {
return c < 0.5 ? a : b;
}
}
}
Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float c) {
if (a.get_type() != b.get_type()) {
if (a.is_num() && b.is_num()) {
real_t va = a;
real_t vb = b;
return va + (vb - va) * c;
}
return a;
}
switch (a.get_type()) {
case Variant::NIL: {
return Variant();
}
case Variant::INT: {
const int64_t va = a.operator int64_t();
return int(va + ((b.operator int64_t()) - va) * c);
}
case Variant::FLOAT: {
const real_t va = a.operator real_t();
return va + ((b.operator real_t()) - va) * c;
}
case Variant::VECTOR2: {
return (a.operator Vector2()).lerp(b.operator Vector2(), c);
}
case Variant::VECTOR2I: {
const Vector2i va = a.operator Vector2i();
const Vector2i vb = b.operator Vector2i();
return Vector2i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c));
}
case Variant::RECT2: {
const Rect2 ra = a.operator Rect2();
const Rect2 rb = b.operator Rect2();
return Rect2(ra.position.lerp(rb.position, c), ra.size.lerp(rb.size, c));
}
case Variant::RECT2I: {
const Rect2i ra = a.operator Rect2i();
const Rect2i rb = b.operator Rect2i();
return Rect2i(int32_t(ra.position.x + (rb.position.x - ra.position.x) * c), int32_t(ra.position.y + (rb.position.y - ra.position.y) * c), int32_t(ra.size.x + (rb.size.x - ra.size.x) * c), int32_t(ra.size.y + (rb.size.y - ra.size.y) * c));
}
case Variant::VECTOR3: {
return (a.operator Vector3()).lerp(b.operator Vector3(), c);
}
case Variant::VECTOR3I: {
const Vector3i va = a.operator Vector3i();
const Vector3i vb = b.operator Vector3i();
return Vector3i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c));
}
case Variant::VECTOR4: {
return (a.operator Vector4()).lerp(b.operator Vector4(), c);
}
case Variant::VECTOR4I: {
const Vector4i va = a.operator Vector4i();
const Vector4i vb = b.operator Vector4i();
return Vector4i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c), int32_t(va.w + (vb.w - va.w) * c));
}
case Variant::PLANE: {
const Plane pa = a.operator Plane();
const Plane pb = b.operator Plane();
return Plane(pa.normal.lerp(pb.normal, c), pa.d + (pb.d - pa.d) * c);
}
case Variant::COLOR: {
return (a.operator Color()).lerp(b.operator Color(), c);
}
case Variant::AABB: {
const ::AABB aa = a.operator ::AABB();
const ::AABB ab = b.operator ::AABB();
return ::AABB(aa.position.lerp(ab.position, c), aa.size.lerp(ab.size, c));
}
case Variant::BASIS: {
return (a.operator Basis()).lerp(b.operator Basis(), c);
}
case Variant::QUATERNION: {
return (a.operator Quaternion()).slerp(b.operator Quaternion(), c);
}
case Variant::TRANSFORM2D: {
return (a.operator Transform2D()).interpolate_with(b.operator Transform2D(), c);
}
case Variant::TRANSFORM3D: {
return (a.operator Transform3D()).interpolate_with(b.operator Transform3D(), c);
}
case Variant::STRING: {
// This is pretty funny and bizarre, but artists like to use it for typewriter effects.
const String sa = a.operator String();
const String sb = b.operator String();
String dst;
int sa_len = sa.length();
int sb_len = sb.length();
int csize = sa_len + (sb_len - sa_len) * c;
if (csize == 0) {
return "";
}
dst.resize(csize + 1);
dst[csize] = 0;
int split = csize / 2;
for (int i = 0; i < csize; i++) {
char32_t chr = ' ';
if (i < split) {
if (i < sa.length()) {
chr = sa[i];
} else if (i < sb.length()) {
chr = sb[i];
}
} else {
if (i < sb.length()) {
chr = sb[i];
} else if (i < sa.length()) {
chr = sa[i];
}
}
dst[i] = chr;
}
return dst;
}
case Variant::PACKED_INT32_ARRAY: {
const Vector<int32_t> *arr_a = Object::cast_to<Vector<int32_t>>(a);
const Vector<int32_t> *arr_b = Object::cast_to<Vector<int32_t>>(b);
int32_t sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
return a;
} else {
Vector<int32_t> v;
v.resize(sz);
{
int32_t *vw = v.ptrw();
const int32_t *ar = arr_a->ptr();
const int32_t *br = arr_b->ptr();
Variant va;
for (int32_t i = 0; i < sz; i++) {
va = interpolate_variant(ar[i], br[i], c);
vw[i] = va;
}
}
return v;
}
}
case Variant::PACKED_INT64_ARRAY: {
const Vector<int64_t> *arr_a = Object::cast_to<Vector<int64_t>>(a);
const Vector<int64_t> *arr_b = Object::cast_to<Vector<int64_t>>(b);
int64_t sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
return a;
} else {
Vector<int64_t> v;
v.resize(sz);
{
int64_t *vw = v.ptrw();
const int64_t *ar = arr_a->ptr();
const int64_t *br = arr_b->ptr();
Variant va;
for (int64_t i = 0; i < sz; i++) {
va = interpolate_variant(ar[i], br[i], c);
vw[i] = va;
}
}
return v;
}
}
case Variant::PACKED_FLOAT32_ARRAY: {
const Vector<float> *arr_a = Object::cast_to<Vector<float>>(a);
const Vector<float> *arr_b = Object::cast_to<Vector<float>>(b);
int sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
return a;
} else {
Vector<float> v;
v.resize(sz);
{
float *vw = v.ptrw();
const float *ar = arr_a->ptr();
const float *br = arr_b->ptr();
Variant va;
for (int i = 0; i < sz; i++) {
va = interpolate_variant(ar[i], br[i], c);
vw[i] = va;
}
}
return v;
}
}
case Variant::PACKED_FLOAT64_ARRAY: {
const Vector<double> *arr_a = Object::cast_to<Vector<double>>(a);
const Vector<double> *arr_b = Object::cast_to<Vector<double>>(b);
int sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
return a;
} else {
Vector<double> v;
v.resize(sz);
{
double *vw = v.ptrw();
const double *ar = arr_a->ptr();
const double *br = arr_b->ptr();
Variant va;
for (int i = 0; i < sz; i++) {
va = interpolate_variant(ar[i], br[i], c);
vw[i] = va;
}
}
return v;
}
}
case Variant::PACKED_VECTOR2_ARRAY: {
const Vector<Vector2> *arr_a = Object::cast_to<Vector<Vector2>>(a);
const Vector<Vector2> *arr_b = Object::cast_to<Vector<Vector2>>(b);
int sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
return a;
} else {
Vector<Vector2> v;
v.resize(sz);
{
Vector2 *vw = v.ptrw();
const Vector2 *ar = arr_a->ptr();
const Vector2 *br = arr_b->ptr();
for (int i = 0; i < sz; i++) {
vw[i] = ar[i].lerp(br[i], c);
}
}
return v;
}
}
case Variant::PACKED_VECTOR3_ARRAY: {
const Vector<Vector3> *arr_a = Object::cast_to<Vector<Vector3>>(a);
const Vector<Vector3> *arr_b = Object::cast_to<Vector<Vector3>>(b);
int sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
return a;
} else {
Vector<Vector3> v;
v.resize(sz);
{
Vector3 *vw = v.ptrw();
const Vector3 *ar = arr_a->ptr();
const Vector3 *br = arr_b->ptr();
for (int i = 0; i < sz; i++) {
vw[i] = ar[i].lerp(br[i], c);
}
}
return v;
}
}
case Variant::PACKED_COLOR_ARRAY: {
const Vector<Color> *arr_a = Object::cast_to<Vector<Color>>(a);
const Vector<Color> *arr_b = Object::cast_to<Vector<Color>>(b);
int sz = arr_a->size();
if (sz == 0 || arr_b->size() != sz) {
return a;
} else {
Vector<Color> v;
v.resize(sz);
{
Color *vw = v.ptrw();
const Color *ar = arr_a->ptr();
const Color *br = arr_b->ptr();
for (int i = 0; i < sz; i++) {
vw[i] = ar[i].lerp(br[i], c);
}
}
return v;
}
}
default: {
return c < 0.5 ? a : b;
}
}
}
Animation::Animation() {}
Animation::~Animation() {

View file

@ -496,6 +496,12 @@ public:
void optimize(real_t p_allowed_velocity_err = 0.01, real_t p_allowed_angular_err = 0.01, int p_precision = 3);
void compress(uint32_t p_page_size = 8192, uint32_t p_fps = 120, float p_split_tolerance = 4.0); // 4.0 seems to be the split tolerance sweet spot from many tests
// Helper math fuctions for Variant.
static Variant add_variant(const Variant &a, const Variant &b);
static Variant subtract_variant(const Variant &a, const Variant &b);
static Variant blend_variant(const Variant &a, const Variant &b, float c);
static Variant interpolate_variant(const Variant &a, const Variant &b, float c);
Animation();
~Animation();
};