Project Pampa request: FCurves normalized display
authorSergey Sharybin <sergey.vfx@gmail.com>
Tue, 29 Oct 2013 18:10:52 +0000 (18:10 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Tue, 29 Oct 2013 18:10:52 +0000 (18:10 +0000)
Added two options to a header of FCurve editor:

- Normalize which makes it so every individual
  curve is fit into -1..1 space.

- Auto-normalize, which probably is to be called
  "Lock" which "locks" curve normalization scale.
  This is useful to prevent curves from jumping
  around when tweaking it.

It's debatable whether it need to be a button to
normalize curves n purpose only, and it's fully
depends on animator's workflow.

Here during Project Pampa we've got Francesco
who get used to auto-renormalization and Hjalti
who prefers locked behavior.

Docs are to be ready soon by Francesco.
Thanks Brecht for the review!

release/scripts/startup/bl_ui/space_graph.py
source/blender/blenkernel/BKE_global.h
source/blender/editors/animation/anim_draw.c
source/blender/editors/include/ED_anim_api.h
source/blender/editors/space_graph/graph_draw.c
source/blender/editors/space_graph/graph_edit.c
source/blender/editors/space_graph/graph_select.c
source/blender/editors/transform/transform_conversions.c
source/blender/makesdna/DNA_anim_types.h
source/blender/makesdna/DNA_space_types.h
source/blender/makesrna/intern/rna_space.c

index 2d0b1c93d1361502fa0b49aa92d74526bd7a5262..61e2f10a0570f05b301f4125f21516cc3608817b 100644 (file)
@@ -46,6 +46,11 @@ class GRAPH_HT_header(Header):
 
         dopesheet_filter(layout, context)
 
+        layout.prop(st, "use_normalization", text="Normalize")
+        row = layout.row()
+        row.active = st.use_normalization
+        row.prop(st, "use_auto_normalization", text="Auto")
+
         layout.prop(st, "auto_snap", text="")
         layout.prop(st, "pivot_point", text="", icon_only=True)
 
index 9d33af1a0f4224816d0525184533bcbbc0fc6348..d0341ab8c897e004d5d5cce108132a4c5cd49129 100644 (file)
@@ -192,6 +192,7 @@ enum {
 #define G_TRANSFORM_OBJ         1
 #define G_TRANSFORM_EDIT        2
 #define G_TRANSFORM_SEQ         4
+#define G_TRANSFORM_FCURVES     8
 
 /* G.special1 */
 
index 4a8557a2b1f63b8c4ea2598d0f4bdee94515bdf1..dcf9c8e623b32b6df7529fb1ee4e3e874f023dd8 100644 (file)
@@ -33,6 +33,7 @@
 #include "DNA_anim_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_space_types.h"
 #include "DNA_userdef_types.h"
 
 #include "BLI_math.h"
@@ -359,9 +360,68 @@ void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, short restore, sh
 /* *************************************************** */
 /* UNITS CONVERSION MAPPING (required for drawing and editing keyframes) */
 
+/* Get flags used for normalization in ANIM_unit_mapping_get_factor. */
+short ANIM_get_normalization_flags(bAnimContext *ac)
+{
+       if (ac->sl->spacetype == SPACE_IPO) {
+               SpaceIpo *sipo = (SpaceIpo *) ac->sl;
+               bool use_normalization = (sipo->flag & SIPO_NORMALIZE) != 0;
+               bool freeze_normalization = (sipo->flag & SIPO_NORMALIZE_FREEZE) != 0;
+               return use_normalization
+                   ? (ANIM_UNITCONV_NORMALIZE |  (freeze_normalization ? ANIM_UNITCONV_NORMALIZE_FREEZE : 0))
+                   : 0;
+       }
+
+       return 0;
+}
+
+static float normalzation_factor_get(FCurve *fcu, short flag)
+{
+       float factor;
+
+       if (flag & ANIM_UNITCONV_RESTORE) {
+               return 1.0f / fcu->prev_norm_factor;
+       }
+
+       if (flag & ANIM_UNITCONV_NORMALIZE_FREEZE) {
+               return fcu->prev_norm_factor;
+       }
+
+       if (G.moving & G_TRANSFORM_FCURVES) {
+               return fcu->prev_norm_factor;
+       }
+
+       fcu->prev_norm_factor = 1.0f;
+       if (fcu->bezt) {
+               BezTriple *bezt;
+               int i;
+               float max_coord = -FLT_MAX;
+
+               if (fcu->totvert < 1) {
+                       return 1.0f;
+               }
+
+               for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
+                       max_coord = max_ff(max_coord, fabsf(bezt->vec[0][1]));
+                       max_coord = max_ff(max_coord, fabsf(bezt->vec[1][1]));
+                       max_coord = max_ff(max_coord, fabsf(bezt->vec[2][1]));
+               }
+
+               if (max_coord > FLT_EPSILON) {
+                       factor = 1.0f / max_coord;
+               }
+       }
+       fcu->prev_norm_factor = factor;
+       return factor;
+}
+
 /* Get unit conversion factor for given ID + F-Curve */
-float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short restore)
+float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag)
 {
+       if (flag & ANIM_UNITCONV_NORMALIZE) {
+               return normalzation_factor_get(fcu, flag);
+       }
+
        /* sanity checks */
        if (id && fcu && fcu->rna_path) {
                PointerRNA ptr, id_ptr;
@@ -374,7 +434,7 @@ float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short rest
                        if (RNA_SUBTYPE_UNIT(RNA_property_subtype(prop)) == PROP_UNIT_ROTATION) {
                                /* if the radians flag is not set, default to using degrees which need conversions */
                                if ((scene) && (scene->unit.system_rotation == USER_UNIT_ROT_RADIANS) == 0) {
-                                       if (restore)
+                                       if (flag & ANIM_UNITCONV_RESTORE)
                                                return DEG2RADF(1.0f);  /* degrees to radians */
                                        else
                                                return RAD2DEGF(1.0f);  /* radians to degrees */
index d23c57273ecd0ee3b4ad2c7e9faf17b006e9814b..d98fa1fc32f1f99ff544bcae68b46ab558657fd4 100644 (file)
@@ -559,10 +559,19 @@ typedef enum eAnimUnitConv_Flags {
        /* only touch selected vertices */
        ANIM_UNITCONV_SELVERTS  = (1 << 3),
        ANIM_UNITCONV_SKIPKNOTS  = (1 << 4),
+       /* Scale FCurve i a way it fits to -1..1 space */
+       ANIM_UNITCONV_NORMALIZE  = (1 << 5),
+       /* Only whennormalization is used: use scale factor from previous run,
+        * prevents curves from jumping all over the place when tweaking them.
+        */
+       ANIM_UNITCONV_NORMALIZE_FREEZE  = (1 << 6),
 } eAnimUnitConv_Flags;
 
+/* Normalizatin flags from Space Graph passing to ANIM_unit_mapping_get_factor */
+short ANIM_get_normalization_flags(bAnimContext *ac);
+
 /* Get unit conversion factor for given ID + F-Curve */
-float ANIM_unit_mapping_get_factor(struct Scene *scene, struct ID *id, struct FCurve *fcu, short restore);
+float ANIM_unit_mapping_get_factor(struct Scene *scene, struct ID *id, struct FCurve *fcu, short flag);
 
 /* ------------- Utility macros ----------------------- */
 
index ba619fd9c77c10b88478f9f26c1d88ef5f219977..e7c98437b9fb82ae26cfda1809a50f2f6b764f29 100644 (file)
@@ -490,6 +490,7 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
        float stime, etime;
        float unitFac;
        float dx, dy;
+       short mapping_flag = ANIM_get_normalization_flags(ac);
 
        /* when opening a blend file on a different sized screen or while dragging the toolbar this can happen
         * best just bail out in this case */
@@ -503,7 +504,7 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
        fcu->driver = NULL;
        
        /* compute unit correction factor */
-       unitFac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, 0);
+       unitFac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
        
        /* Note about sampling frequency:
         *  Ideally, this is chosen such that we have 1-2 pixels = 1 segment
@@ -551,10 +552,11 @@ static void draw_fcurve_curve_samples(bAnimContext *ac, ID *id, FCurve *fcu, Vie
        float fac, v[2];
        int b = fcu->totvert - 1;
        float unit_scale;
+       short mapping_flag = ANIM_get_normalization_flags(ac);
 
        /* apply unit mapping */
        glPushMatrix();
-       unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, 0);
+       unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
        glScalef(1.0f, unit_scale, 1.0f);
 
        glBegin(GL_LINE_STRIP);
@@ -632,10 +634,11 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2
        int b = fcu->totvert - 1;
        int resol;
        float unit_scale;
+       short mapping_flag = ANIM_get_normalization_flags(ac);
 
        /* apply unit mapping */
        glPushMatrix();
-       unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, 0);
+       unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
        glScalef(1.0f, unit_scale, 1.0f);
 
        glBegin(GL_LINE_STRIP);
@@ -788,7 +791,8 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
 {
        ChannelDriver *driver = fcu->driver;
        View2D *v2d = &ac->ar->v2d;
-       float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, false);
+       short mapping_flag = ANIM_get_normalization_flags(ac);
+       float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag);
        
        /* for now, only show when debugging driver... */
        //if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
@@ -1019,7 +1023,8 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
                                }
                        }
                        else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) {
-                               float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, 0);
+                               short mapping_flag = ANIM_get_normalization_flags(ac);
+                               float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
 
                                glPushMatrix();
                                glScalef(1.0f, unit_scale, 1.0f);
index c8e07dbda681bc28dd0cb2048da65ee1817ad83f..ebb9266149af7c38d09e1fcee0daafbb2d86e659 100644 (file)
@@ -116,6 +116,8 @@ void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, floa
                        
                        /* get range */
                        if (calc_fcurve_bounds(fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
+                               short mapping_flag = ANIM_get_normalization_flags(ac);
+
                                /* apply NLA scaling */
                                if (adt) {
                                        txmin = BKE_nla_tweakedit_remap(adt, txmin, NLATIME_CONVERT_MAP);
@@ -123,7 +125,7 @@ void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, floa
                                }
                                
                                /* apply unit corrections */
-                               unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, 0);
+                               unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
                                tymin *= unitFac;
                                tymax *= unitFac;
                                
@@ -330,12 +332,14 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
                FPoint *fpt;
                float unitFac;
                int cfra;
-               
+               SpaceIpo *sipo = (SpaceIpo *) ac->sl;
+               short mapping_flag = ANIM_get_normalization_flags(ac);
+
                /* disable driver so that it don't muck up the sampling process */
                fcu->driver = NULL;
                
                /* calculate unit-mapping factor */
-               unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, 0);
+               unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
                
                /* create samples, but store them in a new curve 
                 *      - we cannot use fcurve_store_samples() as that will only overwrite the original curve 
@@ -578,6 +582,8 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
         * keyframes if these will be visible after doing so...
         */
        if (fcurve_is_keyframable(fcu)) {
+               short mapping_flag = ANIM_get_normalization_flags(&ac);
+
                /* get frame and value from props */
                frame = RNA_float_get(op->ptr, "frame");
                val = RNA_float_get(op->ptr, "value");
@@ -587,7 +593,7 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
                frame = BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP);
                
                /* apply inverse unit-mapping to value to get correct value for F-Curves */
-               val *= ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, 1);
+               val *= ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE);
                
                /* insert keyframe on the specified frame + value */
                insert_vert_fcurve(fcu, frame, val, 0);
@@ -1787,8 +1793,9 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
        
        for (ale = anim_data.first; ale; ale = ale->next) {
                AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+               short mapping_flag = ANIM_get_normalization_flags(&ac);
                KeyframeEditData current_ked;
-               float unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS);
+               float unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS);
 
                memset(&current_ked, 0, sizeof(current_ked));
 
@@ -1891,7 +1898,8 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
        /* snap keyframes */
        for (ale = anim_data.first; ale; ale = ale->next) {
                AnimData *adt = ANIM_nla_mapping_get(ac, ale);
-               float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, 0);
+               short mapping_flag = ANIM_get_normalization_flags(ac);
+               float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag);
 
                ked.f1 = cursor_value / unit_scale;
 
@@ -2012,7 +2020,8 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
        /* mirror keyframes */
        for (ale = anim_data.first; ale; ale = ale->next) {
                AnimData *adt = ANIM_nla_mapping_get(ac, ale);
-               float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS);
+               short mapping_flag = ANIM_get_normalization_flags(ac);
+               float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS);
 
                /* apply unit corrections */
                ked.f1 = cursor_value * unit_scale;
index ce036bec380692be84f2c3437c087ebd11ab1841..d0dcaf91e77d00a28dac17b34cf7a826b5c18b06 100644 (file)
@@ -253,6 +253,8 @@ static void borderselect_graphkeys(bAnimContext *ac, rcti rect, short mode, shor
        else
                mapping_flag = ANIM_UNITCONV_ONLYKEYS;
 
+       mapping_flag |= ANIM_get_normalization_flags(ac);
+
        /* loop over data, doing border select */
        for (ale = anim_data.first; ale; ale = ale->next) {
                AnimData *adt = ANIM_nla_mapping_get(ac, ale);
@@ -996,7 +998,8 @@ static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], L
        
        SpaceIpo *sipo = (SpaceIpo *)ac->sl;
        View2D *v2d = &ac->ar->v2d;
-
+       short mapping_flag = 0;
+       
        /* get curves to search through 
         *      - if the option to only show keyframes that belong to selected F-Curves is enabled,
         *        include the 'only selected' flag...
@@ -1004,12 +1007,13 @@ static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], L
        filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
        if (sipo->flag & SIPO_SELCUVERTSONLY)   // FIXME: this should really be check for by the filtering code...
                filter |= ANIMFILTER_SEL;
+       mapping_flag |= ANIM_get_normalization_flags(ac);
        ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
        
        for (ale = anim_data.first; ale; ale = ale->next) {
                FCurve *fcu = (FCurve *)ale->key_data;
                AnimData *adt = ANIM_nla_mapping_get(ac, ale);
-               float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, 0);
+               float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag);
 
                /* apply NLA mapping to all the keyframes */
                if (adt)
index 41d04c85f4461daeb2fe6aa7a2bfaa076515cb22..573c4f156573b5829cb35c90afab45e45014069a 100644 (file)
@@ -3714,12 +3714,14 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
        float mtx[3][3], smtx[3][3];
        const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
        const bool use_local_center = checkUseLocalCenter_GraphEdit(t);
-       const short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
+       short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
        
        /* determine what type of data we are operating on */
        if (ANIM_animdata_get_context(C, &ac) == 0)
                return;
-       
+
+       anim_map_flag |= ANIM_get_normalization_flags(&ac);
+
        /* filter data */
        filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
        ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -3854,8 +3856,8 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
 
                copy_m3_m3(scaled_mtx, mtx);
                copy_m3_m3(scaled_smtx, smtx);
-               mul_v3_fl(scaled_mtx[1], 1.0f / unit_scale);
-               mul_v3_fl(scaled_smtx[1],  unit_scale);
+               mul_v3_fl(scaled_mtx[1], unit_scale);
+               mul_v3_fl(scaled_smtx[1],  1.0f / unit_scale);
 
                /* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */
                for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
@@ -5861,6 +5863,9 @@ int special_transform_moving(TransInfo *t)
        if (t->spacetype == SPACE_SEQ) {
                return G_TRANSFORM_SEQ;
        }
+       else if (t->spacetype == SPACE_IPO) {
+               return G_TRANSFORM_FCURVES;
+       }
        else if (t->obedit || ((t->flag & T_POSE) && (t->poseobj))) {
                return G_TRANSFORM_EDIT;
        }
index fc0dd54a8e711671fc7ed1866ea688030d5e570d..7a7e08138b047fc03d5906a5d7f9cb41b4a3e98a 100644 (file)
@@ -459,6 +459,8 @@ typedef struct FCurve {
                /* curve coloring (for editor) */
        int color_mode;                 /* coloring method to use (eFCurve_Coloring) */
        float color[3];                 /* the last-color this curve took */
+
+       float prev_norm_factor, pad;
 } FCurve;
 
 
index f71516af5e65e4c32d584beadb6b0ca15b4aafa1..faa99aaaad89fd6658531c58be2467b504d9cf94 100644 (file)
@@ -366,6 +366,9 @@ typedef enum eGraphEdit_Flag {
        SIPO_BEAUTYDRAW_OFF       = (1 << 12),
        /* draw grouped channels with colors set in group */
        SIPO_NODRAWGCOLORS        = (1 << 13),
+       /* normalize curves on display */
+       SIPO_NORMALIZE            = (1 << 14),
+       SIPO_NORMALIZE_FREEZE     = (1 << 15),
 } eGraphEdit_Flag;
 
 /* SpaceIpo->mode (Graph Editor Mode) */
index 5daeb4ae612145da2b74a9eaf141c6516f0af6fe..a99cdda6ff351fc5eaa9084569d823d4d2cba0c6 100644 (file)
@@ -2880,6 +2880,18 @@ static void rna_def_space_graph(BlenderRNA *brna)
        RNA_def_property_boolean_funcs(prop, "rna_SpaceGraphEditor_has_ghost_curves_get", NULL);
        RNA_def_property_ui_text(prop, "Has Ghost Curves", "Graph Editor instance has some ghost curves stored");
        RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+
+       /* nromalize curves */
+       prop = RNA_def_property(srna, "use_normalization", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_NORMALIZE);
+       RNA_def_property_ui_text(prop, "use Normalization", "Display curves in normalized to -1..1 range, "
+                               "for easier editing of multiple curves with different ranges");
+       RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+
+       prop = RNA_def_property(srna, "use_auto_normalization", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NORMALIZE_FREEZE);
+       RNA_def_property_ui_text(prop, "Auto Normalization", "Automatically recalculate curve normalization on every curve edit");
+       RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
 }
 
 static void rna_def_space_nla(BlenderRNA *brna)