Merging with trunk up to r38631.
[blender.git] / source / blender / blenkernel / intern / fmodifier.c
index 0376d75d65183fc72d8c801ae98bac612002f2da..dcf81c194798573be58e030038684c5d137517aa 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/blenkernel/intern/fmodifier.c
+ *  \ingroup bke
+ */
+
+
 
 #include <math.h>
 #include <stdio.h>
 
 #include "BLI_blenlib.h"
 #include "BLI_math.h" /* windows needs for M_PI */
+#include "BLI_utildefines.h"
 
 #include "BKE_fcurve.h"
 #include "BKE_idprop.h"
-#include "BKE_utildefines.h"
+
 
 #define SMALL -1.0e-10
 #define SELECT 1
@@ -340,7 +346,7 @@ static void fcm_fn_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, floa
                case FCM_GENERATOR_FN_LN: /* natural log */
                {
                        /* check that value is greater than 1? */
-                       if (arg > 1.0f) {
+                       if (arg > 1.0) {
                                fn= log;
                        }
                        else {
@@ -352,7 +358,7 @@ static void fcm_fn_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, floa
                case FCM_GENERATOR_FN_SQRT: /* square root */
                {
                        /* no negative numbers */
-                       if (arg > 0.0f) {
+                       if (arg > 0.0) {
                                fn= sqrt;
                        }
                        else {
@@ -368,7 +374,7 @@ static void fcm_fn_generator_evaluate (FCurve *UNUSED(fcu), FModifier *fcm, floa
        
        /* execute function callback to set value if appropriate */
        if (fn) {
-               float value= (float)(data->amplitude*fn(arg) + data->value_offset);
+               float value= (float)(data->amplitude*(float)fn(arg) + data->value_offset);
                
                if (data->flag & FCM_GENERATOR_ADDITIVE)
                        *cvalue += value;
@@ -1007,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 */
@@ -1194,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
@@ -1224,11 +1272,24 @@ float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue,
        for (fcm= modifiers->last; fcm; fcm= fcm->prev) {
                FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
                
-               /* only evaluate if there's a callback for this */
-               // TODO: implement the 'influence' control feature...
-               if (fmi && fmi->evaluate_modifier_time) {
-                       if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
-                               evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
+               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) {
+                                       float influence = eval_fmodifier_influence(fcm, evaltime);
+                                       float nval = fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
+                                       
+                                       evaltime = interpf(nval, evaltime, influence);
+                               }
+                       }
                }
        }
        
@@ -1251,11 +1312,22 @@ void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue,
        for (fcm= modifiers->first; fcm; fcm= fcm->next) {
                FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
                
-               /* only evaluate if there's a callback for this */
-               // TODO: implement the 'influence' control feature...
-               if (fmi && fmi->evaluate_modifier) {
-                       if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
-                               fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime);
+               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) {
+                                       float influence = eval_fmodifier_influence(fcm, evaltime);
+                                       float nval = *cvalue;
+                                       
+                                       fmi->evaluate_modifier(fcu, fcm, &nval, evaltime);
+                                       *cvalue = interpf(nval, *cvalue, influence);
+                               }
+                       }
                }
        }
 }