== Action Editor - Copy/Paste ==
authorJoshua Leung <aligorith@gmail.com>
Wed, 19 Dec 2007 22:37:38 +0000 (22:37 +0000)
committerJoshua Leung <aligorith@gmail.com>
Wed, 19 Dec 2007 22:37:38 +0000 (22:37 +0000)
Now the Copy/Paste functionality stores more info about where keyframes came from. This allows users to copy full poses in the Action Editor and paste them in another action.

Peach request/bugfix for William.

source/blender/src/editaction.c

index dc13e5d301930f9f15f74329d023c8a29dc4093f..c9e2df8d9ebe3826bcc1a872d3c379d18fda13e3 100644 (file)
@@ -1144,10 +1144,9 @@ void clean_action (void)
 
 /* **************************************************** */
 /* COPY/PASTE FOR ACTIONS */
-/* - The copy/paste buffer currently stores a set of IPO curves, with no
- *   repeating curve-types (i.e.  no curves with the same adrcode). 
- * - Only selected keyframes from the source curves are placed here. 
- * - Only 'compatible' pastes are done.
+/* - The copy/paste buffer currently stores a set of Action Channels, with temporary
+ *     IPO-blocks, and also temporary IpoCurves which only contain the selected keyframes.
+ * - Only pastes between compatable data is possible (i.e. same achan->name, ipo-curve type, etc.)
  */
 
 /* globals for copy/paste data (like for other copy/paste buffers) */
@@ -1156,16 +1155,34 @@ ListBase actcopybuf = {NULL, NULL};
 /* This function frees any MEM_calloc'ed copy/paste buffer data */
 void free_actcopybuf ()
 {
-       IpoCurve *icu;
+       bActionChannel *achan, *anext;
+       bConstraintChannel *conchan, *cnext;
        
-       while( (icu= actcopybuf.first) ) {
-               BLI_remlink(&actcopybuf, icu);
-               free_ipo_curve(icu);
+       for (achan= actcopybuf.first; achan; achan= next) {
+               next= achan->next;
+               
+               if (achan->ipo) {
+                       free_ipo(achan->ipo);
+                       MEM_freeN(achan->ipo);
+               }
+               
+               for (conchan=achan->constraintChannels.first; conchan; conchan=cnext) {
+                       cnext= conchan->next;
+                       
+                       if (conchan->ipo) {
+                               free_ipo(conchan->ipo);
+                               MEM_freeN(conchan->ipo);
+                       }
+                       
+                       BLI_freelistN(&achan->constraintChannels, conchan);
+               }
+               
+               BLI_freelinkN(&actcopybuf, achan);
        }
 }
 
 /* This function adds data to the copy/paste buffer, freeing existing data first
- * Only the active action channel gets its selected keyframes copied.
+ * Only the selected action channels gets their selected keyframes copied.
  */
 void copy_actdata ()
 {
@@ -1183,40 +1200,61 @@ void copy_actdata ()
        if (data == NULL) return;
        
        /* filter data */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_ONLYICU);
+       filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_IPOKEYS);
        actdata_filter(&act_data, filter, data, datatype);
        
-       /* each of these entries should be an ipo curve */
+       /* assume that each of these is an ipo-block */
        for (ale= act_data.first; ale; ale= ale->next) {
-               IpoCurve *icu= ale->key_data;
-               IpoCurve *icn;
+               bActionChannel *achan;
+               Ipo *ipo= ale->key_data;
+               Ipo *ipn;
+               IpoCurve *icu, *icn;
                BezTriple *bezt;
-               short nin_buffer= 1;
                int i;
                
-               /* check if a curve like this exists already in buffer */
-               for (icn= actcopybuf.first; icn; icn= icn->next) {
-                       if ((icn->blocktype==icu->blocktype) && (icn->adrcode==icu->adrcode)) {
-                               nin_buffer= 0;
-                               break;
-                       }
+               /* coerce an action-channel out of owner */
+               if (ale->ownertype == ACTTYPE_ACHAN) {
+                       bActionChannel *achanO= ale->owner;
+                       achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan");
+                       strcpy(achan->name, achanO->name);
+               }
+               else if (ale->ownertype == ACTTYPE_SHAPEKEY) {
+                       achan= MEM_callocN(sizeof(bActionChannel), "ActCopyPasteAchan");
+                       strcpy(achan->name, "#ACP_ShapeKey");
                }
-               /* allocate memory for a new curve if a valid one wasn't found */
-               if (nin_buffer) {
-                       icn= MEM_callocN(sizeof(IpoCurve), "actcopybuf");
+               else
+                       continue;
+               BLI_addtail(&actcopybuf, achan);
+               
+               /* add constraint channel if needed, then add new ipo-block */
+               if (ale->type == ACTTYPE_CONCHAN) {
+                       bConstraintChannel *conchanO= ale->data;
+                       bConstraintChannel *conchan;
                        
-                       *icn= *icu;
-                       icn->totvert= 0;
-                       icn->bezt = NULL;
-                       icn->driver = NULL;
+                       conchan= MEM_callocN(sizeof(bConstraintChannel), "ActCopyPasteConchan");
+                       strcpy(conchan->name, conchanO->name);
+                       BLI_addtail(&achan->constraintChannels, conchan);
                        
-                       BLI_addtail(&actcopybuf, icn);
+                       conchan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo");
                }
-               
-               /* find selected BezTriples to add to the buffer */
-               for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
-                       if (BEZSELECTED(bezt))
-                               insert_bezt_icu(icn, bezt);
+               else {
+                       achan->ipo= ipn= MEM_callocN(sizeof(Ipo), "ActCopyPasteIpo");
+               }
+               ipn->blocktype = ipo->blocktype;
+               
+               /* now loop through curves, and only copy selected keyframes */
+               for (icu= ipo->curve.first; icu; icu= icu->next) {
+                       /* allocate a new curve */
+                       icn= MEM_callocN(sizeof(IpoCurve), "ActCopyPasteIcu");
+                       icn->blocktype = icu->blocktype;
+                       icn->adrcode = icu->adrcode;
+                       BLI_addtail(&ipn->curve, icn);
+                       
+                       /* find selected BezTriples to add to the buffer */
+                       for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
+                               if (BEZSELECTED(bezt))
+                                       insert_bezt_icu(icn, bezt);
+                       }
                }
        }
        
@@ -1247,48 +1285,88 @@ void paste_actdata ()
        if (data == NULL) return;
        
        /* filter data */
-       filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT | ACTFILTER_ONLYICU);
+       filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
        actdata_filter(&act_data, filter, data, datatype);
        
        /* from selected channels */
        for (ale= act_data.first; ale; ale= ale->next) {
-               IpoCurve *icu= ale->key_data;
-               IpoCurve *ico;
+               Ipo *ipo_src=NULL, *ipo_dst=ale->key_data;
+               bActionChannel *achan;
+               IpoCurve *ico, *icu;
                BezTriple *bezt;
                int i;
                float offset= 0.0f;
                short offsetInit= 1;
                
-               /* find matching ipo-curve */
-               for (ico= actcopybuf.first; ico; ico= ico->next) {
-                       if ((ico->blocktype==icu->blocktype) && (ico->adrcode==icu->adrcode)) {
-                               /* just start pasting, with the the first keyframe on the current frame, and so on */
-                               for (i=0, bezt=ico->bezt; i < ico->totvert; i++, bezt++) {
-                                       /* initialise offset (if not already done) */
-                                       if (offsetInit) {
-                                               offset= CFRA - bezt->vec[1][0];
-                                               offsetInit= 0;
+               /* find matching ipo-block */
+               for (achan= actcopybuf.first; achan; achan= achan->next) {
+                       /* try to match data */
+                       if (ale->ownertype == ACTTYPE_ACHAN) {
+                               bActionChannel *achant= ale->owner;
+                               
+                               /* check if we have a corresponding action channel */
+                               if (strcmp(achan->name, achant->name)==0) {
+                                       /* check if this is a constraint channel */
+                                       if (ale->type == ACTTYPE_CONCHAN) {
+                                               bConstraintChannel *conchant= ale->data;
+                                               bConstraintChannel *conchan;
+                                               
+                                               for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
+                                                       if (strcmp(conchan->name, conchant->name)==0) {
+                                                               ipo_src= conchan->ipo;
+                                                               break;
+                                                       }
+                                               }
+                                               if (ipo_src) break;
+                                       }
+                                       else {
+                                               ipo_src= achan->ipo;
+                                               break;
+                                       }
+                               }
+                       }
+                       else if (ale->ownertype == ACTTYPE_SHAPEKEY) {
+                               /* check if this action channel is "#ACP_ShapeKey" */
+                               if (strcmp(achan->name, "#ACP_ShapeKey")==0) {
+                                       ipo_src= achan->ipo;
+                                       break;
+                               }
+                       }       
+               }
+               
+               /* loop over curves, pasting keyframes */
+               for (icu= ipo_dst->curve.first; icu; icu= icu->next) {
+                       for (ico= ipo_src->curve.first; ico; ico= ico->next) {
+                               /* only paste if compatable blocktype + adrcode */
+                               if ((ico->blocktype==icu->blocktype) && (ico->adrcode==icu->adrcode)) {
+                                       /* just start pasting, with the the first keyframe on the current frame, and so on */
+                                       for (i=0, bezt=ico->bezt; i < ico->totvert; i++, bezt++) {
+                                               /* initialise offset (if not already done) */
+                                               if (offsetInit) {
+                                                       offset= CFRA - bezt->vec[1][0];
+                                                       offsetInit= 0;
+                                               }
+                                               
+                                               /* temporarily apply offset to src beztriple while copying */
+                                               bezt->vec[0][0] += offset;
+                                               bezt->vec[1][0] += offset;
+                                               bezt->vec[2][0] += offset;
+                                               
+                                               /* insert the keyframe */
+                                               insert_bezt_icu(icu, bezt);
+                                               
+                                               /* un-apply offset from src beztriple after copying */
+                                               bezt->vec[0][0] -= offset;
+                                               bezt->vec[1][0] -= offset;
+                                               bezt->vec[2][0] -= offset;
                                        }
                                        
-                                       /* temporarily apply offset to src beztriple while copying */
-                                       bezt->vec[0][0] += offset;
-                                       bezt->vec[1][0] += offset;
-                                       bezt->vec[2][0] += offset;
-                                       
-                                       /* insert the keyframe */
-                                       insert_bezt_icu(icu, bezt);
+                                       /* recalculate channel's handles? */
+                                       calchandles_ipocurve(icu);
                                        
-                                       /* un-apply offset from src beztriple after copying */
-                                       bezt->vec[0][0] -= offset;
-                                       bezt->vec[1][0] -= offset;
-                                       bezt->vec[2][0] -= offset;
+                                       /* done for this channel */
+                                       break;
                                }
-                               
-                               /* recalculate channel's handles? */
-                               calchandles_ipocurve(icu);
-                               
-                               /* done for this channel */
-                               break;
                        }
                }
        }