/* callback to verify modifier data */ static void validate_fmodifier_cb(bContext *UNUSED(C), void *fcm_v, void *UNUSED(arg)) { FModifier *fcm = (FModifier *)fcm_v; FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); /* call the verify callback on the modifier if applicable */ if (fmi && fmi->verify_data) fmi->verify_data(fcm); }
/* evaluate time modifications imposed by some F-Curve Modifiers * - this step acts as an optimization 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 receive 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 * * Note: *fcu might be NULL */ float evaluate_time_fmodifiers(FModifiersStackStorage *storage, ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime) { /* sanity checks */ if (ELEM(NULL, modifiers, modifiers->last)) { return evaltime; } if (fcu && fcu->flag & FCURVE_MOD_OFF) { return evaltime; } /* Starting from the end of the stack, calculate the time effects of various stacked modifiers * on the time the F-Curve should be evaluated at. * * This is done in reverse order to standard evaluation, as when this is done in standard * order, each modifier would cause jumps to other points in the curve, forcing all * previous ones to be evaluated again for them to be correct. However, if we did in the * reverse order as we have here, we can consider them a macro to micro type of waterfall * effect, which should get us the desired effects when using layered time manipulations * (such as multiple 'stepped' modifiers in sequence, causing different stepping rates) */ uint fcm_index = storage->modifier_count - 1; for (FModifier *fcm = modifiers->last; fcm; fcm = fcm->prev, fcm_index--) { const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); if (fmi == NULL) { continue; } /* If modifier cannot be applied on this frame * (whatever scale it is on, it won't affect the results) * hence we shouldn't bother seeing what it would do given the chance. */ if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 || ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime))) { /* only evaluate if there's a callback for this */ if (fmi->evaluate_modifier_time) { if ((fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) == 0) { void *storage_ptr = POINTER_OFFSET(storage->buffer, fcm_index * storage->size_per_modifier); float nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime, storage_ptr); float influence = eval_fmodifier_influence(fcm, evaltime); evaltime = interpf(nval, evaltime, influence); } } } } /* return the modified evaltime */ return evaltime; }
/* Evaluates 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(FModifiersStackStorage *storage, ListBase *modifiers, FCurve *fcu, float *cvalue, float evaltime) { FModifier *fcm; /* sanity checks */ if (ELEM(NULL, modifiers, modifiers->first)) { return; } if (fcu->flag & FCURVE_MOD_OFF) { return; } /* evaluate modifiers */ uint fcm_index = 0; for (fcm = modifiers->first; fcm; fcm = fcm->next, fcm_index++) { const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); if (fmi == NULL) { continue; } /* Only evaluate if there's a callback for this, * and if F-Modifier can be evaluated on this frame. */ if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 || ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime))) { if (fmi->evaluate_modifier) { if ((fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) == 0) { void *storage_ptr = POINTER_OFFSET(storage->buffer, fcm_index * storage->size_per_modifier); float nval = *cvalue; fmi->evaluate_modifier(fcu, fcm, &nval, evaltime, storage_ptr); float influence = eval_fmodifier_influence(fcm, evaltime); *cvalue = interpf(nval, *cvalue, influence); } } } } }
/* Duplicate all of the F-Modifiers in the Modifier stacks */ void copy_fmodifiers(ListBase *dst, ListBase *src) { FModifier *fcm, *srcfcm; if (ELEM(NULL, dst, src)) return; dst->first = dst->last = NULL; BLI_duplicatelist(dst, src); for (fcm = dst->first, srcfcm = src->first; fcm && srcfcm; srcfcm = srcfcm->next, fcm = fcm->next) { FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); /* make a new copy of the F-Modifier's data */ fcm->data = MEM_dupallocN(fcm->data); /* only do specific constraints if required */ if (fmi && fmi->copy_data) fmi->copy_data(fcm, srcfcm); } }
uint evaluate_fmodifiers_storage_size_per_modifier(ListBase *modifiers) { /* Sanity checks. */ if (ELEM(NULL, modifiers, modifiers->first)) { return 0; } uint max_size = 0; for (FModifier *fcm = modifiers->first; fcm; fcm = fcm->next) { const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); if (fmi == NULL) { continue; } max_size = MAX2(max_size, fmi->storage_size); } return max_size; }
/* Remove and free the given F-Modifier from the given stack */ bool remove_fmodifier(ListBase *modifiers, FModifier *fcm) { const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); /* sanity check */ if (fcm == NULL) { return false; } /* removing the cycles modifier requires a handle update */ FCurve *update_fcu = (fcm->type == FMODIFIER_TYPE_CYCLES) ? fcm->curve : NULL; /* free modifier's special data (stored inside fcm->data) */ if (fcm->data) { if (fmi && fmi->free_data) { fmi->free_data(fcm); } /* free modifier's data (fcm->data) */ MEM_freeN(fcm->data); } /* remove modifier from stack */ if (modifiers) { BLI_freelinkN(modifiers, fcm); /* update the fcurve if the Cycles modifier is removed */ if (update_fcu) { calchandles_fcurve(update_fcu); } return true; } else { /* XXX this case can probably be removed some day, as it shouldn't happen... */ CLOG_STR_ERROR(&LOG, "no modifier stack given"); MEM_freeN(fcm); return false; } }
/* Evaluates 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(FModifierStackStorage *storage, 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); if (fmi == NULL) continue; /* only evaluate if there's a callback for this, and if F-Modifier can be evaluated on this frame */ if ((fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) == 0 || ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) ) { if (fmi->evaluate_modifier || fmi->evaluate_modifier_storage) { if ((fcm->flag & (FMODIFIER_FLAG_DISABLED | FMODIFIER_FLAG_MUTED)) == 0) { float influence = eval_fmodifier_influence(fcm, evaltime); float nval = *cvalue; if ((fmi->requires & FMI_REQUIRES_STORAGE) == 0) { fmi->evaluate_modifier(fcu, fcm, &nval, evaltime); } else { fmi->evaluate_modifier_storage(storage, fcu, fcm, &nval, evaltime); } *cvalue = interpf(nval, *cvalue, influence); } } } } }
/* Make a copy of the specified F-Modifier */ FModifier *copy_fmodifier(FModifier *src) { FModifierTypeInfo *fmi = fmodifier_get_typeinfo(src); FModifier *dst; /* sanity check */ if (src == NULL) return NULL; /* copy the base data, clearing the links */ dst = MEM_dupallocN(src); dst->next = dst->prev = NULL; /* make a new copy of the F-Modifier's data */ dst->data = MEM_dupallocN(src->data); /* only do specific constraints if required */ if (fmi && fmi->copy_data) fmi->copy_data(dst, src); /* return the new modifier */ return dst; }
/* 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) */ bool list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype) { FModifier *fcm; /* if there are no specific filtering criteria, just skip */ if ((mtype == 0) && (acttype == 0)) { return (modifiers && modifiers->first); } /* sanity checks */ if (ELEM(NULL, modifiers, modifiers->first)) { return false; } /* find the first mdifier fitting these criteria */ for (fcm = modifiers->first; fcm; fcm = fcm->next) { const 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 fulfilled */ 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 true; } } /* no matches */ return false; }
void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm) { FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); uiLayout *box, *row, *sub, *col; uiBlock *block; uiBut *but; short width = 314; PointerRNA ptr; /* init the RNA-pointer */ RNA_pointer_create(id, &RNA_FModifier, fcm, &ptr); /* draw header */ { /* get layout-row + UI-block for this */ box = uiLayoutBox(layout); row = uiLayoutRow(box, FALSE); block = uiLayoutGetBlock(row); // err... /* left-align -------------------------------------------- */ sub = uiLayoutRow(row, TRUE); uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT); uiBlockSetEmboss(block, UI_EMBOSSN); /* expand */ uiItemR(sub, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); /* checkbox for 'active' status (for now) */ uiItemR(sub, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); /* name */ if (fmi) uiItemL(sub, IFACE_(fmi->name), ICON_NONE); else uiItemL(sub, IFACE_("<Unknown Modifier>"), ICON_NONE); /* right-align ------------------------------------------- */ sub = uiLayoutRow(row, TRUE); uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); /* 'mute' button */ uiItemR(sub, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); uiBlockSetEmboss(block, UI_EMBOSSN); /* delete button */ but = uiDefIconBut(block, BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete F-Curve Modifier")); uiButSetFunc(but, delete_fmodifier_cb, modifiers, fcm); uiBlockSetEmboss(block, UI_EMBOSS); } /* when modifier is expanded, draw settings */ if (fcm->flag & FMODIFIER_FLAG_EXPANDED) { /* set up the flexible-box layout which acts as the backdrop for the modifier settings */ box = uiLayoutBox(layout); /* draw settings for individual modifiers */ switch (fcm->type) { case FMODIFIER_TYPE_GENERATOR: /* Generator */ draw_modifier__generator(box, id, fcm, width); break; case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */ draw_modifier__fn_generator(box, id, fcm, width); break; case FMODIFIER_TYPE_CYCLES: /* Cycles */ draw_modifier__cycles(box, id, fcm, width); break; case FMODIFIER_TYPE_ENVELOPE: /* Envelope */ draw_modifier__envelope(box, id, fcm, width); break; case FMODIFIER_TYPE_LIMITS: /* Limits */ draw_modifier__limits(box, id, fcm, width); break; case FMODIFIER_TYPE_NOISE: /* Noise */ draw_modifier__noise(box, id, fcm, width); break; case FMODIFIER_TYPE_STEPPED: /* Stepped */ draw_modifier__stepped(box, id, fcm, width); break; default: /* unknown type */ break; } /* one last panel below this: FModifier range */ // TODO: experiment with placement of this { box = uiLayoutBox(layout); /* restricted range ----------------------------------------------------- */ col = uiLayoutColumn(box, TRUE); /* top row: use restricted range */ row = uiLayoutRow(col, TRUE); uiItemR(row, &ptr, "use_restricted_range", 0, NULL, ICON_NONE); if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) { /* second row: settings */ row = uiLayoutRow(col, TRUE); uiItemR(row, &ptr, "frame_start", 0, IFACE_("Start"), ICON_NONE); uiItemR(row, &ptr, "frame_end", 0, IFACE_("End"), ICON_NONE); /* third row: blending influence */ row = uiLayoutRow(col, TRUE); uiItemR(row, &ptr, "blend_in", 0, IFACE_("In"), ICON_NONE); uiItemR(row, &ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE); } /* influence -------------------------------------------------------------- */ col = uiLayoutColumn(box, TRUE); /* top row: use influence */ uiItemR(col, &ptr, "use_influence", 0, NULL, ICON_NONE); if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE) { /* second row: influence value */ uiItemR(col, &ptr, "influence", 0, NULL, ICON_NONE); } } } }
void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm) { FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); uiLayout *box, *row, *subrow; uiBlock *block; uiBut *but; short width= 314; PointerRNA ptr; /* init the RNA-pointer */ RNA_pointer_create(id, &RNA_FModifier, fcm, &ptr); /* draw header */ { /* get layout-row + UI-block for this */ box= uiLayoutBox(layout); row= uiLayoutRow(box, 0); block= uiLayoutGetBlock(row); // err... /* left-align -------------------------------------------- */ subrow= uiLayoutRow(row, 0); uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT); uiBlockSetEmboss(block, UI_EMBOSSN); /* expand */ uiItemR(subrow, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); /* checkbox for 'active' status (for now) */ uiItemR(subrow, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); /* name */ if (fmi) uiItemL(subrow, fmi->name, ICON_NONE); else uiItemL(subrow, "<Unknown Modifier>", ICON_NONE); /* right-align ------------------------------------------- */ subrow= uiLayoutRow(row, 0); uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT); /* 'mute' button */ uiItemR(subrow, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); uiBlockSetEmboss(block, UI_EMBOSSN); /* delete button */ but= uiDefIconBut(block, BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Delete F-Curve Modifier."); uiButSetFunc(but, delete_fmodifier_cb, modifiers, fcm); uiBlockSetEmboss(block, UI_EMBOSS); } /* when modifier is expanded, draw settings */ if (fcm->flag & FMODIFIER_FLAG_EXPANDED) { /* set up the flexible-box layout which acts as the backdrop for the modifier settings */ box= uiLayoutBox(layout); /* draw settings for individual modifiers */ switch (fcm->type) { case FMODIFIER_TYPE_GENERATOR: /* Generator */ draw_modifier__generator(box, id, fcm, width); break; case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */ draw_modifier__fn_generator(box, id, fcm, width); break; case FMODIFIER_TYPE_CYCLES: /* Cycles */ draw_modifier__cycles(box, id, fcm, width); break; case FMODIFIER_TYPE_ENVELOPE: /* Envelope */ draw_modifier__envelope(box, id, fcm, width); break; case FMODIFIER_TYPE_LIMITS: /* Limits */ draw_modifier__limits(box, id, fcm, width); break; case FMODIFIER_TYPE_NOISE: /* Noise */ draw_modifier__noise(box, id, fcm, width); break; case FMODIFIER_TYPE_STEPPED: /* Stepped */ draw_modifier__stepped(box, id, fcm, width); break; default: /* unknown type */ break; } } }