|
Blender
V2.59
|
00001 /* 00002 * $Id: action.c 37512 2011-06-15 14:06:25Z campbellbarton $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00021 * All rights reserved. 00022 * 00023 * Contributor(s): Full recode, Ton Roosendaal, Crete 2005 00024 * Full recode, Joshua Leung, 2009 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00034 #include <string.h> 00035 #include <math.h> 00036 #include <stdlib.h> 00037 #include <stddef.h> 00038 00039 #include "MEM_guardedalloc.h" 00040 00041 #include "DNA_anim_types.h" 00042 #include "DNA_armature_types.h" 00043 #include "DNA_constraint_types.h" 00044 #include "DNA_scene_types.h" 00045 #include "DNA_object_types.h" 00046 00047 #include "BLI_blenlib.h" 00048 #include "BLI_math.h" 00049 #include "BLI_utildefines.h" 00050 #include "BLI_ghash.h" 00051 00052 #include "BKE_animsys.h" 00053 #include "BKE_action.h" 00054 #include "BKE_anim.h" 00055 #include "BKE_constraint.h" 00056 #include "BKE_global.h" 00057 #include "BKE_fcurve.h" 00058 #include "BKE_library.h" 00059 #include "BKE_main.h" 00060 #include "BKE_object.h" 00061 00062 #include "BKE_idprop.h" 00063 00064 #include "BIK_api.h" 00065 00066 #include "RNA_access.h" 00067 00068 /* *********************** NOTE ON POSE AND ACTION ********************** 00069 00070 - Pose is the local (object level) component of armature. The current 00071 object pose is saved in files, and (will be) is presorted for dependency 00072 - Actions have fewer (or other) channels, and write data to a Pose 00073 - Currently ob->pose data is controlled in where_is_pose only. The (recalc) 00074 event system takes care of calling that 00075 - The NLA system (here too) uses Poses as interpolation format for Actions 00076 - Therefore we assume poses to be static, and duplicates of poses have channels in 00077 same order, for quick interpolation reasons 00078 00079 ****************************** (ton) ************************************ */ 00080 00081 /* ***************** Library data level operations on action ************** */ 00082 00083 bAction *add_empty_action(const char name[]) 00084 { 00085 bAction *act; 00086 00087 act= alloc_libblock(&G.main->action, ID_AC, name); 00088 act->id.flag |= LIB_FAKEUSER; // XXX this is nasty for new users... maybe we don't want this anymore 00089 act->id.us++; 00090 00091 return act; 00092 } 00093 00094 // does copy_fcurve... 00095 void make_local_action(bAction *act) 00096 { 00097 // Object *ob; 00098 Main *bmain= G.main; 00099 bAction *actn; 00100 int local=0, lib=0; 00101 00102 if (act->id.lib==NULL) return; 00103 if (act->id.us==1) { 00104 act->id.lib= NULL; 00105 act->id.flag= LIB_LOCAL; 00106 new_id(&bmain->action, (ID *)act, NULL); 00107 return; 00108 } 00109 00110 #if 0 // XXX old animation system 00111 ob= G.main->object.first; 00112 while(ob) { 00113 if(ob->action==act) { 00114 if(ob->id.lib) lib= 1; 00115 else local= 1; 00116 } 00117 ob= ob->id.next; 00118 } 00119 #endif 00120 00121 if(local && lib==0) { 00122 act->id.lib= NULL; 00123 act->id.flag= LIB_LOCAL; 00124 //make_local_action_channels(act); 00125 new_id(&bmain->action, (ID *)act, NULL); 00126 } 00127 else if(local && lib) { 00128 actn= copy_action(act); 00129 actn->id.us= 0; 00130 00131 #if 0 // XXX old animation system 00132 ob= G.main->object.first; 00133 while(ob) { 00134 if(ob->action==act) { 00135 00136 if(ob->id.lib==0) { 00137 ob->action = actn; 00138 actn->id.us++; 00139 act->id.us--; 00140 } 00141 } 00142 ob= ob->id.next; 00143 } 00144 #endif // XXX old animation system 00145 } 00146 } 00147 00148 void free_action (bAction *act) 00149 { 00150 /* sanity check */ 00151 if (act == NULL) 00152 return; 00153 00154 /* Free F-Curves */ 00155 free_fcurves(&act->curves); 00156 00157 /* Free groups */ 00158 if (act->groups.first) 00159 BLI_freelistN(&act->groups); 00160 00161 /* Free pose-references (aka local markers) */ 00162 if (act->markers.first) 00163 BLI_freelistN(&act->markers); 00164 } 00165 00166 bAction *copy_action (bAction *src) 00167 { 00168 bAction *dst = NULL; 00169 bActionGroup *dgrp, *sgrp; 00170 FCurve *dfcu, *sfcu; 00171 00172 if (src == NULL) 00173 return NULL; 00174 dst= copy_libblock(src); 00175 00176 /* duplicate the lists of groups and markers */ 00177 BLI_duplicatelist(&dst->groups, &src->groups); 00178 BLI_duplicatelist(&dst->markers, &src->markers); 00179 00180 /* copy F-Curves, fixing up the links as we go */ 00181 dst->curves.first= dst->curves.last= NULL; 00182 00183 for (sfcu= src->curves.first; sfcu; sfcu= sfcu->next) { 00184 /* duplicate F-Curve */ 00185 dfcu= copy_fcurve(sfcu); 00186 BLI_addtail(&dst->curves, dfcu); 00187 00188 /* fix group links (kindof bad list-in-list search, but this is the most reliable way) */ 00189 for (dgrp=dst->groups.first, sgrp=src->groups.first; dgrp && sgrp; dgrp=dgrp->next, sgrp=sgrp->next) { 00190 if (sfcu->grp == sgrp) { 00191 dfcu->grp= dgrp; 00192 00193 if (dgrp->channels.first == sfcu) 00194 dgrp->channels.first= dfcu; 00195 if (dgrp->channels.last == sfcu) 00196 dgrp->channels.last= dfcu; 00197 00198 break; 00199 } 00200 } 00201 } 00202 00203 dst->id.flag |= LIB_FAKEUSER; // XXX this is nasty for new users... maybe we don't want this anymore 00204 dst->id.us++; 00205 00206 return dst; 00207 } 00208 00209 /* *************** Action Groups *************** */ 00210 00211 /* Get the active action-group for an Action */ 00212 bActionGroup *get_active_actiongroup (bAction *act) 00213 { 00214 bActionGroup *agrp= NULL; 00215 00216 if (act && act->groups.first) { 00217 for (agrp= act->groups.first; agrp; agrp= agrp->next) { 00218 if (agrp->flag & AGRP_ACTIVE) 00219 break; 00220 } 00221 } 00222 00223 return agrp; 00224 } 00225 00226 /* Make the given Action-Group the active one */ 00227 void set_active_action_group (bAction *act, bActionGroup *agrp, short select) 00228 { 00229 bActionGroup *grp; 00230 00231 /* sanity checks */ 00232 if (act == NULL) 00233 return; 00234 00235 /* Deactive all others */ 00236 for (grp= act->groups.first; grp; grp= grp->next) { 00237 if ((grp==agrp) && (select)) 00238 grp->flag |= AGRP_ACTIVE; 00239 else 00240 grp->flag &= ~AGRP_ACTIVE; 00241 } 00242 } 00243 00244 /* Add a new action group with the given name to the action */ 00245 bActionGroup *action_groups_add_new (bAction *act, const char name[]) 00246 { 00247 bActionGroup *agrp; 00248 00249 /* sanity check: must have action and name */ 00250 if (ELEM(NULL, act, name)) 00251 return NULL; 00252 00253 /* allocate a new one */ 00254 agrp = MEM_callocN(sizeof(bActionGroup), "bActionGroup"); 00255 00256 /* make it selected, with default name */ 00257 agrp->flag = AGRP_SELECTED; 00258 strncpy(agrp->name, name[0] ? name : "Group", sizeof(agrp->name)); 00259 00260 /* add to action, and validate */ 00261 BLI_addtail(&act->groups, agrp); 00262 BLI_uniquename(&act->groups, agrp, "Group", '.', offsetof(bActionGroup, name), sizeof(agrp->name)); 00263 00264 /* return the new group */ 00265 return agrp; 00266 } 00267 00268 /* Add given channel into (active) group 00269 * - assumes that channel is not linked to anything anymore 00270 * - always adds at the end of the group 00271 */ 00272 void action_groups_add_channel (bAction *act, bActionGroup *agrp, FCurve *fcurve) 00273 { 00274 /* sanity checks */ 00275 if (ELEM3(NULL, act, agrp, fcurve)) 00276 return; 00277 00278 /* if no channels anywhere, just add to two lists at the same time */ 00279 if (act->curves.first == NULL) { 00280 fcurve->next = fcurve->prev = NULL; 00281 00282 agrp->channels.first = agrp->channels.last = fcurve; 00283 act->curves.first = act->curves.last = fcurve; 00284 } 00285 00286 /* if the group already has channels, the F-Curve can simply be added to the list 00287 * (i.e. as the last channel in the group) 00288 */ 00289 else if (agrp->channels.first) { 00290 /* if the group's last F-Curve is the action's last F-Curve too, 00291 * then set the F-Curve as the last for the action first so that 00292 * the lists will be in sync after linking 00293 */ 00294 if (agrp->channels.last == act->curves.last) 00295 act->curves.last= fcurve; 00296 00297 /* link in the given F-Curve after the last F-Curve in the group, 00298 * which means that it should be able to fit in with the rest of the 00299 * list seamlessly 00300 */ 00301 BLI_insertlinkafter(&agrp->channels, agrp->channels.last, fcurve); 00302 } 00303 00304 /* otherwise, need to find the nearest F-Curve in group before/after current to link with */ 00305 else { 00306 bActionGroup *grp; 00307 00308 /* firstly, link this F-Curve to the group */ 00309 agrp->channels.first = agrp->channels.last = fcurve; 00310 00311 /* step through the groups preceding this one, finding the F-Curve there to attach this one after */ 00312 for (grp= agrp->prev; grp; grp= grp->prev) { 00313 /* if this group has F-Curves, we want weave the given one in right after the last channel there, 00314 * but via the Action's list not this group's list 00315 * - this is so that the F-Curve is in the right place in the Action, 00316 * but won't be included in the previous group 00317 */ 00318 if (grp->channels.last) { 00319 /* once we've added, break here since we don't need to search any further... */ 00320 BLI_insertlinkafter(&act->curves, grp->channels.last, fcurve); 00321 break; 00322 } 00323 } 00324 00325 /* if grp is NULL, that means we fell through, and this F-Curve should be added as the new first 00326 * since group is (effectively) the first group. Thus, the existing first F-Curve becomes the 00327 * second in the chain, etc. etc. 00328 */ 00329 if (grp == NULL) 00330 BLI_insertlinkbefore(&act->curves, act->curves.first, fcurve); 00331 } 00332 00333 /* set the F-Curve's new group */ 00334 fcurve->grp= agrp; 00335 } 00336 00337 /* Remove the given channel from all groups */ 00338 void action_groups_remove_channel (bAction *act, FCurve *fcu) 00339 { 00340 /* sanity checks */ 00341 if (ELEM(NULL, act, fcu)) 00342 return; 00343 00344 /* check if any group used this directly */ 00345 if (fcu->grp) { 00346 bActionGroup *agrp= fcu->grp; 00347 00348 if (agrp->channels.first == agrp->channels.last) { 00349 if (agrp->channels.first == fcu) { 00350 agrp->channels.first= NULL; 00351 agrp->channels.last= NULL; 00352 } 00353 } 00354 else if (agrp->channels.first == fcu) { 00355 if ((fcu->next) && (fcu->next->grp==agrp)) 00356 agrp->channels.first= fcu->next; 00357 else 00358 agrp->channels.first= NULL; 00359 } 00360 else if (agrp->channels.last == fcu) { 00361 if ((fcu->prev) && (fcu->prev->grp==agrp)) 00362 agrp->channels.last= fcu->prev; 00363 else 00364 agrp->channels.last= NULL; 00365 } 00366 00367 fcu->grp= NULL; 00368 } 00369 00370 /* now just remove from list */ 00371 BLI_remlink(&act->curves, fcu); 00372 } 00373 00374 /* Find a group with the given name */ 00375 bActionGroup *action_groups_find_named (bAction *act, const char name[]) 00376 { 00377 /* sanity checks */ 00378 if (ELEM3(NULL, act, act->groups.first, name) || (name[0] == 0)) 00379 return NULL; 00380 00381 /* do string comparisons */ 00382 return BLI_findstring(&act->groups, name, offsetof(bActionGroup, name)); 00383 } 00384 00385 /* Clear all 'temp' flags on all groups */ 00386 void action_groups_clear_tempflags (bAction *act) 00387 { 00388 bActionGroup *agrp; 00389 00390 /* sanity checks */ 00391 if (ELEM(NULL, act, act->groups.first)) 00392 return; 00393 00394 /* flag clearing loop */ 00395 for (agrp = act->groups.first; agrp; agrp = agrp->next) 00396 agrp->flag &= ~AGRP_TEMP; 00397 } 00398 00399 /* *************** Pose channels *************** */ 00400 00401 /* usually used within a loop, so we got a N^2 slowdown */ 00402 bPoseChannel *get_pose_channel(const bPose *pose, const char *name) 00403 { 00404 if (ELEM(NULL, pose, name) || (name[0] == 0)) 00405 return NULL; 00406 00407 if(pose->chanhash) 00408 return BLI_ghash_lookup(pose->chanhash, (void *)name); 00409 00410 return BLI_findstring(&((bPose *)pose)->chanbase, name, offsetof(bPoseChannel, name)); 00411 } 00412 00413 /* Use with care, not on Armature poses but for temporal ones */ 00414 /* (currently used for action constraints and in rebuild_pose) */ 00415 bPoseChannel *verify_pose_channel(bPose *pose, const char *name) 00416 { 00417 bPoseChannel *chan; 00418 00419 if (pose == NULL) 00420 return NULL; 00421 00422 /* See if this channel exists */ 00423 chan= BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name)); 00424 if(chan) { 00425 return chan; 00426 } 00427 00428 /* If not, create it and add it */ 00429 chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel"); 00430 00431 BLI_strncpy(chan->name, name, sizeof(chan->name)); 00432 /* init vars to prevent math errors */ 00433 unit_qt(chan->quat); 00434 unit_axis_angle(chan->rotAxis, &chan->rotAngle); 00435 chan->size[0] = chan->size[1] = chan->size[2] = 1.0f; 00436 00437 chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f; 00438 chan->limitmax[0]= chan->limitmax[1]= chan->limitmax[2]= 180.0f; 00439 chan->stiffness[0]= chan->stiffness[1]= chan->stiffness[2]= 0.0f; 00440 chan->ikrotweight = chan->iklinweight = 0.0f; 00441 unit_m4(chan->constinv); 00442 00443 chan->protectflag = OB_LOCK_ROT4D; /* lock by components by default */ 00444 00445 BLI_addtail(&pose->chanbase, chan); 00446 free_pose_channels_hash(pose); 00447 00448 return chan; 00449 } 00450 00451 /* Find the active posechannel for an object (we can't just use pose, as layer info is in armature) */ 00452 bPoseChannel *get_active_posechannel (Object *ob) 00453 { 00454 bArmature *arm= (ob) ? ob->data : NULL; 00455 bPoseChannel *pchan; 00456 00457 if ELEM3(NULL, ob, ob->pose, arm) 00458 return NULL; 00459 00460 /* find active */ 00461 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { 00462 if ((pchan->bone) && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer)) 00463 return pchan; 00464 } 00465 00466 return NULL; 00467 } 00468 00469 const char *get_ikparam_name(bPose *pose) 00470 { 00471 if (pose) { 00472 switch (pose->iksolver) { 00473 case IKSOLVER_LEGACY: 00474 return NULL; 00475 case IKSOLVER_ITASC: 00476 return "bItasc"; 00477 } 00478 } 00479 return NULL; 00480 } 00481 /* dst should be freed already, makes entire duplicate */ 00482 void copy_pose (bPose **dst, bPose *src, int copycon) 00483 { 00484 bPose *outPose; 00485 bPoseChannel *pchan; 00486 ListBase listb; 00487 00488 if (!src) { 00489 *dst=NULL; 00490 return; 00491 } 00492 00493 if (*dst==src) { 00494 printf("copy_pose source and target are the same\n"); 00495 *dst=NULL; 00496 return; 00497 } 00498 00499 outPose= MEM_callocN(sizeof(bPose), "pose"); 00500 00501 BLI_duplicatelist(&outPose->chanbase, &src->chanbase); 00502 00503 outPose->iksolver = src->iksolver; 00504 outPose->ikdata = NULL; 00505 outPose->ikparam = MEM_dupallocN(src->ikparam); 00506 00507 for (pchan=outPose->chanbase.first; pchan; pchan=pchan->next) { 00508 // TODO: rename this argument... 00509 if (copycon) { 00510 copy_constraints(&listb, &pchan->constraints, TRUE); // copy_constraints NULLs listb 00511 pchan->constraints= listb; 00512 pchan->path= NULL; // XXX remove this line when the new motionpaths are ready... (depreceated code) 00513 pchan->mpath= NULL; /* motion paths should not get copied yet... */ 00514 } 00515 00516 if(pchan->prop) { 00517 pchan->prop= IDP_CopyProperty(pchan->prop); 00518 } 00519 } 00520 00521 /* for now, duplicate Bone Groups too when doing this */ 00522 if (copycon) 00523 BLI_duplicatelist(&outPose->agroups, &src->agroups); 00524 00525 *dst=outPose; 00526 } 00527 00528 void init_pose_itasc(bItasc *itasc) 00529 { 00530 if (itasc) { 00531 itasc->iksolver = IKSOLVER_ITASC; 00532 itasc->minstep = 0.01f; 00533 itasc->maxstep = 0.06f; 00534 itasc->numiter = 100; 00535 itasc->numstep = 4; 00536 itasc->precision = 0.005f; 00537 itasc->flag = ITASC_AUTO_STEP|ITASC_INITIAL_REITERATION; 00538 itasc->feedback = 20.f; 00539 itasc->maxvel = 50.f; 00540 itasc->solver = ITASC_SOLVER_SDLS; 00541 itasc->dampmax = 0.5; 00542 itasc->dampeps = 0.15; 00543 } 00544 } 00545 void init_pose_ikparam(bPose *pose) 00546 { 00547 bItasc *itasc; 00548 switch (pose->iksolver) { 00549 case IKSOLVER_ITASC: 00550 itasc = MEM_callocN(sizeof(bItasc), "itasc"); 00551 init_pose_itasc(itasc); 00552 pose->ikparam = itasc; 00553 break; 00554 case IKSOLVER_LEGACY: 00555 default: 00556 pose->ikparam = NULL; 00557 break; 00558 } 00559 } 00560 00561 void make_pose_channels_hash(bPose *pose) 00562 { 00563 if(!pose->chanhash) { 00564 bPoseChannel *pchan; 00565 00566 pose->chanhash= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "make_pose_chan gh"); 00567 for(pchan=pose->chanbase.first; pchan; pchan=pchan->next) 00568 BLI_ghash_insert(pose->chanhash, pchan->name, pchan); 00569 } 00570 } 00571 00572 void free_pose_channels_hash(bPose *pose) 00573 { 00574 if(pose->chanhash) { 00575 BLI_ghash_free(pose->chanhash, NULL, NULL); 00576 pose->chanhash= NULL; 00577 } 00578 } 00579 00580 00581 void free_pose_channel(bPoseChannel *pchan) 00582 { 00583 // XXX this case here will need to be removed when the new motionpaths are ready 00584 if (pchan->path) { 00585 MEM_freeN(pchan->path); 00586 pchan->path= NULL; 00587 } 00588 00589 if (pchan->mpath) { 00590 animviz_free_motionpath(pchan->mpath); 00591 pchan->mpath= NULL; 00592 } 00593 00594 free_constraints(&pchan->constraints); 00595 00596 if (pchan->prop) { 00597 IDP_FreeProperty(pchan->prop); 00598 MEM_freeN(pchan->prop); 00599 } 00600 } 00601 00602 void free_pose_channels(bPose *pose) 00603 { 00604 bPoseChannel *pchan; 00605 00606 if (pose->chanbase.first) { 00607 for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) 00608 free_pose_channel(pchan); 00609 00610 BLI_freelistN(&pose->chanbase); 00611 } 00612 00613 free_pose_channels_hash(pose); 00614 } 00615 00616 void free_pose(bPose *pose) 00617 { 00618 if (pose) { 00619 /* free pose-channels */ 00620 free_pose_channels(pose); 00621 00622 /* free pose-groups */ 00623 if (pose->agroups.first) 00624 BLI_freelistN(&pose->agroups); 00625 00626 /* free IK solver state */ 00627 BIK_clear_data(pose); 00628 00629 /* free IK solver param */ 00630 if (pose->ikparam) 00631 MEM_freeN(pose->ikparam); 00632 00633 /* free pose */ 00634 MEM_freeN(pose); 00635 } 00636 } 00637 00638 static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan) 00639 { 00640 bConstraint *pcon, *con; 00641 00642 VECCOPY(pchan->loc, chan->loc); 00643 VECCOPY(pchan->size, chan->size); 00644 VECCOPY(pchan->eul, chan->eul); 00645 VECCOPY(pchan->rotAxis, chan->rotAxis); 00646 pchan->rotAngle= chan->rotAngle; 00647 QUATCOPY(pchan->quat, chan->quat); 00648 pchan->rotmode= chan->rotmode; 00649 copy_m4_m4(pchan->chan_mat, (float(*)[4])chan->chan_mat); 00650 copy_m4_m4(pchan->pose_mat, (float(*)[4])chan->pose_mat); 00651 pchan->flag= chan->flag; 00652 00653 con= chan->constraints.first; 00654 for(pcon= pchan->constraints.first; pcon && con; pcon= pcon->next, con= con->next) { 00655 pcon->enforce= con->enforce; 00656 pcon->headtail= con->headtail; 00657 } 00658 } 00659 00660 /* makes copies of internal data, unlike copy_pose_channel_data which only 00661 * copies the pose state. 00662 * hint: use when copying bones in editmode (on returned value from verify_pose_channel) */ 00663 void duplicate_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *pchan_from) 00664 { 00665 /* copy transform locks */ 00666 pchan->protectflag = pchan_from->protectflag; 00667 00668 /* copy rotation mode */ 00669 pchan->rotmode = pchan_from->rotmode; 00670 00671 /* copy bone group */ 00672 pchan->agrp_index= pchan_from->agrp_index; 00673 00674 /* ik (dof) settings */ 00675 pchan->ikflag = pchan_from->ikflag; 00676 VECCOPY(pchan->limitmin, pchan_from->limitmin); 00677 VECCOPY(pchan->limitmax, pchan_from->limitmax); 00678 VECCOPY(pchan->stiffness, pchan_from->stiffness); 00679 pchan->ikstretch= pchan_from->ikstretch; 00680 pchan->ikrotweight= pchan_from->ikrotweight; 00681 pchan->iklinweight= pchan_from->iklinweight; 00682 00683 /* constraints */ 00684 copy_constraints(&pchan->constraints, &pchan_from->constraints, TRUE); 00685 00686 /* id-properties */ 00687 if(pchan->prop) { 00688 /* unlikely but possible it exists */ 00689 IDP_FreeProperty(pchan->prop); 00690 MEM_freeN(pchan->prop); 00691 pchan->prop= NULL; 00692 } 00693 if(pchan_from->prop) { 00694 pchan->prop= IDP_CopyProperty(pchan_from->prop); 00695 } 00696 00697 /* custom shape */ 00698 pchan->custom= pchan_from->custom; 00699 } 00700 00701 00702 /* checks for IK constraint, Spline IK, and also for Follow-Path constraint. 00703 * can do more constraints flags later 00704 */ 00705 /* pose should be entirely OK */ 00706 void update_pose_constraint_flags(bPose *pose) 00707 { 00708 bPoseChannel *pchan, *parchan; 00709 bConstraint *con; 00710 00711 /* clear */ 00712 for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { 00713 pchan->constflag= 0; 00714 } 00715 pose->flag &= ~POSE_CONSTRAINTS_TIMEDEPEND; 00716 00717 /* detect */ 00718 for (pchan= pose->chanbase.first; pchan; pchan=pchan->next) { 00719 for (con= pchan->constraints.first; con; con= con->next) { 00720 if (con->type==CONSTRAINT_TYPE_KINEMATIC) { 00721 bKinematicConstraint *data = (bKinematicConstraint*)con->data; 00722 00723 pchan->constflag |= PCHAN_HAS_IK; 00724 00725 if(data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]==0)) 00726 pchan->constflag |= PCHAN_HAS_TARGET; 00727 00728 /* negative rootbone = recalc rootbone index. used in do_versions */ 00729 if(data->rootbone<0) { 00730 data->rootbone= 0; 00731 00732 if(data->flag & CONSTRAINT_IK_TIP) parchan= pchan; 00733 else parchan= pchan->parent; 00734 00735 while(parchan) { 00736 data->rootbone++; 00737 if((parchan->bone->flag & BONE_CONNECTED)==0) 00738 break; 00739 parchan= parchan->parent; 00740 } 00741 } 00742 } 00743 else if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) { 00744 bFollowPathConstraint *data= (bFollowPathConstraint *)con->data; 00745 00746 /* for drawing constraint colors when color set allows this */ 00747 pchan->constflag |= PCHAN_HAS_CONST; 00748 00749 /* if we have a valid target, make sure that this will get updated on frame-change 00750 * (needed for when there is no anim-data for this pose) 00751 */ 00752 if ((data->tar) && (data->tar->type==OB_CURVE)) 00753 pose->flag |= POSE_CONSTRAINTS_TIMEDEPEND; 00754 } 00755 else if (con->type == CONSTRAINT_TYPE_SPLINEIK) 00756 pchan->constflag |= PCHAN_HAS_SPLINEIK; 00757 else 00758 pchan->constflag |= PCHAN_HAS_CONST; 00759 } 00760 } 00761 } 00762 00763 /* Clears all BONE_UNKEYED flags for every pose channel in every pose 00764 * This should only be called on frame changing, when it is acceptable to 00765 * do this. Otherwise, these flags should not get cleared as poses may get lost. 00766 */ 00767 void framechange_poses_clear_unkeyed(void) 00768 { 00769 Object *ob; 00770 bPose *pose; 00771 bPoseChannel *pchan; 00772 00773 /* This needs to be done for each object that has a pose */ 00774 // TODO: proxies may/may not be correctly handled here... (this needs checking) 00775 for (ob= G.main->object.first; ob; ob= ob->id.next) { 00776 /* we only need to do this on objects with a pose */ 00777 if ( (pose= ob->pose) ) { 00778 for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { 00779 if (pchan->bone) 00780 pchan->bone->flag &= ~BONE_UNKEYED; 00781 } 00782 } 00783 } 00784 } 00785 00786 /* ************************** Bone Groups ************************** */ 00787 00788 /* Adds a new bone-group */ 00789 void pose_add_group (Object *ob) 00790 { 00791 bPose *pose= (ob) ? ob->pose : NULL; 00792 bActionGroup *grp; 00793 00794 if (ELEM(NULL, ob, ob->pose)) 00795 return; 00796 00797 grp= MEM_callocN(sizeof(bActionGroup), "PoseGroup"); 00798 BLI_strncpy(grp->name, "Group", sizeof(grp->name)); 00799 BLI_addtail(&pose->agroups, grp); 00800 BLI_uniquename(&pose->agroups, grp, "Group", '.', offsetof(bActionGroup, name), sizeof(grp->name)); 00801 00802 pose->active_group= BLI_countlist(&pose->agroups); 00803 } 00804 00805 /* Remove the active bone-group */ 00806 void pose_remove_group (Object *ob) 00807 { 00808 bPose *pose= (ob) ? ob->pose : NULL; 00809 bActionGroup *grp = NULL; 00810 bPoseChannel *pchan; 00811 00812 /* sanity checks */ 00813 if (ELEM(NULL, ob, pose)) 00814 return; 00815 if (pose->active_group <= 0) 00816 return; 00817 00818 /* get group to remove */ 00819 grp= BLI_findlink(&pose->agroups, pose->active_group-1); 00820 if (grp) { 00821 /* adjust group references (the trouble of using indices!): 00822 * - firstly, make sure nothing references it 00823 * - also, make sure that those after this item get corrected 00824 */ 00825 for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) { 00826 if (pchan->agrp_index == pose->active_group) 00827 pchan->agrp_index= 0; 00828 else if (pchan->agrp_index > pose->active_group) 00829 pchan->agrp_index--; 00830 } 00831 00832 /* now, remove it from the pose */ 00833 BLI_freelinkN(&pose->agroups, grp); 00834 pose->active_group--; 00835 if(pose->active_group < 0 || pose->agroups.first == NULL) { 00836 pose->active_group= 0; 00837 } 00838 } 00839 } 00840 00841 /* ************** F-Curve Utilities for Actions ****************** */ 00842 00843 /* Check if the given action has any keyframes */ 00844 short action_has_motion(const bAction *act) 00845 { 00846 FCurve *fcu; 00847 00848 /* return on the first F-Curve that has some keyframes/samples defined */ 00849 if (act) { 00850 for (fcu= act->curves.first; fcu; fcu= fcu->next) { 00851 if (fcu->totvert) 00852 return 1; 00853 } 00854 } 00855 00856 /* nothing found */ 00857 return 0; 00858 } 00859 00860 /* Calculate the extents of given action */ 00861 void calc_action_range(const bAction *act, float *start, float *end, short incl_modifiers) 00862 { 00863 FCurve *fcu; 00864 float min=999999999.0f, max=-999999999.0f; 00865 short foundvert=0, foundmod=0; 00866 00867 if (act) { 00868 for (fcu= act->curves.first; fcu; fcu= fcu->next) { 00869 /* if curve has keyframes, consider them first */ 00870 if (fcu->totvert) { 00871 float nmin, nmax; 00872 00873 /* get extents for this curve */ 00874 // TODO: allow enabling/disabling this? 00875 calc_fcurve_range(fcu, &nmin, &nmax, FALSE); 00876 00877 /* compare to the running tally */ 00878 min= MIN2(min, nmin); 00879 max= MAX2(max, nmax); 00880 00881 foundvert= 1; 00882 } 00883 00884 /* if incl_modifiers is enabled, need to consider modifiers too 00885 * - only really care about the last modifier 00886 */ 00887 if ((incl_modifiers) && (fcu->modifiers.last)) { 00888 FModifier *fcm= fcu->modifiers.last; 00889 00890 /* only use the maximum sensible limits of the modifiers if they are more extreme */ 00891 switch (fcm->type) { 00892 case FMODIFIER_TYPE_LIMITS: /* Limits F-Modifier */ 00893 { 00894 FMod_Limits *fmd= (FMod_Limits *)fcm->data; 00895 00896 if (fmd->flag & FCM_LIMIT_XMIN) { 00897 min= MIN2(min, fmd->rect.xmin); 00898 } 00899 if (fmd->flag & FCM_LIMIT_XMAX) { 00900 max= MAX2(max, fmd->rect.xmax); 00901 } 00902 } 00903 break; 00904 00905 case FMODIFIER_TYPE_CYCLES: /* Cycles F-Modifier */ 00906 { 00907 FMod_Cycles *fmd= (FMod_Cycles *)fcm->data; 00908 00909 if (fmd->before_mode != FCM_EXTRAPOLATE_NONE) 00910 min= MINAFRAMEF; 00911 if (fmd->after_mode != FCM_EXTRAPOLATE_NONE) 00912 max= MAXFRAMEF; 00913 } 00914 break; 00915 00916 // TODO: function modifier may need some special limits 00917 00918 default: /* all other standard modifiers are on the infinite range... */ 00919 min= MINAFRAMEF; 00920 max= MAXFRAMEF; 00921 break; 00922 } 00923 00924 foundmod= 1; 00925 } 00926 } 00927 } 00928 00929 if (foundvert || foundmod) { 00930 if(min==max) max+= 1.0f; 00931 *start= min; 00932 *end= max; 00933 } 00934 else { 00935 *start= 0.0f; 00936 *end= 1.0f; 00937 } 00938 } 00939 00940 /* Return flags indicating which transforms the given object/posechannel has 00941 * - if 'curves' is provided, a list of links to these curves are also returned 00942 */ 00943 short action_get_item_transforms (bAction *act, Object *ob, bPoseChannel *pchan, ListBase *curves) 00944 { 00945 PointerRNA ptr; 00946 FCurve *fcu; 00947 char *basePath=NULL; 00948 short flags=0; 00949 00950 /* build PointerRNA from provided data to obtain the paths to use */ 00951 if (pchan) 00952 RNA_pointer_create((ID *)ob, &RNA_PoseBone, pchan, &ptr); 00953 else if (ob) 00954 RNA_id_pointer_create((ID *)ob, &ptr); 00955 else 00956 return 0; 00957 00958 /* get the basic path to the properties of interest */ 00959 basePath= RNA_path_from_ID_to_struct(&ptr); 00960 if (basePath == NULL) 00961 return 0; 00962 00963 /* search F-Curves for the given properties 00964 * - we cannot use the groups, since they may not be grouped in that way... 00965 */ 00966 for (fcu= act->curves.first; fcu; fcu= fcu->next) { 00967 char *bPtr=NULL, *pPtr=NULL; 00968 00969 /* if enough flags have been found, we can stop checking unless we're also getting the curves */ 00970 if ((flags == ACT_TRANS_ALL) && (curves == NULL)) 00971 break; 00972 00973 /* just in case... */ 00974 if (fcu->rna_path == NULL) 00975 continue; 00976 00977 /* step 1: check for matching base path */ 00978 bPtr= strstr(fcu->rna_path, basePath); 00979 00980 if (bPtr) { 00981 /* we must add len(basePath) bytes to the match so that we are at the end of the 00982 * base path so that we don't get false positives with these strings in the names 00983 */ 00984 bPtr += strlen(basePath); 00985 00986 /* step 2: check for some property with transforms 00987 * - to speed things up, only check for the ones not yet found 00988 * unless we're getting the curves too 00989 * - if we're getting the curves, the BLI_genericNodeN() creates a LinkData 00990 * node wrapping the F-Curve, which then gets added to the list 00991 * - once a match has been found, the curve cannot possibly be any other one 00992 */ 00993 if ((curves) || (flags & ACT_TRANS_LOC) == 0) { 00994 pPtr= strstr(bPtr, "location"); 00995 if (pPtr) { 00996 flags |= ACT_TRANS_LOC; 00997 00998 if (curves) 00999 BLI_addtail(curves, BLI_genericNodeN(fcu)); 01000 continue; 01001 } 01002 } 01003 01004 if ((curves) || (flags & ACT_TRANS_SCALE) == 0) { 01005 pPtr= strstr(bPtr, "scale"); 01006 if (pPtr) { 01007 flags |= ACT_TRANS_SCALE; 01008 01009 if (curves) 01010 BLI_addtail(curves, BLI_genericNodeN(fcu)); 01011 continue; 01012 } 01013 } 01014 01015 if ((curves) || (flags & ACT_TRANS_ROT) == 0) { 01016 pPtr= strstr(bPtr, "rotation"); 01017 if (pPtr) { 01018 flags |= ACT_TRANS_ROT; 01019 01020 if (curves) 01021 BLI_addtail(curves, BLI_genericNodeN(fcu)); 01022 continue; 01023 } 01024 } 01025 01026 if ((curves) || (flags & ACT_TRANS_PROP) == 0) { 01027 /* custom properties only */ 01028 pPtr= strstr(bPtr, "[\""); /* extra '"' comment here to keep my texteditor functionlist working :) */ 01029 if (pPtr) { 01030 flags |= ACT_TRANS_PROP; 01031 01032 if (curves) 01033 BLI_addtail(curves, BLI_genericNodeN(fcu)); 01034 continue; 01035 } 01036 } 01037 } 01038 } 01039 01040 /* free basePath */ 01041 MEM_freeN(basePath); 01042 01043 /* return flags found */ 01044 return flags; 01045 } 01046 01047 /* ************** Pose Management Tools ****************** */ 01048 01049 /* Copy the data from the action-pose (src) into the pose */ 01050 /* both args are assumed to be valid */ 01051 /* exported to game engine */ 01052 /* Note! this assumes both poses are aligned, this isnt always true when dealing with user poses */ 01053 void extract_pose_from_pose(bPose *pose, const bPose *src) 01054 { 01055 const bPoseChannel *schan; 01056 bPoseChannel *pchan= pose->chanbase.first; 01057 01058 if (pose==src) { 01059 printf("extract_pose_from_pose source and target are the same\n"); 01060 return; 01061 } 01062 01063 for (schan=src->chanbase.first; (schan && pchan); schan=schan->next, pchan= pchan->next) { 01064 copy_pose_channel_data(pchan, schan); 01065 } 01066 } 01067 01068 /* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */ 01069 void rest_pose(bPose *pose) 01070 { 01071 bPoseChannel *pchan; 01072 01073 if (!pose) 01074 return; 01075 01076 memset(pose->stride_offset, 0, sizeof(pose->stride_offset)); 01077 memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset)); 01078 01079 for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) { 01080 zero_v3(pchan->loc); 01081 zero_v3(pchan->eul); 01082 unit_qt(pchan->quat); 01083 unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); 01084 pchan->size[0]= pchan->size[1]= pchan->size[2]= 1.0f; 01085 01086 pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); 01087 } 01088 } 01089 01090 /* both poses should be in sync */ 01091 void copy_pose_result(bPose *to, bPose *from) 01092 { 01093 bPoseChannel *pchanto, *pchanfrom; 01094 01095 if(to==NULL || from==NULL) { 01096 printf("pose result copy error to:%p from:%p\n", (void *)to, (void *)from); // debug temp 01097 return; 01098 } 01099 01100 if (to==from) { 01101 printf("copy_pose_result source and target are the same\n"); 01102 return; 01103 } 01104 01105 01106 for(pchanfrom= from->chanbase.first; pchanfrom; pchanfrom= pchanfrom->next) { 01107 pchanto= get_pose_channel(to, pchanfrom->name); 01108 if(pchanto) { 01109 copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat); 01110 copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat); 01111 01112 /* used for local constraints */ 01113 VECCOPY(pchanto->loc, pchanfrom->loc); 01114 QUATCOPY(pchanto->quat, pchanfrom->quat); 01115 VECCOPY(pchanto->eul, pchanfrom->eul); 01116 VECCOPY(pchanto->size, pchanfrom->size); 01117 01118 VECCOPY(pchanto->pose_head, pchanfrom->pose_head); 01119 VECCOPY(pchanto->pose_tail, pchanfrom->pose_tail); 01120 01121 pchanto->rotmode= pchanfrom->rotmode; 01122 pchanto->flag= pchanfrom->flag; 01123 pchanto->protectflag= pchanfrom->protectflag; 01124 } 01125 } 01126 } 01127 01128 /* For the calculation of the effects of an Action at the given frame on an object 01129 * This is currently only used for the Action Constraint 01130 */ 01131 void what_does_obaction (Object *ob, Object *workob, bPose *pose, bAction *act, char groupname[], float cframe) 01132 { 01133 bActionGroup *agrp= action_groups_find_named(act, groupname); 01134 01135 /* clear workob */ 01136 clear_workob(workob); 01137 01138 /* init workob */ 01139 copy_m4_m4(workob->obmat, ob->obmat); 01140 copy_m4_m4(workob->parentinv, ob->parentinv); 01141 copy_m4_m4(workob->constinv, ob->constinv); 01142 workob->parent= ob->parent; 01143 01144 workob->rotmode= ob->rotmode; 01145 01146 workob->trackflag= ob->trackflag; 01147 workob->upflag= ob->upflag; 01148 01149 workob->partype= ob->partype; 01150 workob->par1= ob->par1; 01151 workob->par2= ob->par2; 01152 workob->par3= ob->par3; 01153 01154 workob->constraints.first = ob->constraints.first; 01155 workob->constraints.last = ob->constraints.last; 01156 01157 workob->pose= pose; /* need to set pose too, since this is used for both types of Action Constraint */ 01158 01159 BLI_strncpy(workob->parsubstr, ob->parsubstr, sizeof(workob->parsubstr)); 01160 BLI_strncpy(workob->id.name, "OB<ConstrWorkOb>", sizeof(workob->id.name)); /* we don't use real object name, otherwise RNA screws with the real thing */ 01161 01162 /* if we're given a group to use, it's likely to be more efficient (though a bit more dangerous) */ 01163 if (agrp) { 01164 /* specifically evaluate this group only */ 01165 PointerRNA id_ptr; 01166 01167 /* get RNA-pointer for the workob's ID */ 01168 RNA_id_pointer_create(&workob->id, &id_ptr); 01169 01170 /* execute action for this group only */ 01171 animsys_evaluate_action_group(&id_ptr, act, agrp, NULL, cframe); 01172 } 01173 else { 01174 AnimData adt= {NULL}; 01175 01176 /* init animdata, and attach to workob */ 01177 workob->adt= &adt; 01178 01179 adt.recalc= ADT_RECALC_ANIM; 01180 adt.action= act; 01181 01182 /* execute effects of Action on to workob (or it's PoseChannels) */ 01183 BKE_animsys_evaluate_animdata(&workob->id, &adt, cframe, ADT_RECALC_ANIM); 01184 } 01185 } 01186 01187 /* ********** NLA with non-poses works with ipo channels ********** */ 01188 01189 #if 0 // XXX OLD ANIMATION SYSTEM (TO BE REMOVED) 01190 01191 /* ************************ Blending with NLA *************** */ 01192 01193 static void blend_pose_strides(bPose *dst, bPose *src, float srcweight, short mode) 01194 { 01195 float dstweight; 01196 01197 switch (mode){ 01198 case ACTSTRIPMODE_BLEND: 01199 dstweight = 1.0F - srcweight; 01200 break; 01201 case ACTSTRIPMODE_ADD: 01202 dstweight = 1.0F; 01203 break; 01204 default : 01205 dstweight = 1.0F; 01206 } 01207 01208 interp_v3_v3v3(dst->stride_offset, dst->stride_offset, src->stride_offset, srcweight); 01209 } 01210 01211 01212 /* 01213 01214 bone matching diagram, strips A and B 01215 01216 .------------------------. 01217 | A | 01218 '------------------------' 01219 . . b2 01220 . .-------------v----------. 01221 . | B . | 01222 . '------------------------' 01223 . . . 01224 . . . 01225 offset: . 0 . A-B . A-b2+B 01226 . . . 01227 01228 */ 01229 01230 01231 static void blend_pose_offset_bone(bActionStrip *strip, bPose *dst, bPose *src, float srcweight, short mode) 01232 { 01233 /* matching offset bones */ 01234 /* take dst offset, and put src on on that location */ 01235 01236 if(strip->offs_bone[0]==0) 01237 return; 01238 01239 /* are we also blending with matching bones? */ 01240 if(strip->prev && strip->start>=strip->prev->start) { 01241 bPoseChannel *dpchan= get_pose_channel(dst, strip->offs_bone); 01242 if(dpchan) { 01243 bPoseChannel *spchan= get_pose_channel(src, strip->offs_bone); 01244 if(spchan) { 01245 float vec[3]; 01246 01247 /* dst->ctime has the internal strip->prev action time */ 01248 /* map this time to nla time */ 01249 01250 float ctime= get_actionstrip_frame(strip, src->ctime, 1); 01251 01252 if( ctime > strip->prev->end) { 01253 bActionChannel *achan; 01254 01255 /* add src to dest, minus the position of src on strip->prev->end */ 01256 01257 ctime= get_actionstrip_frame(strip, strip->prev->end, 0); 01258 01259 achan= get_action_channel(strip->act, strip->offs_bone); 01260 if(achan && achan->ipo) { 01261 bPoseChannel pchan; 01262 /* Evaluates and sets the internal ipo value */ 01263 calc_ipo(achan->ipo, ctime); 01264 /* This call also sets the pchan flags */ 01265 execute_action_ipo(achan, &pchan); 01266 01267 /* store offset that moves src to location of pchan */ 01268 sub_v3_v3v3(vec, dpchan->loc, pchan.loc); 01269 01270 mul_mat3_m4_v3(dpchan->bone->arm_mat, vec); 01271 } 01272 } 01273 else { 01274 /* store offset that moves src to location of dst */ 01275 01276 sub_v3_v3v3(vec, dpchan->loc, spchan->loc); 01277 mul_mat3_m4_v3(dpchan->bone->arm_mat, vec); 01278 } 01279 01280 /* if blending, we only add with factor scrweight */ 01281 mul_v3_fl(vec, srcweight); 01282 01283 add_v3_v3(dst->cyclic_offset, vec); 01284 } 01285 } 01286 } 01287 01288 add_v3_v3(dst->cyclic_offset, src->cyclic_offset); 01289 } 01290 01291 /* added "sizecorr" here, to allow armatures to be scaled and still have striding. 01292 Only works for uniform scaling. In general I'd advise against scaling armatures ever though! (ton) 01293 */ 01294 static float stridechannel_frame(Object *ob, float sizecorr, bActionStrip *strip, Path *path, float pathdist, float *stride_offset) 01295 { 01296 bAction *act= strip->act; 01297 const char *name= strip->stridechannel; 01298 bActionChannel *achan= get_action_channel(act, name); 01299 int stride_axis= strip->stride_axis; 01300 01301 if(achan && achan->ipo) { 01302 IpoCurve *icu= NULL; 01303 float minx=0.0f, maxx=0.0f, miny=0.0f, maxy=0.0f; 01304 int foundvert= 0; 01305 01306 if(stride_axis==0) stride_axis= AC_LOC_X; 01307 else if(stride_axis==1) stride_axis= AC_LOC_Y; 01308 else stride_axis= AC_LOC_Z; 01309 01310 /* calculate the min/max */ 01311 for (icu=achan->ipo->curve.first; icu; icu=icu->next) { 01312 if(icu->adrcode==stride_axis) { 01313 if(icu->totvert>1) { 01314 foundvert= 1; 01315 minx= icu->bezt[0].vec[1][0]; 01316 maxx= icu->bezt[icu->totvert-1].vec[1][0]; 01317 01318 miny= icu->bezt[0].vec[1][1]; 01319 maxy= icu->bezt[icu->totvert-1].vec[1][1]; 01320 } 01321 break; 01322 } 01323 } 01324 01325 if(foundvert && miny!=maxy) { 01326 float stridelen= sizecorr*fabs(maxy-miny), striptime; 01327 float actiondist, pdist, pdistNewNormalized, offs; 01328 float vec1[4], vec2[4], dir[3]; 01329 01330 /* internal cycling, actoffs is in frames */ 01331 offs= stridelen*strip->actoffs/(maxx-minx); 01332 01333 /* amount path moves object */ 01334 pdist = (float)fmod (pathdist+offs, stridelen); 01335 striptime= pdist/stridelen; 01336 01337 /* amount stride bone moves */ 01338 actiondist= sizecorr*eval_icu(icu, minx + striptime*(maxx-minx)) - miny; 01339 01340 pdist = fabs(actiondist) - pdist; 01341 pdistNewNormalized = (pathdist+pdist)/path->totdist; 01342 01343 /* now we need to go pdist further (or less) on cu path */ 01344 where_on_path(ob, (pathdist)/path->totdist, vec1, dir); /* vec needs size 4 */ 01345 if (pdistNewNormalized <= 1) { 01346 // search for correction in positive path-direction 01347 where_on_path(ob, pdistNewNormalized, vec2, dir); /* vec needs size 4 */ 01348 sub_v3_v3v3(stride_offset, vec2, vec1); 01349 } 01350 else { 01351 // we reached the end of the path, search backwards instead 01352 where_on_path(ob, (pathdist-pdist)/path->totdist, vec2, dir); /* vec needs size 4 */ 01353 sub_v3_v3v3(stride_offset, vec1, vec2); 01354 } 01355 mul_mat3_m4_v3(ob->obmat, stride_offset); 01356 return striptime; 01357 } 01358 } 01359 return 0.0f; 01360 } 01361 01362 static void cyclic_offs_bone(Object *ob, bPose *pose, bActionStrip *strip, float time) 01363 { 01364 /* only called when strip has cyclic, so >= 1.0f works... */ 01365 if(time >= 1.0f) { 01366 bActionChannel *achan= get_action_channel(strip->act, strip->offs_bone); 01367 01368 if(achan && achan->ipo) { 01369 IpoCurve *icu= NULL; 01370 Bone *bone; 01371 float min[3]={0.0f, 0.0f, 0.0f}, max[3]={0.0f, 0.0f, 0.0f}; 01372 int index=0, foundvert= 0; 01373 01374 /* calculate the min/max */ 01375 for (icu=achan->ipo->curve.first; icu; icu=icu->next) { 01376 if(icu->totvert>1) { 01377 01378 if(icu->adrcode==AC_LOC_X) 01379 index= 0; 01380 else if(icu->adrcode==AC_LOC_Y) 01381 index= 1; 01382 else if(icu->adrcode==AC_LOC_Z) 01383 index= 2; 01384 else 01385 continue; 01386 01387 foundvert= 1; 01388 min[index]= icu->bezt[0].vec[1][1]; 01389 max[index]= icu->bezt[icu->totvert-1].vec[1][1]; 01390 } 01391 } 01392 if(foundvert) { 01393 /* bring it into armature space */ 01394 sub_v3_v3v3(min, max, min); 01395 bone= get_named_bone(ob->data, strip->offs_bone); /* weak */ 01396 if(bone) { 01397 mul_mat3_m4_v3(bone->arm_mat, min); 01398 01399 /* dominant motion, cyclic_offset was cleared in rest_pose */ 01400 if (strip->flag & (ACTSTRIP_CYCLIC_USEX | ACTSTRIP_CYCLIC_USEY | ACTSTRIP_CYCLIC_USEZ)) { 01401 if (strip->flag & ACTSTRIP_CYCLIC_USEX) pose->cyclic_offset[0]= time*min[0]; 01402 if (strip->flag & ACTSTRIP_CYCLIC_USEY) pose->cyclic_offset[1]= time*min[1]; 01403 if (strip->flag & ACTSTRIP_CYCLIC_USEZ) pose->cyclic_offset[2]= time*min[2]; 01404 } else { 01405 if( fabs(min[0]) >= fabs(min[1]) && fabs(min[0]) >= fabs(min[2])) 01406 pose->cyclic_offset[0]= time*min[0]; 01407 else if( fabs(min[1]) >= fabs(min[0]) && fabs(min[1]) >= fabs(min[2])) 01408 pose->cyclic_offset[1]= time*min[1]; 01409 else 01410 pose->cyclic_offset[2]= time*min[2]; 01411 } 01412 } 01413 } 01414 } 01415 } 01416 } 01417 01418 /* simple case for now; only the curve path with constraint value > 0.5 */ 01419 /* blending we might do later... */ 01420 static Object *get_parent_path(Object *ob) 01421 { 01422 bConstraint *con; 01423 01424 if(ob->parent && ob->parent->type==OB_CURVE) 01425 return ob->parent; 01426 01427 for (con = ob->constraints.first; con; con=con->next) { 01428 if(con->type==CONSTRAINT_TYPE_FOLLOWPATH) { 01429 if(con->enforce>0.5f) { 01430 bFollowPathConstraint *data= con->data; 01431 return data->tar; 01432 } 01433 } 01434 } 01435 return NULL; 01436 } 01437 01438 /* ************** do the action ************ */ 01439 01440 /* ----- nla, etc. --------- */ 01441 01442 static void do_nla(Scene *scene, Object *ob, int blocktype) 01443 { 01444 bPose *tpose= NULL; 01445 Key *key= NULL; 01446 ListBase tchanbase={NULL, NULL}, chanbase={NULL, NULL}; 01447 bActionStrip *strip, *striplast=NULL, *stripfirst=NULL; 01448 float striptime, frametime, length, actlength; 01449 float blendfac, stripframe; 01450 float scene_cfra= BKE_curframe(scene); 01451 int doit, dostride; 01452 01453 if(blocktype==ID_AR) { 01454 copy_pose(&tpose, ob->pose, 1); 01455 rest_pose(ob->pose); // potentially destroying current not-keyed pose 01456 } 01457 else { 01458 key= ob_get_key(ob); 01459 } 01460 01461 /* check on extend to left or right, when no strip is hit by 'cfra' */ 01462 for (strip=ob->nlastrips.first; strip; strip=strip->next) { 01463 /* escape loop on a hit */ 01464 if( scene_cfra >= strip->start && scene_cfra <= strip->end + 0.1f) /* note 0.1 comes back below */ 01465 break; 01466 if(scene_cfra < strip->start) { 01467 if(stripfirst==NULL) 01468 stripfirst= strip; 01469 else if(stripfirst->start > strip->start) 01470 stripfirst= strip; 01471 } 01472 else if(scene_cfra > strip->end) { 01473 if(striplast==NULL) 01474 striplast= strip; 01475 else if(striplast->end < strip->end) 01476 striplast= strip; 01477 } 01478 } 01479 if(strip==NULL) { /* extend */ 01480 if(striplast) 01481 scene_cfra= striplast->end; 01482 else if(stripfirst) 01483 scene_cfra= stripfirst->start; 01484 } 01485 01486 /* and now go over all strips */ 01487 for (strip=ob->nlastrips.first; strip; strip=strip->next){ 01488 doit=dostride= 0; 01489 01490 if (strip->act && !(strip->flag & ACTSTRIP_MUTE)) { /* so theres an action */ 01491 01492 /* Determine if the current frame is within the strip's range */ 01493 length = strip->end-strip->start; 01494 actlength = strip->actend-strip->actstart; 01495 striptime = (scene_cfra-(strip->start)) / length; 01496 stripframe = (scene_cfra-(strip->start)) ; 01497 01498 if (striptime>=0.0){ 01499 01500 if(blocktype==ID_AR) 01501 rest_pose(tpose); 01502 01503 /* To handle repeat, we add 0.1 frame extra to make sure the last frame is included */ 01504 if (striptime < 1.0f + 0.1f/length) { 01505 01506 /* Handle path */ 01507 if ((strip->flag & ACTSTRIP_USESTRIDE) && (blocktype==ID_AR) && (ob->ipoflag & OB_DISABLE_PATH)==0){ 01508 Object *parent= get_parent_path(ob); 01509 01510 if (parent) { 01511 Curve *cu = parent->data; 01512 float ctime, pdist; 01513 01514 if (cu->flag & CU_PATH){ 01515 /* Ensure we have a valid path */ 01516 if(cu->path==NULL || cu->path->data==NULL) makeDispListCurveTypes(scene, parent, 0); 01517 if(cu->path) { 01518 01519 /* Find the position on the path */ 01520 ctime= bsystem_time(scene, ob, scene_cfra, 0.0); 01521 01522 if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) { 01523 /* correct for actions not starting on zero */ 01524 ctime= (ctime - strip->actstart)/cu->pathlen; 01525 CLAMP(ctime, 0.0, 1.0); 01526 } 01527 pdist = ctime*cu->path->totdist; 01528 01529 if(tpose && strip->stridechannel[0]) { 01530 striptime= stridechannel_frame(parent, ob->size[0], strip, cu->path, pdist, tpose->stride_offset); 01531 } 01532 else { 01533 if (strip->stridelen) { 01534 striptime = pdist / strip->stridelen; 01535 striptime = (float)fmod (striptime+strip->actoffs, 1.0); 01536 } 01537 else 01538 striptime = 0; 01539 } 01540 01541 frametime = (striptime * actlength) + strip->actstart; 01542 frametime= bsystem_time(scene, ob, frametime, 0.0); 01543 01544 if(blocktype==ID_AR) { 01545 extract_pose_from_action (tpose, strip->act, frametime); 01546 } 01547 else if(blocktype==ID_OB) { 01548 extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime); 01549 if(key) 01550 extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime); 01551 } 01552 doit=dostride= 1; 01553 } 01554 } 01555 } 01556 } 01557 /* To handle repeat, we add 0.1 frame extra to make sure the last frame is included */ 01558 else { 01559 01560 /* Mod to repeat */ 01561 if(strip->repeat!=1.0f) { 01562 float cycle= striptime*strip->repeat; 01563 01564 striptime = (float)fmod (cycle, 1.0f + 0.1f/length); 01565 cycle-= striptime; 01566 01567 if(blocktype==ID_AR) 01568 cyclic_offs_bone(ob, tpose, strip, cycle); 01569 } 01570 01571 frametime = (striptime * actlength) + strip->actstart; 01572 frametime= nla_time(scene, frametime, (float)strip->repeat); 01573 01574 if(blocktype==ID_AR) { 01575 extract_pose_from_action (tpose, strip->act, frametime); 01576 } 01577 else if(blocktype==ID_OB) { 01578 extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime); 01579 if(key) 01580 extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime); 01581 } 01582 01583 doit=1; 01584 } 01585 } 01586 /* Handle extend */ 01587 else { 01588 if (strip->flag & ACTSTRIP_HOLDLASTFRAME){ 01589 /* we want the strip to hold on the exact fraction of the repeat value */ 01590 01591 frametime = actlength * (strip->repeat-(int)strip->repeat); 01592 if(frametime<=0.000001f) frametime= actlength; /* rounding errors... */ 01593 frametime= bsystem_time(scene, ob, frametime+strip->actstart, 0.0); 01594 01595 if(blocktype==ID_AR) 01596 extract_pose_from_action (tpose, strip->act, frametime); 01597 else if(blocktype==ID_OB) { 01598 extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime); 01599 if(key) 01600 extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime); 01601 } 01602 01603 /* handle cycle hold */ 01604 if(strip->repeat!=1.0f) { 01605 if(blocktype==ID_AR) 01606 cyclic_offs_bone(ob, tpose, strip, strip->repeat-1.0f); 01607 } 01608 01609 doit=1; 01610 } 01611 } 01612 01613 /* Handle blendin & blendout */ 01614 if (doit){ 01615 /* Handle blendin */ 01616 01617 if (strip->blendin>0.0 && stripframe<=strip->blendin && scene_cfra>=strip->start){ 01618 blendfac = stripframe/strip->blendin; 01619 } 01620 else if (strip->blendout>0.0 && stripframe>=(length-strip->blendout) && scene_cfra<=strip->end){ 01621 blendfac = (length-stripframe)/(strip->blendout); 01622 } 01623 else 01624 blendfac = 1; 01625 01626 if(blocktype==ID_AR) {/* Blend this pose with the accumulated pose */ 01627 /* offset bone, for matching cycles */ 01628 blend_pose_offset_bone (strip, ob->pose, tpose, blendfac, strip->mode); 01629 01630 blend_poses (ob->pose, tpose, blendfac, strip->mode); 01631 if(dostride) 01632 blend_pose_strides (ob->pose, tpose, blendfac, strip->mode); 01633 } 01634 else { 01635 blend_ipochannels(&chanbase, &tchanbase, blendfac, strip->mode); 01636 BLI_freelistN(&tchanbase); 01637 } 01638 } 01639 } 01640 } 01641 } 01642 01643 if(blocktype==ID_OB) { 01644 execute_ipochannels(&chanbase); 01645 } 01646 else if(blocktype==ID_AR) { 01647 /* apply stride offset to object */ 01648 add_v3_v3(ob->obmat[3], ob->pose->stride_offset); 01649 } 01650 01651 /* free */ 01652 if (tpose) 01653 free_pose(tpose); 01654 if(chanbase.first) 01655 BLI_freelistN(&chanbase); 01656 } 01657 01658 #endif // XXX OLD ANIMATION SYSTEM (TO BE REMOVED)