//------------------------NUMERIC PROTOCOLS---------------------- //------------------------obj + obj------------------------------ //addition static PyObject *Quaternion_add(PyObject *q1, PyObject *q2) { float quat[QUAT_SIZE]; QuaternionObject *quat1 = NULL, *quat2 = NULL; if (!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) { PyErr_Format(PyExc_TypeError, "Quaternion addition: (%s + %s) " "invalid type for this operation", Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name); return NULL; } quat1 = (QuaternionObject *)q1; quat2 = (QuaternionObject *)q2; if (BaseMath_ReadCallback(quat1) == -1 || BaseMath_ReadCallback(quat2) == -1) return NULL; add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f); return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(q1)); }
/* helper for apply() - perform sliding for quaternion rotations (using quat blending) */ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) { FCurve *fcu_w = NULL, *fcu_x = NULL, *fcu_y = NULL, *fcu_z = NULL; bPoseChannel *pchan = pfl->pchan; LinkData *ld = NULL; char *path = NULL; float cframe; /* get the path to use - this should be quaternion rotations only (needs care) */ path = BLI_sprintfN("%s.%s", pfl->pchan_path, "rotation_quaternion"); /* get the current frame number */ cframe = (float)pso->cframe; /* using this path, find each matching F-Curve for the variables we're interested in */ while ( (ld = poseAnim_mapping_getNextFCurve(&pfl->fcurves, ld, path)) ) { FCurve *fcu = (FCurve *)ld->data; /* assign this F-Curve to one of the relevant pointers... */ switch (fcu->array_index) { case 3: /* z */ fcu_z = fcu; break; case 2: /* y */ fcu_y = fcu; break; case 1: /* x */ fcu_x = fcu; break; case 0: /* w */ fcu_w = fcu; break; } } /* only if all channels exist, proceed */ if (fcu_w && fcu_x && fcu_y && fcu_z) { float quat_prev[4], quat_next[4]; /* get 2 quats */ quat_prev[0] = evaluate_fcurve(fcu_w, pso->prevFrame); quat_prev[1] = evaluate_fcurve(fcu_x, pso->prevFrame); quat_prev[2] = evaluate_fcurve(fcu_y, pso->prevFrame); quat_prev[3] = evaluate_fcurve(fcu_z, pso->prevFrame); quat_next[0] = evaluate_fcurve(fcu_w, pso->nextFrame); quat_next[1] = evaluate_fcurve(fcu_x, pso->nextFrame); quat_next[2] = evaluate_fcurve(fcu_y, pso->nextFrame); quat_next[3] = evaluate_fcurve(fcu_z, pso->nextFrame); /* perform blending */ if (pso->mode == POSESLIDE_BREAKDOWN) { /* just perform the interpol between quat_prev and quat_next using pso->percentage as a guide */ interp_qt_qtqt(pchan->quat, quat_prev, quat_next, pso->percentage); } else if (pso->mode == POSESLIDE_PUSH) { float quat_diff[4], quat_orig[4]; /* calculate the delta transform from the previous to the current */ /* TODO: investigate ways to favour one transform more? */ sub_qt_qtqt(quat_diff, pchan->quat, quat_prev); /* make a copy of the original rotation */ copy_qt_qt(quat_orig, pchan->quat); /* increase the original by the delta transform, by an amount determined by percentage */ add_qt_qtqt(pchan->quat, quat_orig, quat_diff, pso->percentage); } else { float quat_interp[4], quat_orig[4]; int iters = (int)ceil(10.0f * pso->percentage); /* TODO: maybe a sensitivity ctrl on top of this is needed */ /* perform this blending several times until a satisfactory result is reached */ while (iters-- > 0) { /* calculate the interpolation between the endpoints */ interp_qt_qtqt(quat_interp, quat_prev, quat_next, (cframe - pso->prevFrame) / (pso->nextFrame - pso->prevFrame)); /* make a copy of the original rotation */ copy_qt_qt(quat_orig, pchan->quat); /* tricky interpolations - blending between original and new */ interp_qt_qtqt(pchan->quat, quat_orig, quat_interp, 1.0f / 6.0f); } } } /* free the path now */ MEM_freeN(path); }