F-Curve Modifiers: Generator Modifier Code
authorJoshua Leung <aligorith@gmail.com>
Mon, 16 Mar 2009 01:12:37 +0000 (01:12 +0000)
committerJoshua Leung <aligorith@gmail.com>
Mon, 16 Mar 2009 01:12:37 +0000 (01:12 +0000)
* Rewrote the Generator modifier to be more efficient and support more options
* A few UI tweaks for this, but the UI for this is still not yet functional though.

source/blender/blenkernel/intern/fcurve.c
source/blender/blenkernel/intern/ipo.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/space_graph/graph_buttons.c
source/blender/editors/space_graph/space_graph.c
source/blender/makesdna/DNA_anim_types.h

index e73a2e158adfcf80183fca775405b9e99be898b0..3b60be396e7bd18ec9c0187f672f6e6b276abdac 100644 (file)
@@ -6,6 +6,7 @@
 #include <math.h>
 #include <stdio.h>
 #include <string.h>
+#include <float.h>
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -1119,13 +1120,24 @@ static FModifierTypeInfo FMI_MODNAME = {
 
 /* Generator F-Curve Modifier --------------------------- */
 
+/* Generators available:
+ *     1) simple polynomial generator:
+ *             - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])  
+ *             - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
+ *     2) simple builin 'functions':
+ *             of the form (y = C[0] * fn( C[1]*x + C[2] ) + C[3])
+ *        where fn() can be any one of:
+ *             sin, cos, tan, ln, sqrt
+ *     3) expression...
+ */
+
 static void fcm_generator_free (FModifier *fcm)
 {
        FMod_Generator *data= (FMod_Generator *)fcm->data;
        
        /* free polynomial coefficients array */
-       if (data->poly_coefficients)
-               MEM_freeN(data->poly_coefficients);
+       if (data->coefficients)
+               MEM_freeN(data->coefficients);
 }
 
 static void fcm_generator_copy (FModifier *fcm, FModifier *src)
@@ -1133,9 +1145,9 @@ static void fcm_generator_copy (FModifier *fcm, FModifier *src)
        FMod_Generator *gen= (FMod_Generator *)fcm->data;
        FMod_Generator *ogen= (FMod_Generator *)src->data;
        
-       /* copy polynomial coefficients array? */
-       if (ogen->poly_coefficients)
-               gen->poly_coefficients= MEM_dupallocN(ogen->poly_coefficients);
+       /* copy coefficients array? */
+       if (ogen->coefficients)
+               gen->coefficients= MEM_dupallocN(ogen->coefficients);
 }
 
 static void fcm_generator_new_data (void *mdata)
@@ -1145,7 +1157,8 @@ static void fcm_generator_new_data (void *mdata)
        
        /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
        data->poly_order= 1;
-       cp= data->poly_coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs");
+       data->arraysize= 2;
+       cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs");
        cp[0] = 0; // y-offset 
        cp[1] = 1; // gradient
 }
@@ -1155,26 +1168,113 @@ static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue,
 {
        FMod_Generator *data= (FMod_Generator *)fcm->data;
        
-       /* behaviour depends on mode (NOTE: we don't need to do anything...) */
+       /* behaviour depends on mode 
+        * NOTE: the data in its default state is fine too
+        */
        switch (data->mode) {
-               // TODO: implement factorised polynomial too
-               case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
+               case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
                {
                        /* we overwrite cvalue with the sum of the polynomial */
-                       float value= 0.0f, *cp = NULL;
+                       float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers");
+                       float value= 0.0f;
                        unsigned int i;
                        
+                       /* for each x^n, precalculate value based on previous one first... this should be 
+                        * faster that calling pow() for each entry
+                        */
+                       for (i=0; i < data->arraysize; i++) {
+                               /* first entry is x^0 = 1, otherwise, calculate based on previous */
+                               if (i)
+                                       powers[i]= powers[i-1] * evaltime;
+                               else
+                                       powers[0]= 1;
+                       }
+                       
                        /* for each coefficient, add to value, which we'll write to *cvalue in one go */
-                       // TODO: could this be more efficient (i.e. without need to recalc pow() everytime)
-                       cp= data->poly_coefficients;
-                       for (i=0; (i <= data->poly_order) && (cp); i++, cp++)
-                               value += (*cp) * (float)pow(evaltime, i);
+                       for (i=0; i < data->arraysize; i++)
+                               value += data->coefficients[i] * powers[i];
                        
-                       /* only if something changed */
+                       /* only if something changed, write *cvalue in one go */
+                       if (data->poly_order)
+                               *cvalue= value;
+                               
+                       /* cleanup */
+                       if (powers) 
+                               MEM_freeN(powers);
+               }
+                       break;
+                       
+               case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
+               {
+                       float value= 1.0f, *cp=NULL;
+                       unsigned int i;
+                       
+                       /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */
+                       for (cp=data->coefficients, i=0; (cp) && (i < data->poly_order); cp+=2, i++) 
+                               value *= (cp[0]*evaltime + cp[1]);
+                               
+                       /* only if something changed, write *cvalue in one go */
                        if (data->poly_order)
                                *cvalue= value;
                }
                        break;
+                       
+               case FCM_GENERATOR_FUNCTION: /* builtin function */
+               {
+                       double arg= data->coefficients[1]*evaltime + data->coefficients[2];
+                       double (*fn)(double v) = NULL;
+                       
+                       /* get function pointer to the func to use:
+                        * WARNING: must perform special argument validation hereto guard against crashes  
+                        */
+                       switch (data->func_type)
+                       {
+                               /* simple ones */                       
+                               case FCM_GENERATOR_FN_SIN: /* sine wave */
+                                       fn= sin;
+                                       break;
+                               case FCM_GENERATOR_FN_COS: /* cosine wave */
+                                       fn= cos;
+                                       break;
+                                       
+                               /* validation required */
+                               case FCM_GENERATOR_FN_TAN: /* tangent wave */
+                               {
+                                       /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
+                                       if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0)
+                                               *cvalue= 0.0f; /* no value possible here */
+                                       else
+                                               fn= tan;
+                               }
+                                       break;
+                               case FCM_GENERATOR_FN_LN: /* natural log */
+                               {
+                                       /* check that value is greater than 1? */
+                                       if (arg > 1.0f)
+                                               fn= log;
+                                       else
+                                               *cvalue= 0.0f; /* no value possible here */
+                               }
+                                       break;
+                               case FCM_GENERATOR_FN_SQRT: /* square root */
+                               {
+                                       /* no negative numbers */
+                                       if (arg > 0.0f)
+                                               fn= sqrt;
+                                       else
+                                               *cvalue= 0.0f; /* no vlaue possible here */
+                               }
+                                       break;
+                                       
+                               default:
+                                       printf("Invalid Function-Generator for F-Modifier - %d \n", data->func_type);
+                       }
+                       
+                       /* execute function callback to set value if appropriate */
+                       if (fn)
+                               *cvalue= data->coefficients[0]*fn(arg) + data->coefficients[3];
+               }
+                       break;
 
 #ifndef DISABLE_PYTHON
                case FCM_GENERATOR_EXPRESSION: /* py-expression */
index dbb720fb0bc24903d289aa113e3d2f83dd9dde47..b9417ccb46713d927f9457f691fc62e3f7ec8784 100644 (file)
@@ -1730,53 +1730,5 @@ void do_versions_ipos_to_animato(Main *main)
        /* free unused drivers from actions + ipos */
        free_fcurves(&drivers);
        
-       printf("INFO: animato convert done \n"); // xxx debug
+       printf("INFO: Animato convert done \n"); // xxx debug
 }
-
-
-
-#if 0 // XXX old animation system
-
-/* ***************************** IPO - DataAPI ********************************* */
-
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!! FIXME - BAD CRUFT WARNING !!!!!!!!!!!!!!!!!!!!!!!
-
-/* These functions here should be replaced eventually by the Data API, as this is 
- * inflexible duplication...
- */
-
-/* --------------------- Get Pointer API ----------------------------- */ 
-
-
-/* GS reads the memory pointed at in a specific ordering. There are,
- * however two definitions for it. I have jotted them down here, both,
- * but I think the first one is actually used. The thing is that
- * big-endian systems might read this the wrong way round. OTOH, we
- * constructed the IDs that are read out with this macro explicitly as
- * well. I expect we'll sort it out soon... */
-
-/* from blendef: */
-#define GS(a)  (*((short *)(a)))
-
-/* from misc_util: flip the bytes from x  */
-/*  #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */
-
-
-/* general function to get pointer to source/destination data  */
-void *get_ipo_poin (ID *id, IpoCurve *icu, int *type)
-{
-       void *poin= NULL;
-       MTex *mtex= NULL;
-
-       /* most channels will have float data, but those with other types will override this */
-       *type= IPO_FLOAT;
-
-       /* data is divided into 'blocktypes' based on ID-codes */
-       // all adr codes put into converters!
-
-       /* return pointer */
-       return poin;
-}
-
-
-#endif // XXX old animation system
index e7d5fba23c8b005920c93604735652906b49dcc6..c2fd08bd20f5d810b0e9d97f48b66233ed8a05c5 100644 (file)
@@ -1725,7 +1725,7 @@ static void direct_link_fcurves(FileData *fd, ListBase *list)
                                {
                                        FMod_Generator *data= (FMod_Generator *)fcm->data;
                                        
-                                       data->poly_coefficients= newdataadr(fd, data->poly_coefficients);
+                                       data->coefficients= newdataadr(fd, data->coefficients);
                                }
                                        break;
                                case FMODIFIER_TYPE_PYTHON:
index 45742b8f020978e24119e1ca3fa8e705ec4106ff..2adce78c222877778d96f69bd5a00856ce053704 100644 (file)
@@ -805,9 +805,9 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves)
                                        {
                                                FMod_Generator *data= (FMod_Generator *)fcm->data;
                                                
-                                               /* write polynomial coefficients array */
-                                               if (data->poly_coefficients)
-                                                       writedata(wd, DATA, sizeof(float)*(data->poly_order+1), data->poly_coefficients);
+                                               /* write coefficients array */
+                                               if (data->coefficients)
+                                                       writedata(wd, DATA, sizeof(float)*(data->arraysize), data->coefficients);
                                        }
                                                break;
                                        case FMODIFIER_TYPE_PYTHON:
index 7c078ad184d361dc97cf21447387499fc720c720..c53b6a720de1390f5780c78c06c44a7f15361fc2 100644 (file)
@@ -231,8 +231,47 @@ static void do_graph_region_modifier_buttons(bContext *C, void *arg, int event)
        }
 }
 
+/* macro for use here to draw background box and set height */
+#define DRAW_BACKDROP(height, h) \
+       { \
+               height= h; \
+               if (active) uiBlockSetCol(block, TH_BUT_ACTION); \
+                       uiDefBut(block, ROUNDBOX, B_REDR, "", 10-8, *yco-height, width, height-1, NULL, 5.0, 0.0, 12.0, (float)rb_col, ""); \
+               if (active) uiBlockSetCol(block, TH_AUTO); \
+       }
+
+/* draw settings for generator modifier */
+static void _draw_modifier__generator(uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
+{
+       FMod_Generator *data= (FMod_Generator *)fcm->data;
+       
+       switch (data->mode) {
+               case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
+               {
+                       /* we overwrite cvalue with the sum of the polynomial */
+                       float value= 0.0f, *cp = NULL;
+                       unsigned int i;
+                       
+                       /* draw backdrop */
+                       DRAW_BACKDROP((*height), 96);
+                       
+                       /* for each coefficient, add to value, which we'll write to *cvalue in one go */
+                       cp= data->coefficients;
+                       for (i=0; (i < data->arraysize) && (cp); i++, cp++) {
+                       
+                       }
+               }
+                       break;
+               
+#ifndef DISABLE_PYTHON
+               case FCM_GENERATOR_EXPRESSION: /* py-expression */
+                       // TODO...
+                       break;
+#endif /* DISABLE_PYTHON */
+       }
+}
+
 
-/* for now, just print name of modifier */
 static void graph_panel_modifier_draw(uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco)
 {
        FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
@@ -269,12 +308,16 @@ static void graph_panel_modifier_draw(uiBlock *block, FCurve *fcu, FModifier *fc
        
        /* when modifier is expanded, draw settings */
        if (fcm->flag & FMODIFIER_FLAG_EXPANDED) {
-               height= 97;
-               
-               /* draw backdrop */
-               if (active) uiBlockSetCol(block, TH_BUT_ACTION);
-                       uiDefBut(block, ROUNDBOX, B_REDR, "", 10-8, *yco-height, width, height-1, NULL, 5.0, 0.0, 12.0, (float)rb_col, ""); 
-               if (active) uiBlockSetCol(block, TH_AUTO);
+               /* draw settings for individual modifiers */
+               switch (fcm->type) {
+                       case FMODIFIER_TYPE_GENERATOR: /* Generator */
+                               _draw_modifier__generator(block, fcu, fcm, yco, &height, width, active, rb_col);
+                               break;
+                       
+                       default: /* unknown type */
+                               DRAW_BACKDROP(height, 96);
+                               break;
+               }
        }
        
        /* adjust height for new to start */
index 9466a0674d1b964f21384f50d907fefcaec75444..10ba28dbcac405b8f9c95d51685370c7e110d448 100644 (file)
@@ -83,7 +83,7 @@ ARegion *graph_has_buttons_region(ScrArea *sa)
        
        BLI_insertlinkafter(&sa->regionbase, ar, arnew);
        arnew->regiontype= RGN_TYPE_UI;
-       arnew->alignment= RGN_ALIGN_TOP|RGN_SPLIT_PREV;
+       arnew->alignment= RGN_ALIGN_BOTTOM|RGN_SPLIT_PREV;
        
        arnew->flag = RGN_FLAG_HIDDEN;
        
@@ -569,7 +569,7 @@ void ED_spacetype_ipo(void)
        /* regions: UI buttons */
        art= MEM_callocN(sizeof(ARegionType), "spacetype graphedit region");
        art->regionid = RGN_TYPE_UI;
-       art->minsizey= 160;
+       art->minsizey= 200;
        art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_FRAMES;
        art->listener= NULL; // graph_region_listener;
        art->init= graph_buttons_area_init;
index 3ce656faf9207f6596759d777500e0243729a775..f51300e5f7b77e0ba4b9bed965a303a25e0dcee1 100644 (file)
@@ -69,21 +69,37 @@ typedef struct FMod_Generator {
                /* generator based on PyExpression */
        char expression[256];           /* python expression to use as generator */
        
-               /* simple polynomial generator (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... C[n])  */
-       float *poly_coefficients;       /* array of the coefficients for the polynomial (poly_order + 1 items long) */
-       unsigned int poly_order;        /* order of the polynomial (i.e. 1 for linear, 2 for quadratic) */
+               /* general generator information */
+       float *coefficients;            /* coefficients array */
+       unsigned int arraysize;         /* size of the coefficients array */
+       
+       unsigned short poly_order;      /* order of polynomial generated (i.e. 1 for linear, 2 for quadratic) */
+       short func_type;                        /* builtin math function eFMod_Generator_Functions */
+       
+       int pad;
        
                /* settings */
        short flag;                                     /* settings */
-       short mode;                                     /* which 'generator' to use */
+       short mode;                                     /* which 'generator' to use eFMod_Generator_Modes */
 } FMod_Generator;
 
 /* generator modes */
 enum {
        FCM_GENERATOR_POLYNOMIAL        = 0,
+       FCM_GENERATOR_POLYNOMIAL_FACTORISED,
+       FCM_GENERATOR_FUNCTION,
        FCM_GENERATOR_EXPRESSION,
 } eFMod_Generator_Modes;
 
+/* 'function' generator types */
+enum {
+       FCM_GENERATOR_FN_SIN    = 0,
+       FCM_GENERATOR_FN_COS,
+       FCM_GENERATOR_FN_TAN,
+       FCM_GENERATOR_FN_SQRT,
+       FCM_GENERATOR_FN_LN,
+} eFMod_Generator_Functions;
+
 
 /* envelope modifier - envelope data */
 typedef struct FCM_EnvelopeData {
@@ -444,7 +460,6 @@ enum {
  * be generic (using various placeholder template tags that will be
  * replaced with appropriate information from the context). 
  */
-// TODO: how should templates work exactly? For now, we only implement the specific KeyingSets...
 typedef struct KS_Path {
        struct KS_Path *next, *prev;
        
@@ -452,6 +467,10 @@ typedef struct KS_Path {
        ID *id;                                 /* ID block that keyframes are for */
        char group[64];                 /* name of the group to add to */
        
+               /* relative paths only */
+       int idtype;                             /* ID-type that path can be used on */
+       int templates;                  /* Templates that will be encountered in the path (as set of bitflags) */
+       
                /* all paths */
        char *rna_path;                 /* dynamically (or statically in the case of predefined sets) path */
        int array_index;                /* index that path affects */
@@ -476,6 +495,20 @@ enum {
        KSP_GROUP_KSNAME,
 } eKSP_Grouping;
 
+/* KS_Path->templates  (Template Flags)
+ *
+ * Templates in paths are used to substitute information from the 
+ * active context into relavent places in the path strings. This
+ * enum here defines the flags which define which templates are
+ * required by a path before it can be used
+ */
+enum {
+       KSP_TEMPLATE_OBJECT                     = (1<<0),       /* #obj - selected object */
+       KSP_TEMPLATE_PCHAN                      = (1<<1),       /* #pch - selected posechannel */
+       KSP_TEMPLATE_CONSTRAINT         = (1<<2),       /* #con - active only */
+       KSP_TEMPLATE_NODE                       = (1<<3),       /* #nod - selected node */
+} eKSP_TemplateTypes;
+
 /* ---------------- */
  
 /* KeyingSet definition (ks)