Blender V2.61 - r43446

action.c

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