From d1677e36b663f077312050ac46cea0de1b1212c2 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 7 Jul 2009 11:37:33 +0000 Subject: NLA SoC: Recoded way that Meta-Strips are Evaluated Previously, the quick-hack I coded for Meta-strips evaluation didn't really take into account the possibilities to use Meta-Strips as strips in their own right - i.e. reversed, muted, time-mapping-curves, influence-blending - were all unavailable. This commit makes the aforementioned capabilities of other strips available for Meta-Strips too. The evaluation is now kind-of recursive (as with most of the other methods which take them into account) so that each 'level' of strips get evaluated correctly within their frame-of-reference. TODO: * F-Modifier support for Metas... --- source/blender/blenkernel/intern/anim_sys.c | 158 ++++++++++++++++------------ source/blender/blenkernel/intern/nla.c | 2 +- source/blender/blenkernel/nla_private.h | 6 ++ 3 files changed, 97 insertions(+), 69 deletions(-) (limited to 'source/blender/blenkernel') diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 1d10744ac80..0aadb1825ad 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -627,11 +627,12 @@ static void nlastrip_evaluate_controls (NlaStrip *strip, 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) +/* gets the strip active at the current time for a list of strips for evaluation purposes */ +NlaEvalStrip *nlastrips_ctime_get_strip (ListBase *list, ListBase *strips, short index, float ctime) { NlaStrip *strip, *estrip=NULL; + NlaEvalStrip *nes; + short side= 0; /* loop over strips, checking if they fall within the range */ for (strip= strips->first; strip; strip= strip->next) { @@ -651,7 +652,7 @@ static NlaStrip *ctime_get_strip (ListBase *strips, short *side, float ctime) 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, @@ -663,7 +664,7 @@ static NlaStrip *ctime_get_strip (ListBase *strips, short *side, float ctime) if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) estrip= strip; - *side= NES_TIME_AFTER; + side= NES_TIME_AFTER; } break; } @@ -675,7 +676,7 @@ static NlaStrip *ctime_get_strip (ListBase *strips, short *side, float ctime) if (strip->extendmode != NLASTRIP_EXTEND_NOTHING) estrip= strip; - *side= NES_TIME_AFTER; + side= NES_TIME_AFTER; break; } @@ -683,40 +684,11 @@ static NlaStrip *ctime_get_strip (ListBase *strips, short *side, float ctime) } } - /* 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 */ if ((estrip == NULL) || (estrip->flag & NLASTRIP_FLAG_MUTED)) - return; + return NULL; /* if ctime was not within the boundaries of the strip, clamp! */ switch (side) { @@ -734,8 +706,8 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index */ // TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on... nlastrip_evaluate_controls(estrip, ctime); - if (estrip->influence <= 0.0f) // XXX is it useful to invert the strip? - return; + if (estrip->influence <= 0.0f) + return NULL; /* check if strip has valid data to evaluate, * and/or perform any additional type-specific actions @@ -744,12 +716,12 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index case NLASTRIP_TYPE_CLIP: /* clip must have some action to evaluate */ if (estrip->act == NULL) - return; + return NULL; break; case NLASTRIP_TYPE_TRANSITION: /* there must be strips to transition from and to (i.e. prev and next required) */ if (ELEM(NULL, estrip->prev, estrip->next)) - return; + return NULL; /* evaluate controls for the relevant extents of the bordering strips... */ nlastrip_evaluate_controls(estrip->prev, estrip->start); @@ -760,13 +732,15 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index /* add to list of strips we need to evaluate */ nes= MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip"); - nes->track= nlt; nes->strip= estrip; nes->strip_mode= side; nes->track_index= index; nes->strip_time= estrip->strip_time; - BLI_addtail(list, nes); + if (list) + BLI_addtail(list, nes); + + return nes; } /* ---------------------- */ @@ -897,6 +871,38 @@ static void nlaevalchan_accumulate (NlaEvalChannel *nec, NlaEvalStrip *nes, shor } } +/* accumulate the results of a temporary buffer with the results of the full-buffer */ +static void nlaevalchan_buffers_accumulate (ListBase *channels, ListBase *tmp_buffer, NlaEvalStrip *nes) +{ + NlaEvalChannel *nec, *necn, *necd; + + /* optimise - abort if no channels */ + if (tmp_buffer->first == NULL) + return; + + /* accumulate results in tmp_channels buffer to the accumulation buffer */ + for (nec= tmp_buffer->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_buffer, nec); + BLI_addtail(channels, nec); + } + } + + /* free temp-channels that haven't been assimilated into the buffer */ + BLI_freelistN(tmp_buffer); +} + /* ---------------------- */ /* evaluate action-clip strip */ @@ -945,7 +951,6 @@ static void nlastrip_evaluate_actionclip (PointerRNA *ptr, ListBase *channels, N 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; @@ -986,38 +991,51 @@ static void nlastrip_evaluate_transition (PointerRNA *ptr, ListBase *channels, N nlastrip_evaluate_actionclip(ptr, &tmp_channels, &tmp_nes); - /* optimise - abort if no channels */ - if (tmp_channels.first == NULL) - return; + /* assumulate temp-buffer and full-buffer, using the 'real' strip */ + nlaevalchan_buffers_accumulate(channels, &tmp_channels, nes); +} + +/* evaluate meta-strip */ +static void nlastrip_evaluate_meta (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes) +{ + ListBase tmp_channels = {NULL, NULL}; + NlaStrip *strip= nes->strip; + NlaEvalStrip *tmp_nes; + float evaltime; + /* meta-strip was calculated normally to have some time to be evaluated at + * and here we 'look inside' the meta strip, treating it as a decorated window to + * it's child strips, which get evaluated as if they were some tracks on a strip + * (but with some extra modifiers to apply). + * + * NOTE: keep this in sync with animsys_evaluate_nla() + */ - /* 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); + /* find the child-strip to evaluate */ + evaltime= (nes->strip_time * (strip->end - strip->start)) + strip->start; + tmp_nes= nlastrips_ctime_get_strip(NULL, &strip->strips, -1, evaltime); + if (tmp_nes == NULL) + return; - /* 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); - } - } + /* evaluate child-strip into tmp_channels buffer before accumulating + * in the accumulation buffer + */ + // TODO: need to supply overriding modifiers which will get applied over the top of these + nlastrip_evaluate(ptr, &tmp_channels, tmp_nes); - /* free temp-channels that haven't been assimilated into the buffer */ - BLI_freelistN(&tmp_channels); + /* assumulate temp-buffer and full-buffer, using the 'real' strip */ + nlaevalchan_buffers_accumulate(channels, &tmp_channels, nes); + + /* free temp eval-strip */ + MEM_freeN(tmp_nes); } + /* evaluates the given evaluation strip */ -static void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes) +void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes) { /* actions to take depend on the type of strip */ + // TODO: add 'modifiers' tag to chain switch (nes->strip->type) { case NLASTRIP_TYPE_CLIP: /* action-clip */ nlastrip_evaluate_actionclip(ptr, channels, nes); @@ -1025,11 +1043,14 @@ static void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, NlaEvalStrip case NLASTRIP_TYPE_TRANSITION: /* transition */ nlastrip_evaluate_transition(ptr, channels, nes); break; + case NLASTRIP_TYPE_META: /* meta */ + nlastrip_evaluate_meta(ptr, channels, nes); + break; } } /* write the accumulated settings to */ -static void nladata_flush_channels (ListBase *channels) +void nladata_flush_channels (ListBase *channels) { NlaEvalChannel *nec; @@ -1104,7 +1125,8 @@ static void animsys_evaluate_nla (PointerRNA *ptr, AnimData *adt, float ctime) continue; /* otherwise, get strip to evaluate for this channel */ - nlatrack_ctime_get_strip(&estrips, nlt, track_index, ctime); + nes= nlastrips_ctime_get_strip(&estrips, &nlt->strips, track_index, ctime); + if (nes) nes->track= nlt; } /* only continue if there are strips to evaluate */ diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 4dce9aebe24..511623f46fc 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -452,7 +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_META: /* meta - for now, does the same as transition (is really just an empty container) */ case NLASTRIP_TYPE_TRANSITION: /* transition */ return nlastrip_get_frame_transition(strip, cframe, mode); diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h index 1514a79f03b..016eaedfe4c 100644 --- a/source/blender/blenkernel/nla_private.h +++ b/source/blender/blenkernel/nla_private.h @@ -75,5 +75,11 @@ typedef struct NlaEvalChannel { /* convert from strip time <-> global time */ float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode); +/* --------------- NLA Evaluation (very-private stuff) ----------------------- */ +/* these functions are only defined here to avoid problems with the order in which they get defined... */ + +NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime); +void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes); +void nladata_flush_channels(ListBase *channels); #endif // NLA_PRIVATE -- cgit v1.2.3