/* ============== RE_BlendSkeleton ============== */ int RE_BlendSkeleton(refSkeleton_t *skel, const refSkeleton_t *blend, float frac) { int i; vec3_t lerpedOrigin; quat_t lerpedQuat; vec3_t bounds[2]; if (skel->numBones != blend->numBones) { Ren_Warning("RE_BlendSkeleton: different number of bones %d != %d\n", skel->numBones, blend->numBones); return qfalse; } // lerp between the 2 bone poses for (i = 0; i < skel->numBones; i++) { VectorLerp(skel->bones[i].origin, blend->bones[i].origin, frac, lerpedOrigin); quat_slerp(skel->bones[i].rotation, blend->bones[i].rotation, frac, lerpedQuat); VectorCopy(lerpedOrigin, skel->bones[i].origin); quat_copy(lerpedQuat, skel->bones[i].rotation); } // calculate a bounding box in the current coordinate system for (i = 0; i < 3; i++) { bounds[0][i] = skel->bounds[0][i] < blend->bounds[0][i] ? skel->bounds[0][i] : blend->bounds[0][i]; bounds[1][i] = skel->bounds[1][i] > blend->bounds[1][i] ? skel->bounds[1][i] : blend->bounds[1][i]; } VectorCopy(bounds[0], skel->bounds[0]); VectorCopy(bounds[1], skel->bounds[1]); return qtrue; }
quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm) { quat_t q; anm_time_t tm0 = animation_time(node, tm, 0); struct anm_animation *anim0 = anm_get_active_animation(node, 0); struct anm_animation *anim1 = anm_get_active_animation(node, 1); if(!anim0) { return quat_identity(); } q = get_node_rotation(node, tm0, anim0); if(anim1) { anm_time_t tm1 = animation_time(node, tm, 1); quat_t q1 = get_node_rotation(node, tm1, anim1); q = quat_slerp(q, q1, node->cur_mix); } return q; }
void quat_sberp(fastf_t *qout, const fastf_t *q1, const fastf_t *qa, const fastf_t *qb, const fastf_t *q2, double f) { quat_t p1, p2, p3, p4, p5; /* Interp down the three segments */ quat_slerp( p1, q1, qa, f ); quat_slerp( p2, qa, qb, f ); quat_slerp( p3, qb, q2, f ); /* Interp down the resulting two */ quat_slerp( p4, p1, p2, f ); quat_slerp( p5, p2, p3, f ); /* Interp this segment for final quaternion */ quat_slerp( qout, p4, p5, f ); }
static quat_t get_node_rotation(struct anm_node *node, anm_time_t tm, struct anm_animation *anim) { #ifndef ROT_USE_SLERP quat_t q; q.x = anm_get_value(anim->tracks + ANM_TRACK_ROT_X, tm); q.y = anm_get_value(anim->tracks + ANM_TRACK_ROT_Y, tm); q.z = anm_get_value(anim->tracks + ANM_TRACK_ROT_Z, tm); q.w = anm_get_value(anim->tracks + ANM_TRACK_ROT_W, tm); return q; #else int idx0, idx1, last_idx; anm_time_t tstart, tend; float t, dt; struct anm_track *track_x, *track_y, *track_z, *track_w; quat_t q, q1, q2; track_x = anim->tracks + ANM_TRACK_ROT_X; track_y = anim->tracks + ANM_TRACK_ROT_Y; track_z = anim->tracks + ANM_TRACK_ROT_Z; track_w = anim->tracks + ANM_TRACK_ROT_W; if(!track_x->count) { q.x = track_x->def_val; q.y = track_y->def_val; q.z = track_z->def_val; q.w = track_w->def_val; return q; } last_idx = track_x->count - 1; tstart = track_x->keys[0].time; tend = track_x->keys[last_idx].time; if(tstart == tend) { q.x = track_x->keys[0].val; q.y = track_y->keys[0].val; q.z = track_z->keys[0].val; q.w = track_w->keys[0].val; return q; } tm = anm_remap_time(track_x, tm, tstart, tend); idx0 = anm_get_key_interval(track_x, tm); assert(idx0 >= 0 && idx0 < track_x->count); idx1 = idx0 + 1; if(idx0 == last_idx) { q.x = track_x->keys[idx0].val; q.y = track_y->keys[idx0].val; q.z = track_z->keys[idx0].val; q.w = track_w->keys[idx0].val; return q; } dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time); t = (float)(tm - track_x->keys[idx0].time) / dt; q1.x = track_x->keys[idx0].val; q1.y = track_y->keys[idx0].val; q1.z = track_z->keys[idx0].val; q1.w = track_w->keys[idx0].val; q2.x = track_x->keys[idx1].val; q2.y = track_y->keys[idx1].val; q2.z = track_z->keys[idx1].val; q2.w = track_w->keys[idx1].val; /*q1 = quat_normalize(q1); q2 = quat_normalize(q2);*/ return quat_slerp(q1, q2, t); #endif }
void Quat::slerp(const Quat& q1, const Quat& q2, float t) { quat_slerp(&this->q_, &q1.q_, &q2.q_, t); }
int bn_math_cmd(ClientData clientData, Tcl_Interp *interp, int argc, char **argv) { void (*math_func)(); struct bu_vls result; math_func = (void (*)())clientData; /* object-to-function cast */ bu_vls_init(&result); if (math_func == bn_mat_mul) { mat_t o, a, b; if (argc < 3 || bn_decode_mat(a, argv[1]) < 16 || bn_decode_mat(b, argv[2]) < 16) { bu_vls_printf(&result, "usage: %s matA matB", argv[0]); goto error; } bn_mat_mul(o, a, b); bn_encode_mat(&result, o); } else if (math_func == bn_mat_inv || math_func == bn_mat_trn) { mat_t o, a; if (argc < 2 || bn_decode_mat(a, argv[1]) < 16) { bu_vls_printf(&result, "usage: %s mat", argv[0]); goto error; } (*math_func)(o, a); bn_encode_mat(&result, o); } else if (math_func == bn_matXvec) { mat_t m; hvect_t i, o; if (argc < 3 || bn_decode_mat(m, argv[1]) < 16 || bn_decode_hvect(i, argv[2]) < 4) { bu_vls_printf(&result, "usage: %s mat hvect", argv[0]); goto error; } bn_matXvec(o, m, i); bn_encode_hvect(&result, o); } else if (math_func == bn_mat4x3pnt) { mat_t m; point_t i, o; if (argc < 3 || bn_decode_mat(m, argv[1]) < 16 || bn_decode_vect(i, argv[2]) < 3) { bu_vls_printf(&result, "usage: %s mat point", argv[0]); goto error; } bn_mat4x3pnt(o, m, i); bn_encode_vect(&result, o); } else if (math_func == bn_mat4x3vec) { mat_t m; vect_t i, o; if (argc < 3 || bn_decode_mat(m, argv[1]) < 16 || bn_decode_vect(i, argv[2]) < 3) { bu_vls_printf(&result, "usage: %s mat vect", argv[0]); goto error; } bn_mat4x3vec(o, m, i); bn_encode_vect(&result, o); } else if (math_func == bn_hdivide) { hvect_t i; vect_t o; if (argc < 2 || bn_decode_hvect(i, argv[1]) < 4) { bu_vls_printf(&result, "usage: %s hvect", argv[0]); goto error; } bn_hdivide(o, i); bn_encode_vect(&result, o); } else if (math_func == bn_vjoin1) { point_t o; point_t b, d; fastf_t c; if (argc < 4) { bu_vls_printf(&result, "usage: %s pnt scale dir", argv[0]); goto error; } if ( bn_decode_vect(b, argv[1]) < 3) goto error; if (Tcl_GetDouble(interp, argv[2], &c) != TCL_OK) goto error; if ( bn_decode_vect(d, argv[3]) < 3) goto error; VJOIN1( o, b, c, d ); /* bn_vjoin1( o, b, c, d ) */ bn_encode_vect(&result, o); } else if ( math_func == bn_vblend) { point_t a, c, e; fastf_t b, d; if ( argc < 5 ) { bu_vls_printf(&result, "usage: %s scale pnt scale pnt", argv[0]); goto error; } if ( Tcl_GetDouble(interp, argv[1], &b) != TCL_OK) goto error; if ( bn_decode_vect( c, argv[2] ) < 3) goto error; if ( Tcl_GetDouble(interp, argv[3], &d) != TCL_OK) goto error; if ( bn_decode_vect( e, argv[4] ) < 3) goto error; VBLEND2( a, b, c, d, e ) bn_encode_vect( &result, a ); } else if (math_func == bn_mat_ae) { mat_t o; double az, el; if (argc < 3) { bu_vls_printf(&result, "usage: %s azimuth elevation", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[1], &az) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[2], &el) != TCL_OK) goto error; bn_mat_ae(o, (fastf_t)az, (fastf_t)el); bn_encode_mat(&result, o); } else if (math_func == bn_ae_vec) { fastf_t az, el; vect_t v; if (argc < 2 || bn_decode_vect(v, argv[1]) < 3) { bu_vls_printf(&result, "usage: %s vect", argv[0]); goto error; } bn_ae_vec(&az, &el, v); bu_vls_printf(&result, "%g %g", az, el); } else if (math_func == bn_aet_vec) { fastf_t az, el, twist, accuracy; vect_t vec_ae, vec_twist; if (argc < 4 || bn_decode_vect(vec_ae, argv[1]) < 3 || bn_decode_vect(vec_twist, argv[2]) < 3 || sscanf(argv[3], "%lf", &accuracy) < 1) { bu_vls_printf(&result, "usage: %s vec_ae vec_twist accuracy", argv[0]); goto error; } bn_aet_vec(&az, &el, &twist, vec_ae, vec_twist, accuracy); bu_vls_printf(&result, "%g %g %g", az, el, twist); } else if (math_func == bn_mat_angles) { mat_t o; double alpha, beta, ggamma; if (argc < 4) { bu_vls_printf(&result, "usage: %s alpha beta gamma", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[1], &alpha) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[2], &beta) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[3], &ggamma) != TCL_OK) goto error; bn_mat_angles(o, alpha, beta, ggamma); bn_encode_mat(&result, o); } else if (math_func == bn_eigen2x2) { fastf_t val1, val2; vect_t vec1, vec2; double a, b, c; if (argc < 4) { bu_vls_printf(&result, "usage: %s a b c", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[1], &a) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[2], &c) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[3], &b) != TCL_OK) goto error; bn_eigen2x2(&val1, &val2, vec1, vec2, (fastf_t)a, (fastf_t)b, (fastf_t)c); bu_vls_printf(&result, "%g %g {%g %g %g} {%g %g %g}", val1, val2, V3ARGS(vec1), V3ARGS(vec2)); } else if (math_func == bn_mat_fromto) { mat_t o; vect_t from, to; if (argc < 3 || bn_decode_vect(from, argv[1]) < 3 || bn_decode_vect(to, argv[2]) < 3) { bu_vls_printf(&result, "usage: %s vecFrom vecTo", argv[0]); goto error; } bn_mat_fromto(o, from, to); bn_encode_mat(&result, o); } else if (math_func == bn_mat_xrot || math_func == bn_mat_yrot || math_func == bn_mat_zrot) { mat_t o; double s, c; if (argc < 3) { bu_vls_printf(&result, "usage: %s sinAngle cosAngle", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[1], &s) != TCL_OK) goto error; if (Tcl_GetDouble(interp, argv[2], &c) != TCL_OK) goto error; (*math_func)(o, s, c); bn_encode_mat(&result, o); } else if (math_func == bn_mat_lookat) { mat_t o; vect_t dir; int yflip; if (argc < 3 || bn_decode_vect(dir, argv[1]) < 3) { bu_vls_printf(&result, "usage: %s dir yflip", argv[0]); goto error; } if (Tcl_GetBoolean(interp, argv[2], &yflip) != TCL_OK) goto error; bn_mat_lookat(o, dir, yflip); bn_encode_mat(&result, o); } else if (math_func == bn_vec_ortho || math_func == bn_vec_perp) { vect_t ov, vec; if (argc < 2 || bn_decode_vect(vec, argv[1]) < 3) { bu_vls_printf(&result, "usage: %s vec", argv[0]); goto error; } (*math_func)(ov, vec); bn_encode_vect(&result, ov); } else if (math_func == bn_mat_scale_about_pt_wrapper) { mat_t o; vect_t v; double scale; int status; if (argc < 3 || bn_decode_vect(v, argv[1]) < 3) { bu_vls_printf(&result, "usage: %s pt scale", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[2], &scale) != TCL_OK) goto error; bn_mat_scale_about_pt_wrapper(&status, o, v, scale); if (status != 0) { bu_vls_printf(&result, "error performing calculation"); goto error; } bn_encode_mat(&result, o); } else if (math_func == bn_mat_xform_about_pt) { mat_t o, xform; vect_t v; if (argc < 3 || bn_decode_mat(xform, argv[1]) < 16 || bn_decode_vect(v, argv[2]) < 3) { bu_vls_printf(&result, "usage: %s xform pt", argv[0]); goto error; } bn_mat_xform_about_pt(o, xform, v); bn_encode_mat(&result, o); } else if (math_func == bn_mat_arb_rot) { mat_t o; point_t pt; vect_t dir; double angle; if (argc < 4 || bn_decode_vect(pt, argv[1]) < 3 || bn_decode_vect(dir, argv[2]) < 3) { bu_vls_printf(&result, "usage: %s pt dir angle", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[3], &angle) != TCL_OK) return TCL_ERROR; bn_mat_arb_rot(o, pt, dir, (fastf_t)angle); bn_encode_mat(&result, o); } else if (math_func == quat_mat2quat) { mat_t mat; quat_t quat; if (argc < 2 || bn_decode_mat(mat, argv[1]) < 16) { bu_vls_printf(&result, "usage: %s mat", argv[0]); goto error; } quat_mat2quat(quat, mat); bn_encode_quat(&result, quat); } else if (math_func == quat_quat2mat) { mat_t mat; quat_t quat; if (argc < 2 || bn_decode_quat(quat, argv[1]) < 4) { bu_vls_printf(&result, "usage: %s quat", argv[0]); goto error; } quat_quat2mat(mat, quat); bn_encode_mat(&result, mat); } else if (math_func == bn_quat_distance_wrapper) { quat_t q1, q2; double d; if (argc < 3 || bn_decode_quat(q1, argv[1]) < 4 || bn_decode_quat(q2, argv[2]) < 4) { bu_vls_printf(&result, "usage: %s quatA quatB", argv[0]); goto error; } bn_quat_distance_wrapper(&d, q1, q2); bu_vls_printf(&result, "%g", d); } else if (math_func == quat_double || math_func == quat_bisect || math_func == quat_make_nearest) { quat_t oqot, q1, q2; if (argc < 3 || bn_decode_quat(q1, argv[1]) < 4 || bn_decode_quat(q2, argv[2]) < 4) { bu_vls_printf(&result, "usage: %s quatA quatB", argv[0]); goto error; } (*math_func)(oqot, q1, q2); bn_encode_quat(&result, oqot); } else if (math_func == quat_slerp) { quat_t oq, q1, q2; double d; if (argc < 4 || bn_decode_quat(q1, argv[1]) < 4 || bn_decode_quat(q2, argv[2]) < 4) { bu_vls_printf(&result, "usage: %s quat1 quat2 factor", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[3], &d) != TCL_OK) goto error; quat_slerp(oq, q1, q2, d); bn_encode_quat(&result, oq); } else if (math_func == quat_sberp) { quat_t oq, q1, qa, qb, q2; double d; if (argc < 6 || bn_decode_quat(q1, argv[1]) < 4 || bn_decode_quat(qa, argv[2]) < 4 || bn_decode_quat(qb, argv[3]) < 4 || bn_decode_quat(q2, argv[4]) < 4) { bu_vls_printf(&result, "usage: %s quat1 quatA quatB quat2 factor", argv[0]); goto error; } if (Tcl_GetDouble(interp, argv[5], &d) != TCL_OK) goto error; quat_sberp(oq, q1, qa, qb, q2, d); bn_encode_quat(&result, oq); } else if (math_func == quat_exp || math_func == quat_log) { quat_t qout, qin; if (argc < 2 || bn_decode_quat(qin, argv[1]) < 4) { bu_vls_printf(&result, "usage: %s quat", argv[0]); goto error; } (*math_func)(qout, qin); bn_encode_quat(&result, qout); } else if (math_func == (void (*)())bn_isect_line3_line3) { double t, u; point_t pt, a; vect_t dir, c; int i; static const struct bn_tol tol = { BN_TOL_MAGIC, 0.005, 0.005*0.005, 1e-6, 1-1e-6 }; if (argc != 5) { bu_vls_printf(&result, "Usage: bn_isect_line3_line3 pt dir pt dir (%d args specified)", argc-1); goto error; } if (bn_decode_vect(pt, argv[1]) < 3) { bu_vls_printf(&result, "bn_isect_line3_line3 no pt: %s\n", argv[0]); goto error; } if (bn_decode_vect(dir, argv[2]) < 3) { bu_vls_printf(&result, "bn_isect_line3_line3 no dir: %s\n", argv[0]); goto error; } if (bn_decode_vect(a, argv[3]) < 3) { bu_vls_printf(&result, "bn_isect_line3_line3 no a pt: %s\n", argv[0]); goto error; } if (bn_decode_vect(c, argv[4]) < 3) { bu_vls_printf(&result, "bn_isect_line3_line3 no c dir: %s\n", argv[0]); goto error; } i = bn_isect_line3_line3(&t, &u, pt, dir, a, c, &tol); if (i != 1) { bu_vls_printf(&result, "bn_isect_line3_line3 no intersection: %s\n", argv[0]); goto error; } VJOIN1(a, pt, t, dir); bn_encode_vect(&result, a); } else if (math_func == (void (*)())bn_isect_line2_line2) { double dist[2]; point_t pt, a; vect_t dir, c; int i; static const struct bn_tol tol = { BN_TOL_MAGIC, 0.005, 0.005*0.005, 1e-6, 1-1e-6 }; if (argc != 5) { bu_vls_printf(&result, "Usage: bn_isect_line2_line2 pt dir pt dir (%d args specified)", argc-1); goto error; } /* i = bn_isect_line2_line2 {0 0} {1 0} {1 1} {0 -1} */ VSETALL(pt, 0.0); VSETALL(dir, 0.0); VSETALL(a, 0.0); VSETALL(c, 0.0); if (bn_decode_vect(pt, argv[1]) < 2) { bu_vls_printf(&result, "bn_isect_line2_line2 no pt: %s\n", argv[0]); goto error; } if (bn_decode_vect(dir, argv[2]) < 2) { bu_vls_printf(&result, "bn_isect_line2_line2 no dir: %s\n", argv[0]); goto error; } if (bn_decode_vect(a, argv[3]) < 2) { bu_vls_printf(&result, "bn_isect_line2_line2 no a pt: %s\n", argv[0]); goto error; } if (bn_decode_vect(c, argv[4]) < 2) { bu_vls_printf(&result, "bn_isect_line2_line2 no c dir: %s\n", argv[0]); goto error; } i = bn_isect_line2_line2(dist, pt, dir, a, c, &tol); if (i != 1) { bu_vls_printf(&result, "bn_isect_line2_line2 no intersection: %s\n", argv[0]); goto error; } VJOIN1(a, pt, dist[0], dir); bu_vls_printf(&result, "%g %g", a[0], a[1]); } else { bu_vls_printf(&result, "libbn/bn_tcl.c: math function %s not supported yet\n", argv[0]); goto error; } Tcl_AppendResult(interp, bu_vls_addr(&result), (char *)NULL); bu_vls_free(&result); return TCL_OK; error: Tcl_AppendResult(interp, bu_vls_addr(&result), (char *)NULL); bu_vls_free(&result); return TCL_ERROR; }
/* ============== RE_BuildSkeleton ============== */ int RE_BuildSkeleton(refSkeleton_t *skel, qhandle_t hAnim, int startFrame, int endFrame, float frac, qboolean clearOrigin) { skelAnimation_t *skelAnim; skelAnim = R_GetAnimationByHandle(hAnim); if (skelAnim->type == AT_MD5 && skelAnim->md5) { int i; md5Animation_t *anim = skelAnim->md5; md5Channel_t *channel; md5Frame_t *newFrame, *oldFrame; vec3_t newOrigin, oldOrigin, lerpedOrigin; quat_t newQuat, oldQuat, lerpedQuat; int componentsApplied; // Validate the frames so there is no chance of a crash. // This will write directly into the entity structure, so // when the surfaces are rendered, they don't need to be // range checked again. //if((startFrame >= anim->numFrames) || (startFrame < 0) || (endFrame >= anim->numFrames) || (endFrame < 0)) //{ // Ren_Developer( "RE_BuildSkeleton: no such frame %d to %d for '%s'\n", startFrame, endFrame, anim->name); // //startFrame = 0; // //endFrame = 0; //} Q_clamp(startFrame, 0, anim->numFrames - 1); Q_clamp(endFrame, 0, anim->numFrames - 1); // compute frame pointers oldFrame = &anim->frames[startFrame]; newFrame = &anim->frames[endFrame]; // calculate a bounding box in the current coordinate system for (i = 0; i < 3; i++) { skel->bounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; skel->bounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; } for (i = 0, channel = anim->channels; i < anim->numChannels; i++, channel++) { // set baseframe values VectorCopy(channel->baseOrigin, newOrigin); VectorCopy(channel->baseOrigin, oldOrigin); quat_copy(channel->baseQuat, newQuat); quat_copy(channel->baseQuat, oldQuat); componentsApplied = 0; // update tranlation bits if (channel->componentsBits & COMPONENT_BIT_TX) { oldOrigin[0] = oldFrame->components[channel->componentsOffset + componentsApplied]; newOrigin[0] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if (channel->componentsBits & COMPONENT_BIT_TY) { oldOrigin[1] = oldFrame->components[channel->componentsOffset + componentsApplied]; newOrigin[1] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if (channel->componentsBits & COMPONENT_BIT_TZ) { oldOrigin[2] = oldFrame->components[channel->componentsOffset + componentsApplied]; newOrigin[2] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } // update quaternion rotation bits if (channel->componentsBits & COMPONENT_BIT_QX) { ((vec_t *) oldQuat)[0] = oldFrame->components[channel->componentsOffset + componentsApplied]; ((vec_t *) newQuat)[0] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if (channel->componentsBits & COMPONENT_BIT_QY) { ((vec_t *) oldQuat)[1] = oldFrame->components[channel->componentsOffset + componentsApplied]; ((vec_t *) newQuat)[1] = newFrame->components[channel->componentsOffset + componentsApplied]; componentsApplied++; } if (channel->componentsBits & COMPONENT_BIT_QZ) { ((vec_t *) oldQuat)[2] = oldFrame->components[channel->componentsOffset + componentsApplied]; ((vec_t *) newQuat)[2] = newFrame->components[channel->componentsOffset + componentsApplied]; } QuatCalcW(oldQuat); quat_norm(oldQuat); QuatCalcW(newQuat); quat_norm(newQuat); #if 1 VectorLerp(oldOrigin, newOrigin, frac, lerpedOrigin); quat_slerp(oldQuat, newQuat, frac, lerpedQuat); #else VectorCopy(newOrigin, lerpedOrigin); quat_copy(newQuat, lerpedQuat); #endif // copy lerped information to the bone + extra data skel->bones[i].parentIndex = channel->parentIndex; if (channel->parentIndex < 0 && clearOrigin) { VectorClear(skel->bones[i].origin); QuatClear(skel->bones[i].rotation); // move bounding box back VectorSubtract(skel->bounds[0], lerpedOrigin, skel->bounds[0]); VectorSubtract(skel->bounds[1], lerpedOrigin, skel->bounds[1]); } else { VectorCopy(lerpedOrigin, skel->bones[i].origin); } quat_copy(lerpedQuat, skel->bones[i].rotation); #if defined(REFBONE_NAMES) Q_strncpyz(skel->bones[i].name, channel->name, sizeof(skel->bones[i].name)); #endif } skel->numBones = anim->numChannels; skel->type = SK_RELATIVE; return qtrue; } else if (skelAnim->type == AT_PSA && skelAnim->psa) { int i; psaAnimation_t *anim = skelAnim->psa; axAnimationKey_t *newKey, *oldKey; axReferenceBone_t *refBone; vec3_t newOrigin, oldOrigin, lerpedOrigin; quat_t newQuat, oldQuat, lerpedQuat; refSkeleton_t skeleton; Q_clamp(startFrame, 0, anim->info.numRawFrames - 1); Q_clamp(endFrame, 0, anim->info.numRawFrames - 1); ClearBounds(skel->bounds[0], skel->bounds[1]); skel->numBones = anim->info.numBones; for (i = 0, refBone = anim->bones; i < anim->info.numBones; i++, refBone++) { oldKey = &anim->keys[startFrame * anim->info.numBones + i]; newKey = &anim->keys[endFrame * anim->info.numBones + i]; VectorCopy(newKey->position, newOrigin); VectorCopy(oldKey->position, oldOrigin); quat_copy(newKey->quat, newQuat); quat_copy(oldKey->quat, oldQuat); //QuatCalcW(oldQuat); //QuatNormalize(oldQuat); //QuatCalcW(newQuat); //QuatNormalize(newQuat); VectorLerp(oldOrigin, newOrigin, frac, lerpedOrigin); quat_slerp(oldQuat, newQuat, frac, lerpedQuat); // copy lerped information to the bone + extra data skel->bones[i].parentIndex = refBone->parentIndex; if (refBone->parentIndex < 0 && clearOrigin) { VectorClear(skel->bones[i].origin); QuatClear(skel->bones[i].rotation); // move bounding box back VectorSubtract(skel->bounds[0], lerpedOrigin, skel->bounds[0]); VectorSubtract(skel->bounds[1], lerpedOrigin, skel->bounds[1]); } else { VectorCopy(lerpedOrigin, skel->bones[i].origin); } quat_copy(lerpedQuat, skel->bones[i].rotation); #if defined(REFBONE_NAMES) Q_strncpyz(skel->bones[i].name, refBone->name, sizeof(skel->bones[i].name)); #endif // calculate absolute values for the bounding box approximation VectorCopy(skel->bones[i].origin, skeleton.bones[i].origin); quat_copy(skel->bones[i].rotation, skeleton.bones[i].rotation); if (refBone->parentIndex >= 0) { vec3_t rotated; quat_t quat; refBone_t *bone = &skeleton.bones[i]; refBone_t *parent = &skeleton.bones[refBone->parentIndex]; QuatTransformVector(parent->rotation, bone->origin, rotated); VectorAdd(parent->origin, rotated, bone->origin); QuatMultiply1(parent->rotation, bone->rotation, quat); quat_copy(quat, bone->rotation); AddPointToBounds(bone->origin, skel->bounds[0], skel->bounds[1]); } } skel->numBones = anim->info.numBones; skel->type = SK_RELATIVE; return qtrue; } //Ren_Warning( "RE_BuildSkeleton: bad animation '%s' with handle %i\n", anim->name, hAnim); // FIXME: clear existing bones and bounds? return qfalse; }
QuatP* qslerp(const Quat qa, Quat qb, float t) { quat_slerp(qa, qb, t, qb); return qb; }