Revision: 19713
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=19713
Author:   aligorith
Date:     2009-04-14 13:53:41 +0200 (Tue, 14 Apr 2009)

Log Message:
-----------
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).

Modified Paths:
--------------
    branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c
    
branches/blender2.5/blender/source/blender/editors/space_graph/graph_buttons.c
    branches/blender2.5/blender/source/blender/editors/space_graph/graph_edit.c
    branches/blender2.5/blender/source/blender/makesdna/DNA_anim_types.h

Modified: branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c
===================================================================
--- branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c       
2009-04-14 10:18:48 UTC (rev 19712)
+++ branches/blender2.5/blender/source/blender/blenkernel/intern/fcurve.c       
2009-04-14 11:53:41 UTC (rev 19713)
@@ -1135,6 +1135,43 @@
 };
 #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_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 @@
                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 @@
 };
 
 
+/* 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 @@
        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

Modified: 
branches/blender2.5/blender/source/blender/editors/space_graph/graph_buttons.c
===================================================================
--- 
branches/blender2.5/blender/source/blender/editors/space_graph/graph_buttons.c  
    2009-04-14 10:18:48 UTC (rev 19712)
+++ 
branches/blender2.5/blender/source/blender/editors/space_graph/graph_buttons.c  
    2009-04-14 11:53:41 UTC (rev 19713)
@@ -754,6 +754,43 @@
 
 /* --------------- */
 
+/* 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 @@
                        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;

Modified: 
branches/blender2.5/blender/source/blender/editors/space_graph/graph_edit.c
===================================================================
--- branches/blender2.5/blender/source/blender/editors/space_graph/graph_edit.c 
2009-04-14 10:18:48 UTC (rev 19712)
+++ branches/blender2.5/blender/source/blender/editors/space_graph/graph_edit.c 
2009-04-14 11:53:41 UTC (rev 19713)
@@ -1647,6 +1647,7 @@
        {FMODIFIER_TYPE_NOISE, "NOISE", "Noise", ""},
        {FMODIFIER_TYPE_FILTER, "FILTER", "Filter", ""},
        {FMODIFIER_TYPE_PYTHON, "PYTHON", "Python", ""},
+       {FMODIFIER_TYPE_LIMITS, "LIMITS", "Limits", ""},
        {0, NULL, NULL, NULL}
 };
 

Modified: branches/blender2.5/blender/source/blender/makesdna/DNA_anim_types.h
===================================================================
--- branches/blender2.5/blender/source/blender/makesdna/DNA_anim_types.h        
2009-04-14 10:18:48 UTC (rev 19712)
+++ branches/blender2.5/blender/source/blender/makesdna/DNA_anim_types.h        
2009-04-14 11:53:41 UTC (rev 19713)
@@ -46,7 +46,8 @@
        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 @@
        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)


_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to