2.5 - Warning cleanups (for mingw+scons)
[blender-staging.git] / source / blender / editors / animation / keyframes_general.c
index 8ff65a2a00895f16efaeee047945a18aedf98707..ced3c1177005e7447e265c27b7a6792b27487e69 100644 (file)
 #include "DNA_anim_types.h"
 #include "DNA_action_types.h"
 #include "DNA_curve_types.h"
-#include "DNA_ipo_types.h" // XXX to be removed
 #include "DNA_key_types.h"
 #include "DNA_object_types.h"
 #include "DNA_space_types.h"
 #include "DNA_scene_types.h"
 
+#include "RNA_access.h"
+
 #include "BKE_action.h"
 #include "BKE_fcurve.h"
 #include "BKE_key.h"
@@ -89,73 +90,69 @@ void delete_fcurve_key(FCurve *fcu, int index, short do_recalc)
                calchandles_fcurve(fcu);
 }
 
-#if 0 // XXX obsolete
-/* Delete selected keyframes in given IPO block */
-void delete_ipo_keys(Ipo *ipo)
+/* Delete selected keyframes in given F-Curve */
+void delete_fcurve_keys(FCurve *fcu)
 {
-       IpoCurve *icu, *next;
        int i;
        
-       if (ipo == NULL)
-               return;
-       
-       for (icu= ipo->curve.first; icu; icu= next) {
-               /* store pointer to next ipo-curve, as we may delete the current one */
-               next = icu->next;
-               
-               /* Delete selected BezTriples */
-               for (i=0; i<icu->totvert; i++) {
-                       if (icu->bezt[i].f2 & SELECT) {
-                               memmove(&icu->bezt[i], &icu->bezt[i+1], sizeof(BezTriple)*(icu->totvert-i-1));
-                               icu->totvert--;
-                               i--;
-                       }
-               }
-               
-               /* Only delete if there isn't an ipo-driver still hanging around on an empty curve */
-               if ((icu->totvert==0) && (icu->driver==NULL)) {
-                       BLI_remlink(&ipo->curve, icu);
-                       free_ipo_curve(icu);
+       /* Delete selected BezTriples */
+       for (i=0; i < fcu->totvert; i++) {
+               if (fcu->bezt[i].f2 & SELECT) {
+                       memmove(&fcu->bezt[i], &fcu->bezt[i+1], sizeof(BezTriple)*(fcu->totvert-i-1));
+                       fcu->totvert--;
+                       i--;
                }
        }
+       
+       /* Free the array of BezTriples if there are not keyframes */
+       if (fcu->totvert == 0) {
+               if (fcu->bezt) 
+                       MEM_freeN(fcu->bezt);
+               fcu->bezt= NULL;
+       }
+       
+#if 0 // XXX for now, we don't get rid of empty curves...
+       /* Only delete if there isn't an ipo-driver still hanging around on an empty curve */
+       if ((icu->totvert==0) && (icu->driver==NULL)) {
+               BLI_remlink(&ipo->curve, icu);
+               free_ipo_curve(icu);
+       }
+#endif 
 }
-#endif // XXX obsolete
 
 /* ---------------- */
 
-/* duplicate selected keyframes for the given IPO block */
-void duplicate_ipo_keys(Ipo *ipo)
+/* duplicate selected keyframes for the given F-Curve */
+void duplicate_fcurve_keys(FCurve *fcu)
 {
-       IpoCurve *icu;
        BezTriple *newbezt;
        int i;
-
-       if (ipo == NULL)
+       
+       /* this can only work when there is an F-Curve, and also when there are some BezTriples */
+       if ELEM(NULL, fcu, fcu->bezt)
                return;
-
-       for (icu= ipo->curve.first; icu; icu= icu->next) {
-               for (i=0; i<icu->totvert; i++) {
-                       /* If a key is selected */
-                       if (icu->bezt[i].f2 & SELECT) {
-                               /* Expand the list */
-                               newbezt = MEM_callocN(sizeof(BezTriple) * (icu->totvert+1), "beztriple");
-                               
-                               memcpy(newbezt, icu->bezt, sizeof(BezTriple) * (i+1));
-                               memcpy(newbezt+i+1, icu->bezt+i, sizeof(BezTriple));
-                               memcpy(newbezt+i+2, icu->bezt+i+1, sizeof (BezTriple) *(icu->totvert-(i+1)));
-                               icu->totvert++;
-                               
-                               /* reassign pointers... (free old, and add new) */
-                               MEM_freeN(icu->bezt);
-                               icu->bezt=newbezt;
-                               
-                               /* Unselect the current key*/
-                               BEZ_DESEL(&icu->bezt[i]);
-                               i++;
-                               
-                               /* Select the copied key */
-                               BEZ_SEL(&icu->bezt[i]);
-                       }
+       
+       for (i=0; i < fcu->totvert; i++) {
+               /* If a key is selected */
+               if (fcu->bezt[i].f2 & SELECT) {
+                       /* Expand the list */
+                       newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert+1), "beztriple");
+                       
+                       memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i+1));
+                       memcpy(newbezt+i+1, fcu->bezt+i, sizeof(BezTriple));
+                       memcpy(newbezt+i+2, fcu->bezt+i+1, sizeof (BezTriple) *(fcu->totvert-(i+1)));
+                       fcu->totvert++;
+                       
+                       /* reassign pointers... (free old, and add new) */
+                       MEM_freeN(fcu->bezt);
+                       fcu->bezt=newbezt;
+                       
+                       /* Unselect the current key */
+                       BEZ_DESEL(&fcu->bezt[i]);
+                       i++;
+                       
+                       /* Select the copied key */
+                       BEZ_SEL(&fcu->bezt[i]);
                }
        }
 }
@@ -163,12 +160,7 @@ void duplicate_ipo_keys(Ipo *ipo)
 /* **************************************************** */
 /* Various Tools */
 
-// XXX - stub... until keyframing code is fixed...
-static void insert_vert_fcu(FCurve *fcu, float x, float y, short flag)
-{
-}
-
-/* Basic IPO-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only */
+/* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only */
 void clean_fcurve(FCurve *fcu, float thresh)
 {
        BezTriple *old_bezts, *bezt, *beztn;
@@ -187,7 +179,7 @@ void clean_fcurve(FCurve *fcu, float thresh)
        
        /* now insert first keyframe, as it should be ok */
        bezt = old_bezts;
-       insert_vert_fcu(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
+       insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0);
        
        /* Loop through BezTriples, comparing them. Skip any that do 
         * not fit the criteria for "ok" points.
@@ -224,7 +216,7 @@ void clean_fcurve(FCurve *fcu, float thresh)
                                if (cur[1] > next[1]) {
                                        if (IS_EQT(cur[1], prev[1], thresh) == 0) {
                                                /* add new keyframe */
-                                               insert_vert_fcu(fcu, cur[0], cur[1], 0);
+                                               insert_vert_fcurve(fcu, cur[0], cur[1], 0);
                                        }
                                }
                        }
@@ -232,7 +224,7 @@ void clean_fcurve(FCurve *fcu, float thresh)
                                /* only add if values are a considerable distance apart */
                                if (IS_EQT(cur[1], prev[1], thresh) == 0) {
                                        /* add new keyframe */
-                                       insert_vert_fcu(fcu, cur[0], cur[1], 0);
+                                       insert_vert_fcurve(fcu, cur[0], cur[1], 0);
                                }
                        }
                }
@@ -242,18 +234,18 @@ void clean_fcurve(FCurve *fcu, float thresh)
                                /* does current have same value as previous and next? */
                                if (IS_EQT(cur[1], prev[1], thresh) == 0) {
                                        /* add new keyframe*/
-                                       insert_vert_fcu(fcu, cur[0], cur[1], 0);
+                                       insert_vert_fcurve(fcu, cur[0], cur[1], 0);
                                }
                                else if (IS_EQT(cur[1], next[1], thresh) == 0) {
                                        /* add new keyframe */
-                                       insert_vert_fcu(fcu, cur[0], cur[1], 0);
+                                       insert_vert_fcurve(fcu, cur[0], cur[1], 0);
                                }
                        }
                        else {  
                                /* add if value doesn't equal that of previous */
                                if (IS_EQT(cur[1], prev[1], thresh) == 0) {
                                        /* add new keyframe */
-                                       insert_vert_fcu(fcu, cur[0], cur[1], 0);
+                                       insert_vert_fcurve(fcu, cur[0], cur[1], 0);
                                }
                        }
                }
@@ -272,8 +264,7 @@ typedef struct tSmooth_Bezt {
 } tSmooth_Bezt;
 
 /* Use a weighted moving-means method to reduce intensity of fluctuations */
-//mode= pupmenu("Smooth F-Curve%t|Tweak Points%x1|Flatten Handles%x2");
-void smooth_fcurve(FCurve *fcu, short mode)
+void smooth_fcurve (FCurve *fcu)
 {
        BezTriple *bezt;
        int i, x, totSel = 0;
@@ -294,79 +285,265 @@ void smooth_fcurve(FCurve *fcu, short mode)
                }
        }
        
-       /* check if adjust values too... */
-       if (mode == 2) {
-               /* if any points were selected, allocate tSmooth_Bezt points to work on */
-               if (totSel >= 3) {
-                       tSmooth_Bezt *tarray, *tsb;
-                       
-                       /* allocate memory in one go */
-                       tsb= tarray= MEM_callocN(totSel*sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
+       /* if any points were selected, allocate tSmooth_Bezt points to work on */
+       if (totSel >= 3) {
+               tSmooth_Bezt *tarray, *tsb;
+               
+               /* allocate memory in one go */
+               tsb= tarray= MEM_callocN(totSel*sizeof(tSmooth_Bezt), "tSmooth_Bezt Array");
+               
+               /* populate tarray with data of selected points */
+               bezt= fcu->bezt;
+               for (i=0, x=0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
+                       if (BEZSELECTED(bezt)) {
+                               /* tsb simply needs pointer to vec, and index */
+                               tsb->h1 = &bezt->vec[0][1];
+                               tsb->h2 = &bezt->vec[1][1];
+                               tsb->h3 = &bezt->vec[2][1];
+                               
+                               /* advance to the next tsb to populate */
+                               if (x < totSel- 1) 
+                                       tsb++;
+                               else
+                                       break;
+                       }
+               }
                        
-                       /* populate tarray with data of selected points */
-                       bezt= fcu->bezt;
-                       for (i=0, x=0; (i < fcu->totvert) && (x < totSel); i++, bezt++) {
-                               if (BEZSELECTED(bezt)) {
-                                       /* tsb simply needs pointer to vec, and index */
-                                       tsb->h1 = &bezt->vec[0][1];
-                                       tsb->h2 = &bezt->vec[1][1];
-                                       tsb->h3 = &bezt->vec[2][1];
-                                       
-                                       /* advance to the next tsb to populate */
-                                       if (x < totSel- 1) 
-                                               tsb++;
-                                       else
-                                               break;
-                               }
+               /* calculate the new smoothed F-Curve's with weighted averages:
+                *      - this is done with two passes
+                *      - uses 5 points for each operation (which stores in the relevant handles)
+                *      -       previous: w/a ratio = 3:5:2:1:1
+                *      -       next: w/a ratio = 1:1:2:5:3
+                */
+               
+               /* round 1: calculate previous and next */ 
+               tsb= tarray;
+               for (i=0; i < totSel; i++, tsb++) {
+                       /* don't touch end points (otherwise, curves slowly explode) */
+                       if (ELEM(i, 0, (totSel-1)) == 0) {
+                               const tSmooth_Bezt *tP1 = tsb - 1;
+                               const tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL);
+                               const tSmooth_Bezt *tN1 = tsb + 1;
+                               const tSmooth_Bezt *tN2 = (i+2 < totSel) ? (tsb + 2) : (NULL);
+                               
+                               const float p1 = *tP1->h2;
+                               const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
+                               const float c1 = *tsb->h2;
+                               const float n1 = *tN1->h2;
+                               const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
+                               
+                               /* calculate previous and next */
+                               *tsb->h1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12;
+                               *tsb->h3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12;
                        }
+               }
+               
+               /* round 2: calculate new values and reset handles */
+               tsb= tarray;
+               for (i=0; i < totSel; i++, tsb++) {
+                       /* calculate new position by averaging handles */
+                       *tsb->h2 = (*tsb->h1 + *tsb->h3) / 2;
                        
-                       /* calculate the new smoothed ipo's with weighted averages:
-                        *      - this is done with two passes
-                        *      - uses 5 points for each operation (which stores in the relevant handles)
-                        *      -       previous: w/a ratio = 3:5:2:1:1
-                        *      -       next: w/a ratio = 1:1:2:5:3
-                        */
+                       /* reset handles now */
+                       *tsb->h1 = *tsb->h2;
+                       *tsb->h3 = *tsb->h2;
+               }
+               
+               /* free memory required for tarray */
+               MEM_freeN(tarray);
+       }
+       
+       /* recalculate handles */
+       calchandles_fcurve(fcu);
+}
+
+/* **************************************************** */
+/* Copy/Paste Tools */
+/* - The copy/paste buffer currently stores a set of temporary F-Curves containing only the keyframes 
+ *   that were selected in each of the original F-Curves
+ * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of
+ *     the current frame and the 'first keyframe' (i.e. the earliest one in all channels).
+ * - The earliest frame is calculated per copy operation.
+ */
+
+/* globals for copy/paste data (like for other copy/paste buffers) */
+ListBase animcopybuf = {NULL, NULL};
+static float animcopy_firstframe= 999999999.0f;
+
+/* datatype for use in copy/paste buffer */
+typedef struct tAnimCopybufItem {
+       struct tAnimCopybufItem *next, *prev;
+       
+       ID *id;                         /* ID which owns the curve */
+       bActionGroup *grp;      /* Action Group */
+       char *rna_path;         /* RNA-Path */
+       int array_index;        /* array index */
+       
+       int totvert;            /* number of keyframes stored for this channel */
+       BezTriple *bezt;        /* keyframes in buffer */
+} tAnimCopybufItem;
+
+
+/* This function frees any MEM_calloc'ed copy/paste buffer data */
+// XXX find some header to put this in!
+void free_anim_copybuf (void)
+{
+       tAnimCopybufItem *aci, *acn;
+       
+       /* free each buffer element */
+       for (aci= animcopybuf.first; aci; aci= acn) {
+               acn= aci->next;
+               
+               /* free keyframes */
+               if (aci->bezt) 
+                       MEM_freeN(aci->bezt);
                        
-                       /* round 1: calculate previous and next */ 
-                       tsb= tarray;
-                       for (i=0; i < totSel; i++, tsb++) {
-                               /* don't touch end points (otherwise, curves slowly explode) */
-                               if (ELEM(i, 0, (totSel-1)) == 0) {
-                                       const tSmooth_Bezt *tP1 = tsb - 1;
-                                       const tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL);
-                                       const tSmooth_Bezt *tN1 = tsb + 1;
-                                       const tSmooth_Bezt *tN2 = (i+2 < totSel) ? (tsb + 2) : (NULL);
-                                       
-                                       const float p1 = *tP1->h2;
-                                       const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2);
-                                       const float c1 = *tsb->h2;
-                                       const float n1 = *tN1->h2;
-                                       const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2);
-                                       
-                                       /* calculate previous and next */
-                                       *tsb->h1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12;
-                                       *tsb->h3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12;
+               /* free RNA-path */
+               if (aci->rna_path)
+                       MEM_freeN(aci->rna_path);
+                       
+               /* free ourself */
+               BLI_freelinkN(&animcopybuf, aci);
+       }
+       
+       /* restore initial state */
+       animcopybuf.first= animcopybuf.last= NULL;
+       animcopy_firstframe= 999999999.0f;
+}
+
+/* ------------------- */
+
+/* This function adds data to the keyframes copy/paste buffer, freeing existing data first */
+short copy_animedit_keys (bAnimContext *ac, ListBase *anim_data)
+{      
+       bAnimListElem *ale;
+       
+       /* clear buffer first */
+       free_anim_copybuf();
+       
+       /* assume that each of these is an F-Curve */
+       for (ale= anim_data->first; ale; ale= ale->next) {
+               FCurve *fcu= (FCurve *)ale->key_data;
+               tAnimCopybufItem *aci;
+               BezTriple *bezt, *newbuf;
+               int i;
+               
+               /* firstly, check if F-Curve has any selected keyframes
+                *      - skip if no selected keyframes found (so no need to create unnecessary copy-buffer data)
+                *      - this check should also eliminate any problems associated with using sample-data
+                */
+               if (ANIM_fcurve_keys_bezier_loop(NULL, fcu, NULL, ANIM_editkeyframes_ok(BEZT_OK_SELECTED), NULL) == 0)
+                       continue;
+               
+               /* init copybuf item info */
+               aci= MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem");
+               aci->id= ale->id;
+               aci->grp= fcu->grp;
+               aci->rna_path= MEM_dupallocN(fcu->rna_path);
+               aci->array_index= fcu->array_index;
+               BLI_addtail(&animcopybuf, aci);
+               
+               /* add selected keyframes to buffer */
+               // TODO: currently, we resize array everytime we add a new vert - this works ok as long as it is assumed only a few keys are copied
+               for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
+                       if (BEZSELECTED(bezt)) {
+                               /* add to buffer */
+                               newbuf= MEM_callocN(sizeof(BezTriple)*(aci->totvert+1), "copybuf beztriple");
+                               
+                               /* assume that since we are just resizing the array, just copy all existing data across */
+                               if (aci->bezt)
+                                       memcpy(newbuf, aci->bezt, sizeof(BezTriple)*(aci->totvert));
+                               
+                               /* copy current beztriple across too */
+                               *(newbuf + aci->totvert)= *bezt; 
+                               
+                               /* free old array and set the new */
+                               if (aci->bezt) MEM_freeN(aci->bezt);
+                               aci->bezt= newbuf;
+                               aci->totvert++;
+                               
+                               /* check if this is the earliest frame encountered so far */
+                               if (bezt->vec[1][0] < animcopy_firstframe)
+                                       animcopy_firstframe= bezt->vec[1][0];
+                       }
+               }
+               
+       }
+       
+       /* check if anything ended up in the buffer */
+       if (ELEM(NULL, animcopybuf.first, animcopybuf.last))
+               return -1;
+       
+       /* everything went fine */
+       return 0;
+}
+
+/* This function pastes data from the keyframes copy/paste buffer */
+short paste_animedit_keys (bAnimContext *ac, ListBase *anim_data)
+{
+       bAnimListElem *ale;
+       const Scene *scene= (ac->scene);
+       const float offset = (float)(CFRA - animcopy_firstframe);
+       short no_name= 0;
+       
+       /* check if buffer is empty */
+       if (ELEM(NULL, animcopybuf.first, animcopybuf.last)) {
+               //error("No data in buffer to paste");
+               return -1;
+       }
+       /* check if single channel in buffer (disregard names if so)  */
+       if (animcopybuf.first == animcopybuf.last)
+               no_name= 1;
+       
+       /* from selected channels */
+       for (ale= anim_data->first; ale; ale= ale->next) {
+               FCurve *fcu = (FCurve *)ale->data;              /* destination F-Curve */
+               tAnimCopybufItem *aci= NULL;
+               BezTriple *bezt;
+               int i;
+               
+               /* find buffer item to paste from 
+                *      - if names don't matter (i.e. only 1 channel in buffer), don't check id/group
+                *      - if names do matter, only check if id-type is ok for now (group check is not that important)
+                *      - most importantly, rna-paths should match (array indices are unimportant for now)
+                */
+               // TODO: the matching algorithm here is pathetic!
+               for (aci= animcopybuf.first; aci; aci= aci->next) {
+                       /* check that paths exist */
+                       if (aci->rna_path && fcu->rna_path) {
+                               if (strcmp(aci->rna_path, fcu->rna_path) == 0) {
+                                       /* should be a match unless there's more than one of these */
+                                       if ((no_name) || (aci->array_index == fcu->array_index)) 
+                                               break;
                                }
                        }
-                       
-                       /* round 2: calculate new values and reset handles */
-                       tsb= tarray;
-                       for (i=0; i < totSel; i++, tsb++) {
-                               /* calculate new position by averaging handles */
-                               *tsb->h2 = (*tsb->h1 + *tsb->h3) / 2;
+               }
+               
+               
+               /* copy the relevant data from the matching buffer curve */
+               if (aci) {
+                       /* just start pasting, with the the first keyframe on the current frame, and so on */
+                       for (i=0, bezt=aci->bezt; i < aci->totvert; i++, bezt++) {                                              
+                               /* temporarily apply offset to src beztriple while copying */
+                               bezt->vec[0][0] += offset;
+                               bezt->vec[1][0] += offset;
+                               bezt->vec[2][0] += offset;
                                
-                               /* reset handles now */
-                               *tsb->h1 = *tsb->h2;
-                               *tsb->h3 = *tsb->h2;
+                               /* insert the keyframe */
+                               insert_bezt_fcurve(fcu, bezt);
+                               
+                               /* un-apply offset from src beztriple after copying */
+                               bezt->vec[0][0] -= offset;
+                               bezt->vec[1][0] -= offset;
+                               bezt->vec[2][0] -= offset;
                        }
                        
-                       /* free memory required for tarray */
-                       MEM_freeN(tarray);
+                       /* recalculate F-Curve's handles? */
+                       calchandles_fcurve(fcu);
                }
        }
        
-       /* recalculate handles */
-       calchandles_fcurve(fcu);
+       return 0;
 }
 
 /* **************************************************** */