diff options
author | Joshua Leung <aligorith@gmail.com> | 2009-04-14 15:53:41 +0400 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2009-04-14 15:53:41 +0400 |
commit | 3ef247eed953ea28aca2bc92879ff1c32f04b7f4 (patch) | |
tree | 6b645679dd5046a483ec766105bb4c8144c3784b /source/blender | |
parent | 2d17d8623910b7cbcb353d410a47b9c758d8bc41 (diff) |
FCurve Modifiers - "Limits" Modifier:
This new modifier clamps the values of the F-Curve to lie within specified bounds, much like Limit Location/Rotation/Scale constraints do. You can limit by time range(s) and/or value range(s).
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/intern/fcurve.c | 86 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_buttons.c | 41 | ||||
-rw-r--r-- | source/blender/editors/space_graph/graph_edit.c | 1 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_anim_types.h | 19 |
4 files changed, 133 insertions, 14 deletions
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 3e1b6f29403..2783c135cb9 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -1135,6 +1135,43 @@ static FModifierTypeInfo FMI_MODNAME = { }; #endif +/* Utilities For F-Curve Modifiers ---------------------- */ + +/* Recalculate the F-Curve at evaltime, as modified by the given F-Curve */ +// TODO: this isn't really such an elegant solution for time-modifying F-Modifiers, but it gets too difficult otherwise for now... +static float fcm_reevaluate_fcurve (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime) +{ + ListBase modifiers = {NULL, NULL}; + float new_value = 0.0f; + + /* sanity checking */ + if ELEM(NULL, fcu, fcm) + return cvalue; + + /* unlink given modifier from previous modifiers, keeping the previous ones on the F-Curve, + * but ones after off the F-Curve (so that we avoid the infinitely re-entrant situation). + */ + modifiers.first= fcm; + modifiers.last= fcu->modifiers.last; + + if (fcm->prev) { + fcm->prev->next= NULL; + fcu->modifiers.last= fcm->prev; + } + else + fcu->modifiers.first= fcu->modifiers.last= NULL; + fcm->prev= NULL; + + /* re-enter the evaluation loop (but without the burden of evaluating any modifiers, so 'should' be relatively quick) */ + new_value= evaluate_fcurve(fcu, evaltime); + + /* restore modifiers (don't assume everything is still ok after being re-entrant) */ + addlisttolist(&fcu->modifiers, &modifiers); + + /* return the new value */ + return new_value; +} + /* Generator F-Curve Modifier --------------------------- */ /* Generators available: @@ -1547,9 +1584,7 @@ static void fcm_cycles_new_data (void *mdata) static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime) { FMod_Cycles *data= (FMod_Cycles *)fcm->data; - ListBase mods = {NULL, NULL}; float prevkey[2], lastkey[2], cycyofs=0.0f; - float new_value; short side=0, mode=0; int cycles=0; @@ -1644,17 +1679,8 @@ static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, flo if (evaltime < ofs) evaltime += cycdx; } - - /* store modifiers after (and including ourself) before recalculating curve with new evaltime */ - mods= fcu->modifiers; - fcu->modifiers.first= fcu->modifiers.last= NULL; - - /* re-enter the evaluation loop (but without the burden of evaluating any modifiers, so 'should' be relatively quick) */ - new_value= evaluate_fcurve(fcu, evaltime); - - /* restore modifiers, and set new value (don't assume everything is still ok after being re-entrant) */ - fcu->modifiers= mods; - *cvalue= new_value + cycyofs; + /* reevaluate F-Curve at the new time that we've decided on */ + *cvalue= fcm_reevaluate_fcurve(fcu, fcm, *cvalue, evaltime) + cycyofs; } static FModifierTypeInfo FMI_CYCLES = { @@ -1762,6 +1788,39 @@ static FModifierTypeInfo FMI_PYTHON = { }; +/* Limits F-Curve Modifier --------------------------- */ + +static void fcm_limits_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime) +{ + FMod_Limits *data= (FMod_Limits *)fcm->data; + + /* time limits first */ + if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin)) + *cvalue= fcm_reevaluate_fcurve(fcu, fcm, *cvalue, data->rect.xmin); + if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax)) + *cvalue= fcm_reevaluate_fcurve(fcu, fcm, *cvalue, data->rect.xmax); + + /* value limits now */ + if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin)) + *cvalue= data->rect.ymin; + if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax)) + *cvalue= data->rect.ymax; +} + +static FModifierTypeInfo FMI_LIMITS = { + FMODIFIER_TYPE_LIMITS, /* type */ + sizeof(FMod_Limits), /* size */ + FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */ + FMI_REQUIRES_RUNTIME_CHECK, /* requirements */ + "Limits", /* name */ + "FMod_Limits", /* struct name */ + NULL, /* free data */ + NULL, /* copy data */ + NULL, /* new data */ + NULL /*fcm_python_verify*/, /* verify */ + fcm_limits_evaluate /* 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. @@ -1781,6 +1840,7 @@ static void fmods_init_typeinfo () fmodifiersTypeInfo[4]= NULL/*&FMI_NOISE*/; /* Apply-Noise F-Curve Modifier */ // XXX unimplemented fmodifiersTypeInfo[5]= NULL/*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented fmodifiersTypeInfo[6]= &FMI_PYTHON; /* Custom Python F-Curve Modifier */ + fmodifiersTypeInfo[7]= &FMI_LIMITS; /* Limits F-Curve Modifier */ } /* This function should be used for getting the appropriate type-info when only diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index a59ec1fd4c8..680273ae508 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -754,6 +754,43 @@ static void draw_modifier__envelope(uiBlock *block, FCurve *fcu, FModifier *fcm, /* --------------- */ +/* draw settings for limits modifier */ +static void draw_modifier__limits(uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col) +{ + FMod_Limits *data= (FMod_Limits *)fcm->data; + const int togButWidth = 50; + const int textButWidth = ((width/2)-togButWidth); + + /* set the height */ + (*height) = 90; + + /* basic settings (backdrop + some padding) */ + //DRAW_BACKDROP((*height)); // XXX buggy... + + /* Draw Pairs of LimitToggle+LimitValue */ + uiBlockBeginAlign(block); + uiDefButBitI(block, TOGBUT, FCM_LIMIT_XMIN, B_FMODIFIER_REDRAW, "xMin", 10, *yco-30, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x value"); + uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 10+togButWidth, *yco-30, (textButWidth-5), 18, &data->rect.xmin, -FLT_MAX, FLT_MAX, 0.1,0.5,"Lowest x value to allow"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefButBitI(block, TOGBUT, FCM_LIMIT_XMAX, B_FMODIFIER_REDRAW, "XMax", 10+(width-(textButWidth-5)-togButWidth), *yco-30, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum x value"); + uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 10+(width-textButWidth-5), *yco-30, (textButWidth-5), 18, &data->rect.xmax, -FLT_MAX, FLT_MAX, 0.1,0.5,"Highest x value to allow"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefButBitI(block, TOGBUT, FCM_LIMIT_YMIN, B_FMODIFIER_REDRAW, "yMin", 10, *yco-52, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y value"); + uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 10+togButWidth, *yco-52, (textButWidth-5), 18, &data->rect.ymin, -FLT_MAX, FLT_MAX, 0.1,0.5,"Lowest y value to allow"); + uiBlockEndAlign(block); + + uiBlockBeginAlign(block); + uiDefButBitI(block, TOGBUT, FCM_LIMIT_YMAX, B_FMODIFIER_REDRAW, "YMax", 10+(width-(textButWidth-5)-togButWidth), *yco-52, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum y value"); + uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 10+(width-textButWidth-5), *yco-52, (textButWidth-5), 18, &data->rect.ymax, -FLT_MAX, FLT_MAX, 0.1,0.5,"Highest y value to allow"); + uiBlockEndAlign(block); +} + +/* --------------- */ + static void graph_panel_modifier_draw(uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco) { FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); @@ -810,6 +847,10 @@ static void graph_panel_modifier_draw(uiBlock *block, FCurve *fcu, FModifier *fc case FMODIFIER_TYPE_ENVELOPE: /* Envelope */ draw_modifier__envelope(block, fcu, fcm, yco, &height, width, active, rb_col); break; + + case FMODIFIER_TYPE_LIMITS: /* Limits */ + draw_modifier__limits(block, fcu, fcm, yco, &height, width, active, rb_col); + break; default: /* unknown type */ height= 96; diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 3aea32d64e7..52301ac1b0f 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1647,6 +1647,7 @@ EnumPropertyItem prop_fmodifier_types[] = { {FMODIFIER_TYPE_NOISE, "NOISE", "Noise", ""}, {FMODIFIER_TYPE_FILTER, "FILTER", "Filter", ""}, {FMODIFIER_TYPE_PYTHON, "PYTHON", "Python", ""}, + {FMODIFIER_TYPE_LIMITS, "LIMITS", "Limits", ""}, {0, NULL, NULL, NULL} }; diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 9112a714857..5956c65046b 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -46,7 +46,8 @@ enum { FMODIFIER_TYPE_CYCLES, FMODIFIER_TYPE_NOISE, /* unimplemented - generate variations using some basic noise generator... */ FMODIFIER_TYPE_FILTER, /* unimplemented - for applying: fft, high/low pass filters, etc. */ - FMODIFIER_TYPE_PYTHON, + FMODIFIER_TYPE_PYTHON, + FMODIFIER_TYPE_LIMITS, /* NOTE: all new modifiers must be added above this line */ FMODIFIER_NUM_TYPES @@ -149,6 +150,22 @@ typedef struct FMod_Python { IDProperty *prop; /* ID-properties to provide 'custom' settings */ } FMod_Python; + +/* limits modifier data */ +typedef struct FMod_Limits { + rctf rect; /* rect defining the min/max values */ + int flag; /* settings for limiting */ + int pad; +} FMod_Limits; + +/* limiting flags */ +enum { + FCM_LIMIT_XMIN = (1<<0), + FCM_LIMIT_XMAX = (1<<1), + FCM_LIMIT_YMIN = (1<<2), + FCM_LIMIT_YMAX = (1<<3), +} eFMod_Limit_Flags; + /* Drivers -------------------------------------- */ /* Channel Driver (i.e. Drivers / Expressions) (driver) |