NLA Branch: Setting up evaluation system for action strips
* Refactored F-Curve Modifier stack evaluation into functions which can be reused for F-Curve Modifiers on NLA-Strips * Started setting up temporary accumulation buffer system for use when evaluating strips
This commit is contained in:
@@ -108,11 +108,15 @@ struct FModifier *fcurve_add_modifier(struct FCurve *fcu, int type);
|
||||
void fcurve_copy_modifiers(ListBase *dst, ListBase *src);
|
||||
void fcurve_remove_modifier(struct FCurve *fcu, struct FModifier *fcm);
|
||||
void fcurve_free_modifiers(struct FCurve *fcu);
|
||||
void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end);
|
||||
|
||||
struct FModifier *fcurve_find_active_modifier(struct FCurve *fcu);
|
||||
void fcurve_set_active_modifier(struct FCurve *fcu, struct FModifier *fcm);
|
||||
|
||||
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);
|
||||
|
||||
void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end);
|
||||
|
||||
/* ************** F-Curves API ******************** */
|
||||
|
||||
/* -------- Data Managemnt -------- */
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
@@ -564,7 +565,7 @@ enum {
|
||||
typedef struct NlaEvalChannel {
|
||||
struct NlaEvalChannel *next, *prev;
|
||||
|
||||
PointerRNA *ptr; /* pointer to struct containing property to use */
|
||||
PointerRNA ptr; /* pointer to struct containing property to use */
|
||||
PropertyRNA *prop; /* RNA-property type to use (should be in the struct given) */
|
||||
int index; /* array index (where applicable) */
|
||||
|
||||
@@ -638,13 +639,13 @@ static float nlastrip_get_influence (NlaStrip *strip, float cframe)
|
||||
}
|
||||
|
||||
/* evaluate the evaluation time and influence for the strip, storing the results in the strip */
|
||||
void nlastrip_evaluate_controls (NlaStrip *strip, float cframe)
|
||||
void nlastrip_evaluate_controls (NlaStrip *strip, float ctime)
|
||||
{
|
||||
/* firstly, analytically generate values for influence and time (if applicable) */
|
||||
if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0)
|
||||
strip->strip_time= nlastrip_get_frame(strip, cframe, 1); /* last arg '1' means current time to 'strip'/action time */
|
||||
strip->strip_time= nlastrip_get_frame(strip, ctime, 1); /* last arg '1' means current time to 'strip'/action time */
|
||||
if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0)
|
||||
strip->influence= nlastrip_get_influence(strip, cframe);
|
||||
strip->influence= nlastrip_get_influence(strip, ctime);
|
||||
|
||||
/* now strip's evaluate F-Curves for these settings (if applicable) */
|
||||
if (strip->fcurves.first) {
|
||||
@@ -766,13 +767,104 @@ static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index
|
||||
|
||||
/* ---------------------- */
|
||||
|
||||
/* evaluates the given evaluation strip */
|
||||
// FIXME: will we need the evaluation cache table set up to blend stuff in?
|
||||
// TODO: only evaluate here, but flush in one go using the accumulated channels at end...
|
||||
static void nlastrip_ctime_evaluate (ListBase *channels, NlaEvalStrip *nes, float ctime)
|
||||
/* verify that an appropriate NlaEvalChannel for this F-Curve */
|
||||
static NlaEvalChannel *nlaevalchan_verify (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes, FCurve *fcu, short *newChan)
|
||||
{
|
||||
// 1. (in old code) was to extract 'IPO-channels' from actions
|
||||
// 2. blend between the 'accumulated' data, and the new data
|
||||
NlaEvalChannel *nec= NULL;
|
||||
NlaStrip *strip= nes->strip;
|
||||
PropertyRNA *prop;
|
||||
PointerRNA new_ptr;
|
||||
char *path = NULL;
|
||||
short free_path=0;
|
||||
|
||||
/* sanity checks */
|
||||
if (channels == NULL)
|
||||
return NULL;
|
||||
|
||||
/* get RNA pointer+property info from F-Curve for more convenient handling */
|
||||
/* get path, remapped as appropriate to work in its new environment */
|
||||
free_path= animsys_remap_path(strip->remap, fcu->rna_path, &path);
|
||||
|
||||
/* get property to write to */
|
||||
if (RNA_path_resolve(ptr, path, &new_ptr, &prop) == 0)
|
||||
return NULL;
|
||||
/* only ok if animateable */
|
||||
else if (RNA_property_animateable(&new_ptr, prop) == 0)
|
||||
return NULL;
|
||||
|
||||
/* loop through existing channels, checking for a channel which affects the same property */
|
||||
for (nec= channels->first; nec; nec= nec->next) {
|
||||
if ((nec->ptr.data == new_ptr.data) && (nec->prop == prop))
|
||||
return nec;
|
||||
}
|
||||
|
||||
/* allocate a new struct for this */
|
||||
nec= MEM_callocN(sizeof(NlaEvalChannel), "NlaEvalChannel");
|
||||
*newChan= 1;
|
||||
BLI_addtail(channels, nec);
|
||||
|
||||
nec->ptr= new_ptr;
|
||||
nec->prop= prop;
|
||||
nec->index= fcu->array_index;
|
||||
|
||||
return nec;
|
||||
}
|
||||
|
||||
/* ---------------------- */
|
||||
|
||||
/* evaluate action-clip strip */
|
||||
static void nlastrip_evaluate_actionclip (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes)
|
||||
{
|
||||
NlaStrip *strip= nes->strip;
|
||||
FCurve *fcu;
|
||||
float evaltime;
|
||||
|
||||
/* evaluate strip's modifiers which modify time to evaluate the base curves at */
|
||||
evaltime= evaluate_time_fmodifiers(&strip->modifiers, NULL, 0.0f, strip->strip_time);
|
||||
|
||||
/* evaluate all the F-Curves in the action, saving the relevant pointers to data that will need to be used */
|
||||
for (fcu= strip->act->curves.first; fcu; fcu= fcu->next) {
|
||||
NlaEvalChannel *nec;
|
||||
float value = 0.0f;
|
||||
short newChan = -1;
|
||||
|
||||
/* check if this curve should be skipped */
|
||||
if (fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED))
|
||||
continue;
|
||||
|
||||
/* evaluate the F-Curve's value for the time given in the strip
|
||||
* NOTE: we use the modified time here, since strip's F-Curve Modifiers are applied on top of this
|
||||
*/
|
||||
value= evaluate_fcurve(fcu, evaltime);
|
||||
|
||||
/* apply strip's F-Curve Modifiers on this value
|
||||
* NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval)
|
||||
*/
|
||||
evaluate_value_fmodifiers(&strip->modifiers, fcu, &value, strip->strip_time);
|
||||
|
||||
|
||||
/* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s)
|
||||
* stored in this channel if it has been used already
|
||||
*/
|
||||
nec= nlaevalchan_verify(ptr, channels, nes, fcu, &newChan);
|
||||
//if (nec)
|
||||
// nlaevalchan_accumulate(ptr, nec, nes, newChan, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
switch (nes->strip->type) {
|
||||
case NLASTRIP_TYPE_CLIP: /* action-clip */
|
||||
nlastrip_evaluate_actionclip(ptr, channels, nes);
|
||||
break;
|
||||
case NLASTRIP_TYPE_TRANSITION: /* transition */
|
||||
// XXX code this...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* write the accumulated settings to */
|
||||
@@ -807,7 +899,7 @@ static void animsys_evaluate_nla (PointerRNA *ptr, AnimData *adt, float ctime)
|
||||
|
||||
/* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */
|
||||
for (nes= estrips.first; nes; nes= nes->next)
|
||||
nlastrip_ctime_evaluate(&echannels, nes, ctime);
|
||||
nlastrip_evaluate(ptr, &echannels, nes);
|
||||
|
||||
/* 3. flush effects of accumulating channels in NLA to the actual data they affect */
|
||||
nladata_flush_channels(ptr, &echannels);
|
||||
|
||||
@@ -2166,34 +2166,6 @@ void fcurve_free_modifiers (FCurve *fcu)
|
||||
}
|
||||
}
|
||||
|
||||
/* Bake modifiers for given F-Curve to curve sample data, in the frame range defined
|
||||
* by start and end (inclusive).
|
||||
*/
|
||||
void fcurve_bake_modifiers (FCurve *fcu, int start, int end)
|
||||
{
|
||||
ChannelDriver *driver;
|
||||
|
||||
/* sanity checks */
|
||||
// TODO: make these tests report errors using reports not printf's
|
||||
if ELEM(NULL, fcu, fcu->modifiers.first) {
|
||||
printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* temporarily, disable driver while we sample, so that they don't influence the outcome */
|
||||
driver= fcu->driver;
|
||||
fcu->driver= NULL;
|
||||
|
||||
/* bake the modifiers, by sampling the curve at each frame */
|
||||
fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
|
||||
|
||||
/* free the modifiers now */
|
||||
fcurve_free_modifiers(fcu);
|
||||
|
||||
/* restore driver */
|
||||
fcu->driver= driver;
|
||||
}
|
||||
|
||||
/* Find the active F-Curve Modifier */
|
||||
FModifier *fcurve_find_active_modifier (FCurve *fcu)
|
||||
{
|
||||
@@ -2231,6 +2203,98 @@ void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm)
|
||||
fcm->flag |= FMODIFIER_FLAG_ACTIVE;
|
||||
}
|
||||
|
||||
/* Evaluation API --------------------------- */
|
||||
|
||||
/* evaluate time modifications imposed by some F-Curve Modifiers
|
||||
* - this step acts as an optimisation to prevent the F-Curve stack being evaluated
|
||||
* several times by modifiers requesting the time be modified, as the final result
|
||||
* would have required using the modified time
|
||||
* - modifiers only ever recieve the unmodified time, as subsequent modifiers should be
|
||||
* working on the 'global' result of the modified curve, not some localised segment,
|
||||
* so nevaltime gets set to whatever the last time-modifying modifier likes...
|
||||
* - we start from the end of the stack, as only the last one matters for now
|
||||
*/
|
||||
float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime)
|
||||
{
|
||||
FModifier *fcm;
|
||||
float m_evaltime= evaltime;
|
||||
|
||||
/* sanity checks */
|
||||
if ELEM(NULL, modifiers, modifiers->first)
|
||||
return evaltime;
|
||||
|
||||
/* find the first modifier from end of stack that modifies time, and calculate the time the modifier
|
||||
* would calculate time at
|
||||
*/
|
||||
for (fcm= fcu->modifiers.last; fcm; fcm= fcm->prev) {
|
||||
FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
|
||||
|
||||
/* only evaluate if there's a callback for this */
|
||||
// TODO: implement the 'influence' control feature...
|
||||
if (fmi && fmi->evaluate_modifier_time) {
|
||||
if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
|
||||
m_evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the modified evaltime */
|
||||
return m_evaltime;
|
||||
}
|
||||
|
||||
/* Evalautes the given set of F-Curve Modifiers using the given data
|
||||
* Should only be called after evaluate_time_fmodifiers() has been called...
|
||||
*/
|
||||
void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, float evaltime)
|
||||
{
|
||||
FModifier *fcm;
|
||||
|
||||
/* sanity checks */
|
||||
if ELEM(NULL, modifiers, modifiers->first)
|
||||
return;
|
||||
|
||||
/* evaluate modifiers */
|
||||
for (fcm= modifiers->first; fcm; fcm= fcm->next) {
|
||||
FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
|
||||
|
||||
/* only evaluate if there's a callback for this */
|
||||
// TODO: implement the 'influence' control feature...
|
||||
if (fmi && fmi->evaluate_modifier) {
|
||||
if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
|
||||
fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Bake modifiers for given F-Curve to curve sample data, in the frame range defined
|
||||
* by start and end (inclusive).
|
||||
*/
|
||||
void fcurve_bake_modifiers (FCurve *fcu, int start, int end)
|
||||
{
|
||||
ChannelDriver *driver;
|
||||
|
||||
/* sanity checks */
|
||||
// TODO: make these tests report errors using reports not printf's
|
||||
if ELEM(NULL, fcu, fcu->modifiers.first) {
|
||||
printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* temporarily, disable driver while we sample, so that they don't influence the outcome */
|
||||
driver= fcu->driver;
|
||||
fcu->driver= NULL;
|
||||
|
||||
/* bake the modifiers, by sampling the curve at each frame */
|
||||
fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
|
||||
|
||||
/* free the modifiers now */
|
||||
fcurve_free_modifiers(fcu);
|
||||
|
||||
/* restore driver */
|
||||
fcu->driver= driver;
|
||||
}
|
||||
|
||||
/* ***************************** F-Curve - Evaluation ********************************* */
|
||||
|
||||
/* Evaluate and return the value of the given F-Curve at the specified frame ("evaltime")
|
||||
@@ -2238,7 +2302,6 @@ void fcurve_set_active_modifier (FCurve *fcu, FModifier *fcm)
|
||||
*/
|
||||
float evaluate_fcurve (FCurve *fcu, float evaltime)
|
||||
{
|
||||
FModifier *fcm;
|
||||
float cvalue= 0.0f;
|
||||
float devaltime;
|
||||
|
||||
@@ -2251,28 +2314,8 @@ float evaluate_fcurve (FCurve *fcu, float evaltime)
|
||||
evaltime= cvalue= evaluate_driver(fcu->driver, evaltime);
|
||||
}
|
||||
|
||||
/* evaluate time modifications imposed by some F-Curve Modifiers
|
||||
* - this step acts as an optimisation to prevent the F-Curve stack being evaluated
|
||||
* several times by modifiers requesting the time be modified, as the final result
|
||||
* would have required using the modified time
|
||||
* - modifiers only ever recieve the unmodified time, as subsequent modifiers should be
|
||||
* working on the 'global' result of the modified curve, not some localised segment,
|
||||
* so nevaltime gets set to whatever the last time-modifying modifier likes...
|
||||
* - we start from the end of the stack, as only the last one matters for now
|
||||
*/
|
||||
devaltime= evaltime;
|
||||
|
||||
for (fcm= fcu->modifiers.last; fcm; fcm= fcm->prev) {
|
||||
FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
|
||||
|
||||
/* only evaluate if there's a callback for this */
|
||||
// TODO: implement the 'influence' control feature...
|
||||
if (fmi && fmi->evaluate_modifier_time) {
|
||||
if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
|
||||
devaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* evaluate modifiers which modify time to evaluate the base curve at */
|
||||
devaltime= evaluate_time_fmodifiers(&fcu->modifiers, fcu, cvalue, evaltime);
|
||||
|
||||
/* evaluate curve-data
|
||||
* - 'devaltime' instead of 'evaltime', as this is the time that the last time-modifying
|
||||
@@ -2284,16 +2327,7 @@ float evaluate_fcurve (FCurve *fcu, float evaltime)
|
||||
cvalue= fcurve_eval_samples(fcu, fcu->fpt, devaltime);
|
||||
|
||||
/* evaluate modifiers */
|
||||
for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
|
||||
FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
|
||||
|
||||
/* only evaluate if there's a callback for this */
|
||||
// TODO: implement the 'influence' control feature...
|
||||
if (fmi && fmi->evaluate_modifier) {
|
||||
if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
|
||||
fmi->evaluate_modifier(fcu, fcm, &cvalue, evaltime);
|
||||
}
|
||||
}
|
||||
evaluate_value_fmodifiers(&fcu->modifiers, fcu, &cvalue, evaltime);
|
||||
|
||||
/* if curve can only have integral values, perform truncation (i.e. drop the decimal part)
|
||||
* here so that the curve can be sampled correctly
|
||||
|
||||
Reference in New Issue
Block a user