/* FIXME: Broken, entities "disappears" */ vec3 vec3_slerp(const vec3 *v, const vec3 *u, float t) { const double DOT_THRESHOLD = 0.9995; float dot; float theta; vec3 v0, u0, w; v0 = *v; u0 = *u; dot = vec3_dot(&v0, &u0); if (dot > DOT_THRESHOLD) { vec3_lerp(&v0, &u0, t); } theta = t * acosf(dot); w = vec3_mul(v, dot); w = vec3_sub(u, &w); //w = vector_normalize(&w); v0 = vec3_mul(&v0, cosf(theta)); u0 = vec3_mul(&u0, sinf(theta)); w = vec3_add(&v0, &u0); return w; }
void Vector::lerp(const Vector& v1, const Vector& v2, float t) { vec3_lerp(&this->v_, &v1.v_, &v2.v_, t); }
X42_EXPORT bool X42_CALL x42_LerpAnims( x42animLerp_t *lerp, const x42data_t *x42, const x42animFrames_t *anim, x42opts_t *opts ) { uint i, j; const vec3_t * RESTRICT pv; const vec3_t * RESTRICT sv; const quat_t * RESTRICT rv; vec3_t * RESTRICT po; vec3_t * RESTRICT so; quat_t * RESTRICT ro; REF_PARAM( opts ); #ifndef LIBX42_NO_PARAM_VALIDATION demand_rf( lerp != NULL, X42_ERR_BADPTR, "lerp is NULL" ); demand_rf( anim != NULL, X42_ERR_BADPTR, "anim is NULL" ); demand_rf( x42 != NULL, X42_ERR_BADPTR, "x42 is NULL" ); demand_rf( x42_ValidateHeader( &x42->header ), X42_ERR_BADDATA, "invalid x42 header data" ); #endif pv = x42->posValues; sv = x42->scaleValues; rv = x42->rotValues; po = lerp->p; so = lerp->s; ro = lerp->r; for( i = 0; i < x42->header.numAnimGroups; i++ ) { const x42ksBoneEntry_t * RESTRICT p; uint beginBone = x42->animGroups[i].beginBone; uint endBone = x42->animGroups[i].endBone; float target = anim->frames[i].targetFrame; for( j = beginBone; j < endBone; j++ ) { p = anim->kpairs[j][X42_KT_POSITION]; if( p[0].value == p[1].value ) vec3_cpy( po[j], pv[p[0].value] ); else { float s = (float)(int)p[0].frame; float e = (float)(int)p[1].frame; float t = (target - s) / (e - s); vec3_lerp( po[j], pv[p[0].value], pv[p[1].value], t ); } } for( j = beginBone; j < endBone; j++ ) { p = anim->kpairs[j][X42_KT_SCALE]; if( p[0].value == p[1].value ) vec3_cpy( so[j], sv[p[0].value] ); else { float s = (float)(int)p[0].frame; float e = (float)(int)p[1].frame; float t = (target - s) / (e - s); vec3_lerp( so[j], sv[p[0].value], sv[p[1].value], t ); } } for( j = beginBone; j < endBone; j++ ) { p = anim->kpairs[j][X42_KT_ROTATION]; if( p[0].value == p[1].value ) quat_cpy( ro[j], rv[p[0].value] ); else { float s = (float)(int)p[0].frame; float e = (float)(int)p[1].frame; float t = (target - s) / (e - s); quat_interp( ro[j], rv[p[0].value], rv[p[1].value], t ); } } } return true; }
X42_EXPORT x42animLerp_t* X42_CALL x42_BlendAnimations( void *out_buffer, const x42data_t *x42, const x42animLerp_t *lerp0, const x42animLerp_t *lerp1, const float *blendValues, x42opts_t *opts ) { uint i, j; x42animLerp_t *ret; const vec3_t * RESTRICT pv0, * RESTRICT pv1; const vec3_t * RESTRICT sv0, * RESTRICT sv1; const quat_t * RESTRICT rv0, * RESTRICT rv1; vec3_t * RESTRICT po; vec3_t * RESTRICT so; quat_t * RESTRICT ro; REF_PARAM( opts ); #ifndef LIBX42_NO_PARAM_VALIDATION demand_rn( out_buffer != NULL, X42_ERR_BADPTR, "out_buffer is NULL" ); demand_rn( lerp0 != NULL, X42_ERR_BADPTR, "lerp0 is NULL" ); demand_rn( lerp1 != NULL, X42_ERR_BADPTR, "lerp1 is NULL" ); demand_rn( blendValues != NULL, X42_ERR_BADPTR, "blendValues is NULL" ); demand_rn( x42 != NULL, X42_ERR_BADPTR, "x42 is NULL" ); demand_rn( x42_ValidateHeader( &x42->header ), X42_ERR_BADDATA, "invalid x42 header data" ); #endif ret = (x42animLerp_t*)out_buffer; pv0 = lerp0->p; sv0 = lerp0->s; rv0 = lerp0->r; pv1 = lerp1->p; sv1 = lerp1->s; rv1 = lerp1->r; po = ret->p; so = ret->s; ro = ret->r; for( i = 0; i < x42->header.numAnimGroups; i++ ) { uint beginBone = x42->animGroups[i].beginBone; uint endBone = x42->animGroups[i].endBone; float lerp = blendValues[i]; for( j = beginBone; j < endBone; j++ ) { vec3_lerp( po[j], pv0[j], pv1[j], lerp ); } for( j = beginBone; j < endBone; j++ ) { vec3_lerp( so[j], sv0[j], sv1[j], lerp ); } for( j = beginBone; j < endBone; j++ ) { quat_interp( ro[j], rv0[j], rv1[j], lerp ); } } return ret; }