static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args) { PyObject *value; float tquat[QUAT_SIZE], quat[QUAT_SIZE], fac; if (!PyArg_ParseTuple(args, "Of:slerp", &value, &fac)) { PyErr_SetString(PyExc_TypeError, "quat.slerp(): " "expected Quaternion types and float"); return NULL; } if (BaseMath_ReadCallback(self) == -1) return NULL; if (mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "Quaternion.slerp(other), invalid 'other' arg") == -1) { return NULL; } if (fac > 1.0f || fac < 0.0f) { PyErr_SetString(PyExc_ValueError, "quat.slerp(): " "interpolation factor must be between 0.0 and 1.0"); return NULL; } interp_qt_qtqt(quat, self->quat, tquat, fac); return Quaternion_CreatePyObject(quat, Py_NEW, Py_TYPE(self)); }
/* Only allowed for Poses with identical channels */ static void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode) { bPoseChannel *dchan; const bPoseChannel *schan; bConstraint *dcon, *scon; float dstweight; int i; if (mode == BL_Action::ACT_BLEND_BLEND) { dstweight = 1.0f - srcweight; } else if (mode == BL_Action::ACT_BLEND_ADD) { dstweight = 1.0f; } else { dstweight = 1.0f; } schan= (bPoseChannel *)src->chanbase.first; for (dchan = (bPoseChannel *)dst->chanbase.first; dchan; dchan=(bPoseChannel *)dchan->next, schan= (bPoseChannel *)schan->next) { // always blend on all channels since we don't know which one has been set /* quat interpolation done separate */ if (schan->rotmode == ROT_MODE_QUAT) { float dquat[4], squat[4]; copy_qt_qt(dquat, dchan->quat); copy_qt_qt(squat, schan->quat); if (mode==BL_Action::ACT_BLEND_BLEND) interp_qt_qtqt(dchan->quat, dquat, squat, srcweight); else { mul_fac_qt_fl(squat, srcweight); mul_qt_qtqt(dchan->quat, dquat, squat); } normalize_qt(dchan->quat); } for (i=0; i<3; i++) { /* blending for loc and scale are pretty self-explanatory... */ dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight); dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight); /* euler-rotation interpolation done here instead... */ // FIXME: are these results decent? if (schan->rotmode) dchan->eul[i] = (dchan->eul[i]*dstweight) + (schan->eul[i]*srcweight); } for (dcon= (bConstraint *)dchan->constraints.first, scon= (bConstraint *)schan->constraints.first; dcon && scon; dcon = dcon->next, scon = scon->next) { /* no 'add' option for constraint blending */ dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight; } } /* this pose is now in src time */ dst->ctime= src->ctime; }
static void rotateBevelPiece(Curve *cu, BevPoint *bevp, BevPoint *nbevp, DispList *dlb, float bev_blend, float widfac, float fac, float **r_data) { float *fp, *data = *r_data; int b; fp = dlb->verts; for (b = 0; b < dlb->nr; b++, fp += 3, data += 3) { if (cu->flag & CU_3D) { float vec[3], quat[4]; vec[0] = fp[1] + widfac; vec[1] = fp[2]; vec[2] = 0.0; if (nbevp == NULL) { copy_v3_v3(data, bevp->vec); copy_qt_qt(quat, bevp->quat); } else { interp_v3_v3v3(data, bevp->vec, nbevp->vec, bev_blend); interp_qt_qtqt(quat, bevp->quat, nbevp->quat, bev_blend); } mul_qt_v3(quat, vec); data[0] += fac * vec[0]; data[1] += fac * vec[1]; data[2] += fac * vec[2]; } else { float sina, cosa; if (nbevp == NULL) { copy_v3_v3(data, bevp->vec); sina = bevp->sina; cosa = bevp->cosa; } else { interp_v3_v3v3(data, bevp->vec, nbevp->vec, bev_blend); /* perhaps we need to interpolate angles instead. but the thing is * cosa and sina are not actually sine and cosine */ sina = nbevp->sina * bev_blend + bevp->sina * (1.0f - bev_blend); cosa = nbevp->cosa * bev_blend + bevp->cosa * (1.0f - bev_blend); } data[0] += fac * (widfac + fp[1]) * sina; data[1] += fac * (widfac + fp[1]) * cosa; data[2] += fac * fp[2]; } } *r_data = data; }
/* called from within the core BKE_pose_where_is loop, all animsystems and constraints * were executed & assigned. Now as last we do an IK pass */ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree) { float R_parmat[3][3], identity[3][3]; float iR_parmat[3][3]; float R_bonemat[3][3]; float goalrot[3][3], goalpos[3]; float rootmat[4][4], imat[4][4]; float goal[4][4], goalinv[4][4]; float irest_basis[3][3], full_basis[3][3]; float end_pose[4][4], world_pose[4][4]; float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch = NULL; float resultinf = 0.0f; int a, flag, hasstretch = 0, resultblend = 0; bPoseChannel *pchan; IK_Segment *seg, *parent, **iktree, *iktarget; IK_Solver *solver; PoseTarget *target; bKinematicConstraint *data, *poleangledata = NULL; Bone *bone; if (tree->totchannel == 0) return; iktree = MEM_mallocN(sizeof(void *) * tree->totchannel, "ik tree"); for (a = 0; a < tree->totchannel; a++) { pchan = tree->pchan[a]; bone = pchan->bone; /* set DoF flag */ flag = 0; if (!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP)) flag |= IK_XDOF; if (!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP)) flag |= IK_YDOF; if (!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP)) flag |= IK_ZDOF; if (tree->stretch && (pchan->ikstretch > 0.0f)) { flag |= IK_TRANS_YDOF; hasstretch = 1; } seg = iktree[a] = IK_CreateSegment(flag); /* find parent */ if (a == 0) parent = NULL; else parent = iktree[tree->parent[a]]; IK_SetParent(seg, parent); /* get the matrix that transforms from prevbone into this bone */ copy_m3_m4(R_bonemat, pchan->pose_mat); /* gather transformations for this IK segment */ if (pchan->parent) copy_m3_m4(R_parmat, pchan->parent->pose_mat); else unit_m3(R_parmat); /* bone offset */ if (pchan->parent && (a > 0)) sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail); else /* only root bone (a = 0) has no parent */ start[0] = start[1] = start[2] = 0.0f; /* change length based on bone size */ length = bone->length * len_v3(R_bonemat[1]); /* compute rest basis and its inverse */ copy_m3_m3(rest_basis, bone->bone_mat); copy_m3_m3(irest_basis, bone->bone_mat); transpose_m3(irest_basis); /* compute basis with rest_basis removed */ invert_m3_m3(iR_parmat, R_parmat); mul_m3_m3m3(full_basis, iR_parmat, R_bonemat); mul_m3_m3m3(basis, irest_basis, full_basis); /* basis must be pure rotation */ normalize_m3(basis); /* transform offset into local bone space */ normalize_m3(iR_parmat); mul_m3_v3(iR_parmat, start); IK_SetTransform(seg, start, rest_basis, basis, length); if (pchan->ikflag & BONE_IK_XLIMIT) IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]); if (pchan->ikflag & BONE_IK_YLIMIT) IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]); if (pchan->ikflag & BONE_IK_ZLIMIT) IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]); IK_SetStiffness(seg, IK_X, pchan->stiffness[0]); IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]); IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]); if (tree->stretch && (pchan->ikstretch > 0.0f)) { const float ikstretch = pchan->ikstretch * pchan->ikstretch; /* this function does its own clamping */ IK_SetStiffness(seg, IK_TRANS_Y, 1.0f - ikstretch); IK_SetLimit(seg, IK_TRANS_Y, IK_STRETCH_STIFF_MIN, IK_STRETCH_STIFF_MAX); } } solver = IK_CreateSolver(iktree[0]); /* set solver goals */ /* first set the goal inverse transform, assuming the root of tree was done ok! */ pchan = tree->pchan[0]; if (pchan->parent) { /* transform goal by parent mat, so this rotation is not part of the * segment's basis. otherwise rotation limits do not work on the * local transform of the segment itself. */ copy_m4_m4(rootmat, pchan->parent->pose_mat); /* However, we do not want to get (i.e. reverse) parent's scale, as it generates [#31008] * kind of nasty bugs... */ normalize_m4(rootmat); } else unit_m4(rootmat); copy_v3_v3(rootmat[3], pchan->pose_head); mul_m4_m4m4(imat, ob->obmat, rootmat); invert_m4_m4(goalinv, imat); for (target = tree->targets.first; target; target = target->next) { float polepos[3]; int poleconstrain = 0; data = (bKinematicConstraint *)target->con->data; /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though * strictly speaking, it is a posechannel) */ BKE_constraint_target_matrix_get(scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); /* and set and transform goal */ mul_m4_m4m4(goal, goalinv, rootmat); copy_v3_v3(goalpos, goal[3]); copy_m3_m4(goalrot, goal); normalize_m3(goalrot); /* same for pole vector target */ if (data->poletar) { BKE_constraint_target_matrix_get(scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0); if (data->flag & CONSTRAINT_IK_SETANGLE) { /* don't solve IK when we are setting the pole angle */ break; } else { mul_m4_m4m4(goal, goalinv, rootmat); copy_v3_v3(polepos, goal[3]); poleconstrain = 1; /* for pole targets, we blend the result of the ik solver * instead of the target position, otherwise we can't get * a smooth transition */ resultblend = 1; resultinf = target->con->enforce; if (data->flag & CONSTRAINT_IK_GETANGLE) { poleangledata = data; data->flag &= ~CONSTRAINT_IK_GETANGLE; } } } /* do we need blending? */ if (!resultblend && target->con->enforce != 1.0f) { float q1[4], q2[4], q[4]; float fac = target->con->enforce; float mfac = 1.0f - fac; pchan = tree->pchan[target->tip]; /* end effector in world space */ copy_m4_m4(end_pose, pchan->pose_mat); copy_v3_v3(end_pose[3], pchan->pose_tail); mul_serie_m4(world_pose, goalinv, ob->obmat, end_pose, NULL, NULL, NULL, NULL, NULL); /* blend position */ goalpos[0] = fac * goalpos[0] + mfac * world_pose[3][0]; goalpos[1] = fac * goalpos[1] + mfac * world_pose[3][1]; goalpos[2] = fac * goalpos[2] + mfac * world_pose[3][2]; /* blend rotation */ mat3_to_quat(q1, goalrot); mat4_to_quat(q2, world_pose); interp_qt_qtqt(q, q1, q2, mfac); quat_to_mat3(goalrot, q); } iktarget = iktree[target->tip]; if ((data->flag & CONSTRAINT_IK_POS) && data->weight != 0.0f) { if (poleconstrain) IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos, polepos, data->poleangle, (poleangledata == data)); IK_SolverAddGoal(solver, iktarget, goalpos, data->weight); } if ((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0f)) if ((data->flag & CONSTRAINT_IK_AUTO) == 0) IK_SolverAddGoalOrientation(solver, iktarget, goalrot, data->orientweight); } /* solve */ IK_Solve(solver, 0.0f, tree->iterations); if (poleangledata) poleangledata->poleangle = IK_SolverGetPoleAngle(solver); IK_FreeSolver(solver); /* gather basis changes */ tree->basis_change = MEM_mallocN(sizeof(float[3][3]) * tree->totchannel, "ik basis change"); if (hasstretch) ikstretch = MEM_mallocN(sizeof(float) * tree->totchannel, "ik stretch"); for (a = 0; a < tree->totchannel; a++) { IK_GetBasisChange(iktree[a], tree->basis_change[a]); if (hasstretch) { /* have to compensate for scaling received from parent */ float parentstretch, stretch; pchan = tree->pchan[a]; parentstretch = (tree->parent[a] >= 0) ? ikstretch[tree->parent[a]] : 1.0f; if (tree->stretch && (pchan->ikstretch > 0.0f)) { float trans[3], length; IK_GetTranslationChange(iktree[a], trans); length = pchan->bone->length * len_v3(pchan->pose_mat[1]); ikstretch[a] = (length == 0.0f) ? 1.0f : (trans[1] + length) / length; } else ikstretch[a] = 1.0; stretch = (parentstretch == 0.0f) ? 1.0f : ikstretch[a] / parentstretch; mul_v3_fl(tree->basis_change[a][0], stretch); mul_v3_fl(tree->basis_change[a][1], stretch); mul_v3_fl(tree->basis_change[a][2], stretch); } if (resultblend && resultinf != 1.0f) { unit_m3(identity); blend_m3_m3m3(tree->basis_change[a], identity, tree->basis_change[a], resultinf); } IK_FreeSegment(iktree[a]); } MEM_freeN(iktree); if (ikstretch) MEM_freeN(ikstretch); }
/* only meant for timer usage */ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = CTX_wm_region_view3d(C); struct SmoothView3DStore *sms = rv3d->sms; float step, step_inv; /* escape if not our timer */ if (rv3d->smooth_timer == NULL || rv3d->smooth_timer != event->customdata) return OPERATOR_PASS_THROUGH; if (sms->time_allowed != 0.0) step = (float)((rv3d->smooth_timer->duration) / sms->time_allowed); else step = 1.0f; /* end timer */ if (step >= 1.0f) { /* if we went to camera, store the original */ if (sms->to_camera) { rv3d->persp = RV3D_CAMOB; view3d_smooth_view_state_restore(&sms->org, v3d, rv3d); } else { view3d_smooth_view_state_restore(&sms->dst, v3d, rv3d); ED_view3d_camera_lock_sync(v3d, rv3d); ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); } if ((rv3d->viewlock & RV3D_LOCKED) == 0) { rv3d->view = sms->org_view; } MEM_freeN(rv3d->sms); rv3d->sms = NULL; WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer); rv3d->smooth_timer = NULL; rv3d->rflag &= ~RV3D_NAVIGATING; } else { /* ease in/out */ step = (3.0f * step * step - 2.0f * step * step * step); step_inv = 1.0f - step; interp_v3_v3v3(rv3d->ofs, sms->src.ofs, sms->dst.ofs, step); interp_qt_qtqt(rv3d->viewquat, sms->src.quat, sms->dst.quat, step); rv3d->dist = sms->dst.dist * step + sms->src.dist * step_inv; v3d->lens = sms->dst.lens * step + sms->src.lens * step_inv; ED_view3d_camera_lock_sync(v3d, rv3d); if (ED_screen_animation_playing(CTX_wm_manager(C))) { ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true); } } if (rv3d->viewlock & RV3D_BOXVIEW) view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C)); /* note: this doesn't work right because the v3d->lens is now used in ortho mode r51636, * when switching camera in quad-view the other ortho views would zoom & reset. * * For now only redraw all regions when smoothview finishes. */ if (step >= 1.0f) { WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); } else { ED_region_tag_redraw(CTX_wm_region(C)); } return OPERATOR_FINISHED; }
/* calculate the deformation implied by the curve path at a given parametric position, * and returns whether this operation succeeded. * * note: ctime is normalized range <0-1> * * returns OK: 1/0 */ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float quat[4], float *radius, float *weight) { Curve *cu; Nurb *nu; BevList *bl; Path *path; PathPoint *pp, *p0, *p1, *p2, *p3; float fac; float data[4]; int cycl=0, s0, s1, s2, s3; if (ob==NULL || ob->type != OB_CURVE) return 0; cu= ob->data; if (cu->path==NULL || cu->path->data==NULL) { printf("no path!\n"); return 0; } path= cu->path; pp= path->data; /* test for cyclic */ bl= cu->bev.first; if (!bl) return 0; if (!bl->nr) return 0; if (bl->poly> -1) cycl= 1; ctime *= (path->len-1); s1= (int)floor(ctime); fac= (float)(s1+1)-ctime; /* path->len is corected for cyclic */ s0= interval_test(0, path->len-1-cycl, s1-1, cycl); s1= interval_test(0, path->len-1-cycl, s1, cycl); s2= interval_test(0, path->len-1-cycl, s1+1, cycl); s3= interval_test(0, path->len-1-cycl, s1+2, cycl); p0= pp + s0; p1= pp + s1; p2= pp + s2; p3= pp + s3; /* note, commented out for follow constraint */ //if (cu->flag & CU_FOLLOW) { key_curve_tangent_weights(1.0f-fac, data, KEY_BSPLINE); interp_v3_v3v3v3v3(dir, p0->vec, p1->vec, p2->vec, p3->vec, data); /* make compatible with vectoquat */ negate_v3(dir); //} nu= cu->nurb.first; /* make sure that first and last frame are included in the vectors here */ if (nu->type == CU_POLY) key_curve_position_weights(1.0f-fac, data, KEY_LINEAR); else if (nu->type == CU_BEZIER) key_curve_position_weights(1.0f-fac, data, KEY_LINEAR); else if (s0==s1 || p2==p3) key_curve_position_weights(1.0f-fac, data, KEY_CARDINAL); else key_curve_position_weights(1.0f-fac, data, KEY_BSPLINE); vec[0]= data[0]*p0->vec[0] + data[1]*p1->vec[0] + data[2]*p2->vec[0] + data[3]*p3->vec[0] ; /* X */ vec[1]= data[0]*p0->vec[1] + data[1]*p1->vec[1] + data[2]*p2->vec[1] + data[3]*p3->vec[1] ; /* Y */ vec[2]= data[0]*p0->vec[2] + data[1]*p1->vec[2] + data[2]*p2->vec[2] + data[3]*p3->vec[2] ; /* Z */ vec[3]= data[0]*p0->vec[3] + data[1]*p1->vec[3] + data[2]*p2->vec[3] + data[3]*p3->vec[3] ; /* Tilt, should not be needed since we have quat still used */ if (quat) { float totfac, q1[4], q2[4]; totfac= data[0]+data[3]; if (totfac>FLT_EPSILON) interp_qt_qtqt(q1, p0->quat, p3->quat, data[3] / totfac); else copy_qt_qt(q1, p1->quat); totfac= data[1]+data[2]; if (totfac>FLT_EPSILON) interp_qt_qtqt(q2, p1->quat, p2->quat, data[2] / totfac); else copy_qt_qt(q2, p3->quat); totfac = data[0]+data[1]+data[2]+data[3]; if (totfac>FLT_EPSILON) interp_qt_qtqt(quat, q1, q2, (data[1]+data[2]) / totfac); else copy_qt_qt(quat, q2); } if (radius) *radius= data[0]*p0->radius + data[1]*p1->radius + data[2]*p2->radius + data[3]*p3->radius; if (weight) *weight= data[0]*p0->weight + data[1]*p1->weight + data[2]*p2->weight + data[3]*p3->weight; return 1; }
/* calculate a curve-deform path for a curve * - only called from displist.c -> do_makeDispListCurveTypes */ void calc_curvepath(Object *ob) { BevList *bl; BevPoint *bevp, *bevpn, *bevpfirst, *bevplast; PathPoint *pp; Curve *cu; Nurb *nu; Path *path; float *fp, *dist, *maxdist, xyz[3]; float fac, d=0, fac1, fac2; int a, tot, cycl=0; ListBase *nurbs; /* in a path vertices are with equal differences: path->len = number of verts */ /* NOW WITH BEVELCURVE!!! */ if (ob==NULL || ob->type != OB_CURVE) return; cu= ob->data; nurbs= BKE_curve_nurbs(cu); nu= nurbs->first; if (cu->path) free_path(cu->path); cu->path= NULL; bl= cu->bev.first; if (bl==NULL || !bl->nr) return; cu->path=path= MEM_callocN(sizeof(Path), "calc_curvepath"); /* if POLY: last vertice != first vertice */ cycl= (bl->poly!= -1); if (cycl) tot= bl->nr; else tot= bl->nr-1; path->len= tot+1; /* exception: vector handle paths and polygon paths should be subdivided at least a factor resolu */ if (path->len<nu->resolu*SEGMENTSU(nu)) path->len= nu->resolu*SEGMENTSU(nu); dist= (float *)MEM_mallocN((tot+1)*4, "calcpathdist"); /* all lengths in *dist */ bevp= bevpfirst= (BevPoint *)(bl+1); fp= dist; *fp= 0; for (a=0; a<tot; a++) { fp++; if (cycl && a==tot-1) sub_v3_v3v3(xyz, bevpfirst->vec, bevp->vec); else sub_v3_v3v3(xyz, (bevp+1)->vec, bevp->vec); *fp= *(fp-1)+len_v3(xyz); bevp++; } path->totdist= *fp; /* the path verts in path->data */ /* now also with TILT value */ pp= path->data = (PathPoint *)MEM_callocN(sizeof(PathPoint)*path->len, "pathdata"); bevp= bevpfirst; bevpn= bevp+1; bevplast= bevpfirst + (bl->nr-1); fp= dist+1; maxdist= dist+tot; fac= 1.0f/((float)path->len-1.0f); fac = fac * path->totdist; for (a=0; a<path->len; a++) { d= ((float)a)*fac; /* we're looking for location (distance) 'd' in the array */ while ((d>= *fp) && fp<maxdist) { fp++; if (bevp<bevplast) bevp++; bevpn= bevp+1; if (bevpn>bevplast) { if (cycl) bevpn= bevpfirst; else bevpn= bevplast; } } fac1= *(fp)- *(fp-1); fac2= *(fp)-d; fac1= fac2/fac1; fac2= 1.0f-fac1; interp_v3_v3v3(pp->vec, bevp->vec, bevpn->vec, fac2); pp->vec[3]= fac1*bevp->alfa + fac2*bevpn->alfa; pp->radius= fac1*bevp->radius + fac2*bevpn->radius; pp->weight= fac1*bevp->weight + fac2*bevpn->weight; interp_qt_qtqt(pp->quat, bevp->quat, bevpn->quat, fac2); normalize_qt(pp->quat); pp++; } MEM_freeN(dist); }
/* only meant for timer usage */ static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) { View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d= CTX_wm_region_view3d(C); struct SmoothViewStore *sms= rv3d->sms; float step, step_inv; /* escape if not our timer */ if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata) return OPERATOR_PASS_THROUGH; if(sms->time_allowed != 0.0) step = (float)((rv3d->smooth_timer->duration)/sms->time_allowed); else step = 1.0f; /* end timer */ if(step >= 1.0f) { /* if we went to camera, store the original */ if(sms->to_camera) { rv3d->persp= RV3D_CAMOB; copy_v3_v3(rv3d->ofs, sms->orig_ofs); copy_qt_qt(rv3d->viewquat, sms->orig_quat); rv3d->dist = sms->orig_dist; v3d->lens = sms->orig_lens; } else { copy_v3_v3(rv3d->ofs, sms->new_ofs); copy_qt_qt(rv3d->viewquat, sms->new_quat); rv3d->dist = sms->new_dist; v3d->lens = sms->new_lens; ED_view3d_camera_lock_sync(v3d, rv3d); } if((rv3d->viewlock & RV3D_LOCKED)==0) { rv3d->view= sms->orig_view; } MEM_freeN(rv3d->sms); rv3d->sms= NULL; WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer); rv3d->smooth_timer= NULL; rv3d->rflag &= ~RV3D_NAVIGATING; } else { int i; /* ease in/out */ if (step < 0.5f) step = (float)pow(step*2.0f, 2.0)/2.0f; else step = (float)1.0f-(powf(2.0f*(1.0f-step),2.0f)/2.0f); step_inv = 1.0f-step; for (i=0; i<3; i++) rv3d->ofs[i] = sms->new_ofs[i] * step + sms->orig_ofs[i]*step_inv; interp_qt_qtqt(rv3d->viewquat, sms->orig_quat, sms->new_quat, step); rv3d->dist = sms->new_dist * step + sms->orig_dist*step_inv; v3d->lens = sms->new_lens * step + sms->orig_lens*step_inv; ED_view3d_camera_lock_sync(v3d, rv3d); } if(rv3d->viewlock & RV3D_BOXVIEW) view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C)); WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d); return OPERATOR_FINISHED; }
/* 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); }
static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, const float parent_orco[3], ChildParticle *cpa, const float orco[3], float hairmat[4][4], ParticleCacheKey *keys, ParticleCacheKey *parent_keys, int *r_totkeys, float *r_max_length) { struct ParticleSettings *part = ctx->sim.psys->part; const int seed = ctx->sim.psys->child_seed + (int)(cpa - ctx->sim.psys->child); const int totkeys = ctx->segments + 1; const int extrakeys = ctx->extra_segments; float kink_amp_random = part->kink_amp_random; float kink_amp = part->kink_amp * (1.0f - kink_amp_random * psys_frand(ctx->sim.psys, 93541 + seed)); float kink_freq = part->kink_freq; float kink_shape = part->kink_shape; float kink_axis_random = part->kink_axis_random; float rough1 = part->rough1; float rough2 = part->rough2; float rough_end = part->rough_end; ParticlePathIterator iter; ParticleCacheKey *key; int k; float dir[3]; float spiral_start[3] = {0.0f, 0.0f, 0.0f}; float spiral_start_time = 0.0f; float spiral_par_co[3] = {0.0f, 0.0f, 0.0f}; float spiral_par_vel[3] = {0.0f, 0.0f, 0.0f}; float spiral_par_rot[4] = {1.0f, 0.0f, 0.0f, 0.0f}; float totlen; float cut_time; int start_index = 0, end_index = 0; float kink_base[3]; if (ptex) { kink_amp *= ptex->kink_amp; kink_freq *= ptex->kink_freq; rough1 *= ptex->rough1; rough2 *= ptex->rough2; rough_end *= ptex->roughe; } cut_time = (totkeys - 1) * ptex->length; zero_v3(spiral_start); for (k = 0, key = keys; k < totkeys-1; k++, key++) { if ((float)(k + 1) >= cut_time) { float fac = cut_time - (float)k; ParticleCacheKey *par = parent_keys + k; start_index = k + 1; end_index = start_index + extrakeys; spiral_start_time = ((float)k + fac) / (float)(totkeys - 1); interp_v3_v3v3(spiral_start, key->co, (key+1)->co, fac); interp_v3_v3v3(spiral_par_co, par->co, (par+1)->co, fac); interp_v3_v3v3(spiral_par_vel, par->vel, (par+1)->vel, fac); interp_qt_qtqt(spiral_par_rot, par->rot, (par+1)->rot, fac); break; } } zero_v3(dir); zero_v3(kink_base); kink_base[part->kink_axis] = 1.0f; mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base); /* Fill in invariant part of modifier context. */ ParticleChildModifierContext modifier_ctx = {NULL}; modifier_ctx.thread_ctx = ctx; modifier_ctx.sim = &ctx->sim; modifier_ctx.ptex = ptex; modifier_ctx.cpa = cpa; modifier_ctx.orco = orco; modifier_ctx.parent_keys = parent_keys; for (k = 0, key = keys; k < end_index; k++, key++) { float par_time; float *par_co, *par_vel, *par_rot; psys_path_iter_get(&iter, keys, end_index, NULL, k); if (k < start_index) { sub_v3_v3v3(dir, (key+1)->co, key->co); normalize_v3(dir); par_time = (float)k / (float)(totkeys - 1); par_co = parent_keys[k].co; par_vel = parent_keys[k].vel; par_rot = parent_keys[k].rot; } else { float spiral_time = (float)(k - start_index) / (float)(extrakeys-1); float kink[3], tmp[3]; /* use same time value for every point on the spiral */ par_time = spiral_start_time; par_co = spiral_par_co; par_vel = spiral_par_vel; par_rot = spiral_par_rot; project_v3_v3v3(tmp, kink_base, dir); sub_v3_v3v3(kink, kink_base, tmp); normalize_v3(kink); if (kink_axis_random > 0.0f) { float a = kink_axis_random * (psys_frand(ctx->sim.psys, 7112 + seed) * 2.0f - 1.0f) * (float)M_PI; float rot[3][3]; axis_angle_normalized_to_mat3(rot, dir, a); mul_m3_v3(rot, kink); } do_kink_spiral_deform((ParticleKey *)key, dir, kink, spiral_time, kink_freq, kink_shape, kink_amp, spiral_start); } /* Fill in variant part of modifier context. */ modifier_ctx.par_co = par_co; modifier_ctx.par_vel = par_vel; modifier_ctx.par_rot = par_rot; modifier_ctx.par_orco = parent_orco; /* Apply different deformations to the child path/ */ do_child_modifiers(&modifier_ctx, hairmat, (ParticleKey *)key, par_time); } totlen = 0.0f; for (k = 0, key = keys; k < end_index-1; k++, key++) totlen += len_v3v3((key+1)->co, key->co); *r_totkeys = end_index; *r_max_length = totlen; }