NLA SoC: Start of 'Meta' Strips
authorJoshua Leung <aligorith@gmail.com>
Mon, 6 Jul 2009 03:44:44 +0000 (03:44 +0000)
committerJoshua Leung <aligorith@gmail.com>
Mon, 6 Jul 2009 03:44:44 +0000 (03:44 +0000)
Refactored the backend code/API's to support 'meta' strips (i.e. strips containing other strips). These have been implemented to be nested to 'unlimited' depths (in terms of common usages that is, though there is a very remote chance of stack-overflow in theoretrical evil cases only that shouldn't ever be encountered in production).

This paves the way for implementing the necessary tweaks needed for the transform code (in addition to some cool user-level tricks)

source/blender/blenkernel/BKE_nla.h
source/blender/blenkernel/intern/anim_sys.c
source/blender/blenkernel/intern/nla.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/space_nla/nla_edit.c
source/blender/editors/space_nla/nla_intern.h
source/blender/makesdna/DNA_anim_types.h

index e2b1dd89debf75d552b4266ea257a4abfeeb75f9..efa0591bd53c029d12abb208774af6c039035f9f 100644 (file)
@@ -53,6 +53,13 @@ struct NlaStrip *add_nlastrip_to_stack(struct AnimData *adt, struct bAction *act
 /* ----------------------------- */
 /* API */
 
+short BKE_nlastrips_has_space(ListBase *strips, float start, float end);
+void BKE_nlastrips_sort_strips(ListBase *strips);
+
+short BKE_nlastrips_add_strip(ListBase *strips, struct NlaStrip *strip);
+
+/* ............ */
+
 struct NlaTrack *BKE_nlatrack_find_active(ListBase *tracks);
 void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt);
 
@@ -63,6 +70,7 @@ void BKE_nlatrack_sort_strips(struct NlaTrack *nlt);
 
 short BKE_nlatrack_add_strip(struct NlaTrack *nlt, struct NlaStrip *strip);
 
+/* ............ */
 
 struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt);
 short BKE_nlastrip_within_bounds(struct NlaStrip *strip, float min, float max);
index 9befe9dc9cbebd99ad99f8fdb824cc0a46863f26..1d10744ac80434d863c91e20042aa5396cae365f 100644 (file)
@@ -628,15 +628,13 @@ static void nlastrip_evaluate_controls (NlaStrip *strip, float ctime)
 }
 
 
-/* gets the strip active at the current time for a track for evaluation purposes */
-static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index, float ctime)
+/* gets the strip active at the current time for a given list of strips */
+static NlaStrip *ctime_get_strip (ListBase *strips, short *side, float ctime)
 {
        NlaStrip *strip, *estrip=NULL;
-       NlaEvalStrip *nes;
-       short side= 0;
        
        /* loop over strips, checking if they fall within the range */
-       for (strip= nlt->strips.first; strip; strip= strip->next) {
+       for (strip= strips->first; strip; strip= strip->next) {
                /* check if current time occurs within this strip  */
                if (IN_RANGE_INCL(ctime, strip->start, strip->end)) {
                        /* this strip is active, so try to use it */
@@ -647,13 +645,13 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index
                
                /* if time occurred before current strip... */
                if (ctime < strip->start) {
-                       if (strip == nlt->strips.first) {
+                       if (strip == strips->first) {
                                /* before first strip - only try to use it if it extends backwards in time too */
                                if (strip->extendmode == NLASTRIP_EXTEND_HOLD)
                                        estrip= strip;
                                        
                                /* side is 'before' regardless of whether there's a useful strip */
-                               side= NES_TIME_BEFORE;
+                               *side= NES_TIME_BEFORE;
                        }
                        else {
                                /* before next strip - previous strip has ended, but next hasn't begun, 
@@ -665,7 +663,7 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index
                                
                                if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
                                        estrip= strip;
-                               side= NES_TIME_AFTER;
+                               *side= NES_TIME_AFTER;
                        }
                        break;
                }
@@ -673,11 +671,11 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index
                /* if time occurred after current strip... */
                if (ctime > strip->end) {
                        /* only if this is the last strip should we do anything, and only if that is being held */
-                       if (strip == nlt->strips.last) {
+                       if (strip == strips->last) {
                                if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
                                        estrip= strip;
                                        
-                               side= NES_TIME_AFTER;
+                               *side= NES_TIME_AFTER;
                                break;
                        }
                        
@@ -685,6 +683,35 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index
                }
        }
        
+       /* return the matching strip found */
+       return estrip;
+}
+
+/* gets the strip active at the current time for a track for evaluation purposes */
+static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index, float ctime)
+{
+       ListBase *strips= &nlt->strips;
+       NlaStrip *strip, *estrip=NULL;
+       NlaEvalStrip *nes;
+       short side= 0;
+       
+       /* keep looping over hierarchy of strips until one which fits for the current time is found */
+       while (strips->first) {
+               /* try to get the strip at this frame for this strip */
+               strip= ctime_get_strip(strips, &side, ctime);
+               
+               /* if a strip was found, make this the new estrip, otherwise, stop trying */
+               if (strip) {
+                       /* set new estrip */
+                       estrip= strip;
+                       
+                       /* check children (only available if this is a meta-strip) for better match */
+                       strips= &strip->strips;
+               }
+               else
+                       break;
+       }
+       
        /* check if a valid strip was found
         *      - must not be muted (i.e. will have contribution
         */
index 1244b2900fd129ef40718aba2ba18c8627e613fc..d01fa2c1965061e9e7df5d366a07b2c722b7b18e 100644 (file)
  */
 void free_nlastrip (ListBase *strips, NlaStrip *strip)
 {
+       NlaStrip *cs, *csn;
+       
        /* sanity checks */
        if (strip == NULL)
                return;
                
+       /* free child-strips */
+       for (cs= strip->strips.first; cs; cs= csn) {
+               csn= cs->next;
+               free_nlastrip(&strip->strips, cs);
+       }
+               
        /* remove reference to action */
        if (strip->act)
                strip->act->id.us--;
@@ -144,6 +152,7 @@ void free_nladata (ListBase *tracks)
 NlaStrip *copy_nlastrip (NlaStrip *strip)
 {
        NlaStrip *strip_d;
+       NlaStrip *cs, *cs_d;
        
        /* sanity check */
        if (strip == NULL)
@@ -161,6 +170,14 @@ NlaStrip *copy_nlastrip (NlaStrip *strip)
        copy_fcurves(&strip_d->fcurves, &strip->fcurves);
        copy_fmodifiers(&strip_d->modifiers, &strip->modifiers);
        
+       /* make a copy of all the child-strips, one at a time */
+       strip_d->strips.first= strip_d->strips.last= NULL;
+       
+       for (cs= strip->strips.first; cs; cs= cs->next) {
+               cs_d= copy_nlastrip(cs);
+               BLI_addtail(&strip_d->strips, cs_d);
+       }
+       
        /* return the strip */
        return strip_d;
 }
@@ -435,6 +452,7 @@ static float nlastrip_get_frame_transition (NlaStrip *strip, float cframe, short
 float nlastrip_get_frame (NlaStrip *strip, float cframe, short mode)
 {
        switch (strip->type) {
+               case NLASTRIP_TYPE_META: /* meta (is just a container for other strips, so shouldn't use the action-clip method) */
                case NLASTRIP_TYPE_TRANSITION: /* transition */
                        return nlastrip_get_frame_transition(strip, cframe, mode);
                
@@ -487,6 +505,117 @@ float BKE_nla_tweakedit_remap (AnimData *adt, float cframe, short mode)
 /* *************************************************** */
 /* Basic Utilities */
 
+/* List of Strips ------------------------------------ */
+/* (these functions are used for NLA-Tracks and also for nested/meta-strips) */
+
+/* Check if there is any space in the given list to add the given strip */
+short BKE_nlastrips_has_space (ListBase *strips, float start, float end)
+{
+       NlaStrip *strip;
+       
+       /* sanity checks */
+       if ((strips == NULL) || IS_EQ(start, end))
+               return 0;
+       if (start > end) {
+               puts("BKE_nlastrips_has_space() error... start and end arguments swapped");
+               SWAP(float, start, end);
+       }
+       
+       /* loop over NLA strips checking for any overlaps with this area... */
+       for (strip= strips->first; strip; strip= strip->next) {
+               /* if start frame of strip is past the target end-frame, that means that
+                * we've gone past the window we need to check for, so things are fine
+                */
+               if (strip->start > end)
+                       return 1;
+               
+               /* if the end of the strip is greater than either of the boundaries, the range
+                * must fall within the extents of the strip
+                */
+               if ((strip->end > start) || (strip->end > end))
+                       return 0;
+       }
+       
+       /* if we are still here, we haven't encountered any overlapping strips */
+       return 1;
+}
+
+/* Rearrange the strips in the track so that they are always in order 
+ * (usually only needed after a strip has been moved) 
+ */
+void BKE_nlastrips_sort_strips (ListBase *strips)
+{
+       ListBase tmp = {NULL, NULL};
+       NlaStrip *strip, *sstrip;
+       
+       /* sanity checks */
+       if ELEM(NULL, strips, strips->first)
+               return;
+               
+       /* we simply perform insertion sort on this list, since it is assumed that per track,
+        * there are only likely to be at most 5-10 strips
+        */
+       for (strip= strips->first; strip; strip= strip->next) {
+               short not_added = 1;
+               
+               /* remove this strip from the list, and add it to the new list, searching from the end of 
+                * the list, assuming that the lists are in order 
+                */
+               BLI_remlink(strips, strip);
+               
+               for (sstrip= tmp.last; not_added && sstrip; sstrip= sstrip->prev) {
+                       /* check if add after */
+                       if (sstrip->end < strip->start) {
+                               BLI_insertlinkafter(&tmp, sstrip, strip);
+                               not_added= 0;
+                               break;
+                       }
+               }
+               
+               /* add before first? */
+               if (not_added)
+                       BLI_addhead(&tmp, strip);
+       }
+       
+       /* reassign the start and end points of the strips */
+       strips->first= tmp.first;
+       strips->last= tmp.last;
+}
+
+/* Add the given NLA-Strip to the given list of strips, assuming that it 
+ * isn't currently a member of another list
+ */
+short BKE_nlastrips_add_strip (ListBase *strips, NlaStrip *strip)
+{
+       NlaStrip *ns;
+       short not_added = 1;
+       
+       /* sanity checks */
+       if ELEM(NULL, strips, strip)
+               return 0;
+               
+       /* check if any space to add */
+       if (BKE_nlastrips_has_space(strips, strip->start, strip->end)==0)
+               return 0;
+       
+       /* find the right place to add the strip to the nominated track */
+       for (ns= strips->first; ns; ns= ns->next) {
+               /* if current strip occurs after the new strip, add it before */
+               if (ns->start > strip->end) {
+                       BLI_insertlinkbefore(strips, ns, strip);
+                       not_added= 0;
+                       break;
+               }
+       }
+       if (not_added) {
+               /* just add to the end of the list of the strips then... */
+               BLI_addtail(strips, strip);
+       }
+       
+       /* added... */
+       return 1;
+}
+
 /* NLA-Tracks ---------------------------------------- */
 
 /* Find the active NLA-track for the given stack */
@@ -560,36 +689,20 @@ void BKE_nlatrack_set_active (ListBase *tracks, NlaTrack *nlt_a)
                nlt_a->flag |= NLATRACK_ACTIVE;
 }
 
-/* Check if there is any space in the last track to add the given strip */
+
+/* Check if there is any space in the given track to add a strip of the given length */
 short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end)
 {
-       NlaStrip *strip;
-       
        /* sanity checks */
        if ((nlt == NULL) || IS_EQ(start, end))
                return 0;
        if (start > end) {
-               puts("BKE_nlatrack_has_space error... start and end arguments swapped");
+               puts("BKE_nlatrack_has_space() error... start and end arguments swapped");
                SWAP(float, start, end);
        }
        
-       /* loop over NLA strips checking for any overlaps with this area... */
-       for (strip= nlt->strips.first; strip; strip= strip->next) {
-               /* if start frame of strip is past the target end-frame, that means that
-                * we've gone past the window we need to check for, so things are fine
-                */
-               if (strip->start > end)
-                       return 1;
-               
-               /* if the end of the strip is greater than either of the boundaries, the range
-                * must fall within the extents of the strip
-                */
-               if ((strip->end > start) || (strip->end > end))
-                       return 0;
-       }
-       
-       /* if we are still here, we haven't encountered any overlapping strips */
-       return 1;
+       /* check if there's any space left in the track for a strip of the given length */
+       return BKE_nlastrips_has_space(&nlt->strips, start, end);
 }
 
 /* Rearrange the strips in the track so that they are always in order 
@@ -597,41 +710,12 @@ short BKE_nlatrack_has_space (NlaTrack *nlt, float start, float end)
  */
 void BKE_nlatrack_sort_strips (NlaTrack *nlt)
 {
-       ListBase tmp = {NULL, NULL};
-       NlaStrip *strip, *sstrip;
-       
        /* sanity checks */
        if ELEM(NULL, nlt, nlt->strips.first)
                return;
-               
-       /* we simply perform insertion sort on this list, since it is assumed that per track,
-        * there are only likely to be at most 5-10 strips
-        */
-       for (strip= nlt->strips.first; strip; strip= strip->next) {
-               short not_added = 1;
-               
-               /* remove this strip from the list, and add it to the new list, searching from the end of 
-                * the list, assuming that the lists are in order 
-                */
-               BLI_remlink(&nlt->strips, strip);
-               
-               for (sstrip= tmp.last; not_added && sstrip; sstrip= sstrip->prev) {
-                       /* check if add after */
-                       if (sstrip->end < strip->start) {
-                               BLI_insertlinkafter(&tmp, sstrip, strip);
-                               not_added= 0;
-                               break;
-                       }
-               }
-               
-               /* add before first? */
-               if (not_added)
-                       BLI_addhead(&tmp, strip);
-       }
        
-       /* reassign the start and end points of the strips */
-       nlt->strips.first= tmp.first;
-       nlt->strips.last= tmp.last;
+       /* sort the strips with a more generic function */
+       BKE_nlastrips_sort_strips(&nlt->strips);
 }
 
 /* Add the given NLA-Strip to the given NLA-Track, assuming that it 
@@ -639,33 +723,12 @@ void BKE_nlatrack_sort_strips (NlaTrack *nlt)
  */
 short BKE_nlatrack_add_strip (NlaTrack *nlt, NlaStrip *strip)
 {
-       NlaStrip *ns;
-       short not_added = 1;
-       
        /* sanity checks */
        if ELEM(NULL, nlt, strip)
                return 0;
                
-       /* check if any space to add */
-       if (BKE_nlatrack_has_space(nlt, strip->start, strip->end)==0)
-               return 0;
-       
-       /* find the right place to add the strip to the nominated track */
-       for (ns= nlt->strips.first; ns; ns= ns->next) {
-               /* if current strip occurs after the new strip, add it before */
-               if (ns->start > strip->end) {
-                       BLI_insertlinkbefore(&nlt->strips, ns, strip);
-                       not_added= 0;
-                       break;
-               }
-       }
-       if (not_added) {
-               /* just add to the end of the list of the strips then... */
-               BLI_addtail(&nlt->strips, strip);
-       }
-       
-       /* added... */
-       return 1;
+       /* try to add the strip to the track using a more generic function */
+       return BKE_nlastrips_add_strip(&nlt->strips, strip);
 }
 
 /* NLA Strips -------------------------------------- */
index beebf58b6c00164c0d6f8a0323c1230a90b8803c..956c8e0042e910836614952699ccfe228445c124 100644 (file)
@@ -1826,18 +1826,48 @@ static void direct_link_action(FileData *fd, bAction *act)
        }
 }
 
+static void lib_link_nladata_strips(FileData *fd, ID *id, ListBase *list)
+{
+       NlaStrip *strip;
+       
+       for (strip= list->first; strip; strip= strip->next) {
+               /* check strip's children */
+               lib_link_nladata_strips(fd, id, &strip->strips);
+               
+               /* reassign the counted-reference to action */
+               strip->act = newlibadr_us(fd, id->lib, strip->act);
+       }
+}
 
-static void lib_link_nladata (FileData *fd, ID *id, ListBase *list)
+static void lib_link_nladata(FileData *fd, ID *id, ListBase *list)
 {
        NlaTrack *nlt;
-       NlaStrip *strip;
        
-       /* we only acare about the NLA strips inside the tracks */
+       /* we only care about the NLA strips inside the tracks */
        for (nlt= list->first; nlt; nlt= nlt->next) {
-               for (strip= nlt->strips.first; strip; strip= strip->next) {
-                       /* reassign the counted-reference to action */
-                       strip->act = newlibadr_us(fd, id->lib, strip->act);
-               }
+               lib_link_nladata_strips(fd, id, &nlt->strips);
+       }
+}
+
+/* This handles Animato NLA-Strips linking 
+ * NOTE: this assumes that link_list has already been called on the list 
+ */
+static void direct_link_nladata_strips(FileData *fd, ListBase *list)
+{
+       NlaStrip *strip;
+       
+       for (strip= list->first; strip; strip= strip->next) {
+               /* strip's child strips */
+               link_list(fd, &strip->strips);
+               direct_link_nladata_strips(fd, &strip->strips);
+               
+               /* strip's F-Curves */
+               link_list(fd, &strip->fcurves);
+               direct_link_fcurves(fd, &strip->fcurves);
+               
+               /* strip's F-Modifiers */
+               link_list(fd, &strip->modifiers);
+               direct_link_fcurves(fd, &strip->modifiers);
        }
 }
 
@@ -1845,22 +1875,13 @@ static void lib_link_nladata (FileData *fd, ID *id, ListBase *list)
 static void direct_link_nladata(FileData *fd, ListBase *list)
 {
        NlaTrack *nlt;
-       NlaStrip *strip;
        
        for (nlt= list->first; nlt; nlt= nlt->next) {
                /* relink list of strips */
                link_list(fd, &nlt->strips);
                
                /* relink strip data */
-               for (strip= nlt->strips.first; strip; strip= strip->next) {
-                       /* strip's F-Curves */
-                       link_list(fd, &strip->fcurves);
-                       direct_link_fcurves(fd, &strip->fcurves);
-                       
-                       /* strip's F-Modifiers */
-                       link_list(fd, &strip->modifiers);
-                       direct_link_fcurves(fd, &strip->modifiers);
-               }
+               direct_link_nladata_strips(fd, &nlt->strips);
        }
 }
 
@@ -9560,11 +9581,23 @@ static void expand_keyingsets(FileData *fd, Main *mainvar, ListBase *list)
        }
 }
 
+static void expand_animdata_nlastrips(FileData *fd, Main *mainvar, ListBase *list)
+{
+       NlaStrip *strip;
+       
+       for (strip= list->first; strip; strip= strip->next) {
+               /* check child strips */
+               expand_animdata_nlastrips(fd, mainvar, &strip->strips);
+               
+               /* relink referenced action */
+               expand_doit(fd, mainvar, strip->act);
+       }
+}
+
 static void expand_animdata(FileData *fd, Main *mainvar, AnimData *adt)
 {
        FCurve *fcd;
        NlaTrack *nlt;
-       NlaStrip *strip;
        
        /* own action */
        expand_doit(fd, mainvar, adt->action);
@@ -9580,10 +9613,8 @@ static void expand_animdata(FileData *fd, Main *mainvar, AnimData *adt)
        }
        
        /* nla-data - referenced actions */
-       for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
-               for (strip= nlt->strips.first; strip; strip= strip->next) 
-                       expand_doit(fd, mainvar, strip->act);
-       }
+       for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) 
+               expand_animdata_nlastrips(fd, mainvar, &nlt->strips);
 }      
 
 static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSettings *part)
index 80d1d78257b6123128f6205d088567e86cfaf965..bfdd89e38b13f18ba75aa593667f6fe52d04836f 100644 (file)
@@ -916,26 +916,34 @@ static void write_keyingsets(WriteData *wd, ListBase *list)
        }
 }
 
+static void write_nlastrips(WriteData *wd, ListBase *strips)
+{
+       NlaStrip *strip;
+       
+       for (strip= strips->first; strip; strip= strip->next) {
+               /* write the strip first */
+               writestruct(wd, DATA, "NlaStrip", 1, strip);
+               
+               /* write the strip's F-Curves and modifiers */
+               write_fcurves(wd, &strip->fcurves);
+               write_fmodifiers(wd, &strip->modifiers);
+               
+               /* write the strip's children */
+               write_nlastrips(wd, &strip->strips);
+       }
+}
+
 static void write_nladata(WriteData *wd, ListBase *nlabase)
 {
        NlaTrack *nlt;
-       NlaStrip *strip;
        
        /* write all the tracks */
        for (nlt= nlabase->first; nlt; nlt= nlt->next) {
                /* write the track first */
                writestruct(wd, DATA, "NlaTrack", 1, nlt);
                
-               for (strip= nlt->strips.first; strip; strip= strip->next) {
-                       /* write the strip first */
-                       writestruct(wd, DATA, "NlaStrip", 1, strip);
-                       
-                       /* write the strip's F-Curves and modifiers */
-                       write_fcurves(wd, &strip->fcurves);
-                       write_fmodifiers(wd, &strip->modifiers);
-                       
-                       // TODO write the remaps
-               }
+               /* write the track's strips */
+               write_nlastrips(wd, &nlt->strips);
        }
 }
 
index 10b25beddff198324d06d711b4a81b836d7dd850..e95d0b1a50a5624dee126134d375ccfed795aa90 100644 (file)
@@ -734,8 +734,6 @@ static int nlaedit_move_up_exec (bContext *C, wmOperator *op)
        bAnimListElem *ale;
        int filter;
        
-       BeztEditData bed;
-       
        /* get editor data */
        if (ANIM_animdata_get_context(C, &ac) == 0)
                return OPERATOR_CANCELLED;
@@ -744,9 +742,6 @@ static int nlaedit_move_up_exec (bContext *C, wmOperator *op)
        filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
        ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
        
-       /* init the editing data */
-       memset(&bed, 0, sizeof(BeztEditData));
-       
        /* since we're potentially moving strips from lower tracks to higher tracks, we should
         * loop over the tracks in reverse order to avoid moving earlier strips up multiple tracks
         */
@@ -811,8 +806,6 @@ static int nlaedit_move_down_exec (bContext *C, wmOperator *op)
        bAnimListElem *ale;
        int filter;
        
-       BeztEditData bed;
-       
        /* get editor data */
        if (ANIM_animdata_get_context(C, &ac) == 0)
                return OPERATOR_CANCELLED;
@@ -821,9 +814,6 @@ static int nlaedit_move_down_exec (bContext *C, wmOperator *op)
        filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
        ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
        
-       /* init the editing data */
-       memset(&bed, 0, sizeof(BeztEditData));
-       
        /* loop through the tracks in normal order, since we're pushing strips down,
         * strips won't get operated on twice
         */
@@ -1037,6 +1027,116 @@ void NLA_OT_clear_scale (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+/* ******************** Snap Strips Operator ************************** */
+/* Moves the start-point of the selected strips to the specified places */
+
+/* defines for snap keyframes tool */
+EnumPropertyItem prop_nlaedit_snap_types[] = {
+       {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current frame", ""},
+       {NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
+       {NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
+       {NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+static int nlaedit_snap_exec (bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       Scene *scene= ac.scene;
+       int mode = RNA_enum_get(op->ptr, "type");
+       const float secf = (float)FPS;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* get a list of the editable tracks being shown in the NLA */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
+       ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+       
+       /* since we may add tracks, perform this in reverse order */
+       for (ale= anim_data.last; ale; ale= ale->prev) {
+               ListBase tmp_strips = {NULL, NULL};
+               NlaTrack *nlt= (NlaTrack *)ale->data;
+               NlaStrip *strip, *stripn;
+               
+               /* first pass: move all selected strips to a separate buffer, and apply snapping to them */
+               for (strip= nlt->strips.first; strip; strip= stripn) {
+                       stripn= strip->next;
+                       
+                       if (strip->flag & NLASTRIP_FLAG_SELECT) {
+                               float start, end;
+                               
+                               /* get the existing end-points */
+                               start= strip->start;
+                               end= strip->end;
+                               
+                               /* calculate new start position based on snapping mode */
+                               switch (mode) {
+                                       case NLAEDIT_SNAP_CFRA: /* to current frame */
+                                               strip->start= (float)CFRA;
+                                               break;
+                                       case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
+                                               strip->start= (float)(floor(start+0.5));
+                                               break;
+                                       case NLAEDIT_SNAP_NEAREST_SECOND: /* to nearest second */
+                                               strip->start= ((float)floor(start/secf + 0.5f) * secf);
+                                               break;
+                                       case NLAEDIT_SNAP_NEAREST_MARKER: /* to nearest marker */
+                                               strip->start= (float)ED_markers_find_nearest_marker_time(ac.markers, start);
+                                               break;
+                                       default: /* just in case... no snapping */
+                                               strip->start= start;
+                                               break;
+                               }
+                               
+                               /* get new endpoint based on start-point (and old length) */
+                               strip->end= strip->start + (end - start);
+                               
+                               /* remove strip from track, and add to the temp buffer */
+                               BLI_remlink(&nlt->strips, strip);
+                               BLI_addtail(&tmp_strips, strip);
+                       }
+               }
+               
+               // TODO: finish this...
+       }
+       
+       /* free temp data */
+       BLI_freelistN(&anim_data);
+       
+       /* set notifier that things have changed */
+       ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
+       WM_event_add_notifier(C, NC_SCENE, NULL);
+       
+       /* done */
+       return OPERATOR_FINISHED;
+}
+
+void NLA_OT_snap (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Snap Strips";
+       ot->idname= "NLA_OT_snap";
+       ot->description= "Move start of strips to specified time.";
+       
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= nlaedit_snap_exec;
+       ot->poll= nlaop_poll_tweakmode_off;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_enum(ot->srna, "type", prop_nlaedit_snap_types, 0, "Type", "");
+}
+
 /* *********************************************** */
 /* NLA Modifiers */
 
index 5921b8a75cefdb5f7f29339e015b6bdab3e77322..422686bb4244f5242aa4e5765fca654edb3c42b0 100644 (file)
@@ -87,6 +87,17 @@ void NLA_OT_click_select(wmOperatorType *ot);
 /* **************************************** */
 /* nla_edit.c */
 
+/* defines for snap strips
+ */
+enum {
+       NLAEDIT_SNAP_CFRA = 1,
+       NLAEDIT_SNAP_NEAREST_FRAME,
+       NLAEDIT_SNAP_NEAREST_SECOND,
+       NLAEDIT_SNAP_NEAREST_MARKER,    
+} eNlaEdit_Snap_Mode;
+
+/* --- */
+
 void NLA_OT_tweakmode_enter(wmOperatorType *ot);
 void NLA_OT_tweakmode_exit(wmOperatorType *ot);
 
index a90fad983c491f06ba89cc449b0842751ca97fa1..a8220099a1195d42c6194823b728ec196b3344e6 100644 (file)
@@ -438,11 +438,13 @@ typedef struct AnimMapper {
 typedef struct NlaStrip {
        struct NlaStrip *next, *prev;
        
+       ListBase strips;                        /* 'Child' strips (used for 'meta' strips) */
        bAction *act;                           /* Action that is referenced by this strip (strip is 'user' of the action) */
        AnimMapper *remap;                      /* Remapping info this strip (for tweaking correspondance of action with context) */
        
        ListBase fcurves;                       /* F-Curves for controlling this strip's influence and timing */        // TODO: move out?
        ListBase modifiers;                     /* F-Curve modifiers to be applied to the entire strip's referenced F-Curves */
+       
        float influence;                        /* Influence of strip */
        float strip_time;                       /* Current 'time' within action being used (automatically evaluated, but can be overridden) */
        
@@ -505,6 +507,11 @@ enum {
        NLASTRIP_FLAG_MUTED                     = (1<<12),
                /* NLA strip length is synced to the length of the referenced action */
        NLASTRIP_FLAG_SYNC_LENGTH       = (1<<13),
+       
+       /* temporary editing flags */
+               /* NLA-Strip is really just a temporary meta used to facilitate easier transform code */
+       NLASTRIP_FLAG_TEMP_META         = (1<<30),
+       NLASTRIP_FLAG_EDIT_TOUCHED      = (1<<31),
 } eNlaStrip_Flag;
 
 /* NLA Strip Type */
@@ -513,6 +520,8 @@ enum {
        NLASTRIP_TYPE_CLIP      = 0,
                /* 'transition' - blends between the adjacent strips */
        NLASTRIP_TYPE_TRANSITION,
+               /* 'meta' - a strip which acts as a container for a few others */
+       NLASTRIP_TYPE_META,
 } eNlaStrip_Type;
 
 /* NLA Tracks ------------------------------------- */