F-Modifier Goodies (as requested by @ndy):

* Copy/Paste operators for F-Modifiers
Available in Graph and NLA Editors. Use the Copy/Paste buttons beside the 'Add Modifier' buttons.

Copy copies all the modifiers of the ACTIVE F-Curve or Strip depending on the editor.
Paste pastes modifiers from the buffer to all the selected F-Curves or Strips, adding the new modifiers to the ends of each list.

* 'Stepped Interpolation' F-Modifier
This modifier holds each interpolated value from the F-Curve for several frames without changing the timing. 

This allows to preview motions 'on-twos' for example without altering the timing, or having to go through setting heaps of keyframes. In this case, Andy wanted to use this for CG <-> StopMo.
This commit is contained in:
Joshua Leung 2010-03-18 13:04:46 +00:00
parent 148985edf0
commit 618b459e8b
16 changed files with 490 additions and 7 deletions

@ -158,6 +158,7 @@ FModifierTypeInfo *get_fmodifier_typeinfo(int type);
/* ---------------------- */
struct FModifier *add_fmodifier(ListBase *modifiers, int type);
struct FModifier *copy_fmodifier(struct FModifier *src);
void copy_fmodifiers(ListBase *dst, ListBase *src);
int remove_fmodifier(ListBase *modifiers, struct FModifier *fcm);
int remove_fmodifier_index(ListBase *modifiers, int index);

@ -871,6 +871,49 @@ static FModifierTypeInfo FMI_LIMITS = {
fcm_limits_evaluate /* evaluate */
};
/* Stepped F-Curve Modifier --------------------------- */
static void fcm_stepped_new_data (void *mdata)
{
FMod_Stepped *data= (FMod_Stepped *)mdata;
/* just need to set the step-size to 2-frames by default */
// XXX: or would 5 be more normal?
data->step_size = 2.0f;
}
static float fcm_stepped_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
{
FMod_Stepped *data= (FMod_Stepped *)fcm->data;
int snapblock;
/* we snap to the start of the previous closest block of 'step_size' frames
* after the start offset has been discarded
* - i.e. round down
*/
snapblock = (int)((evaltime - data->start) / data->step_size);
/* reapply the offset, and multiple the snapblock by the size of the steps to get
* the new time to evaluate at
*/
return ((float)snapblock * data->step_size) + data->start;
}
static FModifierTypeInfo FMI_STEPPED = {
FMODIFIER_TYPE_STEPPED, /* type */
sizeof(FMod_Limits), /* size */
FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */
FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
"Stepped", /* name */
"FMod_Stepped", /* struct name */
NULL, /* free data */
NULL, /* copy data */
fcm_stepped_new_data, /* new data */
NULL, /* verify */
fcm_stepped_time, /* evaluate time */
NULL /* evaluate */
};
/* F-Curve Modifier API --------------------------- */
/* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out
* and operations that involve F-Curve modifier specific code.
@ -892,6 +935,7 @@ static void fmods_init_typeinfo ()
fmodifiersTypeInfo[6]= NULL/*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented
fmodifiersTypeInfo[7]= &FMI_PYTHON; /* Custom Python F-Curve Modifier */
fmodifiersTypeInfo[8]= &FMI_LIMITS; /* Limits F-Curve Modifier */
fmodifiersTypeInfo[9]= &FMI_STEPPED; /* Stepped F-Curve Modifier */
}
/* This function should be used for getting the appropriate type-info when only
@ -968,6 +1012,31 @@ FModifier *add_fmodifier (ListBase *modifiers, int type)
return fcm;
}
/* 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;
}
/* Duplicate all of the F-Modifiers in the Modifier stacks */
void copy_fmodifiers (ListBase *dst, ListBase *src)
{

@ -30,6 +30,9 @@
* This file defines the (C-Coded) templates + editing callbacks needed
* by the interface stuff or F-Modifiers, as used by F-Curves in the Graph Editor,
* and NLA-Strips in the NLA Editor.
*
* Copy/Paste Buffer for F-Modifiers:
* For now, this is also defined in this file so that it can be shared between the
*/
#include <string.h>
@ -47,15 +50,18 @@
#include "RNA_access.h"
#include "ED_anim_api.h"
#include "UI_interface.h"
#include "UI_resources.h"
/* ********************************************** */
/* UI STUFF */
// XXX! --------------------------------
/* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */
#define UI_FLT_MAX 10000.0f
/* ********************************************** */
#define B_REDR 1
#define B_FMODIFIER_REDRAW 20
@ -549,6 +555,22 @@ static void draw_modifier__limits(uiLayout *layout, ID *id, FModifier *fcm, shor
/* --------------- */
/* draw settings for stepped interpolation modifier */
static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, short width)
{
uiLayout *col;
PointerRNA ptr;
/* init the RNA-pointer */
RNA_pointer_create(id, &RNA_FModifierStepped, fcm, &ptr);
col= uiLayoutColumn(layout, 0);
uiItemR(col, NULL, 0, &ptr, "step_size", 0);
uiItemR(col, NULL, 0, &ptr, "start_offset", 0);
}
/* --------------- */
void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
{
@ -636,6 +658,10 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie
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;
}
@ -643,3 +669,81 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie
}
/* ********************************************** */
/* COPY/PASTE BUFFER STUFF */
/* Copy/Paste Buffer itself (list of FModifier 's) */
static ListBase fmodifier_copypaste_buf = {NULL, NULL};
/* ---------- */
/* free the copy/paste buffer */
void free_fmodifiers_copybuf (void)
{
/* just free the whole buffer */
free_fmodifiers(&fmodifier_copypaste_buf);
}
/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
* assuming that the buffer has been cleared already with free_fmodifiers_copybuf()
* - active: only copy the active modifier
*/
short ANIM_fmodifiers_copy_to_buf (ListBase *modifiers, short active)
{
short ok = 1;
/* sanity checks */
if ELEM(NULL, modifiers, modifiers->first)
return 0;
/* copy the whole list, or just the active one? */
if (active) {
FModifier *fcm = find_active_fmodifier(modifiers);
if (fcm) {
FModifier *fcmN = copy_fmodifier(fcm);
BLI_addtail(&fmodifier_copypaste_buf, fcmN);
}
else
ok = 0;
}
else
copy_fmodifiers(&fmodifier_copypaste_buf, modifiers);
/* did we succeed? */
return ok;
}
/* 'Paste' the F-Modifier(s) from the buffer to the specified list
* - replace: free all the existing modifiers to leave only the pasted ones
*/
short ANIM_fmodifiers_paste_from_buf (ListBase *modifiers, short replace)
{
FModifier *fcm;
short ok = 0;
/* sanity checks */
if (modifiers == NULL)
return 0;
/* if replacing the list, free the existing modifiers */
if (replace)
free_fmodifiers(modifiers);
/* now copy over all the modifiers in the buffer to the end of the list */
for (fcm= fmodifier_copypaste_buf.first; fcm; fcm= fcm->next) {
/* make a copy of it */
FModifier *fcmN = copy_fmodifier(fcm);
/* make sure the new one isn't active, otherwise the list may get several actives */
fcmN->flag &= ~FMODIFIER_FLAG_ACTIVE;
/* now add it to the end of the list */
BLI_addtail(modifiers, fcmN);
ok = 1;
}
/* did we succeed? */
return ok;
}
/* ********************************************** */

@ -452,9 +452,28 @@ void ANIM_draw_previewrange(const struct bContext *C, struct View2D *v2d);
/* ************************************************* */
/* F-MODIFIER TOOLS */
/* ------------- UI Panel Drawing -------------- */
/* draw a given F-Modifier for some layout/UI-Block */
void ANIM_uiTemplate_fmodifier_draw(struct uiLayout *layout, struct ID *id, ListBase *modifiers, struct FModifier *fcm);
/* ------------- Copy/Paste Buffer -------------- */
/* free the copy/paste buffer */
void free_fmodifiers_copybuf(void);
/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
* assuming that the buffer has been cleared already with free_fmodifiers_copybuf()
* - active: only copy the active modifier
*/
short ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, short active);
/* 'Paste' the F-Modifier(s) from the buffer to the specified list
* - replace: free all the existing modifiers to leave only the pasted ones
*/
short ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, short replace);
/* ************************************************* */
/* ASSORTED TOOLS */

@ -610,8 +610,13 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
row= uiLayoutRow(pa->layout, 0);
block= uiLayoutGetBlock(row);
// XXX for now, this will be a operator button which calls a temporary 'add modifier' operator
// XXX for now, this will be a operator button which calls a 'add modifier' operator
uiDefButO(block, BUT, "GRAPH_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, "Add Modifier", 10, 0, 150, 20, "Adds a new F-Curve Modifier for the active F-Curve");
/* copy/paste (as sub-row)*/
row= uiLayoutRow(row, 1);
uiItemO(row, "", ICON_COPYDOWN, "GRAPH_OT_fmodifier_copy");
uiItemO(row, "", ICON_PASTEDOWN, "GRAPH_OT_fmodifier_paste");
}
/* draw each modifier */

@ -1971,7 +1971,7 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
filter |= (ANIMFILTER_SEL|ANIMFILTER_CURVEVISIBLE);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* smooth keyframes */
/* add f-modifier to each curve */
for (ale= anim_data.first; ale; ale= ale->next) {
FCurve *fcu= (FCurve *)ale->data;
FModifier *fcm;
@ -2017,4 +2017,119 @@ void GRAPH_OT_fmodifier_add (wmOperatorType *ot)
RNA_def_boolean(ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve.");
}
/* ******************** Copy F-Modifiers Operator *********************** */
static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
bAnimListElem *ale;
short ok = 0;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* clear buffer first */
free_fmodifiers_copybuf();
/* get the active F-Curve */
ale= get_active_fcurve_channel(&ac);
/* if this exists, call the copy F-Modifiers API function */
if (ale && ale->data) {
FCurve *fcu= (FCurve *)ale->data;
// TODO: when 'active' vs 'all' boolean is added, change last param!
ok= ANIM_fmodifiers_copy_to_buf(&fcu->modifiers, 0);
/* free temp data now */
MEM_freeN(ale);
}
/* successful or not? */
if (ok == 0) {
BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
return OPERATOR_CANCELLED;
}
else
return OPERATOR_FINISHED;
}
void GRAPH_OT_fmodifier_copy (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Copy F-Modifiers";
ot->idname= "GRAPH_OT_fmodifier_copy";
ot->description= "Copy the F-Modifier(s) of the active F-Curve.";
/* api callbacks */
ot->exec= graph_fmodifier_copy_exec;
ot->poll= graphop_active_fcurve_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* id-props */
//ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one");
}
/* ******************** Paste F-Modifiers Operator *********************** */
static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter, ok=0;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* filter data */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* paste modifiers */
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu= (FCurve *)ale->data;
// TODO: do we want to replace existing modifiers? add user pref for that!
ok += ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, 0);
}
/* clean up */
BLI_freelistN(&anim_data);
/* successful or not? */
if (ok) {
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
else {
BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
return OPERATOR_CANCELLED;
}
}
void GRAPH_OT_fmodifier_paste (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Paste F-Modifiers";
ot->idname= "GRAPH_OT_fmodifier_paste";
ot->description= "Add copied F-Modifiers to the selected F-Curves";
/* api callbacks */
ot->exec= graph_fmodifier_paste_exec;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* ************************************************************************** */

@ -139,6 +139,8 @@ enum {
/* ----------- */
void GRAPH_OT_fmodifier_add(struct wmOperatorType *ot);
void GRAPH_OT_fmodifier_copy(struct wmOperatorType *ot);
void GRAPH_OT_fmodifier_paste(struct wmOperatorType *ot);
/* ----------- */

@ -262,8 +262,9 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_click_insert);
/* F-Curve Modifiers */
// XXX temporary?
WM_operatortype_append(GRAPH_OT_fmodifier_add);
WM_operatortype_append(GRAPH_OT_fmodifier_copy);
WM_operatortype_append(GRAPH_OT_fmodifier_paste);
}
/* ************************** registration - keymaps **********************************/

@ -430,6 +430,11 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
// XXX for now, this will be a operator button which calls a temporary 'add modifier' operator
// FIXME: we need to set the only-active property so that this will only add modifiers for the active strip (not all selected)
uiDefButO(block, BUT, "NLA_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, "Add Modifier", 10, 0, 150, 20, "Adds a new F-Modifier for the active NLA Strip");
/* copy/paste (as sub-row)*/
row= uiLayoutRow(row, 1);
uiItemO(row, "", ICON_COPYDOWN, "NLA_OT_fmodifier_copy");
uiItemO(row, "", ICON_PASTEDOWN, "NLA_OT_fmodifier_paste");
}
/* draw each modifier */

@ -1633,8 +1633,7 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
BLI_freelistN(&anim_data);
/* set notifier that things have changed */
// FIXME: this doesn't really do it justice...
WM_event_add_notifier(C, NC_ANIMATION, NULL);
WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
/* done */
return OPERATOR_FINISHED;
@ -1659,4 +1658,125 @@ void NLA_OT_fmodifier_add (wmOperatorType *ot)
RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add F-Modifier of the specified type to the active strip.");
}
/* ******************** Copy F-Modifiers Operator *********************** */
static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter, ok=0;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* clear buffer first */
free_fmodifiers_copybuf();
/* 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 NLA-Track, add the specified modifier to all selected strips */
for (ale= anim_data.first; ale; ale= ale->next) {
NlaTrack *nlt= (NlaTrack *)ale->data;
NlaStrip *strip;
for (strip= nlt->strips.first; strip; strip=strip->next) {
/* only add F-Modifier if on active strip? */
if ((strip->flag & NLASTRIP_FLAG_ACTIVE)==0)
continue;
// TODO: when 'active' vs 'all' boolean is added, change last param!
ok += ANIM_fmodifiers_copy_to_buf(&strip->modifiers, 0);
}
}
/* successful or not? */
if (ok == 0) {
BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
return OPERATOR_CANCELLED;
}
else
return OPERATOR_FINISHED;
}
void NLA_OT_fmodifier_copy (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Copy F-Modifiers";
ot->idname= "NLA_OT_fmodifier_copy";
ot->description= "Copy the F-Modifier(s) of the active NLA-Strip.";
/* api callbacks */
ot->exec= nla_fmodifier_copy_exec;
ot->poll= nlaop_poll_tweakmode_off;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* id-props */
//ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one");
}
/* ******************** Paste F-Modifiers Operator *********************** */
static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter, ok=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_SEL | ANIMFILTER_FOREDIT);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, add the specified modifier to all selected strips */
for (ale= anim_data.first; ale; ale= ale->next) {
NlaTrack *nlt= (NlaTrack *)ale->data;
NlaStrip *strip;
for (strip= nlt->strips.first; strip; strip=strip->next) {
// TODO: do we want to replace existing modifiers? add user pref for that!
ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0);
}
}
/* clean up */
BLI_freelistN(&anim_data);
/* successful or not? */
if (ok) {
/* set notifier that things have changed */
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
return OPERATOR_FINISHED;
}
else {
BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
return OPERATOR_CANCELLED;
}
}
void NLA_OT_fmodifier_paste (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Paste F-Modifiers";
ot->idname= "NLA_OT_fmodifier_paste";
ot->description= "Add copied F-Modifiers to the selected NLA-Strips";
/* api callbacks */
ot->exec= nla_fmodifier_paste_exec;
ot->poll= nlaop_poll_tweakmode_off;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* *********************************************** */

@ -111,6 +111,8 @@ void NLA_OT_clear_scale(wmOperatorType *ot);
void NLA_OT_snap(wmOperatorType *ot);
void NLA_OT_fmodifier_add(wmOperatorType *ot);
void NLA_OT_fmodifier_copy(wmOperatorType *ot);
void NLA_OT_fmodifier_paste(wmOperatorType *ot);
/* **************************************** */

@ -165,6 +165,8 @@ void nla_operatortypes(void)
WM_operatortype_append(NLA_OT_snap);
WM_operatortype_append(NLA_OT_fmodifier_add);
WM_operatortype_append(NLA_OT_fmodifier_copy);
WM_operatortype_append(NLA_OT_fmodifier_paste);
}
/* ************************** registration - keymaps **********************************/

@ -73,6 +73,7 @@ typedef enum eFModifier_Types {
FMODIFIER_TYPE_FILTER, /* unimplemented - for applying: fft, high/low pass filters, etc. */
FMODIFIER_TYPE_PYTHON,
FMODIFIER_TYPE_LIMITS,
FMODIFIER_TYPE_STEPPED,
/* NOTE: all new modifiers must be added above this line */
FMODIFIER_NUM_TYPES
@ -211,6 +212,7 @@ typedef enum eFMod_Limit_Flags {
FCM_LIMIT_YMAX = (1<<3),
} eFMod_Limit_Flags;
/* noise modifier data */
typedef struct FMod_Noise {
float size;
@ -230,6 +232,13 @@ typedef enum eFMod_Noise_Modifications {
FCM_NOISE_MODIF_MULTIPLY, /* Multiply the curve by noise */
} eFMod_Noise_Modifications;
/* stepped modifier data */
typedef struct FMod_Stepped {
float step_size; /* Number of frames each interpolated value should be held */
float start; /* Reference frame number that stepping starts from */
} FMod_Stepped;
/* Drivers -------------------------------------- */
/* Driver Target (dtar)

@ -217,6 +217,7 @@ extern StructRNA RNA_FModifierGenerator;
extern StructRNA RNA_FModifierLimits;
extern StructRNA RNA_FModifierNoise;
extern StructRNA RNA_FModifierPython;
extern StructRNA RNA_FModifierStepped;
extern StructRNA RNA_FollowPathConstraint;
extern StructRNA RNA_Function;
extern StructRNA RNA_GameBooleanProperty;

@ -51,6 +51,7 @@ EnumPropertyItem fmodifier_type_items[] = {
{FMODIFIER_TYPE_FILTER, "FILTER", 0, "Filter", ""},
{FMODIFIER_TYPE_PYTHON, "PYTHON", 0, "Python", ""},
{FMODIFIER_TYPE_LIMITS, "LIMITS", 0, "Limits", ""},
{FMODIFIER_TYPE_STEPPED, "STEPPED", 0, "Stepped Interpolation", ""},
{0, NULL, 0, NULL, NULL}};
EnumPropertyItem beztriple_keyframe_type_items[] = {
@ -84,6 +85,8 @@ static StructRNA *rna_FModifierType_refine(struct PointerRNA *ptr)
return &RNA_FModifierPython;
case FMODIFIER_TYPE_LIMITS:
return &RNA_FModifierLimits;
case FMODIFIER_TYPE_STEPPED:
return &RNA_FModifierStepped;
default:
return &RNA_UnknownType;
}
@ -712,9 +715,31 @@ static void rna_def_fmodifier_noise(BlenderRNA *brna)
}
/* --------- */
static void rna_def_fmodifier_stepped(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "FModifierStepped", "FModifier");
RNA_def_struct_ui_text(srna, "Stepped Interpolation F-Modifier", "Holds each interpolated value from the F-Curve for several frames without changing the timing");
RNA_def_struct_sdna_from(srna, "FMod_Stepped", "data");
/* properties */
prop= RNA_def_property(srna, "step_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Step Size", "Number of frames to hold each value");
RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
prop= RNA_def_property(srna, "start_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "start");
RNA_def_property_ui_text(prop, "Start Offset", "Reference number of frames before frames get held. Use to get hold for '1-3' vs '5-7' holding patterns");
RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
}
/* --------- */
static void rna_def_fmodifier(BlenderRNA *brna)
{
StructRNA *srna;
@ -1209,6 +1234,7 @@ void RNA_def_fcurve(BlenderRNA *brna)
rna_def_fmodifier_python(brna);
rna_def_fmodifier_limits(brna);
rna_def_fmodifier_noise(brna);
rna_def_fmodifier_stepped(brna);
}

@ -217,6 +217,7 @@ extern wchar_t *copybufinfo;
// XXX copy/paste buffer stuff...
extern void free_anim_copybuf();
extern void free_anim_drivers_copybuf();
extern void free_fmodifiers_copybuf();
extern void free_posebuf();
/* called in creator.c even... tsk, split this! */
@ -272,6 +273,7 @@ void WM_exit(bContext *C)
// free_matcopybuf();
free_anim_copybuf();
free_anim_drivers_copybuf();
free_fmodifiers_copybuf();
free_posebuf();
// free_vertexpaint();
// free_imagepaint();