2.5
[blender.git] / source / blender / blenkernel / intern / action.c
index 3b4de305545a25576bcbf15ab54af278f26adbbe..98f8a83f8094203131313db04107d75f53f2e033 100644 (file)
@@ -1,15 +1,12 @@
 /**
  * $Id$
  *
- * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version. The Blender
- * Foundation also sells licenses for use in proprietary software under
- * the Blender License.  See http://www.blender.org/BL/ for information
- * about this.
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,7 +22,7 @@
  *
  * Contributor(s): Full recode, Ton Roosendaal, Crete 2005
  *
- * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * ***** END GPL LICENSE BLOCK *****
  */
 
 #ifdef HAVE_CONFIG_H
@@ -65,8 +62,9 @@
 
 #include "BLI_arithb.h"
 #include "BLI_blenlib.h"
+#include "BLI_ghash.h"
 
-#include "nla.h"
+//XXX #include "nla.h"
 
 /* *********************** NOTE ON POSE AND ACTION **********************
 
@@ -197,9 +195,9 @@ bAction *copy_action (bAction *src)
        
        dst= copy_libblock(src);
        
-       duplicatelist(&(dst->chanbase), &(src->chanbase));
-       duplicatelist(&(dst->groups), &(src->groups));
-       duplicatelist(&(dst->markers), &(src->markers));
+       BLI_duplicatelist(&(dst->chanbase), &(src->chanbase));
+       BLI_duplicatelist(&(dst->groups), &(src->groups));
+       BLI_duplicatelist(&(dst->markers), &(src->markers));
        
        for (dchan=dst->chanbase.first, schan=src->chanbase.first; dchan; dchan=dchan->next, schan=schan->next) {
                for (dgrp=dst->groups.first, sgrp=src->groups.first; dgrp && sgrp; dgrp=dgrp->next, sgrp=sgrp->next) {
@@ -293,9 +291,15 @@ void copy_pose(bPose **dst, bPose *src, int copycon)
                return;
        }
        
+       if (*dst==src) {
+               printf("copy_pose source and target are the same\n");
+               *dst=NULL;
+               return;
+       }
+       
        outPose= MEM_callocN(sizeof(bPose), "pose");
        
-       duplicatelist(&outPose->chanbase, &src->chanbase);
+       BLI_duplicatelist(&outPose->chanbase, &src->chanbase);
        
        if (copycon) {
                for (pchan=outPose->chanbase.first; pchan; pchan=pchan->next) {
@@ -337,23 +341,83 @@ void free_pose(bPose *pose)
        }
 }
 
+void game_copy_pose(bPose **dst, bPose *src)
+{
+       bPose *out;
+       bPoseChannel *pchan, *outpchan;
+       GHash *ghash;
+       
+       /* the game engine copies the current armature pose and then swaps
+        * the object pose pointer. this makes it possible to change poses
+        * without affecting the original blender data. */
+
+       if (!src) {
+               *dst=NULL;
+               return;
+       }
+       else if (*dst==src) {
+               printf("copy_pose source and target are the same\n");
+               *dst=NULL;
+               return;
+       }
+       
+       out= MEM_dupallocN(src);
+       out->agroups.first= out->agroups.last= NULL;
+       BLI_duplicatelist(&out->chanbase, &src->chanbase);
+
+       /* remap pointers */
+       ghash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+       pchan= src->chanbase.first;
+       outpchan= out->chanbase.first;
+       for (; pchan; pchan=pchan->next, outpchan=outpchan->next)
+               BLI_ghash_insert(ghash, pchan, outpchan);
+
+       for (pchan=out->chanbase.first; pchan; pchan=pchan->next) {
+               pchan->parent= BLI_ghash_lookup(ghash, pchan->parent);
+               pchan->child= BLI_ghash_lookup(ghash, pchan->child);
+               pchan->path= NULL;
+       }
+
+       BLI_ghash_free(ghash, NULL, NULL);
+       
+       *dst=out;
+}
+
+void game_free_pose(bPose *pose)
+{
+       if (pose) {
+               /* we don't free constraints, those are owned by the original pose */
+               if(pose->chanbase.first)
+                       BLI_freelistN(&pose->chanbase);
+               
+               MEM_freeN(pose);
+       }
+}
+
 static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan)
 {
        bConstraint *pcon, *con;
        
        VECCOPY(pchan->loc, chan->loc);
        VECCOPY(pchan->size, chan->size);
+       VECCOPY(pchan->eul, chan->eul);
        QUATCOPY(pchan->quat, chan->quat);
+       pchan->rotmode= chan->rotmode;
+       Mat4CpyMat4(pchan->chan_mat, (float(*)[4])chan->chan_mat);
+       Mat4CpyMat4(pchan->pose_mat, (float(*)[4])chan->pose_mat);
        pchan->flag= chan->flag;
        
        con= chan->constraints.first;
-       for(pcon= pchan->constraints.first; pcon; pcon= pcon->next) {
+       for(pcon= pchan->constraints.first; pcon; pcon= pcon->next, con= con->next) {
                pcon->enforce= con->enforce;
                pcon->headtail= con->headtail;
        }
 }
 
-/* checks for IK constraint, can do more constraints flags later */
+/* checks for IK constraint, and also for Follow-Path constraint.
+ * can do more constraints flags later 
+ */
 /* pose should be entirely OK */
 void update_pose_constraint_flags(bPose *pose)
 {
@@ -361,13 +425,15 @@ void update_pose_constraint_flags(bPose *pose)
        bConstraint *con;
        
        /* clear */
-       for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
+       for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
                pchan->constflag= 0;
        }
+       pose->flag &= ~POSE_CONSTRAINTS_TIMEDEPEND;
+       
        /* detect */
-       for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
-               for(con= pchan->constraints.first; con; con= con->next) {
-                       if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
+       for (pchan= pose->chanbase.first; pchan; pchan=pchan->next) {
+               for (con= pchan->constraints.first; con; con= con->next) {
+                       if (con->type==CONSTRAINT_TYPE_KINEMATIC) {
                                bKinematicConstraint *data = (bKinematicConstraint*)con->data;
                                
                                pchan->constflag |= PCHAN_HAS_IK;
@@ -390,7 +456,20 @@ void update_pose_constraint_flags(bPose *pose)
                                        }
                                }
                        }
-                       else pchan->constflag |= PCHAN_HAS_CONST;
+                       else if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) {
+                               bFollowPathConstraint *data= (bFollowPathConstraint *)con->data;
+                               
+                               /* for drawing constraint colors when color set allows this */
+                               pchan->constflag |= PCHAN_HAS_CONST;
+                               
+                               /* if we have a valid target, make sure that this will get updated on frame-change
+                                * (needed for when there is no anim-data for this pose)
+                                */
+                               if ((data->tar) && (data->tar->type==OB_CURVE))
+                                       pose->flag |= POSE_CONSTRAINTS_TIMEDEPEND;
+                       }
+                       else 
+                               pchan->constflag |= PCHAN_HAS_CONST;
                }
        }
 }
@@ -475,10 +554,11 @@ static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert
 {
        float length, actlength, repeat, scale;
        
+       if (strip->repeat == 0.0f) strip->repeat = 1.0f;
        repeat = (strip->flag & ACTSTRIP_USESTRIDE) ? (1.0f) : (strip->repeat);
-       if(strip->scale == 0.0f) strip->scale= 1.0f;
        
-       scale = abs(strip->scale); /* scale must be positive (for now) */
+       if (strip->scale == 0.0f) strip->scale= 1.0f;
+       scale = fabs(strip->scale); /* scale must be positive (for now) */
        
        actlength = strip->actend-strip->actstart;
        if (actlength == 0.0f) actlength = 1.0f;
@@ -619,7 +699,6 @@ void blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
        bPoseChannel *dchan;
        const bPoseChannel *schan;
        bConstraint *dcon, *scon;
-       float   dquat[4], squat[4];
        float dstweight;
        int i;
        
@@ -641,23 +720,34 @@ void blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
                        
                        /* Do the transformation blend */
                        if (schan->flag & POSE_ROT) {
-                               QUATCOPY(dquat, dchan->quat);
-                               QUATCOPY(squat, schan->quat);
-                               if(mode==ACTSTRIPMODE_BLEND)
-                                       QuatInterpol(dchan->quat, dquat, squat, srcweight);
-                               else {
-                                       QuatMulFac(squat, srcweight);
-                                       QuatMul(dchan->quat, dquat, squat);
+                               /* quat interpolation done separate */
+                               if (schan->rotmode == PCHAN_ROT_QUAT) {
+                                       float dquat[4], squat[4];
+                                       
+                                       QUATCOPY(dquat, dchan->quat);
+                                       QUATCOPY(squat, schan->quat);
+                                       if (mode==ACTSTRIPMODE_BLEND)
+                                               QuatInterpol(dchan->quat, dquat, squat, srcweight);
+                                       else {
+                                               QuatMulFac(squat, srcweight);
+                                               QuatMul(dchan->quat, dquat, squat);
+                                       }
+                                       
+                                       NormalQuat(dchan->quat);
                                }
-                               
-                               NormalQuat (dchan->quat);
                        }
 
-                       for (i=0; i<3; i++){
+                       for (i=0; i<3; i++) {
+                               /* blending for loc and scale are pretty self-explanatory... */
                                if (schan->flag & POSE_LOC)
                                        dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight);
                                if (schan->flag & POSE_SIZE)
                                        dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight);
+                               
+                               /* euler-rotation interpolation done here instead... */
+                               // FIXME: are these results decent?
+                               if ((schan->flag & POSE_ROT) && (schan->rotmode))
+                                       dchan->eul[i] = (dchan->eul[i]*dstweight) + (schan->eul[i]*srcweight);
                        }
                        dchan->flag |= schan->flag;
                }
@@ -671,33 +761,33 @@ void blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
        dst->ctime= src->ctime;
 }
 
-
+/* Calculate the extents of given action */
 void calc_action_range(const bAction *act, float *start, float *end, int incl_hidden)
 {
-       const bActionChannel *chan;
-       const bConstraintChannel *conchan;
-       const IpoCurve  *icu;
-       float min=999999999.0f, max=-999999999.0;
+       bActionChannel *chan;
+       bConstraintChannel *conchan;
+       IpoCurve *icu;
+       float min=999999999.0f, max=-999999999.0f;
        int     foundvert=0;
 
-       if(act) {
+       if (act) {
                for (chan=act->chanbase.first; chan; chan=chan->next) {
-                       if(incl_hidden || (chan->flag & ACHAN_HIDDEN)==0) {
-                               if(chan->ipo) {
+                       if ((incl_hidden) || (chan->flag & ACHAN_HIDDEN)==0) {
+                               if (chan->ipo) {
                                        for (icu=chan->ipo->curve.first; icu; icu=icu->next) {
-                                               if(icu->totvert) {
-                                                       min= MIN2 (min, icu->bezt[0].vec[1][0]);
-                                                       max= MAX2 (max, icu->bezt[icu->totvert-1].vec[1][0]);
+                                               if (icu->totvert) {
+                                                       min= MIN2(min, icu->bezt[0].vec[1][0]);
+                                                       max= MAX2(max, icu->bezt[icu->totvert-1].vec[1][0]);
                                                        foundvert=1;
                                                }
                                        }
                                }
                                for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) {
-                                       if(conchan->ipo) {
+                                       if (conchan->ipo) {
                                                for (icu=conchan->ipo->curve.first; icu; icu=icu->next) {
-                                                       if(icu->totvert) {
-                                                               min= MIN2 (min, icu->bezt[0].vec[1][0]);
-                                                               max= MAX2 (max, icu->bezt[icu->totvert-1].vec[1][0]);
+                                                       if (icu->totvert) {
+                                                               min= MIN2(min, icu->bezt[0].vec[1][0]);
+                                                               max= MAX2(max, icu->bezt[icu->totvert-1].vec[1][0]);
                                                                foundvert=1;
                                                        }
                                                }
@@ -725,6 +815,11 @@ void extract_pose_from_pose(bPose *pose, const bPose *src)
        const bPoseChannel *schan;
        bPoseChannel *pchan= pose->chanbase.first;
 
+       if (pose==src) {
+               printf("extract_pose_from_pose source and target are the same\n");
+               return;
+       }
+
        for (schan=src->chanbase.first; schan; schan=schan->next, pchan= pchan->next) {
                copy_pose_channel_data(pchan, schan);
        }
@@ -784,6 +879,7 @@ void rest_pose(bPose *pose)
                for (i=0; i<3; i++) {
                        pchan->loc[i]= 0.0f;
                        pchan->quat[i+1]= 0.0f;
+                       pchan->eul[i]= 0.0f;
                        pchan->size[i]= 1.0f;
                }
                pchan->quat[0]= 1.0f;
@@ -802,6 +898,12 @@ void copy_pose_result(bPose *to, bPose *from)
                return;
        }
 
+       if (to==from) {
+               printf("copy_pose_result source and target are the same\n");
+               return;
+       }
+
+
        for(pchanfrom= from->chanbase.first; pchanfrom; pchanfrom= pchanfrom->next) {
                pchanto= get_pose_channel(to, pchanfrom->name);
                if(pchanto) {
@@ -828,7 +930,7 @@ typedef struct NlaIpoChannel {
        int type;
 } NlaIpoChannel;
 
-static void extract_ipochannels_from_action(ListBase *lb, ID *id, bAction *act, char *name, float ctime)
+void extract_ipochannels_from_action(ListBase *lb, ID *id, bAction *act, const char *name, float ctime)
 {
        bActionChannel *achan= get_action_channel(act, name);
        IpoCurve *icu;
@@ -921,15 +1023,18 @@ static void blend_ipochannels(ListBase *dst, ListBase *src, float srcweight, int
        }
 }
 
-static void execute_ipochannels(ListBase *lb)
+int execute_ipochannels(ListBase *lb)
 {
        NlaIpoChannel *nic;
+       int count = 0;
        
        for(nic= lb->first; nic; nic= nic->next) {
                if(nic->poin) {
                        write_ipo_poin(nic->poin, nic->type, nic->val);
+                       count++;
                }
        }
+       return count;
 }
 
 /* nla timing */
@@ -946,11 +1051,7 @@ static float nla_time(float cfra, float unit)
        
        /* global time */
        cfra*= G.scene->r.framelen;     
-
-
-       /* decide later... */
-//     if(no_speed_curve==0) if(ob && ob->ipo) cfra= calc_ipo_time(ob->ipo, cfra);
-
+       
        return cfra;
 }
 
@@ -960,7 +1061,7 @@ static float nla_time(float cfra, float unit)
 static float stridechannel_frame(Object *ob, float sizecorr, bActionStrip *strip, Path *path, float pathdist, float *stride_offset)
 {
        bAction *act= strip->act;
-       char *name= strip->stridechannel;
+       const char *name= strip->stridechannel;
        bActionChannel *achan= get_action_channel(act, name);
        int stride_axis= strip->stride_axis;
 
@@ -1128,12 +1229,13 @@ void what_does_obaction (Object *ob, bAction *act, float cframe)
        workob.constraints.first = ob->constraints.first;
        workob.constraints.last = ob->constraints.last;
 
-       strcpy(workob.parsubstr, ob->parsubstr); 
+       strcpy(workob.parsubstr, ob->parsubstr);
+       strcpy(workob.id.name, ob->id.name);
        
        /* extract_ipochannels_from_action needs id's! */
        workob.action= act;
        
-       extract_ipochannels_from_action(&tchanbase, &ob->id, act, "Object", bsystem_time(&workob, cframe, 0.0));
+       extract_ipochannels_from_action(&tchanbase, &workob.id, act, "Object", bsystem_time(&workob, cframe, 0.0));
        
        if (tchanbase.first) {
                execute_ipochannels(&tchanbase);