NLA SoC: Transition Strips + Strip Adding Operators + Bugfixes
authorJoshua Leung <aligorith@gmail.com>
Fri, 19 Jun 2009 04:45:56 +0000 (04:45 +0000)
committerJoshua Leung <aligorith@gmail.com>
Fri, 19 Jun 2009 04:45:56 +0000 (04:45 +0000)
== Transitions ==
Transition strips are now able to be created + evaluated. Transitions allow for interpolation between the endpoints of two adjacent strips in the same track (i.e. two strips which occur in the same track one after the other, but with a gap between them).

- The current behaviour when only one endpoint affects some setting is non-optimal, since it appears somewhat inconsistently extend/replace values...
- Transform code needs a few fixes still to deal with these

== Strip Adding Operators ==
* New strips referencing Actions can be added using the Shift-A hotkey while in the strips-area. You must have a track selected first though.
The new strip will get added, starting from the current frame, in the selected track(s) only if there is enough space to do so. Otherwise, the new strip gets added at the top of the stack in a new track.

* New transition strips can be added with the Shift-T hotkey while in the strips area. You must have two adjacent strips selected for this to work.

== New Backend Methods ==
* Recoded the strip/track adding API to be more flexible
* Added a new method for testing whether F-Curve has any modifiers of with certain attributes. Will be used in a later bugfix...

== Bugfixes ==
- Fixed bug with strip-blending which caused the blending modes to be useless.
- NLA buttons now use proper poll callbacks instead of defining checks
- Commented out missing operator in menus, silencing warnings in console
- Removed obsolete/incorrect comments

source/blender/blenkernel/BKE_fcurve.h
source/blender/blenkernel/BKE_nla.h
source/blender/blenkernel/intern/anim_sys.c
source/blender/blenkernel/intern/fcurve.c
source/blender/blenkernel/intern/nla.c
source/blender/editors/space_nla/nla_buttons.c
source/blender/editors/space_nla/nla_draw.c
source/blender/editors/space_nla/nla_edit.c
source/blender/editors/space_nla/nla_header.c
source/blender/editors/space_nla/nla_intern.h
source/blender/editors/space_nla/nla_ops.c

index 7058b9d236af83c2a0b33567898003a5defd1f45..af272e892f2984ec634fd03d7f0463e67283585e 100644 (file)
@@ -112,6 +112,8 @@ void fcurve_free_modifiers(struct FCurve *fcu);
 struct FModifier *fcurve_find_active_modifier(struct FCurve *fcu);
 void fcurve_set_active_modifier(struct FCurve *fcu, struct FModifier *fcm);
 
+short fcurve_has_suitable_modifier(FCurve *fcu, int mtype, short acttype);
+
 float evaluate_time_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float cvalue, float evaltime);
 void evaluate_value_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float *cvalue, float evaltime);
 
index 078c1ba52bb870431d01f89e5ca1883b189e6130..5200ca6d4d7989bcad08ac5d60cd7924623f2b4d 100644 (file)
@@ -61,6 +61,8 @@ void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt);
 short BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
 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 a864e3d4e875c948c9a33b07c7c58bcafdf7607f..2efb4f2b2d3458f5c615449c55ce3403c00d4a04 100644 (file)
@@ -558,13 +558,20 @@ typedef struct NlaEvalStrip {
        
        short track_index;                      /* the index of the track within the list */
        short strip_mode;                       /* which end of the strip are we looking at */
+       
+       float strip_time;                       /* time at which which strip is being evaluated */
 } NlaEvalStrip;
 
 /* NlaEvalStrip->strip_mode */
 enum {
+               /* standard evaluation */
        NES_TIME_BEFORE = -1,
        NES_TIME_WITHIN,
        NES_TIME_AFTER,
+       
+               /* transition-strip evaluations */
+       NES_TIME_TRANSITION_START,
+       NES_TIME_TRANSITION_END,
 } eNlaEvalStrip_StripMode;
 
 
@@ -583,10 +590,10 @@ typedef struct NlaEvalChannel {
 
 /* ---------------------- */
 
-/* non clipped mapping for strip-time <-> global time 
+/* non clipped mapping for strip-time <-> global time (for Action-Clips)
  *     invert = convert action-strip time to global time 
  */
-static float nlastrip_get_frame (NlaStrip *strip, float cframe, short invert)
+static float nlastrip_get_frame_actionclip (NlaStrip *strip, float cframe, short invert)
 {
        float length, actlength, repeat, scale;
        
@@ -603,8 +610,8 @@ static float nlastrip_get_frame (NlaStrip *strip, float cframe, short invert)
        if (IS_EQ(actlength, 0.0f)) actlength = 1.0f;
        
        /* length of strip */
-       length = strip->end - strip->start;
-       if (IS_EQ(length, 0.0f)) length= actlength * scale * repeat;
+       length= actlength * scale * repeat;
+       if (IS_EQ(length, 0.0f)) length= strip->end - strip->start;
        
        /* reversed = play strip backwards */
        if (strip->flag & NLASTRIP_FLAG_REVERSE) {
@@ -623,6 +630,48 @@ static float nlastrip_get_frame (NlaStrip *strip, float cframe, short invert)
        }
 }
 
+/* non clipped mapping for strip-time <-> global time (for Transitions)
+ *     invert = convert action-strip time to global time 
+ */
+static float nlastrip_get_frame_transition (NlaStrip *strip, float cframe, short invert)
+{
+       float length;
+       
+       /* length of strip */
+       length= strip->end - strip->start;
+       
+       /* reversed = play strip backwards */
+       if (strip->flag & NLASTRIP_FLAG_REVERSE) {
+               /* invert = convert within-strip-time to global time */
+               if (invert)
+                       return strip->end - (length * cframe);
+               else
+                       return (strip->end - cframe) / length;
+       }
+       else {
+               /* invert = convert within-strip-time to global time */
+               if (invert)
+                       return (length * cframe) + strip->start;
+               else
+                       return (cframe - strip->start) / length;
+       }
+}
+
+/* non clipped mapping for strip-time <-> global time
+ *     invert = convert action-strip time to global time 
+ */
+static float nlastrip_get_frame (NlaStrip *strip, float cframe, short invert)
+{
+       switch (strip->type) {
+               case NLASTRIP_TYPE_TRANSITION: /* transition */
+                       return nlastrip_get_frame_transition(strip, cframe, invert);
+               
+               case NLASTRIP_TYPE_CLIP: /* action-clip (default) */
+               default:
+                       return nlastrip_get_frame_actionclip(strip, cframe, invert);
+       }       
+}
+
 /* calculate influence of strip based for given frame based on blendin/out values */
 static float nlastrip_get_influence (NlaStrip *strip, float cframe)
 {
@@ -631,7 +680,6 @@ static float nlastrip_get_influence (NlaStrip *strip, float cframe)
        strip->blendout= (float)fabs(strip->blendout);
        
        /* result depends on where frame is in respect to blendin/out values */
-       // the +0.0001 factors are to combat rounding errors
        if (IS_EQ(strip->blendin, 0)==0 && (cframe <= (strip->start + strip->blendin))) {
                /* there is some blend-in */
                return (float)fabs(cframe - strip->start) / (strip->blendin);
@@ -746,12 +794,13 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index
         *      - negative influence is not supported yet... how would that be defined?
         */
        // TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on...
-       // TODO: should we clamp the time to only be on the endpoints of the strip?
        nlastrip_evaluate_controls(estrip, ctime);
        if (estrip->influence <= 0.0f) // XXX is it useful to invert the strip?
                return;
                
-       /* check if strip has valid data to evaluate */
+       /* check if strip has valid data to evaluate,
+        * and/or perform any additional type-specific actions
+        */
        switch (estrip->type) {
                case NLASTRIP_TYPE_CLIP: 
                        /* clip must have some action to evaluate */
@@ -760,9 +809,12 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index
                        break;
                case NLASTRIP_TYPE_TRANSITION:
                        /* there must be strips to transition from and to (i.e. prev and next required) */
-                       // TODO: what happens about cross-track transitions? 
                        if (ELEM(NULL, estrip->prev, estrip->next))
                                return;
+                               
+                       /* evaluate controls for the relevant extents of the bordering strips... */
+                       nlastrip_evaluate_controls(estrip->prev, estrip->start);
+                       nlastrip_evaluate_controls(estrip->next, estrip->end);
                        break;
        }
        
@@ -773,6 +825,7 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index
        nes->strip= estrip;
        nes->strip_mode= side;
        nes->track_index= index;
+       nes->strip_time= estrip->strip_time;
        
        BLI_addtail(list, nes);
 }
@@ -847,6 +900,8 @@ static NlaEvalChannel *nlaevalchan_verify (PointerRNA *ptr, ListBase *channels,
                nec->prop= prop;
                nec->index= fcu->array_index;
        }
+       else
+               *newChan= 0;
        
        /* we can now return */
        return nec;
@@ -856,6 +911,7 @@ static NlaEvalChannel *nlaevalchan_verify (PointerRNA *ptr, ListBase *channels,
 static void nlaevalchan_accumulate (NlaEvalChannel *nec, NlaEvalStrip *nes, short newChan, float value)
 {
        NlaStrip *strip= nes->strip;
+       short blendmode= strip->blendmode;
        float inf= strip->influence;
        
        /* if channel is new, just store value regardless of blending factors, etc. */
@@ -863,13 +919,19 @@ static void nlaevalchan_accumulate (NlaEvalChannel *nec, NlaEvalStrip *nes, shor
                nec->value= value;
                return;
        }
+               
+       /* if this is being performed as part of transition evaluation, incorporate
+        * an additional weighting factor for the influence
+        */
+       if (nes->strip_mode == NES_TIME_TRANSITION_END) 
+               inf *= nes->strip_time;
        
        /* premultiply the value by the weighting factor */
        if (IS_EQ(inf, 0)) return;
        value *= inf;
        
        /* perform blending */
-       switch (strip->blendmode) {
+       switch (blendmode) {
                case NLASTRIP_MODE_ADD:
                        /* simply add the scaled value on to the stack */
                        nec->value += value;
@@ -938,8 +1000,80 @@ static void nlastrip_evaluate_actionclip (PointerRNA *ptr, ListBase *channels, N
        }
 }
 
+/* evaluate transition strip */
+static void nlastrip_evaluate_transition (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes)
+{
+       ListBase tmp_channels = {NULL, NULL};
+       NlaEvalChannel *nec, *necn, *necd;
+       NlaEvalStrip tmp_nes;
+       NlaStrip *s1, *s2;
+       
+       /* get the two strips to operate on 
+        *      - we use the endpoints of the strips directly flanking our strip
+        *        using these as the endpoints of the transition (destination and source)
+        *      - these should have already been determined to be valid...
+        *      - if this strip is being played in reverse, we need to swap these endpoints
+        *        otherwise they will be interpolated wrong
+        */
+       if (nes->strip->flag & NLASTRIP_FLAG_REVERSE) {
+               s1= nes->strip->next;
+               s2= nes->strip->prev;
+       }
+       else {
+               s1= nes->strip->prev;
+               s2= nes->strip->next;
+       }
+       
+       /* prepare template for 'evaluation strip' 
+        *      - based on the transition strip's evaluation strip data
+        *      - strip_mode is NES_TIME_TRANSITION_* based on which endpoint
+        *      - strip_time is the 'normalised' (i.e. in-strip) time for evaluation,
+        *        which doubles up as an additional weighting factor for the strip influences
+        *        which allows us to appear to be 'interpolating' between the two extremes
+        */
+       tmp_nes= *nes;
+       
+       /* evaluate these strips into a temp-buffer (tmp_channels) */
+               /* first strip */
+       tmp_nes.strip_mode= NES_TIME_TRANSITION_START;
+       tmp_nes.strip= s1;
+       nlastrip_evaluate_actionclip(ptr, &tmp_channels, &tmp_nes);
+       
+               /* second strip */
+       tmp_nes.strip_mode= NES_TIME_TRANSITION_END;
+       tmp_nes.strip= s2;
+       nlastrip_evaluate_actionclip(ptr, &tmp_channels, &tmp_nes);
+       
+       
+       /* optimise - abort if no channels */
+       if (tmp_channels.first == NULL)
+               return;
+       
+       
+       /* accumulate results in tmp_channels buffer to the accumulation buffer */
+       for (nec= tmp_channels.first; nec; nec= necn) {
+               /* get pointer to next channel in case we remove the current channel from the temp-buffer */
+               necn= nec->next;
+               
+               /* try to find an existing matching channel for this setting in the accumulation buffer */
+               necd= nlaevalchan_find_match(channels, &nec->ptr, nec->prop, nec->index);
+               
+               /* if there was a matching channel already in the buffer, accumulate to it,
+                * otherwise, add the current channel to the buffer for efficiency
+                */
+               if (necd)
+                       nlaevalchan_accumulate(necd, nes, 0, nec->value);
+               else {
+                       BLI_remlink(&tmp_channels, nec);
+                       BLI_addtail(channels, nec);
+               }
+       }
+       
+       /* free temp-channels that haven't been assimilated into the buffer */
+       BLI_freelistN(&tmp_channels);
+}
+
 /* evaluates the given evaluation strip */
-// TODO: only evaluate here, but flush in one go using the accumulated channels at end...
 static void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes)
 {
        /* actions to take depend on the type of strip */
@@ -948,7 +1082,7 @@ static void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, NlaEvalStrip
                        nlastrip_evaluate_actionclip(ptr, channels, nes);
                        break;
                case NLASTRIP_TYPE_TRANSITION: /* transition */
-                       // XXX code this...
+                       nlastrip_evaluate_transition(ptr, channels, nes);
                        break;
        }
 }
index 5820761234cd9749c5475b4aafb8ccd8ddf598c8..d8b5135a1b1ae806764ce6598fd9cd3211be6315 100644 (file)
@@ -2242,6 +2242,42 @@ void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm)
                fcm->flag |= FMODIFIER_FLAG_ACTIVE;
 }
 
+/* Do we have any modifiers which match certain criteria 
+ *     - mtype - type of modifier (if 0, doesn't matter)
+ *     - acttype - type of action to perform (if -1, doesn't matter)
+ */
+short fcurve_has_suitable_modifier (FCurve *fcu, int mtype, short acttype)
+{
+       FModifier *fcm;
+       
+       /* if there are no specific filtering criteria, just skip */
+       if ((mtype == 0) && (acttype == 0))
+               return (fcu && fcu->modifiers.first);
+               
+       /* sanity checks */
+       if ELEM(NULL, fcu, fcu->modifiers.first)
+               return 0;
+               
+       /* find the first mdifier fitting these criteria */
+       for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
+               FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
+               short mOk=1, aOk=1; /* by default 1, so that when only one test, won't fail */
+               
+               /* check if applicable ones are fullfilled */
+               if (mtype)
+                       mOk= (fcm->type == mtype);
+               if (acttype > -1)
+                       aOk= (fmi->acttype == acttype);
+                       
+               /* if both are ok, we've found a hit */
+               if (mOk && aOk)
+                       return 1;
+       }
+       
+       /* no matches */
+       return 0;
+}  
+
 /* Evaluation API --------------------------- */
 
 /* evaluate time modifications imposed by some F-Curve Modifiers
index cef141280327143b81cbee933f0be7cc5ffcdfea..0684d943754f60038891a20dd8d06ef0ec2997fd 100644 (file)
@@ -293,9 +293,8 @@ NlaStrip *add_nlastrip (bAction *act)
 /* Add new NLA-strip to the top of the NLA stack - i.e. into the last track if space, or a new one otherwise */
 NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act)
 {
-       NlaStrip *strip, *ns;
+       NlaStrip *strip;
        NlaTrack *nlt;
-       short not_added = 1;
        
        /* sanity checks */
        if ELEM(NULL, adt, act)
@@ -306,36 +305,15 @@ NlaStrip *add_nlastrip_to_stack (AnimData *adt, bAction *act)
        if (strip == NULL)
                return NULL;
        
-       /* check if the last NLA-track (if it exists) has any space for this strip:
-        *      - if so, add this strip to that track
-        */
-       if ( (adt->nla_tracks.last == NULL) || 
-                (BKE_nlatrack_has_space(adt->nla_tracks.last, strip->start, strip->end)==0) ) 
-       {
-               /* no space, so add to a new track... */
+       /* firstly try adding strip to last track, but if that fails, add to a new track */
+       if (BKE_nlatrack_add_strip(adt->nla_tracks.last, strip) == 0) {
+               /* trying to add to the last track failed (no track or no space), 
+                * so add a new track to the stack, and add to that...
+                */
                nlt= add_nlatrack(adt, NULL);
-       }
-       else 
-       {
-               /* there's some space, so add to this track... */
-               nlt= adt->nla_tracks.last;
+               BKE_nlatrack_add_strip(nlt, strip);
        }
        
-       /* 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);
-       }
-       
-       
        /* returns the strip added */
        return strip;
 }
@@ -490,6 +468,40 @@ void BKE_nlatrack_sort_strips (NlaTrack *nlt)
        nlt->strips.last= tmp.last;
 }
 
+/* Add the given NLA-Strip to the given NLA-Track, assuming that it 
+ * isn't currently attached to another one 
+ */
+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;
+}
+
 /* NLA Strips -------------------------------------- */
 
 /* Find the active NLA-strip within the given track */
@@ -571,7 +583,7 @@ short nlastrip_is_first (AnimData *adt, NlaStrip *strip)
        /* should be first now */
        return 1;
 }
-
 /* Tools ------------------------------------------- */
 
 /* For the given AnimData block, add the active action to the NLA
index cb21dd669349d53b89305e30418c49f903816c71..cb76f7fc735eb93c3ce253769ef1ff89a1a41593 100644 (file)
@@ -144,11 +144,38 @@ static int nla_panel_context(const bContext *C, PointerRNA *nlt_ptr, PointerRNA
        return found;
 }
 
+#if 0
 static int nla_panel_poll(const bContext *C, PanelType *pt)
 {
        return nla_panel_context(C, NULL, NULL);
 }
+#endif
 
+static int nla_track_panel_poll(const bContext *C, PanelType *pt)
+{
+       PointerRNA ptr;
+       return (nla_panel_context(C, &ptr, NULL) && (ptr.data != NULL));
+}
+
+static int nla_strip_panel_poll(const bContext *C, PanelType *pt)
+{
+       PointerRNA ptr;
+       return (nla_panel_context(C, NULL, &ptr) && (ptr.data != NULL));
+}
+
+static int nla_strip_actclip_panel_poll(const bContext *C, PanelType *pt)
+{
+       PointerRNA ptr;
+       NlaStrip *strip;
+       
+       if (!nla_panel_context(C, NULL, &ptr))
+               return 0;
+       if (ptr.data == NULL)
+               return 0;
+       
+       strip= ptr.data;
+       return (strip->type == NLASTRIP_TYPE_CLIP);
+}
 
 /* -------------- */
 
@@ -163,8 +190,6 @@ static void nla_panel_track (const bContext *C, Panel *pa)
        /* check context and also validity of pointer */
        if (!nla_panel_context(C, &nlt_ptr, NULL))
                return;
-       if (nlt_ptr.data == NULL)
-               return;
 
        block= uiLayoutGetBlock(layout);
        uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
@@ -185,8 +210,6 @@ static void nla_panel_properties(const bContext *C, Panel *pa)
        /* check context and also validity of pointer */
        if (!nla_panel_context(C, NULL, &strip_ptr))
                return;
-       if (strip_ptr.data == NULL)
-               return;
 
        block= uiLayoutGetBlock(layout);
        uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
@@ -239,8 +262,6 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
        /* check context and also validity of pointer */
        if (!nla_panel_context(C, NULL, &strip_ptr))
                return;
-       if (strip_ptr.data == NULL)
-               return;
        
        // XXX FIXME: move this check into a poll callback
        if (RNA_enum_get(&strip_ptr, "type") != NLASTRIP_TYPE_CLIP)
@@ -279,8 +300,6 @@ static void nla_panel_evaluation(const bContext *C, Panel *pa)
        /* check context and also validity of pointer */
        if (!nla_panel_context(C, NULL, &strip_ptr))
                return;
-       if (strip_ptr.data == NULL)
-               return;
                
        block= uiLayoutGetBlock(layout);
        uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
@@ -291,6 +310,24 @@ static void nla_panel_evaluation(const bContext *C, Panel *pa)
        // animated_time
 }
 
+/* F-Modifiers for active NLA-Strip */
+static void nla_panel_modifiers(const bContext *C, Panel *pa)
+{
+       PointerRNA strip_ptr;
+       uiLayout *layout= pa->layout;
+       //uiLayout *column, *row, *subcol;
+       uiBlock *block;
+
+       /* check context and also validity of pointer */
+       if (!nla_panel_context(C, NULL, &strip_ptr))
+               return;
+               
+       block= uiLayoutGetBlock(layout);
+       uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
+               
+       // TODO...
+}
+
 /* ******************* general ******************************** */
 
 
@@ -302,35 +339,35 @@ void nla_buttons_register(ARegionType *art)
        strcpy(pt->idname, "NLA_PT_track");
        strcpy(pt->label, "Active Track");
        pt->draw= nla_panel_track;
-       pt->poll= nla_panel_poll;
+       pt->poll= nla_track_panel_poll;
        BLI_addtail(&art->paneltypes, pt);
        
        pt= MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
        strcpy(pt->idname, "NLA_PT_properties");
        strcpy(pt->label, "Active Strip");
        pt->draw= nla_panel_properties;
-       pt->poll= nla_panel_poll;
+       pt->poll= nla_strip_panel_poll;
        BLI_addtail(&art->paneltypes, pt);
        
        pt= MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
        strcpy(pt->idname, "NLA_PT_actionclip");
        strcpy(pt->label, "Action Clip");
        pt->draw= nla_panel_actclip;
-       pt->poll= nla_panel_poll; // XXX need a special one to check for 'action clip' types only
+       pt->poll= nla_strip_actclip_panel_poll;
        BLI_addtail(&art->paneltypes, pt);
        
        pt= MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation");
        strcpy(pt->idname, "NLA_PT_evaluation");
        strcpy(pt->label, "Evaluation");
        pt->draw= nla_panel_evaluation;
-       pt->poll= nla_panel_poll;
+       pt->poll= nla_strip_panel_poll;
        BLI_addtail(&art->paneltypes, pt);
        
        pt= MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers");
        strcpy(pt->idname, "NLA_PT_modifiers");
        strcpy(pt->label, "Modifiers");
-       //pt->draw= nla_panel_modifiers;
-       pt->poll= nla_panel_poll;
+       pt->draw= nla_panel_modifiers;
+       pt->poll= nla_strip_panel_poll;
        BLI_addtail(&art->paneltypes, pt);
 }
 
index 8d417a150aa0dbc83ec7987cd1b736166eb1ada2..3a3f86bb5a3135cd234252b8262b59e63b127e45 100644 (file)
@@ -202,11 +202,20 @@ static void nla_draw_strip_text (NlaTrack *nlt, NlaStrip *strip, int index, View
        char str[256];
        rctf rect;
        
-       /* for now, just init the string with a fixed-format */
-       if (strip->act)
-               sprintf(str, "%d | Act: %s | %.2f <-> %.2f", index, strip->act->id.name+2, strip->start, strip->end);
-       else
-               sprintf(str, "%d | Act: <NONE>", index);
+       /* for now, just init the string with fixed-formats */
+       switch (strip->type) {
+               case NLASTRIP_TYPE_TRANSITION: /* Transition */
+                       sprintf(str, "%d | Transition | %.2f <-> %.2f", index, strip->start, strip->end);
+                       break;
+               
+               case NLASTRIP_TYPE_CLIP:        /* Action-Clip (default) */
+               default:
+                       if (strip->act)
+                               sprintf(str, "%d | Act: %s | %.2f <-> %.2f", index, strip->act->id.name+2, strip->start, strip->end);
+                       else
+                               sprintf(str, "%d | Act: <NONE>", index); // xxx... need a better format?
+                       break;
+       }
        
        /* set text colour - if colours (see above) are light, draw black text, otherwise draw white */
        if (strip->flag & (NLASTRIP_FLAG_ACTIVE|NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_TWEAKUSER))
@@ -295,7 +304,9 @@ void draw_nla_main_data (bAnimContext *ac, SpaceNla *snla, ARegion *ar)
                                {
                                        AnimData *adt= BKE_animdata_from_id(ale->id);
                                        
-                                       /* just draw a semi-shaded rect spanning the width of the viewable area if there's data */
+                                       /* just draw a semi-shaded rect spanning the width of the viewable area if there's data,
+                                        * and a second darker rect within which we draw keyframe indicator dots if there's data
+                                        */
                                        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                                        glEnable(GL_BLEND);
                                        
index e8af67aebd120b5d70c7d54f62acb09e59304e80..2996a00517792fd27a7fdd31f8c4c38b9f84eec6 100644 (file)
@@ -48,6 +48,8 @@
 #include "BKE_animsys.h"
 #include "BKE_nla.h"
 #include "BKE_context.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
 #include "BKE_report.h"
 #include "BKE_screen.h"
 #include "BKE_utildefines.h"
@@ -215,6 +217,229 @@ void NLAEDIT_OT_tweakmode_exit (wmOperatorType *ot)
 /* *********************************************** */
 /* NLA Editing Operations */
 
+/* ******************** Add Action-Clip Operator ***************************** */
+/* Add a new Action-Clip strip to the active track (or the active block if no space in the track) */
+
+/* pop up menu allowing user to choose the action to use */
+static int nlaedit_add_actionclip_invoke (bContext *C, wmOperator *op, wmEvent *evt)
+{
+       Main *m= CTX_data_main(C);
+       bAction *act;
+       uiPopupMenu *pup;
+       uiLayout *layout;
+       
+       pup= uiPupMenuBegin(C, "Add Action Clip", 0);
+       layout= uiPupMenuLayout(pup);
+       
+       /* loop through Actions in Main database, adding as items in the menu */
+       for (act= m->action.first; act; act= act->id.next)
+               uiItemStringO(layout, act->id.name+2, 0, "NLAEDIT_OT_add_actionclip", "action", act->id.name);
+       uiItemS(layout);
+       
+       uiPupMenuEnd(C, pup);
+       
+       return OPERATOR_CANCELLED;
+}
+
+/* add the specified action as new strip */
+static int nlaedit_add_actionclip_exec (bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       Scene *scene;
+       
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter, items;
+       
+       bAction *act = NULL;
+       char actname[22];
+       float cfra;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       scene= ac.scene;
+       cfra= (float)CFRA;
+               
+       /* get action to use */
+       RNA_string_get(op->ptr, "action", actname);
+       act= (bAction *)find_id("AC", actname+2);
+       
+       if (act == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "No valid Action to add.");
+               //printf("Add strip - actname = '%s' \n", actname);
+               return OPERATOR_CANCELLED;
+       }
+       
+       /* get a list of the editable tracks being shown in the NLA
+        *      - this is limited to active ones for now, but could be expanded to 
+        */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
+       items= ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+       
+       if (items == 0) {
+               BKE_report(op->reports, RPT_ERROR, "No active track(s) to add strip to.");
+               return OPERATOR_CANCELLED;
+       }
+       
+       /* for every active track, try to add strip to free space in track or to the top of the stack if no space */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               NlaTrack *nlt= (NlaTrack *)ale->data;
+               AnimData *adt= BKE_animdata_from_id(ale->id);
+               NlaStrip *strip= NULL;
+               
+               /* create a new strip, and offset it to start on the current frame */
+               strip= add_nlastrip(act);
+               
+               strip->end              += (cfra - strip->start);
+               strip->start     = cfra;
+               
+               /* firstly try adding strip to our current track, but if that fails, add to a new track */
+               if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
+                       /* trying to add to the current failed (no space), 
+                        * so add a new track to the stack, and add to that...
+                        */
+                       nlt= add_nlatrack(adt, NULL);
+                       BKE_nlatrack_add_strip(nlt, strip);
+               }
+       }
+       
+       /* 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 NLAEDIT_OT_add_actionclip (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Add Action Strip";
+       ot->idname= "NLAEDIT_OT_add_actionclip";
+       ot->description= "Add an Action-Clip strip (i.e. an NLA Strip referencing an Action) to the active track.";
+       
+       /* api callbacks */
+       ot->invoke= nlaedit_add_actionclip_invoke;
+       ot->exec= nlaedit_add_actionclip_exec;
+       ot->poll= nlaop_poll_tweakmode_off;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+               // TODO: this would be nicer as an ID-pointer...
+       RNA_def_string(ot->srna, "action", "", 21, "Action", "Name of Action to add as a new Action-Clip Strip.");
+}
+
+/* ******************** Add Transition Operator ***************************** */
+/* Add a new transition strip between selected strips */
+
+/* add the specified action as new strip */
+static int nlaedit_add_transition_exec (bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       int done = 0;
+       
+       /* 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);
+       
+       /* for each track, find pairs of strips to add transitions to */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               NlaTrack *nlt= (NlaTrack *)ale->data;
+               NlaStrip *s1, *s2;
+               
+               /* get initial pair of strips */
+               if ELEM(nlt->strips.first, NULL, nlt->strips.last)
+                       continue;
+               s1= nlt->strips.first;
+               s2= s1->next;
+               
+               /* loop over strips */
+               for (; s1 && s2; s1=s2, s2=s2->next) {
+                       NlaStrip *strip;
+                       
+                       /* check if both are selected */
+                       if ELEM(0, (s1->flag & NLASTRIP_FLAG_SELECT), (s2->flag & NLASTRIP_FLAG_SELECT))
+                               continue;
+                       /* check if there's space between the two */
+                       if (IS_EQ(s1->end, s2->start))
+                               continue;
+                               
+                       /* allocate new strip */
+                       strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
+                       BLI_insertlinkafter(&nlt->strips, s1, strip);
+                       
+                       /* set the type */
+                       strip->type= NLASTRIP_TYPE_TRANSITION;
+                       
+                       /* generic settings 
+                        *      - selected flag to highlight this to the user
+                        *      - auto-blends to ensure that blend in/out values are automatically 
+                        *        determined by overlaps of strips
+                        */
+                       strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
+                       
+                       /* range is simply defined as the endpoints of the adjacent strips */
+                       strip->start    = s1->end;
+                       strip->end              = s2->start;
+                       
+                       /* scale and repeat aren't of any use, but shouldn't ever be 0 */
+                       strip->scale= 1.0f;
+                       strip->repeat = 1.0f;
+                       
+                       /* make note of this */
+                       done++;
+               }
+       }
+       
+       /* free temp data */
+       BLI_freelistN(&anim_data);
+       
+       /* was anything added? */
+       if (done) {
+               /* 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;
+       }
+       else {
+               BKE_report(op->reports, RPT_ERROR, "Needs at least a pair of adjacent selected strips.");
+               return OPERATOR_CANCELLED;
+       }
+}
+
+void NLAEDIT_OT_add_transition (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Add Transition";
+       ot->idname= "NLAEDIT_OT_add_transition";
+       ot->description= "Add a transition strip between two adjacent selected strips.";
+       
+       /* api callbacks */
+       ot->exec= nlaedit_add_transition_exec;
+       ot->poll= nlaop_poll_tweakmode_off;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
 /* ******************** Delete Strips Operator ***************************** */
 /* Deletes the selected NLA-Strips */
 
@@ -230,7 +455,7 @@ static int nlaedit_delete_exec (bContext *C, wmOperator *op)
        if (ANIM_animdata_get_context(C, &ac) == 0)
                return OPERATOR_CANCELLED;
                
-       /* get a list of the AnimData blocks being shown in the NLA */
+       /* 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);
        
@@ -292,7 +517,7 @@ static int nlaedit_split_exec (bContext *C, wmOperator *op)
        if (ANIM_animdata_get_context(C, &ac) == 0)
                return OPERATOR_CANCELLED;
                
-       /* get a list of the AnimData blocks being shown in the NLA */
+       /* get a list of 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);
        
index 0d42c544a3f16c31ad076e710f0fbff47dc0c615..970d602c0af545b303d3582c49d1a0ac4be9cd7e 100644 (file)
@@ -110,7 +110,7 @@ static void nla_viewmenu(bContext *C, uiLayout *layout, void *arg_unused)
        
        uiItemS(layout);
        
-       uiItemO(layout, NULL, 0, "NLA_OT_view_all");
+       //uiItemO(layout, NULL, 0, "NLA_OT_view_all");
        
        if (sa->full) 
                uiItemO(layout, NULL, 0, "SCREEN_OT_screen_full_area"); // "Tile Window", Ctrl UpArrow
@@ -146,6 +146,9 @@ static void nla_editmenu(bContext *C, uiLayout *layout, void *arg_unused)
        uiItemO(layout, NULL, 0, "NLA_OT_add_tracks");
        uiItemBooleanO(layout, "Add Tracks Above Selected", 0, "NLA_OT_add_tracks", "above_selected", 1);
        
+       uiItemO(layout, NULL, 0, "NLA_OT_add_actionclip");
+       uiItemO(layout, NULL, 0, "NLA_OT_add_transition");
+       
        uiItemO(layout, NULL, 0, "NLAEDIT_OT_split");
        
        uiItemS(layout);
index 5c6670cfd6f8a608268240acef1a808cd2a81d55..f1bde40f4ab1108589ce4da6e5d7bb027d81065c 100644 (file)
@@ -92,6 +92,9 @@ void NLAEDIT_OT_tweakmode_exit(wmOperatorType *ot);
 
 /* --- */
 
+void NLAEDIT_OT_add_actionclip(wmOperatorType *ot);
+void NLAEDIT_OT_add_transition(wmOperatorType *ot);
+
 void NLAEDIT_OT_delete(wmOperatorType *ot);
 void NLAEDIT_OT_split(wmOperatorType *ot);
 
index 981ef9a4f870cbef362ff9a7b3c3be3c09e0bea2..a9b7022157e2e27842c30caeac573e0eb7fe6441 100644 (file)
@@ -134,6 +134,9 @@ void nla_operatortypes(void)
        WM_operatortype_append(NLAEDIT_OT_tweakmode_enter);
        WM_operatortype_append(NLAEDIT_OT_tweakmode_exit);
        
+       WM_operatortype_append(NLAEDIT_OT_add_actionclip);
+       WM_operatortype_append(NLAEDIT_OT_add_transition);
+       
        WM_operatortype_append(NLAEDIT_OT_delete);
        WM_operatortype_append(NLAEDIT_OT_split);
 }
@@ -208,6 +211,10 @@ static void nla_keymap_main (wmWindowManager *wm, ListBase *keymap)
        WM_keymap_add_item(keymap, "NLAEDIT_OT_tweakmode_enter", TABKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "NLAEDIT_OT_tweakmode_exit", TABKEY, KM_PRESS, 0, 0);
                
+               /* add strips */
+       WM_keymap_add_item(keymap, "NLAEDIT_OT_add_actionclip", AKEY, KM_PRESS, KM_SHIFT, 0);
+       WM_keymap_add_item(keymap, "NLAEDIT_OT_add_transition", TKEY, KM_PRESS, KM_SHIFT, 0);
+               
                /* delete */
        WM_keymap_add_item(keymap, "NLAEDIT_OT_delete", XKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "NLAEDIT_OT_delete", DELKEY, KM_PRESS, 0, 0);