diff options
-rw-r--r-- | source/blender/blenkernel/BKE_fcurve.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_nla.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/anim_sys.c | 156 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/fcurve.c | 36 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/nla.c | 72 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_buttons.c | 65 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_draw.c | 23 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_edit.c | 229 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_header.c | 5 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_intern.h | 3 | ||||
-rw-r--r-- | source/blender/editors/space_nla/nla_ops.c | 7 |
11 files changed, 536 insertions, 64 deletions
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 7058b9d236a..af272e892f2 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -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); diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h index 078c1ba52bb..5200ca6d4d7 100644 --- a/source/blender/blenkernel/BKE_nla.h +++ b/source/blender/blenkernel/BKE_nla.h @@ -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); diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index a864e3d4e87..2efb4f2b2d3 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -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; } } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 5820761234c..d8b5135a1b1 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -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 diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index cef14128032..0684d943754 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -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 diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index cb21dd66934..cb76f7fc735 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -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); } diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 8d417a150aa..3a3f86bb5a3 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -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); diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index e8af67aebd1..2996a005177 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -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); diff --git a/source/blender/editors/space_nla/nla_header.c b/source/blender/editors/space_nla/nla_header.c index 0d42c544a3f..970d602c0af 100644 --- a/source/blender/editors/space_nla/nla_header.c +++ b/source/blender/editors/space_nla/nla_header.c @@ -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); diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h index 5c6670cfd6f..f1bde40f4ab 100644 --- a/source/blender/editors/space_nla/nla_intern.h +++ b/source/blender/editors/space_nla/nla_intern.h @@ -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); diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c index 981ef9a4f87..a9b7022157e 100644 --- a/source/blender/editors/space_nla/nla_ops.c +++ b/source/blender/editors/space_nla/nla_ops.c @@ -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); |