Browse Source

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

Move some static methods to `Animation` from `Variant` for refactoring `Animation` and `Tween`
Rémi Verschelde 2 years ago
parent
commit
a981a8061f

+ 0 - 24
core/extension/gdnative_interface.cpp

@@ -251,27 +251,6 @@ static GDNativeBool gdnative_variant_booleanize(const GDNativeVariantPtr p_self)
 	return self->booleanize();
 	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) {
 static void gdnative_variant_duplicate(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep) {
 	const Variant *self = (const Variant *)p_self;
 	const Variant *self = (const Variant *)p_self;
 	memnew_placement(r_ret, Variant(self->duplicate(p_deep)));
 	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_recursive_hash = gdnative_variant_recursive_hash;
 	gdni.variant_hash_compare = gdnative_variant_hash_compare;
 	gdni.variant_hash_compare = gdnative_variant_hash_compare;
 	gdni.variant_booleanize = gdnative_variant_booleanize;
 	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_duplicate = gdnative_variant_duplicate;
 	gdni.variant_stringify = gdnative_variant_stringify;
 	gdni.variant_stringify = gdnative_variant_stringify;
 
 

+ 0 - 3
core/extension/gdnative_interface.h

@@ -427,9 +427,6 @@ typedef struct {
 	GDNativeInt (*variant_recursive_hash)(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count);
 	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_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other);
 	GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self);
 	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_duplicate)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep);
 	void (*variant_stringify)(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret);
 	void (*variant_stringify)(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret);
 
 

+ 0 - 3
core/variant/variant.h

@@ -552,9 +552,6 @@ public:
 	void zero();
 	void zero();
 	Variant duplicate(bool p_deep = false) const;
 	Variant duplicate(bool p_deep = false) const;
 	Variant recursive_duplicate(bool p_deep, int recursion_count) 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 */
 	/* Built-In Methods */
 
 

+ 0 - 566
core/variant/variant_setget.cpp

@@ -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() {
 void Variant::_register_variant_setters_getters() {
 	register_named_setters_getters();
 	register_named_setters_getters();
 	register_indexed_setters_getters();
 	register_indexed_setters_getters();

+ 2 - 3
editor/animation_track_editor.cpp

@@ -6050,10 +6050,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
 							real_t to_diff = fmod(b - a, Math_TAU);
 							real_t to_diff = fmod(b - a, Math_TAU);
 							to_v = a + fmod(2.0 * to_diff, Math_TAU) - to_diff;
 							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 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) {
 						for (double delta_t = dur_step; delta_t < fixed_duration; delta_t += dur_step) {
 							Pair<real_t, Variant> keydata;
 							Pair<real_t, Variant> keydata;
 							keydata.first = from_t + delta_t;
 							keydata.first = from_t + delta_t;

+ 3 - 4
scene/animation/animation_player.cpp

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

+ 12 - 3
scene/animation/animation_tree.cpp

@@ -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);
 								t->value = Math::fposmod(rot_a + (rot_b - rot_init) * (float)blend, (float)Math_TAU);
 							} else {
 							} 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 {
 						} else {
 							if (blend < CMP_EPSILON) {
 							if (blend < CMP_EPSILON) {
@@ -1703,7 +1708,11 @@ void AnimationTree::_process_graph(double p_delta) {
 				case Animation::TYPE_VALUE: {
 				case Animation::TYPE_VALUE: {
 					TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
 					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;
 				} break;
 				case Animation::TYPE_BEZIER: {
 				case Animation::TYPE_BEZIER: {

+ 11 - 260
scene/animation/tween.cpp

@@ -32,6 +32,7 @@
 
 
 #include "scene/animation/easing_equations.h"
 #include "scene/animation/easing_equations.h"
 #include "scene/main/node.h"
 #include "scene/main/node.h"
+#include "scene/resources/animation.h"
 
 
 Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = {
 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.
 	{ &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_trans, TransitionType::TRANS_MAX, Variant());
 	ERR_FAIL_INDEX_V(p_ease, EaseType::EASE_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);
-
-	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);
-		}
+	// 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;
+	}
 
 
-		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() {
 void Tween::_bind_methods() {
@@ -748,10 +499,10 @@ void PropertyTweener::start() {
 	}
 	}
 
 
 	if (relative) {
 	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) {
 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) {
 MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration) {
 	callback = p_callback;
 	callback = p_callback;
 	initial_val = p_from;
 	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;
 	final_val = p_to;
 	duration = p_duration;
 	duration = p_duration;
 }
 }

+ 0 - 1
scene/animation/tween.h

@@ -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 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);
 	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 step(float p_delta);
 	bool can_process(bool p_tree_paused) const;
 	bool can_process(bool p_tree_paused) const;

+ 461 - 3
scene/resources/animation.cpp

@@ -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 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 {
 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;
 	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() {}
 
 
 Animation::~Animation() {
 Animation::~Animation() {

+ 6 - 0
scene/resources/animation.h

@@ -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 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
 	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();
 	~Animation();
 	~Animation();
 };
 };