FModifier Influence/BlendIn-Out
authorJoshua Leung <aligorith@gmail.com>
Sat, 4 Jun 2011 06:22:01 +0000 (06:22 +0000)
committerJoshua Leung <aligorith@gmail.com>
Sat, 4 Jun 2011 06:22:01 +0000 (06:22 +0000)
Following on from my commit to introduce frame ranges for FModifiers,
those frame ranges can now have blend in/out values. By setting a
blendin or blendout value, you're specifying the number of frames for
the modifier's "full influence" to take effect or fade out relative to
the start/end frames.

The "full influence" above needs a little clarification.

When the "use influence" setting is enabled, "full influence" is taken
from the "influence" slider (a new setting). Otherwise, it uses 1.0
(i.e. unmodified influence, same as old behaviour before the
introduction of influence controls). The influence slider basically
says how much the modifier's effects are allowed to contribute to the
final result.

---

Notes:
- This opt-in "Use Influence" approach is really forced upon us
because there are heaps of old files for which we cannot easily
version patch without spending some effort going through all the data
in the file, hunting out the F-Modifiers.
- interpf() seems to use a backwards order compared to everything else

source/blender/blenkernel/intern/fmodifier.c
source/blender/editors/animation/fmodifier_ui.c
source/blender/makesdna/DNA_anim_types.h
source/blender/makesrna/intern/rna_fcurve.c

index 4a1a0f9ac6b949f000c031dcc26e8e4fe440e95d..dcf81c194798573be58e030038684c5d137517aa 100644 (file)
@@ -1013,6 +1013,7 @@ FModifier *add_fmodifier (ListBase *modifiers, int type)
        fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
        fcm->type = type;
        fcm->flag = FMODIFIER_FLAG_EXPANDED;
+       fcm->influence = 1.0f;
        BLI_addtail(modifiers, fcm);
        
        /* tag modifier as "active" if no other modifiers exist in the stack yet */
@@ -1200,6 +1201,47 @@ short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype
 
 /* Evaluation API --------------------------- */
 
+/* helper function - calculate influence of FModifier */
+static float eval_fmodifier_influence (FModifier *fcm, float evaltime)
+{
+       float influence;
+       
+       /* sanity check */
+       if (fcm == NULL) 
+               return 0.0f;
+       
+       /* should we use influence stored in modifier or not 
+        * NOTE: this is really just a hack so that we don't need to version patch old files ;)
+        */
+       if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE)
+               influence = fcm->influence;
+       else
+               influence = 1.0f;
+               
+       /* restricted range or full range? */
+       if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
+               if ((evaltime <= fcm->sfra) || (evaltime >= fcm->efra)) {
+                       /* out of range */
+                       return 0.0f;
+               }
+               else if ((evaltime > fcm->sfra) && (evaltime < fcm->sfra + fcm->blendin)) {
+                       /* blend in range */
+                       float a = fcm->sfra;
+                       float b = fcm->sfra + fcm->blendin;
+                       return influence * (evaltime - a) / (b - a);
+               }
+               else if ((evaltime < fcm->efra) && (evaltime > fcm->efra - fcm->blendout)) {
+                       /* blend out range */
+                       float a = fcm->efra;
+                       float b = fcm->efra - fcm->blendout;
+                       return influence * (evaltime - a) / (b - a);
+               }
+       }
+       
+       /* just return the influence of the modifier */
+       return influence;
+}
+
 /* 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
@@ -1240,10 +1282,13 @@ float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue,
                        ((fcm->sfra <= evaltime) && (fcm->efra >= evaltime)) )
                {
                        /* only evaluate if there's a callback for this */
-                       // TODO: implement the 'influence' control feature...
                        if (fmi->evaluate_modifier_time) {
-                               if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
-                                       evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
+                               if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) {
+                                       float influence = eval_fmodifier_influence(fcm, evaltime);
+                                       float nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
+                                       
+                                       evaltime = interpf(nval, evaltime, influence);
+                               }
                        }
                }
        }
@@ -1271,13 +1316,17 @@ void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue,
                        continue;
                
                /* only evaluate if there's a callback for this, and if F-Modifier can be evaluated on this frame */
-               // TODO: implement the 'influence' control feature...
                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)
-                                       fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime);
+                               if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0) {
+                                       float influence = eval_fmodifier_influence(fcm, evaltime);
+                                       float nval = *cvalue;
+                                       
+                                       fmi->evaluate_modifier(fcu, fcm, &nval, evaltime);
+                                       *cvalue = interpf(nval, *cvalue, influence);
+                               }
                        }
                }
        }
index 3018fa697b841769ed9bca89a7bc9f8363b9fc9c..8058454f5101af4410a95fa576bb4f59fa0ac33b 100644 (file)
@@ -604,7 +604,7 @@ static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, sho
 void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
 {
        FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-       uiLayout *box, *row, *subrow;
+       uiLayout *box, *row, *subrow, *col;
        uiBlock *block;
        uiBut *but;
        short width= 314;
@@ -700,16 +700,36 @@ void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifie
                {
                        box = uiLayoutBox(layout);
                        
+                       /* restricted range ----------------------------------------------------- */
+                       col = uiLayoutColumn(box, 1);
+                       
                        /* top row: use restricted range */
-                       row= uiLayoutRow(box, 0);
+                       row= uiLayoutRow(col, 1);
                        uiItemR(row, &ptr, "use_restricted_range", 0, NULL, ICON_NONE);
                        
                        if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
                                /* second row: settings */
-                               row = uiLayoutRow(box, 1);
+                               row = uiLayoutRow(col, 1);
                                
                                uiItemR(row, &ptr, "frame_start", 0, "Start", ICON_NONE);
                                uiItemR(row, &ptr, "frame_end", 0, "End", ICON_NONE);
+                               
+                               /* third row: blending influence */
+                               row = uiLayoutRow(col, 1);
+                               
+                               uiItemR(row, &ptr, "blend_in", 0, "In", ICON_NONE);
+                               uiItemR(row, &ptr, "blend_out", 0, "Out", ICON_NONE);
+                       }
+                       
+                       /* influence -------------------------------------------------------------- */
+                       col = uiLayoutColumn(box, 1);
+                       
+                       /* 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);
                        }
                }
        }
index 88a3fe81825fb7baa94fc26aa1279e97d002474c..c650d15722d23a453f5775c9822eb386b19bf59b 100644 (file)
@@ -65,6 +65,8 @@ typedef struct FModifier {
        
        float sfra;                     /* start frame of restricted frame-range */
        float efra;                     /* end frame of restricted frame-range */
+       float blendin;          /* number of frames from sfra before modifier takes full influence */
+       float blendout;         /* number of frames from efra before modifier fades out */
 } FModifier;
 
 /* Types of F-Curve modifier 
@@ -97,7 +99,9 @@ typedef enum eFModifier_Flags {
                /* user wants modifier to be skipped */
        FMODIFIER_FLAG_MUTED             = (1<<3),
                /* restrict range that F-Modifier can be considered over */
-       FMODIFIER_FLAG_RANGERESTRICT = (1<<4)
+       FMODIFIER_FLAG_RANGERESTRICT = (1<<4),
+               /* use influence control */
+       FMODIFIER_FLAG_USEINFLUENCE  = (1<<5)
 } eFModifier_Flags; 
 
 /* --- */
index ba0563f554abcc6fe852542efb43acbe58db1d6b..263978221bb30b71a373c7e574fb2f0cf351ec1d 100644 (file)
@@ -470,6 +470,14 @@ static void rna_FModifier_end_frame_range(PointerRNA *ptr, float *min, float *ma
        *max= MAXFRAMEF;
 }
 
+static void rna_FModifier_blending_range(PointerRNA *ptr, float *min, float *max)
+{
+       FModifier *fcm= (FModifier*)ptr->data;
+
+       *min= 0.0f;
+       *max= fcm->efra - fcm->sfra;
+}
+
 static void rna_FModifier_active_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
 {
        FModifier *fm, *fmo= (FModifier*)ptr->data;
@@ -1050,6 +1058,32 @@ static void rna_def_fmodifier(BlenderRNA *brna)
        RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifier_end_frame_range");
        RNA_def_property_ui_text(prop, "End Frame", "Frame that modifier's influence ends (if Restrict Frame Range is in use)");
        RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
+       
+       prop= RNA_def_property(srna, "blend_in", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "blendin");
+       RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifier_blending_range");
+       RNA_def_property_ui_text(prop, "Blend In", "Number of frames from start frame for influence to take effect");
+       RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
+       
+       prop= RNA_def_property(srna, "blend_out", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "blendout");
+       RNA_def_property_float_funcs(prop, NULL, NULL, "rna_FModifier_blending_range");
+       RNA_def_property_ui_text(prop, "Blend Out", "Number of frames from start frame for influence to fade out");
+       RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
+       
+       /* influence */
+       prop= RNA_def_property(srna, "use_influence", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", FMODIFIER_FLAG_USEINFLUENCE);
+       RNA_def_property_ui_text(prop, "Use Influence", "F-Curve Modifier's effects will be tempered by a default factor");
+       RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
+       RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); // XXX: depends on UI implementation
+       
+       prop= RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR);
+       RNA_def_property_float_sdna(prop, NULL, "influence");
+       RNA_def_property_range(prop, 0.0f, 1.0f);
+       RNA_def_property_float_default(prop, 1.0f);
+       RNA_def_property_ui_text(prop, "Influence", "Amount of influence F-Curve Modifier will have when not fading in/out");
+       RNA_def_property_update(prop, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
 }      
 
 /* *********************** */