Proportional editing for IPO editor - version ready for feedback by artists.
authorAntony Riakiotakis <kalast@gmail.com>
Fri, 27 Mar 2015 14:23:39 +0000 (15:23 +0100)
committerAntony Riakiotakis <kalast@gmail.com>
Tue, 31 Mar 2015 14:45:30 +0000 (16:45 +0200)
This works by using the distance in the x axis only (usually artists want to influence nearby
keyframes based on timing, not value). Tweaking handles is the same as tweaking
the central handle. It's a bit ambiguous if proportional editing is really meaningful
for handles but will leave that for artists to decide.

release/scripts/startup/bl_ui/space_graph.py
source/blender/editors/include/ED_anim_api.h
source/blender/editors/space_graph/graph_ops.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform_constraints.c
source/blender/editors/transform/transform_conversions.c

index d3e1a866e431c6522da4b1f7d1b391502770fd28..4c3f4bb695ee472c14bfe7c0f77038bc4bf51cb3 100644 (file)
@@ -29,6 +29,7 @@ class GRAPH_HT_header(Header):
         from bl_ui.space_dopesheet import dopesheet_filter
 
         layout = self.layout
+        toolsettings = context.tool_settings
 
         st = context.space_data
 
@@ -46,6 +47,11 @@ class GRAPH_HT_header(Header):
         row.active = st.use_normalization
         row.prop(st, "use_auto_normalization", text="Auto")
 
+        row = layout.row(align=True)
+        row.prop(toolsettings, "proportional_edit", icon_only=True)
+        if toolsettings.proportional_edit != 'DISABLED':
+            row.prop(toolsettings, "proportional_edit_falloff", icon_only=True)
+
         layout.prop(st, "auto_snap", text="")
         layout.prop(st, "pivot_point", icon_only=True)
 
index 8cf42dfce6ca73fbe9d8aede0b5f7af42276acc9..7fd0d35d514012bebf52d7bfbdf52025e74c7940 100644 (file)
@@ -114,8 +114,9 @@ typedef struct bAnimListElem {
        int     flag;           /* copy of elem's flags for quick access */
        int     index;          /* for un-named data, the index of the data in its collection */
        
-       short   update;         /* (eAnim_Update_Flags)  tag the element for updating */
-       
+       char    update;         /* (eAnim_Update_Flags)  tag the element for updating */
+       char    tag;            /* tag the included data. Temporary always */
+
        short   datatype;       /* (eAnim_KeyType) type of motion data to expect */
        void   *key_data;       /* motion data - mostly F-Curves, but can be other types too */
        
index b52945297b943d850967c063a571cc68751880f8..33e8b522335e15c4ad00648914453e070dd51e71 100644 (file)
@@ -562,7 +562,6 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
        WM_keymap_add_item(keymap, "GRAPH_OT_easing_type", EKEY, KM_PRESS, KM_CTRL, 0);
        
        /* destructive */
-       WM_keymap_add_item(keymap, "GRAPH_OT_clean", OKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "GRAPH_OT_smooth", OKEY, KM_PRESS, KM_ALT, 0);
        WM_keymap_add_item(keymap, "GRAPH_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
        
@@ -608,6 +607,11 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
        /* transform system */
        transform_keymap_for_space(keyconf, keymap, SPACE_IPO);
        
+       kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle_enum", OKEY, KM_PRESS, 0, 0);
+       RNA_string_set(kmi->ptr, "data_path", "tool_settings.proportional_edit");
+       RNA_string_set(kmi->ptr, "value_1", "DISABLED");
+       RNA_string_set(kmi->ptr, "value_2", "ENABLED");
+
        /* pivot point settings */
        kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0);
        RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
index 586c9d625898bc88cfb97ebda3cd905b304b5c41..c8d81383d79034997b759c1dc365a0d4b275b904 100644 (file)
@@ -2089,6 +2089,12 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
                t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
                t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
        }
+       else if (t->spacetype == SPACE_IPO) {
+               unit_m3(t->spacemtx);
+               t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+               //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
+               t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
+       }
        else
                unit_m3(t->spacemtx);
 
index ccb81c7342bd375fb89b855f4ce02d707c1c4efa..bcd66f56c5321ace5fab7d02aa4d1db04ff91d5c 100644 (file)
@@ -46,6 +46,7 @@
 #include "BLI_math.h"
 #include "BLI_utildefines.h"
 #include "BLI_string.h"
+#include "BLI_rect.h"
 
 #include "BKE_context.h"
 
@@ -757,12 +758,22 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
                                ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
                        }
                        else if (t->options & CTX_PAINT_CURVE) {
-                               aspx = aspy = 1.0;
+                               aspx = aspy = 1.0f;
                        }
                        else {
                                ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
                        }
-                       glScalef(1.0f / aspx, 1.0f / aspy, 1.0);
+                       glScalef(1.0f / aspx, 1.0f / aspy, 1.0f);
+               }
+               else if (t->spacetype == SPACE_IPO) {
+                       /* only scale y */
+                       rcti *mask = &t->ar->v2d.mask;
+                       rctf *datamask = &t->ar->v2d.cur;
+                       float xsize = BLI_rctf_size_x(datamask);
+                       float ysize = BLI_rctf_size_y(datamask);
+                       float xmask = BLI_rcti_size_x(mask);
+                       float ymask = BLI_rcti_size_y(mask);
+                       glScalef(1.0f, (ysize / xsize) * (xmask / ymask), 1.0f);
                }
 
                depth_test_enabled = glIsEnabled(GL_DEPTH_TEST);
index a74de31491a05fa1d57fd69939078c20a3fee2e0..e34439945ca2b220b7f429f08016987af2dd109b 100644 (file)
@@ -3786,6 +3786,27 @@ static bool graph_edit_use_local_center(TransInfo *t)
        return (t->around == V3D_LOCAL) && !graph_edit_is_translation_mode(t);
 }
 
+
+static void graph_key_shortest_dist(FCurve *fcu, TransData *td_start, TransData *td, bool use_handle)
+{
+       int j = 0;
+       TransData *td_iter = td_start;
+
+       td->dist = FLT_MAX;
+       for (; j < fcu->totvert; j++) {
+               BezTriple *bezt = fcu->bezt + j;
+               const bool sel2 = (bezt->f2 & SELECT) != 0;
+               const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+               const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+               if (sel1 || sel2 || sel3) {
+                       td->dist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
+               }
+
+               td_iter += 3;
+       }
+}
+
 static void createTransGraphEditData(bContext *C, TransInfo *t)
 {
        SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
@@ -3808,6 +3829,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
        const bool is_translation_mode = graph_edit_is_translation_mode(t);
        const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
        const bool use_local_center = graph_edit_use_local_center(t);
+       const bool propedit = (t->flag & T_PROP_EDIT) != 0;
        short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
        
        /* determine what type of data we are operating on */
@@ -3839,6 +3861,8 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
                AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
                FCurve *fcu = (FCurve *)ale->key_data;
                float cfra;
+               int curvecount = 0;
+               bool selected = false;
 
                /* F-Curve may not have any keyframes */
                if (fcu->bezt == NULL)
@@ -3859,20 +3883,34 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
                                const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
                                const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
 
-                               if (!is_translation_mode || !(sel2)) {
-                                       if (sel1) {
-                                               count++;
+                               if (propedit) {
+                                       curvecount += 3;
+                                       if (sel2 || sel1 || sel3)
+                                               selected = true;
+                               }
+                               else {
+                                       if (!is_translation_mode || !(sel2)) {
+                                               if (sel1) {
+                                                       count++;
+                                               }
+
+                                               if (sel3) {
+                                                       count++;
+                                               }
                                        }
 
-                                       if (sel3) {
+                                       /* only include main vert if selected */
+                                       if (sel2 && !use_local_center) {
                                                count++;
                                        }
                                }
+                       }
+               }
 
-                               /* only include main vert if selected */
-                               if (sel2 && !use_local_center) {
-                                       count++;
-                               }
+               if (propedit) {
+                       if (selected) {
+                               count += curvecount;
+                               ale->tag = true;
                        }
                }
        }
@@ -3925,7 +3963,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
                float cfra;
 
                /* F-Curve may not have any keyframes */
-               if (fcu->bezt == NULL)
+               if (fcu->bezt == NULL || (propedit && ale->tag == 0))
                        continue;
 
                /* convert current-frame to action-time (slightly less accurate, especially under
@@ -3948,66 +3986,135 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
                                TransDataCurveHandleFlags *hdata = NULL;
                                /* short h1=1, h2=1; */ /* UNUSED */
                                
-                               /* only include handles if selected, irrespective of the interpolation modes.
-                                * also, only treat handles specially if the center point isn't selected. 
-                                */
-                               if (!is_translation_mode || !(sel2)) {
-                                       if (sel1) {
-                                               hdata = initTransDataCurveHandles(td, bezt);
-                                               bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, sel1, true, intvals, mtx, smtx, unit_scale);
+                               if (propedit) {
+                                       bool is_sel = (sel2 || sel1 || sel3);
+                                       /* we always select all handles for proportional editing if central handle is selected */
+                                       initTransDataCurveHandles(td, bezt);
+                                       bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, is_sel, true, intvals, mtx, smtx, unit_scale);
+                                       initTransDataCurveHandles(td, bezt);
+                                       bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, is_sel, false, intvals, mtx, smtx, unit_scale);
+                                       initTransDataCurveHandles(td, bezt);
+                                       bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, is_sel, true, intvals, mtx, smtx, unit_scale);
+                               }
+                               else {
+                                       /* only include handles if selected, irrespective of the interpolation modes.
+                                        * also, only treat handles specially if the center point isn't selected.
+                                        */
+                                       if (!is_translation_mode || !(sel2)) {
+                                               if (sel1) {
+                                                       hdata = initTransDataCurveHandles(td, bezt);
+                                                       bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, sel1, true, intvals, mtx, smtx, unit_scale);
+                                               }
+                                               else {
+                                                       /* h1 = 0; */ /* UNUSED */
+                                               }
+
+                                               if (sel3) {
+                                                       if (hdata == NULL)
+                                                               hdata = initTransDataCurveHandles(td, bezt);
+                                                       bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, sel3, true, intvals, mtx, smtx, unit_scale);
+                                               }
+                                               else {
+                                                       /* h2 = 0; */ /* UNUSED */
+                                               }
                                        }
-                                       else {
-                                               /* h1 = 0; */ /* UNUSED */
+
+                                       /* only include main vert if selected */
+                                       if (sel2 && !use_local_center) {
+                                               /* move handles relative to center */
+                                               if (is_translation_mode) {
+                                                       if (sel1) td->flag |= TD_MOVEHANDLE1;
+                                                       if (sel3) td->flag |= TD_MOVEHANDLE2;
+                                               }
+
+                                               /* if handles were not selected, store their selection status */
+                                               if (!(sel1) || !(sel3)) {
+                                                       if (hdata == NULL)
+                                                               hdata = initTransDataCurveHandles(td, bezt);
+                                               }
+
+                                               bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, sel2, false, intvals, mtx, smtx, unit_scale);
+
                                        }
-                                       
-                                       if (sel3) {
-                                               if (hdata == NULL)
-                                                       hdata = initTransDataCurveHandles(td, bezt);
-                                               bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, sel3, true, intvals, mtx, smtx, unit_scale);
+                                       /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...):
+                                        *      - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
+                                        *        then check if we're using auto-handles.
+                                        *      - If so, change them auto-handles to aligned handles so that handles get affected too
+                                        */
+                                       if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) &&
+                                           ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
+                                           ELEM(t->mode, TFM_ROTATION, TFM_RESIZE))
+                                       {
+                                               if (hdata && (sel1) && (sel3)) {
+                                                       bezt->h1 = HD_ALIGN;
+                                                       bezt->h2 = HD_ALIGN;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               
+               /* Sets handles based on the selection */
+               testhandles_fcurve(fcu, use_handle);
+       }
+
+       if (propedit) {
+               /* loop 2: build transdata arrays */
+               td = t->data;
+
+               for (ale = anim_data.first; ale; ale = ale->next) {
+                       AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+                       FCurve *fcu = (FCurve *)ale->key_data;
+                       TransData *td_start = td;
+                       float cfra;
+
+                       /* F-Curve may not have any keyframes */
+                       if (fcu->bezt == NULL || (ale->tag == 0))
+                               continue;
+
+                       /* convert current-frame to action-time (slightly less accurate, especially under
+                        * higher scaling ratios, but is faster than converting all points)
+                        */
+                       if (adt)
+                               cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+                       else
+                               cfra = (float)CFRA;
+
+                       /* 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++) {
+                               if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
+                                       const bool sel2 = (bezt->f2 & SELECT) != 0;
+                                       const bool sel1 = use_handle ? (bezt->f1 & SELECT) != 0 : sel2;
+                                       const bool sel3 = use_handle ? (bezt->f3 & SELECT) != 0 : sel2;
+
+                                       if (sel1 || sel2) {
+                                               td->dist = 0.0f;
                                        }
                                        else {
-                                               /* h2 = 0; */ /* UNUSED */
+                                               graph_key_shortest_dist(fcu, td_start, td, use_handle);
                                        }
-                               }
-                               
-                               /* only include main vert if selected */
-                               if (sel2 && !use_local_center) {
-                                       /* move handles relative to center */
-                                       if (is_translation_mode) {
-                                               if (sel1) td->flag |= TD_MOVEHANDLE1;
-                                               if (sel3) td->flag |= TD_MOVEHANDLE2;
+                                       td++;
+
+                                       if (sel2) {
+                                               td->dist = 0.0f;
                                        }
-                                       
-                                       /* if handles were not selected, store their selection status */
-                                       if (!(sel1) || !(sel3)) {
-                                               if (hdata == NULL)
-                                                       hdata = initTransDataCurveHandles(td, bezt);
+                                       else {
+                                               graph_key_shortest_dist(fcu, td_start, td, use_handle);
                                        }
-                                       
-                                       bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 1, sel2, false, intvals, mtx, smtx, unit_scale);
-                                       
-                               }
-                               /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...):
-                                *      - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
-                                *        then check if we're using auto-handles.
-                                *      - If so, change them auto-handles to aligned handles so that handles get affected too
-                                */
-                               if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) &&
-                                   ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
-                                   ELEM(t->mode, TFM_ROTATION, TFM_RESIZE))
-                               {
-                                       if (hdata && (sel1) && (sel3)) {
-                                               bezt->h1 = HD_ALIGN;
-                                               bezt->h2 = HD_ALIGN;
+                                       td++;
+
+                                       if (sel3 || sel2) {
+                                               td->dist = 0.0f;
                                        }
+                                       else {
+                                               graph_key_shortest_dist(fcu, td_start, td, use_handle);
+                                       }
+                                       td++;
                                }
                        }
                }
-               
-               /* Sets handles based on the selection */
-               testhandles_fcurve(fcu, use_handle);
        }
-       
+
        /* cleanup temp list */
        ANIM_animdata_freelist(&anim_data);
 }
@@ -7631,13 +7738,14 @@ void createTransData(bContext *C, TransInfo *t)
        else if (t->spacetype == SPACE_IPO) {
                t->flag |= T_POINTS | T_2D_EDIT;
                createTransGraphEditData(C, t);
-#if 0
+
                if (t->data && (t->flag & T_PROP_EDIT)) {
+                       t->flag |= T_PROP_CONNECTED;
+                       t->flag &= ~T_PROP_PROJECTED;
                        sort_trans_data(t); // makes selected become first in array
-                       set_prop_dist(t, 1);
+                       set_prop_dist(t, false);
                        sort_trans_data_dist(t);
                }
-#endif
        }
        else if (t->spacetype == SPACE_NODE) {
                t->flag |= T_POINTS | T_2D_EDIT;